mixer
Mixer控件用于音频通道的路由控制,由多个输入和一个输出组成,多个输入可以自由地混合在一起,形成混合后的输出:
对于Mixer控件,我们可以认为是多个简单控件的组合,通常,我们会为mixer的每个输入端都单独定义一个简单控件来控制该路输入的开启和关闭,反应在代码上,就是定义一个soc_kcontrol_new数组:
SOC_SINGLE :定义一个最简单的控件
- xname(该控件的名字)
- reg(该控件对应的寄存器的地址)
- shift(控制位在寄存器中的位移)
- max(控件可设置的最大值)
- invert(设定值是否逻辑取反)
SOC_DOUBLE
- xname(该控件的名字)
- reg(该控件对应的寄存器的地址)
- shift_left(控制位在寄存器中的位移)
- shift_right(控制位在寄存器中的位移)
- max(控件可设置的最大值)
- invert(设定值是否逻辑取反)
SOC_SINGLE_TLV: 定义一个 TLV控件
- xname(该控件的名字)
- reg(该控件对应的寄存器的地址)
- shift(控制位在寄存器中的位移)
- max(控件可设置的最大值)
- invert(设定值是否逻辑取反)
- tlv_array (dB值映射值)
SOC_SINGLE_TLV是SOC_SINGLE的一种扩展, 主要定义那些有增益控制的控件(增益,EQ)
最常用的就是用于音量控件时,设定值与对应的dB值之间的映射关系
- DECLARE_TLV_DB_SCALE //用于定义一个dB值映射的 tlv_array
SOC_DOUBLE_R_TLV
- xname(该控件的名字)
- reg_left(该控件对应的left寄存器)
- shift_left(控制位在寄存器中的位移)
- shift_right(控制位在寄存器中的位移)
- max(控件可设置的最大值)
- invert(设定值是否逻辑取反)
- tlv_array (dB值映射值)
实例如下:
static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1);
SOC_DOUBLE_R_TLV("PCM Volume",
NAU88C22_LEFT_DAC_DIGITAL_VOLUME, NAU88C22_RIGHT_DAC_DIGITAL_VOLUME,
0, 255, 0, digital_tlv),
SOC_DAPM_SINGLE
定义的是一个kcontrol,但是是dapm的kcontrol,和普通的kcontrol区别是,回调不一样
- xname(该控件的名字)
- reg(该控件对应的寄存器的地址)
- shift(控制位在寄存器中的位移)
- max(控件可设置的最大值)
- invert(设定值是否逻辑取反)
mux
mux控件与mixer控件类似,也是多个输入端和一个输出端的组合控件,与mixer控件不同的是,mux控件的多个输入端同时只能有一个被选中。因此,mux控件所对应的寄存器,通常可以设定一段连续的数值,每个不同的数值对应不同的输入端被打开,与上述的mixer控件不同,ASoc用soc_enum结构来描述mux控件的寄存器信息:
/* enumerated kcontrol */
struct soc_enum {
int reg;
unsigned char shift_l;
unsigned char shift_r;
unsigned int items;
unsigned int mask;
const char * const *texts;
const unsigned int *values;
};
SOC_ENUM
- xname(该控件的名字)
使用方法
static const char *nau88c22_companding[] = {"Off", "NC", "u-law", "A-law"};
static SOC_ENUM_SINGLE_DECL(adc_compand,
NAU88C22_COMPANDING_CONTROL, 1, nau88c22_companding);
SOC_ENUM("ADC Companding", adc_compand),
DAPM常用宏定义
SND_SOC_DAPM_DAC
#define SND_SOC_DAPM_DAC(wname, stname, wreg, wshift, winvert) \
{ .id = snd_soc_dapm_dac, .name = wname, .sname = stname, \
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) }
#define SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert) \
.reg = wreg, .mask = 1, .shift = wshift, \
.on_val = winvert ? 0 : 1, .off_val = winvert ? 1 : 0
- wname(widget名字)
- stname (stream名字)
- wreg (widget对应的寄存器)
- wshift(widget对应的寄存器的位移)
- winvert(widget是否 逻辑取反)
SND_SOC_DAPM_PGA
#define SND_SOC_DAPM_PGA(wname, wreg, wshift, winvert,\
wcontrols, wncontrols) \
{ .id = snd_soc_dapm_pga, .name = wname, \
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
- wname(widget名字)
- wreg (widget对应的寄存器)
- wshift(widget对应的寄存器的位移)
- winvert(widget是否 逻辑取反)
- kcontrol_news (widget相关的 kcontrol)
- wncontrols (widget相关的 kcontrol的个数)
SND_SOC_DAPM_MIXER
#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
wcontrols, wncontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, \
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = wncontrols}
- wname(widget名字)
- wreg (widget对应的寄存器)
- wshift(widget对应的寄存器的位移)
- winvert(widget是否 逻辑取反)
- kcontrol_news (widget相关的 kcontrol)
- wncontrols (widget相关的 kcontrol的个数)
SND_SOC_DAPM_SUPPLY
#define SND_SOC_DAPM_SUPPLY(wname, wreg, wshift, winvert, wevent, wflags) \
{ .id = snd_soc_dapm_supply, .name = wname, \
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event = wevent, .event_flags = wflags}
- wname(widget名字)
- wreg (widget对应的寄存器)
- wshift(widget对应的寄存器的位移)
- winvert(widget是否 逻辑取反)
- wevent (widget的外部事件的回调 )
- wflags (widget的外部事件类型的标记)
SND_SOC_DAPM_SUPPLY_S
#define SND_SOC_DAPM_SUPPLY_S(wname, wsubseq, wreg, wshift, winvert, wevent, \
wflags) \
{ .id = snd_soc_dapm_supply, .name = wname, \
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.event = wevent, .event_flags = wflags, .subseq = wsubseq}
- wname(widget名字)
- wsubseq (widget的排序)
- wreg (widget对应的寄存器)
- wshift(widget对应的寄存器的位移)
- winvert(widget是否 逻辑取反)
- wevent (widget的外部事件的回调 )
- wflags (widget的外部事件类型的标记)
SND_SOC_DAPM_INPUT
#define SND_SOC_DAPM_INPUT(wname) \
{ .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM }
SND_SOC_DAPM_OUTPUT
#define SND_SOC_DAPM_OUTPUT(wname) \
{ .id = snd_soc_dapm_output, .name = wname, .kcontrol_news = NULL, \
.num_kcontrols = 0, .reg = SND_SOC_NOPM }
SOC_MIXER_ARRAY
#define SOC_MIXER_ARRAY(wname, wreg, wshift, winvert, \
wcontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, \
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
.kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols)}