1. 引言
WM8960 是一款 高性能立体声编解码器(Codec),支持 耳机放大、扬声器驱动、麦克风输入、I²C 控制和 I²S 音频传输。它常用于 嵌入式 Linux 设备,如 NXP i.MX8M Plus EVK,并与 SAI(I²S 控制器) 配合使用。
在 Linux ASoC(ALSA System-on-Chip) 体系下,WM8960 主要涉及以下组件:
- Codec 驱动(WM8960 控制和音频处理)
- Platform 驱动(SAI 传输接口)
- Machine 驱动(绑定 Codec 和 SAI)
本篇博文将完整剖析 WM8960 音频驱动的实现,涵盖:
- 设备树(DTS)配置
- ASoC 框架解析
- WM8960 Codec 驱动解析
- 音频数据流管理
- Machine Driver 详解
- 调试与测试
2. 设备树(DTS)解析
在 设备树(DTS)中,WM8960 主要涉及 I2C 设备注册、音频控制器(SAI)、音频流路径。
2.1 注册 WM8960 I2C 设备
&i2c3 {
clock-frequency = <400000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c3>;
status = "okay";
codec: wm8960@1a {
compatible = "wlf,wm8960";
reg = <0x1a>; // WM8960 I2C 地址
clocks = <&audio_blk_ctrl IMX8MP_CLK_AUDIO_BLK_CTRL_SAI3_MCLK1>;
clock-names = "mclk";
wlf,shared-lrclk;
wlf,hp-cfg = <3 2 3>;
wlf,gpio-cfg = <1 3>;
SPKVDD1-supply = <®_audio_pwr>;
};
};
解析:
compatible = "wlf,wm8960";
→ 设备匹配 WM8960 驱动reg = <0x1a>;
→ 设备 I2C 地址clocks
→ 配置mclk
时钟源SPKVDD1-supply
→ 供电管理
2.2 定义 Sound Card
sound-wm8960 {
compatible = "fsl,imx-audio-wm8960";
model = "wm8960-audio";
audio-cpu = <&sai3>; // 绑定 SAI3 控制器
audio-codec = <&codec>; // 绑定 WM8960 编解码器
audio-asrc = <&easrc>; // 绑定 ASRC 进行音频采样率转换
hp-det-gpio = <&gpio4 28 0>; // 耳机检测 GPIO
audio-routing =
"Headphone Jack", "HP_L",
"Headphone Jack", "HP_R",
"Ext Spk", "SPK_LP",
"Ext Spk", "SPK_LN",
"Ext Spk", "SPK_RP",
"Ext Spk", "SPK_RN",
"LINPUT1", "Mic Jack",
"LINPUT3", "Mic Jack",
"Mic Jack", "MICB";
};
解析:
audio-cpu = <&sai3>;
→ 绑定SAI3
控制器audio-codec = <&codec>;
→ 绑定WM8960
audio-routing
→ 定义音频输入/输出路径
2.3 SAI3 配置
&sai3 {
assigned-clocks = <&clk IMX8MP_CLK_SAI3>,
<&clk IMX8MP_CLK_SAI3_ROOT>;
assigned-clock-parents = <&clk IMX8MP_AUDIO_PLL1_OUT>;
assigned-clock-rates = <12288000>, <12288000>;
status = "okay";
};
MCLK
来源:AUDIO_PLL1
assigned-clock-rates
设置12.288 MHz
3. ASoC 框架解析
ALSA System-on-Chip(ASoC) 框架包含:
- Codec Driver(编解码器驱动) →
sound/soc/codecs/wm8960.c
- Platform Driver(SAI 控制器) →
sound/soc/fsl/fsl_sai.c
- Machine Driver(绑定 Codec 和 SAI) →
sound/soc/fsl/imx-wm8960.c
4. 核心驱动代码
4.1 Codec 驱动
static int wm8960_i2c_probe(struct i2c_client *i2c) {
struct wm8960_priv *wm8960;
wm8960 = devm_kzalloc(&i2c->dev, sizeof(*wm8960), GFP_KERNEL);
wm8960->regmap = devm_regmap_init_i2c(i2c, &wm8960_regmap);
return devm_snd_soc_register_component(&i2c->dev,
&soc_component_dev_wm8960, &wm8960_dai, 1);
}
- I²C 设备初始化
- 注册
wm8960
组件
4.2 Machine 驱动
static struct snd_soc_dai_link imx_wm8960_dai = {
.name = "WM8960",
.stream_name = "WM8960 HiFi",
.cpu_dai_name = "sai3",
.codec_dai_name = "wm8960-hifi",
.platform_name = "fsl-sai",
.codec_name = "wm8960.1-001a",
};
- 绑定 SAI3
- Codec 设备名
wm8960.1-001a
5. 调试与测试
5.1 确认设备是否注册
dmesg | grep wm8960
ls /sys/class/sound
aplay -l
5.2 I2C 设备调试
i2cdetect -y -r 3 # 查看 I2C3 总线设备
5.3 播放音频
aplay -D hw:0,0 test.wav
6. 结论
本文完整解析了 WM8960 音频驱动的实现,包括 设备树、ASoC 框架、核心代码、音频数据流管理、机器驱动和调试方法。开发者可以基于这些内容,深入理解 嵌入式 Linux 音频系统,并在实际项目中 高效调试和优化。
适用场景
✅ 嵌入式 Linux 音频开发
✅ i.MX8M Plus EVK Yocto 项目
✅ ASoC 体系下的音频调试
✅ Codec + SAI 设备驱动分析