轉(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等