linux内核SPI总线驱动分析

xiaoxiao2021-02-27  480

1、SPI概述

SPI是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口,SPI

是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线。通信方式为主

从式通常是1个主设备、1个或多个从设备。SDI(数据输入),SDO(数据输出),SCLK(时钟),

CS(片选)。

2、Linux SPI 驱动总体架构

SPI的驱动架构可以分为如下层次:SPI核心层、SPI控制器驱动层、SPI设备驱动层。

2.1、SPI核心层

SPI核心层是Linux 内核SPI的核心部分,提供了核心数据结构的定义、SPI控制器驱动和 设备驱动的注册和注销接口。向下屏蔽 了物理总线 的差异,向上提供了统一的接口,以便设备 驱动通过总线控制器进行数据读写。

2.2、SPI控制器驱动层

SPI控制器驱动层,每种平台都有属于自己的控制器驱动。它的职责是为系统中每条SPI 总线提 供具体的读写方法。在物理上, 每个SPI控制器可以连接若干个SPI从设备。 系统开机时,控制器驱动首先被加载。一个控制器驱动用于一条特定的SPI总线的读写, 一个控制器驱动可以用 struct spi_master 来描述。 数据结构struct spi_master struct spi_master { struct device dev; s16 bus_num; u16 num_chipselect; int (*setup) (struct spi_device *spi); int (*transfer) (struct spi_device *spi, struct spi_message *mesg); void (*cleanup)(struct spi_device *spi); }; bus_num表示控制器对应的总线号。 num_chipselect表示控制器可以支持多少个SPI设备。 setup函数用于设置控制器相关的工作时钟、传输模式等。 transfer函数是实现SPI总线读写方法的函数,实现数据的双向传输。 cleanup函数为控制器驱动注销时调用,针对驱动初始化时申请的一些内核资源进行清理恢 复工作。

2.3、SPI设备驱动层

SPI设备驱动层为用户接口层,其为用户提供了通过SPI总线访问具体设备的接口。 SPI设备驱动层可以用两个数据结构来描述,struct spi_driver 和 struct spi_device struct spi_driver {      int         (*probe)(struct spi_device *spi);      int         (*remove)(struct spi_device *spi);      void            (*shutdown)(struct spi_device *spi);      int         (*suspend)(struct spi_device *spi, pm_message_t mesg);      int         (*resume)(struct spi_device *spi);      struct device_driver    driver;  };  driver是为device服务的,spi_driver注册时会扫描spi bus上的设备,设备和驱动通过 名字 进行匹配绑定。 probe函数用于驱动和设备匹配时被调用。SPI通信是通过消息队列,而不像i2c通过 与从 设备对话方式来实现 数据交互。 struct spi_device {      struct device         dev;      struct spi_master   *master;      u32                      max_speed_hz;      u8                       chip_select;      u8                       mode;        u8                       bits_per_word;      int                       irq;      void                    *controller_state;      void                    *controller_data;      char                    modalias[32];   };  通常spi_device对应SPI bus上某个特定的spi设备。并且spi_device封装了一个 spi_master结 构体。spi_device包含了该spi 设备特定的私有属性,比如它的最大频率, 片选,输入输出模 式等等。 spi_device的板信息用spi_board_info结构体来描述: struct spi_board_info {       char modalias[SPI_NAME_SIZE];         const void*      platform_data; void*               controller_data; int                   irq; u32                 max_speed_hz; u16                 bus_num; u16                 chip_select;       u8                mode; }; 这个结构体记录了SPI外设使用的主机控制器序号、片选信号、数据比特率、SPI传输方式等 spi_board_info结构体通过spi_register_board_info函数注册到链表board_list上。

2.4枚举过程

drivers/spi/spi.c:     spi_register_board_info         /* 对于每一个spi_master,调用spi_match_master_to_boardinfo */         list_for_each_entry(master, &spi_master_list, list)             spi_match_master_to_boardinfo             /* board_info里含有bus_num, 如果某个spi_master的bus_num跟它一样              * 则创建一个新的spi_device              */                     if (master->bus_num == bi->busnum)                         spi_new_device                             spi_alloc_device                             /* 记录bi信息, 比如片选,MODE,MAX HZ */                                 spi_add_device /* 根据名字找到spi_driver, 调用它的probe函数 */                                 spi_setup(spi);

                                device_add  /* 会绑定到一个spi_driver */

2.5数据收发过程

    spi_write         spi_message_init(&m);         初始化一个spi_message  /* 一个不可打断的SPI传输过程: cs=0,传数据,cs=1 */                                /* 一个spi_message由多个spi_transfer组成 */         spi_message_add_tail(&t, &m);  /* spi_transfe是SPI上传输的单方向1个或多个字节 */         spi_sync(spi, &m);  /* 启动传输并等待完成 */     

2.6 spi_driver如何调用spi_controller

    spi_sync         __spi_sync(spi, message, 0);             spi_async_locked                 __spi_async                     master->transfer(spi, message);             wait_for_completion

转载请注明原文地址: https://www.6miu.com/read-1073.html

最新回复(0)