From b289cafe0ee43feb6c3ab232aa71222c72d8d62c Mon Sep 17 00:00:00 2001 From: Sameer Pujar Date: Thu, 11 Jul 2019 16:15:48 +0530 Subject: [PATCH] ASoC: tegra-alt: fix channel conversions for dmic DMIC controller can be configured to receive data in both left and right channels or in just the left channel or the right channel. Currently we have dmic->ch_select to configure the same. There are few issues w.r.t the way this is used. * dmic->ch_select overrides both client and audio channels of TX CIF. * channels in params_channels(params) is not used and hence requested number of channels in hw_param() callback is not considered. * stereo to mono conversion at TX CIF is not supported This patch addresses all above issues with following * expose a mixer control, "Channel Select", for channel override for CIF channels. * dmic->ch_select is only used to override client channels. * by default ch_select is set to stereo and "None" option is removed * expose mixer control, "stereo to mono", for stere->mono conversion This can be used to select one of the following methods for conversion CH0 --> pick the first channel CH1 --> pick the second channel AVG --> (CH0 + CH1) / 2 * "None" is not required for mono->stereo and hence removed and only below are sufficient. ZERO --> zero out the second channel COPY --> copy the first channel to the second channel * Replaced "TX" prefix for mixer controls with "Capture". This aligns with the policy we used for ADMAIF and I2S. * "Channel Select" control is replaced with "Controller Channel Select", as the control is related to DMIC controller and will be more meaningful. Bug 200520821 Bug 200503387 Change-Id: I8a103f67dc75ca651ee3df3d8594971327364c84 Signed-off-by: Sameer Pujar Reviewed-on: https://git-master.nvidia.com/r/2151729 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Mohan Kumar D GVS: Gerrit_Virtual_Submit Reviewed-by: Dara Ramesh Reviewed-by: mobile promotions Tested-by: mobile promotions --- .../soc/tegra-alt/include/tegra210_dmic_alt.h | 9 +- sound/soc/tegra-alt/tegra210_dmic_alt.c | 87 ++++++++++++------- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/sound/soc/tegra-alt/include/tegra210_dmic_alt.h b/sound/soc/tegra-alt/include/tegra210_dmic_alt.h index 2788ba38..86cc2ecc 100644 --- a/sound/soc/tegra-alt/include/tegra210_dmic_alt.h +++ b/sound/soc/tegra-alt/include/tegra210_dmic_alt.h @@ -76,7 +76,6 @@ #define TEGRA210_DMIC_DBG_CTRL_BYPASS BIT(0) enum tegra_dmic_ch_select { - DMIC_CH_SELECT_NONE, DMIC_CH_SELECT_LEFT, DMIC_CH_SELECT_RIGHT, DMIC_CH_SELECT_STEREO, @@ -97,9 +96,11 @@ struct tegra210_dmic { struct pinctrl_state *pin_idle_state; const char *prod_name; int boost_gain; /* with 100x factor */ - int ch_select; - int tx_mono_to_stereo; - int sample_rate_via_control; + unsigned int ch_select; + unsigned int mono_to_stereo; + unsigned int stereo_to_mono; + unsigned int sample_rate_via_control; + unsigned int channels_via_control; unsigned int osr_val; /* osr value */ int lrsel; bool is_shutdown; diff --git a/sound/soc/tegra-alt/tegra210_dmic_alt.c b/sound/soc/tegra-alt/tegra210_dmic_alt.c index 85646fbe..dbbaff0e 100644 --- a/sound/soc/tegra-alt/tegra210_dmic_alt.c +++ b/sound/soc/tegra-alt/tegra210_dmic_alt.c @@ -162,36 +162,34 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream, { struct device *dev = dai->dev; struct tegra210_dmic *dmic = snd_soc_dai_get_drvdata(dai); - int channels, srate, dmic_clk, osr = dmic->osr_val, ret; + int srate, dmic_clk, osr = dmic->osr_val, ret; struct tegra210_xbar_cif_conf cif_conf; unsigned long long boost_gain; - int channel_select; + unsigned int channels; memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); srate = params_rate(params); if (dmic->sample_rate_via_control) srate = dmic->sample_rate_via_control; - dmic_clk = (1 << (6+osr)) * srate; - if (dmic->ch_select == DMIC_CH_SELECT_NONE) { - channels = 2; - channel_select = DMIC_CH_SELECT_STEREO; - } else { - channels = 1; - channel_select = dmic->ch_select; - } - - cif_conf.client_channels = channels; + channels = params_channels(params); + if (dmic->channels_via_control) + channels = dmic->channels_via_control; cif_conf.audio_channels = channels; - /* For capture path, the mono input from client channel - * can be converted to stereo with cif controls. - */ - if (dmic->tx_mono_to_stereo > 0) { - cif_conf.mono_conv = dmic->tx_mono_to_stereo - 1; - cif_conf.audio_channels = 2; + switch (dmic->ch_select) { + case DMIC_CH_SELECT_LEFT: + case DMIC_CH_SELECT_RIGHT: + cif_conf.client_channels = 1; + break; + case DMIC_CH_SELECT_STEREO: + cif_conf.client_channels = 2; + break; + default: + dev_err(dev, "unsupported ch_select value\n"); + return -EINVAL; } if ((tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { @@ -218,7 +216,7 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream, TEGRA210_DMIC_DBG_CTRL_DCR_ENABLE); regmap_update_bits(dmic->regmap, TEGRA210_DMIC_CTRL, TEGRA210_DMIC_CTRL_CHANNEL_SELECT_MASK, - channel_select << CH_SEL_SHIFT); + (dmic->ch_select + 1) << CH_SEL_SHIFT); /* Configure LPF for passthrough and use */ /* its gain register for applying boost; */ @@ -275,8 +273,9 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream, if (dmic->format_out) cif_conf.audio_bits = tegra210_dmic_fmt_values[dmic->format_out]; - cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_24; + cif_conf.mono_conv = dmic->mono_to_stereo; + cif_conf.stereo_conv = dmic->stereo_to_mono; tegra210_xbar_set_cif(dmic->regmap, TEGRA210_DMIC_TX_CIF_CTRL, &cif_conf); @@ -292,16 +291,20 @@ static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol, if (strstr(kcontrol->id.name, "Boost")) ucontrol->value.integer.value[0] = dmic->boost_gain; - else if (strstr(kcontrol->id.name, "Mono")) + else if (strstr(kcontrol->id.name, "Controller Channel Select")) ucontrol->value.integer.value[0] = dmic->ch_select; - else if (strstr(kcontrol->id.name, "TX mono to stereo")) - ucontrol->value.integer.value[0] = - dmic->tx_mono_to_stereo; + else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + ucontrol->value.integer.value[0] = dmic->mono_to_stereo; + else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + ucontrol->value.integer.value[0] = dmic->stereo_to_mono; else if (strstr(kcontrol->id.name, "output bit format")) ucontrol->value.integer.value[0] = dmic->format_out; else if (strstr(kcontrol->id.name, "Sample Rate")) ucontrol->value.integer.value[0] = dmic->sample_rate_via_control; + else if (strstr(kcontrol->id.name, "Channels")) + ucontrol->value.integer.value[0] = + dmic->channels_via_control; else if (strstr(kcontrol->id.name, "OSR Value")) ucontrol->value.integer.value[0] = dmic->osr_val; else if (strstr(kcontrol->id.name, "LR Select")) @@ -319,14 +322,18 @@ static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol, if (strstr(kcontrol->id.name, "Boost")) dmic->boost_gain = value; - else if (strstr(kcontrol->id.name, "Mono")) + else if (strstr(kcontrol->id.name, "Controller Channel Select")) dmic->ch_select = ucontrol->value.integer.value[0]; - else if (strstr(kcontrol->id.name, "TX mono to stereo")) - dmic->tx_mono_to_stereo = value; + else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + dmic->mono_to_stereo = value; + else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + dmic->stereo_to_mono = value; else if (strstr(kcontrol->id.name, "output bit format")) dmic->format_out = value; else if (strstr(kcontrol->id.name, "Sample Rate")) dmic->sample_rate_via_control = value; + else if (strstr(kcontrol->id.name, "Channels")) + dmic->channels_via_control = value; else if (strstr(kcontrol->id.name, "OSR Value")) dmic->osr_val = value; else if (strstr(kcontrol->id.name, "LR Select")) @@ -382,7 +389,7 @@ static const struct snd_soc_dapm_route tegra210_dmic_routes[] = { }; static const char * const tegra210_dmic_ch_select[] = { - "None", "L", "R", + "L", "R", "Stereo", }; static const struct soc_enum tegra210_dmic_ch_enum = @@ -390,7 +397,11 @@ static const struct soc_enum tegra210_dmic_ch_enum = tegra210_dmic_ch_select); static const char * const tegra210_dmic_mono_conv_text[] = { - "None", "ZERO", "COPY", + "ZERO", "COPY", +}; + +static const char * const tegra210_dmic_stereo_conv_text[] = { + "CH0", "CH1", "AVG", }; static const struct soc_enum tegra210_dmic_mono_conv_enum = @@ -398,6 +409,11 @@ static const struct soc_enum tegra210_dmic_mono_conv_enum = ARRAY_SIZE(tegra210_dmic_mono_conv_text), tegra210_dmic_mono_conv_text); +static const struct soc_enum tegra210_dmic_stereo_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra210_dmic_stereo_conv_text), + tegra210_dmic_stereo_conv_text); + static const char * const tegra210_dmic_format_text[] = { "None", "16", @@ -427,14 +443,20 @@ static const struct soc_enum tegra210_dmic_lrsel_enum = static const struct snd_kcontrol_new tegra210_dmic_controls[] = { SOC_SINGLE_EXT("Boost Gain", 0, 0, 25599, 0, tegra210_dmic_get_control, tegra210_dmic_put_control), - SOC_ENUM_EXT("Mono Channel Select", tegra210_dmic_ch_enum, - tegra210_dmic_get_control, tegra210_dmic_put_control), - SOC_ENUM_EXT("TX mono to stereo conv", tegra210_dmic_mono_conv_enum, + SOC_ENUM_EXT("Controller Channel Select", tegra210_dmic_ch_enum, tegra210_dmic_get_control, tegra210_dmic_put_control), + SOC_ENUM_EXT("Capture mono to stereo conv", + tegra210_dmic_mono_conv_enum, tegra210_dmic_get_control, + tegra210_dmic_put_control), + SOC_ENUM_EXT("Capture stereo to mono conv", + tegra210_dmic_stereo_conv_enum, tegra210_dmic_get_control, + tegra210_dmic_put_control), SOC_ENUM_EXT("output bit format", tegra210_dmic_format_enum, tegra210_dmic_get_control, tegra210_dmic_put_control), SOC_SINGLE_EXT("Sample Rate", 0, 0, 48000, 0, tegra210_dmic_get_control, tegra210_dmic_put_control), + SOC_SINGLE_EXT("Channels", 0, 0, 2, 0, tegra210_dmic_get_control, + tegra210_dmic_put_control), SOC_ENUM_EXT("OSR Value", tegra210_dmic_osr_enum, tegra210_dmic_get_control, tegra210_dmic_put_control), SOC_ENUM_EXT("LR Select", tegra210_dmic_lrsel_enum, @@ -560,6 +582,7 @@ static int tegra210_dmic_platform_probe(struct platform_device *pdev) dmic->is_shutdown = false; dmic->prod_name = NULL; dmic->osr_val = DMIC_OSR_64; + dmic->ch_select = DMIC_CH_SELECT_STEREO; dev_set_drvdata(&pdev->dev, dmic); if (!(tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) {