3. DTS常用属性

设备树(Device Tree Source, DTS)通过一系列标准属性来描述硬件设备的特征、资源需求和连接关系。掌握这些核心属性是编写正确设备树文件的基础,也是实现设备树覆盖(Overlay)与热插拔驱动的关键前提。本章将逐一详解最常用的五大属性:compatible、reg、interrupts、status 和 gpios。

学习提示: 这些属性并非孤立存在,它们共同构成了内核与设备驱动之间的“契约”。理解每个属性的语义、格式和约束,能帮助你在调试设备树问题时快速定位错误。

3.1 compatible 属性:设备与驱动的匹配钥匙

compatible 属性是设备树中最核心的字符串属性,它指定了设备的“兼容性”标识。内核通过该属性查找并绑定对应的设备驱动。

  • 格式: 一个或多个字符串,按优先级从高到低排列。
  • 命名规范: 通常采用 "厂商,设备型号" 的形式,例如 "ti,am335x-uart"、"fsl,imx6q-uart"。
  • 匹配机制: 内核驱动中的 of_match_table 会与设备节点的 compatible 值进行精确匹配。匹配成功则调用驱动的 probe 函数。
实战案例: 一个 I2C 触摸屏节点的 compatible 属性可以同时声明多个兼容型号,确保驱动向后兼容。
// 设备树节点
i2c_touch: touch@38 {
    compatible = "edt,edt-ft5406", "edt,edt-ft5x06";
    reg = <0x38>;
    interrupt-parent = <&gpio1>;
    interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
};

上述代码中,内核会优先尝试匹配 "edt,edt-ft5406",若失败则尝试 "edt,edt-ft5x06"。这种机制允许一个驱动支持多个硬件版本。

compatible 属性匹配流程 设备节点 compatible = "A","B" 内核匹配层 of_match_table 匹配成功 调用 probe() 匹配失败 尝试下一个 compatible 说明:compatible 列表中的顺序决定了匹配优先级,第一个匹配成功即停止搜索。

3.2 reg 属性:定义设备地址空间

reg 属性用于描述设备在总线上的地址范围,通常由一组或多组 (地址, 长度) 对组成。它直接对应硬件寄存器的物理地址空间。

属性字段 含义 示例值
address-cells 父节点中定义,表示地址字段占用的 32 位单元数 <1> 或 <2>
size-cells 父节点中定义,表示长度字段占用的 32 位单元数 <1> 或 <2>
reg 实际的地址-长度对列表 <0x10000000 0x1000>
常见错误: 忘记在父节点中正确设置 #address-cells 和 #size-cells,会导致内核解析 reg 时出现地址错位或长度错误。
// 父节点定义地址格式
soc {
    #address-cells = <1>;
    #size-cells = <1>;

    // 子节点使用 reg 属性
    uart0: serial@10000000 {
        compatible = "ns16550a";
        reg = <0x10000000 0x1000>;  // 基地址 0x10000000,长度 0x1000
        interrupts = <33>;
        clock-frequency = <1843200>;
    };

    gpio0: gpio@10001000 {
        compatible = "brcm,bcm2835-gpio";
        reg = <0x10001000 0x100>;   // 基地址 0x10001000,长度 0x100
        interrupts = <17>;
        gpio-controller;
        #gpio-cells = <2>;
    };
};

在驱动代码中,通过 of_iomap() 或 platform_get_resource() 函数获取 reg 属性定义的物理地址,并将其映射到内核虚拟地址空间。

reg 属性地址映射关系 设备树节点 reg = <0x1000 0x200> #address-cells = <1> 物理地址空间 基址: 0x1000 长度: 0x200 内核虚拟映射 ioremap() 驱动访问 说明:reg 属性定义物理地址,内核通过 ioremap 将其映射为虚拟地址供驱动使用。 address-cells 和 size-cells 决定了 reg 中每个地址-长度对的解析方式。

3.3 interrupts 属性:中断资源描述

interrupts 属性用于描述设备使用的中断号、触发类型等信息。它通常与 interrupt-parent 属性配合使用,后者指定中断控制器节点。

  • interrupt-parent: 指向中断控制器的 phandle,若子节点未定义,则继承父节点的值。
  • interrupts: 一个或多个中断描述符,格式由中断控制器的 #interrupt-cells 决定。
  • 常见触发类型:
    • IRQ_TYPE_EDGE_RISING (1) — 上升沿触发
    • IRQ_TYPE_EDGE_FALLING (2) — 下降沿触发
    • IRQ_TYPE_LEVEL_HIGH (4) — 高电平触发
    • IRQ_TYPE_LEVEL_LOW (8) — 低电平触发
// 中断控制器定义
gic: interrupt-controller@10400000 {
    compatible = "arm,gic-400";
    reg = <0x10400000 0x10000>;
    interrupt-controller;
    #interrupt-cells = <3>;  // GIC 使用 3 个 cell: 中断类型、编号、触发标志
};

// 使用中断的设备节点
ethernet@20000000 {
    compatible = "smsc,lan9115";
    reg = <0x20000000 0x1000>;
    interrupt-parent = <&gic>;
    interrupts = <0 33 4>;  // SPI 中断,编号 33,高电平触发
};
关键点: 中断号在设备树中通常是硬件中断号,而非 Linux IRQ 号。内核通过 irq_domain 机制完成映射。
中断路由结构 外设设备 interrupts = <33 4> 中断控制器 #interrupt-cells = <3> irq_domain 映射 CPU 内核 Linux IRQ 号 说明:interrupt-parent 指向中断控制器,interrupts 提供硬件中断信息,内核完成最终映射。

3.4 status 属性:设备状态控制

status 属性用于控制设备节点的启用或禁用状态,是设备树覆盖(Overlay)中实现热插拔逻辑的核心属性之一。

status 值 含义 典型使用场景
okay 设备已启用,驱动可以正常探测 默认使能设备
disabled 设备被禁用,驱动不会探测 硬件未焊接、或需要动态控制
fail 设备检测失败,驱动不会探测 硬件自检失败时由 Bootloader 设置
reserved 设备保留,不用于当前系统 多平台兼容时使用
避坑指南: 在 Overlay 中,若父节点 status = "disabled",即使子节点 status = "okay",子设备也不会被使能。必须确保整条设备树路径上的节点均为 okay 状态。
// 基板设备树:默认禁用某个外设
&i2c1 {
    status = "okay";

    touch: touch@38 {
        compatible = "edt,edt-ft5406";
        reg = <0x38>;
        status = "disabled";  // 默认禁用,等待 Overlay 使能
    };
};

// Overlay 文件:使能触摸屏
&touch {
    status = "okay";  // 通过 Overlay 动态启用
};

3.5 gpios 属性:GPIO 资源描述

gpios 属性用于描述设备使用的 GPIO 引脚,包括引脚号、标志位等信息。它依赖于 GPIO 控制器节点提供的 #gpio-cells 定义。

  • gpio-controller: 标记节点为 GPIO 控制器。
  • #gpio-cells: 指定 GPIO 描述符需要的 cell 数量,通常为 2(GPIO 号 + 标志位)。
  • 标志位: 常用值包括 GPIO_ACTIVE_HIGH (0) 和 GPIO_ACTIVE_LOW (1)。
// GPIO 控制器定义
gpio0: gpio@10001000 {
    compatible = "brcm,bcm2835-gpio";
    reg = <0x10001000 0x100>;
    gpio-controller;
    #gpio-cells = <2>;
    interrupts = <17>;
};

// 使用 GPIO 的设备
leds {
    compatible = "gpio-leds";

    led-red {
        label = "red-led";
        gpios = <&gpio0 18 GPIO_ACTIVE_HIGH>;  // GPIO0 的 18 号引脚,高电平有效
        linux,default-trigger = "heartbeat";
    };

    led-green {
        label = "green-led";
        gpios = <&gpio0 19 GPIO_ACTIVE_LOW>;   // GPIO0 的 19 号引脚,低电平有效
        default-state = "off";
    };
};
驱动对应: 在驱动中通过 of_get_named_gpio() 或 devm_gpiod_get() 函数获取 GPIO 描述符,然后使用标准的 GPIO API 进行控制。
GPIO 连接关系 GPIO 控制器 #gpio-cells = <2> 引脚 18, 19, 20 ... 设备节点 gpios = <&gpio0 18 0> gpios = <&gpio0 19 1> gpios = <&gpio0 20 0> 物理外设 LED / 按键 传感器 说明:gpios 属性通过 phandle 引用 GPIO 控制器,并指定引脚号和有效电平标志。

3.6 属性综合对比与实战建议

下表总结了五个核心属性的关键特征,便于在实际开发中快速查阅和对比:

属性名 数据类型 核心作用 依赖关系 Overlay 常用操作
compatible 字符串列表 驱动匹配 无 通常不修改
reg u32 数组 地址空间定义 #address-cells, #size-cells 通常不修改
interrupts u32 数组 中断资源描述 interrupt-parent, #interrupt-cells 可能修改中断号
status 字符串 设备使能/禁用 无 最常修改
gpios phandle + u32 数组 GPIO 引脚描述 gpio-controller, #gpio-cells 可能修改引脚号
实战建议: 在编写 Overlay 时,优先通过修改 status 属性来控制设备的启用与禁用。对于 reg 和 compatible 属性,除非硬件设计变更,否则不建议在 Overlay 中修改。中断和 GPIO 的修改需要确保与硬件实际连接一致。