|
如果你做过嵌入式音频开发,一定经历过这种痛苦:硬件上只是换了一颗CODEC芯片,软件上却要重新写一个Machine Driver(C代码+编译+调试),动辄一两天。更难受的是,这些驱动代码80%都是重复的——解析DTS、设置dai_link、注册声卡...... 有没有办法把这些重复劳动消灭掉?有,而且Rockchip平台已经帮你铺好了三条路。 |
一、Machine Driver到底是干什么的?
用大白话说,Machine Driver是"组装说明书"。它告诉内核:SoC的哪个音频接口(I2S/SAI/PDM)连接了哪颗CODEC,它们之间用什么格式通信,谁提供时钟。
CPU DAI(I2S/SAI)+ CODEC(ES8388/RK817)+MachineDriver=一个完整的声卡
没有这个"说明书",CPU DAI驱动和CODEC驱动就是两个独立的零件,谁也找不到谁。

二、三条路,按需求选
Rockchip平台目前主要提供三种Machine Driver方案:
|
方案 |
复杂度 |
适用场景 |
|
Simple Card |
低(只改DTS) |
单DAI +单CODEC,绝大多数情况 |
|
Multi Codecs |
中 |
一DAI接多CODEC,带耳机检测/按键 |
|
HDMI Audio |
中 |
HDMI/DP音频输出 |
下面逐一讲解。
三、Simple Card:最省心的"万能胶"
3.1它解决了什么痛点?
在Simple Card出现之前,每适配一块新板子都要写独立的Machine Driver:
板子A(I2S + ES8388)→ es8388_machine.c板子B(I2S + RT5645)→ rt5645_machine.c板子 C(SAI + 自定义 CODEC)→ 又得写一份......
有了Simple Card,内核框架帮你做了所有通用逻辑,你只需要在DTS里写几行配置,声卡就注册好了。不需要写一行C代码。
3.2最小DTS配置有多简单?
sound {compatible ="simple-audio-card";simple-audio-card,name ="rockchip-es8388";simple-audio-card,format="i2s";simple-audio-card,mclk-fs = <256>;simple-audio-card,cpu {sound-dai = <&i2s0>; /* CPU 侧音频接口 */};simple-audio-card,codec {sound-dai = <&es8388>; /* CODEC 芯片 */};};
就这几行,一个声卡就注册完成了。内核里的simple-card.c会自动解析这些属性,帮你完成以前需要手写的所有步骤。
3.3常用配置属性速查
|
属性 |
作用 |
示例值 |
|
format |
DAI通信格式 |
"i2s"、"dsp_a"、"left_j" |
|
mclk-fs |
MCLK倍频 |
128、256、512 |
|
bitclock-master |
BCLK由谁提供 |
<&cpu_dai>或<&codec_dai> |
|
frame-master |
LRCK由谁提供 |
同上 |
|
bitclock-inversion |
BCLK反相 |
蓝牙音频常见 |
|
dai-tdm-slot-num |
TDM Slot数量 |
8 |
|
dai-tdm-slot-width |
每个Slot位宽 |
32 |
3.4主从模式怎么配?
最常见的情况:CPU做Master(SoC产生时钟)
simple-audio-card,bitclock-master= <&cpu_dai>;simple-audio-card,frame-master= <&cpu_dai>;
特殊情况:CODEC做Master(比如某些低延迟场景)
simple-audio-card,bitclock-master= <&codec_dai>;simple-audio-card,frame-master= <&codec_dai>;
配错主从关系,最直接的后果就是时钟对不上,声卡要么注册失败,要么播放出来的是杂音。
3.5一个实际例子:RK3576车载平台的三路声卡
/* 声卡 0:TDM 8 通道 */sound0 {compatible ="simple-audio-card";simple-audio-card,name ="rockchip,tdm";simple-audio-card,format ="i2s";simple-audio-card,mclk-fs = <256>;simple-audio-card,cpu {sound-dai = <&sai1>;dai-tdm-slot-num = <8>;dai-tdm-slot-width = <32>;};simple-audio-card,codec {sound-dai = <&dummy_codec0>;};};/* 声卡 1:低延迟播放(CODEC 为主时钟) */sound1 {compatible ="simple-audio-card";simple-audio-card,name ="rockchip,low-latency";simple-audio-card,format ="i2s";simple-audio-card,mclk-fs = <256>;simple-audio-card,bitclock-master = <&dummy_clk1>;simple-audio-card,frame-master = <&dummy_clk1>;simple-audio-card,cpu {sound-dai = <&sai4>;};dummy_clk1: simple-audio-card,codec {sound-dai = <&dummy_codec1>;};};/* 声卡 2:蓝牙音频(PCM 格式 + 时钟反相) */sound2 {compatible ="simple-audio-card";simple-audio-card,name ="rockchip,bt";simple-audio-card,format ="dsp_a";simple-audio-card,bitclock-inversion;simple-audio-card,mclk-fs = <256>;simple-audio-card,cpu {sound-dai = <&sai2>;};simple-audio-card,codec {sound-dai = <&bt_codec 1>;};};
一块芯片上同时跑TDM、低延迟、蓝牙三路音频,每种场景的配置差异一目了然。
四、Multi Codecs:一个DAI驱动多个CODEC
4.1什么时候需要它?
Simple Card只能做到"一对一":一个DAI接一个CODEC。但产品经常有这样的需求:
•同一个I2S既要接耳机CODEC,又要接扬声器功放
•需要检测耳机插入/拔出,自动切换音频输出
•耳机线上有按键(播放/暂停、音量加减)
•需要支持ASRC异步采样率转换
这些需求Simple Card搞不定,需要用rockchip_multicodecs.c。
4.2核心能力一览
|
功能 |
说明 |
|
Jack检测 |
GPIO中断+ ADC电压判断耳机/耳麦类型 |
|
ADC按键 |
通过ADC电压映射识别耳机线上的按键 |
|
extcon通知 |
通知Android系统耳机插拔事件 |
|
DAPM路由 |
耳机/扬声器/麦克风的动态电源管理 |
4.3 Jack检测是怎么工作的?
耳机插入 → GPIO 中断触发│▼读取 ADC 电压值│├──0~222mV → 普通耳机(无麦)├──223~1500mV→ 耳麦(带麦克风)└── >1501mV → 普通耳机│▼上报 Jack 状态 → 通知 Android → 启动按键轮询
原理很简单:不同阻抗的耳机会在检测引脚上产生不同的分压,驱动根据电压范围判断类型。这不是什么玄学,就是初中物理的分压电路。
4.4 DTS配置示例
multicodecs_sound: multicodecs-sound {compatible ="rockchip,multicodecs-card";rockchip,card-name ="rockchip-multicodecs";rockchip,cpu = <&i2s0>;rockchip,codec = <&es8388>, <&hdmi_codec>;rockchip,mclk-fs = <256>;/* 耳机检测 GPIO */rockchip,hp-det-gpio = <&gpio3 RK_PA5 GPIO_ACTIVE_LOW>;rockchip,hp-ctl-gpio = <&gpio3 RK_PA6 GPIO_ACTIVE_HIGH>;rockchip,spk-ctl-gpio = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>;/* ADC 按键配置 */adc-keys{compatible ="adc-keys";io-channels = <&saradc 0>;button-play {label ="play";linux,code =; press-threshold-microvolt = <100000>; /* 100mV */};button-volup {label ="volume up";linux,code =; press-threshold-microvolt = <300000>; /* 300mV */};};};
注意rockchip,codec后面可以跟多个phandle,这就是"一个DAI接多个CODEC"的关键。
五、HDMI Audio:音视频一体输出
5.1架构
HDMI音频和模拟音频最大的区别是:音频数据不是直接送给扬声器,而是先交给HDMI编码器,和画面打包后一起发出去。
SoCI2S/SAI → HDMI 编码器 → HDMI 线缆 → 显示器/TV 出声│ ││ └── hdmi-codec.c(通用 HDMI CODEC 驱动)│└── rockchip_hdmi.c(Rockchip HDMI Machine Driver)
5.2 DTS配置
hdmi_sound: hdmi-sound {compatible ="rockchip,hdmi";rockchip,mclk-fs = <128>; /* HDMI 通常用 128 倍频 */rockchip,card-name ="rockchip-hdmi";rockchip,cpu = <&sai6>;rockchip,codec = <&hdmi>;rockchip,jack-det; /* 启用 HDMI 热插拔检测 */};
DP音频的配置类似,只是倍频和接口不同:
dp0_sound: dp0-sound {compatible ="rockchip,hdmi";rockchip,mclk-fs = <512>; /* DP 用 SPDIF,512 倍频 */rockchip,card-name ="rockchip-dp0";rockchip,cpu = <&spdif_tx3>;rockchip,codec = <&dp0 1>;rockchip,jack-det;};
六、DAPM路由:别把声音送错门
DAPM(Dynamic Audio Power Management)是ASoC的自动电源管理机制。Machine Driver通过audio-routing定义音频信号在芯片内部的走线:
sound {simple-audio-card,audio-routing ="Headphone","HPOL", /* 左声道输出 → 耳机 */"Headphone","HPOR", /* 右声道输出 → 耳机 */"Speaker","SPKLN", /* 左声道 → 扬声器 */"Speaker","SPKLP", /* 右声道 → 扬声器 */"MICBIAS","Main Mic", /* 主麦克风需要偏置电压 */"IN1P","Main Mic"; /* 麦克风信号输入 */};
注意格式:每一行都是"目标", "源"的顺序。目标通常是外部接口(Headphone/Speaker/Mic),源是CODEC内部的widget名称。
如果路由配错了,可能出现"播放正常但耳机没声"、"录音有信号但来源不对"等奇怪问题。排查时可以用这个命令查看DAPM状态:
cat/sys/kernel/debug/asoc/*/dapm/widget
七、三种方案怎么选?一张图说清楚
|
需求 |
推荐方案 |
|
普通播放/录制,单CODEC |
Simple Card |
|
要耳机检测+自动切换 |
Multi Codecs |
|
耳机线上有按键 |
Multi Codecs |
|
一个DAI同时接耳机+扬声器 |
Multi Codecs |
|
需要ASRC采样率转换 |
Multi Codecs |
|
HDMI/DP音频输出 |
HDMI Audio |
|
TDM多通道音频 |
Simple Card(配TDM参数) |
八、总结
Machine Driver的本质是"连接说明书"。Rockchip平台通过三种方案覆盖了从最简单到较复杂的所有场景:
•Simple Card让90%的场景不再需要写C代码,改DTS就能适配新板子
•Multi Codecs在Simple Card基础上扩展了耳机检测、ADC按键、多CODEC支持
•HDMI Audio专门处理音视频一体的输出场景
-
接口
+关注
关注
33文章
9648浏览量
157855 -
音频
+关注
关注
31文章
3254浏览量
86587 -
Rockchip
+关注
关注
0文章
97浏览量
19709
发布评论请先 登录
【ELF 2学习板试用】05 ASoC中的machine class
BPS恒流驱动IC选型指南
分析一下Rockchip DRM的主驱动程序
RK3288 Android6.0 Audio的ASOC驱动及数据结构分析
Rockchip Linux SDK uboot logo开发指南
Rockchip i2c开发指南
Rockchip RKDevInfoWriteTool工具及使用指南
RK平台UART开发!从驱动配置到测试全流程
RK 平台 SPI 开发完全指南(驱动 + 配置 + 测试 + 优化)
深入解析Rockchip SFC驱动:SPI Flash传输流程与问题排查指南
Rockchip Machine Driver选型指南:从“每块板子写驱动”到“只改几行配置”
评论