(转载)SPI总线和外设驱动(一)

SPI(Serial Peripheral Interface)串行外设接口,是一种高速、全双工的通信总线,只占用芯片的四个引脚,分别为数据输入(SDI)、数据输出(SDO)、时钟信号(SCLK)、片选信号(CS),目前越来越多的芯片集成了这种方式。通常情况下,一个SPI主控器能外接多个从设备,然后通过CS片选信号选择从设备,通过SDI、SDO进行数据的传输。

1、硬件连接

SPI主控制器与从设备的连接示意图如下:

(转载)SPI总线和外设驱动(一)

SPI主控器与从设备连接示意图

2、SPI驱动架构分析

SPI驱动框架可以分为SPI核心层SPI控制器驱动层SPI设备驱动层

2.1、SPI核心层

SPI核心层主要负责注册SPI总线和提供通用API接口,与平台无关。核心层代码在源码目录的<drivers/spi/spi.c>,主要定义了总线类型和主控制器设备类,总线类型的代码如下:

(转载)SPI总线和外设驱动(一)

上述程序定义了SPI总线类型,通过bus_register()函数,将SPI总线注册进总线,成功注册后在sys/bus下即可找到spi节点。

控制器设备类代码如下:

(转载)SPI总线和外设驱动(一)

上述程序主要定义了SPI总线主控制器的设备类,通过调用class_register()函数注册设备类,成功注册后,在/sys/class目录下即可找到spi_master文件节点。

2.2、SPI控制器驱动层

spi_master结构体对应着主控制器驱动,在<include/linux/spi/spi.h>文件中定义,如下:

(转载)SPI总线和外设驱动(一)

注:bus_num通常从0开始计数,比如控制器有3路SPI,则bus_num设置为2

在<drivers/spi/spi.c>中定义了三个函数用于分配、注册和注销spi_master

为spi_master分配空间

(转载)SPI总线和外设驱动(一)

注册spi_master

(转载)SPI总线和外设驱动(一)

注销spi_master

(转载)SPI总线和外设驱动(一)

3、SPI设备驱动层

在<include/linux/spi/spi.h>中定义了描述spi设备信息的结构体spi_device,如下:

(转载)SPI总线和外设驱动(一)

向总线注册设备时还需要spi_board_info结构体,它的字段定义时大部分与spi_device相同,定义在<include/linux/spi/spi.h>中,如下:

(转载)SPI总线和外设驱动(一)

定义好spi_board_info后,就可以向SPI总线注册设备了。注册设备的API在<drivers/spi/spi.c>中被定义,如果SPI控制器已经被加载,调用:

(转载)SPI总线和外设驱动(一)

如果在板子的初始化代码中,调用以下API注册函数:

(转载)SPI总线和外设驱动(一)

spi_driver结构体在<include/linux/spi/spi.h>中定义,代码如下:

(转载)SPI总线和外设驱动(一)

定义好spi_driver后,在<drivers/spi/spi.c>通过spi_register_driver()可以完成驱动注册,spi_register_driver如下:

(转载)SPI总线和外设驱动(一)

178~184行是给spi_driver结构体赋值,185行注册驱动,187行将spi_register_driver导入内核符号表,以供其他模块使用。

SPI数据传输最核心的结构体是spi_transfer,在<include/linux/spi/spi.h>中定义,如下:

(转载)SPI总线和外设驱动(一)

SPI传输数据的另一个核心数据结构是spi_message,代码定义在<include/linux/spi/spi.h>,每次SPI传输数据中,都可能包含几个数据包,这时就应该通过spi_message结构体拼接起来。如下:

(转载)SPI总线和外设驱动(一)

在<include/linux/spi/spi.h>中定义了一些spi相关接口函数,对于SPI设备驱动编程而言,通常只关心spi_write()和spi_read()两个函数即可。

spi_write()完成同步数据发送

(转载)SPI总线和外设驱动(一)

spi_read()完成同步数据接收

(转载)SPI总线和外设驱动(一)