4. 设备树与音频设备:设备树节点定义、compatible属性、reg与interrupts属性解析
在嵌入式 Linux 音频驱动开发中,设备树(Device Tree)是连接硬件描述与驱动代码的核心桥梁。本章将深入解析音频设备在设备树中的节点定义方式,重点讲解 compatible、reg 和 interrupts 三个关键属性的语义与用法,帮助你在实际项目中准确描述音频硬件资源。
4.1 音频设备树节点基础结构
一个典型的音频设备节点通常包含以下结构:
/ {
sound {
compatible = "vendor,audio-codec";
reg = <0x001a0000 0x1000>;
interrupts = <0 42 4>;
clocks = <&clkc 15>;
#sound-dai-cells = <0>;
};
};
每个节点由 节点名、属性 和 子节点 组成。节点名通常反映设备类型(如 i2s、codec、dma),而 compatible 属性是驱动匹配的关键。
audio-codec),而非具体型号(如 wm8960)。具体型号信息应放在 compatible 属性中,以保持设备树的通用性。
4.2 compatible 属性:驱动匹配的钥匙
compatible 属性是设备树中最关键的属性之一,它定义了设备与驱动之间的匹配关系。该属性是一个字符串列表,格式为 "厂商,型号",驱动通过 of_match_table 进行匹配。
| 属性字段 | 含义 | 示例 |
|---|---|---|
| 厂商前缀 | 设备制造商标识,通常使用标准前缀 | ti(TI)、nxp(NXP)、realtek |
| 型号标识 | 具体芯片或IP核型号 | tlv320aic3x、wm8960、ak4458 |
| 兼容性列表 | 可指定多个兼容型号,从最具体到最通用 | "ti,tlv320aic3106", "ti,tlv320aic3x" |
驱动中的匹配表定义示例:
static const struct of_device_id audio_codec_of_match[] = {
{ .compatible = "ti,tlv320aic3106", },
{ .compatible = "ti,tlv320aic3x", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, audio_codec_of_match);
compatible 字符串列表按优先级从高到低排列。驱动匹配时,会遍历设备树中的字符串,与 of_match_table 中的条目逐一比较,先匹配到的优先。因此,应将最具体的型号放在最前面。
4.3 reg 属性:寄存器地址与内存映射
reg 属性用于描述设备在系统总线上的地址空间,包括起始地址和长度。对于音频设备,通常用于指定 I2S 控制器、音频编解码器或 DMA 控制器的寄存器基址。
reg 属性的格式为 <地址 长度> 对,可包含多个地址段:
reg = <0x001a0000 0x1000>; // 单个地址段
reg = <0x001a0000 0x1000 // 第一个地址段:控制寄存器
0x001b0000 0x0200>; // 第二个地址段:数据缓冲区
在驱动中,通过 platform_get_resource() 或 of_iomap() 获取并映射这些地址:
struct resource *res;
void __iomem *base;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
| reg 索引 | 典型用途 | 获取方式 |
|---|---|---|
| 0 | 主控制寄存器基址 | platform_get_resource(pdev, IORESOURCE_MEM, 0) |
| 1 | FIFO 或数据缓冲区 | platform_get_resource(pdev, IORESOURCE_MEM, 1) |
| 2 | 辅助功能寄存器(如时钟控制) | platform_get_resource(pdev, IORESOURCE_MEM, 2) |
reg 时,应确保起始地址和长度符合硬件手册要求,否则 devm_ioremap_resource() 会返回错误。
4.4 interrupts 属性:中断资源描述
interrupts 属性用于描述设备使用的中断资源,包括中断控制器、中断号和触发类型。其格式依赖于中断控制器的 #interrupt-cells 属性。
对于 ARM GIC(Generic Interrupt Controller),通常使用 3 个 cell:
interrupts = <0 42 4>;
// 第1个cell: 中断类型 (0=SPI, 1=PPI)
// 第2个cell: 中断号 (SPI: 32-1019, PPI: 16-31)
// 第3个cell: 触发类型 (1=上升沿, 2=下降沿, 4=高电平, 8=低电平)
驱动中获取中断号的典型方式:
int irq;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
ret = devm_request_irq(&pdev->dev, irq, audio_isr,
IRQF_TRIGGER_HIGH, "audio-codec", dev);
| 中断类型 | cell 值 | 说明 | 典型中断号范围 |
|---|---|---|---|
| SPI(共享外设中断) | 0 | 多个设备可共享的中断线 | 32 ~ 1019 |
| PPI(私有外设中断) | 1 | 每个 CPU 核心私有的中断 | 16 ~ 31 |
interrupts = <0 42 4>,实际 Linux 内核看到的中断号是 42 + 32 = 74。驱动开发时,应使用 platform_get_irq() 返回的原始值,无需手动偏移。
4.5 音频设备树完整示例:I2S 控制器 + 编解码器
以下是一个完整的音频子系统设备树示例,展示了 I2S 控制器与音频编解码器的节点定义:
/ {
sound_card {
compatible = "simple-audio-card";
simple-audio-card,name = "MyAudioCard";
simple-audio-card,format = "i2s";
simple-audio-card,bitclock-master = <&codec>;
simple-audio-card,frame-master = <&codec>;
cpu {
sound-dai = <&i2s0>;
};
codec {
sound-dai = <&codec>;
};
};
i2s0: i2s@001a0000 {
compatible = "vendor,i2s-controller";
reg = <0x001a0000 0x1000>;
interrupts = <0 45 4>;
clocks = <&clkc 15>, <&clkc 16>;
clock-names = "bus", "mclk";
dmas = <&dma 2>, <&dma 3>;
dma-names = "tx", "rx";
#sound-dai-cells = <0>;
};
codec: audio-codec@001b0000 {
compatible = "ti,tlv320aic3106", "ti,tlv320aic3x";
reg = <0x001b0000 0x0200>;
interrupts = <0 46 4>;
clocks = <&clkc 17>;
clock-names = "mclk";
#sound-dai-cells = <0>;
};
};
clocks、dmas 等额外属性,这些属性与 reg、interrupts 共同构成完整的硬件资源描述。驱动通过 of_parse_phandle() 和 of_property_read_u32() 等 API 解析这些属性。
4.6 设备树资源解析流程 SVG 图
下图展示了音频驱动从设备树节点解析硬件资源的完整流程:
4.7 常见问题与避坑指南
- compatible 字符串拼写错误:驱动匹配失败是最常见的问题。务必核对设备树中的
compatible字符串与驱动of_match_table中的字符串完全一致(包括大小写)。 - reg 地址范围重叠:多个设备节点不应使用重叠的
reg地址范围,否则会导致ioremap失败。使用devm_ioremap_resource()可自动检测地址冲突。 - 中断号配置错误:对于 GIC 控制器,SPI 中断号在设备树中从 0 开始,但内核内部会加 32。不要手动调整中断号,始终使用
platform_get_irq()获取。 - 缺少 #interrupt-cells:中断控制器节点必须定义
#interrupt-cells属性,否则设备节点的interrupts属性无法被正确解析。 - 音频设备特有属性遗漏:音频驱动常需要
#sound-dai-cells、clocks、dmas等属性,这些属性在设备树中缺失会导致sound card注册失败。
dtc -I dtb -O dts 反编译设备树二进制文件,检查节点属性是否正确。在驱动中通过 dev_info() 打印解析到的资源值,与设备树中的定义进行比对。
4.8 本章小结
设备树是音频驱动开发中不可或缺的硬件描述语言。通过本章的学习,你应掌握:
- 音频设备树节点的基本结构,包括节点名、属性和子节点的组织方式。
compatible属性的匹配机制,以及如何编写驱动匹配表。reg属性的地址空间描述方法,以及驱动中获取寄存器基址的 API。interrupts属性的中断资源描述,包括 GIC 的中断类型和触发方式。- 完整的音频设备树示例,以及常见问题的排查方法。