4. Linux SPI 子系统架构:核心层、控制器驱动层、设备驱动层的关系与数据流

Linux SPI 子系统采用经典的分层架构设计,将硬件控制逻辑、协议抽象与设备操作解耦。理解这三层的关系与数据流,是进行全志 T113 SPI 驱动开发与性能调优的基础。本章将深入剖析 SPI 核心层、控制器驱动层(SPI Master)与设备驱动层(SPI Device Driver)的职责、交互机制以及数据在层间的流动路径。

4.1 三层架构总览

SPI 子系统在 Linux 内核中位于 drivers/spi/ 目录下,其架构从上到下依次为:

  • SPI 设备驱动层:挂载在 SPI 总线上的具体外设驱动(如 ADC、触摸屏、显示控制器),通过 SPI 核心层提供的 API 与控制器通信。
  • SPI 核心层:提供统一的框架,管理 SPI 总线、设备注册、消息队列调度以及数据传输的抽象接口。
  • SPI 控制器驱动层:直接操作硬件寄存器,实现 SPI 时序、DMA 传输、中断处理等底层功能。
架构优势:这种分层使得设备驱动开发者无需关心底层寄存器细节,控制器驱动开发者无需关心具体外设协议,核心层则负责协调两者,极大提高了代码复用性和可移植性。

4.2 核心数据结构与角色

三层架构通过几个关键数据结构紧密关联:

数据结构 所属层次 核心作用
struct spi_controller 核心层 / 控制器层 代表一个 SPI 主机控制器,包含总线号、传输队列、时钟设置、DMA 配置以及底层传输函数指针(transfer_one、transfer_one_message)。
struct spi_device 核心层 / 设备层 代表挂载在 SPI 总线上的一个从设备,包含片选号、模式(CPOL/CPHA)、最大速度、bits_per_word 等配置。
struct spi_message 核心层 一次原子传输的请求,包含一个或多个 spi_transfer 结构,由核心层排队并提交给控制器驱动。
struct spi_transfer 核心层 描述一次单向或双向的数据传输,包含发送/接收缓冲区、长度、速度、延迟等参数。
struct spi_driver 设备驱动层 SPI 设备驱动结构体,包含 probe、remove、id_table 等回调,用于与 SPI 核心层进行设备匹配和生命周期管理。

4.3 分层关系与交互流程

下图展示了 SPI 子系统三层之间的静态关系与动态数据流:

SPI 子系统三层架构与数据流 SPI 设备驱动层 (SPI Device Driver) spi_driver.probe() → spi_setup() → spi_write_then_read() struct spi_driver | struct spi_device | 设备节点 (/dev/spidevX.Y) SPI 核心层 (SPI Core) spi_register_controller() | spi_register_driver() | 消息队列调度 struct spi_controller | struct spi_message | struct spi_transfer SPI 控制器驱动层 (SPI Master Driver) transfer_one() | transfer_one_message() | prepare_message() 硬件寄存器操作 | DMA 配置 | 中断处理 (全志 T113 SPI 控制器) spi_write() / spi_read() __spi_pump_messages() 中断回调 / DMA 完成 complete() 唤醒 数据流方向:设备驱动 → 核心层排队 → 控制器驱动硬件传输 → 中断/DMA完成 → 核心层回调 → 设备驱动唤醒

4.4 数据流详细路径

一次典型的 SPI 读写操作(例如全志 T113 上的 SPI 触摸屏读取坐标)的数据流如下:

  1. 设备驱动发起请求:调用 spi_write_then_read() 或构造 spi_message 并调用 spi_async()。
  2. 核心层消息排队:核心层将 spi_message 添加到控制器驱动的消息队列中,并通过 __spi_pump_messages() 调度。
  3. 控制器驱动准备传输:调用 prepare_message() 设置硬件寄存器(如 T113 的 SPI 控制寄存器、时钟分频、DMA 地址)。
  4. 硬件传输:控制器驱动执行 transfer_one(),启动 SPI 时钟,通过 FIFO 或 DMA 逐字节交换数据。
  5. 中断/DMA 完成:传输完成触发中断或 DMA 完成回调,控制器驱动调用 spi_finalize_current_message()。
  6. 核心层回调:核心层调用 spi_message.complete 回调函数,唤醒等待的设备驱动。
  7. 设备驱动处理数据:设备驱动从接收缓冲区解析数据,完成一次读写操作。
性能关键点:在全志 T113 上,数据流中的瓶颈通常出现在步骤 3(寄存器配置开销)和步骤 5(中断延迟)。调优时需关注 transfer_one 的实现效率以及是否启用了 DMA 来减少 CPU 干预。

4.5 各层关键接口与回调

下表总结了各层之间交互的核心函数接口:

接口函数 所属层 调用方向 说明
spi_async() 设备驱动 → 核心层 异步提交消息 非阻塞,立即返回,通过 complete 回调通知结果
spi_sync() 设备驱动 → 核心层 同步提交消息 阻塞等待传输完成,内部调用 spi_async
__spi_pump_messages() 核心层 → 控制器驱动 消息调度 从队列取出消息,调用控制器驱动的 transfer_one_message
transfer_one_message() 控制器驱动 核心层回调 处理整个消息(可能包含多个 transfer),负责硬件传输
transfer_one() 控制器驱动 核心层回调 处理单个 transfer,适用于简单控制器
spi_finalize_current_message() 控制器驱动 → 核心层 传输完成通知 在中断或 DMA 完成上下文中调用,唤醒等待的设备驱动
spi_setup() 设备驱动 → 核心层 设备配置 设置 spi_device 的模式、速度、bits_per_word 等参数

4.6 全志 T113 中的分层实现特点

在全志 T113 平台,SPI 控制器驱动(spi-sunxi.c)的实现有以下特点:

  • 控制器驱动注册:通过 spi_alloc_master() 分配 spi_controller,设置 transfer_one 回调为 sunxi_spi_transfer_one,并注册到核心层。
  • 硬件队列支持:T113 的 SPI 控制器内置 64 字节 FIFO,驱动利用 prepare_message 预填充 FIFO,减少中断次数。
  • DMA 集成:当传输长度超过阈值(通常 64 字节)时,驱动自动切换到 DMA 模式,通过 dmaengine_slave_config 配置源/目的地址。
  • 中断处理:传输完成中断(TC)和 FIFO 空/满中断分别处理,中断服务程序调用 spi_finalize_current_message 通知核心层。
调优陷阱:在 T113 上,如果 SPI 时钟频率设置过高(超过 100 MHz),FIFO 可能因时序紧张而出现数据溢出。此时应检查 transfer_one 中的时钟分频配置,并考虑降低频率或启用 DMA 以缓解 FIFO 压力。

4.7 分层架构对性能调优的指导意义

理解三层架构有助于精准定位性能瓶颈:

  • 设备驱动层:检查是否频繁调用 spi_sync 导致上下文切换开销,建议批量传输或使用 spi_async 配合回调。
  • 核心层:消息队列深度和调度策略影响吞吐量,可通过调整 spi_controller.rt 标志启用实时调度。
  • 控制器驱动层:transfer_one 的实现效率是性能核心,应减少寄存器读写次数,充分利用 FIFO 和 DMA。