Linux驅動修煉之道-SPI驅動框架原始碼分析(中)
來自:http://blog.csdn.net/woshixingaaa/article/details/6574220
這篇來分析spi子系統的建立過程。
嵌入式微處理器訪問SPI裝置有兩種方式:使用GPIO模擬SPI介面的工作時序或者使用SPI控制器。使用GPIO模擬SPI介面的工作時序是非常容易實現的,但是會導致大量的時間耗費在模擬SPI介面的時序上,訪問效率比較低,容易成為系統瓶頸。這裡主要分析使用SPI控制器的情況。
這個是由sys檔案系統匯出的spi子系統在核心中的檢視了。
首先了解一下Linux核心中的幾個檔案:spi.c也就是spi子系統的核心了,spi_s3c24xx.c是s3c24xx系列晶片的SPI controller驅動,它向更上層的SPI核心層(spi.c)提供介面用來控制晶片的SPI controller,是一個被其他驅動使用的驅動。而spidev.c是在核心層基礎之上將SPI controller模擬成一個字元型的驅動,向檔案系統提供標準的檔案系統介面,用來操作對應的SPI
controller。
下面我們來看看spi子系統是怎麼註冊進核心的:
- staticint __init spi_init(void)
- {
- int status;
- buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
- if (!buf) {
- status = -ENOMEM;
- goto err0;
- }
- status = bus_register(&spi_bus_type);
- if (status < 0)
-
goto
- status = class_register(&spi_master_class);
- if (status < 0)
- goto err2;
- return 0;
- err2:
- bus_unregister(&spi_bus_type);
- err1:
- kfree(buf);
- buf = NULL;
- err0:
- return status;
- }
- postcore_initcall(spi_init);
這裡註冊了一個spi_bus_type,也就是一個spi匯流排,和一個spi_master的class。分別對應上圖中sys/bus/下的spi目錄和sys/class/下的spi_master目錄。
下面來分析SPI controller驅動的註冊與初始化過程,首先執行的是s3c24xx_spi_init。
- staticint __init s3c24xx_spi_init(void)
- {
- return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);
- }
platform_driver_probe中完成了s3c24xx_spi_driver這個平臺驅動的註冊,相應的平臺裝置在devs.c中定義,在smdk2440_devices中新增&s3c_device_spi0,&s3c_device_spi1,這就生成了圖中所示的s3c24xx-spi.0與s3c24xx-spi.1,當然了這圖是在網上找的,不是我畫的,所以是6410的。這裡s3c24xx-spi.0表示s3c2440的spi controller的0號介面,s3c24xx-spi.1表示s3c2440的spi controller的1號介面。註冊了s3c24xx_spi_driver後,賦值了平臺驅動的probe函式為s3c24xx_spi_probe。所以當match成功後,呼叫s3c24xx_spi_probe,這裡看其實現:
- staticint __init s3c24xx_spi_probe(struct platform_device *pdev)
- {
- struct s3c2410_spi_info *pdata;
- struct s3c24xx_spi *hw;
- struct spi_master *master;
- struct resource *res;
- int err = 0;
- /*分配struct spi_master+struct s3c24xx_spi大小的資料,把s3c24xx_spi設為spi_master的私有資料*/
- master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
- if (master == NULL) {
- dev_err(&pdev->dev, "No memory for spi_master\n");
- err = -ENOMEM;
- goto err_nomem;
- }
- /*從master中獲得s3c24xx_spi*/
- hw = spi_master_get_devdata(master);
- memset(hw, 0, sizeof(struct s3c24xx_spi));
- hw->master = spi_master_get(master);
- /*驅動移植的時候需要實現的重要結構,初始化為&s3c2410_spi0_platdata*/
- hw->pdata = pdata = pdev->dev.platform_data;
- hw->dev = &pdev->dev;
- if (pdata == NULL) {
- dev_err(&pdev->dev, "No platform data supplied\n");
- err = -ENOENT;
- goto err_no_pdata;
- }
- /*設定平臺的私有資料為s3c24xx_spi*/
- platform_set_drvdata(pdev, hw);
- init_completion(&hw->done);
- /* setup the master state. */
- /*該總線上的裝置數*/
- master->num_chipselect = hw->pdata->num_cs;
- /*匯流排號*/
- master->bus_num = pdata->bus_num;
- /* setup the state for the bitbang driver */
- /*spi_bitbang專門負責資料的傳輸*/
- hw->bitbang.master = hw->master;
- hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
- hw->bitbang.chipselect = s3c24xx_spi_chipsel;
- hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
- hw->bitbang.master->setup = s3c24xx_spi_setup;
- dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
- 。。。。。。。。。。。。。。。。。。。。。。。。
- /*初始化設定暫存器,包括對SPIMOSI,SPIMISO,SPICLK引腳的設定*/
- s3c24xx_spi_initialsetup(hw);
- /* register our spi controller */
- err = spi_bitbang_start(&hw->bitbang);
- 。。。。。。。。。。。。。。。。。。。。。
- }
- spi controller的register在spi_bitbang_start函式中實現:
- int spi_bitbang_start(struct spi_bitbang *bitbang)
- {
- int status;
- if (!bitbang->master || !bitbang->chipselect)
- return -EINVAL;
- /*動態建立一個work_struct結構,它的處理函式是bitbang_work*/
- INIT_WORK(&bitbang->work, bitbang_work);
- spin_lock_init(&bitbang->lock);
- INIT_LIST_HEAD(&bitbang->queue);
- /*spi的資料傳輸就是用這個方法*/
- if (!bitbang->master->transfer)
- bitbang->master->transfer = spi_bitbang_transfer;
- if (!bitbang->txrx_bufs) {
- bitbang->use_dma = 0;
- /*spi_s3c24xx.c中有spi_bitbang_bufs方法,在bitbang_work中被呼叫*/
- bitbang->txrx_bufs = spi_bitbang_bufs;
- if (!bitbang->master->setup) {
- if (!bitbang->setup_transfer)
- bitbang->setup_transfer =
- spi_bitbang_setup_transfer;
- /*在spi_s3c24xx.c中有setup的處理方法,在spi_new_device中被呼叫*/
- bitbang->master->setup = spi_bitbang_setup;
- bitbang->master->cleanup = spi_bitbang_cleanup;
- }
- } elseif (!bitbang->master->setup)
- return -EINVAL;
- /* this task is the only thing to touch the SPI bits */
- bitbang->busy = 0;
- /呼叫create_singlethread_workqueue建立單個工作執行緒/
- bitbang->workqueue = create_singlethread_workqueue(
- dev_name(bitbang->master->dev.parent));
- if (bitbang->workqueue == NULL) {
- status = -EBUSY;
-
相關推薦
Linux驅動修煉之道-SPI驅動框架原始碼分析(中-續)
然後看這裡是怎樣註冊spi主機控制器驅動的: int spi_register_master(struct spi_master *master) { 。。。。。。。。。。。。。。。。 /*將spi新增到核心,這
Linux驅動修煉之道-SPI驅動框架原始碼分析(中)
來自:http://blog.csdn.net/woshixingaaa/article/details/6574220 這篇來分析spi子系統的建立過程。 嵌入式微處理器訪問SPI裝置有兩種方式:使用GPIO模擬SPI介面的工作時序或者使用SPI控制
Linux驅動修煉之道-SPI驅動框架原始碼分析(上)
SPI驅動架構,以前用過,不過沒這個詳細,跟各位一起分享: 來自:http://blog.csdn.net/woshixingaaa/article/details/6574215 SPI協議是一種同步的序列資料連線標準,由摩托羅拉公司命名,可工作於全雙工模式。相
Linux驅動修煉之道-SPI驅動框架原始碼分析(下-續)
spi_async在spi.h中定義的: <span style="font-size:18px;">staticinlineint spi_async(struct spi_device *spi, struct spi_mess
Linux驅動修煉之道-DM9000A網絡卡驅動框架原始碼分析
網路裝置的初始化: 通過模組的載入函式看出DM9000A的驅動是以平臺驅動的形式註冊進核心的,下邊是模組的載入函式: 1.static int __init 2.dm9000_init(void) 2.{ 3. printk(KERN_INFO "%
Linux驅動修煉之道-DMA框架原始碼分析(下)
static irqreturn_t s3c2410_dma_irq(int irq, void *devpw) { struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw; struct s3c2410_dma_buf *buf
Linux驅動修煉之道-DMA框架原始碼分析
DMA使用3個狀態的有限狀態機: 1.初始狀態,DMA等待DMA請求,一旦請求到達DMA進入狀態2,DMA ACK與INT REQ為0。 2.在這個狀態,DMA ACK置為1並且計數器CURR_TC的值被從DCON[19:0]載入,注意DMA ACK保持為1直到它被清除。 3.在這個狀態,處理DMA原子
Linux驅動修煉之道
一些學習Linux驅動的筆記整理在這裡與大家分享,如果那裡有錯誤也請高手指出。若干年後能進入INTEL開源中心或IBM搞linux kernel是我目前的目標。君子藏器於身,待時而動。文章連載,不斷更新中。
linux驅動修煉之道-混雜裝置
Linux驅動中把無法歸類的五花八門的裝置定義為混雜裝置(用miscdevice結構體表述)。miscdevice共享一個主裝置號MISC_MAJOR(即10),但次裝置號不同。 所有的miscdevice裝置形成了一個連結串列,對裝置訪問時核心根據次裝置號查詢對應的mi
Java修煉之道--集合框架
前言 Java集合框架 (Java Collections Framework, JCF) 也稱容器,這裡可以類比 C++ 中的 STL,在市面上似乎還沒能找到一本詳細介紹的書籍。在這裡主要對如下部分進行原始碼分析,及在面試中常見的問題。 例如,在阿里面試常
⑳tiny4412 Linux驅動開發之MMC子系統驅動程式
本次我們來說一下SDIO子系統的控制器的開發部分,這部分也是和硬體平臺相關的,在說這個之前,我們先來了解一下相關硬體的基礎知識和概念. MMC MMC全稱MultiMedia Card,由西門子公司和SanDisk公司1997年推出的多媒體記憶卡標準。MMC卡尺寸為32mm
Linux 裝置驅動篇之-------I2c裝置驅動(待續)
Linux 裝置驅動篇之-------I2c裝置驅動 雖然I2C硬體體系結構和協議都很容易理解,但是Linux I2C驅動體系結構卻有相當的複雜度,它主要由3部分組成,即I2C裝置驅動、I2C匯流
SQL優化三板斧:精簡之道、驅動為王、集合為本
作者介紹 黃浩,現任職於中國惠普,從業十年,始終專注於SQL。在華為做專案的兩年多,做過大大小小的SQL多達1500個。閒暇之餘,喜歡將部分案例寫成部落格發表在華為內部資料庫官方社群,反響強烈,已連續四個月蟬聯該社群最佳博主。目前已開設專欄“優哉悠齋”,成為首個受邀社群“專家訪談”的外協人員。 公元
Linux裝置模型之tty&&uart驅動架構分析
五: uart_add_one_port()操作 在前面提到.在對uart裝置檔案過程中.會將操作轉換到對應的port上,這個port跟uart_driver是怎麼關聯起來的呢?這就是uart_add_ont_port()的主要工作了. 顧名思義,這個函式是在uart_driver增加一個port.程式碼如
Linux 裝置驅動篇之I2c裝置驅動
Linux 裝置驅動篇之I2c裝置驅動fulinux一、I2C驅動體系雖然I2C硬體體系結構和協議都很容易理解,但是Linux I2C驅動體系結構卻有相當的複雜度,它主要由3部分組成,即I2C裝置驅動、
linux spi驅動開發學習(四)-----spi驅動程式完整流程分析
所有的應用程式使用dev/目錄下建立的裝置,這些字元裝置的操作函式集在檔案spidev.c中實現。 點選(此處)摺疊或開啟 static const struct file_operations spidev_fops = { .owner = THIS
第16章 驅動開發之字元裝置驅動程式框架
16.1 字元裝置驅動程式框架簡介 我們在學習 C 語言的時候,知道每個應用程式的入口函式,即第一個被執行的函式是 main函式,那麼,我們自己的驅動程式,哪個函式是入口函式呢? 在寫驅動程式的時候,如果函式的名字可以任意取,常常為 xxxx_init(),
Spark修煉之道(基礎篇)——Linux大資料開發基礎:第十三節:Shell程式設計入門(五)
本節主要內容 while expression do command command done (1)計數器格式 適用於迴圈次數已知或固定時 root@sparkslave02:~/ShellLearning/Chapter13# vim w
嵌入式Linux裝置驅動開發之:按鍵驅動程式例項
11.6 按鍵驅動程式例項 11.6.1 按鍵工作原理 高電平和低電平相接怎麼會變成低電平呢 就像你把電源正極的負極相連一樣會把電壓拉低。大電流會從高電平引腳流向低電平引腳,把高電平引腳拉低。 LED和蜂鳴器是最簡單的GPIO的應用,都不需要任何外部
Linux運維之道之網絡基礎學習筆記1.1
達內 linux雲計算運維 網絡基礎1.1TCP/IP詳細解讀:TCP/IP協議簡介:TCP/IP是最廣泛支持的通信協議集合---包括大量internet應用中的標準協議;---支持跨網絡架構,跨操作系統平臺的通信;主機與主機之間通信的三個要素:---IP地址;---子網掩碼;---IP路由;IP地址