3、设备树规范:标准属性(compatible、reg、interrupts、status等)
设备树里那些标准属性,说白了就是内核和硬件之间的「通用接口协议」。你想想看,如果每个驱动都自己发明一套属性命名,那内核得乱成什么样?所以规范定了这么几个核心属性,大家统一遵守。我最早啃设备树的时候,就是被这几个属性绕晕过,后来发现其实就那么回事。
3.1 compatible —— 硬件身份证
这个属性最重要。它告诉内核:「我是谁,我能兼容谁」。格式很简单:"厂商,型号"。比如:
compatible = "ti,am335x-uart", "ns16550";
内核匹配驱动时,会从左往右试。第一个最精确,后面的作为备选。我在项目中遇到过一个问题:某款芯片的UART模块,厂商在设备树里只写了 "custom-uart",结果内核没有对应驱动,系统直接不认这个串口。后来加上 "ns16550" 作为兼容项,立马就好了。
3.2 reg —— 硬件地址空间
reg 描述的是设备在总线上的地址范围。格式是 reg = <地址 长度>。看个例子:
uart0: serial@44e09000 {
compatible = "ti,am335x-uart", "ns16550";
reg = <0x44e09000 0x2000>;
};
这里地址是 0x44e09000,长度 0x2000(8KB)。内核拿到这个信息后,就知道该把哪段物理地址映射到虚拟地址空间。
嗯,这里要注意:reg 里的地址是总线地址,不是 CPU 看到的物理地址。如果设备挂在 I2C 或 SPI 总线上,reg 表示的是从设备地址。比如:
eeprom@50 {
compatible = "atmel,24c02";
reg = <0x50>;
};
这里的 0x50 就是 I2C 从设备地址,没有长度字段。
3.3 interrupts —— 中断连接线
interrupts 属性描述设备的中断信息。它依赖 interrupt-parent 指定中断控制器。格式通常是:
interrupt-parent = &intc;
interrupts = <0 56 4>;
这三个数字的含义:
- 第一个:中断类型(0=SPI,1=PPI)
- 第二个:中断号(硬件中断号)
- 第三个:触发方式(1=上升沿,2=下降沿,4=高电平,8=低电平)
你想想看,如果设备有多个中断怎么办?那就写多组:
interrupts = <0 56 4>, <0 57 4>;
内核会按顺序解析,驱动里通过 platform_get_irq() 依次获取。
3.4 status —— 设备开关
status 属性控制设备是否启用。取值就几个:
| 值 | 含义 |
|---|---|
| "okay" | 设备启用,正常工作 |
| "disabled" | 设备禁用,内核不初始化 |
| "reserved" | 保留,由固件使用 |
| "fail" | 设备检测失败 |
我习惯在开发板上把所有外设都设为 "okay",量产时再根据实际硬件裁剪。有一次客户说某个功能不工作,我远程一看,设备树里 status 写成了 "disable"(少了个 d),内核直接忽略了该设备。
3.5 其他常用标准属性
除了上面四个,还有几个我经常用的:
- device_type:早期设备树用的多,现在基本被 compatible 取代。但有些总线(如 PCI)还在用。
- model:描述板子型号,比如
model = "TI AM335x BeagleBone Black"。 - clock-frequency:直接指定时钟频率,常用于简单设备。
- gpios:描述 GPIO 引脚,格式是
<控制器 引脚号 标志>。
3.6 知识体系结构图
下面这张图把标准属性的关系理清楚了:
3.7 实战中的组合使用
实际项目中,这些属性很少单独出现。我给你看一个完整的例子:
uart2: serial@48022000 {
compatible = "ti,omap4-uart", "ns16550";
reg = <0x48022000 0x400>;
interrupts = <0 73 4>;
status = "okay";
clock-frequency = <48000000>;
};
这个节点描述了 OMAP4 上的 UART2:
- 兼容 TI 自家驱动和标准 16550 驱动
- 寄存器基址 0x48022000,大小 1KB
- 使用 SPI 中断 73,高电平触发
- 设备启用,时钟 48MHz
内核解析时,先看 status 决定是否处理,然后用 compatible 找驱动,reg 做 ioremap,interrupts 注册中断处理函数。一气呵成。
标准属性就是设备树的「语法基础」。搞懂了它们,你就能读懂大部分设备树文件了。剩下的就是各种 binding 文档里定义的厂商专用属性,那些都是基于这些标准属性扩展出来的。