歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux SPI框架

Linux SPI框架

日期:2017/3/1 10:17:19   编辑:Linux編程

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. };

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. buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
  5. if (!buf) {
  6. status = -ENOMEM;
  7. goto err0;
  8. }
  9. status = bus_register(&spi_bus_type);//注冊SPI總線
  10. if (status < 0)
  11. goto err1;
  12. status = class_register(&spi_master_class);//注冊spi_master類
  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. }

我們來看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. return strcmp(spi->modalias, drv->name) == 0;
  5. }

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

這裡已經完成了SPI子系統初始化的第一步,也就是注冊SPI總線,這一步是和平台無關的,第二步是和平台相關的初始化,下一節再做介紹。

Copyright © Linux教程網 All Rights Reserved