4. 设备树常用属性详解:compatible、reg、interrupts、status、clocks、resets 等核心属性的含义与用法
设备树(Device Tree)中的属性(Property)是描述硬件配置与连接关系的基本单元。每个设备节点通过一组标准属性向内核驱动传递关键信息,包括设备类型、寄存器地址、中断号、时钟源、复位信号以及当前状态等。本章将逐一剖析这些核心属性的语义、语法规则与典型用法,帮助你在编写 SPI 与 I2C 设备节点时做到准确无误。
学习提示: 设备树属性是驱动与硬件之间的“契约”。属性值写错或遗漏,轻则设备无法识别,重则系统崩溃。建议在阅读本章时对照实际开发板的手册或原理图进行验证。
4.1 compatible 属性:设备与驱动的匹配钥匙
compatible 是设备树中最关键的属性,它指定了设备所兼容的驱动名称列表。内核在启动时通过该属性查找匹配的驱动,并完成设备与驱动的绑定。
- 格式: 字符串列表,按优先级从高到低排列。
- 命名规范:
"厂商,设备型号",例如"ti,ads1115"、"microchip,mcp2515"。 - 匹配机制: 内核遍历列表,依次尝试匹配驱动中的
of_match_table。
// SPI 设备节点示例
spi_device: ads1115@0 {
compatible = "ti,ads1115", "ti,ads1015"; // 优先匹配 ads1115,其次 ads1015
reg = <0>;
spi-max-frequency = <1000000>;
};
// I2C 设备节点示例
i2c_device: mpu6050@68 {
compatible = "invensense,mpu6050";
reg = <0x68>;
};
最佳实践: 始终将最精确的兼容字符串放在第一位,通用兼容字符串放在后面。这样既能支持特定型号的优化驱动,又能回退到通用驱动。
4.2 reg 属性:地址空间与片选编号
reg 属性用于描述设备在总线上的地址信息。对于 SPI 设备,它表示片选(CS)编号;对于 I2C 设备,它表示从设备地址。该属性由一组或多组 <地址 长度> 对组成。
| 总线类型 | reg 含义 | 典型格式 | 示例 |
|---|---|---|---|
| SPI | 片选编号(CS) | reg = <cs_num>; |
reg = <0>; 表示 CS0 |
| I2C | 7 位从设备地址 | reg = <address>; |
reg = <0x68>; 表示地址 0x68 |
| 内存映射设备 | 基地址 + 映射长度 | reg = <base_addr length>; |
reg = <0x10000000 0x1000>; |
// SPI 多片选示例
spi_controller: spi@ff040000 {
compatible = "rockchip,rk3399-spi";
reg = <0xff040000 0x1000>; // SPI 控制器自身寄存器
#address-cells = <1>;
#size-cells = <0>;
device0: flash@0 {
compatible = "jedec,spi-nor";
reg = <0>; // 片选 0
spi-max-frequency = <50000000>;
};
device1: sensor@1 {
compatible = "bosch,bme280";
reg = <1>; // 片选 1
spi-max-frequency = <10000000>;
};
};
// I2C 多设备示例
i2c_controller: i2c@ff3c0000 {
compatible = "rockchip,rk3399-i2c";
reg = <0xff3c0000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
rtc@51 {
compatible = "nxp,pcf8563";
reg = <0x51>; // I2C 从地址 0x51
};
eeprom@50 {
compatible = "atmel,24c02";
reg = <0x50>; // I2C 从地址 0x50
};
};
常见错误: I2C 地址写错是最高频的故障原因。注意:设备树中 I2C 地址使用 7 位地址(不含读写位),且必须与数据手册中的从设备地址一致。例如,MPU6050 的 7 位地址为 0x68,而非 0xD0(8 位地址)。
4.3 interrupts 属性:中断信号的描述
interrupts 属性定义了设备的中断请求信号。它通常与 interrupt-parent 配合使用,后者指定中断控制器节点。中断描述符包含中断号、触发类型等信息。
- 格式:
interrupts = <中断号 触发类型>; - 触发类型宏:
IRQ_TYPE_EDGE_RISING (1)— 上升沿触发IRQ_TYPE_EDGE_FALLING (2)— 下降沿触发IRQ_TYPE_LEVEL_HIGH (4)— 高电平触发IRQ_TYPE_LEVEL_LOW (8)— 低电平触发
// 带中断的 I2C 触摸屏节点
i2c@ff3c0000 {
touchscreen@38 {
compatible = "edt,edt-ft5406";
reg = <0x38>;
interrupt-parent = <&gpio3>; // 中断连接到 gpio3 控制器
interrupts = <14 IRQ_TYPE_EDGE_FALLING>; // GPIO3_14,下降沿触发
touchscreen-size-x = <800>;
touchscreen-size-y = <480>;
};
};
// 带中断的 SPI 网络控制器
spi@ff040000 {
can@0 {
compatible = "microchip,mcp2515";
reg = <0>;
interrupt-parent = <&gpio1>;
interrupts = <7 IRQ_TYPE_LEVEL_LOW>; // GPIO1_7,低电平触发
clocks = <&can_osc>;
spi-max-frequency = <10000000>;
};
};
4.4 status 属性:设备状态控制
status 属性用于控制设备节点的启用或禁用状态。它允许在不修改设备树源文件的情况下,通过设备树覆盖(overlay)或引导加载程序动态调整设备状态。
| 状态值 | 含义 | 使用场景 |
|---|---|---|
"okay" |
设备启用,驱动正常加载 | 默认启用状态 |
"disabled" |
设备禁用,驱动不加载 | 硬件未焊接、引脚冲突、调试时临时关闭 |
"reserved" |
设备保留,不由操作系统管理 | 固件或安全世界使用 |
"fail" |
设备检测失败 | 由引导程序自动设置 |
// 在 dtsi 文件中默认禁用,在具体板级 dts 中启用
// soc.dtsi
i2c2: i2c@ff3c0000 {
compatible = "rockchip,rk3399-i2c";
reg = <0xff3c0000 0x1000>;
status = "disabled"; // 默认禁用
};
// board.dts
&i2c2 {
status = "okay"; // 板级启用
clock-frequency = <400000>;
eeprom@50 {
compatible = "atmel,24c02";
reg = <0x50>;
status = "okay";
};
};
调试技巧: 当某个外设不工作时,首先检查
status 属性是否为 "okay"。很多情况下,设备树覆盖或引导参数可能意外地将设备设置为 "disabled"。使用 dtc -I dtb -O dts 反编译设备树二进制文件即可查看实际状态。
4.5 clocks 属性:时钟源与频率配置
clocks 属性指定设备使用的时钟源。它通过 phandle 引用时钟控制器节点,并可附带时钟索引或时钟 ID。时钟框架是 Linux 设备驱动中管理时钟频率与功耗的核心机制。
- 格式:
clocks = <&clock_controller clock_id>; - clock-names: 为每个时钟指定名称,便于驱动通过名称查找。
- 常见场景: SPI 控制器需要总线时钟,I2C 控制器需要参考时钟,外设需要工作时钟。
// SPI 控制器时钟配置
spi1: spi@ff1d0000 {
compatible = "rockchip,rk3399-spi";
reg = <0xff1d0000 0x1000>;
interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru SCLK_SPI1>, <&cru PCLK_SPI1>;
clock-names = "spi", "apb";
status = "disabled";
};
// I2C 设备时钟配置
i2c0: i2c@ff3c0000 {
compatible = "rockchip,rk3399-i2c";
reg = <0xff3c0000 0x1000>;
interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru SCLK_I2C0>, <&cru PCLK_I2C0>;
clock-names = "i2c", "apb";
status = "disabled";
};
// 外设时钟示例:SPI 连接的 ADC 需要外部时钟
spi0: spi@ff040000 {
adc@0 {
compatible = "ti,ads1256";
reg = <0>;
clocks = <&adc_osc>; // 外部晶振
clock-names = "adc_clk";
spi-max-frequency = <20000000>;
};
};
4.6 resets 属性:复位信号管理
resets 属性用于描述设备的复位信号。与时钟类似,它通过 phandle 引用复位控制器,并指定复位 ID。复位信号在设备初始化、电源管理以及错误恢复中至关重要。
- 格式:
resets = <&reset_controller reset_id>; - reset-names: 为每个复位信号命名,便于驱动识别。
- 典型用法: 在设备 probe 时释放复位,在 suspend 时断言复位以节省功耗。
// SPI 控制器复位配置
spi2: spi@ff1e0000 {
compatible = "rockchip,rk3399-spi";
reg = <0xff1e0000 0x1000>;
interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru SCLK_SPI2>, <&cru PCLK_SPI2>;
clock-names = "spi", "apb";
resets = <&cru SRST_SPI2>;
reset-names = "spi";
status = "disabled";
};
// I2C 控制器复位配置
i2c3: i2c@ff3d0000 {
compatible = "rockchip,rk3399-i2c";
reg = <0xff3d0000 0x1000>;
interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;
clock-names = "i2c", "apb";
resets = <&cru SRST_I2C3>;
reset-names = "i2c";
status = "disabled";
};
4.7 属性综合对比表
下表汇总了本章介绍的六个核心属性,方便你在编写设备节点时快速查阅。
| 属性名 | 功能 | SPI 设备用法 | I2C 设备用法 | 是否必需 |
|---|---|---|---|---|
compatible |
驱动匹配标识 | "厂商,型号" |
"厂商,型号" |
是 |
reg |
地址 / 片选 | 片选编号(0, 1, 2...) | 7 位 I2C 地址 | 是 |
interrupts |
中断描述 | 中断号 + 触发类型 | 中断号 + 触发类型 | 视设备而定 |
status |
设备状态控制 | "okay" / "disabled" |
"okay" / "disabled" |
推荐 |
clocks |
时钟源引用 | <&cru SCLK_SPI> |
<&cru SCLK_I2C> |
视设备而定 |
resets |
复位信号引用 | <&cru SRST_SPI> |
<&cru SRST_I2C> |
视设备而定 |
核心原则: 每个设备节点至少需要
compatible 和 reg 两个属性才能被内核正确识别。其他属性根据硬件设计需求选择性添加。在编写节点时,建议参考同一 SoC 平台的其他设备节点写法,保持风格一致。
4.8 本章小结
本章详细讲解了设备树中六个核心属性的语义与用法:
- compatible — 设备与驱动的匹配钥匙,遵循“厂商,型号”命名规范。
- reg — 地址空间描述,SPI 用片选编号,I2C 用从设备地址。
- interrupts — 中断信号描述,需配合 interrupt-parent 使用。
- status — 设备状态控制,支持 okay/disabled/reserved/fail。
- clocks — 时钟源引用,通过 phandle 指向 CRU 或外部晶振。
- resets — 复位信号引用,用于设备初始化与电源管理。