目录
零、本文主要内容
一、DAPM的作用
二、内核文档解读
2.1 Description
2.2 DAPM Widgets
2.2.1 Stream Domain Widgets
2.2.2 Path Domain Widgets
2.2.3 Machine domain Widgets
2.2.4 Codec (BIAS) Domain
2.2.5 一种虚拟的控制方式--Virtual Widgets
2.3 Codec/DSP Widget Interconnections
2.3.1 Machine Widget Interconnections
2.4 Endpoint Widgets
2.5 DAPM Widget Events
三、总结几个重要的知识点
零、本文主要内容
一、DAPM的作用
- 自动化使能与失能路径:这是DAPM比较kcontrol引入的最大特征。我们知道对于外设,上电和下电的顺序很重要,不恰当的顺序容易引起pop音,如果全部硬件都抽象成kcontrol,那么你就需要手动的安排一下上电或者下电的顺序,但是如果定义成DAPM类型,那么系统会帮你按照一定的顺序进行上下电。
- 对用户层透明:DAPM和kcontrol都有的作用,对寄存器等操作进行封装,从而在用户层使用更方便,用户无须了解外设如何控制,只需要执行对应的命令,底层就会配置好外设
- 独立性:DAPM和kcontrol都有的作用,其在内核中拥有属于自己的一套电源管理系统,不会与其他电源管理系统冲突
二、内核文档解读
- Description:基本描述与power domains的划分
- DAPM Widgets:DAPM Widgets种类的划分、以及各个domains与DAPM Widgets的关系
- Codec/DSP Widget Interconnections:Widget如何进行连接,也就是route的相关内容
- Endpoint Widgets:端点widget,介绍端点widget的种类,这个端点widget决定一条route是否完整,route两端都是端点widget才能自动上电,这也是自动化上下电的前提
- DAPM Widget Events:个别widget支持对特定事件进行处理
/linux-5.15.164/include/sound/soc-dapm.h
2.1 Description
Dynamic Audio Power Management (DAPM) is designed to allow portable Linux devices to use the minimum amount of power within the audio subsystem at all times. It is independent of other kernel PM and as such, can easily co-exist with the other PM systems.
DAPM is also completely transparent to all user space applications as all power switching is done within the ASoC core. No code changes or recompiling are required for user space applications. DAPM makes power switching decisions based upon any audio stream (capture/playback) activity and audio mixer settings within the device.
DAPM spans the whole machine. It covers power control within the entire audio subsystem, this includes internal codec power blocks and machine level power systems.
Codec Bias domain:管理核心编解码器电源 (VREF/VMID),通常在编解码器挂载或挂载移除时处理。
Platform/Machine domain:控制物理输入输出,比如耳机插拔事件。
Path domain:与音频信号路径相关,用户通过混音器配置(如 alsamixer)触发。
Stream domain:控制音频流的启停。也就是ADC跟DAC,对应录音与播放。例如 aplay、arecord。
2.2 DAPM Widgets
组件 | 描述 | DAPM Widget具体含义 |
Mixer | 混合多个模拟信号为一个单一模拟信号 | 用于将多个音频信号组合成一个输出信号,通常用于音量控制或音频混音。 |
Mux | 模拟开关,输出多个输入中的一个 | 允许选择多个输入信号中的一个进行传输,可以用于不同音频源的切换。 |
PGA | 可编程增益放大器或衰减控件 | 用于调节音频信号的增益或衰减,可以动态调整音量。 |
ADC | 模拟到数字转换器 | 将模拟信号转换为数字信号,通常用于将模拟音频输入转换为数字格式。 |
DAC | 数字到模拟转换器 | 将数字信号转换为模拟信号,用于将数字音频输出转换为模拟输出。 |
Switch | 模拟开关 | 控制音频信号的传输或切换,通常在信号路径中切换不同的信号源。 |
Input | 编解码器输入引脚 | 音频输入引脚,用于接收外部信号到编解码器。 |
Output | 编解码器输出引脚 | 音频输出引脚,用于输出编解码器的音频信号。 |
Headphone | 耳机(和可选插孔) | 用于连接耳机输出或耳机插孔,通常是音频输出的最后一步。 |
Mic | 麦克风(和可选插孔) | 用于连接麦克风输入或麦克风插孔,捕捉外部声音信号。 |
Line | 线路输入/输出(和可选插孔) | 用于接收或发送线路音频信号,可以是音频源或音频输出设备。 |
Speaker | 扬声器 | 用于将音频信号转换为声波输出的硬件设备。 |
Supply | 其他控件使用的电源或时钟供给控件 | 提供所需电力或时钟信号给其他控件,如DAC、ADC等。 |
Regulator | 为音频组件提供电力的外部调节器 | 外部电源调节器,提供稳定的电压和电流供应,确保音频组件正常运行。 |
Clock | 为音频组件提供时钟的外部时钟 | 提供稳定的时钟信号,确保音频数据的同步传输。 |
AIF IN | 音频接口输入(带TDM槽掩码) | 音频接口输入控件,用于接收通过TDM协议传输的音频数据。 |
AIF OUT | 音频接口输出(带TDM槽掩码) | 音频接口输出控件,用于发送通过TDM协议传输的音频数据。 |
Siggen | 信号发生器 | 用于生成特定频率或幅度的测试音频信号,通常用于音频设备的调试。 |
DAI IN | 数字音频接口输入 | 数字音频输入控件,用于接收数字音频数据。 |
DAI OUT | 数字音频接口输出 | 数字音频输出控件,用于发送数字音频数据。 |
DAI Link | 两个DAI结构之间的DAI链路 | 在两个数字音频接口之间建立连接,通常用于实现音频传输。 |
Pre | 特殊的PRE控件(在其他控件之前执行) | 特殊类型控件,用于在其他控件之前执行初始化或前置处理。 |
Post | 特殊的POST控件(在其他控件之后执行) | 特殊类型控件,用于在其他控件之后执行后置处理或清理工作。 |
Buffer | DSP中的组件间音频数据缓冲区 | 用于在DSP内部存储音频数据,在多个组件之间传递音频数据。 |
Scheduler | DSP内部调度器,负责调度组件/处理流水线工作 | 控制DSP内部任务的执行顺序,确保音频处理任务按顺序执行。 |
Effect | 执行音频处理效果的控件 | 用于执行音频效果处理,如回声、混响、均衡等。 |
SRC | DSP或编解码器内的采样率转换器 | 用于转换音频信号的采样率,通常用于不同采样率之间的信号适配。 |
ASRC | DSP或编解码器内的异步采样率转换器 | 用于异步转换采样率,能够处理源信号和目标信号不同步的情况。 |
Encoder | 将音频数据从一种格式(通常为PCM)编码为另一种通常为压缩格式的控件 | 对音频数据进行编码处理,将其转换为压缩格式以减小数据大小。 |
Decoder | 将音频数据从压缩格式解码为未压缩格式(如PCM)的控件 | 对压缩格式的音频数据进行解码处理,恢复为标准未压缩格式(如PCM)。 |
2.2.1 Stream Domain Widgets
- ADC (Analog-to-Digital Converter):模拟到数字的转换器,用于将模拟音频信号转换为数字信号。
- DAC (Digital-to-Analog Converter):数字到模拟的转换器,用于将数字音频信号转换为模拟信号。
- AIF IN:音频接口输入,通常用于数字音频输入(如 TDM、I2S)。
- AIF OUT:音频接口输出,用于数字音频输出。
/linux-5.15.164/include/sound/soc-dapm.h
219行 /* stream domain */
2.2.2 Path Domain Widgets
/linux-5.15.164/include/sound/soc-dapm.h
82行 /* path domain */
- 第一种:PGA,也就是增益放大器,通常用于调节信号的增益或衰减,比如:
#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert, wcontrols, wncontrols)
#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert, wcontrols)
#define SND_SOC_DAPM_PGA_E(wname, wreg, wshift, winvert, wcontrols, wncontrols, wevent, wflags)
#define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, wevent, wflags)
- 第二种:Mixer,也就是混音器,用于将多个音频输入信号混合成一个输出信号,它能够控制每个输入信号的音量或开关状态。比如:
#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, wcontrols, wncontrols)
#define SND_SOC_DAPM_MIXER_NAMED_CTL(wname, wreg, wshift, winvert, wcontrols, wncontrols)
#define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, wcontrols)
#define SOC_MIXER_NAMED_CTL_ARRAY(wname, wreg, wshift, winvert, wcontrols)
#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, wncontrols, wevent, wflags)
- 第三种,Output Driver,也就是输出驱动,通常用于提供最终输出的信号,它可以驱动扬声器或其他音频输出设备,例如用在DAC后边增强DAC的输出,代码:
#define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert, wcontrols, wncontrols)
#define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, wncontrols, wevent, wflags)
- 第四种,Switch,也就是开关,控制音频路径的开关状态,比如:
#define SND_SOC_DAPM_SWITCH(wname, wreg, wshift, winvert, wcontrols)
#define SND_SOC_DAPM_SWITCH_E(wname, wreg, wshift, winvert, wcontrols, wevent, wflags)
- 第五种,Mux,复用器,用于选择不同的信号源,通常用于多个输入之间的选择。比如:
#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols)
#define SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, wevent, wflags)
2.2.3 Machine domain Widgets
- Speaker Amp:扬声器放大器
- Microphone Bias:麦克风偏差
- Jack connectors:插孔连接器
2.2.4 Codec (BIAS) Domain
- 当 codec 的电源状态(power state)发生变化时,特别是与音频流(stream)事件相关时。
- 当内核的电源管理(PM)事件触发时。
2.2.5 一种虚拟的控制方式--Virtual Widgets
SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
2.3 Codec/DSP Widget Interconnections
Widgets are connected to each other within the codec, platform and machine by audio paths (called interconnections).
Each interconnection must be defined in order to create a map of all audio paths between widgets.
This is easiest with a diagram of the codec or DSP (and schematic of the machine audio system),
as it requires joining widgets together via their audio signal paths.
- Widgets 通过音频路径连接在一起,这些路径(audio paths)称为互联(Interconnections),它们定义了音频信号如何从一个widgets传递到另一个widgets。
- with a diagram of the codec or DSP (and schematic of the machine audio system)
/* output mixer */
{"Output Mixer", "Line Bypass Switch", "Line Input"},
{"Output Mixer", "HiFi Playback Switch", "DAC"},
{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
Destination Widget <=== Path Name <=== Source Widget
- 连接的方式:snd_soc_dapm_connect_input(codec, sink, path, source);
- 注册的方式:snd_soc_dapm_new_widgets(codec)
2.3.1 Machine Widget Interconnections
2.4 Endpoint Widgets
- Headphone Jack 耳机插孔
- Internal Speaker 内置扬声器
- Internal Mic 内置麦克风
- Mic Jack 麦克风插孔
- Codec Pins 编解码器引脚
/linux-5.15.164/sound/soc/soc-dapm.c
3618 struct snd_soc_dapm_widget *
3619 snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm,
3620 const struct snd_soc_dapm_widget *widget)
- w->is_ep:通过设置此属性来标识端点类型。端点可以是源(Source)或接收端(Sink)。定义如下:
#define SND_SOC_DAPM_EP_SOURCE SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_IN)
#define SND_SOC_DAPM_EP_SINK SND_SOC_DAPM_DIR_TO_EP(SND_SOC_DAPM_DIR_OUT)
Widget ID
|
Widget Name
|
Endpoint Type
|
Description
|
snd_soc_dapm_mic
|
Microphone
|
SND_SOC_DAPM_EP_SOURCE
|
输入端点,作为音频信号源。
|
snd_soc_dapm_input
|
Input
|
SND_SOC_DAPM_EP_SOURCE
|
输入端点,作为音频信号源。
|
snd_soc_dapm_spk
|
Speaker
|
SND_SOC_DAPM_EP_SINK
|
输出端点,作为音频信号接收端。
|
snd_soc_dapm_hp
|
Headphone
|
SND_SOC_DAPM_EP_SINK
|
输出端点,作为音频信号接收端。
|
snd_soc_dapm_output
|
Output
|
SND_SOC_DAPM_EP_SINK
|
输出端点,作为音频信号接收端。
|
snd_soc_dapm_vmid
|
Virtual Midrail
|
SND_SOC_DAPM_EP_SOURCE
|
输入端点,作为音频信号源。
|
snd_soc_dapm_siggen
|
Signal Generator
|
SND_SOC_DAPM_EP_SOURCE
|
输入端点,作为音频信号源。
|
snd_soc_dapm_sink
|
Sink
|
SND_SOC_DAPM_EP_SINK
|
输出端点,作为音频信号接收端。
|
2.5 DAPM Widget Events
- SND_SOC_DAPM_PRE_PMU (0x1): 在 widget 电源打开之前触发。
- SND_SOC_DAPM_POST_PMU (0x2): 在 widget 电源打开之后触发。
- SND_SOC_DAPM_PRE_PMD (0x4): 在 widget 电源关闭之前触发。
- SND_SOC_DAPM_POST_PMD (0x8): 在 widget 电源关闭之后触发。
- SND_SOC_DAPM_PRE_REG (0x10): 在音频路径设置之前触发。
- SND_SOC_DAPM_POST_REG (0x20): 在音频路径设置之后触发。
/* turn speaker amplifier on/off depending on use */
static int corgi_amp_event(struct snd_soc_dapm_widget *w, int event)
{
gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event));
return 0;
}
/* corgi machine dapm widgets */
static const struct snd_soc_dapm_widget wm8731_dapm_widgets =
SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event);
- event 参数是传递的事件类型,SND_SOC_DAPM_EVENT_ON(event) 是用来判断事件类型是否要求设备打开(或关闭)。
- gpio_set_value(CORGI_GPIO_APM_ON, ...) 是控制GPIO引脚的函数,开关扬声器功放。CORGI_GPIO_APM_ON 是控制扬声器功放电源的GPIO引脚。
三、总结几个重要的知识点
- DAPM和kcontrol的关系
- DAPM的种类
- 如何实现自动使能/失能通路
- DAPM提供哪些扩展功能