3. 设备树基础:设备树语法、节点属性、reg与interrupts属性详解
设备树(Device Tree,DT)是嵌入式 Linux 中描述硬件拓扑结构的核心机制。对于 RTC 驱动开发者而言,正确编写设备树节点是驱动能够被内核识别、资源能够正确分配的前提。本节将系统讲解设备树的语法结构、节点与属性定义,并重点剖析 reg 和 interrupts 这两个与 RTC 驱动直接相关的关键属性。
3.1 设备树语法基础
设备树源文件(.dts)采用树形结构描述硬件,每个硬件设备对应一个节点(node),节点内包含若干属性(property)。基本语法规则如下:
- 节点定义:
node-name@unit-address,其中unit-address通常为设备基地址。 - 属性格式:
property-name = <value>;或property-name = "string";。 - 标签(label):用于引用节点,如
rtc0: rtc@68。 - 包含文件:通过
#include引入.dtsi头文件,实现 SoC 级硬件描述复用。
关键点:设备树中的节点名称不直接决定驱动匹配,驱动通过
compatible 属性与设备节点绑定。
3.2 节点属性详解
设备树属性是描述设备特征的核心载体。下表列出 RTC 节点中最常用的属性及其含义:
| 属性名 | 格式 | 说明 | RTC 示例 |
|---|---|---|---|
compatible |
字符串列表 | 驱动匹配标识,格式为 "厂商,型号" |
"dallas,ds1307" |
reg |
<address length> |
描述设备地址空间(I2C 地址或内存映射基址) | <0x68 0x1>(I2C 地址 0x68) |
interrupts |
<irq flags> |
描述中断号及触发类型 | <2 IRQ_TYPE_EDGE_FALLING> |
interrupt-parent |
phandle | 指定中断控制器节点引用 | <&gpio1> |
status |
字符串 | 设备状态:"okay" 或 "disabled" |
"okay" |
clock-frequency |
整数 | 外部晶振频率(单位 Hz) | <32768> |
trickle-resistor-ohms |
整数 | RTC 涓流充电电阻值 | <2000> |
调试提示:使用
dtc -I dtb -O dts 反编译 DTB 文件,可验证设备树属性是否被正确编译和加载。
3.3 reg 属性:地址空间描述
reg 属性用于描述设备在总线上的地址范围。对于 RTC 设备,其含义因总线类型而异:
- I2C RTC:
reg的第一个值表示 7 位 I2C 从设备地址,第二个值通常为1(表示地址长度)。 - SPI RTC:
reg表示片选(CS)编号,地址长度通常为1。 - 内存映射 RTC:
reg表示寄存器基地址和映射长度,如<0x020b8000 0x1000>。
// I2C RTC 节点示例(DS1307)
rtc0: rtc@68 {
compatible = "dallas,ds1307";
reg = <0x68 0x1>; // I2C 地址 0x68
interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio1>;
status = "okay";
};
// 内存映射 RTC 节点示例(SoC 内置 RTC)
rtc1: rtc@200b8000 {
compatible = "vendor,soc-rtc";
reg = <0x200b8000 0x1000>; // 基址 0x200b8000,长度 4KB
interrupts = <0 43 4>; // GIC SPI 中断号 43,高电平触发
status = "okay";
};
3.4 interrupts 属性:中断描述
interrupts 属性描述设备的中断请求线。其格式取决于中断控制器类型:
| 中断控制器类型 | interrupts 格式 | 说明 |
|---|---|---|
| GPIO 中断控制器 | <gpio_irq flags> |
gpio_irq 为 GPIO 引脚号,flags 为触发类型 |
| GIC(通用中断控制器) | <type irq flags> |
type=0 为 SPI(共享外设中断),type=1 为 PPI(私有外设中断) |
| 级联中断控制器 | <parent_irq child_irq flags> |
父控制器中断号 + 子控制器中断号 |
中断触发类型 flags 常用宏定义(定义在 include/dt-bindings/interrupt-controller/irq.h):
IRQ_TYPE_EDGE_RISING(1):上升沿触发IRQ_TYPE_EDGE_FALLING(2):下降沿触发IRQ_TYPE_LEVEL_HIGH(4):高电平触发IRQ_TYPE_LEVEL_LOW(8):低电平触发
常见错误:I2C RTC 的中断引脚通常为开漏输出,应使用
IRQ_TYPE_EDGE_FALLING 或 IRQ_TYPE_LEVEL_LOW,而非电平触发中的高电平模式,否则可能导致中断丢失或死锁。
3.5 设备树节点与驱动匹配流程
下图展示了从设备树节点到驱动 probe 函数的完整匹配流程:
3.6 完整 RTC 设备树节点示例
以下是一个典型的 I2C RTC 设备树节点,集成本节所述的全部关键属性:
// 在 i2c 总线节点下定义 RTC 子节点
&i2c1 {
status = "okay";
clock-frequency = <100000>; // 100kHz I2C 时钟
rtc@68 {
compatible = "maxim,ds3231", "dallas,ds1307";
reg = <0x68 0x1>;
interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
interrupt-parent = <&gpio2>;
status = "okay";
// 可选属性:晶振频率、涓流充电配置
clock-frequency = <32768>;
trickle-resistor-ohms = <2000>;
aux-voltage-chargeable = <1>;
};
};
调试技巧:在驱动 probe 函数中添加
dev_info(dev, "reg addr: 0x%llx, irq: %d\n", res->start, irq); 打印,验证设备树解析是否正确。若 irq 为 0 或负数,说明 interrupts 属性解析失败。
3.7 常见设备树错误与排查方法
| 错误现象 | 可能原因 | 排查方法 |
|---|---|---|
| 驱动 probe 未被调用 | compatible 字符串不匹配 | 检查 of_match_table 与设备树中的 compatible 是否一致 |
| reg 读取为 0 | reg 属性格式错误或地址长度不匹配 | 使用 dtc -I dtb -O dts 反编译确认 reg 值 |
| 中断无法注册 | interrupt-parent 缺失或指向错误 | 检查 /proc/interrupts 确认中断控制器是否注册 |
| 设备树编译报错 | 语法错误或引用的标签未定义 | 使用 dtc -@ -I dts -O dtb 编译并查看错误行号 |