Linux SPI设备分析1

Linux SPI设备分析1(基于Linux6.6)---SPI设备框架介绍

 

 

一、概述

1.1、SPI 驱动框架概述

SPI 驱动的主要任务是管理 SPI 总线与 SPI 设备之间的通信。SPI 设备通常通过 SPI 总线连接到主设备,而 SPI 驱动则负责处理数据传输、配置和设备管理。Linux 中的 SPI 驱动分为两部分:

  • SPI 总线驱动(SPI bus driver):负责管理 SPI 总线的硬件操作。
  • SPI 设备驱动(SPI device driver):与特定 SPI 设备进行交互,执行数据的读写等操作。

1.2、SPI 设备驱动框架的组成部分

一个完整的 SPI 设备驱动通常由以下几个部分组成:

1.SPI 设备的描述结构(spi_device

在 Linux 内核中,SPI 设备通过 spi_device 结构表示。该结构包含了与特定 SPI 设备相关的所有信息,如设备名称、SPI 总线、设备 ID、片选等。

struct spi_device {
    struct device dev;             // 设备的基础结构体
    struct spi_controller *controller; // 关联的 SPI 控制器
    unsigned int max_speed_hz;     // 最大传输速度
    unsigned int chip_select;      // 片选编号
    unsigned int mode;             // SPI 模式
    u16 irq;                       // 中断号
    const char *modalias;          // 设备别名
    // 其他 SPI 设备相关参数
};

2.SPI 控制器(spi_controller

spi_controller 结构代表了 SPI 总线控制器。SPI 控制器驱动负责管理总线的具体硬件操作,如配置时钟、传输数据等。

struct spi_controller {
    struct device dev;
    int (*setup)(struct spi_device *spi); // 设置 SPI 设备
    int (*transfer)(struct spi_device *spi, struct spi_transfer *xfer); // SPI 传输接口
    // 其他 SPI 总线控制器相关信息
};

3.SPI 传输(spi_transfer

spi_transfer 结构用于表示一个 SPI 传输操作,描述了数据缓冲区、传输长度、传输方式等信息。

struct spi_transfer {
    unsigned long tx_buf;         // 发送数据缓冲区
    unsigned long rx_buf;         // 接收数据缓冲区
    unsigned len;                 // 传输数据长度
    unsigned speed_hz;            // 传输速度
    unsigned cs_change;           // 是否改变片选
    unsigned delay_usecs;         // 延时
    // 其他传输相关参数
};

4.SPI 设备驱动(spi_driver

spi_driver 结构用于注册和管理 SPI 设备驱动。它定义了如何绑定 SPI 设备、初始化设备、处理传输请求等。

struct spi_driver {
    struct device_driver driver;
    int (*probe)(struct spi_device *spi);    // 设备探测函数
    int (*remove)(struct spi_device *spi);   // 设备移除函数
    int (*suspend)(struct spi_device *spi);  // 设备挂起函数
    int (*resume)(struct spi_device *spi);   // 设备恢复函数
    const struct spi_device_id *id_table;    // 设备 ID 表
};

1.3、SPI 驱动的核心操作流程

SPI 驱动的操作流程大致分为以下几个步骤:

1.设备探测(Probe)

当 SPI 总线上的设备插入时,SPI 驱动会通过设备的 probe 函数来初始化设备。probe 函数负责设置设备的基本参数,如最大速度、SPI 模式、传输缓冲区等。

static int spi_example_probe(struct spi_device *spi)
{
    pr_info("Probing SPI device\n");
    // 初始化设备,设置 SPI 设备的参数
    return 0;
}

2.设备移除(Remove)

当设备从 SPI 总线上移除时,SPI 驱动会调用 remove 函数来清理资源并释放设备。

static int spi_example_remove(struct spi_device *spi)
{
    pr_info("Removing SPI device\n");
    // 清理设备资源
    return 0;
}

3.设备传输(Transfer)

SPI 设备驱动通过 spi_transfer 来发送或接收数据。spi_transfer 结构体描述了数据传输的相关信息,传输通常通过 spi_syncspi_async 来执行。

  • spi_sync:同步传输,即调用后会等待传输完成。
  • spi_async:异步传输,即启动传输后不会等待,传输完成后通过回调函数通知。
static int spi_example_transfer(struct spi_device *spi)
{
    struct spi_transfer transfer = {
        .tx_buf = tx_data,
        .rx_buf = rx_data,
        .len = sizeof(tx_data),
        .speed_hz = 1000000,
    };

    // 执行同步传输
    return spi_sync(spi, &transfer);
}

4.SPI 驱动注册(Registration)

init 函数中,SPI 驱动通过 spi_register_driver 函数将驱动注册到内核。这样内核会根据 SPI 设备的 ID 自动匹配合适的驱动。

static struct spi_driver example_spi_driver = {
    .driver = {
        .name = "example_spi_driver",
    },
    .probe = spi_example_probe,
    .remove = spi_example_remove,
    .id_table = example_spi_id_table,
};

module_spi_driver(example_spi_driver);

1.4、SPI 驱动开发中的注意事项

  • SPI 模式:SPI 有 4 种模式,具体取决于时钟极性(CPOL)和时钟相位(CPHA)。需要确保驱动中正确配置 SPI 模式,以确保与设备正确通信。
  • 传输时序:SPI 协议是同步的,时序要求严格。确保在传输时保持时钟和数据的同步。
  • 性能优化:SPI 总线的速度较高时,可能会出现数据传输的瓶颈。可以通过增加 DMA 支持来提高传输效率。
  • 多设备支持:SPI 总线上可能有多个设备,通过不同的片选线来区分。在设备驱动中要正确配置片选线和传输时序。

1.5、cpu-spi控制器-spi设备关联说明

spi驱动模型是如何抽象:

  1. 针对spi控制器与spi控制器驱动抽象出spi master类型,其中spi_master可以理解为spi控制器设备,同时该类中包含了spi通信实现产生接口spi_transfer(此处没有为spi 控制器抽象一个驱动类,而是将spi控制器产生通信时序的驱动,抽象为spi_transfer方法);
  2. 针对spi设备抽象了spi_dev、spi_driver类;
  3. 针对spi总线,实例化一个bus_type类型的对象。

d353eeb0328141cd9f31be5ecb95e24c.png 

spi总线与i2c类型,它们的控制器抽象类都提供了总线通信的方法(在i2c_adapter中抽象了algo方法,而在spi_master抽象了transfer接口)。

二、spi_master、spi dev、spi bus、spi driver的关联

2.1、基于设备-总线-驱动模型的关联

spi模型、i2c模型均是基于LINUX设备-总线-驱动模型的,主要描述下spi_driver、spi_device、spi_master、spi_bus这四个类型中device类型、device_driver类型的成员变量之间的关联。

如下图所示:

  1. 在spi总线上只有spi device、spi driver是注册到spi总线上的,而spi master是没有注册到spi总线上的,这点是与i2c驱动模型的区别(在i2c驱动模型中spi master也是注册到i2c总线上的,只是不进行与i2c driver的绑定);
  2. Spi device与spi driver借助设备-总线-驱动模型的数据结构与接口,完成绑定与解绑操作;
  3. Spi device与spi master之间借助设备模型的数据结构,完成父子节点的关联(如下图中橙色箭头所指)
  4. Spi device与spi master之间借助spi的数据结构,完成了device与master绑定(如下图中绿色箭头所指)

252f54d2901d4fdf9da2c67fc18cff17.png

 

2.2、spi通用字符设备创建相关

 

通过spi master提供的方法与具体的cs引脚设置,即可完成针对某一个spi dev的通信。因此spi 驱动模块也开发了通用字符设备,但与i2c不同的是,创建的spi通用字符设备需要同时包含spi master与spi device这两个变量。

     在i2c模型中,也存在i2c adapter设备对应的字符设备,在i2c设备驱动模型中,主要是在i2cadper 注册到i2c总线时,通过触发BUS_NOTIFY_ADD_DEVICE、BUS_NOTIFY_DEL_DEVICE通知,在这两个通知注册的处理接口中,借助device_add接口完成字符设备的添加;

而在spi驱动模型中,因没有将spi master注册到spi总线上,因此无法使用i2c模块那一套方式创建字符设备,且spi字符设备必须与spi device进行绑定(主要是获取对应的cs引脚),这是与i2c通用字符设备不同的地方。而且spi模块注册了名为“spidev”spi driver,该spi driver就是为了创建spi 通用字符设备而存在的。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值