3. DAPM Widget 类型:Mixer、Mux、PGA、ADC、DAC、Input、Output、Supply 等 Widget 的作用与注册方式
DAPM(Dynamic Audio Power Management)的核心抽象单元是 Widget。每个 Widget 代表音频路径中的一个功能节点,例如混音器、选择器、放大器或编解码器端点。理解每种 Widget 的语义和注册方法是进行 DAPM 路由调试的基础。
3.1 Widget 类型总览与分类
ALSA 将 Widget 分为若干标准类型,每种类型对应不同的硬件行为和路由规则。下表列出了最常用的 Widget 类型及其核心作用:
| Widget 类型 | 枚举值 | 核心作用 | 典型硬件对应 |
|---|---|---|---|
| Mixer | snd_soc_dapm_mixer |
多路输入混合为一路输出,支持独立通路开关 | 模拟混音器、多路加法器 |
| Mux | snd_soc_dapm_mux |
多路输入选择一路输出,互斥切换 | 模拟开关、输入选择器 |
| PGA | snd_soc_dapm_pga |
可编程增益放大器,支持通断和增益控制 | 前置放大器、耳机放大器 |
| ADC | snd_soc_dapm_adc |
模拟转数字,通常带时钟使能 | 音频 ADC 转换器 |
| DAC | snd_soc_dapm_dac |
数字转模拟,通常带时钟使能 | 音频 DAC 转换器 |
| Input | snd_soc_dapm_input |
外部模拟信号输入端点,无控制逻辑 | 麦克风插孔、线路输入 |
| Output | snd_soc_dapm_output |
外部模拟信号输出端点,无控制逻辑 | 耳机插孔、扬声器端子 |
| Supply | snd_soc_dapm_supply |
电源/偏置/时钟供给节点,不直接传输音频 | LDO 稳压器、PLL、参考电压 |
/sys/kernel/debug/asoc/codec_name/dapm 中查看所有已注册的 Widget 及其当前状态。Supply 类型的 Widget 不会出现在音频路径中,但会影响其他 Widget 的上电顺序。
3.2 核心 Widget 详解与注册方式
3.2.1 Mixer Widget
Mixer 是最复杂的 Widget 类型之一。它允许多个输入同时贡献到输出,每个输入通常由一个 snd_kcontrol_new 控制其通断或音量。注册时使用 SND_SOC_DAPM_MIXER 宏。
/* 定义 Mixer 的控制项 */
static const struct snd_kcontrol_new mixr_controls[] = {
SOC_DAPM_SINGLE("Line In Switch", MIXER_REG, 0, 1, 0),
SOC_DAPM_SINGLE("Mic Switch", MIXER_REG, 1, 1, 0),
};
/* 定义 Mixer Widget */
SND_SOC_DAPM_MIXER("Main Mixer", SND_SOC_NOPM, 0, 0,
mixr_controls, ARRAY_SIZE(mixr_controls))
Mixer 的路由规则:只要任意一个输入通路开启,Mixer 即处于上电状态。所有输入信号在内部叠加后从输出端送出。
3.2.2 Mux Widget
Mux 实现“多选一”的互斥切换。与 Mixer 不同,Mux 同一时刻只能有一条输入路径导通。注册使用 SND_SOC_DAPM_MUX 宏,控制项通常为枚举类型。
static const char * const mux_text[] = {"Line In", "Mic", "FM"};
static const struct soc_enum mux_enum =
SOC_ENUM_SINGLE(MUX_REG, 0, ARRAY_SIZE(mux_text), mux_text);
static const struct snd_kcontrol_new mux_control =
SOC_DAPM_ENUM("Input Select", mux_enum);
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &mux_control)
3.2.3 PGA Widget
PGA 代表可编程增益放大器。它通常具有通断控制和增益调节能力。注册使用 SND_SOC_DAPM_PGA 宏,可以指定事件回调(如启动时延迟、关闭时静音)。
SND_SOC_DAPM_PGA("Headphone PGA", PGA_POWER_REG, 0, 0, NULL, 0)
PGA 的电源状态完全由输入路径决定:当输入路径有效且 PGA 自身开关开启时,PGA 上电。如果 PGA 没有连接任何有效的输入源,DAPM 会将其关闭以节省功耗。
3.2.4 ADC 与 DAC Widget
ADC 和 DAC 是模拟域与数字域之间的桥梁。它们通常需要额外的时钟或使能信号,因此常与 Supply Widget 配合使用。注册宏分别为 SND_SOC_DAPM_ADC 和 SND_SOC_DAPM_DAC。
SND_SOC_DAPM_ADC("HiFi ADC", "Capture", ADC_POWER_REG, 0, 0)
SND_SOC_DAPM_DAC("HiFi DAC", "Playback", DAC_POWER_REG, 0, 0)
ADC/DAC 的第二个参数是 Stream Name,用于与 PCM 流绑定。当用户空间启动录音或播放时,DAPM 会自动使能对应的 ADC/DAC Widget。
3.2.5 Input 与 Output Widget
Input 和 Output 是路径的端点。它们不包含任何控制逻辑,仅作为音频信号进入或离开芯片的标记。注册宏为 SND_SOC_DAPM_INPUT 和 SND_SOC_DAPM_OUTPUT。
SND_SOC_DAPM_INPUT("Mic Jack")
SND_SOC_DAPM_OUTPUT("Speaker")
这些 Widget 始终处于“上电”状态,因为它们代表物理连接点。调试时若发现路径无法连通,检查端点名称是否与路由表中完全匹配(包括大小写)。
3.2.6 Supply Widget
Supply 是 DAPM 中特殊的“隐形”节点。它不传输音频数据,但为其他 Widget 提供电源、偏置或时钟。注册使用 SND_SOC_DAPM_SUPPLY 宏,通常带有事件回调。
SND_SOC_DAPM_SUPPLY("VREF", VREF_REG, 0, 0, vref_event,
SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
Supply 的电源管理规则:当任何依赖该 Supply 的 Widget 请求上电时,Supply 先于它们上电;当所有依赖 Widget 都下电后,Supply 才下电。这种机制保证了供电顺序的正确性。
3.3 Widget 注册的整体流程
所有 Widget 在驱动初始化时通过 snd_soc_dapm_new_controls() 批量注册。该函数接收一个 snd_soc_dapm_widget 数组,将其挂入 Codec 或 Card 的 DAPM 链表。
static const struct snd_soc_dapm_widget codec_widgets[] = {
SND_SOC_DAPM_INPUT("Mic Jack"),
SND_SOC_DAPM_MICBIAS("Mic Bias", MICBIAS_REG, 0, 0),
SND_SOC_DAPM_MUX("Input Mux", SND_SOC_NOPM, 0, 0, &mux_control),
SND_SOC_DAPM_PGA("Mic PGA", PGA_REG, 0, 0, NULL, 0),
SND_SOC_DAPM_ADC("HiFi ADC", "Capture", ADC_REG, 0, 0),
SND_SOC_DAPM_OUTPUT("Headphone"),
};
static int codec_probe(struct snd_soc_component *component) {
snd_soc_dapm_new_controls(&component->dapm, codec_widgets,
ARRAY_SIZE(codec_widgets));
/* 后续注册路由表 */
return 0;
}
3.4 Widget 类型与电源域的关系
不同类型的 Widget 对电源域的影响不同。下图展示了典型音频路径中 Widget 的电源依赖关系:
从上图可以看出:
- Supply 位于最底层,为 ADC、PGA 等提供电源基础。
- ADC/DAC 依赖 Supply,同时作为模拟域和数字域的转换边界。
- PGA 提供增益控制,通常位于 ADC 之后或 DAC 之前。
- Mux 和 Mixer 负责路径选择与混合,位于路径中间。
- Input/Output 是路径的起点和终点,不依赖其他 Widget 供电。
3.5 调试要点总结
| Widget 类型 | 调试关注点 | 常见问题 |
|---|---|---|
| Mixer | 检查各输入通路控制项是否生效 | 控制项寄存器位错误导致通路无法开启 |
| Mux | 确认枚举值与寄存器值对应关系 | 枚举文本与硬件寄存器值不匹配 |
| PGA | 检查增益寄存器范围和事件回调 | 事件回调中未正确设置寄存器 |
| ADC/DAC | 确认 Stream Name 与 PCM 流匹配 | Stream Name 拼写错误导致无法自动上电 |
| Input/Output | 验证端点名称与路由表一致 | 名称大小写或空格不匹配 |
| Supply | 检查依赖关系链是否完整 | Supply 未注册导致依赖 Widget 无法上电 |
cat /sys/kernel/debug/asoc/codec_name/dapm 查看所有 Widget 的实时电源状态。对于 Mixer 和 Mux,还可以通过 amixer 命令手动切换控制项,观察 DAPM 状态变化。