Rockchip Machine Driver选型指南:从“每块板子写驱动”到“只改几行配置”

电子说

1.4w人已加入

描述

 

如果你做过嵌入式音频开发,一定经历过这种痛苦:硬件上只是换了一颗 CODEC 芯片,软件上却要重新写一个 Machine Driver代码 编译 调试),动辄一两天。更难受的是,这些驱动代码 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 倍频

128256512

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 做 MasterSoC 产生时钟)

  •  
  •  
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 路由:别把声音送错门

DAPMDynamic 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% 的场景不再需要写 代码,改 DTS 就能适配新板子

Multi Codecs  Simple Card 基础上扩展了耳机检测、ADC 按键、多 CODEC 支持

HDMI Audio 专门处理音视频一体的输出场景

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分