4. 常用设备树属性:compatible、reg、interrupts、status、clocks、gpios 等属性详解
设备树属性是连接硬件描述与内核驱动行为的桥梁。每个节点通过一组标准属性向内核传递硬件拓扑、地址映射、中断路由、时钟与 GPIO 依赖等关键信息。本章将逐一拆解最常用的六大属性,结合 DTB 加载与驱动 probe 阶段的排查要点,帮助你在实际调试中快速定位属性配置错误。
排查前置提醒: 属性值写错(如大小写、地址位数、中断类型码)是 DTB 加载失败或驱动 probe 返回 -ENODEV 的最常见原因。建议始终对照芯片参考手册与内核 binding 文档逐字段校验。
4.1 compatible —— 驱动匹配的“身份证”
compatible 属性是设备节点与内核驱动之间建立绑定的核心字段。驱动通过 of_match_table 中的字符串列表与设备树节点的 compatible 值进行精确匹配。
4.1.1 格式与匹配规则
- 格式:
"厂商,型号",例如"ti,am335x-uart"、"fsl,imx6q-uart"。 - 匹配顺序: 内核优先匹配列表中的第一个字符串;若驱动支持多个兼容型号,则按
of_match_table中的顺序依次尝试。 - 通配符: 不支持下划线或通配符,必须精确字符串匹配。
// 设备树节点示例
uart0: serial@44e09000 {
compatible = "ti,am335x-uart", "ti,omap3-uart";
reg = <0x44e09000 0x2000>;
interrupts = <72>;
};
// 驱动匹配表示例
static const struct of_device_id omap_uart_of_match[] = {
{ .compatible = "ti,am335x-uart", .data = &am335x_uart_data },
{ .compatible = "ti,omap3-uart", .data = &omap3_uart_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, omap_uart_of_match);
常见排查点: 驱动 probe 未执行时,优先检查
compatible 字符串是否与驱动中的 of_match_table 完全一致(包括大小写、连字符、逗号后是否有空格)。使用 dtc -I dtb -O dts 反编译 DTB 确认实际值。
4.1.2 匹配流程 SVG
4.2 reg —— 地址空间与内存映射
reg 属性描述设备在系统总线上的地址范围。内核通过它完成 IO 资源注册,驱动调用 of_iomap() 或 platform_get_resource() 获取映射后的虚拟地址。
4.2.1 格式与地址单元
| 属性 | 含义 | 示例 |
|---|---|---|
#address-cells |
地址字段占用的 32 位单元数 | 1(32位地址)、2(64位地址) |
#size-cells |
长度字段占用的 32 位单元数 | 1(32位长度)、2(64位长度) |
reg |
地址 + 长度对,格式为 <addr size> |
<0x44e09000 0x2000> |
// 32位地址空间示例
soc {
#address-cells = <1>;
#size-cells = <1>;
uart0: serial@44e09000 {
reg = <0x44e09000 0x2000>; // 起始地址 0x44e09000,长度 0x2000
};
};
// 64位地址空间示例
pcie@40000000 {
#address-cells = <3>;
#size-cells = <2>;
reg = <0x00 0x40000000 0x00 0x10000000>; // 高32位 低32位 高32位长度 低32位长度
};
排查技巧: 使用
cat /proc/iomem 查看内核注册的 IO 资源是否与 DTB 中的 reg 一致。若驱动 probe 返回 -EBUSY,通常意味着 reg 地址范围与其他设备重叠。
4.2.2 reg 解析流程 SVG
4.3 interrupts —— 中断路由与触发类型
interrupts 属性描述设备的中断请求线。它依赖 interrupt-parent 指定中断控制器,并通过 #interrupt-cells 定义每个中断描述所需的单元数。
4.3.1 中断描述格式
| 中断控制器类型 | #interrupt-cells | 格式说明 |
|---|---|---|
| GIC(通用中断控制器) | 3 | <中断类型 中断号 触发标志> |
| 简单中断控制器 | 1 | <中断号> |
| 级联中断控制器 | 2 | <父中断号 子中断号> |
// GIC 中断示例(ARM 平台)
gic: interrupt-controller@48241000 {
compatible = "arm,cortex-a15-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x48241000 0x1000>;
};
uart0: serial@44e09000 {
compatible = "ti,am335x-uart";
reg = <0x44e09000 0x2000>;
interrupt-parent = <&gic>;
interrupts = <0 72 4>; // 类型:SPI(0) 中断号:72 触发:高电平(4)
};
常见排查点: 中断号与触发类型必须与芯片手册完全一致。使用
cat /proc/interrupts 查看中断是否注册成功;若中断未触发,检查 interrupt-parent 的 phandle 是否正确指向中断控制器节点。
4.3.2 中断路由 SVG
4.4 status —— 设备启用控制
status 属性控制设备节点是否被内核枚举。它通常用于在 board-level DTS 中覆盖 SoC 级 DTSI 中的设备状态。
4.4.1 可选值及含义
| 值 | 含义 | 内核行为 |
|---|---|---|
"okay" |
设备启用 | 正常创建 platform_device,调用 probe |
"disabled" |
设备禁用 | 跳过该节点,不创建设备 |
"reserved" |
保留状态 | 通常用于特殊固件场景 |
"fail" |
设备故障 | 内核标记为不可用 |
// SoC 级 DTSI 中默认禁用
uart0: serial@44e09000 {
compatible = "ti,am335x-uart";
reg = <0x44e09000 0x2000>;
status = "disabled";
};
// Board 级 DTS 中启用
&uart0 {
status = "okay";
};
排查技巧: 若驱动 probe 未执行,首先检查
status 是否为 "okay"。使用 cat /proc/device-tree/<path>/status 查看当前状态值。注意字符串必须小写,"OK" 或 "Ok" 均无效。
4.5 clocks —— 时钟依赖与频率配置
clocks 属性描述设备依赖的时钟源。它通过 phandle 引用时钟控制器节点,驱动使用 clk_get() 或 devm_clk_get() 获取时钟句柄。
4.5.1 时钟属性格式
// 时钟控制器定义
clocks {
uart0_clk: clock@44e00000 {
compatible = "ti,am335x-clock";
#clock-cells = <0>;
clock-frequency = <48000000>;
};
};
// 设备引用时钟
uart0: serial@44e09000 {
compatible = "ti,am335x-uart";
reg = <0x44e09000 0x2000>;
clocks = <&uart0_clk>;
clock-names = "fck";
};
4.5.2 时钟属性对比表
| 属性 | 作用 | 驱动获取方式 |
|---|---|---|
clocks |
时钟 phandle 列表 | of_clk_get() |
clock-names |
时钟名称列表,与 clocks 一一对应 | devm_clk_get(dev, name) |
clock-frequency |
固定频率(用于无时钟控制器场景) | of_property_read_u32() |
常见排查点: 时钟未使能是驱动挂死或数据传输异常的主要原因。使用
cat /sys/kernel/debug/clk/clk_summary 查看时钟是否已开启;检查 clock-names 是否与驱动中的字符串匹配。
4.6 gpios —— GPIO 引用与配置
gpios 属性(或 cs-gpios、reset-gpios 等命名后缀)描述设备使用的 GPIO 引脚。驱动通过 gpiod_get() 或 of_get_named_gpio() 获取 GPIO 描述符。
4.6.1 GPIO 属性格式
// GPIO 控制器定义
gpio0: gpio@44e07000 {
compatible = "ti,am335x-gpio";
#gpio-cells = <2>;
gpio-controller;
reg = <0x44e07000 0x1000>;
};
// 设备引用 GPIO
led0 {
compatible = "gpio-leds";
gpios = <&gpio0 15 GPIO_ACTIVE_HIGH>; // GPIO0_15, 高电平有效
};
// 带名称的 GPIO 引用
spi0: spi@48030000 {
compatible = "ti,am335x-spi";
cs-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>,
<&gpio0 11 GPIO_ACTIVE_LOW>;
};
4.6.2 GPIO 属性排查表
| 排查项 | 检查方法 | 典型错误 |
|---|---|---|
| GPIO 号越界 | 对比芯片手册 GPIO 范围 | 引用了不存在的 GPIO bank |
| GPIO 复用冲突 | 检查 pinctrl 配置 | 同一引脚被两个设备使用 |
| 有效电平错误 | 确认 GPIO_ACTIVE_HIGH/LOW | LED 常亮或常灭 |
| phandle 错误 | 检查 gpio-controller 节点路径 | 编译报错或 probe 返回 -EINVAL |
4.6.3 GPIO 引用关系 SVG
4.7 属性综合排查对照表
| 属性 | 驱动获取 API | 常见错误 | 排查命令 |
|---|---|---|---|
compatible |
of_match_table |
字符串不匹配、大小写错误 | dtc -I dtb -O dts |
reg |
platform_get_resource() |
地址越界、#address-cells 不匹配 | cat /proc/iomem |
interrupts |
platform_get_irq() |
中断号错误、触发类型不匹配 | cat /proc/interrupts |
status |
内核自动判断 | 拼写错误、未设置为 "okay" | cat /proc/device-tree/.../status |
clocks |
devm_clk_get() |
时钟未使能、clock-names 不匹配 | cat /sys/kernel/debug/clk/clk_summary |
gpios |
gpiod_get() |
GPIO 号越界、复用冲突 | cat /sys/kernel/debug/gpio |
核心原则: 设备树属性的本质是“硬件拓扑的静态描述”。驱动通过标准 API 解析这些属性,任何解析失败都会导致 probe 提前返回。排查时遵循“从 DTB 原始值 → 内核解析结果 → 驱动使用方式”的三层验证路径,可以快速定位 90% 的属性相关问题。