2. Linux SPI子系统架构:三层架构与核心数据结构

Linux SPI子系统采用经典的分层设计思想,将SPI总线操作抽象为SPI核心层、SPI控制器驱动层和SPI设备驱动层。这种分层架构使得控制器厂商和设备厂商可以独立开发驱动,通过标准接口完成数据交互。理解这三层架构及其对应的数据结构,是编写高效SPI控制器驱动的基础。

Linux SPI子系统三层架构 SPI设备驱动层 spi_driver / spi_device 实现具体外设(ADC、传感器、显示屏等)的读写协议 通过spi_transfer构造消息,调用spi_async/spi_sync发起传输 SPI核心层 spi.c / spi.h 管理spi_master与spi_device的注册/注销 提供spi_async/spi_sync/spi_write_then_read等通用API SPI控制器驱动层 spi_master / spi_controller 实现硬件FIFO、DMA、GPIO片选等底层操作 填充master->transfer_one_message / transfer_one / set_cs等回调 数据传输方向:设备驱动 → 核心层 → 控制器驱动 → SPI总线 → 硬件外设

2.1 SPI核心层(SPI Core)

SPI核心层位于drivers/spi/spi.c,是连接设备驱动与控制器驱动的桥梁。核心层负责总线注册、设备枚举、数据传输调度以及通用API的提供。

核心层主要职责

  • 总线管理:注册SPI总线类型(spi_bus_type),维护spi_master和spi_device的链表。
  • 设备与驱动匹配:通过设备树(Device Tree)或ACPI、板级代码创建设备,并与spi_driver进行匹配。
  • 传输调度:将spi_device发起的spi_transfer队列化,调用控制器驱动的回调执行实际传输。
  • 通用API封装:提供同步(spi_sync)、异步(spi_async)以及便捷函数(spi_write_then_read)。
关键点:核心层不直接操作硬件寄存器,所有硬件访问都通过控制器驱动的回调函数完成。这种设计保证了核心层的平台无关性。

2.2 SPI控制器驱动层

控制器驱动层是SPI子系统的硬件抽象层,直接与SoC的SPI控制器硬件交互。该层需要实现struct spi_master(或struct spi_controller)中的回调函数,完成FIFO操作、DMA配置、片选控制等底层逻辑。

spi_master核心数据结构

字段/回调 类型 说明
bus_num u16 SPI总线编号,用于标识控制器实例
num_chipselect u16 支持的片选信号数量
mode_bits u32 支持的SPI模式位掩码(CPOL/CPHA/CS_HIGH等)
flags u32 控制器能力标志(如DMA支持、FIFO大小等)
transfer_one_message 回调 处理整个消息队列,默认实现由核心层提供
transfer_one 回调 处理单个spi_transfer,控制器驱动通常重写此函数
set_cs 回调 控制片选信号的电平状态
prepare_message 回调 在消息传输前进行硬件准备(如配置DMA)
unprepare_message 回调 消息传输完成后的清理工作
dma_rx/dma_tx dma_chan* DMA通道句柄,用于FIFO+DMA传输优化
控制器驱动开发要点:在probe()函数中分配spi_master,设置bus_num、num_chipselect、mode_bits,并注册transfer_one和set_cs回调。对于支持FIFO和DMA的控制器,还需要配置dma_rx/dma_tx通道。

2.3 SPI设备驱动层

设备驱动层面向具体的SPI外设(如MCP2515 CAN控制器、AD7793 ADC、SPI Flash等)。设备驱动通过struct spi_driver注册到SPI总线,使用struct spi_device访问控制器。

spi_device与spi_driver

数据结构 关键字段 说明
spi_device chip_select, max_speed_hz, mode, bits_per_word, controller_state 代表一个SPI从设备,由核心层在设备树解析或板级代码中创建
spi_driver probe, remove, id_table, driver 设备驱动结构体,通过spi_register_driver()注册
spi_transfer tx_buf, rx_buf, len, speed_hz, delay_usecs, cs_change 描述一次SPI传输的缓冲区、长度、速率和时序参数

spi_transfer传输流程

  1. 设备驱动构造一个或多个spi_transfer,填充发送缓冲区、接收缓冲区、传输长度等参数。
  2. 将spi_transfer添加到spi_message中,调用spi_sync()或spi_async()提交消息。
  3. 核心层将消息加入控制器的消息队列,调用控制器驱动的transfer_one_message或transfer_one。
  4. 控制器驱动根据传输参数配置硬件寄存器,启动FIFO或DMA传输。
  5. 传输完成后,控制器驱动调用spi_finalize_current_message()通知核心层,核心层唤醒等待的设备驱动。
spi_transfer 数据结构与传输流程 struct spi_transfer tx_buf : const void* rx_buf : void* len : unsigned speed_hz : u32 cs_change : u8 struct spi_message transfers : list_head complete : void (*)(void*) context : void* status : int actual_length : unsigned spi_message_add_tail() 传输执行流程 ① 设备驱动构造transfer ② 加入message并调用spi_sync() ③ 核心层入队调度 ④ 控制器驱动执行硬件传输 ⑤ 回调complete通知完成 优化切入点:控制器驱动在步骤④中利用FIFO批量传输减少CPU干预, 或使用DMA将数据搬运完全交给硬件,实现零CPU拷贝传输。 数据流向:spi_device → spi_message → spi_master → 硬件FIFO/DMA → SPI总线 每个spi_transfer可以独立配置速率、字长和片选行为,支持同一消息内不同transfer切换配置

2.4 三层架构的交互流程

当设备驱动发起一次SPI读写时,三层架构按照以下顺序协同工作:

步骤 所在层 操作描述
1 设备驱动层 构造spi_transfer,设置tx_buf/rx_buf/len,调用spi_sync()
2 核心层 将spi_message加入master->queue,调用master->transfer_one_message
3 控制器驱动层 解析spi_transfer,配置控制器寄存器(波特率、模式、FIFO阈值)
4 控制器驱动层 启动FIFO传输或触发DMA请求,硬件自动完成数据移位
5 控制器驱动层 传输完成中断或DMA完成回调,调用spi_finalize_current_message()
6 核心层 唤醒等待队列,设备驱动获取传输结果(msg->status和msg->actual_length)
常见误区:初学者容易在设备驱动中直接操作控制器寄存器,这破坏了分层架构。正确的做法是设备驱动只通过spi_sync/spi_async与核心层交互,所有硬件寄存器操作必须封装在控制器驱动中。

2.5 数据结构关系总结

以下表格总结了三个核心数据结构在分层架构中的角色和关联:

数据结构 所属层 创建者 使用者 生命周期
spi_master 控制器驱动层 控制器驱动probe() 核心层、控制器驱动 与控制器硬件绑定,直到驱动卸载
spi_device 核心层/设备驱动层 核心层(设备树解析) 设备驱动 从设备枚举到移除
spi_transfer 设备驱动层 设备驱动 核心层、控制器驱动 单次传输,完成后释放
架构设计优势:三层架构使得SPI控制器驱动可以复用同一套核心层代码,设备驱动无需关心底层硬件差异。例如,一个SPI Flash驱动可以在不同SoC上运行,只要各SoC提供了符合规范的控制器驱动。本课程后续章节将重点讲解如何在控制器驱动层实现FIFO和DMA优化,以提升传输吞吐量并降低CPU占用率。