直接来自内核的\Documentation\sound\alsa\soc中dapm.txt
1.描述
音频电源动态管理(DAPM)的目的是为了在音频子系统中允许便携式的linux设备一直使用最小的电量。它独立于其它内核电源管理,因此可以很方便的和其它电源管理系统共存。
DAPM对于所有用户空间的程序也是完全透明的,因为所有的电源开关都是由ASoC core来切换的。用户空间的程序 不需要改变代码和重新编译 。DAPM使得电源开关的切换基于设备的任何的音频流(采集或回放)活动和音频混音器设置之上。
DAPM贯穿于整个machine。它覆盖整个音频子系统的电源控制,包括内部的codec电源模块和machine等级的电源系统。
DAPM中有4个电源相关的域:
1.Codec域--VREF(参考电压),VMID(core codec和音频电源)
通常在codec probe/remove和suspend/resume时被控制,因此可以在侧音不需要电源时在stream time被设置。
2.Platform/Machine 域 -- 是platform/machine和user action相关的输入输出物理连接,由machine driver配置并且响应一不事件。比如HP插入时
3.Path 域 --- 音频子系统的信号路径
当mixer和mux设置被用户改变时自动设置,比如alsamixer,amixer
4.Stream 域 -- DACs和ADCs
当回放和采集流开始或者结束时被相应的使能和禁止,比如aplay,arecord
所有DAPM电源开关的策略由整个machine的一个音频线路图自动控制。这个线路图是和每一个machine相关的,并且由所有音频部件(包括内部的codec部件)的互联系统构成。以后,所有影响电源的音频部件被叫做widget
2.DAPM 部件
DAPM音频部件分为一系列的类型:
Mixer--将一些模拟信号混合为一个单一的模拟信号
Mux--一个控制多路输入但只有一个输出的模拟开关
PGA--一个可编程的增益放大器或者衰减部件
ADC--模拟信号到数字信号转换器
DAC--数字信号到模拟信号转换器
Switch--一个模拟开关
Input--codec的一个输出接口
Output--codec的一个输入接口
Headphone--耳机(和可选的Jack)
Mic--Mic(和可选的Jack)
Line--线路输入/输出(和可选的Jack)
Speaker--扬声器
Supply--被其它部件使用的电源和时钟供应部件
Pre--特殊的前置部件(在所有其它部件前执行)
Post--特殊的后置部件(在所有其它部件后执行)
(Widgets 定义在include/sound/soc-dapm.h)
widgets经常在codec的driver和machine的driver中被添加.在soc-dapm.h中有一些很方便的宏可以用来快速的构建codecs和machines 的一系列的DAPM widgets。
大多数的widgets有一个name,register,shift,和invert。一些widgets有一些用于stream名字和kcontrols的多余的参数。
2.1 Stream Domain Widgets
-------------------------------------
Stream Widgets 和stream power domain相关并且包含ADCs和DACs。
Stream Widgets有如下的格式:
SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
注意:stream的名字必须和相应的你snd_soc_codec_dai中codec的stream name 一致
例如。用于HiFi回放和采集的stream widegets
SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1),
SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1),
2.2 Path Domain Widgets
---------------------------------
Path domain wideget 有控制和影响音频子系统中音频信号或音频路径的能力。他们有如下的格式:
SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls)
所有widget kcontrols可以用controls和num_controls 成员设置。
比如.mixer widget(首先定义kcontrols)
/*Output Mixer*/
static const snd_kcontrol_new_t wm8731_output_mixer_controls[] = {
SOC_DAPM_SINGLE("Line Bypass Switch", WM8731_APANA, 3, 1, 0),
SOC_DAPM_SINGLE("Mic Sidetone Switch", WM8731_APANA, 5, 1, 0),
SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
};
SND_SOC_DAPM_MIXER("Output Mixer", WM8731_PWR, 4, 1, wm8731_output_mixer_controls,ARRAY_SIZE(wm8731_output_mixer_controls)),
如果你不想以mixer widget的name作为mixer元素的名字前缀,你可以使用SND_SOC_DAPM_MIXER_NAMED_CTL宏代替,参数和使用SND_SOC_DAPM_MIXER一样
2.3 Platform/Machine domain Widgets
--------------------------------------------------
Machine widgets和codec widgets不同的是,它们没有codec 寄存器位。一个machine widget和每一个可以被独立的供电的machine音频控件相关(非codec),例如
--扬声器放大器
--Microphone Bias
--Jack 连接器
一个machine widget可以有一个可选的回调函数。
例如,对于一个外部的Mic,Jack connector widget在mic插入的时候使能Mic Bias
static int spitz_mic_bias(struct snd_soc_dapm_widget* w, int event)
{
gpio_set_value(SPITZ_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event));
return 0;
}
SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
2.4 Codec Domain
------------------------
codec power domain 没有widgets,它被codec DAPM时间处理函数处理。这个处理函数在codec 的powerstate被任何stream event或内核PM 事件改变时调用。
2.5 Virtual Widgets
------------------------
一些widgets存在于没有任何相应软件电源控制的codec或者machine音频位图。这种情况下需要创建一个虚拟的widget---一个没有控制bits的widget。例如
SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
这可以被用于在软件上合并signal paths在一起。
在所有的widget被定义之后,他们可以通过调用snd_soc_dapm_new_control()被独立的添加到DAPM子系统。
3.Codec Widget Interconnections(相互连接)
=================================
Widgets在codec和machine上通过audio paths相互连接。每一个连接必须被定义以便在widgets间创建一个所有
音频路径的map
建立codec或者machine音频系统的是很简单的,这是因为它需要通过他们的音频信号路径 把widget组合在一起
e.g., from the WM8731 output mixer (wm8731.c)
WM8731输出mixer有3个输入(源)
1. Line Bypass Input--------------------线路旁路输入
2. DAC (HiFi playback)-----------------DAC(HiFi 回放)
3. Mic Sidetone Input-------------------Mic 侧音输入
这个例子中每一个输入都有一个与之相关的kcontrol(在上面定义)并且通过kcontrol name和输出mixer相连。我们现在可以和用它们的源widgets和destination widget(wrt 音频信号)来连接 /* 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
或者: Sink, Path, Source
或者: "Output Mixer" 通过"HiFi Playback Switch"和"DAC"连接
当没有path name和widgets(比如一个直接的连接)相连接时,我们使用NULL作为path name 通过下列函数来创建连接 snd_soc_dapm_connect_input(codec, sink, path, source);
最后,当所有的widgets和连接已经呗注册进内核时我们应当调用snd_soc_dapm_new_widgets(codec) 这会使得内核遍历codec和machine,因此内部的DAPM状态会和物理的machine状态匹配
3.1 Machine Widget Interconnections
-------------------------------------------------
machine widget的连接创建方式和codec一样,并且直接将codec的pins连接到machine level 的 widgets 例如。连接speaker 输出编码pins到内部的speaker
/*ext speaker 连接到codec pins LOUT2,ROUT2*/
{"Ext Spk", NULL , "ROUT2"},
{"Ext Spk", NULL , "LOUT2"},
这样会让DAPM为已经连接的pin和独立NC的pin上电和关闭
4 Endpoint Widgets
===================
一个endpoint是machine内部一个音频信号的开始或者结束点(widget)并且包含codec。例如
o Headphone Jack
o Internal Speaker
o Internal Mic
o Mic Jack
o Codec Pins
当一个codec pin 为NC时,它可以通过如下的函数来标记为没有使用 snd_soc_dapm_set_endpoint(codec, "Widget Name", 0); 最后一个参数是0时为inactive,是1时为active.这样这个pin和它的输入widget不会上电 也不会耗费电量
5 DAPM Widget Events
====================
一些widgets可以在PM事件的DAPM core中注册他们的偏好。 比如.一个有放大器的Speaker注册一个widget这样amplifier可以在speaker使用 的时候才上电
/*打开和关闭amplifier 使用如下的函数*/
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;
}
/*相应的machine dapm widgets */
static const struct snd_soc_dapm_widget wm8731_dapm_widgets =
SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event);
请在soc-dapm.h中查看支持events的所有widgets
5.1 Event types
---------------------
evevt widgets支持如下的event 类型
/* dapm event types */
#define SND_SOC_DAPM_PRE_PMU 0x1 /* before widget power up */
#define SND_SOC_DAPM_POST_PMU 0x2 /* after widget power up */
#define SND_SOC_DAPM_PRE_PMD 0x4 /* before widget power down */
#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */