2. 设备树基础:设备树语法、节点、属性、reg、interrupts

设备树(Device Tree,DT)是一种描述硬件资源的数据结构,用于将不可枚举的硬件信息从内核源码中剥离,交由 Bootloader(如 U-Boot)传递给内核。在 V4L2 驱动开发中,设备树是配置摄像头 sensor 的 I2C 地址、电源引脚(pinctrl)、时钟频率、中断号以及数据总线(CSI/Parallel)的核心手段。

学习提示: 设备树不是编程语言,而是一种键值对(Key-Value)的树形描述文件。掌握设备树语法是编写 V4L2 sensor 驱动设备节点的前提。

2.1 设备树源文件结构

设备树源文件(.dts)采用树形结构,以 /dts-v1/; 开头,根节点为 /,内部包含若干子节点,每个节点代表一个硬件设备或总线。其基本语法如下:

/dts-v1/;

/ {
    model = "Embedded Camera Board";
    compatible = "vendor,camera-board";

    soc {
        #address-cells = <1>;
        #size-cells = <1>;

        i2c0: i2c@ff010000 {
            compatible = "snps,designware-i2c";
            reg = <0xff010000 0x1000>;
            #address-cells = <1>;
            #size-cells = <0>;

            sensor: camera@1a {
                compatible = "sony,imx219";
                reg = <0x1a>;
                clocks = <&osc 0>;
                clock-names = "xvclk";
                interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;
            };
        };
    };
};
关键点: 每个节点以 节点名@地址 形式标识,reg 属性描述地址空间,interrupts 描述中断资源。

2.2 节点与属性

设备树由节点(Node)和属性(Property)组成。节点表示硬件设备或总线,属性描述节点的特征。

元素 语法 说明
根节点 / { ... }; 设备树的顶层容器,所有设备节点都挂载在根节点下
子节点 node-name@address { ... }; 表示具体设备,@address 通常为寄存器基址或 I2C 地址
标签 label: node-name@address 为节点起别名,方便在其他位置引用(如 &sensor)
属性 property-name = <value>; 键值对,值可以是字符串、32 位整数数组、64 位整数数组或二进制数据
字符串属性 compatible = "vendor,device"; 用于匹配驱动,格式为 厂商,设备名
整数数组 reg = <0x1000 0x2000>; 用尖括号包裹,空格分隔多个 32 位整数
常见错误: 忘记在 < > 内使用空格分隔整数,或混淆 #address-cells 与 #size-cells 的数值,会导致 reg 解析错误。

2.3 reg 属性:描述地址空间

reg 属性用于描述设备在总线上的地址范围,由 #address-cells 和 #size-cells 共同决定其解析方式。

  • #address-cells:表示地址字段占用的 32 位整数个数。
  • #size-cells:表示长度字段占用的 32 位整数个数。
  • reg:格式为 <address1 length1 address2 length2 ...>。

例如,一个 64 位地址空间的设备:

#address-cells = <2>;   // 地址用两个 32 位整数表示(高32位 + 低32位)
#size-cells = <2>;      // 长度用两个 32 位整数表示
reg = <0x0 0xff010000 0x0 0x1000>;  // 基址 0xff010000,长度 0x1000
V4L2 场景: 对于 I2C 连接的 sensor,#address-cells = <1>,#size-cells = <0>,reg = <0x1a> 表示 I2C 从设备地址为 0x1a。

2.4 interrupts 属性:描述中断资源

interrupts 属性描述设备使用的中断号、触发类型等信息,需要配合 interrupt-parent 使用。

字段 说明 示例值
中断控制器类型 GIC(通用中断控制器)或本地中断 GIC_SPI(共享外设中断)
中断号 硬件中断编号 42
触发类型 电平触发或边沿触发 IRQ_TYPE_LEVEL_HIGH

典型的中断描述:

interrupt-parent = <&gic>;  // 引用中断控制器节点
interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>;

对于 GPIO 中断,可以使用 interrupts-extended 属性指定不同的中断控制器:

interrupts-extended = <&gpio1 5 IRQ_TYPE_EDGE_RISING>;
V4L2 场景: sensor 的帧同步(VSYNC)中断通常配置为边沿触发,用于通知内核一帧图像数据已准备好。

2.5 设备树结构图

下图展示了 V4L2 camera 子系统中设备树的典型层级结构,从根节点到具体的 sensor 设备节点:

V4L2 Camera 设备树层级结构 / (根节点) soc i2c0: i2c@ff010000 sensor: camera@1a compatible = "sony,imx219" 节点属性说明 • reg = <0x1a> → I2C 从设备地址 0x1a • clocks = <&osc 0> → 引用外部振荡器时钟 • interrupts = <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH> → 中断号 42,高电平触发 • #address-cells = <1>; #size-cells = <0> → reg 只包含一个 32 位地址 • compatible = "sony,imx219" → 驱动匹配字符串

2.6 常用属性速查表

属性名 类型 用途 V4L2 典型用法
compatible 字符串 驱动匹配 "ov5640,ovti"
reg 整数数组 地址/寄存器范围 <0x3c> (I2C 地址)
interrupts 整数数组 中断描述 <GIC_SPI 42 IRQ_TYPE_LEVEL_HIGH>
clocks 引用数组 时钟源 <&osc 0>
clock-names 字符串数组 时钟名称 "xvclk", "mclk"
pinctrl-0 引用 引脚复用配置 <&camera_pins>
status 字符串 设备状态 "okay" 或 "disabled"

2.7 设备树编译与反编译

设备树源文件(.dts)需要编译为二进制设备树 Blob(.dtb),内核在启动时解析 .dtb 文件。常用命令如下:

# 编译 .dts 为 .dtb
dtc -I dts -O dtb -o my-board.dtb my-board.dts

# 反编译 .dtb 为 .dts
dtc -I dtb -O dts -o my-board.dts my-board.dtb

# 查看设备树内容(十六进制)
fdtdump my-board.dtb
调试技巧: 在 Linux 内核启动后,可以通过 /proc/device-tree/ 目录查看当前使用的设备树结构,每个节点对应一个目录,属性对应文件。

2.8 本章小结

  • 设备树使用树形结构描述硬件,节点代表设备,属性代表设备参数。
  • reg 属性由 #address-cells 和 #size-cells 决定解析方式,用于描述地址空间。
  • interrupts 属性配合 interrupt-parent 描述中断资源,支持 SPI、PPI 和 GPIO 中断。
  • V4L2 sensor 驱动中,设备树用于配置 I2C 地址、时钟、中断和引脚复用,是驱动与硬件解耦的关键。
  • 掌握 dtc 工具的使用,能够快速验证和调试设备树配置。