Linux SPI設備驅動框架

轉載出處:http://blog.csdn.net/vanbreaker/article/details/7733476

      

一 、


       Linux的SPI子系統採用主機驅動和外設驅動分離的思想,首先主機SPI控制器是一種平臺設備,因此它以platform的方式註冊進內核,外設的信息是以boardinfo形式靜態定義的,在創建spi_master時,會根據外設的bus_num和主機的bus_num是否相等,來選擇是否將該外設掛接在該SPI主控制器下。先看SPI子系統中幾個關鍵的數據結構:

struct spi_master用來描述一個SPI主控制器

[cpp] view plain copy
  1. struct spi_master {  
  2.     struct device    dev;  
  3.     s16    bus_num; /*總線編號*/  
  4.     u16    num_chipselect;/*支持的外設數量*/  
  5.     u16    dma_alignment;  
  6.     int   (*transfer)(struct spi_device *spi, struct spi_message *mesg);/*用於將消息添加到隊列*/  
  7.     void  (*cleanup)(struct spi_device *spi);  
  8. };  


struct spi_device用來描述一個SPI從設備

[cpp] view plain copy
  1. struct spi_device {  
  2.     struct device       dev;  
  3.     struct spi_master   *master;                 /*從設備所屬的SPI主控器*/  
  4.     u32         max_speed_hz;   /*最大傳輸頻率*/  
  5.     u8          chip_select;    /*片選號,用於區別其他從設備*/  
  6.     u8          mode;           /*傳輸模式*/  
  7. /*各個mode的定義*/  
  8. #define SPI_CPHA    0x01             /* clock phase */  
  9. #define SPI_CPOL    0x02             /* clock polarity */  
  10. #define SPI_MODE_0  (0|0)        /* (original MicroWire) */  
  11. #define SPI_MODE_1  (0|SPI_CPHA)  
  12. #define SPI_MODE_2  (SPI_CPOL|0)  
  13. #define SPI_MODE_3  (SPI_CPOL|SPI_CPHA)  
  14. #define SPI_CS_HIGH 0x04         /* chipselect active high? */  
  15. #define SPI_LSB_FIRST   0x08         /* per-word bits-on-wire */  
  16. #define SPI_3WIRE   0x10             /* SI/SO signals shared */  
  17. #define SPI_LOOP    0x20             /* loopback mode */  
  18.     u8          bits_per_word; /*每個字的比特數*/  
  19.     int         irq;           /*所使用的中斷*/  
  20.     void            *controller_state;  
  21.     void            *controller_data;  
  22.     char            modalias[32];  /*設備名,在和從設備驅動匹配時會用到*/  
  23.   
  24. };  


struct spi_driver用來描述一個SPI從設備的驅動,它的形式和struct platform_driver是一致的

[cpp] view plain copy
  1. struct spi_driver {  
  2.     int         (*probe)(struct spi_device *spi);  
  3.     int         (*remove)(struct spi_device *spi);  
  4.     void            (*shutdown)(struct spi_device *spi);  
  5.     int         (*suspend)(struct spi_device *spi, pm_message_t mesg);  
  6.     int         (*resume)(struct spi_device *spi);  
  7.     struct device_driver    driver;  
  8. };  


SPI子系統初始化的第一步就是將SPI總線註冊進內核,並且在/sys下創建一個spi_master的類,以後註冊的從設備都將掛接在該總線下

[cpp] view plain copy
  1. static int __init spi_init(void)  
  2. {  
  3.     int status;  
  4.   
  5.     buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);  
  6.     if (!buf) {  
  7.         status = -ENOMEM;  
  8.         goto err0;  
  9.     }  
  10.   
  11.     status = bus_register(&spi_bus_type);//註冊SPI總線  
  12.     if (status < 0)  
  13.         goto err1;  
  14.   
  15.     status = class_register(&spi_master_class);//註冊spi_master類  
  16.     if (status < 0)  
  17.         goto err2;  
  18.     return 0;  
  19.   
  20. err2:  
  21.     bus_unregister(&spi_bus_type);  
  22. err1:  
  23.     kfree(buf);  
  24.     buf = NULL;  
  25. err0:  
  26.     return status;  
  27. }  


我們來看spi_bus_type的定義

[cpp] view plain copy
  1. struct bus_type spi_bus_type = {  
  2.     .name       = "spi",  
  3.     .dev_attrs  = spi_dev_attrs,  
  4.     .match      = spi_match_device,  
  5.     .uevent     = spi_uevent,  
  6.     .suspend    = spi_suspend,  
  7.     .resume     = spi_resume,  
  8. };  

來看掛接在SPI總線下的從設備和從設備驅動是如何匹配的,也就是spi_match_device函數

[cpp] view plain copy
  1. static int spi_match_device(struct device *dev, struct device_driver *drv)  
  2. {  
  3.     const struct spi_device *spi = to_spi_device(dev);  
  4.   
  5.     return strcmp(spi->modalias, drv->name) == 0;  
  6. }  


這裏可以看到是將struct device_driver中的name字段與struct spi_device中的modalias字段進行匹配

 

這裏已經完成了SPI子系統初始化的第一步,也就是註冊SPI總線,這一步是和平臺無關的,第二步是和平臺相關的初始化。


二、


       上面介紹了SPI子系統中的一些重要數據結構和SPI子系統初始化的第一步,也就是註冊SPI總線。這節介紹針對於s3c24xx平臺的SPI子系統初始化,在看具體的代碼之前,先上一張自己畫的圖,幫助理清初始化的主要步驟

 

顯然,SPI是一種平臺特定的資源,所以它是以platform平臺設備的方式註冊進內核的,因此它的struct platform_device結構是已經靜態定義好了的,現在只待它的struct platform_driver註冊,然後和platform_device匹配。

 

初始化的入口:

[html] view plain copy
  1. static int __init s3c24xx_spi_init(void)  
  2. {  
  3.         return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);  
  4. }  


platform_driver_probe()會調用platform_driver_register()來註冊驅動,然後在註冊的過程中尋求匹配的platform_device,一旦匹配成功,便會調用probe函數,也就是s3c24xx_spi_probe(),在看這個函數之前,還得介紹幾個相關的數據結構。

struct s3c2410_spi_info是一個板級結構,也是在移植時就定義好的,在初始化spi_master時用到,platform_device-->dev-->platform_data會指向這個結構。

[cpp] view plain copy
  1. struct s3c2410_spi_info {  
  2.     int          pin_cs;    /* simple gpio cs */  
  3.     unsigned int         num_cs;    /* total chipselects */  
  4.     int          bus_num;/* bus number to use. */  
  5.   
  6.     void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);  
  7.     void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);  
  8. };  

 

struct s3c24xx_spi用來具體描述s3c24xx平臺上一個SPI控制器

[cpp] view plain copy
  1. struct s3c24xx_spi {  
  2.     /* bitbang has to be first */  
  3.     struct spi_bitbang   bitbang;  
  4.     struct completion    done;  
  5.   
  6.     void __iomem        *regs;  
  7.     int          irq;  
  8.     int          len;  
  9.     int          count;  
  10.   
  11.     void            (*set_cs)(struct s3c2410_spi_info *spi,  
  12.                       int cs, int pol);  
  13.   
  14.     /* data buffers */  
  15.     const unsigned char *tx;  
  16.     unsigned char       *rx;  
  17.   
  18.     struct clk      *clk;  
  19.     struct resource     *ioarea;  
  20.     struct spi_master   *master;  
  21.     struct spi_device   *curdev;  
  22.     struct device       *dev;  
  23.     struct s3c2410_spi_info *pdata;  
  24. };  


struct spi_bitbang用於控制實際的數據傳輸

[cpp] view plain copy
  1. struct spi_bitbang {  
  2.     struct workqueue_struct *workqueue;  /*工作隊列*/  
  3.     struct work_struct  work;  
  4.   
  5.     spinlock_t      lock;  
  6.     struct list_head    queue;  
  7.     u8          busy;  
  8.     u8          use_dma;  
  9.     u8          flags;      /* extra spi->mode support */  
  10.   
  11.     struct spi_master   *master;         /*bitbang所屬的master*/  
  12.   
  13.      /*用於設置設備傳輸時的時鐘,字長等*/  
  14.     int (*setup_transfer)(struct spi_device *spi,  
  15.             struct spi_transfer *t);  
  16.   
  17.     void    (*chipselect)(struct spi_device *spi, int is_on);  
  18. #define BITBANG_CS_ACTIVE   1   /* normally nCS, active low */  
  19. #define BITBANG_CS_INACTIVE 0  
  20.   
  21.     /*針對於平臺的傳輸控制函數*/  
  22.     int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);  
  23.   
  24.     /* txrx_word[SPI_MODE_*]() just looks like a shift register */  
  25.     u32 (*txrx_word[4])(struct spi_device *spi,  
  26.             unsigned nsecs,  
  27.             u32 word, u8 bits);  
  28. };  

 

下面來看s3c24xx_spi_probe()函數的實現

[cpp] view plain copy
  1. static int __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.   
  9.     /*創建spi_master,並將spi_master->private_data指向s3c24xx_spi*/  
  10.     master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));  
  11.     if (master == NULL) {  
  12.         dev_err(&pdev->dev, "No memory for spi_master\n");  
  13.         err = -ENOMEM;  
  14.         goto err_nomem;  
  15.     }  
  16.   
  17.     hw = spi_master_get_devdata(master);//獲取s3c24xx_spi  
  18.     memset(hw, 0, sizeof(struct s3c24xx_spi));  
  19.   
  20.     hw->master = spi_master_get(master);  
  21.     hw->pdata = pdata = pdev->dev.platform_data;  
  22.     hw->dev = &pdev->dev;  
  23.   
  24.     if (pdata == NULL) {  
  25.         dev_err(&pdev->dev, "No platform data supplied\n");  
  26.         err = -ENOENT;  
  27.         goto err_no_pdata;  
  28.     }  
  29.   
  30.     platform_set_drvdata(pdev, hw);  
  31.     init_completion(&hw->done);  
  32.   
  33.     /* setup the master state. */  
  34.          /*片選數和SPI主控制器編號是在platform_data中已經定義好了的*/  
  35.     master->num_chipselect = hw->pdata->num_cs;  
  36.     master->bus_num = pdata->bus_num;  
  37.   
  38.     /* setup the state for the bitbang driver */  
  39.   
  40.     /*設置bitbang的所屬master和控制傳輸的相關函數*/  
  41.     hw->bitbang.master         = hw->master;  
  42.     hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;  
  43.     hw->bitbang.chipselect     = s3c24xx_spi_chipsel;  
  44.     hw->bitbang.txrx_bufs      = s3c24xx_spi_txrx;  
  45.     hw->bitbang.master->setup  = s3c24xx_spi_setup;  
  46.   
  47.     dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);  
  48.   
  49.     /* find and map our resources */  
  50.   
  51.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  52.     if (res == NULL) {  
  53.         dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");  
  54.         err = -ENOENT;  
  55.         goto err_no_iores;  
  56.     }  
  57.   
  58.     hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1,  
  59.                     pdev->name);  
  60.   
  61.     if (hw->ioarea == NULL) {  
  62.         dev_err(&pdev->dev, "Cannot reserve region\n");  
  63.         err = -ENXIO;  
  64.         goto err_no_iores;  
  65.     }  
  66.   
  67.     /*映射SPI控制寄存器*/  
  68.     hw->regs = ioremap(res->start, (res->end - res->start)+1);  
  69.     if (hw->regs == NULL) {  
  70.         dev_err(&pdev->dev, "Cannot map IO\n");  
  71.         err = -ENXIO;  
  72.         goto err_no_iomap;  
  73.     }  
  74.   
  75.     /*獲取中斷號*/  
  76.     hw->irq = platform_get_irq(pdev, 0);  
  77.     if (hw->irq < 0) {  
  78.         dev_err(&pdev->dev, "No IRQ specified\n");  
  79.         err = -ENOENT;  
  80.         goto err_no_irq;  
  81.     }  
  82.   
  83.     /*註冊中斷*/  
  84.     err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);  
  85.     if (err) {  
  86.         dev_err(&pdev->dev, "Cannot claim IRQ\n");  
  87.         goto err_no_irq;  
  88.     }  
  89.   
  90.     hw->clk = clk_get(&pdev->dev, "spi");  
  91.     if (IS_ERR(hw->clk)) {  
  92.         dev_err(&pdev->dev, "No clock for device\n");  
  93.         err = PTR_ERR(hw->clk);  
  94.         goto err_no_clk;  
  95.     }  
  96.   
  97.     /* setup any gpio we can */  
  98.   
  99.     if (!pdata->set_cs) {  
  100.         if (pdata->pin_cs < 0) {  
  101.             dev_err(&pdev->dev, "No chipselect pin\n");  
  102.             goto err_register;  
  103.         }  
  104.   
  105.         err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));  
  106.         if (err) {  
  107.             dev_err(&pdev->dev, "Failed to get gpio for cs\n");  
  108.             goto err_register;  
  109.         }  
  110.           
  111.         hw->set_cs = s3c24xx_spi_gpiocs;//設定片選函數  
  112.         gpio_direction_output(pdata->pin_cs, 1);  
  113.     } else  
  114.         hw->set_cs = pdata->set_cs;  
  115.   
  116.     s3c24xx_spi_initialsetup(hw);  
  117.   
  118.     /* register our spi controller */  
  119.          /* 註冊主機SPI控制器 */  
  120.     err = spi_bitbang_start(&hw->bitbang);  
  121.     if (err) {  
  122.         dev_err(&pdev->dev, "Failed to register SPI master\n");  
  123.         goto err_register;  
  124.     }  
  125.   
  126.     return 0;  
  127.   
  128.  err_register:  
  129.     if (hw->set_cs == s3c24xx_spi_gpiocs)  
  130.         gpio_free(pdata->pin_cs);  
  131.   
  132.     clk_disable(hw->clk);  
  133.     clk_put(hw->clk);  
  134.   
  135.  err_no_clk:  
  136.     free_irq(hw->irq, hw);  
  137.   
  138.  err_no_irq:  
  139.     iounmap(hw->regs);  

[cpp] view plain copy
  1. int spi_bitbang_start(struct spi_bitbang *bitbang)  
  2. {  
  3.     int status;  
  4.   
  5.     if (!bitbang->master || !bitbang->chipselect)  
  6.         return -EINVAL;  
  7.   
  8.     /*初始化一個struct work,處理函數爲bitbang_work*/  
  9.     INIT_WORK(&bitbang->work, bitbang_work);  
  10.     spin_lock_init(&bitbang->lock);  
  11.     INIT_LIST_HEAD(&bitbang->queue);  
  12.   
  13.     /*檢測bitbang中的函數是否都定義了,如果沒定義,則默認使用spi_bitbang_xxx*/  
  14.     if (!bitbang->master->transfer)  
  15.         bitbang->master->transfer = spi_bitbang_transfer;  
  16.     if (!bitbang->txrx_bufs) {  
  17.         bitbang->use_dma = 0;  
  18.         bitbang->txrx_bufs = spi_bitbang_bufs;  
  19.         if (!bitbang->master->setup) {  
  20.             if (!bitbang->setup_transfer)  
  21.                 bitbang->setup_transfer =  
  22.                      spi_bitbang_setup_transfer;  
  23.             bitbang->master->setup = spi_bitbang_setup;  
  24.             bitbang->master->cleanup = spi_bitbang_cleanup;  
  25.         }  
  26.     } else if (!bitbang->master->setup)  
  27.         return -EINVAL;  
  28.   
  29.     /* this task is the only thing to touch the SPI bits */  
  30.     bitbang->busy = 0;  
  31.     /*創建bitbang的工作隊列*/  
  32.     bitbang->workqueue = create_singlethread_workqueue(  
  33.             dev_name(bitbang->master->dev.parent));  
  34.     if (bitbang->workqueue == NULL) {  
  35.         status = -EBUSY;  
  36.         goto err1;  
  37.     }  
  38.   
  39.     /* driver may get busy before register() returns, especially 
  40.      * if someone registered boardinfo for devices 
  41.      */  
  42.      /*註冊spi_master*/  
  43.     status = spi_register_master(bitbang->master);  
  44.     if (status < 0)  
  45.         goto err2;  
  46.   
  47.     return status;  
  48.   
  49. err2:  
  50.     destroy_workqueue(bitbang->workqueue);  
  51. err1:  
  52.     return status;  
  53. }  

 

下一個關鍵函數就是spi_register_master(),用於註冊spi_master

[cpp] view plain copy
  1. int spi_register_master(struct spi_master *master)  
  2. {  
  3.     static atomic_t     dyn_bus_id = ATOMIC_INIT((1<<15) - 1);  
  4.     struct device       *dev = master->dev.parent;  
  5.     int         status = -ENODEV;  
  6.     int         dynamic = 0;  
  7.   
  8.     if (!dev)  
  9.         return -ENODEV;  
  10.   
  11.     /* even if it's just one always-selected device, there must 
  12.      * be at least one chipselect 
  13.      */  
  14.     if (master->num_chipselect == 0)//片選數不能爲0  
  15.         return -EINVAL;  
  16.   
  17.     /* convention:  dynamically assigned bus IDs count down from the max */  
  18.     if (master->bus_num < 0) {  
  19.         /* FIXME switch to an IDR based scheme, something like 
  20.          * I2C now uses, so we can't run out of "dynamic" IDs 
  21.          */  
  22.         master->bus_num = atomic_dec_return(&dyn_bus_id);  
  23.         dynamic = 1;  
  24.     }  
  25.   
  26.     /* register the device, then userspace will see it. 
  27.      * registration fails if the bus ID is in use. 
  28.      */  
  29.     dev_set_name(&master->dev, "spi%u", master->bus_num);  
  30.     status = device_add(&master->dev);//添加spi_master設備  
  31.     if (status < 0)  
  32.         goto done;  
  33.     dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),  
  34.             dynamic ? " (dynamic)" : "");  
  35.   
  36.     /* populate children from any spi device tables */  
  37.     scan_boardinfo(master);//遍歷板級信息,尋找可以掛接在該spi_master下的從設備  
  38.     status = 0;  
  39. done:  
  40.     return status;  
  41. }  


 

[cpp] view plain copy
  1. static void scan_boardinfo(struct spi_master *master)  
  2. {  
  3.     struct boardinfo    *bi;  
  4.   
  5.     mutex_lock(&board_lock);  
  6.     list_for_each_entry(bi, &board_list, list) {  
  7.         struct spi_board_info   *chip = bi->board_info;  
  8.         unsigned        n;  
  9.   
  10.         for (n = bi->n_board_info; n > 0; n--, chip++) {  
  11.             if (chip->bus_num != master->bus_num)  
  12.                 continue;  
  13.             /* NOTE: this relies on spi_new_device to 
  14.              * issue diagnostics when given bogus inputs 
  15.              */  
  16.              /*bus_num相等則創建新設備*/  
  17.             (void) spi_new_device(master, chip);  
  18.         }  
  19.     }  
  20.     mutex_unlock(&board_lock);  
  21. }  


spi_board_info是板級信息,是在移植時就寫好的,並且要將其註冊

[cpp] view plain copy
  1. struct spi_board_info {  
  2.     char        modalias[32];  /*名字*/  
  3.     const void  *platform_data;  
  4.     void        *controller_data;  
  5.     int     irq;          /*中斷號*/  
  6.     u32     max_speed_hz; /*最高傳輸速率*/  
  7.     u16     bus_num;      /*所屬的spi_master編號*/  
  8.     u16     chip_select;  /*片選號*/  
  9.   
  10.     u8      mode;         /*傳輸模式*/  
  11.   
  12. };  

 

最後一步就是將相應的從設備註冊進內核

[cpp] view plain copy
  1. struct spi_device *spi_new_device(struct spi_master *master,  
  2.                   struct spi_board_info *chip)  
  3. {  
  4.     struct spi_device   *proxy;  
  5.     int         status;  
  6.   
  7.     /* NOTE:  caller did any chip->bus_num checks necessary. 
  8.      * 
  9.      * Also, unless we change the return value convention to use 
  10.      * error-or-pointer (not NULL-or-pointer), troubleshootability 
  11.      * suggests syslogged diagnostics are best here (ugh). 
  12.      */  
  13.   
  14.     /*創建SPI_device*/  
  15.     proxy = spi_alloc_device(master);  
  16.     if (!proxy)  
  17.         return NULL;  
  18.   
  19.     WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));  
  20.   
  21.     /*初始化*/  
  22.     proxy->chip_select = chip->chip_select;  
  23.     proxy->max_speed_hz = chip->max_speed_hz;  
  24.     proxy->mode = chip->mode;  
  25.     proxy->irq = chip->irq;  
  26.     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));  
  27.     proxy->dev.platform_data = (void *) chip->platform_data;  
  28.     proxy->controller_data = chip->controller_data;  
  29.     proxy->controller_state = NULL;  
  30.   
  31.     /*將新設備添加進內核*/  
  32.     status = spi_add_device(proxy);  
  33.     if (status < 0) {  
  34.         spi_dev_put(proxy);  
  35.         return NULL;  
  36.     }  
  37.   
  38.     return proxy;  
  39. }  

三、


最後以spidev設備驅動爲例,來闡述SPI數據傳輸的過程。spidev是內核中一個通用的設備驅動,我們註冊的從設備都可以使用該驅動,只需在註冊時將從設備的modalias字段設置爲"spidev",這樣才能和spidev驅動匹配成功。我們要傳輸的數據有時需要分爲一段一段的(比如先發送,後讀取,就需要兩個字段),每個字段都被封裝成一個transfer,N個transfer可以被添加到message中,作爲一個消息包進行傳輸。當用戶發出傳輸數據的請求時,message並不會立刻傳輸到從設備,而是由之前定義的transfer()函數將message放入一個等待隊列中,這些message會以FIFO的方式有workqueue調度進行傳輸,這樣能夠避免SPI從設備同一時間對主SPI控制器的競爭。和之前一樣,還是習慣先畫一張圖來描述數據傳輸的主要過程。

 

         在使用spidev設備驅動時,需要先初始化spidev. spidev是以字符設備的形式註冊進內核的。

[cpp] view plain copy
  1. static int __init spidev_init(void)  
  2. {  
  3.     int status;  
  4.   
  5.     /* Claim our 256 reserved device numbers.  Then register a class 
  6.      * that will key udev/mdev to add/remove /dev nodes.  Last, register 
  7.      * the driver which manages those device numbers. 
  8.      */  
  9.     BUILD_BUG_ON(N_SPI_MINORS > 256);  
  10.     /*將spidev作爲字符設備註冊*/  
  11.     status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);  
  12.     if (status < 0)  
  13.         return status;  
  14.   
  15.     /*創建spidev類*/  
  16.     spidev_class = class_create(THIS_MODULE, "spidev");  
  17.     if (IS_ERR(spidev_class)) {  
  18.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);  
  19.         return PTR_ERR(spidev_class);  
  20.     }  
  21.   
  22.     /*註冊spidev的driver,可與modalias字段爲"spidev"的spi_device匹配*/  
  23.     status = spi_register_driver(&spidev_spi);  
  24.     if (status < 0) {  
  25.         class_destroy(spidev_class);  
  26.         unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);  
  27.     }  
  28.     return status;  
  29. }  


與相應的從設備匹配成功後,則調用spidev中的probe函數

[cpp] view plain copy
  1. static int spidev_probe(struct spi_device *spi)  
  2. {  
  3.     struct spidev_data  *spidev;  
  4.     int         status;  
  5.     unsigned long       minor;  
  6.   
  7.     /* Allocate driver data */  
  8.     spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);  
  9.     if (!spidev)  
  10.         return -ENOMEM;  
  11.   
  12.     /* Initialize the driver data */  
  13.     spidev->spi = spi;//設定spi  
  14.     spin_lock_init(&spidev->spi_lock);  
  15.     mutex_init(&spidev->buf_lock);  
  16.   
  17.     INIT_LIST_HEAD(&spidev->device_entry);  
  18.   
  19.     /* If we can allocate a minor number, hook up this device. 
  20.      * Reusing minors is fine so long as udev or mdev is working. 
  21.      */  
  22.     mutex_lock(&device_list_lock);  
  23.     minor = find_first_zero_bit(minors, N_SPI_MINORS);//尋找沒被佔用的次設備號  
  24.     if (minor < N_SPI_MINORS) {  
  25.         struct device *dev;  
  26.         /*計算設備號*/  
  27.         spidev->devt = MKDEV(SPIDEV_MAJOR, minor);  
  28.         /*在spidev_class下創建設備*/  
  29.         dev = device_create(spidev_class, &spi->dev, spidev->devt,  
  30.                     spidev, "spidev%d.%d",  
  31.                     spi->master->bus_num, spi->chip_select);  
  32.         status = IS_ERR(dev) ? PTR_ERR(dev) : 0;  
  33.     } else {  
  34.         dev_dbg(&spi->dev, "no minor number available!\n");  
  35.         status = -ENODEV;  
  36.     }  
  37.     if (status == 0) {  
  38.         set_bit(minor, minors);//將minors的相應位置位,表示該位對應的次設備號已被佔用  
  39.         list_add(&spidev->device_entry, &device_list);//將創建的spidev添加到device_list  
  40.     }  
  41.     mutex_unlock(&device_list_lock);  
  42.   
  43.     if (status == 0)  
  44.         spi_set_drvdata(spi, spidev);  
  45.     else  
  46.         kfree(spidev);  
  47.   
  48.     return status;  
  49. }  


然後就可以利用spidev模塊提供的接口來實現主從設備之間的數據傳輸了。我們以spidev_write()函數爲例來分析數據傳輸的過程,實際上spidev_read()和其是差不多的,只是前面的一些步驟不一樣,可以參照上圖。

[cpp] view plain copy
  1. static ssize_t  
  2. spidev_write(struct file *filp, const char __user *buf,  
  3.         size_t count, loff_t *f_pos)  
  4. {  
  5.     struct spidev_data  *spidev;  
  6.     ssize_t         status = 0;  
  7.     unsigned long       missing;  
  8.   
  9.     /* chipselect only toggles at start or end of operation */  
  10.     if (count > bufsiz)  
  11.         return -EMSGSIZE;  
  12.   
  13.     spidev = filp->private_data;  
  14.   
  15.     mutex_lock(&spidev->buf_lock);  
  16.     //將用戶要發送的數據拷貝到spidev->buffer  
  17.     missing = copy_from_user(spidev->buffer, buf, count);  
  18.     if (missing == 0) {//全部拷貝成功,則調用spidev_sysn_write()  
  19.         status = spidev_sync_write(spidev, count);  
  20.     } else  
  21.         status = -EFAULT;  
  22.     mutex_unlock(&spidev->buf_lock);  
  23.   
  24.     return status;  
  25. }  


 

[cpp] view plain copy
  1. static inline ssize_t  
  2. spidev_sync_write(struct spidev_data *spidev, size_t len)  
  3. {  
  4.     struct spi_transfer t = {//設置傳輸字段  
  5.             .tx_buf     = spidev->buffer,  
  6.             .len        = len,  
  7.         };  
  8.     struct spi_message   m;//創建message  
  9.   
  10.     spi_message_init(&m);  
  11.     spi_message_add_tail(&t, &m);//將transfer添加到message中  
  12.     return spidev_sync(spidev, &m);  
  13. }  


我們來看看struct spi_transfer和struct spi_message是如何定義的

[cpp] view plain copy
  1. struct spi_transfer {  
  2.     /* it's ok if tx_buf == rx_buf (right?) 
  3.      * for MicroWire, one buffer must be null 
  4.      * buffers must work with dma_*map_single() calls, unless 
  5.      *   spi_message.is_dma_mapped reports a pre-existing mapping 
  6.      */  
  7.     const void  *tx_buf;//發送緩衝區  
  8.     void        *rx_buf;//接收緩衝區  
  9.     unsigned    len;    //傳輸數據的長度  
  10.   
  11.     dma_addr_t  tx_dma;  
  12.     dma_addr_t  rx_dma;  
  13.   
  14.     unsigned    cs_change:1; //該位如果爲1,則表示當該transfer傳輸完後,改變片選信號  
  15.     u8      bits_per_word;//字比特數  
  16.     u16     delay_usecs;  //傳輸後的延時   
  17.     u32     speed_hz;  //指定的時鐘  
  18.   
  19.     struct list_head transfer_list;//用於將該transfer鏈入message  
  20. };  


 

[cpp] view plain copy
  1. struct spi_message {  
  2.     struct list_head    transfers;//用於鏈接spi_transfer  
  3.   
  4.     struct spi_device   *spi;      //指向目的從設備  
  5.   
  6.     unsigned        is_dma_mapped:1;  
  7.   
  8.     /* REVISIT:  we might want a flag affecting the behavior of the 
  9.      * last transfer ... allowing things like "read 16 bit length L" 
  10.      * immediately followed by "read L bytes".  Basically imposing 
  11.      * a specific message scheduling algorithm. 
  12.      * 
  13.      * Some controller drivers (message-at-a-time queue processing) 
  14.      * could provide that as their default scheduling algorithm.  But 
  15.      * others (with multi-message pipelines) could need a flag to 
  16.      * tell them about such special cases. 
  17.      */  
  18.   
  19.     /* completion is reported through a callback */  
  20.     void            (*complete)(void *context);//用於異步傳輸完成時調用的回調函數  
  21.     void            *context;                  //回調函數的參數  
  22.     unsigned        actual_length;            //實際傳輸的長度  
  23.     int         status;  
  24.   
  25.     /* for optional use by whatever driver currently owns the 
  26.      * spi_message ...  between calls to spi_async and then later 
  27.      * complete(), that's the spi_master controller driver. 
  28.      */  
  29.     struct list_head    queue; //用於將該message鏈入bitbang等待隊列  
  30.     void            *state;  
  31. };  


繼續跟蹤源碼,進入spidev_sync(),從這一步開始,read和write就完全一樣了

[cpp] view plain copy
  1. <span style="font-size:12px;">static ssize_t  
  2. spidev_sync(struct spidev_data *spidev, struct spi_message *message)  
  3. {  
  4.     DECLARE_COMPLETION_ONSTACK(done);  
  5.     int status;  
  6.   
  7.     message->complete = spidev_complete;//設置回調函數  
  8.     message->context = &done;              
  9.   
  10.     spin_lock_irq(&spidev->spi_lock);  
  11.     if (spidev->spi == NULL)  
  12.         status = -ESHUTDOWN;  
  13.     else  
  14.         status = spi_async(spidev->spi, message);//調用spi核心層的函數spi_async()  
  15.     spin_unlock_irq(&spidev->spi_lock);  
  16.   
  17.     if (status == 0) {  
  18.         wait_for_completion(&done);  
  19.         status = message->status;  
  20.         if (status == 0)  
  21.             status = message->actual_length;  
  22.     }  
  23.     return status;  
  24. }</span>  


 

[cpp] view plain copy
  1. static inline int  
  2. spi_async(struct spi_device *spi, struct spi_message *message)  
  3. {  
  4.     message->spi = spi;  
  5.     /*調用master的transfer函數將message放入等待隊列*/  
  6.     return spi->master->transfer(spi, message);  
  7. }  


 

s3c24xx平臺下的transfer函數是在bitbang_start()函數中定義的,爲bitbang_transfer()

[cpp] view plain copy
  1. int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)  
  2. {  
  3.     struct spi_bitbang  *bitbang;  
  4.     unsigned long       flags;  
  5.     int         status = 0;  
  6.   
  7.     m->actual_length = 0;  
  8.     m->status = -EINPROGRESS;  
  9.   
  10.     bitbang = spi_master_get_devdata(spi->master);  
  11.   
  12.     spin_lock_irqsave(&bitbang->lock, flags);  
  13.     if (!spi->max_speed_hz)  
  14.         status = -ENETDOWN;  
  15.     else {  
  16.         list_add_tail(&m->queue, &bitbang->queue);//將message添加到bitbang的等待隊列  
  17.         queue_work(bitbang->workqueue, &bitbang->work);//調度運行work  
  18.     }  
  19.     spin_unlock_irqrestore(&bitbang->lock, flags);  
  20.   
  21.     return status;  
  22. }  

這裏可以看到transfer函數不負責實際的數據傳輸,而是將message添加到等待隊列中。同樣在spi_bitbang_start()中,有這樣一個定義INIT_WORK(&bitbang->work, bitbang_work);因此bitbang_work()函數會被調度運行,類似於底半部機制

[cpp] view plain copy
  1. static void bitbang_work(struct work_struct *work)  
  2. {  
  3.     struct spi_bitbang  *bitbang =  
  4.         container_of(work, struct spi_bitbang, work);//獲取bitbang  
  5.     unsigned long       flags;  
  6.   
  7.     spin_lock_irqsave(&bitbang->lock, flags);  
  8.     bitbang->busy = 1;  
  9.     while (!list_empty(&bitbang->queue)) {//等待隊列不爲空  
  10.         struct spi_message  *m;  
  11.         struct spi_device   *spi;  
  12.         unsigned        nsecs;  
  13.         struct spi_transfer *t = NULL;  
  14.         unsigned        tmp;  
  15.         unsigned        cs_change;  
  16.         int         status;  
  17.         int         (*setup_transfer)(struct spi_device *,  
  18.                         struct spi_transfer *);  
  19.         /*取出等待隊列中的的第一個message*/  
  20.         m = container_of(bitbang->queue.next, struct spi_message,  
  21.                 queue);  
  22.         list_del_init(&m->queue);//將message從隊列中刪除  
  23.         spin_unlock_irqrestore(&bitbang->lock, flags);  
  24.   
  25.         /* FIXME this is made-up ... the correct value is known to 
  26.          * word-at-a-time bitbang code, and presumably chipselect() 
  27.          * should enforce these requirements too? 
  28.          */  
  29.         nsecs = 100;  
  30.   
  31.         spi = m->spi;  
  32.         tmp = 0;  
  33.         cs_change = 1;  
  34.         status = 0;  
  35.         setup_transfer = NULL;  
  36.   
  37.         /*遍歷message中的所有傳輸字段,逐一進行傳輸*/  
  38.         list_for_each_entry (t, &m->transfers, transfer_list) {  
  39.   
  40.             /* override or restore speed and wordsize */  
  41.             if (t->speed_hz || t->bits_per_word) {  
  42.                 setup_transfer = bitbang->setup_transfer;  
  43.                 if (!setup_transfer) {  
  44.                     status = -ENOPROTOOPT;  
  45.                     break;  
  46.                 }  
  47.             }  
  48.             /*調用setup_transfer根據transfer中的信息進行時鐘、字比特數的設定*/  
  49.             if (setup_transfer) {  
  50.                 status = setup_transfer(spi, t);  
  51.                 if (status < 0)  
  52.                     break;  
  53.             }  
  54.   
  55.             /* set up default clock polarity, and activate chip; 
  56.              * this implicitly updates clock and spi modes as 
  57.              * previously recorded for this device via setup(). 
  58.              * (and also deselects any other chip that might be 
  59.              * selected ...) 
  60.              */  
  61.             if (cs_change) {//使能外設的片選  
  62.                 bitbang->chipselect(spi, BITBANG_CS_ACTIVE);  
  63.                 ndelay(nsecs);  
  64.             }  
  65.             cs_change = t->cs_change;//這裏確定進行了這個字段的傳輸後是否要改變片選狀態  
  66.             if (!t->tx_buf && !t->rx_buf && t->len) {  
  67.                 status = -EINVAL;  
  68.                 break;  
  69.             }  
  70.   
  71.             /* transfer data.  the lower level code handles any 
  72.              * new dma mappings it needs. our caller always gave 
  73.              * us dma-safe buffers. 
  74.              */  
  75.             if (t->len) {  
  76.                 /* REVISIT dma API still needs a designated 
  77.                  * DMA_ADDR_INVALID; ~0 might be better. 
  78.                  */  
  79.                 if (!m->is_dma_mapped)  
  80.                     t->rx_dma = t->tx_dma = 0;  
  81.                 /*調用針對於平臺的傳輸函數txrx_bufs*/  
  82.                 status = bitbang->txrx_bufs(spi, t);  
  83.             }  
  84.             if (status > 0)  
  85.                 m->actual_length += status;  
  86.             if (status != t->len) {  
  87.                 /* always report some kind of error */  
  88.                 if (status >= 0)  
  89.                     status = -EREMOTEIO;  
  90.                 break;  
  91.             }  
  92.             status = 0;  
  93.   
  94.             /* protocol tweaks before next transfer */  
  95.             /*如果要求在傳輸完一個字段後進行delay,則進行delay*/  
  96.             if (t->delay_usecs)  
  97.                 udelay(t->delay_usecs);  
  98.   
  99.             if (!cs_change)  
  100.                 continue;  
  101.               
  102.             /*最後一個字段傳輸完畢了,則跳出循環*/  
  103.             if (t->transfer_list.next == &m->transfers)  
  104.                 break;  
  105.   
  106.             /* sometimes a short mid-message deselect of the chip 
  107.              * may be needed to terminate a mode or command 
  108.              */  
  109.             ndelay(nsecs);  
  110.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);  
  111.             ndelay(nsecs);  
  112.         }  
  113.   
  114.         m->status = status;  
  115.         m->complete(m->context);  
  116.   
  117.         /* restore speed and wordsize */  
  118.         if (setup_transfer)  
  119.             setup_transfer(spi, NULL);  
  120.   
  121.         /* normally deactivate chipselect ... unless no error and 
  122.          * cs_change has hinted that the next message will probably 
  123.          * be for this chip too. 
  124.          */  
  125.         if (!(status == 0 && cs_change)) {  
  126.             ndelay(nsecs);  
  127.             bitbang->chipselect(spi, BITBANG_CS_INACTIVE);  
  128.             ndelay(nsecs);  
  129.         }  
  130.   
  131.         spin_lock_irqsave(&bitbang->lock, flags);  
  132.     }  
  133.     bitbang->busy = 0;  
  134.     spin_unlock_irqrestore(&bitbang->lock, flags);  
  135. }  


只要bitbang->queue等待隊列不爲空,就表示相應的SPI主控制器上還有傳輸任務沒有完成,因此bitbang_work()會被不斷地調度執行。 bitbang_work()中的工作主要是兩個循環,外循環遍歷等待隊列中的message,內循環遍歷message中的transfer,在bitbang_work()中,傳輸總是以transfer爲單位的。當選定了一個transfer後,便會調用transfer_txrx()函數,進行實際的數據傳輸,顯然這個函數是針對於平臺的SPI控制器而實現的,在s3c24xx平臺中,該函數爲s3c24xx_spi_txrx();

[cpp] view plain copy
  1. static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)  
  2. {  
  3.     struct s3c24xx_spi *hw = to_hw(spi);  
  4.   
  5.     dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",  
  6.         t->tx_buf, t->rx_buf, t->len);  
  7.   
  8.     hw->tx = t->tx_buf;//獲取發送緩衝區  
  9.     hw->rx = t->rx_buf;//獲取讀取緩存區  
  10.     hw->len = t->len;  //獲取數據長度  
  11.     hw->count = 0;  
  12.   
  13.     init_completion(&hw->done);//初始化完成量  
  14.   
  15.     /* send the first byte */  
  16.     /*只發送第一個字節,其他的在中斷中發送(讀取)*/  
  17.     writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);  
  18.   
  19.     wait_for_completion(&hw->done);  
  20.   
  21.     return hw->count;  
  22. }  


 

[cpp] view plain copy
  1. static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)  
  2. {  
  3.     /*如果tx不爲空,也就是說當前是從主機向從機發送數據,則直接將tx[count]發送過去, 
  4.       如果tx爲空,也就是說當前是從從機向主機發送數據,則向從機寫入0*/  
  5.     return hw->tx ? hw->tx[count] : 0;  
  6. }  


負責SPI數據傳輸的中斷函數:

[cpp] view plain copy
  1. static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)  
  2. {  
  3.     struct s3c24xx_spi *hw = dev;  
  4.     unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);  
  5.     unsigned int count = hw->count;  
  6.   
  7.     /*衝突檢測*/  
  8.     if (spsta & S3C2410_SPSTA_DCOL) {  
  9.         dev_dbg(hw->dev, "data-collision\n");  
  10.         complete(&hw->done);  
  11.         goto irq_done;  
  12.     }  
  13.   
  14.     /*設備忙檢測*/  
  15.     if (!(spsta & S3C2410_SPSTA_READY)) {  
  16.         dev_dbg(hw->dev, "spi not ready for tx?\n");  
  17.         complete(&hw->done);  
  18.         goto irq_done;  
  19.     }  
  20.   
  21.     hw->count++;  
  22.   
  23.     if (hw->rx)//讀取數據到緩衝區  
  24.         hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);  
  25.   
  26.     count++;  
  27.   
  28.     if (count < hw->len)//向從機寫入數據  
  29.         writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);  
  30.     else//count == len,一個字段發送完成,喚醒完成量  
  31.         complete(&hw->done);  
  32.   
  33.  irq_done:  
  34.     return IRQ_HANDLED;  
  35. }  

這裏可以看到一點,即使tx爲空,也就是說用戶申請的是從從設備讀取數據,也要不斷地向從設備寫入數據,只不過寫入從設備的是無效數據(0),這樣做得目的是爲了維持SPI總線上的時鐘。至此,SPI框架已分析完畢。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章