spi slave及master接口驱动及传输时序

本文详细介绍了SPI slave驱动的实现,包括如何编写多设备驱动、封装读写请求以及如何分发到master。通过分析`spidev.c`,展示了从打开设备到读写操作的数据传递流程。同时,解释了SPI读写请求的封装,以及同步和异步操作在kernel中的处理。最后,探讨了SPI传输时序的关键参数CPOL和CPHA,并强调了时钟同步的重要性。
摘要由CSDN通过智能技术生成

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);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值