spi slave驱动
spi slave驱动在kernel中可以主要参考spidev.c,这是一个字符驱动,可以匹配kernel中的多个名称为“spidev”的spi设备,
分析这个文件,主要有以下几个重点:
1. 如何编写多设备公用驱动
2. 如何封装读写请求到spi框架层
3. spi message请求如何分发到master
自spi_board_info或者spi master注册后,两者就已经完成了匹配的工作,spi slave驱动不关心任何匹配的细节,它只需要完成
与spi slave的匹配,就可以通过slave进而找到master。这里是通过spi_register_driver(&spidev_spi_driver);注册进
kernel,而后spi框架进行name match,再调用probe,完成关于设备的一些成员初始化操作。
下面针对上面的三个问题,进行分析这个驱动,
spi设备全局链及保护信号量:
static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);
相对与设备的驱动数据:
struct spidev_data {
dev_t devt; //设备号
spinlock_t spi_lock; //spi 结构体的pin锁
struct spi_device *spi;
struct list_head device_entry;//挂接到device_list
struct mutex buf_lock; //保护数据的lock
unsigned users; //使用者
u8 *buffer; //实际数据区,由open时进行动态分配,release时释放
};
spi中任何会由多个使用者访问的区域,都需要使用锁保护,如这里的users,个人觉得需要使用原子变量而不应该简单的使用整形。
在probe的时候,首先分配spidev_data,并初始化其spi/device_entry/buf_lock/spi_lock,查找一个可用的bit用作次
设备号,创建设备spidev busnum.cs,挂到全局链中,并将私有数据spidev_data放到dev->p->driver_data中。
open时,从inode中获取dev_t,然后对比整个链,找到目标数据spidev_data,放到file->private_data中,并分配缓存
读写时,直接从file中获取对应的spidev_data数据,然后通过spi device来传递spi请求。
以上主要是数据如何传递的问题。
SPI读写请求的封装很简单,如下:
static inline ssize_t spidev_sync_write(struct spidev_data *spidev, size_t len)
{
struct spi_transfer t = {
.tx_buf = spidev->buffer,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spidev_sync(spidev, &m);
}
static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len)
{
struct spi_transfer t = {
.rx_buf = spidev->buffer,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spidev_sync(spidev, &m);
}
封装的同步函数:
static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
spi slave及master接口驱动及传输时序
最新推荐文章于 2024-05-18 16:39:38 发布
本文详细介绍了SPI slave驱动的实现,包括如何编写多设备驱动、封装读写请求以及如何分发到master。通过分析`spidev.c`,展示了从打开设备到读写操作的数据传递流程。同时,解释了SPI读写请求的封装,以及同步和异步操作在kernel中的处理。最后,探讨了SPI传输时序的关键参数CPOL和CPHA,并强调了时钟同步的重要性。
摘要由CSDN通过智能技术生成