Rockchip Machine Driver选型指南:从“每块板子写驱动”到“只改几行配置” 电子说
|
如果你做过嵌入式音频开发,一定经历过这种痛苦:硬件上只是换了一颗 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)+ Machine Driver = 一个完整的声卡
没有这个 "说明书",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 编码器,和画面打包后一起发出去。
SoC I2S/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 专门处理音视频一体的输出场景
全部0条评论
快来发表一下你的评论吧 !