asoc dapm相关

来源:互联网 发布:模具设计软件 编辑:程序博客网 时间:2024/05/22 06:56

区别常见的damp widget

MIXER

MIXER 混合器,选择哪几路,如LOUT R, 在tinymix中会长出多个和此MIXER相关的switch,可以同时打开一个多个switch。
以rt5658为例,
SND_SOC_DAPM_MIXER(“LOUT R MIX”, SND_SOC_NOPM, 0, 0, rt5658_lout_r_mix, ARRAY_SIZE(rt5658_lout_r_mix)),

static const struct snd_kcontrol_new rt5658_lout_r_mix[] = {
SOC_DAPM_SINGLE(“DAC R2 Switch”, RT5658_LOUT_MIXER,
RT5658_M_DAC_R2_LM_SFT, 1, 1),
SOC_DAPM_SINGLE(“OUTVOL R Switch”, RT5658_LOUT_MIXER,
RT5658_M_OV_R_LM_SFT, 1, 1),
};

框架图:
这里写图片描述

最终会长出如下:
45 BOOL 1 LOUT R MIX DAC R2 Switch Off
46 BOOL 1 LOUT R MIX OUTVOL R Switch Off


MUX

MUX 选择器,选择哪一路,如SPDIF MUX、PDM R MUX、PDM L MUX

SND_SOC_DAPM_MUX(“SPDIF Mux”, SND_SOC_NOPM, 0, 0, &rt5658_spdif_mux)

static const char * const rt5658_spdif_src[] = {
“IF1_DAC1”, “IF1_DAC2”, “IF2_DAC”, “IF3_DAC”
};
static const SOC_ENUM_SINGLE_DECL(
rt5658_spdif_enum, RT5658_SPDIF_CTRL,
RT5658_SPDIF_SEL_SFT, rt5658_spdif_src);
static const struct snd_kcontrol_new rt5658_spdif_mux =
SOC_DAPM_ENUM(“SPDIF Source”, rt5658_spdif_enum);

框架图:
这里写图片描述

最终会长出如下:
35 ENUM 1 SPDIF Mux IF1_DAC1


SWITCH

SWITCH 是一个开关

SND_SOC_DAPM_SWITCH(“LOUT R Playback”, SND_SOC_NOPM, 0, 0, &lout_r_switch)
static const struct snd_kcontrol_new lout_r_switch =
SOC_DAPM_SINGLE(“Switch”, RT5658_LOUT, RT5658_R_MUTE_SFT, 1, 1);

框架图:
这里写图片描述

最终长出如下:
38 BOOL 1 LOUT R Playback Switch Off

MIXER MUX SWITCH是会长出来的,另外在dapm_widget中的PGA, PGA_S, SUPPLY, SUPPLY_S, DAC, ADC, INPUT, OUTPUT, AIF_IN, AIF_OUT, MIC_BIAS是不会长出来的。


构成snd_kcontrol_new的一些宏定义

SOC_SINGLE

算是最简单的控件,这种控件只有一个控制量,比如一个开关,或者是数值的变化(比如codec中的某个频率,FIFO大小等)

#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
((unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \
.platform_max = xmax, .invert = xinvert})

#define SOC_SINGLE(xname, reg, shift, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }

定义 SOC_SINGLE_VALUE宏的目的主要是为了填充struct soc_mixer_control结构体
当上层调用info, get, put函数的时候可以将kcontrol->private_value强制转换为struct soc_mixer_control类型,然后使用这个结构体中的reg, shift, max等数据。


SOC_SINGLE_TLV

#define SOC_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }

SOC_SINGLE_TLV是SOC_SINGLE的扩展,只是比SOC_SINGLE多了tlv_array参数,主要定义那些有增益控制的kcontrol,如音量控制,EQ均衡器。

static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
SOC_SINGLE_TLV(“Mono Playback Volume”, RT5658_MONO_OUT, RT5658_L_VOL_SFT, 39, 1, out_vol_tlv)

从上面可以看出,这个Mono Playback Volume对应寄存器RT5658_MONO_OUT的RT5658_L_VOL_SFT偏移处,寄存器可以设的最大值是39,对应的db是从-4650*0.01dB开始,step是150*0.01dB


SOC_DOUBLE

与SOC_SINGLE类似,区别是SOC_SINGLE只控制一个变量,而SOC_DOUBLE可以同时在他一个寄存器控制两个相似的变量,最常用的是用于一些立体声的kcontrol


MIXER kcontrol

对于前面说到的和dapm相关的kcontrol也是由很多个SOC_SINGLE构成的
static const struct snd_kcontrol_new left_speaker_mixer[] = {
SOC_DAPM_SINGLE(“Input Switch”, WM8993_SPEAKER_MIXER, 7, 1, 0),
SOC_DAPM_SINGLE(“IN1LP Switch”, WM8993_SPEAKER_MIXER, 5, 1, 0),
SOC_DAPM_SINGLE(“Output Switch”, WM8993_SPEAKER_MIXER, 3, 1, 0),
SOC_DAPM_SINGLE(“DAC Switch”, WM8993_SPEAKER_MIXER, 6, 1, 0),
};


SOC_ENUM

Asoc使用SOC_ENUM来描述mux kcontrol
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
.max = xmax, .texts = xtexts }
#define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \
SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts)
#define SOC_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
.info = snd_soc_info_enum_double, \
.get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
.private_value = (unsigned long)&xenum }

以上一般使用 SOC_ENUM_SINGLE去填充SOC_ENUM中的private_value字段,这个private_value在info, get, put函数中要转化为struct soc_enum结构体,来获取里面的reg, shift等。


SOC_VALUE_ENUM

#define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
.mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues}

#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \
SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues)

#define SOC_VALUE_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
.info = snd_soc_info_enum_double, \
.get = snd_soc_get_value_enum_double, \
.put = snd_soc_put_value_enum_double, \
.private_value = (unsigned long)&xenum }

SOC_ENUM和SOC_VALUE_ENUM区别是SOC_VALUE_ENUM多了一个value字段,value是一个数组,上层通过info, get, put传递一个索引,找到索引对应的value下标的数组值。这样做的好处是通过连续的索引可以找到不连续的value数组中的值。


SOC_SINGLE_EXT

需要自己定义get和put回调时,可以使用带EXT版本。

0 0