Skip to content

从 tinymix 到 WM8960 DAPM 路由 ​

平台:100ask i.MX6ULL Pro
内核:NXP BSP Linux 4.9.88本文:用板子上的 tinymix 输出对照 Codec 内模拟通路,再阅读 snd_soc_dapm_route / mixer widget 源码


目录 ​


1. 本文要回答什么 ​

tinymix controls 里那一长串名字是什么?其中带 Mixer / Switch 的项如何对应 WM8960 内部连线?驱动里用哪个结构体声明这些连线?


2. 先建立图像:读后续所需概念 ​

把 Codec 里的模拟音频想成一座小城市供电网络。后文会反复出现下面这些词,先对齐含义:

概念比喻在驱动 / 用户态里是什么
DAPM整座城的调度所:谁在用电就给谁通电Dynamic Audio Power Management:按是否存在 complete path 给 widget 上电 / 断电
widget一座变电站 / 路口图上的节点(snd_soc_dapm_widget):DAC、ADC、Mixer、HP_L 等,常绑一颗电源位
route图纸上画好的「应从 A 到 B」驱动里的静态声明(snd_soc_dapm_route / 本驱动的 audio_paths[]):{ sink, control, source }
path两站之间真正铺好的一段电线route 注册后的运行时边(snd_soc_dapm_path);字段 connect 表示这段当前是否接通
DAPM kcontrol电线上的闸刀挂在 MIXER 等 widget 上的开关(使用 SOC_DAPM_SINGLE 声明);tinymix 里名字多含 … Mixer … Switch
普通 kcontrol变电站里的旋钮(音量等)改增益 / 静音 / ALC,一般不决定边通不通;与闸刀出现在同一张 tinymix 列表里
complete path从发电厂一直通到用户家的整条线路端点有效(在播 / 在录)且中间每一段 path 的 connect 都为真

关系可以记成一句话:

驱动用 route 画图纸,内核建成 path。DAPM kcontrol 决定某段 path 是否 connect。拼出 complete path 之后,沿线 widget 才由 DAPM 供电。

播放时心里可以记这一条:

text
Left DAC ──path──► Left Output Mixer ──path──► … ──path──► HP_L
   ▲                      ▲
widget                 widget
   │                      │
   │         闸刀 = DAPM kcontrol
   │         (如 PCM Playback Switch)
   └──────── complete path(整条都通才算)────────┘

图纸上的一笔 = route:{ "Left Output Mixer", "PCM Playback Switch", "Left DAC" }

几个易混点:

  • route 与 path:route 是源码里的静态表项;path 是运行时的边。后文画图、谈通断,说的是 path;谈到 audio_paths[],说的是 route。
  • DAPM kcontrol 与普通 kcontrol:都在 tinymix 里。闸刀管这段路通不通,旋钮管音量和参数。闸刀断开时,有音量,喇叭仍然无声,因为 complete path 没有接通。
  • control == NULL 的 route:图纸上规定常通,没有闸刀,注册后 path 一直 connect。
  • 内核在 dapm_power_widgets 里扫描的,正是 complete path(DAC→输出脚、输入脚→ADC、旁路、环回等)。

3. tinymix 的输出 ​

本板 tinymix 默认操作 card 0。两个常用子命令:

命令作用
tinymix controls只列控件:编号 / 类型 / 通道数 / 名字,不含当前值
tinymix contents在清单基础上再读出当前值(BOOL 为 On/Off,INT 带 range)
tinymix get '名字'读单个控件

只跑 controls 时看不到开关是开还是关,看 route 开关请用:

bash
tinymix contents
tinymix get 'Left Output Mixer PCM Playback Switch'

本板枚举结果约为 58 个控件。其中编号约 42~57 的 BOOL,名字形如 Left Output Mixer PCM Playback Switch,正是后文路由图上的边开关。


4. 两类控件:音量与 route 开关 ​

同一声卡的 mixer 列表里混着两类东西,宜分开看:

类型典型名字作用
普通 mixerSpeaker Playback Volume、Capture Volume、ALC / 3D 等改增益、静音、算法参数;多数来自 wm8960_snd_controls[]
DAPM mixer 开关… Mixer … Switch(约 ctl 42~57)选模拟支路是否接通;来自 widget 上挂的 SOC_DAPM_SINGLE

音量设置对了仍可能无声:可能是 PCM Playback Switch 等路径开关未接通,或 DAPM 未上电,数字通路与喇叭之间仍断开。

板子上与路由直接相关的 BOOL(tinymix controls 摘录):

text
42  Left Boost Mixer LINPUT2 Switch
43  Left Boost Mixer LINPUT3 Switch
44  Left Boost Mixer LINPUT1 Switch
45  Right Boost Mixer RINPUT2 Switch
46  Right Boost Mixer RINPUT3 Switch
47  Right Boost Mixer RINPUT1 Switch
48  Left Input Mixer Boost Switch
49  Right Input Mixer Boost Switch
50  Left Output Mixer PCM Playback Switch
51  Left Output Mixer LINPUT3 Switch
52  Left Output Mixer Boost Bypass Switch
53  Right Output Mixer PCM Playback Switch
54  Right Output Mixer RINPUT3 Switch
55  Right Output Mixer Boost Bypass Switch
56  Mono Output Mixer Left Switch
57  Mono Output Mixer Right Switch

5. 按开关画出路由图 ​

图中边上的标注对应上表 ctl 编号;无编号的边在驱动里 control 字段为 NULL,表示常通(不经 tinymix 开关)。

读 DAPM 路由图之前,可先对照芯片手册里的模拟前端(本板耳机麦走 LINPUT1 这一路):

WM8960 Figure 8:Microphone Input PGA Circuit

图源:Cirrus Logic WM8960 Datasheet Figure 8(版权归原厂商)。完整 PDF 见仓库 refs/datasheets/WM8960.pdf。

手册链(左声道)可记成:

LINPUT1 →(LMN1)→ Left Input PGA →(LMICBOOST)→(LMIC2B)→ Left Boost Mixer → Left ADC

控件位与 tinymix:

手册本板日常对照
LMN1Left Boost Mixer LINPUT1 Switch(ctl 44)
LMIC2BLeft Input Mixer Boost Switch(ctl 48)
LMICBOOSTLeft Input Boost Mixer LINPUT1 Volume(粗档再放大)
LINVOLCapture Volume 等 PGA 细调增益

手册与驱动 widget 名称可能对不上。手册没有 Left Input Mixer 这一块。对照时以寄存器位为准:

手册 Figure 8驱动 wm8960.c DAPM
Left Input PGA 一侧(选脚 LMN1 等)+ AINL 电源域widget Left Boost Mixer(其上挂 LINPUT1/2/3 Switch)
LMIC2B挂在 Left Input Mixer 上的 Boost Switch
手册里的 Left Boost Mixer(求和后进 ADC)图上更接近 Left Input Mixer → Left ADC 这一段

驱动链顺序是:Left Boost Mixer →(48)→ Left Input Mixer → ADC;与手册「PGA → LMIC2B → Boost Mixer → ADC」的命名左右对调。下文 Mermaid / tinymix 仍用驱动原名;48 还会同时出现在 LINPUT1 → Left Input Mixer 上(见 §7)。

5.1 录音(Capture) ​

模拟输入 → Boost Mixer / Input Mixer → ADC。相关开关主要是 42~49。

要点:

  • LINPUT2 / LINPUT3(及对称 RINPUT2 / RINPUT3)进入 Input Mixer 的边在驱动里是常通。
  • 走 Boost 支路时,需打开对应 LINPUT/RINPUT Switch,并打开 48 / 49(Boost Switch)。
  • 48 同时出现在两条边上(Boost Mixer→Input Mixer,以及 LINPUT1→Input Mixer),见 §7。
  • 本板插座 / 板载麦克风接到哪几个输入脚,见 §5.3。

5.2 播放(Playback) ​

DAC / 旁路 → Output Mixer → 耳机 / 喇叭(驱动里还可经 Mono Mixer 到 OUT3)。相关开关主要是 50~57。

播放时打开 50 / 53(PCM Playback Switch),Left/Right DAC 才能进 Output Mixer,再经后面的常通边到 HP_* / SPK_*。

LINPUT3 Switch(51、54)和 Boost Bypass(52、55)不经过 DAC,模拟信号直接进 Output Mixer。Left Switch / Right Switch(56、57)把左右 Output Mixer 送到 Mono Mixer,再出到芯片的 OUT3 脚。本板耳机插座接在 HP_L / HP_R,OUT3 没有接到插座,日常播放只开 50 / 53。

5.3 本板原理图与脚位 ​

百问底板原理图(100ask_imx6ull_v1.1.pdf 音频页,U17 WM8960)省略电阻、去耦与电源后,可以分成数字、模拟两张看:

数字口(SoC ↔ Codec)

模拟口(Codec ↔ 板级)

两路麦还共用 Codec 的 MICBIAS 偏置(图中略)。

板级通路接到 WM8960用 tinymix 时
3.5 mm 耳机麦(J10 → MIC1P)LINPUT1(耦合电容)打开左侧 Boost 相关开关(如 44 LINPUT1 Switch、48 Boost Switch)
板载麦克风(MIC2P / MIC2N)RINPUT2 / RINPUT1(差分)打开右侧 Boost(45~47、49)
耳机左右HP_L / HP_R → 约 47 µF 隔直 → J10数字播放经 Output Mixer 常通边到 HP_*
外接喇叭SPK_LP/LN/RP/RN 差分 → 喇叭座与耳机共用 Output Mixer 之后的喇叭功放脚
耳机插入检测 HPDRINPUT3 / JD3;ADCLRC/GPIO1 作 AUD_INTMachine 用 hp-det = <3 0> 选片内 JD
OUT3未外接驱动另有 Mono / capless 附加表;本板日常走 HP_* / SPK_*

audio-routing 用 Mic Jack、Main MIC、Headphone Jack 等名字挂到这些 Codec 脚;DAPM / tinymix 里看到的仍是 LINPUT*、HP_* 一类芯片侧名字。Machine 侧 sound 节点写法见 ASoC 四层 §6.1。


6. 源码:路由写在哪个结构体 ​

6.1 边:struct snd_soc_dapm_route ​

本驱动主路由表是 audio_paths[]:

c
/* sound/soc/codecs/wm8960.c */
static const struct snd_soc_dapm_route audio_paths[] = {
	{ "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" },
	{ "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
	{ "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" },

	{ "Left Input Mixer", "Boost Switch", "Left Boost Mixer" },
	{ "Left Input Mixer", "Boost Switch", "LINPUT1" },
	{ "Left Input Mixer", NULL, "LINPUT2" },
	{ "Left Input Mixer", NULL, "LINPUT3" },
	/* 右侧对称 … */

	{ "Left ADC", NULL, "Left Input Mixer" },
	{ "Right ADC", NULL, "Right Input Mixer" },

	{ "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" },
	{ "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer" },
	{ "Left Output Mixer", "PCM Playback Switch", "Left DAC" },
	/* 右侧对称 … */

	{ "LOUT1 PGA", NULL, "Left Output Mixer" },
	/* … → HP_L / SPK_* … */
};

每个元素三个字段:

字段含义
sink下游 widget 名(字符串,须与 widget 名一致)
control边上开关名;NULL = 常通
source上游 widget 名

有名字的 control 必须与某个 MIXER widget 上挂的 DAPM kcontrol 名字一致,否则边无法受 tinymix 控制。

6.2 widget:struct snd_soc_dapm_widget ​

widget 在 wm8960_dapm_widgets[],例如:

c
SND_SOC_DAPM_INPUT("LINPUT1"),
SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8960_POWER1, 5, 0,
		   wm8960_lin_boost, ARRAY_SIZE(wm8960_lin_boost)),
SND_SOC_DAPM_MIXER("Left Input Mixer", WM8960_POWER3, 5, 0,
		   wm8960_lin, ARRAY_SIZE(wm8960_lin)),
SND_SOC_DAPM_ADC("Left ADC", "Capture", WM8960_POWER1, 3, 0),
SND_SOC_DAPM_DAC("Left DAC", "Playback", WM8960_POWER2, 8, 0),
SND_SOC_DAPM_MIXER("Left Output Mixer", WM8960_POWER3, 3, 0,
		   wm8960_loutput_mixer, ARRAY_SIZE(wm8960_loutput_mixer)),
/* … PGA / OUTPUT … */

SND_SOC_DAPM_MIXER 的后两个参数是该 mixer 的开关表及其长度。

6.3 Mixer 开关:SOC_DAPM_SINGLE ​

例如输出混音与输入 Boost:

c
static const struct snd_kcontrol_new wm8960_lin_boost[] = {
	SOC_DAPM_SINGLE("LINPUT2 Switch", WM8960_LINPATH, 6, 1, 0),
	SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LINPATH, 7, 1, 0),
	SOC_DAPM_SINGLE("LINPUT1 Switch", WM8960_LINPATH, 8, 1, 0),
};

static const struct snd_kcontrol_new wm8960_loutput_mixer[] = {
	SOC_DAPM_SINGLE("PCM Playback Switch", WM8960_LOUTMIX, 8, 1, 0),
	SOC_DAPM_SINGLE("LINPUT3 Switch", WM8960_LOUTMIX, 7, 1, 0),
	SOC_DAPM_SINGLE("Boost Bypass Switch", WM8960_BYPASS1, 7, 1, 0),
};

用户态看到的长名字是 widget 名 + Mixer 开关名 拼出来的,例如:

Left Output Mixer + PCM Playback Switch
→ Left Output Mixer PCM Playback Switch(ctl 50)。

6.4 注册入口 ​

c
snd_soc_dapm_new_controls(dapm, wm8960_dapm_widgets,
			  ARRAY_SIZE(wm8960_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));

顺序上:先建 widget(含 mixer 开关),再 add_routes 把字符串表示的边挂进 DAPM 图。


7. 一个开关挂两条边 ​

录音图里 48 标在两条边上,对应源码:

c
{ "Left Input Mixer", "Boost Switch", "Left Boost Mixer" },
{ "Left Input Mixer", "Boost Switch", "LINPUT1" },  /* Really Boost Switch */

同一 Boost Switch(ctl 48)被两行 snd_soc_dapm_route 引用,一次 tinymix set 两条边一起通断。右侧 49 对 RINPUT1 / Right Boost Mixer 同理。源码注释 Really Boost Switch 标明第二行边的硬件语义仍是该 Boost 位(手册 LMIC2B)。


8. 小结 ​

  • widget = 点,path = 边,route = 图纸,DAPM kcontrol = 闸刀,complete path = 端到端通电线路。
  • 列表里约 42~57 的 BOOL 是 DAPM 路由开关;前面多为音量 / 算法类控件。
  • 播 / 录应分开看图:录音看 Boost / Input Mixer(42~49);播放看 Output Mixer 的 PCM / Bypass(50~57)。
  • 本板:耳机麦进 LINPUT1,板载麦克风进 RINPUT1/2,耳机 / 喇叭走 HP_* / SPK_*;OUT3 未外接。
  • 边在 audio_paths[](struct snd_soc_dapm_route);点在 wm8960_dapm_widgets[];开关短名在 SOC_DAPM_SINGLE 表里,经 snd_soc_dapm_add_routes 挂上。

附录 A 源码索引 ​

位置内容
sound/soc/codecs/wm8960.c — wm8960_lin_boost / wm8960_lin / wm8960_loutput_mixer 等mixer 开关短名与寄存器位
同文件 — wm8960_dapm_widgets[]DAPM 节点
同文件 — audio_paths[] / audio_paths_out3[]路由边
同文件 — wm8960_add_widgetsdapm_new_controls + dapm_add_routes
include/sound/soc-dapm.hsnd_soc_dapm_route / widget 宏
仓库 refs/datasheets/WM8960.pdf芯片手册
/files/wm8960-fig8-mic-input-pga.png手册 Figure 8 摘图

基于 VitePress 构建