一. 简介
前面一篇文章学习了SPI设备驱动涉及的结构体与(注册/注销)函数。
另一篇文章学习了(在支持设备树情况下),SPI 设备信息如何描述,具体就是在设备树文件中创建SPI节点及SPI设备节点,文章如下:
SPI 设备驱动编写流程:创建SPI节点以及SPI设备节点(在设备树文件中)-CSDN博客
本文继续学习SPI设备驱动的编写流程,具体学习SPI设备数据收发处理。
二. SPI 设备驱动编写流程:SPI 设备数据收发处理流程
SPI 设备驱动的核心是 spi_driver
。
当我们向 Linux 内核注册成功 spi_driver 以后,就可以使用 SPI 核心层提供的 API 函数来对设备进行读写操作了。
1. spi_transfer结构体与 spi_message结构体
首先是
spi_transfer
结构体,此结构体用于描述
SPI
传输信息,结构体内容如下:
struct spi_transfer {
/* it's ok if tx_buf == rx_buf (right?)
* for MicroWire, one buffer must be null
* buffers must work with dma_*map_single() calls, unless
* spi_message.is_dma_mapped reports a pre-existing mapping
*/
const void *tx_buf;
void *rx_buf;
unsigned len;
dma_addr_t tx_dma;
dma_addr_t rx_dma;
struct sg_table tx_sg;
struct sg_table rx_sg;
unsigned cs_change:1;
unsigned tx_nbits:3;
unsigned rx_nbits:3;
#define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */
#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */
#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */
u8 bits_per_word;
u16 delay_usecs;
u32 speed_hz;
struct list_head transfer_list;
};
第
7
行,
tx_buf
保存着要发送的数据。
第
8
行,
rx_buf
用于保存接收到的数据。
第
9
行,
len
是要进行传输的数据长度,
SPI
是全双工通信,因此在一次通信中发送和
接收的字节数都是一样的,所以
spi_transfer
中也就没有发送长度和接收长度之分。
spi_transfer 需要组织成 spi_message,spi_message
也是一个结构体,内容如下:
struct spi_message {
struct list_head transfers;
struct spi_device *spi;
unsigned is_dma_mapped:1;
.....................
/* completion is reported through a callback */
void (*complete)(void *context);
void *context;
unsigned frame_length;
unsigned actual_length;
int status;
/* for optional use by whatever driver currently owns the
* spi_message ... between calls to spi_async and then later
* complete(), that's the spi_master controller driver.
*/
struct list_head queue;
void *state;
};
2. 初始化 spi_message,添加spi_transfer到spi_message队列中
在使用
spi_message
之前需要对其进行初始化,
spi_message
初始化函数为
spi_message_init
,
函数原型如下:
void spi_message_init(struct spi_message *m)
函数参数和返回值含义如下:
m
:
要初始化的
spi_message
。
返回值:
无。
spi_message
初始化完成以后需要将
spi_transfer
添加到
spi_message
队列中,这里我们要用
到
spi_message_add_tail
函数,此函数原型如下:
void spi_message_add_tail(struct spi_transfer *t, struct spi_message *m)
函数参数和返回值含义如下:
t
:
要添加到队列中的
spi_transfer
。
m
:
spi_transfer
要加入的
spi_message
。
返回值:
无。
3. SPI数据传输
spi_message
准备好以后就可以进行数据传输了,数据传输分为同步传输和异步传输。
同步
传输会阻塞的等待
SPI
数据传输完成,同步传输函数为
spi_sync
函数,函数原型如下:
int spi_sync(struct spi_device *spi, struct spi_message *message)
函数参数和返回值含义如下:
spi
:
要进行数据传输的
spi_device
。
message
:要传输的
spi_message
。
返回值:
无。
异步传输不会阻塞的等到 SPI
数据传输完成。
异步传输需要设置
spi_message
中的
complete
成员变量,
complete
是一个回调函数,当
SPI
异步传输完成以后,此函数就会被调用。
SPI
异步传
输函数为
spi_async
函数,函数原型如下:
int spi_async(struct spi_device *spi, struct spi_message *message)
函数参数和返回值含义如下:
spi
:
要进行数据传输的
spi_device
。
message
:要传输的
spi_message
。
返回值:
无。
在本次的 SPI实验中,我们采用同步传输方式来完成 SPI 数据的传输工作,也就是 spi_sync