diff --git a/sound/soc/tegra-alt/tegra210_admaif_alt.c b/sound/soc/tegra-alt/tegra210_admaif_alt.c index 76f6af33..e64f9a9d 100644 --- a/sound/soc/tegra-alt/tegra210_admaif_alt.c +++ b/sound/soc/tegra-alt/tegra210_admaif_alt.c @@ -320,16 +320,16 @@ static int tegra210_admaif_hw_params(struct snd_pcm_substream *substream, struct tegra210_admaif *admaif = snd_soc_dai_get_drvdata(dai); struct tegra210_xbar_cif_conf cif_conf; unsigned int reg; - int valid_bit; + int valid_bit, channels; memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); - if (admaif->override_channels[dai->id] > 0) { - cif_conf.audio_channels = admaif->override_channels[dai->id]; - cif_conf.client_channels = admaif->override_channels[dai->id]; - } else { - cif_conf.audio_channels = params_channels(params); - cif_conf.client_channels = params_channels(params); - } + + channels = params_channels(params); + if (admaif->override_channels[dai->id] > 0) + channels = admaif->override_channels[dai->id]; + + cif_conf.audio_channels = channels; + cif_conf.client_channels = channels; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: @@ -360,9 +360,27 @@ static int tegra210_admaif_hw_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { reg = TEGRA210_ADMAIF_CHAN_ACIF_TX_CTRL + (dai->id * TEGRA210_ADMAIF_CHANNEL_REG_STRIDE); + /* For playback path, the mono input from client channel + * can be converted to stereo using cif controls. + */ + if (admaif->tx_mono_to_stereo[dai->id] > 0) { + cif_conf.mono_conv = + admaif->tx_mono_to_stereo[dai->id] - 1; + cif_conf.audio_channels = 2; + cif_conf.client_channels = 1; + } } else { reg = TEGRA210_ADMAIF_CHAN_ACIF_RX_CTRL + (dai->id * TEGRA210_ADMAIF_CHANNEL_REG_STRIDE); + /* For capture path, the stereo audio channel can be + * converted to mono using cif controls. + */ + if (admaif->rx_stereo_to_mono[dai->id] > 0) { + cif_conf.stereo_conv = + admaif->rx_stereo_to_mono[dai->id] - 1; + cif_conf.audio_channels = 2; + cif_conf.client_channels = 1; + } } tegra210_admaif_set_pack_mode(admaif->regmap, reg, valid_bit); @@ -478,19 +496,40 @@ static struct snd_soc_dai_ops tegra210_admaif_dai_ops = { .prepare = tegra210_admaif_prepare, }; -static int tegra210_admaif_get_channels(struct snd_kcontrol *kcontrol, +static int tegra210_admaif_get_format(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct tegra210_admaif *admaif = snd_soc_codec_get_drvdata(codec); + int i; + char buf[50]; + + if (strstr(kcontrol->id.name, "Channels")) + ucontrol->value.integer.value[0] = + admaif->override_channels[mc->reg]; + else { + for (i = 0 ; i < TEGRA210_ADMAIF_CHANNEL_COUNT; i++) { + snprintf(buf, 50, "ADMAIF%d RX stereo to mono", i+1); + if (strstr(kcontrol->id.name, buf)) { + ucontrol->value.integer.value[0] = + admaif->rx_stereo_to_mono[i]; + break; + } + snprintf(buf, 50, "ADMAIF%d TX mono to stereo", i+1); + if (strstr(kcontrol->id.name, buf)) { + ucontrol->value.integer.value[0] = + admaif->tx_mono_to_stereo[i]; + break; + } + } + } - ucontrol->value.integer.value[0] = admaif->override_channels[mc->reg]; return 0; } -static int tegra210_admaif_put_channels(struct snd_kcontrol *kcontrol, +static int tegra210_admaif_put_format(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct soc_mixer_control *mc = @@ -498,12 +537,30 @@ static int tegra210_admaif_put_channels(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tegra210_admaif *admaif = snd_soc_codec_get_drvdata(codec); int value = ucontrol->value.integer.value[0]; + int i; + char buf[50]; - if (value > 0 && value <= 16) { - admaif->override_channels[mc->reg] = value; - return 0; - } else - return -EINVAL; + if (strstr(kcontrol->id.name, "Channels")) { + if (value > 0 && value <= 16) + admaif->override_channels[mc->reg] = value; + else + return -EINVAL; + } else { + for (i = 0 ; i < TEGRA210_ADMAIF_CHANNEL_COUNT; i++) { + snprintf(buf, 50, "ADMAIF%d RX stereo to mono", i+1); + if (strstr(kcontrol->id.name, buf)) { + admaif->rx_stereo_to_mono[i] = value; + break; + } + snprintf(buf, 50, "ADMAIF%d TX mono to stereo", i+1); + if (strstr(kcontrol->id.name, buf)) { + admaif->tx_mono_to_stereo[i] = value; + break; + } + } + } + + return 0; } static int tegra210_admaif_dai_probe(struct snd_soc_dai *dai) @@ -728,9 +785,37 @@ static const struct snd_soc_dapm_route tegra210_admaif_routes[] = { ADMAIF_ROUTES(20) }; +static const char * const tegra_admaif_stereo_conv_text[] = { + "None", "CH0", "CH1", "AVG", +}; + +static const char * const tegra_admaif_mono_conv_text[] = { + "None", "ZERO", "COPY", +}; + +static const struct soc_enum tegra_admaif_mono_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra_admaif_mono_conv_text), + tegra_admaif_mono_conv_text); + +static const struct soc_enum tegra_admaif_stereo_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra_admaif_stereo_conv_text), + tegra_admaif_stereo_conv_text); + #define TEGRA210_ADMAIF_CHANNEL_CTRL(reg) \ SOC_SINGLE_EXT("ADMAIF" #reg " Channels", reg - 1, 0, 16, 0, \ - tegra210_admaif_get_channels, tegra210_admaif_put_channels) + tegra210_admaif_get_format, tegra210_admaif_put_format) + +#define TEGRA210_ADMAIF_TX_CIF_CTRL(reg) \ + SOC_ENUM_EXT("ADMAIF" #reg " TX mono to stereo conv", \ + tegra_admaif_mono_conv_enum, tegra210_admaif_get_format, \ + tegra210_admaif_put_format) + +#define TEGRA210_ADMAIF_RX_CIF_CTRL(reg) \ + SOC_ENUM_EXT("ADMAIF" #reg " RX stereo to mono conv", \ + tegra_admaif_stereo_conv_enum, tegra210_admaif_get_format, \ + tegra210_admaif_put_format) static struct snd_kcontrol_new tegra210_admaif_controls[] = { TEGRA210_ADMAIF_CHANNEL_CTRL(1), @@ -753,7 +838,51 @@ static struct snd_kcontrol_new tegra210_admaif_controls[] = { TEGRA210_ADMAIF_CHANNEL_CTRL(17), TEGRA210_ADMAIF_CHANNEL_CTRL(18), TEGRA210_ADMAIF_CHANNEL_CTRL(19), - TEGRA210_ADMAIF_CHANNEL_CTRL(20) + TEGRA210_ADMAIF_CHANNEL_CTRL(20), +#endif + TEGRA210_ADMAIF_RX_CIF_CTRL(1), + TEGRA210_ADMAIF_RX_CIF_CTRL(2), + TEGRA210_ADMAIF_RX_CIF_CTRL(3), + TEGRA210_ADMAIF_RX_CIF_CTRL(4), + TEGRA210_ADMAIF_RX_CIF_CTRL(5), + TEGRA210_ADMAIF_RX_CIF_CTRL(6), + TEGRA210_ADMAIF_RX_CIF_CTRL(7), + TEGRA210_ADMAIF_RX_CIF_CTRL(8), + TEGRA210_ADMAIF_RX_CIF_CTRL(9), + TEGRA210_ADMAIF_RX_CIF_CTRL(10), +#if defined(CONFIG_ARCH_TEGRA_18x_SOC) + TEGRA210_ADMAIF_RX_CIF_CTRL(11), + TEGRA210_ADMAIF_RX_CIF_CTRL(12), + TEGRA210_ADMAIF_RX_CIF_CTRL(13), + TEGRA210_ADMAIF_RX_CIF_CTRL(14), + TEGRA210_ADMAIF_RX_CIF_CTRL(15), + TEGRA210_ADMAIF_RX_CIF_CTRL(16), + TEGRA210_ADMAIF_RX_CIF_CTRL(17), + TEGRA210_ADMAIF_RX_CIF_CTRL(18), + TEGRA210_ADMAIF_RX_CIF_CTRL(19), + TEGRA210_ADMAIF_RX_CIF_CTRL(20), +#endif + TEGRA210_ADMAIF_TX_CIF_CTRL(1), + TEGRA210_ADMAIF_TX_CIF_CTRL(2), + TEGRA210_ADMAIF_TX_CIF_CTRL(3), + TEGRA210_ADMAIF_TX_CIF_CTRL(4), + TEGRA210_ADMAIF_TX_CIF_CTRL(5), + TEGRA210_ADMAIF_TX_CIF_CTRL(6), + TEGRA210_ADMAIF_TX_CIF_CTRL(7), + TEGRA210_ADMAIF_TX_CIF_CTRL(8), + TEGRA210_ADMAIF_TX_CIF_CTRL(9), + TEGRA210_ADMAIF_TX_CIF_CTRL(10), +#if defined(CONFIG_ARCH_TEGRA_18x_SOC) + TEGRA210_ADMAIF_TX_CIF_CTRL(11), + TEGRA210_ADMAIF_TX_CIF_CTRL(12), + TEGRA210_ADMAIF_TX_CIF_CTRL(13), + TEGRA210_ADMAIF_TX_CIF_CTRL(14), + TEGRA210_ADMAIF_TX_CIF_CTRL(15), + TEGRA210_ADMAIF_TX_CIF_CTRL(16), + TEGRA210_ADMAIF_TX_CIF_CTRL(17), + TEGRA210_ADMAIF_TX_CIF_CTRL(18), + TEGRA210_ADMAIF_TX_CIF_CTRL(19), + TEGRA210_ADMAIF_TX_CIF_CTRL(20), #endif }; diff --git a/sound/soc/tegra-alt/tegra210_amx_alt.c b/sound/soc/tegra-alt/tegra210_amx_alt.c index 24be653d..809b223b 100644 --- a/sound/soc/tegra-alt/tegra210_amx_alt.c +++ b/sound/soc/tegra-alt/tegra210_amx_alt.c @@ -319,11 +319,15 @@ static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai, memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); + channels = params_channels(params); + if (strstr(dai->name, "OUT")) { channels = amx->output_channels > 0 ? - amx->output_channels : params_channels(params); - } else - channels = params_channels(params); + amx->output_channels : channels; + } else { + channels = amx->input_channels[dai->id] > 0 ? + amx->input_channels[dai->id] : channels; + } if (channels < 1 || channels > 16) return -EINVAL; @@ -513,28 +517,49 @@ static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol, return 0; } -static int tegra210_amx_get_output_channels(struct snd_kcontrol *kcontrol, +static int tegra210_amx_get_channels(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec); + int reg = mc->reg; + char buf[50]; + + snprintf(buf, 50, "Input%d Channels", reg); + if (strstr(kcontrol->id.name, buf)) + ucontrol->value.integer.value[0] = amx->input_channels[reg - 1]; + else if (strstr(kcontrol->id.name, "Output Channels")) + ucontrol->value.integer.value[0] = amx->output_channels; - ucontrol->value.integer.value[0] = amx->output_channels; return 0; } -static int tegra210_amx_put_output_channels(struct snd_kcontrol *kcontrol, +static int tegra210_amx_put_channels(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec); + int reg = mc->reg; int value = ucontrol->value.integer.value[0]; + char buf[50]; - if (value > 0 && value <= 16) { - amx->output_channels = value; - return 0; - } else - return -EINVAL; + snprintf(buf, 50, "Input%d Channels", reg); + if (strstr(kcontrol->id.name, buf)) { + if (value > 0 && value <= 16) + amx->input_channels[reg - 1] = value; + else + return -EINVAL; + } else if (strstr(kcontrol->id.name, "Output Channels")) { + if (value > 0 && value <= 16) + amx->output_channels = value; + else + return -EINVAL; + } + return 0; } static int tegra210_amx_codec_probe(struct snd_soc_codec *codec) @@ -618,8 +643,13 @@ static const struct snd_soc_dapm_route tegra210_amx_routes[] = { #define TEGRA210_AMX_OUTPUT_CHANNELS_CTRL(reg) \ SOC_SINGLE_EXT("Output Channels", reg, 0, 16, 0, \ - tegra210_amx_get_output_channels, \ - tegra210_amx_put_output_channels) + tegra210_amx_get_channels, \ + tegra210_amx_put_channels) + +#define TEGRA210_AMX_INPUT_CHANNELS_CTRL(reg) \ + SOC_SINGLE_EXT("Input" #reg " Channels", reg, 0, 16, 0, \ + tegra210_amx_get_channels, \ + tegra210_amx_put_channels) static struct snd_kcontrol_new tegra210_amx_controls[] = { TEGRA210_AMX_BYTE_MAP_CTRL(0), @@ -688,6 +718,10 @@ static struct snd_kcontrol_new tegra210_amx_controls[] = { TEGRA210_AMX_BYTE_MAP_CTRL(63), TEGRA210_AMX_OUTPUT_CHANNELS_CTRL(1), + TEGRA210_AMX_INPUT_CHANNELS_CTRL(1), + TEGRA210_AMX_INPUT_CHANNELS_CTRL(2), + TEGRA210_AMX_INPUT_CHANNELS_CTRL(3), + TEGRA210_AMX_INPUT_CHANNELS_CTRL(4), }; static struct snd_soc_codec_driver tegra210_amx_codec = { diff --git a/sound/soc/tegra-alt/tegra210_dmic_alt.c b/sound/soc/tegra-alt/tegra210_dmic_alt.c index 08393d4d..f6385c57 100644 --- a/sound/soc/tegra-alt/tegra210_dmic_alt.c +++ b/sound/soc/tegra-alt/tegra210_dmic_alt.c @@ -154,7 +154,6 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream, memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); - channels = params_channels(params); srate = params_rate(params); dmic_clk = (1 << (6+osr)) * srate; @@ -166,6 +165,17 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream, channel_select = dmic->ch_select; } + cif_conf.client_channels = channels; + 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; + } + if ((tegra_platform_is_unit_fpga() || tegra_platform_is_fpga())) { program_dmic_gpio(); program_dmic_clk(dmic_clk); @@ -241,9 +251,6 @@ static int tegra210_dmic_hw_params(struct snd_pcm_substream *substream, regmap_write(dmic->regmap, TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x00000000); - cif_conf.audio_channels = channels; - cif_conf.client_channels = channels; - switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: cif_conf.audio_bits = TEGRA210_AUDIOCIF_BITS_16; @@ -274,6 +281,9 @@ static int tegra210_dmic_get_control(struct snd_kcontrol *kcontrol, ucontrol->value.integer.value[0] = dmic->boost_gain; else if (strstr(kcontrol->id.name, "Mono")) 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; return 0; } @@ -283,11 +293,14 @@ static int tegra210_dmic_put_control(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tegra210_dmic *dmic = snd_soc_codec_get_drvdata(codec); + int value = ucontrol->value.integer.value[0]; if (strstr(kcontrol->id.name, "Boost")) - dmic->boost_gain = ucontrol->value.integer.value[0]; + dmic->boost_gain = value; else if (strstr(kcontrol->id.name, "Mono")) dmic->ch_select = ucontrol->value.integer.value[0]; + else if (strstr(kcontrol->id.name, "TX mono to stereo")) + dmic->tx_mono_to_stereo = value; return 0; } @@ -349,16 +362,29 @@ static const struct snd_soc_dapm_route tegra210_dmic_routes[] = { static const char * const tegra210_dmic_ch_select[] = { "None", "L", "R", }; + static const struct soc_enum tegra210_dmic_ch_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_dmic_ch_select), tegra210_dmic_ch_select); + +static const char * const tegra210_dmic_mono_conv_text[] = { + "None", "ZERO", "COPY", +}; + +static const struct soc_enum tegra210_dmic_mono_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra210_dmic_mono_conv_text), + tegra210_dmic_mono_conv_text); + static const struct snd_kcontrol_new tegra210_dmic_controls[] = { SOC_SINGLE_EXT("Boost Gain", 0, 0, 25600, 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, + tegra210_dmic_get_control, tegra210_dmic_put_control), + }; static struct snd_soc_codec_driver tegra210_dmic_codec = { .probe = tegra210_dmic_codec_probe, diff --git a/sound/soc/tegra-alt/tegra210_mixer_alt.c b/sound/soc/tegra-alt/tegra210_mixer_alt.c index 9dca99b9..291efd7f 100644 --- a/sound/soc/tegra-alt/tegra210_mixer_alt.c +++ b/sound/soc/tegra-alt/tegra210_mixer_alt.c @@ -141,6 +141,39 @@ static int tegra210_mixer_write_ram(struct tegra210_mixer *mixer, return 0; } +static int tegra210_mixer_put_format(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tegra210_mixer *mixer = snd_soc_codec_get_drvdata(codec); + int value = ucontrol->value.integer.value[0]; + + if (strstr(kcontrol->id.name, "Channels")) { + if (value > 0 && value <= 8) + mixer->channels_via_control[mc->reg - 1] = value; + else + return -EINVAL; + } + + return 0; +} + +static int tegra210_mixer_get_format(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tegra210_mixer *mixer = snd_soc_codec_get_drvdata(codec); + + if (strstr(kcontrol->id.name, "Channels")) + ucontrol->value.integer.value[0] = + mixer->channels_via_control[mc->reg - 1]; + + return 0; +} static int tegra210_mixer_get_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -189,7 +222,8 @@ static int tegra210_mixer_put_gain(struct snd_kcontrol *kcontrol, static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer, struct snd_pcm_hw_params *params, - unsigned int reg) + unsigned int reg, + unsigned int id) { int channels, audio_bits; struct tegra210_xbar_cif_conf cif_conf; @@ -197,8 +231,9 @@ static int tegra210_mixer_set_audio_cif(struct tegra210_mixer *mixer, memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); channels = params_channels(params); - if (channels < 2) - return -EINVAL; + + if (mixer->channels_via_control[id]) + channels = mixer->channels_via_control[id]; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -230,7 +265,8 @@ static int tegra210_mixer_in_hw_params(struct snd_pcm_substream *substream, ret = tegra210_mixer_set_audio_cif(mixer, params, TEGRA210_MIXER_AXBAR_RX1_CIF_CTRL + - (dai->id * TEGRA210_MIXER_AXBAR_RX_STRIDE)); + (dai->id * TEGRA210_MIXER_AXBAR_RX_STRIDE), + dai->id); /* write the gain config poly coefficients */ for (i = 0; i < 14; i++) { @@ -261,7 +297,8 @@ static int tegra210_mixer_out_hw_params(struct snd_pcm_substream *substream, ret = tegra210_mixer_set_audio_cif(mixer, params, TEGRA210_MIXER_AXBAR_TX1_CIF_CTRL + - ((dai->id-10) * TEGRA210_MIXER_AXBAR_TX_STRIDE)); + ((dai->id-10) * TEGRA210_MIXER_AXBAR_TX_STRIDE), + dai->id); return ret; } @@ -394,6 +431,36 @@ static const struct snd_kcontrol_new tegra210_mixer_gain_ctls[] = { \ 0x20000, 0, tegra210_mixer_get_gain, tegra210_mixer_put_gain), SOC_SINGLE_EXT("RX10 Gain Instant", MIXER_GAIN_CONFIG_RAM_ADDR(9), 0, 0x20000, 0, tegra210_mixer_get_gain, tegra210_mixer_put_gain), + SOC_SINGLE_EXT("RX1 Channels", 1, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("RX2 Channels", 2, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("RX3 Channels", 3, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("RX4 Channels", 4, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("RX5 Channels", 5, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("RX6 Channels", 6, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("RX7 Channels", 7, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("RX8 Channels", 8, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("RX9 Channels", 9, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("RX10 Channels", 10, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("TX1 Channels", 11, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("TX2 Channels", 12, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("TX3 Channels", 13, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("TX4 Channels", 14, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), + SOC_SINGLE_EXT("TX5 Channels", 15, 0, 8, 0, + tegra210_mixer_get_format, tegra210_mixer_put_format), SOC_SINGLE("Mixer Enable", TEGRA210_MIXER_ENABLE, 0, 1, 0), }; diff --git a/sound/soc/tegra-alt/tegra210_mvc_alt.c b/sound/soc/tegra-alt/tegra210_mvc_alt.c index 54df6e3e..75c891c4 100644 --- a/sound/soc/tegra-alt/tegra210_mvc_alt.c +++ b/sound/soc/tegra-alt/tegra210_mvc_alt.c @@ -325,7 +325,7 @@ static int tegra210_mvc_put_channels(struct snd_kcontrol *kcontrol, unsigned int val; val = ucontrol->value.integer.value[0]; - if ((val > 0) && (val << 16)) + if ((val > 0) && (val <= 8)) mvc->cif_channels = val; else return -EINVAL; diff --git a/sound/soc/tegra-alt/tegra210_sfc_alt.c b/sound/soc/tegra-alt/tegra210_sfc_alt.c index a3553178..4fb448a8 100644 --- a/sound/soc/tegra-alt/tegra210_sfc_alt.c +++ b/sound/soc/tegra-alt/tegra210_sfc_alt.c @@ -301,8 +301,6 @@ static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc, memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); channels = params_channels(params); - if (channels < 2) - return -EINVAL; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -315,6 +313,9 @@ static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc, return -EINVAL; } + if (sfc->channels_via_control) + channels = sfc->channels_via_control; + if (sfc->stereo_conv_input > 0 && 2 == channels && (reg == TEGRA210_SFC_AXBAR_RX_CIF_CTRL)) { cif_conf.stereo_conv = sfc->stereo_conv_input - 1; @@ -473,9 +474,10 @@ static int tegra210_sfc_get_format(struct snd_kcontrol *kcontrol, /* get the format control flag */ if (strstr(kcontrol->id.name, "input")) ucontrol->value.integer.value[0] = sfc->format_in; - - if (strstr(kcontrol->id.name, "output")) + else if (strstr(kcontrol->id.name, "output")) ucontrol->value.integer.value[0] = sfc->format_out; + else if (strstr(kcontrol->id.name, "Channels")) + ucontrol->value.integer.value[0] = sfc->channels_via_control; return 0; } @@ -485,13 +487,19 @@ static int tegra210_sfc_put_format(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tegra210_sfc *sfc = snd_soc_codec_get_drvdata(codec); + int value = ucontrol->value.integer.value[0]; /* set the format control flag */ if (strstr(kcontrol->id.name, "input")) - sfc->format_in = ucontrol->value.integer.value[0]; - - if (strstr(kcontrol->id.name, "output")) - sfc->format_out = ucontrol->value.integer.value[0]; + sfc->format_in = value; + else if (strstr(kcontrol->id.name, "output")) + sfc->format_out = value; + else if (strstr(kcontrol->id.name, "Channels")) { + if (value > 0 && value <= 2) + sfc->channels_via_control = value; + else + return -EINVAL; + } return 0; } @@ -657,7 +665,7 @@ static struct snd_soc_dai_driver tegra210_sfc_dais[] = { .capture = { .stream_name = "SFC Transmit", .channels_min = 1, - .channels_max = 16, + .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_96000, .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | @@ -719,6 +727,8 @@ static const struct snd_kcontrol_new tegra210_sfc_controls[] = { tegra210_sfc_get_format, tegra210_sfc_put_format), SOC_ENUM_EXT("output bit format", tegra210_sfc_format_enum, tegra210_sfc_get_format, tegra210_sfc_put_format), + SOC_SINGLE_EXT("Channels", 0, 0, 2, 0, + tegra210_sfc_get_format, tegra210_sfc_put_format), SOC_SINGLE_EXT("init", 0, 0, 1, 0, tegra210_sfc_init_get, tegra210_sfc_init_put), SOC_ENUM_EXT("input stereo conv", tegra210_sfc_stereo_conv_enum,