Re: [PATCH v2] ASoC: msm8916-wcd-digital: Add sidetone support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu,  6 Jun 2019 13:42:42 +0100
Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxx> wrote:

> This patch adds sidetone support via one of the 3 RX Mix paths
> using IIR1 and IIR2.
> IIR1 can be feed by any Decimators or RX paths, and IIRx can also be
> looped back to RX mixers to provide sidetone functionality.
> Two IIR filters are used for Side tone equalization and each filter
> is 5 stage.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxx>
> ---
> Changes since v1:
> 	- added missing break in switch
> 	- Moved IIR bands enable to switch controls
> 
>  sound/soc/codecs/msm8916-wcd-digital.c | 282
> +++++++++++++++++++++++++ 1 file changed, 282 insertions(+)
> 
> diff --git a/sound/soc/codecs/msm8916-wcd-digital.c
> b/sound/soc/codecs/msm8916-wcd-digital.c index
> a63961861e55..1db7e43ec203 100644 ---
> a/sound/soc/codecs/msm8916-wcd-digital.c +++
> b/sound/soc/codecs/msm8916-wcd-digital.c @@ -187,6 +187,43 @@
>  #define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
>  				     SNDRV_PCM_FMTBIT_S32_LE)
>  
> +/* Codec supports 2 IIR filters */
> +enum {
> +	IIR1 = 0,
> +	IIR2,
> +	IIR_MAX,
> +};
> +
> +/* Codec supports 5 bands */
> +enum {
> +	BAND1 = 0,
> +	BAND2,
> +	BAND3,
> +	BAND4,
> +	BAND5,
> +	BAND_MAX,
> +};
> +
> +#define WCD_IIR_FILTER_SIZE	(sizeof(u32)*BAND_MAX)
> +
> +#define WCD_IIR_FILTER_CTL(xname, iidx, bidx) \
> +{       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
> +	.info = wcd_iir_filter_info, \
> +	.get = msm8x16_wcd_get_iir_band_audio_mixer, \
> +	.put = msm8x16_wcd_put_iir_band_audio_mixer, \
> +	.private_value = (unsigned long)&(struct wcd_iir_filter_ctl)
> { \
> +		.iir_idx = iidx, \
> +		.band_idx = bidx, \
> +		.bytes_ext = {.max = WCD_IIR_FILTER_SIZE, }, \
> +	} \
> +}
> +
> +struct wcd_iir_filter_ctl {
> +	unsigned int iir_idx;
> +	unsigned int band_idx;
> +	struct soc_bytes_ext bytes_ext;
> +};
> +
>  struct msm8916_wcd_digital_priv {
>  	struct clk *ahbclk, *mclk;
>  };
> @@ -298,6 +335,161 @@ static
> SOC_ENUM_SINGLE_DECL(rx2_dcb_cutoff_enum, LPASS_CDC_RX2_B4_CTL, 0,
> static SOC_ENUM_SINGLE_DECL(rx3_dcb_cutoff_enum,
> LPASS_CDC_RX3_B4_CTL, 0, dc_blocker_cutoff_text); 
> +static int msm8x16_wcd_codec_set_iir_gain(struct snd_soc_dapm_widget
> *w,
> +		struct snd_kcontrol *kcontrol, int event)
> +{
> +	struct snd_soc_component *component =
> +			snd_soc_dapm_to_component(w->dapm);
> +	int value = 0, reg = 0;
> +
> +	switch (event) {
> +	case SND_SOC_DAPM_POST_PMU:
> +		if (w->shift == 0)
> +			reg = LPASS_CDC_IIR1_GAIN_B1_CTL;
> +		else if (w->shift == 1)
> +			reg = LPASS_CDC_IIR2_GAIN_B1_CTL;
> +		value = snd_soc_component_read32(component, reg);
> +		snd_soc_component_write(component, reg, value);
> +		break;
> +	default:
> +		break;
> +	}
> +	return 0;
> +}
> +
> +static uint32_t get_iir_band_coeff(struct snd_soc_component
> *component,
> +				   int iir_idx, int band_idx,
> +				   int coeff_idx)
> +{
> +	uint32_t value = 0;
> +
> +	/* Address does not automatically update if reading */
> +	snd_soc_component_write(component,
> +		(LPASS_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
> +		((band_idx * BAND_MAX + coeff_idx)
> +		* sizeof(uint32_t)) & 0x7F);
> +
> +	value |= snd_soc_component_read32(component,
> +		(LPASS_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx));
> +
> +	snd_soc_component_write(component,
> +		(LPASS_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
> +		((band_idx * BAND_MAX + coeff_idx)
> +		* sizeof(uint32_t) + 1) & 0x7F);
> +
> +	value |= (snd_soc_component_read32(component,
> +		(LPASS_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
> +
> +	snd_soc_component_write(component,
> +		(LPASS_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
> +		((band_idx * BAND_MAX + coeff_idx)
> +		* sizeof(uint32_t) + 2) & 0x7F);
> +
> +	value |= (snd_soc_component_read32(component,
> +		(LPASS_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
> +
> +	snd_soc_component_write(component,
> +		(LPASS_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
> +		((band_idx * BAND_MAX + coeff_idx)
> +		* sizeof(uint32_t) + 3) & 0x7F);
> +
> +	/* Mask bits top 2 bits since they are reserved */
> +	value |= ((snd_soc_component_read32(component,
> +		 (LPASS_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) &
> 0x3f) << 24);
> +	return value;
> +
> +}
> +
> +static int msm8x16_wcd_get_iir_band_audio_mixer(
> +					struct snd_kcontrol
> *kcontrol,
> +					struct snd_ctl_elem_value
> *ucontrol) +{
> +
> +	struct snd_soc_component *component =
> +			snd_soc_kcontrol_component(kcontrol);
> +	struct wcd_iir_filter_ctl *ctl =
> +			(struct wcd_iir_filter_ctl
> *)kcontrol->private_value;
> +	struct soc_bytes_ext *params = &ctl->bytes_ext;
> +	int iir_idx = ctl->iir_idx;
> +	int band_idx = ctl->band_idx;
> +	u32 coeff[BAND_MAX];
> +
> +	coeff[0] = get_iir_band_coeff(component, iir_idx, band_idx,
> 0);
> +	coeff[1] = get_iir_band_coeff(component, iir_idx, band_idx,
> 1);
> +	coeff[2] = get_iir_band_coeff(component, iir_idx, band_idx,
> 2);
> +	coeff[3] = get_iir_band_coeff(component, iir_idx, band_idx,
> 3);
> +	coeff[4] = get_iir_band_coeff(component, iir_idx, band_idx,
> 4); +
> +	memcpy(ucontrol->value.bytes.data, &coeff[0], params->max);
> +
> +	return 0;
> +}
> +
> +static void set_iir_band_coeff(struct snd_soc_component *component,
> +				int iir_idx, int band_idx,
> +				uint32_t value)
> +{
> +	snd_soc_component_write(component,
> +		(LPASS_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
> +		(value & 0xFF));
> +
> +	snd_soc_component_write(component,
> +		(LPASS_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
> +		(value >> 8) & 0xFF);
> +
> +	snd_soc_component_write(component,
> +		(LPASS_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
> +		(value >> 16) & 0xFF);
> +
> +	/* Mask top 2 bits, 7-8 are reserved */
> +	snd_soc_component_write(component,
> +		(LPASS_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
> +		(value >> 24) & 0x3F);
> +}
> +
> +static int msm8x16_wcd_put_iir_band_audio_mixer(
> +					struct snd_kcontrol
> *kcontrol,
> +					struct snd_ctl_elem_value
> *ucontrol) +{
> +	struct snd_soc_component *component =
> +			snd_soc_kcontrol_component(kcontrol);
> +	struct wcd_iir_filter_ctl *ctl =
> +			(struct wcd_iir_filter_ctl
> *)kcontrol->private_value;
> +	struct soc_bytes_ext *params = &ctl->bytes_ext;
> +	int iir_idx = ctl->iir_idx;
> +	int band_idx = ctl->band_idx;
> +	u32 coeff[BAND_MAX];
> +
> +	memcpy(&coeff[0], ucontrol->value.bytes.data, params->max);
> +
> +	/* Mask top bit it is reserved */
> +	/* Updates addr automatically for each B2 write */
> +	snd_soc_component_write(component,
> +		(LPASS_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
> +		(band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
> +
> +	set_iir_band_coeff(component, iir_idx, band_idx, coeff[0]);
> +	set_iir_band_coeff(component, iir_idx, band_idx, coeff[1]);
> +	set_iir_band_coeff(component, iir_idx, band_idx, coeff[2]);
> +	set_iir_band_coeff(component, iir_idx, band_idx, coeff[3]);
> +	set_iir_band_coeff(component, iir_idx, band_idx, coeff[4]);
> +
> +	return 0;
> +}
> +
> +static int wcd_iir_filter_info(struct snd_kcontrol *kcontrol,
> +				struct snd_ctl_elem_info *ucontrol)
> +{
> +	struct wcd_iir_filter_ctl *ctl =
> +		(struct wcd_iir_filter_ctl *)kcontrol->private_value;
> +	struct soc_bytes_ext *params = &ctl->bytes_ext;
> +
> +	ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
> +	ucontrol->count = params->max;
> +
> +	return 0;
> +}
> +
>  static const struct snd_kcontrol_new
> msm8916_wcd_digital_snd_controls[] = { SOC_SINGLE_S8_TLV("RX1 Digital
> Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL, -128, 127, digital_gain),
> @@ -322,6 +514,44 @@ static const struct snd_kcontrol_new
> msm8916_wcd_digital_snd_controls[] = { SOC_SINGLE("RX1 Mute Switch",
> LPASS_CDC_RX1_B6_CTL, 0, 1, 0), SOC_SINGLE("RX2 Mute Switch",
> LPASS_CDC_RX2_B6_CTL, 0, 1, 0), SOC_SINGLE("RX3 Mute Switch",
> LPASS_CDC_RX3_B6_CTL, 0, 1, 0), +
> +	SOC_SINGLE("IIR1 Band1 Switch", LPASS_CDC_IIR1_CTL, 0, 1, 0),
> +	SOC_SINGLE("IIR1 Band2 Switch", LPASS_CDC_IIR1_CTL, 1, 1, 0),
> +	SOC_SINGLE("IIR1 Band3 Switch", LPASS_CDC_IIR1_CTL, 2, 1, 0),
> +	SOC_SINGLE("IIR1 Band4 Switch", LPASS_CDC_IIR1_CTL, 3, 1, 0),
> +	SOC_SINGLE("IIR1 Band5 Switch", LPASS_CDC_IIR1_CTL, 4, 1, 0),
> +	SOC_SINGLE("IIR2 Band1 Switch", LPASS_CDC_IIR2_CTL, 0, 1, 0),
> +	SOC_SINGLE("IIR2 Band2 Switch", LPASS_CDC_IIR2_CTL, 1, 1, 0),
> +	SOC_SINGLE("IIR2 Band3 Switch", LPASS_CDC_IIR2_CTL, 2, 1, 0),
> +	SOC_SINGLE("IIR2 Band4 Switch", LPASS_CDC_IIR2_CTL, 3, 1, 0),
> +	SOC_SINGLE("IIR2 Band5 Switch", LPASS_CDC_IIR2_CTL, 4, 1, 0),
> +	WCD_IIR_FILTER_CTL("IIR1 Band1", IIR1, BAND1),
> +	WCD_IIR_FILTER_CTL("IIR1 Band2", IIR1, BAND2),
> +	WCD_IIR_FILTER_CTL("IIR1 Band3", IIR1, BAND3),
> +	WCD_IIR_FILTER_CTL("IIR1 Band4", IIR1, BAND4),
> +	WCD_IIR_FILTER_CTL("IIR1 Band5", IIR1, BAND5),
> +	WCD_IIR_FILTER_CTL("IIR2 Band1", IIR2, BAND1),
> +	WCD_IIR_FILTER_CTL("IIR2 Band2", IIR2, BAND2),
> +	WCD_IIR_FILTER_CTL("IIR2 Band3", IIR2, BAND3),
> +	WCD_IIR_FILTER_CTL("IIR2 Band4", IIR2, BAND4),
> +	WCD_IIR_FILTER_CTL("IIR2 Band5", IIR2, BAND5),
> +	SOC_SINGLE_SX_TLV("IIR1 INP1 Volume",
> LPASS_CDC_IIR1_GAIN_B1_CTL,
> +			0,  -84, 40, digital_gain),
> +	SOC_SINGLE_SX_TLV("IIR1 INP2 Volume",
> LPASS_CDC_IIR1_GAIN_B2_CTL,
> +			0,  -84, 40, digital_gain),
> +	SOC_SINGLE_SX_TLV("IIR1 INP3 Volume",
> LPASS_CDC_IIR1_GAIN_B3_CTL,
> +			0,  -84, 40, digital_gain),
> +	SOC_SINGLE_SX_TLV("IIR1 INP4 Volume",
> LPASS_CDC_IIR1_GAIN_B4_CTL,
> +			0,  -84,	40, digital_gain),

There seems to be some alignment issue in above line.
And while I'm commenting this place, there is only 4 Volume controls,
while there is 5 switches for IIR1 and IIR2, is this right?

> +	SOC_SINGLE_SX_TLV("IIR2 INP1 Volume",
> LPASS_CDC_IIR2_GAIN_B1_CTL,
> +			0,  -84, 40, digital_gain),
> +	SOC_SINGLE_SX_TLV("IIR2 INP2 Volume",
> LPASS_CDC_IIR2_GAIN_B2_CTL,
> +			0,  -84, 40, digital_gain),
> +	SOC_SINGLE_SX_TLV("IIR2 INP3 Volume",
> LPASS_CDC_IIR2_GAIN_B3_CTL,
> +			0,  -84, 40, digital_gain),
> +	SOC_SINGLE_SX_TLV("IIR2 INP4 Volume",
> LPASS_CDC_IIR2_GAIN_B4_CTL,
> +			0,  -84, 40, digital_gain),
> +
>  };
>  
>  static int msm8916_wcd_digital_enable_interpolator(
> @@ -448,6 +678,24 @@ static int
> msm8916_wcd_digital_enable_dmic(struct snd_soc_dapm_widget *w, return
> 0; }
>  
> +static const char * const iir_inp1_text[] = {
> +	"ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
> +};
> +
> +static const struct soc_enum iir1_inp1_mux_enum =
> +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_EQ1_B1_CTL,
> +		0, 6, iir_inp1_text);
> +
> +static const struct soc_enum iir2_inp1_mux_enum =
> +	SOC_ENUM_SINGLE(LPASS_CDC_CONN_EQ2_B1_CTL,
> +		0, 6, iir_inp1_text);
> +
> +static const struct snd_kcontrol_new iir1_inp1_mux =
> +	SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
> +
> +static const struct snd_kcontrol_new iir2_inp1_mux =
> +	SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
> +
>  static const struct snd_soc_dapm_widget
> msm8916_wcd_digital_dapm_widgets[] = { /*RX stuff */
>  	SND_SOC_DAPM_AIF_IN("I2S RX1", NULL, 0, SND_SOC_NOPM, 0, 0),
> @@ -534,6 +782,15 @@ static const struct snd_soc_dapm_widget
> msm8916_wcd_digital_dapm_widgets[] = { SND_SOC_DAPM_MIC("Digital
> Mic1", NULL), SND_SOC_DAPM_MIC("Digital Mic2", NULL),
>  
> +	/* Sidetone */
> +	SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0,
> &iir1_inp1_mux),
> +	SND_SOC_DAPM_PGA_E("IIR1", LPASS_CDC_CLK_SD_CTL, 0, 0, NULL,
> 0,
> +		msm8x16_wcd_codec_set_iir_gain,
> SND_SOC_DAPM_POST_PMU), +
> +	SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0,
> &iir2_inp1_mux),
> +	SND_SOC_DAPM_PGA_E("IIR2", LPASS_CDC_CLK_SD_CTL, 1, 0, NULL,
> 0,
> +		msm8x16_wcd_codec_set_iir_gain,
> SND_SOC_DAPM_POST_PMU), +
>  };
>  
>  static int msm8916_wcd_digital_get_clks(struct platform_device *pdev,
> @@ -708,10 +965,14 @@ static const struct snd_soc_dapm_route
> msm8916_wcd_digital_audio_map[] = { {"RX1 MIX1 INP1", "RX1", "I2S
> RX1"}, {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
>  	{"RX1 MIX1 INP1", "RX3", "I2S RX3"},
> +	{"RX1 MIX1 INP1", "IIR1", "IIR1"},
> +	{"RX1 MIX1 INP1", "IIR2", "IIR2"},
>  
>  	{"RX1 MIX1 INP2", "RX1", "I2S RX1"},
>  	{"RX1 MIX1 INP2", "RX2", "I2S RX2"},
>  	{"RX1 MIX1 INP2", "RX3", "I2S RX3"},
> +	{"RX1 MIX1 INP2", "IIR1", "IIR1"},
> +	{"RX1 MIX1 INP2", "IIR2", "IIR2"},
>  
>  	{"RX1 MIX1 INP3", "RX1", "I2S RX1"},
>  	{"RX1 MIX1 INP3", "RX2", "I2S RX2"},
> @@ -728,10 +989,14 @@ static const struct snd_soc_dapm_route
> msm8916_wcd_digital_audio_map[] = { {"RX2 MIX1 INP1", "RX1", "I2S
> RX1"}, {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
>  	{"RX2 MIX1 INP1", "RX3", "I2S RX3"},
> +	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
> +	{"RX2 MIX1 INP1", "IIR2", "IIR2"},
>  
>  	{"RX2 MIX1 INP2", "RX1", "I2S RX1"},
>  	{"RX2 MIX1 INP2", "RX2", "I2S RX2"},
>  	{"RX2 MIX1 INP2", "RX3", "I2S RX3"},
> +	{"RX2 MIX1 INP1", "IIR1", "IIR1"},
> +	{"RX2 MIX1 INP1", "IIR2", "IIR2"},
>  
>  	{"RX2 MIX1 INP3", "RX1", "I2S RX1"},
>  	{"RX2 MIX1 INP3", "RX2", "I2S RX2"},
> @@ -748,10 +1013,27 @@ static const struct snd_soc_dapm_route
> msm8916_wcd_digital_audio_map[] = { {"RX3 MIX1 INP1", "RX1", "I2S
> RX1"}, {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
>  	{"RX3 MIX1 INP1", "RX3", "I2S RX3"},
> +	{"RX3 MIX1 INP1", "IIR1", "IIR1"},
> +	{"RX3 MIX1 INP1", "IIR2", "IIR2"},
>  
>  	{"RX3 MIX1 INP2", "RX1", "I2S RX1"},
>  	{"RX3 MIX1 INP2", "RX2", "I2S RX2"},
>  	{"RX3 MIX1 INP2", "RX3", "I2S RX3"},
> +	{"RX3 MIX1 INP2", "IIR1", "IIR1"},
> +	{"RX3 MIX1 INP2", "IIR2", "IIR2"},
> +
> +	{"RX1 MIX2 INP1", "IIR1", "IIR1"},
> +	{"RX2 MIX2 INP1", "IIR1", "IIR1"},
> +	{"RX1 MIX2 INP1", "IIR2", "IIR2"},
> +	{"RX2 MIX2 INP1", "IIR2", "IIR2"},
> +
> +	{"IIR1", NULL, "IIR1 INP1 MUX"},
> +	{"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
> +	{"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
> +
> +	{"IIR2", NULL, "IIR2 INP1 MUX"},
> +	{"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
> +	{"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
>  
>  	{"RX3 MIX1 INP3", "RX1", "I2S RX1"},
>  	{"RX3 MIX1 INP3", "RX2", "I2S RX2"},

_______________________________________________
Alsa-devel mailing list
Alsa-devel@xxxxxxxxxxxxxxxx
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel



[Index of Archives]     [ALSA User]     [Linux Audio Users]     [Pulse Audio]     [Kernel Archive]     [Asterisk PBX]     [Photo Sharing]     [Linux Sound]     [Video 4 Linux]     [Gimp]     [Yosemite News]

  Powered by Linux