转载请标注原文地址:http://blog.csdn.net/uranus_wm/article/details/12855325
前三篇文章对录音的大体流程介绍了下
这篇文章讲一下codec内部的dapm配置
dapm的全称:dynamic audio power managment
还是先看张图:
这幅图是codec内部ctrl连接关系的一张示意图,当然实际的codec内部连接更加灵活,这里只是大致列出了其中一些走向关系
所谓dapm其实就是管理配置这些内部控制器,如mixer,muxer,gpa,micbias等,以实现音频通路和音量的切换以及电源管理
在codec probe的时候会向snd_soc注册一些dapm control
其中某些control以:{目标,控制,源}的形式出现
这类control形成了一条简单路径关系,“源”通过“控制”到达“目标”
这个“控制”通常类型是“MIXER”或者“MUXER”
他们通常是多条路径route的控制点
“MIXER”指多输入一输出,多输入可以同时有效
“MUXER”指多输入一输出,只能选择一路输入有效
由此简单路径我们构成一条从mic输入到speaker输出的完整路径
也可以是从mic输入到aif1输出的完整路径,这就是我们录音的dapm route
同时每一个“控制”都会对应其相应的寄存器配置,如下面的SOC_DAPM_SINGLE申明
static int wm8994_codec_probe(struct snd_soc_codec *codec) { struct wm8994 *control; struct wm8994_priv *wm8994; struct snd_soc_dapm_context *dapm = &codec->dapm; wm_hubs_add_analogue_controls(codec); snd_soc_add_controls(codec, wm8994_snd_controls, ARRAY_SIZE(wm8994_snd_controls)); snd_soc_dapm_new_controls(dapm, wm8994_dapm_widgets, ARRAY_SIZE(wm8994_dapm_widgets)); } struct snd_soc_dapm_route { const char *sink; const char *control; const char *source; /* Note: currently only supported for links where source is a supply */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); }; static const struct snd_soc_dapm_route wm8994_lateclk_revd_intercon[] = { { "DAC1L", NULL, "Late DAC1L Enable PGA" }, { "Late DAC1L Enable PGA", NULL, "DAC1L Mixer" }, { "DAC1R", NULL, "Late DAC1R Enable PGA" }, { "Late DAC1R Enable PGA", NULL, "DAC1R Mixer" }, { "DAC2L", NULL, "Late DAC2L Enable PGA" }, { "Late DAC2L Enable PGA", NULL, "AIF2DAC2L Mixer" }, { "DAC2R", NULL, "Late DAC2R Enable PGA" }, { "Late DAC2R Enable PGA", NULL, "AIF2DAC2R Mixer" }, { "AIF2ADCL", NULL, "Late DAC2L Enable PGA" }, //wangmeng,20130625 { "AIF2ADCR", NULL, "Late DAC2R Enable PGA"} //wangmeng,20130625 static const struct snd_soc_dapm_route intercon[] = { { "CLK_SYS", NULL, "AIF1CLK", check_clk_sys }, { "CLK_SYS", NULL, "AIF2CLK", check_clk_sys }, /* DAC2/AIF2 outputs */ { "AIF2ADCL", NULL, "AIF2DAC2L Mixer" }, { "AIF2DAC2L Mixer", "AIF2 Switch", "AIF2DACL" }, { "AIF2DAC2L Mixer", "AIF1.2 Switch", "AIF1DAC2L" }, { "AIF2DAC2L Mixer", "AIF1.1 Switch", "AIF1DAC1L" }, { "AIF2DAC2L Mixer", "Left Sidetone Switch", "Left Sidetone" }, { "AIF2DAC2L Mixer", "Right Sidetone Switch", "Right Sidetone" }, { "AIF2ADCR", NULL, "AIF2DAC2R Mixer" }, { "AIF2DAC2R Mixer", "AIF2 Switch", "AIF2DACR" }, { "AIF2DAC2R Mixer", "AIF1.2 Switch", "AIF1DAC2R" }, { "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, { "AIF2DAC2R Mixer", "Left Sidetone Switch", "Left Sidetone" }, { "AIF2DAC2R Mixer", "Right Sidetone Switch", "Right Sidetone" }, } SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, aif2dac2r_mix, ARRAY_SIZE(aif2dac2r_mix)), static const struct snd_kcontrol_new aif2dac2r_mix[] = { SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, 5, 1, 0), SOC_DAPM_SINGLE("Left Sidetone Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, 4, 1, 0), SOC_DAPM_SINGLE("AIF2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, 2, 1, 0), SOC_DAPM_SINGLE("AIF1.2 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, 1, 1, 0), SOC_DAPM_SINGLE("AIF1.1 Switch", WM8994_DAC2_RIGHT_MIXER_ROUTING, 0, 1, 0), };
上面的代码片段我们可以发现找到这样一条route:
{ "AIF2DAC2R Mixer", "AIF1.1 Switch", "AIF1DAC1R" }, { "Late DAC2R Enable PGA", NULL, "AIF2DAC2R Mixer" },
“AIF1DAC1R”通过“AIF1.1 Switch”到达“AIF2DAC2R Mixer”再通过“NULL”到达“Late DAC2R Enable PGA”
这里“NULL”表示无条件到达,说明其内部是直接相连的
下面这段是录音时从main mic输入(IN1LN-IN1LP差分输入)到aif1输出的配置表
实际操作时,通常将“源”省略
const AudioMixer device_input_Main_Mic[] = { #if defined (USES_I2S_AUDIO) || defined (USES_PCM_AUDIO) //Main_MIC(IN1L N_VMID) to MIXIN to ADC to DAC2 Mixer to AIF2(ADCDAT2) //Main_MIC(IN1L N_VMID) to MIXINL {"IN1L PGA IN1LN Switch", 1}, //OFF,IN1LN {"IN1L PGA IN1LP Switch", 1}, //VMID,IN1LP {"IN1L Switch", 1}, //[0..1]:[MUTE..UNMUTE] ,0018h:b7 {"IN1L Volume", 12}, //[1..31]:[-16.5db..+30db],0018h {"MIXINL IN1L Switch", 1}, {"MIXINL IN1L Volume",1}, //[0..1]:[0db..+30db]],0029h /*ADCL to AIF1ADC*/ {"ADCL Mux", 0}, //ADC,DMIC {"AIF1ADCL Source", 0}, //Left,Right {"AIF1ADCR Source", 0}, //Left,Right {"AIF1ADC1 Volume", 119}, //[0,1..119]:[MUTE,-71.625db..+17.625db],0400h_0401h default:C0 eq 0db {"AIF1ADC1L DRC Switch",1}, {"AIF1ADC1R DRC Switch",1}, {"AIF1ADC1L Mixer ADC/DMIC Switch",1}, {"AIF1ADC1R Mixer ADC/DMIC Switch",1}, #elif defined(USES_SPDIF_AUDIO) #endif {NULL, NULL} };