SPI學習-2(linux driver實現(xiàn))

轉(zhuǎn)載

1仔蝌、SPI總線:

? ? ? ?SPI(同步外設(shè)接口)是由摩托羅拉公司開發(fā)的全雙工同步串行總線,其接口由 MISO(串行數(shù)據(jù)輸入),MOSI(串行數(shù)據(jù)輸出),SCK(串行移位時鐘),SS/CS(從使能信號)四種信號構(gòu)成(當然了,現(xiàn)在芯片技術(shù)日新月異,SPI 模塊的結(jié)構(gòu)也在變化中,象 OMAP 系列中的 SPI 模塊還支持 5 線的一種模式),SS /CS決定了唯一的與主設(shè)備通信的從設(shè)備,主設(shè)備通過產(chǎn)生移位時鐘來發(fā)起通訊怀薛。通訊時,數(shù)據(jù)由 MOSI 輸出,MISO 輸入,數(shù)據(jù)在時鐘的上升

或下降沿由 MOSI 輸出,在緊接著的下降或上升沿由 MISO 讀入,這樣經(jīng)過 8/16 次時鐘的改變,完成 8/16 位數(shù)據(jù)的傳輸删性。

? ? ? ?SPI 模塊為了和外設(shè)進行數(shù)據(jù)交換,根據(jù)外設(shè)工作要求,其輸出串行同步時鐘極性(CPOL)和相位(CPHA)可以進行配置。如果 CPOL=0,串行同步時鐘的空閑狀態(tài)為低電平;如果CPOL=1,串行同步時鐘的空閑狀態(tài)為高電平。如果 CPHA=0,在串行同步時鐘的第一個跳變沿(上升或下降)數(shù)據(jù)被采樣;如果 CPHA=1,在串行同步時鐘的第二個跳變沿(上升或下降)數(shù)據(jù)被采樣。

2、LINUX驅(qū)動的分層與分離:

? ? ? ?在面向?qū)ο蟮某绦蛟O(shè)計中,可以為某一類相似的事物定義一個基類,而具體的事物可以繼承這個基類中的函數(shù)瓮钥。Linux 內(nèi)核中頻繁使用到面向?qū)ο蟮脑O(shè)計思想。在設(shè)備驅(qū)動方面,往往為同類的設(shè)備設(shè)計了一個框架,而框架中的核心層則實現(xiàn)了該設(shè)備通用的一些功能烹吵。而且具體的設(shè)備不想使用核心層的函數(shù),它可以重載之碉熄。這就是我們所說的在驅(qū)動設(shè)計中的分層思想。

? ? ? ?此外,在驅(qū)動的設(shè)計中,我們還會使用分離的思想肋拔。如果一個設(shè)備的驅(qū)動和 host 的驅(qū)動休戚相關(guān),那么,這就意味著這個普通的設(shè)備如果用在不同的 host 上,會采用 n 個版本的驅(qū)動锈津。如果產(chǎn)品單一,也許感覺不到不使用分離思想來設(shè)計驅(qū)動的危害,但是我們想一下,這個世上被人們稱道的多是什么?精品,藝術(shù)品!精品如何打造?注重細節(jié),不只考慮單一需求!大家開發(fā)個東西不容易,怎么能隨隨便便就讓它茫然眾碼矣呢,所以,何時何地,我們都要以打造精品的思想來要求自己,讓自己的勞動力不浪費。

使用分離的思想來設(shè)計驅(qū)動的話,就夠就是這樣的:

? ? ? ?外設(shè)驅(qū)動與主機控制器的驅(qū)動不相關(guān),主機控制器的驅(qū)動不關(guān)心外設(shè),而外設(shè)驅(qū)動也不關(guān)心主機,外設(shè)只是訪問核心層的通用 API 進行數(shù)據(jù)傳輸,主機和外設(shè)之間可以進行任意的組合凉蜂。相當于在控制器驅(qū)動和設(shè)備驅(qū)動之間增加一層核心層,對內(nèi)對外都隱藏了對端的不確定性一姿。仔細通讀USB,SPI,PCI 的代碼就會發(fā)現(xiàn)這種思想的體現(xiàn)。

3跃惫、LINUX設(shè)備模型:

? ? ? ?設(shè)備驅(qū)動模型中,主要包含總線叮叹、設(shè)備和驅(qū)動三個實體,總線將設(shè)備和驅(qū)動綁定,在系統(tǒng)每注冊一個設(shè)備的時候,會尋找與之匹配的驅(qū)動,反之,在系統(tǒng)每注冊一個驅(qū)動的時候,會尋找與之匹配的設(shè)備,而匹配由總線完成。

? ? ? ?根據(jù)這個模型的需求,一個現(xiàn)實的 linux 設(shè)備和驅(qū)動通常都需要掛接在一種總線上,否則誰來管他們的匹配啊,注冊驅(qū)動和注冊設(shè)備都是由不同的 API 來完成的爆存。對于本身依附于 PCI,USB,I2C,SPI 等的設(shè)備而言,這自然不是問題,但是在嵌入式系統(tǒng)里面,Controller 系統(tǒng)中集成的外設(shè)控制器,掛載在內(nèi)存空間的外設(shè)確不依附于此類總線蛉顽。就像 SPI 控制器,PCI 控制器等等都是這種情況。那如何處理呢先较?基于這一背景,Linux 發(fā)明了一種虛擬的總線稱為 platform 總線,相應的設(shè)備稱為 platform_device,而驅(qū)動稱為 platform_driver携冤。關(guān)于platform總線這里就不多說了悼粮,網(wǎng)上有很多資料。

? ? ? 使用 platform 總線在驅(qū)動中大體有以下幾個好處:

a,使得設(shè)備被掛接在一個總線上,使配套的 sysfs 節(jié)點曾棕、設(shè)備電源管理都成為可能扣猫。

b, 隔離了 BSP 和驅(qū)動。BSP 中定義 platform 設(shè)備和設(shè)備使用的資源(可以使用platform_data 的形式來包括 platform 設(shè)備的設(shè)備),設(shè)備的具體配置信息翘地。而在驅(qū)動中,只需要通過通用 API 去獲取資源和數(shù)據(jù),做到了板相關(guān)代碼和驅(qū)動代碼的分離,使得驅(qū)動具有更好的可擴展性和跨平臺性申尤。

4、LINUX SPI 核心層:

? ? ? ?核心層代碼負責這個框架中通用的部分衙耕,滿足分層的思想昧穿,位于drivers/spi/spi.c。主要承擔的工作包括:注冊 spi總線,提供基本 SPI 總線操作 API:

int spi_register_driver(struct spi_driver *sdrv)橙喘;

struct spi_device *spi_alloc_device(struct spi_master *master)时鸵;

int spi_add_device(struct spi_device *spi);

struct spi_device *spi_new_device(struct spi_master *master,?struct spi_board_info *chip)厅瞎;

struct spi_master *spi_alloc_master(struct device *dev, unsigned size)饰潜;

int spi_register_master(struct spi_master *master);

void spi_unregister_master(struct spi_master *master)和簸;

int spi_sync(struct spi_device *spi, struct spi_message *message)彭雾;

int spi_write_then_read(struct spi_device *spi,?const u8 *txbuf, unsigned n_tx,?u8 *rxbuf, unsigned n_rx);

spi_register_board_info(struct spi_board_info const *info, unsigned n)比搭;

等......(具體查看/driver/spi/spi.c)

4.1、spi主機master

? ? ? ?在 Linux 中,每一個類型的驅(qū)動都會有一個相應的結(jié)構(gòu)體來描述,spi_master 就是用來描述 SPI 主機控制器驅(qū)動的,其主要成員是bus_num,cs,spi 模式和時鐘設(shè)置用到的函數(shù),數(shù)據(jù)傳輸用到的函數(shù)等南誊。一個 master 對應一個 spi 總線,或者說是一個 spi 接口:

struct spi_master {

struct device ? dev;

s16 ? ? ? ? bus_num; //表示是SPI主機控制器的編號身诺。由平臺代碼決定

u16 ? ? ? ? num_chipselect;?//控制器支持的片選數(shù)量,即能支持多少個spi設(shè)備

int ? ? ? ? (*setup)(struct spi_device *spi);?//針對設(shè)備設(shè)置SPI的工作時鐘及數(shù)據(jù)傳輸模式等抄囚。在spi_add_device函數(shù)中調(diào)用霉赡。

int ? ? ? ? (*transfer)(struct spi_device *spi,?struct spi_message *mesg);?//實現(xiàn)數(shù)據(jù)的雙向傳輸,可能會睡眠

void ? ? ? (*cleanup)(struct spi_device *spi);?//注銷時調(diào)用

};

? ? ? ?SPI主機驅(qū)動中分配幔托、注冊和注銷 SPI 主機驅(qū)動結(jié)構(gòu)體將調(diào)用spi核心層API:?spi_alloc_master();?spi_register_master();?spi_unregister_master();

實際上在master的驅(qū)動中實現(xiàn)的就是spi_master中的初始化以及注冊穴亏,其中最重要的就是transfer和setup這兩個操作的實現(xiàn)。spi每次數(shù)據(jù)傳輸最終調(diào)用到的函數(shù)就是這里的transfer重挑。該函數(shù)就對應著實際硬件上寄存器的控制嗓化。setup同理。

? ? ? ?這里可能會有疑問,spi master controller 注冊對應的驅(qū)動框架里的哪一層?按說,spi 主機控制器已經(jīng)作為 platform 設(shè)備都注冊過了谬哀。這里就需要用驅(qū)動設(shè)計里面的分層思想來解釋刺覆。使用到 platform 總線 API 注冊到 platform總線上的控制器設(shè)備和驅(qū)動,都是 common 的部分。specific 的部分,會在 platform driver注冊后,在 probe 函數(shù)里面基于注冊的 common 部分的資源信息來具體實現(xiàn)史煎。稱之為spi_master 的注冊部分谦屑。

4.2驳糯、spi從機slave

? ? ? ?依附于spi總線的驅(qū)動都會有一個spi_driver結(jié)構(gòu)體來描述,結(jié)構(gòu)體中定義對應的操作函數(shù)指針:

struct spi_driver {

? ? int ? ? ? ? (*probe)(struct spi_device *spi);

? ? int ? ? ? ? (*remove)(struct spi_device *spi);

? ? void ? ? ? (*shutdown)(struct spi_device *spi);

? ? int ? ? ? ? (*suspend)(struct spi_device *spi, pm_message_t mesg);

? ? int ? ? ? ? (*resume)(struct spi_device *spi);

? ? struct device_driver ? ?driver;

};

? ? ? ?依附于spi總線的設(shè)備都會有一個spi_device結(jié)構(gòu)體來描述氢橙,結(jié)構(gòu)中定義了設(shè)備的片選酝枢、模式、速率以及對應主機驅(qū)動的spi_master等悍手。

struct spi_device {

? ? struct device ? ? ? dev;

? ? struct spi_master ? *master;

? ? u32 ? ? ? ? max_speed_hz;

? ? u8 ? ? ? ? ?chip_select;

? ? u8 ? ? ? ? ?mode;

#define SPI_CPHA ? ?0x01 ? ? ? ? ? ?/* clock phase */

#define SPI_CPOL ? ?0x02 ? ? ? ? ? ?/* clock polarity */

#define SPI_MODE_0 ?(0|0) ? ? ? ? ? /* (original MicroWire) */

#define SPI_MODE_1 ?(0|SPI_CPHA)

#define SPI_MODE_2 ?(SPI_CPOL|0)

#define SPI_MODE_3 ?(SPI_CPOL|SPI_CPHA)

#define SPI_CS_HIGH 0x04 ? ? ? ? ? ?/* chipselect active high? */

#define SPI_LSB_FIRST ? 0x08 ? ? ? ? ? ?/* per-word bits-on-wire */

#define SPI_3WIRE ? 0x10 ? ? ? ? ? ?/* SI/SO signals shared */

#define SPI_LOOP ? ?0x20 ? ? ? ? ? ?/* loopback mode */

? ? u8 ? ? ? ? ?bits_per_word;

? ? int ? ? ? ? irq;

? ? void ? ? ? ? ? ?*controller_state;

? ? void ? ? ? ? ? ?*controller_data;

? ? char ? ? ? ? ? ?modalias[32];

};

? ? ? ?依附于Spi總線的設(shè)備驅(qū)動對應的總線類型為spi_bus_type帘睦,在內(nèi)核的drivers/spi/spi.c中定義。

struct bus_type spi_bus_type = {?

? ? .name ? ? ? = "spi",

? ? .dev_attrs ?= spi_dev_attrs,

? ? .match ? ? ?= spi_match_device,

? ? .uevent ? ? = spi_uevent,

? ? .suspend ? ?= spi_suspend,

? ? .resume ? ? = spi_resume,

};

EXPORT_SYMBOL_GPL(spi_bus_type);

? ? ? ?而具體的spi外設(shè)信息linux spi 用 struct spi_board_info來描述谓苟,該結(jié)構(gòu)體包含外設(shè)的片選號官脓、總線號、模式以及傳輸速率等信息涝焙。在系統(tǒng)初始化時將會調(diào)用spi_register_board_info()來注冊硬件信息卑笨。

? ? ? ?spi設(shè)備驅(qū)動將會調(diào)用spi_register_driver();來注冊一個spi_driver驅(qū)動,注冊時最終會調(diào)用spi_bus_type中的match來使spi_driver和spi_device相匹配仑撞。設(shè)備驅(qū)動spi_driver是在驅(qū)動里定義的赤兴,但是spi_device呢?事實上上文提到的spi_master的注冊會在spi_register_board_info之后隧哮,spi_master注冊的過程中會調(diào)用scan_boardinfo掃描board_list桶良,找到掛接在它上面的spi設(shè)備,然后創(chuàng)建并注冊spi_device沮翔。

5陨帆、LINUX SPI 控制器設(shè)備和驅(qū)動:

? ? ? ?在嵌入式系統(tǒng)中,一般處理器中都集成了spi控制器采蚀。該控制器一般都為master疲牵。以下分析spi控制器master驅(qū)動。

? ? ? ?由設(shè)備模型可知榆鼠,spi控制器的設(shè)備和驅(qū)動是要掛在總線上的纲爸。所以spi控制器驅(qū)動用到了platform虛擬總線。spi控制器platform設(shè)備在BSP的初始化中被注冊妆够,驅(qū)動一般放在driver/spi/下识啦。

如,在 BSP 文件中添加相應的資源代碼:

通常,會在 arch/***/mach-***/xxxx.c 中添加神妹,例如:

static struct platform_device ***_spi_pdev1 = {

.name = “***_spi”,

.id = 1,

.resource = ***_spi_resources1,

.num_resources = ARRAY_SIZE(***_spi_resources1),

.dev = {

.platform_data = &***_spi_pdata1,

},

};

然后會在 BSP 的 init 過程中使用 platform_device_register 將它注冊進系統(tǒng)颓哮。若片上有n個spi控制器,可以在此定義n個platform_device鸵荠。注冊成功后即可在sys/bus/platform/devices下看到對應的***_spi.n题翻。

spi控制器驅(qū)動代碼init時調(diào)用platform_driver_register:

static int __init xxxx_spi_init(void)

{

? ? return platform_driver_register(&xxxx_spi_driver); //注冊spi驅(qū)動器的platform驅(qū)動

}

注冊成功后即可在sys/bus/platform/drivers下看到對應的***_spi。

platform_driver和platform_device匹配后,會調(diào)用驅(qū)動中的***_probe嵌赠。然后根據(jù)傳入的platform_device參數(shù)塑荒,構(gòu)建一個用于描述SPI控制器的結(jié)構(gòu)體spi_master,并注冊姜挺。spi_register_master(master)齿税。后續(xù)注冊的spi_device需要選定自己的spi_master,并利用spi_master提供的傳輸功能傳輸spi數(shù)據(jù)炊豪。

? ? ? ?仔細瀏覽代碼可以發(fā)現(xiàn),在 SPI 向 platform 總線注冊的時候,象 platform_device 中的device_data 或 driver_data 都是空的,并沒有將它賦值,這些都是在 probe 函數(shù)中完成的凌箕。

? ? ? ?在probe 函數(shù)里面的數(shù)據(jù)結(jié)構(gòu)的設(shè)計和代碼都是按照驅(qū)動框架的要求來實現(xiàn)的,主要包括 spi controller memory 的映射,IRQ 的注冊,controller 的 reset 和對 register 進行初始化賦值。調(diào)用spi_alloc_master分配spi_master設(shè)備词渤,對spi_master進行賦值等牵舱。最后,它將調(diào)用 spi_bitbang_start()來創(chuàng)建一個 work queue,由此 SPI 設(shè)備驅(qū)動可以向這個工作隊列注冊 transfer 方法。

? ? ? ?接下來就得實現(xiàn)spi_master結(jié)構(gòu)中的transfer缺虐、setup芜壁、cleanup及中斷處理等的方法。

6高氮、LINUX SPI 外設(shè)驅(qū)動:

? ? ? ?不同的spi外設(shè)在spi總線通信上的需求不盡相同慧妄,比如模式、時鐘速率剪芍、片選腳等等塞淹。這些跟具體硬件相關(guān)的信息都用spi_board_info來描述。在系統(tǒng)初始化時調(diào)用spi_register_board_info來將板上所有的外設(shè)注冊到board_list鏈表上罪裹。

以m25p80為參考:

在S5PC100對應的m25p10 BSP代碼中:

static struct spi_board_info s3c_spi_devs[] __initdata = {

? ? ? ? ? ? ? ? {

? ? ? ? ? ? ? ? ? ? ? ? .modalias ?= "m25p10",?

? ? ? ? ? ? ? ? ? ? ? ? .mode = SPI_MODE_0, ? ?//CPOL=0, CPHA=0 此處選擇具體數(shù)據(jù)傳輸模式

? ? ? ? ? ? ? ? ? ? ? ? .max_speed_hz = 10000000, ? ?//最大的spi時鐘頻率

? ? ? ? ? ? ? ? ? ? ? ? /* Connected to SPI-0 as 1st Slave */

? ? ? ? ? ? ? ? ? ? ? ? .bus_num ?= 0, ? ?//設(shè)備連接在spi控制器0上

? ? ? ? ? ? ? ? ? ? ? ? .chip_select ?= 0, ? ?//片選線號饱普,在S5PC100的控制器驅(qū)動中沒有使用它作為片選的依據(jù),而是選擇了下文controller_data里的方法状共。

? ? ? ? ? ? ? ? ? ? ? ? .controller_data = &smdk_spi0_csi[0],

? ? ? ? ? ? ? ? },

? ? ? ? };

在這可以看到對m25p10這塊flash芯片的spi通信模式等的初始化套耕。注意spi_board_info結(jié)構(gòu)中的modalias元素,在這的名字應和對應的spi設(shè)備驅(qū)動中spi_driver里的driver的name一致口芍。因為spi_driver和spi_device在總線匹配時會對比這個名字箍铲,一樣則匹配成功雇卷。

? ? ? ? static struct s3c64xx_spi_csinfo smdk_spi0_csi[] = {

? ? ? ? ? ? ? ? [0] = {

? ? ? ? ? ? ? ? ? ? ? ? .set_level = smdk_m25p10_cs_set_level,

? ? ? ? ? ? ? ? ? ? ? ? .fb_delay = 0x3,

? ? ? ? ? ? ? ? },

? ? ? ? };

? ? ? ? static void smdk_m25p10_cs_set_level(int high) ? ?//spi控制器會用這個方法設(shè)置cs

? ? ? ? {

? ? ? ? ? ? ? ? u32 val;

? ? ? ? ? ? ? ? val = readl(S5PC1XX_GPBDAT);

? ? ? ? ? ? ? ? if (high)

? ? ? ? ? ? ? ? ? ? ? ? val |= (1<<3);//拉高片選腳

? ? ? ? ? ? ? ? else

? ? ? ? ? ? ? ? ? ? ? ? val &= ~(1<<3);//拉低片選腳

? ? ? ? ? ? ? ? writel(val, S5PC1XX_GPBDAT);

? ? ? ? }

spi的片選腳是可配置的鬓椭,smdk_m25p10_cs_set_level()會被master控制器驅(qū)動調(diào)用,用來使能外設(shè)关划。

? ? ? ?spi_register_board_info(s3c_spi_devs, ARRAY_SIZE(s3c_spi_devs));//注冊spi_board_info小染。這個代碼會把spi_board_info注冊要鏈表board_list上。

以linux內(nèi)核中的/driver/mtd/devices/m25p80.c驅(qū)動為參考贮折。

static struct spi_driver m25p80_driver = { //spi_driver的構(gòu)建

? ? ? ? ? ? ? ? .driver = {

? ? ? ? ? ? ? ? ? ? ? ? .name = "m25p80",

? ? ? ? ? ? ? ? ? ? ? ? .bus = &spi_bus_type,

? ? ? ? ? ? ? ? ? ? ? ? .owner = THIS_MODULE,

? ? ? ? ? ? ? ? },

? ? ? ? ? ? ? ? .probe = m25p_probe,

? ? ? ? ? ? ? ? .remove = __devexit_p(m25p_remove),

? ? ? ? ? ? ? ? */

? ? ? ? };

spi_register_driver(&m25p80_driver);//spi driver的注冊

在有匹配的spi device時裤翩,會調(diào)用m25p_probe

static int __devinit m25p_probe(struct spi_device *spi)

? ? ? ? {

? ? ? ? ? ? ? ? ……

? ? ? ? }

根據(jù)傳入的spi_device參數(shù),可以找到對應的spi_master。接下來就可以利用spi子系統(tǒng)為我們完成數(shù)據(jù)交互了踊赠『强福可以參看m25p80_read函數(shù)。要完成傳輸筐带,先理解下面幾個結(jié)構(gòu)的含義:(這兩個結(jié)構(gòu)的定義及詳細注釋參見include/linux/spi/spi.h)

? ? ? ? spi_message:描述一次完整的傳輸今穿,即cs信號從高->底->高的傳輸

? ? ? ? spi_transfer:多個spi_transfer夠成一個spi_message

? ? ? ? 舉例說明:m25p80的讀過程如下圖

可以分解為兩個spi_ transfer一個是寫命令,另一個是讀數(shù)據(jù)伦籍。具體實現(xiàn)參見m25p80.c中的m25p80_read函數(shù)蓝晒。下面內(nèi)容摘取之此函數(shù)。

struct spi_transfer t[2]; ? ?//定義了兩個spi_transfer

? ? ? ? struct spi_message m; ? ? //定義了兩個spi_message

? ? ? ? spi_message_init(&m); ? ? //初始化其transfers鏈表

t[0].tx_buf = flash->command;

? ? ? ? t[0].len = CMD_SIZE + FAST_READ_DUMMY_BYTE; ? ? //定義第一個transfer的寫指針和長度

? ? ? ? spi_message_add_tail(&t[0], &m); ? ?//添加到spi_message

? ? ? ? t[1].rx_buf = buf;

? ? ? ? t[1].len = len; ? ? //定義第二個transfer的讀指針和長度

spi_message_add_tail(&t[1], &m); ? ? //添加到spi_message

? ? ? ? flash->command[0] = OPCODE_READ;

? ? ? ? flash->command[1] = from >> 16;

? ? ? ? flash->command[2] = from >> 8;

? ? ? ? flash->command[3] = from; ? ?//初始化前面寫buf的內(nèi)容

spi_sync(flash->spi, &m); ? ? //調(diào)用spi_master發(fā)送spi_message

// spi_sync為同步方式發(fā)送帖鸦,還可以用spi_async異步方式芝薇,那樣的話,需要設(shè)置回調(diào)完成函數(shù)作儿。

另外你也可以選擇一些封裝好的更容易使用的函數(shù)洛二,這些函數(shù)可以在include/linux/spi/spi.h文件中找到,如:

extern int spi_write_then_read(struct spi_device *spi, const u8 *txbuf, unsigned n_tx, u8 *rxbuf, unsigned n_rx);

? ? ? ?對于 SPI 的設(shè)備驅(qū)動,得益于 linux driver framework 設(shè)計者的功勞,這里我們只需要用到 spi.h 中定義的方法就可以了,不用去修改 spi 控制器的代碼立倍。一般的,我們的設(shè)備驅(qū)動框架是使用 spi_regiser_driver 向系統(tǒng)進行注冊,就可以讓系統(tǒng)用你指定的與.name 相匹配的硬件交互并執(zhí)行你的讀寫請求,滿足分離的思想灭红。

7、linux spi 通用驅(qū)動spidev.c

? ? ? ?/driver/spi/spidev.c是linux內(nèi)核提供的一個spi通用驅(qū)動口注。如果不想寫具體的spi芯片驅(qū)動变擒,使用這個驅(qū)動能給我們帶來很多便利,非常方便寝志。在內(nèi)核代碼下的Documentation/spi/spidev是對spidev的描述娇斑。其中還提供一個spidev_test.c的測試程序。

? ? ? ?使用很簡單材部,只要在你的BSP代碼中將spi_board_info的modalias定義為.modalias ? ?= "spidev"毫缆,這樣設(shè)備啟動后就可以在/dev看到spidev0.0字樣. 0.0 就是bus_num.chip_select(對應BSP中的設(shè)置)

? ? ? ?spidev注冊成字符設(shè)備,可以方便的使用其提供的標準read/write/ioctl功能函數(shù)對設(shè)備進行讀寫設(shè)置操作乐导。設(shè)備的全雙工半雙工都得以實現(xiàn)苦丁。具體使用可以細看spidev.c或借鑒spidev_test.c

下圖是驅(qū)動加載成功后,sys目錄下的主要結(jié)構(gòu)物臂,由于目錄非常復雜僅僅列出了主要的結(jié)構(gòu)sys目錄下spi子系統(tǒng)結(jié)構(gòu):

linux下的設(shè)備模型包括幾個主要的概念

sysfs?(dev是用戶空間接口旺拉,根據(jù)sysfs下的class目錄由mdev負責建立)

bus總線,linux下的設(shè)備都是建立在總線上的棵磷,platform總線是一個虛擬的總線蛾狗,所有的的片上設(shè)備基本上都接在這個虛擬總線上device是設(shè)備

device_driver是設(shè)備驅(qū)動class是類別,從功能角度對設(shè)備進行分類仪媒。

注意沉桌,在sys/bus目錄下有platform目錄和spi目錄

這兩個目錄下面的設(shè)備分別代表什么呢?

platform下的設(shè)備有s3c64xx-spi0和s3c64xx-spi1分別對應了s3c6410上的spi0和spi1接口。

參考:

? ? ? ? ? ?http://www.embedu.org/Column/Column367.htm

? ? ? ? ? ?http://www.linuxidc.com/Linux/2011-11/46656.htm

http://www.arm9home.net/read.php?tid=10788等

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末留凭,一起剝皮案震驚了整個濱河市佃扼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蔼夜,老刑警劉巖松嘶,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異挎扰,居然都是意外死亡翠订,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門遵倦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尽超,“玉大人,你說我怎么就攤上這事梧躺∷扑” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵掠哥,是天一觀的道長巩踏。 經(jīng)常有香客問我,道長续搀,這世上最難降的妖魔是什么塞琼? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮禁舷,結(jié)果婚禮上彪杉,老公的妹妹穿的比我還像新娘。我一直安慰自己牵咙,他們只是感情好派近,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著洁桌,像睡著了一般渴丸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上另凌,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天谱轨,我揣著相機與錄音,去河邊找鬼途茫。 笑死碟嘴,一個胖子當著我的面吹牛溪食,可吹牛的內(nèi)容都是我干的囊卜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼栅组!你這毒婦竟也來了雀瓢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤玉掸,失蹤者是張志新(化名)和其女友劉穎刃麸,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體司浪,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡泊业,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了啊易。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吁伺。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖租谈,靈堂內(nèi)的尸體忽然破棺而出篮奄,到底是詐尸還是另有隱情,我是刑警寧澤割去,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布烁涌,位于F島的核電站静汤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜仗扬,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望籍滴。 院中可真熱鬧执庐,春花似錦、人聲如沸酒繁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽州袒。三九已至揭绑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間郎哭,已是汗流浹背他匪。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夸研,地道東北人邦蜜。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像亥至,于是被迫代替她去往敵國和親悼沈。 傳聞我的和親對象是個殘疾皇子贱迟,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容