歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux SPI框架

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

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

  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從設備

  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是一致的

  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的類,以後注冊的從設備都將掛接在該總線下

  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的定義

  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函數

  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總線,這一步是和平台無關的,第二步是和平台相關的初始化,下一節再做介紹。

Copyright © Linux教程網 All Rights Reserved