3. 设备树常用属性:compatible、reg、interrupts、status、model 等核心属性详解
设备树(Device Tree)中的每个节点都通过一系列属性(Properties)来描述硬件设备的特征、资源需求和工作状态。这些属性是内核驱动与硬件信息之间的桥梁。本章将深入解析最核心的五个属性:compatible、reg、interrupts、status 和 model,并结合实战案例说明其用法。
核心要点:设备树属性本质上是“键-值”对。键是字符串,值可以是字符串、整数数组、二进制数据或字符串列表。理解每个属性的编码规则和语义,是编写正确设备树的前提。
3.1 compatible 属性:驱动匹配的“身份证”
compatible 是设备树中最重要的属性,它指定了设备与内核驱动之间的匹配关系。其值是一个字符串列表,格式通常为 "厂商,型号"。
- 匹配顺序:内核在加载驱动时,会按照设备树中
compatible列表的从前到后顺序,依次与驱动中of_match_table里的字符串进行匹配。第一个匹配成功的驱动将被绑定。 - 命名规范:推荐使用全小写字母,厂商名与型号之间用逗号分隔,例如
"ti,am335x-uart"、"fsl,imx6q-uart"。 - 兼容性设计:通常将最具体的型号放在最前面,通用型号放在后面。例如
"ti,am335x-uart", "ns16550",表示该设备兼容 TI 的 AM335x UART,同时也兼容标准的 16550 UART。
实战示例:以下代码展示了一个 UART 节点的 compatible 属性及其对应的内核驱动匹配表。
// 设备树节点
uart0: serial@44e09000 {
compatible = "ti,am335x-uart", "ns16550";
reg = <0x44e09000 0x2000>;
interrupts = <72>;
status = "okay";
};
// 内核驱动中的匹配表 (Linux 内核源码示例)
static const struct of_device_id omap_uart_of_match[] = {
{ .compatible = "ti,am335x-uart", .data = &am335x_uart_data, },
{ .compatible = "ti,omap2-uart", .data = &omap2_uart_data, },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, omap_uart_of_match);
3.2 reg 属性:描述地址空间与资源范围
reg 属性用于描述设备在系统总线上的地址空间,通常包含一个或多个 地址/长度对。其格式为 reg = <address1 length1 [address2 length2] ...>。
- 地址单元:地址和长度的位数由父节点的
#address-cells和#size-cells属性决定。通常#address-cells = <1>表示 32 位地址,#address-cells = <2>表示 64 位地址。 - 多段描述:如果一个设备有多个不连续的地址区域(如 FIFO 缓冲区、控制寄存器、数据寄存器),可以使用多个地址/长度对。
- 资源映射:内核通过
platform_get_resource()或of_iomap()等 API 从reg属性中获取物理地址并映射到虚拟地址空间。
常见错误:忘记在父节点中正确设置
#address-cells 和 #size-cells,或者子节点的 reg 属性中地址/长度数量与父节点定义不匹配,会导致内核解析失败,驱动无法获取正确的资源。
// 父节点定义地址单元
soc {
compatible = "simple-bus";
#address-cells = <1>; // 32位地址
#size-cells = <1>; // 32位长度
// 子节点使用 reg 描述两段地址空间
ethernet: ethernet@4a100000 {
compatible = "ti,cpsw";
reg = <0x4a100000 0x800 // 控制寄存器基址+长度
0x4a100800 0x100>; // 数据寄存器基址+长度
interrupts = <40 41>;
status = "okay";
};
};
3.3 interrupts 属性:连接中断控制器
interrupts 属性用于描述设备产生的中断信号,其格式依赖于父节点(中断控制器)的 #interrupt-cells 属性。通常包含中断号和触发类型。
- 中断号:在 ARM GIC(通用中断控制器)中,通常使用 SPI(共享外设中断)或 PPI(私有外设中断)编号。
- 触发类型:常见值包括
IRQ_TYPE_EDGE_RISING(上升沿触发)、IRQ_TYPE_LEVEL_HIGH(高电平触发) 等。 - 多中断:如果一个设备有多个中断源(如 TX 中断、RX 中断),可以在
interrupts属性中列出多个中断描述。 - 中断父节点:通过
interrupt-parent属性指定该设备连接的中断控制器节点。如果未指定,则继承父节点的中断控制器。
实战示例:以下代码展示了一个 GPIO 按键的中断配置,使用上升沿触发。
// 中断控制器节点 (GIC)
gic: interrupt-controller@48241000 {
compatible = "arm,cortex-a15-gic";
#interrupt-cells = <3>; // 格式: <中断类型 中断号 触发类型>
interrupt-controller;
reg = <0x48241000 0x1000>;
};
// 使用中断的设备节点
key: gpio-keys {
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&gpio1>; // 连接到 GPIO 控制器
button@0 {
label = "User Button";
linux,code = <KEY_ENTER>;
interrupts = <3 IRQ_TYPE_EDGE_RISING>; // GPIO1_3 上升沿中断
status = "okay";
};
};
3.4 status 属性:控制设备启用状态
status 属性用于指示设备的启用或禁用状态。它允许在不修改硬件描述的情况下,通过设备树来启用或禁用某个外设。
| 状态值 | 含义 | 说明 |
|---|---|---|
"okay" |
设备已启用 | 内核将正常探测并初始化该设备 |
"disabled" |
设备已禁用 | 内核将跳过该设备,不进行探测 |
"reserved" |
设备保留 | 通常用于固件保留的设备,操作系统不应使用 |
"fail" |
设备检测失败 | 表示设备在硬件上存在但检测失败,通常由 Bootloader 设置 |
最佳实践:在 SoC 的 dtsi 文件中,通常将外设的 status 默认设置为
"disabled",然后在具体的板级 dts 文件中,根据实际硬件情况将需要启用的外设设置为 "okay"。这样可以避免未使用的外设占用资源。
// SoC 级 dtsi 文件 (默认禁用)
i2c0: i2c@44e0b000 {
compatible = "ti,am335x-i2c";
reg = <0x44e0b000 0x1000>;
interrupts = <70>;
status = "disabled"; // 默认禁用
};
// 板级 dts 文件 (启用并配置)
&i2c0 {
status = "okay"; // 在板级文件中启用
clock-frequency = <400000>;
pinctrl-names = "default";
pinctrl-0 = <&i2c0_pins>;
};
3.5 model 属性:描述设备型号
model 属性是一个字符串,用于描述设备或板卡的具体型号。它通常出现在根节点或设备节点中,提供人类可读的硬件标识信息。
- 根节点使用:在根节点中,
model属性描述整个开发板的型号,例如"TI AM335x BeagleBone Black"。 - 设备节点使用:在具体设备节点中,
model属性可以描述该设备的精确型号,例如"Samsung S5K5BAFX 5MP Camera"。 - 与 compatible 的区别:
compatible用于驱动匹配,是内核编程接口;model主要用于信息展示和调试,不参与驱动匹配逻辑。
// 根节点中的 model 属性
/ {
model = "TI AM335x BeagleBone Black";
compatible = "ti,am335x-bone-black", "ti,am335x-bone", "ti,am33xx";
#address-cells = <1>;
#size-cells = <1>;
// 设备节点中的 model 属性
lcd: display@0 {
compatible = "ilitek,ili9341";
model = "ILI9341 2.8 inch TFT LCD";
reg = <0>;
status = "okay";
};
};
3.6 属性综合实战:构建一个完整的 I2C 设备节点
下面通过一个完整的 I2C 温度传感器节点,综合运用本章所学的五个核心属性。
// I2C 控制器节点
i2c2: i2c@4819c000 {
compatible = "ti,omap4-i2c";
reg = <0x4819c000 0x1000>;
interrupts = <30>;
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
clock-frequency = <100000>;
// 挂载在 I2C 总线上的温度传感器
temp_sensor: temperature-sensor@48 {
compatible = "ti,tmp102"; // 驱动匹配
reg = <0x48>; // I2C 从设备地址
interrupts = <5 IRQ_TYPE_EDGE_FALLING>; // 中断配置
model = "TI TMP102 Digital Temperature Sensor"; // 型号描述
status = "okay"; // 启用设备
};
};
实战要点:
- compatible:使用
"ti,tmp102"与内核中的 TMP102 驱动匹配。 - reg:在 I2C 子节点中,reg 表示从设备地址
0x48,而不是内存地址。 - interrupts:使用
5号中断,下降沿触发。 - status:显式设置为
"okay",确保设备被探测。 - model:提供人类可读的型号信息,便于调试。
3.7 属性使用避坑指南
| 属性 | 常见错误 | 正确做法 |
|---|---|---|
| compatible | 字符串拼写错误,或顺序颠倒 | 严格遵循 "厂商,型号" 格式,最具体在前 |
| reg | 地址/长度数量与父节点 cells 不匹配 | 检查父节点 #address-cells 和 #size-cells |
| interrupts | 中断号超出范围,或触发类型错误 | 查阅芯片手册,确认中断号和 GIC 类型 |
| status | 忘记设置,或拼写为 "ok"、"disable" | 使用标准值 "okay" 或 "disabled" |
| model | 与 compatible 混淆,或包含特殊字符 | 仅用于描述,使用简洁明了的字符串 |
重要提醒:设备树属性是大小写敏感的。
"okay" 不能写成 "OK" 或 "Ok";"ti,am335x-uart" 不能写成 "TI,AM335X-UART"。错误的拼写会导致驱动匹配失败或设备无法正常工作。