驱动开发硬核特训 · Day 30(下篇): 深入解析 lm48100q I2C 音频编解码器驱动模型(基于 i.MX8MP)
作者:嵌入式Jerry
视频教程请关注 B 站:“嵌入式Jerry”
一、背景与目标
在本篇中,我们围绕 TI 的 lm48100q 音频编解码器 展开,深入讲解其作为 I2C 外设如何集成至 Linux 内核音频子系统(ASoC),配合 i.MX8MP 平台上的 SAI 接口 实现音频回放功能。
目标包括:
- 理解 lm48100q 的设备树绑定方式
- 解析 codec 驱动与 machine 驱动的协同工作
- 分析其 register map、音频路径、power domain 的实现方式
- 展示 ASoC codec 驱动完整注册流程及常用结构体
- 给出核心代码结构 + 注释 + 驱动关系图
在这里插入图片描述
二、设备树配置分析(i.MX8MP)
在 imx8mp-evk.dts
中:
&i2c2 {clock-frequency = <100000>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c2>;status = "okay";lm48100q_codec: lm48100q@7d {compatible = "ti,lm48100q";reg = <0x7d>;#sound-dai-cells = <0>;};
};
解释:
- i2c2 为 I2C 控制器,
lm48100q
为挂载在 I2C 总线上的 codec,地址为0x7d
。 #sound-dai-cells = <0>
:表示 DAI(Digital Audio Interface)不接受参数,是一个单一 DAI。
对应的 sound-pcm1754
节点配置了该 codec:
sound-pcm1754 {compatible = "simple-audio-card";...simple-audio-card,codec {sound-dai = <&lm48100q_codec>;};
};
三、Linux 驱动结构概览
lm48100q 采用标准的 ASoC codec 驱动模型,主要涉及三个部分:
lm48100q.c
:codec 驱动本体(提供 DAI,电源,widget,路由定义)simple-audio-card.c
:machine 驱动(描述 CPU 和 codec 的连接关系)fsl-sai.c
:SAI 接口的 platform 驱动
整体结构如下图:
Userspace (aplay)↓ALSA PCM Interface↓ASoC Core Framework↓ ↓Codec Driver Platform Driverlm48100q.c fsl-sai.c↓ ↓I2C (regmap) SAI (platform)↓ ↓音频编解码芯片 i.MX SAI 控制器
四、lm48100q Codec 驱动详解
源码路径:sound/soc/codecs/lm48100q.c
(或 TI 提供)
1. 模块入口与 of 绑定
static const struct of_device_id lm48100q_of_match[] = {{ .compatible = "ti,lm48100q" },{},
};
MODULE_DEVICE_TABLE(of, lm48100q_of_match);
绑定设备树节点中的 "ti,lm48100q"
。
2. I2C 驱动结构
static struct i2c_driver lm48100q_i2c_driver = {.driver = {.name = "lm48100q",.of_match_table = lm48100q_of_match,},.probe = lm48100q_i2c_probe,.remove = lm48100q_i2c_remove,
};
3. codec 结构体注册
static const struct regmap_config lm48100q_regmap = {.reg_bits = 8,.val_bits = 8,.max_register = LM48100Q_MAX_REG,.volatile_reg = lm48100q_volatile,
};static int lm48100q_i2c_probe(struct i2c_client *i2c)
{struct regmap *regmap;regmap = devm_regmap_init_i2c(i2c, &lm48100q_regmap);...return devm_snd_soc_register_component(&i2c->dev,&soc_component_dev_lm48100q, &lm48100q_dai, 1);
}
- 使用 regmap 管理寄存器读写
- 通过
snd_soc_register_component()
注册 codec
4. DAI 定义
static struct snd_soc_dai_driver lm48100q_dai = {.name = "lm48100q-hifi",.playback = {.stream_name = "Playback",.channels_min = 2,.channels_max = 2,.rates = SNDRV_PCM_RATE_8000_192000,.formats = SNDRV_PCM_FMTBIT_S16_LE |SNDRV_PCM_FMTBIT_S24_LE,},.ops = &lm48100q_dai_ops,
};
该 DAI 只支持 Playback,不支持录音。
5. 控件与路径配置(Widgets & Routes)
static const struct snd_soc_dapm_widget lm48100q_dapm_widgets[] = {SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),SND_SOC_DAPM_OUTPUT("HPOL"),SND_SOC_DAPM_OUTPUT("HPOR"),
};static const struct snd_soc_dapm_route lm48100q_dapm_routes[] = {{ "HPOL", NULL, "DAC" },{ "HPOR", NULL, "DAC" },
};
定义音频组件的连接路径。
五、Machine 驱动部分(simple-audio-card)
无需用户实现,使用设备树进行配置:
sound-pcm1754 {compatible = "simple-audio-card";simple-audio-card,name = "pcm1754-audio";...simple-audio-card,cpu {sound-dai = <&sai3>;};simple-audio-card,codec {sound-dai = <&lm48100q_codec>;};
};
ASoC core 解析 device tree 并自动注册 machine 驱动。
六、SAI 平台驱动(以 SAI3 为例)
路径:sound/soc/fsl/fsl_sai.c
它通过 platform_driver
提供 snd_soc_dai_driver
,用于与 codec 的 DAI 建立连接关系。
七、应用层播放验证
音频配置好后,在根文件系统中可使用如下命令验证:
aplay -D plughw:0,0 test.wav
如果设备树、驱动、路径配置都正确,lm48100q
会响应并输出音频信号至耳机口。
八、完整调试技巧总结
1. 确认设备树生效:
dmesg | grep lm48100q
cat /proc/device-tree/soc@0/bus@30800000/i2c@30a20000/lm48100q@7d/compatible
2. 查看注册的声卡与 DAI:
cat /proc/asound/cards
cat /proc/asound/pcm
3. 检查 regmap:
i2cget -y 0 0x7d 0x01
九、小结
模块 | 类型 | 驱动入口 |
---|---|---|
lm48100q | Codec | I2C + ASoC Codec |
SAI3 | Platform | fsl-sai |
Sound Card | Machine | simple-audio-card DT |
lm48100q codec 的驱动模型是典型的 I2C + ASoC codec 类型,配合 i.MX 的 SAI 控制器,适用于嵌入式音频设备中的播放场景,具有较好的模块化与可移植性。
🔚 结语
至此,《驱动开发硬核特训 · Day 30》完整结束,我们已完整解析了两个典型的 I2C 总线驱动:at24 EEPROM 与 lm48100q 音频 codec,分别展示了 字符设备模型 与 子系统型 Codec 驱动 的集成方式。
📌 技术平台:嵌入式Jerry
📺 视频教程请关注 B 站:“嵌入式Jerry”