3. 设备树常用属性:compatible、reg、interrupts、status、gpios 等属性详解
设备树(Device Tree)是描述硬件拓扑结构的配置文件,它通过一系列标准属性将非可枚举的硬件信息传递给内核。对于 Linux Platform 驱动开发者而言,掌握设备树常用属性的含义、语法和匹配规则,是编写可移植、可维护驱动的核心基础。本章将逐一剖析 compatible、reg、interrupts、status、gpios 等关键属性,并结合实际案例与 SVG 结构图进行讲解。
3.1 compatible 属性:驱动匹配的核心标识
compatible 属性是设备树中最关键的属性,它定义了设备与驱动之间的匹配关系。内核通过该属性的字符串值,在设备树节点与驱动列表之间建立连接。
3.1.1 属性格式与匹配规则
compatible 属性是一个字符串列表,通常遵循 "厂商,设备型号" 的命名规范。内核在匹配时,会按照列表中的顺序依次尝试,直到找到匹配的驱动。
// 设备树节点示例
i2c@1c00000 {
compatible = "fsl,imx6q-i2c", "fsl,imx21-i2c";
reg = <0x01c00000 0x4000>;
interrupts = <0 38 4>;
status = "okay";
};
在上述示例中,内核会先尝试匹配 "fsl,imx6q-i2c",如果失败,则尝试 "fsl,imx21-i2c"。这种“最具体优先”的匹配策略,使得同一驱动可以兼容多个硬件版本。
3.1.2 驱动侧匹配方式
在 Platform 驱动中,通过 of_match_table 指定支持的设备列表:
static const struct of_device_id my_i2c_of_match[] = {
{ .compatible = "fsl,imx6q-i2c", .data = &imx6q_i2c_data },
{ .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_data },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, my_i2c_of_match);
static struct platform_driver my_i2c_driver = {
.probe = my_i2c_probe,
.remove = my_i2c_remove,
.driver = {
.name = "my_i2c",
.of_match_table = my_i2c_of_match,
},
};
compatible 字符串时,应遵循“厂商前缀 + 逗号 + 设备型号”的格式。厂商前缀需在 Documentation/devicetree/bindings/vendor-prefixes.yaml 中注册,避免与其他厂商冲突。
3.2 reg 属性:描述设备地址空间
reg 属性用于描述设备在总线上的地址范围,包括起始地址和长度。它是内核为设备分配 I/O 内存、寄存器映射的基础。
3.2.1 属性格式与地址单元
reg 属性的格式由父节点的 #address-cells 和 #size-cells 决定:
// 32位地址系统
#address-cells = <1>;
#size-cells = <1>;
reg = <0x01c00000 0x4000>; // 起始地址 0x01c00000,长度 0x4000
// 64位地址系统
#address-cells = <2>;
#size-cells = <2>;
reg = <0x00000000 0x01c00000 0x00000000 0x00004000>; // 高32位+低32位地址,高32位+低32位长度
3.2.2 多段地址空间
一个设备可能拥有多个不连续的地址段,reg 属性可以包含多组地址-长度对:
// 两个地址段:控制寄存器区和数据缓冲区
reg = <0x01c00000 0x1000>, // 控制寄存器:0x01c00000 ~ 0x01c00fff
<0x01c01000 0x2000>; // 数据缓冲区:0x01c01000 ~ 0x01c02fff
| 参数 | 说明 | 示例值 |
|---|---|---|
#address-cells |
地址字段占用的 32 位单元数 | 1(32位地址)或 2(64位地址) |
#size-cells |
长度字段占用的 32 位单元数 | 1(32位长度)或 2(64位长度) |
reg |
地址-长度对列表,每对包含 (address-cells + size-cells) 个单元 | <0x1000 0x200> |
#address-cells 和 #size-cells 设置错误,内核将无法正确解析 reg 属性,导致设备资源申请失败。务必检查总线控制器节点的地址单元配置。
3.3 interrupts 属性:中断资源描述
interrupts 属性用于描述设备使用的中断资源,包括中断号、触发类型和优先级等信息。它是设备与中断控制器之间的桥梁。
3.3.1 属性格式与中断单元
interrupts 属性的格式由父节点(中断控制器)的 #interrupt-cells 决定:
// 中断控制器定义
intc: interrupt-controller@00a01000 {
compatible = "arm,cortex-a9-gic";
#interrupt-cells = <3>;
interrupt-controller;
reg = <0x00a01000 0x1000>;
};
// 设备节点使用中断
device@1c00000 {
compatible = "my,device";
reg = <0x01c00000 0x4000>;
interrupts = <0 38 4>; // GIC SPI 中断号 38,高电平触发
};
3.3.2 中断类型与触发方式
对于 ARM GIC(Generic Interrupt Controller),#interrupt-cells = <3> 的格式为:
| 字段 | 说明 | 取值 |
|---|---|---|
| 中断类型 | 0 = SPI(共享外设中断),1 = PPI(私有外设中断) | 0 或 1 |
| 中断号 | SPI 中断号(32~1019),PPI 中断号(16~31) | 数值 |
| 触发方式 | 1 = 上升沿触发,2 = 下降沿触发,4 = 高电平触发,8 = 低电平触发 | 1, 2, 4, 8 |
// 常见中断配置示例
interrupts = <0 38 4>; // SPI 中断号38,高电平触发
interrupts = <0 42 1>; // SPI 中断号42,上升沿触发
interrupts = <1 14 8>; // PPI 中断号14,低电平触发
3.4 status 属性:设备状态控制
status 属性用于控制设备节点的启用状态,允许在不修改硬件描述的情况下,通过设备树动态启用或禁用设备。
3.4.1 属性取值与含义
| 取值 | 含义 | 内核行为 |
|---|---|---|
"okay" |
设备启用 | 内核正常创建设备并调用 probe |
"disabled" |
设备禁用 | 内核跳过该设备,不创建 platform_device |
"reserved" |
设备保留 | 内核不创建设备,但保留资源供其他用途 |
"fail" |
设备故障 | 内核标记设备为故障状态,不加载驱动 |
3.4.2 实际应用场景
// 在 SoC 级设备树中默认禁用某些外设
&uart1 {
status = "disabled";
};
&uart2 {
status = "disabled";
};
// 在板级设备树中按需启用
&uart1 {
status = "okay";
pinctrl-0 = <&pinctrl_uart1>;
pinctrl-names = "default";
};
status 属性快速启用或禁用设备,避免重新编译内核。对于未使用的硬件模块,建议在板级设备树中设置为 "disabled",以节省系统资源。
3.5 gpios 属性:GPIO 资源描述
gpios 属性用于描述设备使用的 GPIO 引脚,包括 GPIO 控制器引用、引脚号和标志位。它是设备与 GPIO 子系统之间的接口。
3.5.1 属性格式与 GPIO 说明符
gpios 属性是一个 phandle 加 GPIO 说明符的列表,格式由 GPIO 控制器的 #gpio-cells 决定:
// GPIO 控制器定义
gpio0: gpio@02000000 {
compatible = "fsl,imx6q-gpio";
reg = <0x02000000 0x4000>;
gpio-controller;
#gpio-cells = <2>; // 引脚号 + 标志位
};
// 设备使用 GPIO
leds {
compatible = "gpio-leds";
led-red {
gpios = <&gpio0 3 GPIO_ACTIVE_LOW>; // GPIO0_3,低电平有效
label = "red-led";
};
led-green {
gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; // GPIO0_4,高电平有效
label = "green-led";
};
};
3.5.2 GPIO 标志位定义
| 标志位 | 宏定义 | 说明 |
|---|---|---|
0 |
GPIO_ACTIVE_HIGH |
高电平有效(默认) |
1 |
GPIO_ACTIVE_LOW |
低电平有效 |
2 |
GPIO_OPEN_DRAIN |
开漏输出 |
4 |
GPIO_OPEN_SOURCE |
开源输出 |
3.5.3 驱动侧获取 GPIO
// 在驱动 probe 函数中获取 GPIO
static int my_led_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct gpio_desc *led_gpio;
// 通过设备树获取 GPIO
led_gpio = devm_gpiod_get(dev, "led", GPIOD_OUT_LOW);
if (IS_ERR(led_gpio)) {
dev_err(dev, "Failed to get LED GPIO\n");
return PTR_ERR(led_gpio);
}
// 使用 GPIO
gpiod_set_value(led_gpio, 1);
return 0;
}
3.6 其他常用属性
除了上述核心属性外,设备树还定义了多个常用属性,用于描述设备的其他硬件特性:
| 属性名 | 用途 | 示例 |
|---|---|---|
clocks |
指定设备使用的时钟源 | clocks = <&clks IMX6QDL_CLK_UART1>; |
resets |
指定设备使用的复位信号 | resets = <&rst 10>; |
dmas |
指定设备使用的 DMA 通道 | dmas = <&sdma 2>; |
pinctrl-0 |
指定设备的引脚复用配置 | pinctrl-0 = <&pinctrl_uart1>; |
power-domains |
指定设备所属的电源域 | power-domains = <&pd_core>; |
compatible 决定驱动匹配,reg 定义地址空间,interrupts 描述中断资源,status 控制设备状态,gpios 提供 GPIO 接口。掌握这些属性的语法和内核解析逻辑,是编写高质量 Platform 驱动的基础。