1. 程式人生 > >Linux驅動修煉之道-SPI驅動框架原始碼分析(中)

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子系統是怎麼註冊進核心的:

  1. staticint __init spi_init(void)  
  2. {  
  3.     int status;  
  4.     buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);  
  5.     if (!buf) {  
  6.         status = -ENOMEM;  
  7.         goto err0;  
  8.     }  
  9.     status = bus_register(&spi_bus_type);  
  10.     if (status < 0)  
  11.         goto
     err1;  
  12.     status = class_register(&spi_master_class);  
  13.     if (status < 0)  
  14.         goto err2;  
  15.     return 0;  
  16. err2:  
  17.     bus_unregister(&spi_bus_type);  
  18. err1:  
  19.     kfree(buf);  
  20.     buf = NULL;  
  21. err0:  
  22.     return status;  
  23. }  
  24. postcore_initcall(spi_init);  

這裡註冊了一個spi_bus_type,也就是一個spi匯流排,和一個spi_master的class。分別對應上圖中sys/bus/下的spi目錄和sys/class/下的spi_master目錄。

下面來分析SPI controller驅動的註冊與初始化過程,首先執行的是s3c24xx_spi_init。

  1. staticint __init s3c24xx_spi_init(void)  
  2. {  
  3.         return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);  
  4. }  

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,這裡看其實現:

  1. staticint __init s3c24xx_spi_probe(struct platform_device *pdev)  
  2. {  
  3.     struct s3c2410_spi_info *pdata;  
  4.     struct s3c24xx_spi *hw;  
  5.     struct spi_master *master;  
  6.     struct resource *res;  
  7.     int err = 0;  
  8.     /*分配struct spi_master+struct s3c24xx_spi大小的資料,把s3c24xx_spi設為spi_master的私有資料*/
  9.     master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));  
  10.     if (master == NULL) {  
  11.         dev_err(&pdev->dev, "No memory for spi_master\n");  
  12.         err = -ENOMEM;  
  13.         goto err_nomem;  
  14.     }  
  15.     /*從master中獲得s3c24xx_spi*/
  16.     hw = spi_master_get_devdata(master);  
  17.     memset(hw, 0, sizeof(struct s3c24xx_spi));  
  18.     hw->master = spi_master_get(master);  
  19.     /*驅動移植的時候需要實現的重要結構,初始化為&s3c2410_spi0_platdata*/
  20.     hw->pdata = pdata = pdev->dev.platform_data;  
  21.     hw->dev = &pdev->dev;  
  22.     if (pdata == NULL) {  
  23.         dev_err(&pdev->dev, "No platform data supplied\n");  
  24.         err = -ENOENT;  
  25.         goto err_no_pdata;  
  26.     }  
  27.     /*設定平臺的私有資料為s3c24xx_spi*/
  28.     platform_set_drvdata(pdev, hw);  
  29.     init_completion(&hw->done);  
  30.     /* setup the master state. */
  31.     /*該總線上的裝置數*/
  32.     master->num_chipselect = hw->pdata->num_cs;  
  33.     /*匯流排號*/
  34.     master->bus_num = pdata->bus_num;  
  35.     /* setup the state for the bitbang driver */
  36.     /*spi_bitbang專門負責資料的傳輸*/
  37.     hw->bitbang.master         = hw->master;  
  38.     hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;  
  39.     hw->bitbang.chipselect     = s3c24xx_spi_chipsel;  
  40.     hw->bitbang.txrx_bufs      = s3c24xx_spi_txrx;  
  41.     hw->bitbang.master->setup  = s3c24xx_spi_setup;  
  42.     dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);  
  43.     。。。。。。。。。。。。。。。。。。。。。。。。  
  44.     /*初始化設定暫存器,包括對SPIMOSI,SPIMISO,SPICLK引腳的設定*/
  45.     s3c24xx_spi_initialsetup(hw);  
  46.     /* register our spi controller */
  47.     err = spi_bitbang_start(&hw->bitbang);  
  48.         。。。。。。。。。。。。。。。。。。。。。  
  49. }  
  50. spi controller的register在spi_bitbang_start函式中實現:  
  51. int spi_bitbang_start(struct spi_bitbang *bitbang)  
  52. {  
  53.     int status;  
  54.     if (!bitbang->master || !bitbang->chipselect)  
  55.         return -EINVAL;  
  56.     /*動態建立一個work_struct結構,它的處理函式是bitbang_work*/
  57.     INIT_WORK(&bitbang->work, bitbang_work);  
  58.     spin_lock_init(&bitbang->lock);  
  59.     INIT_LIST_HEAD(&bitbang->queue);  
  60.     /*spi的資料傳輸就是用這個方法*/
  61.     if (!bitbang->master->transfer)  
  62.         bitbang->master->transfer = spi_bitbang_transfer;  
  63.     if (!bitbang->txrx_bufs) {  
  64.         bitbang->use_dma = 0;  
  65.         /*spi_s3c24xx.c中有spi_bitbang_bufs方法,在bitbang_work中被呼叫*/
  66.         bitbang->txrx_bufs = spi_bitbang_bufs;  
  67.         if (!bitbang->master->setup) {  
  68.             if (!bitbang->setup_transfer)  
  69.                 bitbang->setup_transfer =  
  70.                      spi_bitbang_setup_transfer;  
  71.             /*在spi_s3c24xx.c中有setup的處理方法,在spi_new_device中被呼叫*/
  72.             bitbang->master->setup = spi_bitbang_setup;  
  73.             bitbang->master->cleanup = spi_bitbang_cleanup;  
  74.         }  
  75.     } elseif (!bitbang->master->setup)  
  76.         return -EINVAL;  
  77.     /* this task is the only thing to touch the SPI bits */
  78.     bitbang->busy = 0;  
  79.     /呼叫create_singlethread_workqueue建立單個工作執行緒/  
  80.     bitbang->workqueue = create_singlethread_workqueue(  
  81.             dev_name(bitbang->master->dev.parent));  
  82.     if (bitbang->workqueue == NULL) {  
  83.         status = -EBUSY;  
  84.         

    相關推薦

    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地址