1. Linux SPI子系统概述
SPI(Serial Peripheral Interface)作为嵌入式领域最常用的同步串行通信协议之一,在传感器、存储设备、显示模块等外设连接中扮演着关键角色。Linux内核中的SPI子系统自2.6版本引入后,经过多年迭代已形成成熟的驱动框架。本次研究的4.9.88版本内核正处于长期支持(LTS)周期,其SPI实现兼具稳定性和现代特性。
在实际项目中,我发现很多开发者对SPI子系统的理解停留在表面API调用层面。本文将结合4.9.88内核源码,深入剖析SPI核心层(drivers/spi/spi.c)、主机控制器驱动(如spi-bcm2835.c)以及设备驱动(如spidev.c)的三层架构关系。特别值得注意的是,这个版本的内核已经支持了DMA传输、多设备片选等高级特性,但相关文档却十分匮乏。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. SPI子系统架构深度解析
2.1 核心层实现机制
内核的spi.c文件定义了子系统的基础设施,其中几个关键数据结构需要重点理解:
-
struct spi_controller:代表物理SPI控制器,包含传输函数指针、DMA配置等硬件相关参数。在4.9.88中新增了dma_map_dev字段,用于支持IOMMU设备。 -
struct spi_device:描述连接到控制器的具体设备,包含模式、频率等配置信息。这里有个易错点——很多人会混淆chip_select和cs_gpio的区别:前者是控制器内部的片选编号,后者则是使用GPIO模拟片选时的引脚号。 -
struct spi_transfer:描述单次传输的数据块,其中的delay_usecs字段在4.9.88中被优化为支持纳秒级延时。我曾在一个高速ADC项目中,就因为这个延时精度不足导致采样率上不去。
2.2 主机控制器驱动开发要点
以流行的bcm2835驱动为例,注册控制器时需要特别注意:
c复制static int bcm2835_spi_probe(struct platform_device *pdev)
{
ctlr = spi_alloc_master(&pdev->dev, sizeof(*bs));
ctlr->mode_bits = SPI_CPOL |
