回顾平台总线设备驱动模型
Linux驱动程序开始基于"平台总线设备驱动"模型,把驱动程序分成两边:
- 左边注册一个platform_driver结构体,里面是比较固定的、通用的代码
- 右边注册一个platform_device结构体,里面是硬件资源
- 可以在C文件中注册platform_device
- 也可以使用设备树创建一个节点,内核解析设备树时注册platform_device
数据结构
SPI子系统中根据主从控制的方式,有两类设备,SPI控制器和SPI设备。
SPI控制器有驱动程序,提供SPI的传输能力。
SPI设备也有自己的驱动程序,提供SPI设备的访问能力:
- 它知道怎么访问这个设备,它知道这个设备的数据含义是什么
- 它会调用SPI控制器的函数来收发数据。
SPI控制器数据结构
根据内核文件中的定义:include\linux\spi\spi.h
Linux中使用spi_master结构体描述SPI控制器,里面最重要的成员就是transfer
函数指针:
根据上文注释中对transfer函数的描述,可以提炼出函数具备以下特性:
- 支持双向批量传输
- transfer()方法不能休眠;它的主要作用是将消息添加到队列中
- 目前还没有从队列中删除操作,或者任何其他请求管理
- 对于给定的spi_device,消息队列是单纯的FIFO方式
- 选择一个芯片然后传输数据,master的主要工作是处理它的消息队列
- 如果有多个spi_device子节点,i/o队列仲裁算法未指定具体方式,可以是轮询,fifo,优先、保留、优先等
- 片选信号在整个消息期间保持活跃,除非被spi_transfer.cs_change != 0所修改
- 消息传输使用时钟和SPI模式参数,这些参数是由setup()之前为这个设备建立
SPI设备数据结构
根据内核文件中的定义:include\linux\spi\spi.h
Linux中使用spi_device结构体描述SPI设备,里面记录有设备的片选引脚、频率、挂在哪个SPI控制器下面:
SPI设备驱动
根据内核文件中的定义:include\linux\spi\spi.h
Linux中使用spi_driver结构体描述SPI设备驱动:
spi_driver为主机端协议驱动数据结构,其中支持的函数或结构体功能定义:
- id_table:该驱动程序支持的SPI设备列表
- probe:将这个驱动绑定到spi设备。驱动程序可以验证设备是否确实存在,并且可能需要配置一些在系统设置期间完成的初始配置中不需要的特征(如bits_per_word)。
- remove:从spi设备解绑定该驱动程序
- shutdown:在系统状态转换期间使用的标准关机回调函数,例如powerdown/halt和kexec
- driver: SPI设备驱动程序应该初始化该结构的name和owner字段。
SPI驱动框架
如何把SPI控制器部分和SPI设备部分结合起来:
- SPI控制器的platform_device侧需要硬件的描述信息,硬件信息可以来自与设备树的定义,也可以从.C文件中注册platform_device
- SPI控制器的platform_driver需要与platform_device结构比较和匹配,匹配上后,调用platform_driver中的probe函数
- probe函数除了生成spi_master,还会解析设备树,生成SPI设备侧的spi_device
- SPI设备侧的spi_driver和spi_device会进行匹配比较,再调用spi_driver的probe函数
下图来自韦东山SPI总线设备驱动模型的图示,清晰的介绍了SPI设备和SPI控制器之间的关联。
设备树文件的内容
SPI控制器驱动程序
SPI控制器的驱动程序可以基于"平台总线设备驱动"模型来实现:
- 在设备树里描述SPI控制器的硬件信息,在设备树子节点里描述挂在下面的SPI设备的信息
- 在platform_driver中提供一个probe函数
- 它会注册一个spi_master
- 还会解析设备树子节点,创建spi_device结构体
SPI设备驱动程序
跟"平台总线设备驱动模型"类似,Linux中也有一个"SPI总线设备驱动模型":
- 左边是spi_driver,使用C文件实现,里面有id_table表示能支持哪些SPI设备,有probe函数
- 右边是spi_device,用来描述SPI设备,比如它的片选引脚、频率
- 可以来自设备树:比如由SPI控制器驱动程序解析设备树后创建、注册spi_device
- 可以来自C文件:比如使用
spi_register_board_info
创建、注册spi_device