动态音频电源管理 .

2019-07-14 00:59发布

动态音频电源管理(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 */