动态音频电源管理(DAPM)用来使得任何时候便携Linux设备都最小化音
频子系统的功耗,而且它独立于其它内核电源管理,容易与其他电源管理系统模块共存。
dapm的切换根据设备内的音频流活动(捕获/回放)和混音器设置来决定的。
它是独立于其他内核PM,因此,可以很方便地共同存在与其他的PM系统。
DAPM对所有的用户空间应用程序是完全透明的,在ASOC的核心完成所有的电源切换。
对用户空间应用程序不需任何代码更改或重新编译。
DAPM切换电源的依据是设备内的任何音频流(捕捉/回放)活动和音频混频器设置
DAPM跨越整个机器。它覆盖了整个音频子系统的电源控制,这包括内部编解码器的电源模块和计算机级别的电源系统。
DAPM有4个电源范围域
1.域编解码器 - VREF,VMID(核心编解码器和音频功率)
通常控制在编解码器探测/删除,休眠/唤醒,如果电源不为侧音虽然可以设置在流时间控制
2.平台/机器域 - 平台/计算机和用户的具体行动是物理连接的输入和输出,
配置是由机器驱动程序,响应由异步事件做出。e.g当耳机插入
3.路径域 - 当混频器和MUX设置由用户更改,音频子系统信号路径自动设置。
例如命令alsamixer,amixer。
4. 流域 - 当流播放/捕获分别开始和停止,启用和禁用DAC和ADC。例如aplay,的arecord。
通过咨询整机的音频路由映射所有的DAPM电源会自动切换。
这张地图具体到每一台机器,且连接每个音频组件(包括内部的编解码器组件)之间的互联。
所有影响电源的音频组件叫作widgets
2. DAPM Widgets ===============
音频DAPM部件分为很多类型:
o Mixer - 几个模拟信号混合成一个单一的模拟信号. o Mux
一个模拟开关仅输出所有输入中的一个
o PGA - 一个可编程增益放大器或衰减widget.
o ADC - 模数转换器
o DAC - 数模转换器
o Switch - 模拟开关
o Input - 编解码器输入引脚
o Output - 编解码器输出引脚
o Headphone - Headphone (and optional Jack)
o Mic - Mic (and optional Jack)
o Line - Line Input/Output (and optional Jack)
o Speaker - Speaker
o Supply - 其他小部件所使用的电源或时钟供应部件.
o Pre - 特别前部件(所有其他EXEC之前)
o Post - 特别的后部件(其他EXEC之后)
(Widgets是定义在include /sound/ SOC dapm.h)
WIDGETS通常添加在编解码器驱动程序和机器的驱动程序。有很方便的宏在SoC-dapm.h定义,
可用于快速构建的编解码器和机器DAPM部件的部件列表。
大多数部件有一个名称,注册,移位和翻转。对流的名字和kcontrols有些部件有额外的参数。
2.1流域WIDGETS
流widgets涉及到流电源域只包含的ADC(模数转换器)和DAC(数模转换器)。
流部件有以下格式
SND_SOC_DAPM_DAC(name, stream name, reg, shift, invert),
注:流的名称必须符合相应的流的名字,在你的解码器snd_soc_codec_dai。
e.g. stream widgets for HiFi playback and capture
SND_SOC_DAPM_DAC("HiFi DAC", "HiFi Playback", REG, 3, 1),
SND_SOC_DAPM_ADC("HiFi ADC", "HiFi Capture", REG, 2, 1),
2.2路径域widgets
在音频子系统内,路径域widgets有能力控制或影响音频信号或音频路径。他们有以下形式:
SND_SOC_DAPM_PGA(name, reg, shift, invert, controls, num_controls)
任何部件kcontrols可以设置使用的control和num_controls成员。
e.g. Mixer widget (the kcontrols are declared first)
/* 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)),
如果你不想要的混频器与混频器部件的名称前缀的元素,
您可以使用SND_SOC_DAPM_MIXER_NAMED_CTL代替。
与SND_SOC_DAPM_MIXER相同的参数。
2.3平台/机器域widgets
机器widgets与编解码器widgets不同,他们没有与之相关的编解码器的寄存器位。
一台机器widget 被分配到每一台机器的音频组件(非编解码器),可以独立供电。
e.g.
o Speaker Amp
o Microphone Bias
o Jack connectors
一个机器widget可以有一个可选的回调。
e.g.
接头widget能为麦克风使能麦克风偏置,当有外部麦克风插入时。
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编解码器域
编解码器的电源域没有widgets,通过DAPM的事件处理程序处理。
调用此处理函数,当编解码器的电源状态改变WRT任何流事件或内核PM事件。
2.5虚拟widgets
有时音频编解码器或机地图存在一些widgets,没有任何相应的软件电源控制。
在这种情况下,有必要建立一个虚拟的widget - 没有控制位的widget ,
如:
SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_DAPM_NOPM, 0, 0, NULL, 0),
软件可以用来合并信号路径。
所有的部件已经确定后,然后,他们可以通过调用snd_soc_dapm_new_control()单独添加到DAPM子系统。
3.编解码器部件互连
在编解码器和机器,Widgets通过音频路径相互连接。
每个互连必须定义, 为了创造一个所有的音频小部件之间路径图。
这是最简单的编解码器(机器音频系统的原理图)用图。
因为它需要通过其音频信号路径一起加入widgets 。
例如,从WM8731输出的混音器(wm8731.c)
1. Line Bypass Input
2. DAC (HiFi playback)
3. Mic Sidetone Input
在这个例子中每个输入与它相关联的kcontrol(在上面的例子定义),
通过其kcontrol名称连接到输出混音器。
现在,我们可以连接目标widget(WRT音频信号)的源widgets。
/* output mixer */
{"Output Mixer", "Line Bypass Switch", "Line Input"},
{"Output Mixer", "HiFi Playback Switch", "DAC"},
{"Output Mixer", "Mic Sidetone Switch", "Mic Bias"},
So we have :-
Destination Widget <=== Path Name <=== Source Widget
Or:-
Sink, Path, Source
Or :-
"Output Mixer" is connected to the "DAC" via the "HiFi Playback Switch".
当没有路径名,连接部件(例如,直接连接),我们通过路径名NULL。
一个调用互连创建:
snd_soc_dapm_connect_input(codec, sink, path, source);
最后,在所有的widgets 和互连已注册的核心后,snd_soc_dapm_new_widgets(codec)必须被调用后。
这将导致核心扫描编解码器和机器,使内部的DAPM状态去匹配机器的物理状态。
3.1机器部件互连
-----------------------------------
机器widget 互连创建与codec的直接连接codec引脚到机器级别的widgets方式相同 。
例如codec扬声器输出引脚连接到内部扬声器。
/ *分机扬声器连接到codec引脚LOUT2,ROUT2* /
{"Ext Spk", NULL , "ROUT2"},
{"Ext Spk", NULL , "LOUT2"},
这允许DAPM电源打开或关闭连接(在使用)的引脚和分别未连接的引脚。
4.端点widgets
端点是整个机器(包括解码器)音频信号的起点或者终点
例如:
o Headphone Jack
o Internal Speaker
o Internal Mic
o Mic Jack
o Codec Pins
当一个编解码器引脚是NC,它可以被标记为不可用一个调用
snd_soc_dapm_set_endpoint(codec, "Widget Name", 0);
最后一个参数是0表示不活跃和是1表示活跃。这种方式将导致引脚和输入部件绝不会被供电和消耗功率。
这也适用于机器部件。
eg.
如果耳机连接到插孔,然后插孔可标记为活动。
如果耳机被移除,那么耳机插孔可以被标记为非活动。
5 DAPM构件事件
有些部件可以以PM的事件的方式注册到DAPM核心。
e.g.
扬声器放大器注册一个部件,只有当SPK在使用,放大器才被供电。
/*根据使用情况开启/关闭扬声器放大器* /
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;
}
static const struct snd_soc_dapm_widget wm8731_dapm_widgets = SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event);
请查看SOC-dapm.h所有支持事件的其他部件。
5.1 事件类型
以下是事件部件支持的事件类型。
/* 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 */