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