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 子系统三层之间的静态关系与动态数据流:
4.4 数据流详细路径
一次典型的 SPI 读写操作(例如全志 T113 上的 SPI 触摸屏读取坐标)的数据流如下:
- 设备驱动发起请求:调用
spi_write_then_read()或构造spi_message并调用spi_async()。 - 核心层消息排队:核心层将
spi_message添加到控制器驱动的消息队列中,并通过__spi_pump_messages()调度。 - 控制器驱动准备传输:调用
prepare_message()设置硬件寄存器(如 T113 的 SPI 控制寄存器、时钟分频、DMA 地址)。 - 硬件传输:控制器驱动执行
transfer_one(),启动 SPI 时钟,通过 FIFO 或 DMA 逐字节交换数据。 - 中断/DMA 完成:传输完成触发中断或 DMA 完成回调,控制器驱动调用
spi_finalize_current_message()。 - 核心层回调:核心层调用
spi_message.complete回调函数,唤醒等待的设备驱动。 - 设备驱动处理数据:设备驱动从接收缓冲区解析数据,完成一次读写操作。
性能关键点:在全志 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。