3. I2C设备树绑定:设备树节点语法、compatible属性、reg地址配置

在车载嵌入式Linux系统中,I2C外设的硬件拓扑与驱动匹配完全依赖设备树(Device Tree)描述。设备树节点是驱动与硬件之间的“契约”,其中compatible属性决定驱动匹配,reg属性定义I2C从设备地址。本节将深入解析I2C设备树绑定的核心语法与实战配置。

3.1 I2C设备树节点基本语法

一个标准的I2C从设备节点必须嵌套在I2C控制器节点内部,并遵循以下结构:

&i2c1 {
    status = "okay";
    clock-frequency = <400000>;   /* 400kHz Fast Mode */

    /* I2C从设备节点 */
    temperature-sensor@48 {
        compatible = "ti,tmp102", "ti,tmp101";
        reg = <0x48>;
        interrupt-parent = <&gpio2>;
        interrupts = <5 IRQ_TYPE_EDGE_FALLING>;
    };
};
节点元素 说明 示例值
节点名称@地址 设备节点名,@后跟I2C从设备地址(7位) temperature-sensor@48
compatible 驱动匹配字符串,优先使用第一个 "ti,tmp102", "ti,tmp101"
reg I2C从设备地址(7位或10位) <0x48>
interrupt-parent 中断控制器phandle &gpio2
interrupts 中断号与触发类型 <5 IRQ_TYPE_EDGE_FALLING>
车载经验提示:I2C节点名称中的@地址必须与reg属性值一致,否则设备树编译器(DTC)会报地址不匹配警告。在车载多传感器共线场景中,此错误极易导致驱动加载失败。

3.2 compatible属性:驱动匹配的核心

compatible属性是一个字符串列表,内核通过该属性在驱动列表中查找匹配项。匹配规则遵循“最精确优先”原则:

  • 第一字符串:精确的芯片型号,如 "ti,tmp102"。
  • 后续字符串:兼容的通用型号或系列名,如 "ti,tmp101"。
  • 驱动端匹配:使用 of_match_table 结构体定义。
/* 驱动端匹配表示例 */
static const struct of_device_id tmp102_of_match[] = {
    { .compatible = "ti,tmp102", .data = &tmp102_config },
    { .compatible = "ti,tmp101", .data = &tmp101_config },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, tmp102_of_match);
场景 compatible写法 匹配结果
精确匹配 "ti,tmp102" 仅匹配tmp102专用驱动
兼容匹配 "ti,tmp102", "ti,tmp101" 优先匹配tmp102,其次tmp101
厂商前缀错误 "nxp,tmp102" 匹配失败,驱动无法加载
常见陷阱:车载项目中常因compatible字符串大小写或厂商前缀不一致导致驱动不匹配。务必与芯片数据手册和内核驱动源码中的字符串完全一致。

3.3 reg地址配置:7位与10位地址

reg属性定义I2C从设备的从机地址。I2C总线支持7位和10位两种地址模式:

  • 7位地址:范围 0x00 ~ 0x7F,常用地址如 0x48、0x50。
  • 10位地址:范围 0x000 ~ 0x3FF,需在节点中显式声明 reg = <0x10 0x00> 格式。
/* 7位地址示例 */
eeprom@50 {
    compatible = "atmel,24c02";
    reg = <0x50>;
    pagesize = <16>;
};

/* 10位地址示例(罕见,需控制器支持) */
sensor@10 {
    compatible = "vendor,10bit-sensor";
    reg = <0x10 0x00>;  /* 高5位 + 低7位 */
    reg-names = "i2c-addr";
};
车载调试要点:使用 i2cdetect -y <bus> 扫描总线确认设备地址。若设备树中reg地址与硬件实际地址不符,驱动探测阶段将返回-ENXIO错误。

3.4 I2C设备树绑定完整流程图

下图展示了从设备树节点到驱动匹配、设备注册的完整流程:

I2C设备树绑定与驱动匹配流程 设备树节点 解析compatible属性 遍历of_match_table 匹配成功 → probe() 匹配失败 → 返回-ENODEV 读取reg地址 & 初始化 注册中断 & 设备就绪 说明:probe()函数中通过i2c_client->addr获取reg地址,通过client->irq获取中断号

3.5 车载I2C设备树绑定实战案例

以车载胎压监测传感器(TPMS)和环境光传感器(ALS)挂载在同一I2C总线为例:

&i2c3 {
    status = "okay";
    clock-frequency = <100000>;  /* 100kHz Standard Mode */
    pinctrl-0 = <&i2c3_pins>;

    /* TPMS传感器 */
    tpms@60 {
        compatible = "infineon,sp40", "infineon,sp37";
        reg = <0x60>;
        interrupt-parent = <&gpio1>;
        interrupts = <3 IRQ_TYPE_EDGE_RISING>;
        pressure-threshold = <1800>;  /* 自定义属性 */
    };

    /* 环境光传感器 */
    ambient-light@44 {
        compatible = "rohm,bh1750";
        reg = <0x44>;
        measurement-mode = <2>;  /* 连续高分辨率模式 */
    };
};
设备 compatible reg地址 中断配置
TPMS传感器 "infineon,sp40" 0x60 GPIO1_3,上升沿触发
环境光传感器 "rohm,bh1750" 0x44 无中断(轮询模式)
车载设计建议:同一I2C总线上的设备地址不能冲突。使用i2cdetect扫描确认地址唯一性。若地址冲突,需通过硬件地址引脚或I2C多路复用器(如PCA9548)解决。

3.6 设备树绑定常见错误与调试

在车载I2C设备树调试中,以下错误最为常见:

  • 地址格式错误:reg = <0x48> 误写为 reg = <72>(十进制),导致地址不匹配。
  • compatible拼写错误:厂商前缀或型号大小写不一致,如 "TI,tmp102" 而非 "ti,tmp102"。
  • 中断号越界:interrupts 指定的GPIO引脚号超出控制器范围。
  • status遗漏:父节点或子节点未设置 status = "okay",设备被禁用。
/* 错误示例:地址冲突 + compatible拼写错误 */
&i2c2 {
    status = "okay";
    sensor@48 {
        compatible = "Ti,Tmp102";  /* 错误:大小写不一致 */
        reg = <0x48>;
    };
    eeprom@48 {  /* 错误:地址0x48已被占用 */
        compatible = "atmel,24c02";
        reg = <0x48>;
    };
};
调试命令速查:
dtc -I dtb -O dts -o output.dts input.dtb — 反编译DTB检查节点
ls /sys/bus/i2c/devices/ — 查看已注册的I2C设备
cat /proc/interrupts | grep i2c — 查看I2C中断分配