4. 设备树常用属性详解
设备树中的属性(Property)是描述硬件设备特征、配置和连接关系的关键载体。每个节点通过一系列标准属性向内核驱动传递必要信息。本章将深入解析嵌入式开发中最常用的六大属性,帮助您准确理解其语义、格式及在驱动匹配与资源获取中的实际作用。
4.1 compatible 属性:驱动匹配的“身份证”
compatible 属性是设备树节点与Linux驱动之间建立关联的核心桥梁。它指定了设备所兼容的硬件型号,驱动通过该属性进行匹配探测。
4.1.1 格式与规范
属性值为字符串列表,推荐采用 "厂商,型号" 的命名规范,确保全局唯一性。列表中的第一个字符串为最精确的匹配项,后续为兼容的通用型号。
compatible = "ti,am335x-uart", "ns16550";
上述示例表示该设备是TI AM335x平台的UART控制器,同时兼容标准的ns16550 UART。内核驱动匹配时,优先查找 "ti,am335x-uart",若未找到则尝试 "ns16550"。
4.1.2 驱动匹配流程
4.1.3 驱动端匹配表示例
static const struct of_device_id am335x_uart_of_match[] = {
{ .compatible = "ti,am335x-uart", },
{ .compatible = "ns16550", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, am335x_uart_of_match);
static struct platform_driver am335x_uart_driver = {
.probe = am335x_uart_probe,
.remove = am335x_uart_remove,
.driver = {
.name = "am335x-uart",
.of_match_table = am335x_uart_of_match,
},
};
4.2 reg 属性:描述地址空间与寄存器
reg 属性用于描述设备在总线上的地址空间,通常包含起始地址和长度。对于内存映射设备,它定义了驱动需要操作的寄存器区域。
4.2.1 格式与组成
reg 由一组或多组 <地址 长度> 对组成,地址和长度的位数由父节点的 #address-cells 和 #size-cells 决定。
uart0: serial@44e09000 {
compatible = "ti,am335x-uart", "ns16550";
reg = <0x44e09000 0x2000>;
interrupts = <72>;
};
上述示例中,reg = <0x44e09000 0x2000> 表示UART0的寄存器基地址为0x44E09000,地址空间大小为0x2000字节。
4.2.2 多段地址空间
某些设备拥有多个不连续的地址区域,例如包含控制寄存器和数据缓冲区。此时 reg 可包含多组地址对:
dma: dma-controller@4a000000 {
compatible = "ti,edma3";
reg = <0x4a000000 0x10000> /* 全局寄存器 */
<0x4a100000 0x10000>; /* 通道寄存器 */
interrupts = <12 13 14>;
};
4.2.3 地址与长度单元说明
| 属性 | 含义 | 典型值 |
|---|---|---|
#address-cells |
地址字段占用的32位单元数 | 1(32位地址)或 2(64位地址) |
#size-cells |
长度字段占用的32位单元数 | 1(32位长度)或 0(无长度) |
platform_get_resource(pdev, IORESOURCE_MEM, 0) 获取第一段地址空间,返回 struct resource 结构体,内含起始地址和长度。
4.3 interrupts 属性:连接中断控制器
interrupts 属性描述设备使用的中断资源,包括中断号、触发类型等信息。它必须与父节点的 interrupt-parent 或全局中断控制器配合使用。
4.3.1 基本格式
interrupts = <中断号 触发类型>;
中断号的位数由中断控制器的 #interrupt-cells 决定。以ARM GIC(通用中断控制器)为例,通常使用2个cell:
gpio0: gpio@44e07000 {
compatible = "ti,omap4-gpio";
reg = <0x44e07000 0x1000>;
interrupts = <96 0x4>; /* 中断号96,高电平触发 */
};
4.3.2 中断触发类型
| 标志位 | 触发类型 | 说明 |
|---|---|---|
| 0x0 | IRQ_TYPE_NONE | 未指定 |
| 0x1 | IRQ_TYPE_EDGE_RISING | 上升沿触发 |
| 0x2 | IRQ_TYPE_EDGE_FALLING | 下降沿触发 |
| 0x3 | IRQ_TYPE_EDGE_BOTH | 双边沿触发 |
| 0x4 | IRQ_TYPE_LEVEL_HIGH | 高电平触发 |
| 0x8 | IRQ_TYPE_LEVEL_LOW | 低电平触发 |
4.3.3 中断映射关系
4.4 status 属性:设备启用控制
status 属性用于控制设备节点的启用或禁用状态,是设备树中实现硬件裁剪和配置灵活性的重要手段。
4.4.1 可选值
| 值 | 含义 | 说明 |
|---|---|---|
"okay" |
设备启用 | 驱动正常探测并初始化设备 |
"disabled" |
设备禁用 | 内核跳过该节点,不创建设备 |
"reserved" |
保留 | 设备被保留,驱动不操作 |
"fail" |
设备故障 | 设备存在但不可用 |
4.4.2 典型应用场景
在SoC级DTSI文件中,外设通常默认设置为 status = "disabled",在板级DTS文件中根据实际硬件焊接情况选择性启用:
// am33xx.dtsi (SoC级)
uart0: serial@44e09000 {
compatible = "ti,am335x-uart";
reg = <0x44e09000 0x2000>;
status = "disabled";
};
// myboard.dts (板级)
&uart0 {
status = "okay";
pinctrl-0 = <&uart0_pins>;
};
status = "okay",避免依赖默认值。同时检查硬件原理图,确保启用的外设引脚未被复用冲突。
4.5 clocks 属性:时钟资源绑定
clocks 属性将设备与其所需的时钟源关联起来,驱动通过该属性获取时钟句柄,实现时钟使能、频率配置等操作。
4.5.1 基本格式
clocks = <&clock_controller clock_id>;
clock-names = "name";
clocks 属性值是一个phandle加时钟索引的组合,clock-names 为每个时钟指定名称,便于驱动按名称查找。
i2c0: i2c@44e0b000 {
compatible = "ti,omap4-i2c";
reg = <0x44e0b000 0x1000>;
interrupts = <70>;
clocks = <&l4_wkup_clkctrl 0>;
clock-names = "fck";
};
4.5.2 多时钟设备
复杂外设可能需要多个时钟源,例如AHB总线时钟和APB总线时钟:
usb: usb@4a064000 {
compatible = "ti,am335x-usb";
reg = <0x4a064000 0x1000>;
interrupts = <18>;
clocks = <&l3_clkctrl 0>, <&l4_clkctrl 0>;
clock-names = "usb_ahb", "usb_apb";
};
4.5.3 驱动获取时钟
static int my_probe(struct platform_device *pdev)
{
struct clk *clk;
clk = devm_clk_get(&pdev->dev, "fck");
if (IS_ERR(clk))
return PTR_ERR(clk);
clk_prepare_enable(clk);
// ... 设备初始化 ...
}
4.6 gpios 属性:GPIO资源描述
gpios 属性用于描述设备使用的GPIO引脚,包括GPIO控制器引用、引脚号和标志位。它是设备树中连接外设与GPIO控制器的标准方式。
4.6.1 格式与示例
gpios = <&gpio_controller pin_number flags>;
led: led@0 {
compatible = "gpio-leds";
gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
label = "user-led";
};
上述示例中,LED连接到GPIO0控制器的第12号引脚,高电平有效。
4.6.2 GPIO标志位
| 标志位 | 宏定义 | 说明 |
|---|---|---|
| 0 | GPIO_ACTIVE_HIGH | 高电平有效 |
| 1 | GPIO_ACTIVE_LOW | 低电平有效 |
| 2 | GPIO_OPEN_DRAIN | 开漏输出 |
| 4 | GPIO_OPEN_SOURCE | 开源输出 |
4.6.3 多GPIO设备
某些设备需要多个GPIO引脚,例如复位引脚和中断引脚:
wifi: wifi@1 {
compatible = "broadcom,bcm4334";
reg = <1>;
gpios = <&gpio1 15 GPIO_ACTIVE_LOW>, /* 复位引脚 */
<&gpio1 16 GPIO_ACTIVE_HIGH>; /* 中断引脚 */
gpio-names = "reset", "irq";
};
4.6.4 驱动获取GPIO
static int my_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct gpio_desc *reset_gpio;
reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
gpiod_set_value(reset_gpio, 0); // 拉低复位
msleep(10);
gpiod_set_value(reset_gpio, 1); // 释放复位
}
- compatible:驱动匹配的核心标识,采用"厂商,型号"格式。
- reg:描述地址空间,支持多段不连续区域。
- interrupts:绑定中断资源,需配合中断控制器解析。
- status:控制设备启用/禁用,实现硬件配置灵活裁剪。
- clocks:关联时钟源,驱动通过名称获取时钟句柄。
- gpios:描述GPIO引脚,支持命名和标志位配置。
4.7 属性综合应用示例
以下是一个完整的SPI设备节点,综合使用了本章讲解的所有属性:
spi0: spi@48030000 {
compatible = "ti,am335x-spi", "ti,omap4-spi";
reg = <0x48030000 0x1000>;
interrupts = <65>;
clocks = <&l4_per_clkctrl 0>;
clock-names = "fck";
status = "okay";
#address-cells = <1>;
#size-cells = <0>;
adc: adc@0 {
compatible = "ti,ads1256";
reg = <0>;
spi-max-frequency = <1000000>;
interrupts-extended = <&gpio2 5 GPIO_ACTIVE_LOW>;
clocks = <&adc_clk 0>;
clock-names = "adc_clk";
gpios = <&gpio2 6 GPIO_ACTIVE_HIGH>; /* 复位引脚 */
status = "okay";
};
};