DAPM实战应用

现在来实际应用一下DAPM(在ASoC-codec层进行操作),先展示一下效果:

可以看到上面主要包括了三大类型:

1.音量控制

2.Lineout开关

3.DAC-Mixer的通路开关

第一类-带增益音量控制(tlv)

设置好tlv

static const DECLARE_TLV_DB_SCALE(digital_tlv, 0, -96, -5478);
static const unsigned int lineout_tlv[] = {
		TLV_DB_RANGE_HEAD(2),
		0, 0, TLV_DB_SCALE_ITEM(0, 0, 1),
		1, 31, TLV_DB_SCALE_ITEM(-2460, 120, 1),
};

创建control

struct snd_kcontrol_new codec_controls[] = {
		SOC_SINGLE_TLV("digital volume", DAC_DPC, DVOL, 0x4E, 1, digital_tlv),
		SOC_SINGLE_TLV("lineout volume", DAC_REG, LINEOUT_VOL, 0x2A, 0, lineout_tlv),
};

注:SOC_SINGLE_TLV是用来设置名字、寄存器、便宜、最大值、mute以及tlv的

注册(在platform_driver的probe函数)

ret = snd_soc_add_component_controls(component, codec_controls,
					ARRAY_SIZE(codec_controls));

第二类-Lineout开关

带三类-DAC-Mixer的通路开关

这两类一起介绍,因为它们都涉及到了control之间的连接,需要使用到widget

创建Mixer控件

static const struct snd_kcontrol_new left_output_mixer[] = {
		SOC_DAPM_SINGLE("DACL Switch", MIXER_REG, LMIX_LDAC, 1, 0),
		SOC_DAPM_SINGLE("DACR Switch", MIXER_REG, LMIX_RDAC, 1, 0),
};
static const struct snd_kcontrol_new right_output_mixer[] = {
		SOC_DAPM_SINGLE("DACL Switch", MIXER_REG, RMIX_LDAC, 1, 0),
		SOC_DAPM_SINGLE("DACR Switch", MIXER_REG, RMIX_RDAC, 1, 0),
};

创建widget

static const struct snd_soc_dapm_widget codec_dapm_widgets[] = {
		/* 定义音频输入接口作为通路的起点 */
		SND_SOC_DAPM_AIF_IN_E("DACL", "Playback", 0, DAC_REG, DACLEN, 0,
			      codec_playback_event,
			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
		SND_SOC_DAPM_AIF_IN_E("DACR", "Playback", 0, DAC_REG, DACREN, 0,
			      codec_playback_event,
			      SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
		/* 定义widget-mixer */
		SND_SOC_DAPM_MIXER("OutputL Mixer", MIXER_REG, LMIXEN, 0,
			   left_output_mixer, ARRAY_SIZE(left_output_mixer)),
		SND_SOC_DAPM_MIXER("OutputR Mixer", MIXER_REG, RMIXEN, 0,
			   right_output_mixer, ARRAY_SIZE(right_output_mixer)),
		/* 定义输出引脚,作为通路终点 */
		SND_SOC_DAPM_OUTPUT("LINEOUTL"),
		SND_SOC_DAPM_OUTPUT("LINEOUTR"),
		/* 作为通路的线路输入 */
		SND_SOC_DAPM_LINE("LINEOUT", lineout_event),
};

这里涉及到了事件event,也就是自己可以定义一个函数,让它在上电前、后或断电前、后执行,一般就是用于控制对应的寄存器

event的原型

static int lineout_event(struct snd_soc_dapm_widget *w,
					struct snd_kcontrol *k, int event)

执行时机可以在事件函数里面用switch简单地判断

switch (event) {
case:
		...
}

既然设计到了音频通路的连接,那么接下来则需要创建通路

创建route

static const struct snd_soc_dapm_route codec_dapm_routes[] = {
		/* 设置DAC和mixer直接的通路 */
		{"OutputL Mixer", "DACR Switch", "DACR"},
		{"OutputL Mixer", "DACL Switch", "DACL"},
		{"OutputR Mixer", "DACL Switch", "DACL"},
		{"OutputR Mixer", "DACR Switch", "DACR"},
		/* 让mixer和输出端点直连 */
		{"LINEOUTL", NULL, "OutputL Mixer"},
		{"LINEOUTR", NULL, "OutputR Mixer"},
};

添加widget和route(在platform_driver的probe函数)

ret = snd_soc_dapm_new_controls(dapm, codec_dapm_widgets,
					ARRAY_SIZE(codec_dapm_widgets));
ret = snd_soc_dapm_add_routes(dapm, codec_dapm_routes,
					ARRAY_SIZE(codec_dapm_routes));

猜你喜欢

转载自blog.csdn.net/hhx123456798/article/details/123319155