1. 驱动研究的思路首先我们需要搭建驱动的框架图这样便于我们理解驱动从搭建到工作的数据流向把 SPI 的框架分成四个部分用户层 →内核层 → 硬件层1.1 用户层用户层在 SPI 架构中处于“顶端”。它的核心地位是业务逻辑的来源与控制指令的发起者。在 Linux 中用户层并不直接控制物理引脚那是内核驱动的任务用户层通过标准化接口将“要发什么数据”、“发多快”、“什么模式”等高级需求下发给内核即交给内核层进行处理。用户层不需要关心底层的时序、片选电平变化或中断处理它只负责数据的定义与组织。用户层的使用方法逻辑流程用户层使用 SPI 的过程是一个典型的“三步走”流程本质上是在进行配置与交互契约的建立设备发现与映射 (Open)含义用户程序通过访问 /dev/spidevX.Y 设备节点在用户态与内核中的 spidev 驱动之间建立连接。逻辑Linux 将 SPI 外设抽象为字符设备。这里的 X.Y 明确了物理上哪个 SPI 控制器Master的哪一个片选引脚正在被操作。参数约定与数据封装含义用户层定义本次通信的协议细节。逻辑用户层通过填充一个特定的数据结构如 spi_ioc_transfer 结构体明确告知内核通信配置频率Speed、位宽Bits、模式Mode如极性/相位设置。数据缓冲区明确发送缓冲区Tx的内存地址以及接收缓冲区Rx的内存地址。长度明确此次传输数据的字节数。执行同步调用 (ioctl)含义这是用户层与内核层的边界跨越点。逻辑用户层使用 ioctl 系统调用将封装好的“传输协议”一次性交付给内核。此时控制权从用户态切换到内核态。内核的 spidev 驱动接收到这些请求解析协议将其进一步拆解并交给 SPI 子系统的内核层最后由底层的硬件控制器执行真正的物理传输。传输完成后结果同步返回给用户层用户层即可从指定的接收缓冲区中读取数据。1.2 内核层以下是 内核层 的三大核心内容(抽象层主控层接口层)抽象层 (SPI Core)“规则的制定者”职能定位抽象层是 Linux SPI 子系统的核心它位于 drivers/spi/spi.c充当硬件控制器主控层与外设驱动接口层之间的中间件。它屏蔽了不同 SoC 硬件架构的差异为驱动开发者提供了一套统一的、平台无关的编程接口。核心动作构建总线骨架通过 bus_register 创建 spi_bus_type确立 SPI 总线的管理空间定义总线的探测、匹配与移除规则。维护匹配机制管理 spi_device硬件描述与 spi_driver驱动程序的映射表。通过对比 compatible 属性实现驱动的自动加载与 probe 触发。标准化 API 分发向上导出 spi_sync、spi_async、spi_write/read 等标准化接口并将外设驱动提交的逻辑请求Message进行序列化。队列仲裁调度实现 spi_pump_messages 机制维护一个传输队列确保同一时刻只有一个传输请求占用物理控制器负责 CPU 睡眠/唤醒的调度。核心职责全局状态管理维护系统中所有控制器Controllers和外设Devices的注册状态分配总线编号如 spi0、spi1。请求转译与映射将外设驱动定义的业务抽象spi_transfer 结构体链表映射为控制器能够执行的物理任务。阻塞与回调处理管理进程上下文同步模式下的睡眠与 wait_for_completion和中断上下文异步模式下的 callback 触发实现请求执行效率的最大化核心动作中的标准化 API 分发解释标准化 API 分发在 Linux 内核中API 分发是指 SPI 核心层 (spi_core) 通过导出一组通用的函数接口强制所有协议驱动外设驱动遵循统一的调用规范。技术定义抽象层定义了 spi_sync、spi_async 等函数原型这些函数在 include/linux/spi/spi.h 中声明。实现机制无论底层是哪种 SoC 的 SPI 控制器如 i.MX6 的 eCSPI 或其他架构协议驱动开发者无需针对具体硬件编写驱动代码。开发者只需构造标准的 spi_message 结构体并将该指针传递给 spi_sync 或 spi_async。本质这是接口抽象化。核心层SPI Core通过制定标准化 API在调用者接口层与 被调用者主控层)之间确立了统一的交互契约从而实现了业务逻辑与物理驱动的解耦确保了驱动程序在不同硬件平台上的高度兼容性。序列化序列化是指核心层通过排队机制将并发的异步传输请求转化为单线程的、串行的传输序列以符合 SPI 物理总线“同一时刻只能处理一个传输”的特性。技术定义SPI 控制器物理上是一个半双工或全双工的共享总线无法同时处理来自不同设备Device的多条 spi_message。核心层通过 spi_pump_messages 机制实现这一需求。具体过程1挂载当接口层调用 spi_async 或 spi_sync 时核心层将传入的 spi_message 挂载到对应控制器实例struct spi_controller的传输队列queue 链表中。2调度核心层维护一个后台工作队列或内核线程。当总线处于空闲状态时该线程被激活。3处理线程从队列中取出队首的 spi_message将其交由控制器驱动的 transfer_one 回调函数执行。4互斥在传输完成之前后续的请求会被持续挂载到队列中直到当前传输完成并触发回调核心层才会从队列中取出下一个 spi_message。本质这是并发控制与资源仲裁。它保证了即便外设驱动在用户空间或中断上下文中并发提交了多个请求物理总线上的信号流也不会因多设备竞争而发生冲突或损坏。同步与异步映射(spi_sync/async)同步映射 (spi_sync) 的逻辑进程状态发起请求后当前进程被挂起睡眠。CPU 行为调度器切换进程去处理别的任务。驱动行为驱动程序在调用 spi_sync 的那一行代码停住了直到硬件传输完成中断唤醒它它才会继续执行 spi_sync 后面的代码。也就是说同步映射的时候当前执行线程会被挂起进入睡眠态此时内核调度器会释放 CPU 资源去处理其他任务从而提高系统利用率。当硬件完成数据传输并产生中断后内核唤醒该线程继续执行。场景适合线性逻辑代码写起来像在操作普通文件。异步映射 (spi_async) 的逻辑进程状态发起请求后当前进程不被挂起继续向下执行立即返回。CPU 行为CPU 接着执行 spi_async 下面的代码。驱动行为驱动程序不需要“等”。你在发起请求时必须通过一个 回调函数 (Callback Function) 告诉内核“等你硬件传输完了请去执行这个函数”。传输完成时当硬件传输完成并产生中断内核会在中断上下文中去调用你之前定义的那个回调函数。也就是说异步映射的时候CPU会继续向下执行后面的代码直到传输完成后硬件向 CPU 发送硬件中断内核在处理中断过程中调用预留的回调函数。场景适合高性能场景如网卡、复杂传感器数据采集驱动程序可以在 SPI 还在传输数据的时候去处理别的数据包大大提高了并发能力。主控层 (Controller Driver)“即控制器驱动注册”。这是 SPI 子系统的“通道提供者”它位于 SoC 内部如 eCSPI 模块。核心动作注册控制器对象spi_register_controller向系统声明“我具备通过物理引脚驱动总线的能力”。职责负责将抽象层传递下来的标准化数据包spi_message翻译成特定硬件芯片能识别的寄存器配置和物理引脚信号时钟、MOSI/MISO、片选并处理传输过程中的中断与 DMA 请求。接口层 (Protocol/Device Driver)“业务的执行者”接口层是 Linux 驱动模型中直接对接特定硬件外设如传感器、显示屏、存储芯片的一层。它的工作逻辑可以被视为一个“翻译官”将操作系统定义的抽象接口翻译为特定硬件的物理通信序列。核心功能1.设备节点创建/dev/spidevX.Y2.数据交互spidev_read 和 spidev_write 调用 spi_sync3.控制流spidev_ioctl 用户态动态修改SPI参数4.同步与异步的映射用户态结构体如何映射到 spi_transfer向上接口驱动到系统的业务呈现接口层的主要职能是为用户空间提供访问硬件的能力使硬件功能对应用程序可见即提供设备节点接口。1设备模型实例化当驱动执行 probe 时它会调用内核 API如 cdev_add、input_register_device 或 hwmon_device_register在 /dev 或 /sys 下创建节点。2业务逻辑实现①字符设备接口通过实现 file_operations如 read, write, ioctl让用户空间能够以操作普通文件的方式读取传感器数据。②子系统对接将获取的物理数据填入内核标准子系统如 Input 子系统用于按键Hwmon 子系统用于温度MTD 子系统用于 Flash。这样用户空间程序无需关心 SPI 细节只需读取标准的系统接口即可。3并发控制在向上提供接口时接口层必须处理好用户并发访问的问题通常使用 mutex 或 spinlock 保证 spi_message 在发送时的数据一致性。向下接口驱动到总线的请求序列化这是接口层作为“协议终端”执行通信的核心逻辑它决定了数据如何通过 SPI 总线传输。通信环境配置 (Setup)利用 spi_setup() 预设通信协议参数时钟极性、频率等确保满足外设 Datasheet 的时序要求。协议构建 (Construction)将业务逻辑拆解为 spi_transfer 序列如“发送地址接收数据”的组合并封装进 spi_message 容器。服务调用 (Service Request)通过调用 SPI Core 导出的 spi_sync 或 spi_async将请求托付给总线进行排队与调度。视角动作核心内容对上用户暴露功能提供设备节点、实现文件操作接口File Ops、提供语义化的数据读取方式。对下总线实现协议设置通信时序Setup、封装传输请求Transfer、解析原始数据流。SPI 子系统数据流向闭环向上 (Up / Towards User Space)方向指朝向用户空间 (User Space)、应用程序的方向。含义越往“上”越接近业务逻辑越远离底层物理硬件。例子接口层向上对接的是 /dev/ 下的设备节点或者像 Hwmon (硬件监控)、Input (输入系统) 这种直接服务于应用层的子系统。向下 (Down / Towards Hardware)方向指朝向物理硬件 (Hardware/Controller) 的方向。含义越往“下”越接近物理电路、寄存器、电平信号。例子主控层向下操作 SoC 里的 eCSPI 寄存器控制引脚的高低电平。1. 下行流从“业务请求”到“物理信号”这一阶段数据从业务层通过接口封装最终被转化为物理引脚的电平变化。接口层 (发起与构造)操作定义外设协议如 0x9F 指令。封装将数据填入 spi_transfer并将多个传输单元打包成 spi_message 容器。投递调用 spi_sync 或 spi_async将容器交付给抽象层这两个API是属于抽象层的之前提到过抽象层进行标准化 API 分发这里接口层就是作用使用者调用了抽象层的 API 接口。抽象层 (核心调度与序列化)排队将 spi_message 放入该控制器对应的 queue 链表中确保独占访问总线。调度由内核线程如 spi_pump从队首取出消息并将控制权通过 transfer_one 回调传递给主控层。主控层 (物理翻译与执行)解析将 spi_message 拆解为控制寄存器参数如时钟配置、片选电平。驱动通过中断或 DMA 搬运数据驱动物理引脚MOSI/MISO/SCK完成电平切换。接口层→抽象层→主控层在 SPI 子系统的运行过程中抽象层SPI Core作为中间枢纽分别与接口层和主控层签署了不同性质的“契约”。以下是下行流向上契约接口层 ↔ 抽象层任务委托向上契约指的是抽象层Core向它上方的层级接口层提供的服务契约。动作核心接口层协议驱动通过填写 spi_message 数据结构构建本次传输的任务描述符并将其提交给抽象层。任务定义接口层通过 spi_message 明确告知“我需要将缓冲区 A 的数据发送并将响应存储到缓冲区 B请完成这一任务。”抽象层的职能作为“物流中心”抽象层负责搬运数据但不修改数据本身。它负责处理请求的入队、优先级排序和并发控制确保“托付”的任务能安全抵达目的地。屏蔽差异的本质接口层通过遵循此契约彻底摆脱了对底层控制器实现细节如 DMA 配置、中断向量选择的依赖。对于接口层而言硬件交互是透明的。向下契约抽象层 ↔ 主控层执行细节向下契约指的是抽象层Core向它下方的层级主控层提出的执行要求。动作核心抽象层在调度完成后调用主控层预设的 transfer_one 接口函数函数钩子/Hook。职责定义主控层控制器驱动作为“物理执行者”通过实现 transfer_one 回调将抽象层传来的数据指令转化为 SoC 的底层硬件行为。物理实现在此阶段主控层负责操作 SoC 内部寄存器精确控制 SCK 时钟波形、MOSI/MISO 电平翻转及片选CS时序。屏蔽差异的本质主控层通过遵循此契约无需知晓上层业务的具体意义无论是读传感器、写 Flash 还是屏幕显示。它只负责把数据按照 SPI 总线规范“打”在线路上对于主控层而言业务逻辑是不可见Blind的。2. 上行流从“物理电平”到“业务确认”这一阶段硬件完成传输后通过中断机制将状态反馈回上层。主控层 (中断捕获)反馈物理传输完成硬件触发中断控制器驱动读取状态寄存器确认传输结束。通知调用抽象层提供的 spi_finalize_current_transfer 接口。抽象层 (状态交付)同步逻辑唤醒调用 spi_sync 时被阻塞的进程wait_for_completion。异步逻辑在中断上下文执行预注册的 message-complete 回调函数。接口层 (结果解析)数据读取从 Rx Buffer 中读取反馈回来的原始字节流。语义化将字节流转化为业务意义如解析出温度值 25.5°C并将其反馈给用户空间的应用程序。主控层→抽象层→接口层SPI 子系统上行流 (结果反馈契约模型)向下契约主控层 ↔ 抽象层状态反馈动作核心当物理层传输完成主控层触发硬件中断。在中断服务程序ISR中主控层通过调用抽象层提供的接口如 spi_finalize_current_transfer来交付结果。契约内容主控层向抽象层汇报“我已经执行完了任务这是传输后的状态成功或失败并且已将硬件读取到的数据存入了对应的 Rx Buffer。”抽象层的职能作为“状态收集器”抽象层负责核对任务状态释放被占用的总线资源并判断当前传输是否为 spi_message 的最后一环。反馈的本质主控层无需关心上层如何处理数据它只负责报告物理传输的“完结状态”。向上契约抽象层 ↔ 接口层结果交付动作核心抽象层根据传输发起时的模式同步或异步执行对应的唤醒操作或回调逻辑。契约内容抽象层通知接口层“你之前委托的任务已经完成缓冲区 B 中的数据已准备好请查收。”同步模式调用 complete(message-done)将处于睡眠态的调用进程唤醒。异步模式在中断上下文执行预注册的 message-complete 回调函数。接口层的职能作为“业务解析者”接口层接收到通知后进入缓冲区读取结果并将其转化为具体的业务含义如将原始电压值转为温度读数。反馈的本质接口层无需关心底层是如何产生的信号波动或中断它只需要依据“任务完成”的契约在约定的内存位置处理数据即可。1.3 硬件层硬件层在 SPI 架构中处于“底层”。它的核心地位是物理通信的执行主体与数据信号的源头。在 Linux SPI 架构中硬件层是驱动程序所操控的真实物理对象。它并非由内核代码构成但它是内核驱动代码的终极映射目标。驱动程序的每一行寄存器操作最终都会在硬件层通过电子信号的形式表现出来。硬件层不理解业务意义它只遵循固定的电子时序逻辑进行数据的移位与采样。硬件层的使用方法物理逻辑流程1. 物理链路连接含义这是 SPI 总线通信的基础由 SoC 的物理引脚通过 PCB 走线连接至外设芯片如传感器、Flash。逻辑包括四条核心物理线SCLK (时钟线决定传输速度)、MOSI (主发从收)、MISO (主收从发)、以及 CS/SS (片选线决定当前通信的目标从设备)。2. 时序协议执行含义硬件层依据预设的 SPI 模式Mode 0-3进行时序动作。逻辑当控制器驱动开始工作时硬件层严格执行以下物理动作片选触发将指定的 CS 引脚电平由高拉低激活从设备。位移驱动依据 SCLK 时钟的上升沿或下降沿在 MOSI/MISO 线上进行位的推入与采样。数据锁存在传输完成后将数据存入移位寄存器或通过 DMA 存入内存。3. 中断与状态触发含义硬件层是通信结果的物理见证者。逻辑当一次完整的传输任务如 8 个时钟脉冲结束后硬件层会改变自身的状态寄存器并向 SoC 的中断控制器发送一个硬件中断信号。这个信号是内核层感知“传输完成”的唯一物理依据从而触发内核的后续回调流程。硬件层与主控层的映射关系硬件层与主控层之间的关系可以总结为向下映射契约 (主控层 ↔ 硬件层)职责定义主控层是硬件层的操控者。映射逻辑代码中的“寄存器位”如 SPI_CR1 寄存器中的 SPE 位必须精确对应硬件手册Datasheet中的物理功能。屏蔽差异的本质硬件层通过寄存器向主控层提供一组物理控制接口。只要主控层正确翻转了寄存器硬件层就一定会产生对应的物理波形。这种映射使得内核驱动能够以“软件思维”控制“物理世界”。