设备树核心属性compatible详解:从入门到实战
引言:设备树的"身份证"系统
在嵌入式开发中,设备树(Device Tree)是连接硬件与软件的关键桥梁。而compatible属性就是设备树的"身份证",它决定了硬件设备如何被操作系统识别和驱动。本文将通过生活化类比和实战案例,带你彻底掌握compatible的奥秘。
一、compatible属性基础概念
1.1 设备树结构类比
想象设备树是一个大型公司的组织架构图:
- 节点(Node) = 部门(如研发部、市场部)
- 属性(Property) = 部门职责描述
- compatible = 部门编号(唯一标识)
1.2 compatible的核心作用
compatible = "厂商,设备型号", "通用标准";
- 第一字符串:精确匹配(如"asus,rog-strix")
- 后续字符串:通用兼容(如"pci-express")
就像身份证:
- 姓名:精确匹配(“张三”)
- 民族/性别:通用属性(“汉族/男”)
二、compatible实战解析
2.1 基础应用案例:LED驱动
leds {
compatible = "gpio-leds"; // 通用LED驱动匹配
power_led: power {
label = "system:power"; // 设备标识
gpios = <&gpio 15 GPIO_ACTIVE_HIGH>; // 物理引脚
default-state = "on";
};
};
驱动匹配过程:
2.2 进阶案例:触摸屏驱动
&i2c1 {
touchscreen@38 {
compatible = "focaltech,ft6236", "edt,edt-ft5x06";
reg = <0x38>; // I2C地址
interrupt-parent = <&gpio>;
interrupts = <5 IRQ_TYPE_EDGE_FALLING>; // 中断引脚
};
};
匹配优先级:
- 优先匹配
focaltech,ft6236(厂商专用驱动) - 若无,匹配
edt,edt-ft5x06(通用驱动)
三、项目实战:添加新设备
3.1 场景:为全志T113添加温湿度传感器
硬件:AHT20温湿度传感器(I2C接口)
步骤1:设备树节点添加
// 文件: sun8i-t113.dtsi
&i2c2 {
status = "okay";
aht20: sensor@38 {
compatible = "aosong,aht20"; // 匹配驱动
reg = <0x38>;// I2C地址
vdd-supply = <®_dcdc1>;// 电源
};
};
步骤2:驱动代码匹配
// 驱动文件: drivers/iio/humidity/aht20.c
static const struct of_device_id aht20_of_match[] = {
{ .compatible = "aosong,aht20" }, // 匹配字符串
{ }
};
MODULE_DEVICE_TABLE(of, aht20_of_match);
static struct i2c_driver aht20_driver = {
.driver = {
.name = "aht20",
.of_match_table = aht20_of_match, // 关键匹配表
},
.probe = aht20_probe,
.id_table = aht20_id,
};
步骤3:验证加载
# 查看内核日志
dmesg | grep aht20
# 预期输出:
# [3.452100] aht20 2-0038: AHT20 temperature sensor registered
3.2 调试技巧
问题排查表:
| 现象 | 可能原因 | 解决方案 |
|---|---|---|
| 设备未加载 | compatible拼写错误 | dmesg |
| 驱动未触发 | 缺少MODULE_DEVICE_TABLE | 检查驱动是否声明 |
| 重复匹配 | 多个驱动声明相同compatible | 检查驱动冲突 |
四、类比学习:设备树属性家族
4.1 寄存器属性:reg
reg = <地址 长度>;
类比:设备的"家庭住址"
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x20000000>; // 512MB内存
};
4.2 中断属性:interrupts
interrupts = <控制器 编号 触发类型>;
类比:设备的"紧急联系电话"
ethernet@1c30000 {
interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
// GIC控制器, SPI中断82, 高电平触发
};
4.3 时钟属性:clocks
clocks = <&时钟源 时钟ID>;
类比:设备的"生物钟"
uart0: serial@5000000 {
clocks = <&ccu CLK_BUS_UART0>; // 使用CCU的UART0时钟
};
五、compatible高级应用
5.1 多设备兼容
compatible = "ti,tps65218", "ti,tps65217";
// 支持新老两代芯片
5.2 设备变种处理
// 驱动中处理变种
static int sensor_probe(struct i2c_client *client)
{
if (of_device_is_compatible(np, "aosong,aht20-pro")) {
// 专业版特殊处理
} else {
// 标准版处理
}
}
5.3 自动设备生成
// 自动生成多个I2C设备
i2c {
compatible = "simple-bus"; // 通用总线驱动
#address-cells = <1>;
#size-cells = <0>;
sensor@48 { ... };
eeprom@50 { ... };
};
六、实战拓展:跨平台设备树
6.1 全志T113 vs 瑞芯微RK3568
| 属性 | T113 | RK3568 | 转换规则 |
|---|---|---|---|
| GPIO | &pio PH 5 | &gpio3 RK_PA1 | 引脚重映射 |
| 时钟 | &ccu CLK_PLL_PERIPH0 | &cru PLL_CPLL | 时钟树转换 |
| 中断 | GIC_SPI 50 | GIC_SPI 148 | 中断号重计算 |
6.2 通用设备树模板
/dts-v1/;
/ {
compatible = "board-vendor,board-name"; // 板级标识
#address-cells = <1>;
#size-cells = <1>;
memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x40000000>; // 1GB内存
};
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu0: cpu@0 {
compatible = "arm,cortex-a7";
device_type = "cpu";
reg = <0>;
};
};
soc {
compatible = "simple-bus";
#address-cells = <1>;
#size-cells = <1>;
ranges;
serial0: uart@5000000 {
compatible = "snps,dw-apb-uart";
reg = <0x05000000 0x100>;
interrupts = <0 20 4>;
clocks = <&clk_periph>;
};
};
};
七、调试工具集
7.1 设备树查看命令
# 反编译DTB
dtc -I dtb -O dts -o system.dts /boot/dtb.img
# 查看节点属性
ls /proc/device-tree/soc/uart@5000000/
# 实时调试
echo "file drivers/of/*.c +p" > /sys/kernel/debug/dynamic_debug/control
7.2 图形化工具
使用dt-viewer工具可视化设备树
结语:compatible设计哲学
compatible属性体现了Linux设备模型的核心理念:
- 硬件抽象:分离驱动与硬件细节
- 向后兼容:通过多字符串支持老设备
- 开放扩展:厂商可定义私有属性
开发箴言:
优秀的设备树设计:
- 精确匹配:确保设备正确初始化
- 通用兼容:最大化驱动复用
- 清晰分层:硬件描述结构化
实战资源:
5461

被折叠的 条评论
为什么被折叠?



