3. 设备树中SPI节点的描述
在嵌入式Linux系统中,SPI外设的硬件拓扑与驱动绑定完全通过设备树(Device Tree)描述。设备树节点分为两层:SPI控制器节点(定义主机端SPI总线能力)和SPI从设备子节点(定义挂载在总线上的具体外设)。正确配置这两层节点的属性,是SPI驱动正常工作的前提。
核心原则:SPI控制器节点提供总线控制器的硬件资源(寄存器基址、中断、时钟、DMA等);SPI从设备子节点描述外设的片选、通信速率、模式及与驱动的绑定关系。两者通过父子层级结构关联。
3.1 SPI控制器节点属性
SPI控制器节点通常位于SoC的soc或amba总线节点下,其compatible属性匹配对应的SPI主机驱动。以下为典型控制器节点属性清单:
| 属性名 | 类型 | 说明 | 示例值 |
|---|---|---|---|
compatible |
string | 匹配SPI主机驱动,格式"厂商,型号" | "rockchip,rk3399-spi" |
reg |
u32/u64对 | 控制器寄存器基址与长度 | <0xff1c0000 0x1000> |
interrupts |
u32 | SPI控制器中断号 | |
clocks |
phandle | SPI模块时钟与PCLK时钟 | <&cru SCLK_SPI0>, <&cru PCLK_SPI0> |
clock-names |
string-list | 时钟名称,与clocks对应 | "spi", "apb_pclk" |
dmas |
phandle | DMA通道(可选) | <&dmac 0>, <&dmac 1> |
dma-names |
string-list | DMA通道名称 | "tx", "rx" |
#address-cells |
u32 | 子节点地址单元数,固定为1 | <1> |
#size-cells |
u32 | 子节点大小单元数,固定为0 | <0> |
提示:
#address-cells = <1> 和 #size-cells = <0> 是SPI控制器的固定约定。子节点的reg属性仅表示片选编号(CS index),而非地址范围。
以下为完整的SPI控制器节点示例(以Rockchip RK3399为例):
spi0: spi@ff1c0000 {
compatible = "rockchip,rk3399-spi";
reg = <0xff1c0000 0x1000>;
interrupts = ;
clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
clock-names = "spi", "apb_pclk";
dmas = <&dmac 0>, <&dmac 1>;
dma-names = "tx", "rx";
#address-cells = <1>;
#size-cells = <0>;
status = "disabled";
/* 子节点在此处添加 */
};
3.2 SPI从设备子节点属性
每个挂载在SPI总线上的外设,在控制器节点内以一个子节点表示。子节点的reg属性指定片选编号,compatible属性匹配具体设备驱动。以下为关键属性详解:
3.2.1 reg属性——片选编号
reg在SPI子节点中表示片选线索引(CS index),从0开始。控制器根据该值驱动对应的GPIO或硬件片选信号。一个控制器最多支持多个片选,具体数量由硬件决定。
/* 片选0上的温度传感器 */
temp_sensor: sensor@0 {
reg = <0>; /* CS0 */
compatible = "ti,lm70";
spi-max-frequency = <5000000>;
};
/* 片选1上的ADC */
adc_device: adc@1 {
reg = <1>; /* CS1 */
compatible = "ti,ads7950";
spi-max-frequency = <10000000>;
};
3.2.2 compatible属性——驱动匹配
格式为"厂商,型号",内核SPI设备驱动通过of_match_table匹配该字符串。支持多级兼容(如"ti,lm70", "ti,lm71"),驱动优先匹配第一个。
3.2.3 spi-max-frequency属性——最大通信速率
指定该从设备支持的最大SPI时钟频率(单位Hz)。控制器驱动在初始化时会根据该值配置SCLK分频系数。实际通信速率不得超过该值,否则可能导致数据错误。
常见错误:spi-max-frequency设置过高(超过从设备规格)会导致通信不稳定;设置过低则浪费总线带宽。建议参考从设备数据手册的SCLK上限,并保留20%余量。
3.2.4 SPI模式属性
通过以下布尔属性配置SPI模式(CPOL/CPHA组合):
| 属性 | 作用 | 对应模式 |
|---|---|---|
spi-cpol |
时钟极性:空闲时SCLK为高电平 | 模式1/3(CPOL=1) |
spi-cpha |
时钟相位:数据在第二个边沿采样 | 模式2/3(CPHA=1) |
spi-3wire |
三线模式(无MISO/MOSI区分) | 半双工模式 |
spi-cs-high |
片选信号高电平有效(默认低有效) | 片选极性反转 |
spi-lsb-first |
LSB先传输(默认MSB先) | 位序反转 |
模式组合示例:
/* SPI模式3:CPOL=1, CPHA=1 */
flash@0 {
reg = <0>;
compatible = "jedec,spi-nor";
spi-max-frequency = <80000000>;
spi-cpol; /* 空闲高电平 */
spi-cpha; /* 第二个边沿采样 */
};
3.3 完整设备树节点示例
以下展示一个包含两个从设备的完整SPI控制器节点:
&spi0 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&spi0_clk &spi0_csn0 &spi0_mosi &spi0_miso>;
/* 从设备1:SPI NOR Flash */
flash@0 {
reg = <0>;
compatible = "jedec,spi-nor";
spi-max-frequency = <50000000>;
spi-cpol;
spi-cpha;
m25p,fast-read;
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "bootloader";
reg = <0x0 0x100000>;
};
partition@100000 {
label = "kernel";
reg = <0x100000 0x300000>;
};
};
};
/* 从设备2:SPI温度传感器 */
temp@1 {
reg = <1>;
compatible = "ti,lm70";
spi-max-frequency = <5000000>;
spi-3wire; /* 三线模式 */
};
};
关键检查点:
- 控制器节点
status = "okay"确保使能; - 子节点
reg值必须与硬件片选GPIO对应; spi-max-frequency不能超过控制器最大支持频率和从设备规格的较小值;- SPI模式属性(cpol/cpha)必须与从设备数据手册一致,否则通信失败。
3.4 常见配置错误与排查
| 错误现象 | 可能原因 | 排查方法 |
|---|---|---|
| 驱动probe不调用 | compatible不匹配或status="disabled" | 检查/sys/firmware/devicetree/下节点内容 |
| SPI通信数据全0xFF | 片选未选中或模式不匹配 | 用示波器测量CS/SCLK/MOSI波形 |
| 通信速率异常 | spi-max-frequency超出硬件能力 | 降低频率测试,检查时钟树配置 |
| 多个设备冲突 | reg值重复或片选GPIO冲突 | 确保每个子节点reg唯一 |
调试技巧:使用
dtc -I dtb -O dts反编译设备树二进制,确认节点属性是否被正确编译。运行时查看/proc/device-tree/下的属性值,验证内核解析结果。