3. DTS 常用属性详解:compatible、reg、interrupts、status、clocks 等核心属性

设备树(Device Tree Source, DTS)中的属性是描述硬件设备特征与连接关系的“语言”。对于 Platform 驱动开发者而言,掌握核心属性的含义、语法与匹配规则,是正确配置设备树、实现驱动与设备绑定的基础。本章将逐一剖析 compatible、reg、interrupts、status、clocks 等最常用的属性,并结合实际案例说明其配置方法与调试要点。

3.1 compatible 属性:驱动与设备的“身份证”

compatible 是设备树中最关键的属性,它指定了设备的兼容性字符串列表。内核通过该属性将设备节点与对应的 Platform 驱动进行匹配。

3.1.1 语法与规范

compatible = "manufacturer,model", "generic,model";
  • 厂商前缀:通常使用芯片或板卡制造商的名称缩写,如 ti、fsl、samsung。
  • 设备型号:具体的外设或 IP 核名称,如 omap-gpio、imx-uart。
  • 兼容列表:字符串列表,按“最具体到最通用”的顺序排列。内核匹配时,优先使用第一个字符串。

3.1.2 匹配优先级

匹配方式 说明 优先级
OF 匹配表 驱动中 of_match_table 与设备树 compatible 精确匹配 最高
ACPI 匹配 仅用于 ACPI 固件,嵌入式场景较少 次高
ID 表匹配 传统 platform_driver.id_table 匹配 较低
名称回退 当无匹配表时,内核尝试用设备节点名称匹配驱动名称 最低
实战建议:在驱动中始终定义 of_match_table,并确保设备树中的 compatible 字符串与之一致。这是最可靠、最高效的匹配方式。

3.1.3 内联 SVG:compatible 匹配流程

compatible 属性匹配流程 设备树节点 compatible = "ti,omap-gpio" 内核 OF 匹配层 of_match_table 扫描 驱动 probe 回调执行 匹配失败 驱动不加载 说明:内核按 compatible 列表顺序匹配,第一个匹配成功即触发 probe。若全部失败,则驱动不加载。

3.2 reg 属性:描述设备地址空间

reg 属性用于描述设备在系统总线上的地址范围,通常包含一个或多个地址/长度对。Platform 驱动通过 platform_get_resource() 系列函数获取这些信息。

3.2.1 基本格式

reg = <address1 length1 address2 length2 ...>;
  • address:设备基地址,通常为 32 位或 64 位值。
  • length:地址空间的长度(字节数)。
  • 多段描述:当设备有多个不连续的地址区域时,可依次列出。

3.2.2 典型示例

uart@44e09000 {
    compatible = "ti,omap3-uart";
    reg = <0x44e09000 0x2000>;
    interrupts = <0 72 4>;
};

上述节点描述了一个 UART 设备,其寄存器基地址为 0x44e09000,映射长度为 0x2000(8KB)。

3.2.3 驱动中获取 reg 资源

#include <linux/platform_device.h>
#include <linux/io.h>

static int my_probe(struct platform_device *pdev)
{
    struct resource *res;
    void __iomem *base;

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (!res)
        return -ENXIO;

    base = devm_ioremap_resource(&pdev->dev, res);
    if (IS_ERR(base))
        return PTR_ERR(base);

    /* 使用 base 访问寄存器 */
    return 0;
}
常见错误:reg 属性中的地址必须与系统地址映射一致。若设备挂在某个总线桥后面,地址需使用总线域地址,而非 CPU 物理地址。调试时可通过 /proc/iomem 检查资源分配是否正确。

3.3 interrupts 属性:连接中断控制器

interrupts 属性描述设备的中断请求线(IRQ)信息,包括中断号、触发类型等。它必须与 interrupt-parent 配合使用,以指定中断控制器。

3.3.1 属性组成

interrupt-parent = <&gic>;
interrupts = <0 89 4>;
  • interrupt-parent:指向中断控制器的 phandle。
  • interrupts:一个或多个中断描述符,格式由中断控制器定义。

3.3.2 常见中断描述符格式

中断控制器类型 格式 说明
GIC(通用中断控制器) <0 89 4> 0=SPI, 89=中断号, 4=触发类型(高电平触发)
简单中断控制器 <5 2> 5=中断号, 2=触发类型(下降沿触发)
级联中断控制器 <&gpio1 15 0> gpio1=控制器, 15=引脚, 0=低电平触发

3.3.3 触发类型编码

值 触发类型 描述
0 IRQ_TYPE_NONE 未指定
1 IRQ_TYPE_EDGE_RISING 上升沿触发
2 IRQ_TYPE_EDGE_FALLING 下降沿触发
3 IRQ_TYPE_EDGE_BOTH 双边沿触发
4 IRQ_TYPE_LEVEL_HIGH 高电平触发
8 IRQ_TYPE_LEVEL_LOW 低电平触发

3.3.4 内联 SVG:中断路由拓扑

设备树中断路由拓扑 UART 设备 interrupts = <0 89 4> GIC 中断控制器 interrupt-parent CPU 内核 GPIO 按键 interrupts = <15 2> GPIO 控制器 中断控制器 CPU 内核 说明:外设通过 interrupt-parent 指向中断控制器,中断控制器将中断路由到 CPU。级联场景下,GPIO 控制器作为中断控制器转发下级中断。

3.4 status 属性:设备启用控制

status 属性用于控制设备节点的启用或禁用状态,是设备树中实现“条件编译”的重要手段。

3.4.1 可选值

值 含义 内核行为
"okay" 设备启用 内核正常创建设备并尝试绑定驱动
"disabled" 设备禁用 内核跳过该节点,不创建设备
"reserved" 保留状态 通常用于特殊场景,如固件保留
"fail" 设备故障 内核标记设备不可用

3.4.2 使用场景

  • SoC 级 dtsi 文件:通常将外设节点 status = "disabled",由板级 dts 文件按需启用。
  • 板级定制:在板级 dts 中通过 &uart1 { status = "okay"; }; 启用特定外设。
  • 调试与隔离:临时禁用某个外设以排查硬件冲突或驱动问题。
/* 在 soc.dtsi 中 */
uart1: serial@44e09000 {
    compatible = "ti,omap3-uart";
    reg = <0x44e09000 0x2000>;
    interrupts = <0 72 4>;
    status = "disabled";  /* 默认禁用 */
};

/* 在 board.dts 中 */
&uart1 {
    status = "okay";      /* 板级启用 */
};
调试技巧:通过 /sys/devices/platform/ 目录检查设备是否创建。若节点 status = "disabled",则对应目录不会出现。也可使用 dtc -I fs -O dts /sys/firmware/devicetree/base 查看运行时设备树状态。

3.5 clocks 属性:时钟资源描述

clocks 属性用于描述设备所需的时钟输入,通常与 clock-names 配合使用,使驱动能够通过名称获取特定时钟句柄。

3.5.1 基本语法

clocks = <&clkc 16>, <&clkc 17>;
clock-names = "uart_clk", "baud_clk";
  • clocks:时钟 phandle 列表,每个条目指向一个时钟提供者。
  • clock-names:可选的名称列表,与 clocks 一一对应。

3.5.2 驱动中获取时钟

#include <linux/clk.h>

static int my_probe(struct platform_device *pdev)
{
    struct clk *clk;

    clk = devm_clk_get(&pdev->dev, "uart_clk");
    if (IS_ERR(clk))
        return PTR_ERR(clk);

    clk_prepare_enable(clk);
    /* 使用时钟 */
    return 0;
}

3.5.3 时钟属性对比

属性 作用 是否必需 典型值
clocks 指定设备使用的时钟源 视设备而定 <&clkc 16>
clock-names 为时钟源命名,便于驱动查找 推荐 "uart_clk"
assigned-clocks 预分配时钟频率或父时钟 可选 <&clkc 16>
assigned-clock-rates 指定预分配频率值 可选 <48000000>

3.6 属性综合配置示例

以下是一个完整的 UART 设备节点,综合使用了上述所有核心属性:

uart0: serial@10000000 {
    compatible = "myvendor,uart-1.0", "ns16550";
    reg = <0x10000000 0x1000>;
    interrupts = <0 33 4>;
    interrupt-parent = <&gic>;
    clocks = <&clkc 16>, <&clkc 17>;
    clock-names = "uart_clk", "baud_clk";
    status = "okay";
};

3.7 调试与验证方法

  1. 查看设备树编译:使用 dtc -I dts -O dtb -o test.dtb test.dts 检查语法错误。
  2. 查看运行时设备树:cat /proc/device-tree/uart0/compatible 验证属性值。
  3. 检查驱动匹配:dmesg | grep uart0 查看 probe 是否被调用。
  4. 资源分配检查:cat /proc/iomem | grep 10000000 确认地址映射。
  5. 中断调试:cat /proc/interrupts | grep uart 查看中断号分配。
核心要点回顾:
  • compatible 是驱动匹配的关键,必须与 of_match_table 一致。
  • reg 描述地址资源,驱动通过 platform_get_resource 获取。
  • interrupts 需配合 interrupt-parent 使用,触发类型编码要准确。
  • status 控制设备启用/禁用,是板级定制的常用手段。
  • clocks 与 clock-names 提供时钟管理接口,驱动需正确获取和使能时钟。