一. 简介
SPI 驱动框架和 I2C 很类似,都分为主机控制器驱动和设备驱动,主机控制器也就是 SOC的 SPI 控制器接口。
例如,在裸机篇中的《第二十七章 SPI 实验》,我们编写了 bsp_spi.c 和 bsp_spi.h 这两个文件,这两个文件是 I.MX6U 的 SPI 控制器驱动。
我们编写好 SPI 控制器驱动以后就可 以直接使用了不管是什么 SPI 设备, SPI 控制器部分的驱动都是一样,我们的重点就落在了 种类繁多的 SPI 设备驱动。
二. Linux下SPI驱动:SPI主机驱动简介
接下来简单分析一下SPI主机驱动,也就是SPI控制器驱动。一般SPI主机驱动是半导体厂商编写的。
1. spi_master结构体
SPI 主机驱动就是 SOC 的 SPI 控制器驱动,类似 I2C 驱动里面的适配器驱动。 Linux 内核 使用 spi_master 表示 SPI 主机驱动, spi_master 是个结构体,定义在 include/linux/spi/spi.h 文件
中,内容如下 ( 有缩减 ) :
struct spi_master {struct device dev;struct list_head list;
..................s16 bus_num;
/* chipselects will be integral to many controllers; some others
* might use board-specific GPIOs.
*/u16 num_chipselect;/* some SPI controllers pose alignment requirements on DMAable
* buffers; let protocol drivers know about these requirements.
*/u16 dma_alignment;/* spi_device.mode flags understood by this controller driver */u16 mode_bits;/* bitmask of supported bits_per_word for transfers */u32 bits_per_word_mask;
...................
/* limits on transfer speed */u32 min_speed_hz;u32 max_speed_hz;/* other constraints relevant to this driver */u16 flags;
.................../* lock and mutex for SPI bus locking */spinlock_t bus_lock_spinlock;struct mutex bus_lock_mutex;/* flag indicating that the SPI bus is locked for exclusive use */bool bus_lock_flag;
...................int (*setup)(struct spi_device *spi);
...................
int (*transfer)(struct spi_device *spi,struct spi_message *mesg);
................... int (*transfer_one_message)(struct spi_master *master,struct spi_message *mesg);
...................
};
第 39 行, transfer 函数,和 i2c_algorithm 中的 master_xfer 函数一样,控制器数据传输函 数。
第 42 行, transfer_one_message 函数,也用于 SPI 数据发送,用于发送一个 spi_message ,SPI 的数据会打包成 spi_message ,然后以队列方式发送出去。
也就是 SPI 主机端最终会通过 transfer 函数与 SPI 设备进行通信。因此,对于 SPI 主机控制器的驱 动编写者而言, transfer 函数是需要实现的,因为不同的 SOC 其 SPI 控制器不同,寄存器都不一 样。
和 I2C 适配器驱动一样, SPI 主机驱动一般都是 SOC 厂商去编写的,所以,我们作为 SOC 的 使用者,这一部分的驱动就不用操心了,除非你是在 SOC 原厂工作,内容就是写 SPI 主机驱 动。
SPI 主机驱动的核心就是申请 spi_master,然后初始化 spi_master,最后向 Linux 内核注册spi_master。
spi_alloc_master 函数用于申请 spi_master ,函数原型如下:
struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
函数参数和返回值含义如下:
dev :设备,一般是 platform_device 中的 dev 成员变量。
size : 私有数据大小,可以通过 spi_master_get_devdata 函数获取到这些私有数据。
返回值: 申请到的 spi_master 。
spi_master 的释放通过 spi_master_put 函数来完成,当我们删除一个 SPI 主机驱动的时候就 需要释放掉前面申请的 spi_master , spi_master_put 函数原型如下:
void spi_master_put(struct spi_master *master)
函数参数和返回值含义如下:
master :要释放的 spi_master 。
返回值: 无。
3. spi_master 的注册与注销
当 spi_master 初始化完成以后就需要将其注册到 Linux 内核, spi_master 注册函数为
spi_register_master函数 ,函数原型如下:
int spi_register_master(struct spi_master *master)
函数参数和返回值含义如下:
master :要注册的 spi_master 。
返回值: 0 ,成功;负值,失败。
I.MX6U 的 SPI 主机驱动会采用 spi_bitbang_start 这个 API 函数来完成 spi_master 的注册,
spi_bitbang_start 函数内部其实也是通过调用 spi_register_master 函数来完成 spi_master 的注册。
如果要注销 spi_master 的话可以使用 spi_unregister_master 函数,此函数原型为:
void spi_unregister_master(struct spi_master *master)
函数参数和返回值含义如下:
master :要注销的 spi_master 。
返回值: 无。
注意:如果使用 spi_bitbang_start 注册 spi_master 的话,就要使用 spi_bitbang_stop 来注销掉 spi_master。