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 函数的完整匹配流程:

设备树节点与驱动匹配流程 设备树节点 compatible = "dallas,ds1307" 内核 OF 子系统 解析 DTB,创建 device_node 驱动匹配表 of_match_table 扫描 驱动 probe 函数 获取 reg / interrupts 资源 of_iomap / of_get_address 解析 reg 属性 of_irq_get / request_irq 解析 interrupts 属性 rtc_device_register / devm_rtc_device_register 注册到 RTC 核心框架 说明: 驱动通过 compatible 匹配节点后,使用 OF API(of_iomap、of_irq_get)从设备树中提取 reg 和 interrupts 配置。 错误解析将导致资源获取失败,RTC 设备无法正常工作。

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 编译并查看错误行号