Introduction to controls in alsa

mixer

Mixer control is used for routing control of audio channel. It is composed of multiple inputs and one output. Multiple inputs can be freely mixed together to form a mixed output:
For the mixer control, we can think of it as a combination of multiple simple controls. Usually, we will define a single simple control for each input end of the mixer to control the opening and closing of the input of the channel. The response in the code is to define a soc_kcontrol_new array:

SOC_SINGLE: define the simplest control

  • xname (the name of the control)
  • reg (address of the register corresponding to the control)
  • Shift (shift of control bit in register)
  • max (the maximum value that the control can set)
  • invert (whether the set value is logically reversed)

SOC_DOUBLE

  • xname (the name of the control)
  • reg (address of the register corresponding to the control)
  • shift_left (displacement of control bit in register)
  • shift_right (displacement of control bit in register)
  • max (the maximum value that the control can set)
  • invert (whether the set value is logically reversed)

SOC_SINGLE_TLV: define a TLV control

  • xname (the name of the control)
  • reg (address of the register corresponding to the control)
  • Shift (shift of control bit in register)
  • max (the maximum value that the control can set)
  • invert (whether the set value is logically reversed)
  • tlv_array (dB value mapping value)

SOC_SINGLE_TLV is SOC_ An extension of single, which mainly defines those controls with gain control (gain, EQ)
The most commonly used is the mapping relationship between the set value and the corresponding dB value when used for the volume control

  • DECLARE_TLV_DB_SCALE / / used to define a TLV for dB value mapping_ array

SOC_DOUBLE_R_TLV

  • xname (the name of the control)
  • reg_left (the left register corresponding to the control)
  • shift_left (displacement of control bit in register)
  • shift_right (displacement of control bit in register)
  • max (the maximum value that the control can set)
  • invert (whether the set value is logically reversed)
  • tlv_array (dB value mapping value)

Examples are as follows:

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
It defines a kcontrol, but it is the kcontrol of dapm. The difference between a normal kcontrol and a callback is different

  • xname (the name of the control)
  • reg (address of the register corresponding to the control)
  • Shift (shift of control bit in register)
  • max (the maximum value that the control can set)
  • invert (whether the set value is logically reversed)

mux

Similar to the mixer control, the mux control is also a combined control with multiple inputs and one output. Unlike the mixer control, only one of multiple inputs of the mux control can be selected at the same time. Therefore, the register corresponding to the mux control can usually set a continuous value, and each different value corresponds to a different input to be opened. Unlike the above mixer control, ASoc uses soc_enum structure to describe the register information of mux control:

/* 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 (the name of the control)

usage method

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 common macro definitions

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 name)
  • stname (stream name)
  • wreg (register corresponding to widget)
  • Wsshift (displacement of the register corresponding to the widget)
  • winvert (whether the widget is logically inverted)

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 name)
  • wreg (register corresponding to widget)
  • Wsshift (displacement of the register corresponding to the widget)
  • winvert (whether the widget is logically inverted)
  • kcontrol_news (widget related kcontrol)
  • Wncontrols (number of kcontrol s related to widgets)

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 name)
  • wreg (register corresponding to widget)
  • Wsshift (displacement of the register corresponding to the widget)
  • winvert (whether the widget is logically inverted)
  • kcontrol_news (widget related kcontrol)
  • Wncontrols (number of kcontrol s related to widgets)

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 name)
  • wreg (register corresponding to widget)
  • Wsshift (displacement of the register corresponding to the widget)
  • winvert (whether the widget is logically inverted)
  • Wevent (callback of external event of widget)
  • Wflags (tag of external event type of 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 name)
  • Wsubseq (sorting of widgets)
  • wreg (register corresponding to widget)
  • Wsshift (displacement of the register corresponding to the widget)
  • winvert (whether the widget is logically inverted)
  • Wevent (callback of external event of widget)
  • Wflags (tag of external event type of 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)}

Tags: Alsa

Posted on Thu, 23 Sep 2021 07:30:04 -0400 by figment