SPI 是时钟同步、全双工的串行总线,但它不定义统一的寄存器协议、设备发现方式或数据帧格式。Linux SPI 子系统因此将两类职责拆开:控制器驱动管理 SoC 的时钟、FIFO、DMA、片选和中断;协议驱动理解某颗传感器、Flash 或 ADC 的命令、寄存器和数据格式。设备树或其他固件描述负责告诉内核“哪条总线上挂着哪颗设备”。
三层对象如何配合
spi_controller 对应硬件控制器;设备树节点创建 spi_device,其中包含 chip select、mode、最大频率等板级信息;spi_driver 通过 of_match_table 匹配并在 probe 中初始化具体器件。协议驱动将一个或多个 spi_transfer 组合为 spi_message,同步提交或异步提交给 controller。
SPI mode 和片选边界不能靠猜
CPOL/CPHA 决定时钟空闲电平与采样边沿,设备树 spi-cpol、spi-cpha/mode 配错时,逻辑分析仪上可能“有波形”却数据全错。频率、bits-per-word、bit order、CS 极性和 transfer 间 CS 是否保持,也都由器件 datasheet 决定。多段读寄存器事务常要求“命令和数据之间 CS 不能释放”。
1 | struct spi_transfer xfers[] = { |
控制器是否能在相邻 transfer 间保持 CS、是否改用 DMA、最小/最大传输长度,都应查 controller capability 和实际硬件波形。
驱动调试从外到内
先确认运行时设备树节点、compatible、chip select、频率和 pinctrl;再确认 controller 已 probe、时钟/复位/供电资源可用;随后在 protocol driver probe 中读取一个稳定的识别寄存器;最后用逻辑分析仪检查 CS、SCLK、MOSI/MISO、mode 和帧长度。不要一开始就怀疑“SPI 子系统有 bug”。
spidev 很适合 bring-up 和产测工具,但不是绕开正式协议驱动的长期替代品。内核需要知道设备的电源管理、并发、错误恢复和系统 suspend/resume 语义,才能让硬件稳定地融入系统。