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)
关键区别: Mixer 允许多路同时输入(叠加),Mux 只允许一路输入(选择)。调试时若发现路径冲突,检查是否误将 Mux 当作 Mixer 使用。

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;
}
常见错误: Widget 名称必须全局唯一(在同一 Codec 或 Card 内)。重复名称会导致注册失败或路由混乱。建议使用“功能_位置”的命名规范,如 “Main Mixer”、“HP Amp”。

3.4 Widget 类型与电源域的关系

不同类型的 Widget 对电源域的影响不同。下图展示了典型音频路径中 Widget 的电源依赖关系:

Widget 类型与电源域依赖关系 Supply: VREF / PLL ADC: HiFi ADC PGA: Mic PGA Mux: Input Mux Mixer: Main Mixer 电源传播规则 Supply 先于所有依赖节点上电 Mixer 只要一路输入开启即上电 Mux 只有选中路径生效

从上图可以看出:

  • 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 状态变化。