3. 设备树基础与I2C配置
设备树,说白了就是一块「硬件描述板」。Linux 内核通过它才知道你的板子上接了哪些外设、地址是多少、用哪个中断。我刚开始接触设备树时也觉得这东西很玄乎,后来调过几块板子就明白了——它就是个结构化的配置文件。
这一章我们聚焦三个事:设备树语法怎么用、WM8960 节点怎么写、I2C 控制器怎么配。最后编译验证,确保改动生效。
3.1 设备树语法速览
设备树文件后缀是 .dts,编译后生成 .dtb。基本单元叫「节点」,每个节点描述一个硬件设备。
/dts-v1/;
/ {
model = "My Audio Board";
compatible = "vendor,board";
i2c1: i2c@40012000 {
compatible = "st,stm32-i2c1";
reg = <0x40012000 0x400>;
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
wm8960: codec@1a {
compatible = "wlf,wm8960";
reg = <0x1a>;
};
};
};
几个关键点:
- compatible:驱动匹配的关键字,格式通常是「厂商,设备名」。
- reg:地址信息。对 I2C 设备来说就是从机地址。
- status:
"okay"表示启用,"disabled"表示关闭。 - #address-cells 和 #size-cells:定义子节点 reg 的格式。I2C 总线一般用
<1 0>。
3.2 在设备树中描述 WM8960 节点
WM8960 是一个音频编解码芯片,挂在 I2C 总线上。我们需要告诉内核:它的地址、用哪个 I2C 控制器、以及音频相关的时钟和引脚。
下面是一个完整的 WM8960 节点示例:
&i2c1 {
status = "okay";
clock-frequency = <100000>;
wm8960: audio-codec@1a {
compatible = "wlf,wm8960";
reg = <0x1a>;
#sound-dai-cells = <0>;
clocks = <&clk IMX6QDL_CLK_CKO>;
clock-names = "mclk";
AVDD-supply = <®_3p3v>;
DVDD-supply = <®_3p3v>;
wlf,shared-lrclk;
};
};
解释一下:
- clock-frequency:I2C 总线速度,100kHz 是标准模式。
- #sound-dai-cells:音频 DAI 接口的配置,一般设为 0。
- clocks:主时钟 MCLK 的来源。WM8960 需要外部提供 12.288MHz 或 24.576MHz。
- supply:电源域,告诉内核这个芯片用哪路供电。
- wlf,shared-lrclk:厂商自定义属性,表示左右声道时钟共享。
3.3 配置 I2C 控制器与时钟
WM8960 的 I2C 控制器节点通常在 SoC 的 .dtsi 文件里已经定义好了。我们只需要在板级 .dts 文件中启用它,并配置 pinmux。
以 i.MX6Q 为例:
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
status = "okay";
};
&iomuxc {
pinctrl_i2c1: i2c1grp {
fsl,pins = <
MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1
MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1
>;
};
};
时钟部分,WM8960 的 MCLK 通常来自 SoC 的某个时钟输出引脚。比如 i.MX6Q 的 CKO 引脚:
&clks {
assigned-clocks = <&clk IMX6QDL_CLK_CKO>;
assigned-clock-parents = <&clk IMX6QDL_CLK_OSC>;
assigned-clock-rates = <12288000>;
};
这里把 CKO 时钟设为 12.288MHz,正好是 WM8960 需要的 MCLK 频率。
| 时钟名称 | 典型频率 | 用途 |
|---|---|---|
| MCLK | 12.288 MHz / 24.576 MHz | 编解码器主时钟 |
| BCLK | 1.536 MHz ~ 6.144 MHz | I2S 位时钟 |
| LRCLK | 48 kHz / 96 kHz | 左右声道帧时钟 |
3.4 编译并验证设备树
设备树写完后,需要编译成 .dtb 文件。方法很简单:
# 进入内核源码目录
make ARCH=arm dtbs
# 或者单独编译某个设备树
make ARCH=arm imx6q-sabresd.dtb
编译完成后,把 .dtb 文件复制到启动分区,重启系统。
验证设备树是否生效,我一般用这几个方法:
- 查看 /proc/device-tree:
ls /proc/device-tree/i2c1/audio-codec@1a/
如果能看到 compatible、reg 等文件,说明节点被正确解析了。
- 检查内核启动日志:
dmesg | grep wm8960
正常会看到类似:
wm8960 0-001a: WM8960 audio codec initialized
- 使用 i2cdetect 扫描总线:
i2cdetect -y 1
如果地址 0x1a 显示为 UU,表示设备已被驱动占用。
dtc -I dtb -O dts 反编译 .dtb,检查生成的 .dts 是否符合预期。这样可以避免一些低级错误。
3.5 本章知识结构图
下面这张 SVG 图梳理了设备树配置 WM8960 的完整链路:
从图中可以看到,WM8960 的设备树配置涉及 I2C 控制器、时钟、pinmux 和电源四个维度。任何一个环节出问题,音频驱动都可能无法正常工作。