Linux SPI框架(上)

来源:互联网 发布:淘宝教育哪里点进去 编辑:程序博客网 时间:2024/04/29 21:17

 Linux的SPI子系统采用主机驱动和外设驱动分离的思想,首先主机SPI控制器是一种平台设备,因此它以platform的方式注册进内核,外设的信息是以boardinfo形式静态定义的,在创建spi_master时,会根据外设的bus_num和主机的bus_num是否相等,来选择是否将该外设挂接在该SPI主控制器下。先看SPI子系统中几个关键的数据结构:

struct spi_master用来描述一个SPI主控制器

[cpp] view plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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 plaincopy
  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总线,这一步是和平台无关的,第二步是和平台相关的初始化,下一节再做介绍。

0 0
原创粉丝点击