2. Linux SPI子系统架构

在车载嵌入式Linux系统中,SPI(Serial Peripheral Interface)子系统采用经典的分层架构设计,从上到下依次为:SPI设备驱动层、SPI核心层、SPI控制器驱动层。这种分层设计实现了硬件无关性与驱动可移植性,是车载ECU之间高速同步通信的基础。

2.1 三层架构总览

SPI子系统位于Linux内核的 drivers/spi/ 目录下,其核心思想是将SPI控制器(主机端)的硬件操作与SPI设备(从机端)的协议处理解耦。三层职责如下表所示:

层级 内核路径/文件 核心职责 关键数据结构
SPI设备驱动层 drivers/spi/spidev.c
或自定义驱动
实现具体SPI外设(如ADC、CAN控制器、传感器)的协议解析与数据交互 spi_driver、spi_device
SPI核心层 drivers/spi/spi.c 提供统一的框架:总线注册、设备枚举、数据传输队列管理、回调调度 spi_controller、spi_transfer、spi_message
SPI控制器驱动层 drivers/spi/spi-*.c
(如spi-imx.c、spi-dw.c)
直接操作SPI控制器寄存器,完成时钟、片选、数据移位等硬件时序 spi_controller(填充ops)、spi_master
车载工程要点: 在车载项目中,SPI控制器驱动通常由SoC厂商(如NXP i.MX8、TI Jacinto)提供,而设备驱动层则需要工程师根据具体外设手册(如车载音频DSP、安全气囊传感器)自行开发。核心层一般无需修改,但需要理解其回调机制以配置DMA或中断模式。

2.2 三层架构数据流与回调机制

SPI数据传输的完整路径从用户空间或内核子系统发起,经过设备驱动层封装为 spi_message,由核心层排队调度,最终由控制器驱动层完成硬件收发。下图展示了这一数据流与回调关系:

SPI三层架构数据流与回调机制 SPI三层架构数据流与回调机制 SPI设备驱动层(Device Driver) spi_driver.probe() → 创建 spi_device → 封装 spi_message 回调:spi_driver.remove() | spi_driver.shutdown() 关键结构:spi_driver, spi_device, spi_transfer spi_async() / spi_sync() SPI核心层(Core Layer) spi_controller 管理 | 消息队列调度 | 传输原子化 回调:spi_controller.transfer_one_message() | .prepare_message() 关键结构:spi_controller, spi_message, spi_transfer .transfer_one_message() SPI控制器驱动层(Controller Driver) 操作 SPI 控制器寄存器 | 配置时钟/片选/模式 | 触发 DMA 回调:.transfer_one() | .set_cs() | .handle_irq() 关键结构:spi_controller.ops, 硬件寄存器映射 数据流方向:用户/内核 → 设备驱动 → 核心层 → 控制器驱动 → SPI总线

2.3 各层关键数据结构与回调详解

2.3.1 SPI设备驱动层

设备驱动层通过 spi_driver 结构体注册到SPI总线。核心回调包括:

  • probe():当SPI核心层检测到设备与驱动匹配时调用,完成设备初始化、配置spi_device参数(模式、频率、bits_per_word)。
  • remove():设备移除或驱动卸载时调用,释放资源。
  • shutdown():系统关机或休眠时调用,用于车载安全场景下的外设下电时序。
/* SPI设备驱动模板 - 车载传感器示例 */
static int car_sensor_probe(struct spi_device *spi)
{
    struct car_sensor_data *data;
    /* 配置SPI通信参数 */
    spi->mode = SPI_MODE_0;
    spi->max_speed_hz = 10 * 1000 * 1000; /* 10MHz */
    spi->bits_per_word = 8;
    spi_setup(spi);

    data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
    spi_set_drvdata(spi, data);
    /* 注册输入子系统或IIO设备 */
    return 0;
}

static struct spi_driver car_sensor_driver = {
    .driver = {
        .name   = "car_sensor",
        .of_match_table = car_sensor_of_match,
    },
    .probe  = car_sensor_probe,
    .remove = car_sensor_remove,
};
module_spi_driver(car_sensor_driver);

2.3.2 SPI核心层

核心层是SPI子系统的中枢,负责管理 spi_controller 和 spi_device 的生命周期。其核心回调机制如下:

回调函数 触发时机 车载场景作用
transfer_one_message() 核心层从消息队列取出一个spi_message时 将消息拆解为多个transfer,逐个下发到控制器驱动
prepare_message() transfer_one_message执行前 预配置DMA通道或锁定SPI总线(防止多核竞态)
unprepare_message() transfer_one_message执行完成后 释放DMA资源或解锁总线
can_dma() 核心层判断是否使用DMA传输时 根据transfer长度决定是否启用DMA(车载大数据流场景关键)
车载优化提示: 在车载多传感器数据采集场景中,核心层的消息队列深度和DMA阈值直接影响实时性。建议通过 spi_controller.rt 标志启用实时调度,并合理设置 spi_controller.max_dma_len 以匹配车载SPI帧长(通常为8~64字节)。

2.3.3 SPI控制器驱动层

控制器驱动层直接与硬件寄存器交互,是三层中唯一与SoC绑定的部分。其回调函数通过 spi_controller.ops 结构体注册:

/* 控制器驱动核心回调结构 */
struct spi_controller_mem_ops {
    int (*exec_op)(struct spi_mem *mem, const struct spi_mem_op *op);
};

/* 传统SPI控制器回调(更常见) */
static const struct spi_controller_ops imx_spi_ops = {
    .transfer_one       = imx_spi_transfer_one,   /* 单次传输 */
    .set_cs             = imx_spi_set_cs,         /* 片选控制 */
    .handle_irq         = imx_spi_irq_handler,    /* 中断处理 */
    .prepare_transfer_hardware = imx_spi_prepare_hw,
    .unprepare_transfer_hardware = imx_spi_unprepare_hw,
};

控制器驱动层的关键回调功能:

  • transfer_one():执行单次SPI传输(发送+接收),通常通过FIFO或DMA完成。
  • set_cs():控制片选信号(GPIO或硬件片选),车载多从机场景需注意片选延迟。
  • handle_irq():处理传输完成中断、错误中断,唤醒等待队列。

2.4 数据流完整路径:从spi_sync到硬件时序

以下是一个典型的同步SPI传输数据流,展示三层之间的协作:

  1. 设备驱动层:调用 spi_sync(spi, &msg),将 spi_message 提交到核心层。
  2. 核心层:将消息加入 spi_controller 的传输队列,调用 __spi_pump_messages() 进行调度。
  3. 核心层:调用 spi_controller.prepare_message() 进行传输前准备。
  4. 核心层:调用 spi_controller.transfer_one_message(),该函数遍历消息中的所有 spi_transfer。
  5. 控制器驱动层:对每个transfer调用 .transfer_one(),配置SPI控制器的数据寄存器、时钟分频、片选极性。
  6. 硬件层:SPI控制器通过MOSI/MISO线完成数据移位,产生SCK时钟。
  7. 回调返回:传输完成后,控制器驱动触发中断或DMA完成回调,核心层调用 .unprepare_message(),最终唤醒等待的 spi_sync 调用者。
SPI同步传输数据流时序 SPI同步传输(spi_sync)数据流时序 ① spi_sync() ② 消息入队 ③ prepare_msg ④ transfer_one_msg ⑤ transfer_one() ⑥ 硬件移位 ⑦ unprepare_msg ⑧ 唤醒等待队列 层级归属:①⑧ 设备驱动层 | ②③⑦ 核心层 | ④⑤ 核心层→控制器驱动层 | ⑥ 硬件层 关键回调链:spi_sync → __spi_pump_messages → prepare_message → transfer_one_message → transfer_one 完成回调:transfer_one完成 → unprepare_message → spi_finalize_current_message → 唤醒spi_sync

2.5 车载工程中的回调定制要点

车载安全关键场景注意: 在ADAS或线控底盘系统中,SPI通信失败可能导致功能安全等级(ASIL)违规。定制回调时需注意:
  • 在 .transfer_one() 中增加超时看门狗,防止SPI总线锁死。
  • 在 .handle_irq() 中区分传输完成中断与错误中断(如帧错误、溢出),并上报错误状态。
  • 在 .set_cs() 中确保片选信号满足从机时序要求(如CS建立时间 > 50ns)。

通过理解SPI子系统的三层架构与回调机制,车载Linux工程师可以精准定位驱动问题,并针对特定硬件优化传输性能。下一节将深入讲解SPI控制器驱动中DMA与中断模式的配置参数。