diff --git a/sound/soc/tegra-alt/tegra210_admaif_alt.c b/sound/soc/tegra-alt/tegra210_admaif_alt.c index 5bceba9f..1b297aac 100644 --- a/sound/soc/tegra-alt/tegra210_admaif_alt.c +++ b/sound/soc/tegra-alt/tegra210_admaif_alt.c @@ -32,10 +32,10 @@ #include "tegra_pcm_alt.h" #include "tegra210_xbar_alt.h" -#include "tegra210_admaif_alt.h" #if defined(CONFIG_ARCH_TEGRA_18x_SOC) #include #endif +#include "tegra210_admaif_alt.h" #define DRV_NAME "tegra210-ape-admaif" @@ -300,8 +300,13 @@ static int tegra210_admaif_hw_params(struct snd_pcm_substream *substream, int valid_bit; memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); - cif_conf.audio_channels = params_channels(params); - cif_conf.client_channels = params_channels(params); + 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); + } switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: @@ -462,6 +467,34 @@ static struct snd_soc_dai_ops tegra210_admaif_dai_ops = { .trigger = tegra210_admaif_trigger, }; +static int tegra210_admaif_get_channels(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct tegra210_admaif *admaif = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = admaif->override_channels[mc->reg]; + return 0; +} + +static int tegra210_admaif_put_channels(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_kcontrol_chip(kcontrol); + struct tegra210_admaif *admaif = snd_soc_codec_get_drvdata(codec); + int value = ucontrol->value.integer.value[0]; + + if (value > 0 && value <= 16) { + admaif->override_channels[mc->reg] = value; + return 0; + } else + return -EINVAL; +} + static int tegra210_admaif_dai_probe(struct snd_soc_dai *dai) { struct tegra210_admaif *admaif = snd_soc_dai_get_drvdata(dai); @@ -680,6 +713,33 @@ static const struct snd_soc_dapm_route tegra210_admaif_routes[] = { ADMAIF_ROUTES(20) }; +#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) + +static struct snd_kcontrol_new tegra210_admaif_controls[] = { + TEGRA210_ADMAIF_CHANNEL_CTRL(1), + TEGRA210_ADMAIF_CHANNEL_CTRL(2), + TEGRA210_ADMAIF_CHANNEL_CTRL(3), + TEGRA210_ADMAIF_CHANNEL_CTRL(4), + TEGRA210_ADMAIF_CHANNEL_CTRL(5), + TEGRA210_ADMAIF_CHANNEL_CTRL(6), + TEGRA210_ADMAIF_CHANNEL_CTRL(7), + TEGRA210_ADMAIF_CHANNEL_CTRL(8), + TEGRA210_ADMAIF_CHANNEL_CTRL(9), + TEGRA210_ADMAIF_CHANNEL_CTRL(10), + TEGRA210_ADMAIF_CHANNEL_CTRL(11), + TEGRA210_ADMAIF_CHANNEL_CTRL(12), + TEGRA210_ADMAIF_CHANNEL_CTRL(13), + TEGRA210_ADMAIF_CHANNEL_CTRL(14), + TEGRA210_ADMAIF_CHANNEL_CTRL(15), + TEGRA210_ADMAIF_CHANNEL_CTRL(16), + TEGRA210_ADMAIF_CHANNEL_CTRL(17), + TEGRA210_ADMAIF_CHANNEL_CTRL(18), + TEGRA210_ADMAIF_CHANNEL_CTRL(19), + TEGRA210_ADMAIF_CHANNEL_CTRL(20) +}; + static int tegra210_admaif_codec_probe(struct snd_soc_codec *codec) { struct tegra210_admaif *admaif = snd_soc_codec_get_drvdata(codec); @@ -695,6 +755,8 @@ static struct snd_soc_codec_driver tegra210_admaif_codec = { .num_dapm_widgets = TEGRA210_ADMAIF_CHANNEL_COUNT * 4, .dapm_routes = tegra210_admaif_routes, .num_dapm_routes = TEGRA210_ADMAIF_CHANNEL_COUNT * 6, + .controls = tegra210_admaif_controls, + .num_controls = ARRAY_SIZE(tegra210_admaif_controls), .idle_bias_off = 1, }; @@ -748,7 +810,7 @@ static int tegra210_admaif_probe(struct platform_device *pdev) admaif->soc_data->num_ch, GFP_KERNEL); if (!admaif->capture_dma_data) { - dev_err(&pdev->dev, "Can't allocate tegra_alt_pcm_dma_params\n"); + dev_err(&pdev->dev, "Can't allocate capture_dma_data\n"); ret = -ENOMEM; goto err; } @@ -758,7 +820,7 @@ static int tegra210_admaif_probe(struct platform_device *pdev) admaif->soc_data->num_ch, GFP_KERNEL); if (!admaif->playback_dma_data) { - dev_err(&pdev->dev, "Can't allocate tegra_alt_pcm_dma_params\n"); + dev_err(&pdev->dev, "Can't allocate playback_dma_data\n"); ret = -ENOMEM; goto err; } diff --git a/sound/soc/tegra-alt/tegra210_amx_alt.c b/sound/soc/tegra-alt/tegra210_amx_alt.c index c0e6d5ac..cc33e1ae 100644 --- a/sound/soc/tegra-alt/tegra210_amx_alt.c +++ b/sound/soc/tegra-alt/tegra210_amx_alt.c @@ -311,16 +311,22 @@ static int tegra210_amx_suspend(struct device *dev) } #endif -static int tegra210_amx_set_audio_cif(struct tegra210_amx *amx, +static int tegra210_amx_set_audio_cif(struct snd_soc_dai *dai, struct snd_pcm_hw_params *params, unsigned int reg) { + struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); int channels, audio_bits; struct tegra210_xbar_cif_conf cif_conf; 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); + if (channels < 1 || channels > 16) return -EINVAL; @@ -351,15 +357,13 @@ static int tegra210_amx_set_audio_cif(struct tegra210_amx *amx, return 0; } - static int tegra210_amx_in_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); int ret; - ret = tegra210_amx_set_audio_cif(amx, params, + ret = tegra210_amx_set_audio_cif(dai, params, TEGRA210_AMX_AXBAR_RX1_CIF_CTRL + (dai->id * TEGRA210_AMX_AUDIOCIF_CH_STRIDE)); @@ -394,17 +398,17 @@ static int tegra210_amx_out_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); int ret; if (tegra_platform_is_unit_fpga() || tegra_platform_is_fpga()) { /* update map ram */ + struct tegra210_amx *amx = snd_soc_dai_get_drvdata(dai); tegra210_amx_set_master_stream(amx, 0, TEGRA210_AMX_WAIT_ON_ANY); tegra210_amx_update_map_ram(amx); tegra210_amx_set_out_byte_mask(amx); } - ret = tegra210_amx_set_audio_cif(amx, params, + ret = tegra210_amx_set_audio_cif(dai, params, TEGRA210_AMX_AXBAR_TX_CIF_CTRL); return ret; @@ -493,24 +497,39 @@ static int tegra210_amx_put_byte_map(struct snd_kcontrol *kcontrol, /* update byte map */ tegra210_amx_set_map_table(amx, reg, stream, channel, byte); - /* update byte_mask */ - if (value) { - /* enable slot */ - if (reg > 31) - amx->byte_mask[1] |= (1 << (reg - 32)); - else - amx->byte_mask[0] |= (1 << reg); - } else { - /* disable slot */ - if (reg > 31) - amx->byte_mask[1] &= ~(1 << (reg - 32)); - else - amx->byte_mask[0] &= ~(1 << reg); - } + /* update byte_mask to enable slot */ + if (reg > 31) + amx->byte_mask[1] |= (1 << (reg - 32)); + else + amx->byte_mask[0] |= (1 << reg); return 0; } +static int tegra210_amx_get_output_channels(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = amx->output_channels; + return 0; +} + +static int tegra210_amx_put_output_channels(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec); + int value = ucontrol->value.integer.value[0]; + + if (value > 0 && value <= 16) { + amx->output_channels = value; + return 0; + } else + return -EINVAL; +} + static int tegra210_amx_codec_probe(struct snd_soc_codec *codec) { struct tegra210_amx *amx = snd_soc_codec_get_drvdata(codec); @@ -590,7 +609,12 @@ static const struct snd_soc_dapm_route tegra210_amx_routes[] = { SOC_SINGLE_EXT("Byte Map " #reg, reg, 0, 0xFF, 0, \ tegra210_amx_get_byte_map, tegra210_amx_put_byte_map) -static struct snd_kcontrol_new tegra210_amx_map_controls[] = { +#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) + +static struct snd_kcontrol_new tegra210_amx_controls[] = { TEGRA210_AMX_BYTE_MAP_CTRL(0), TEGRA210_AMX_BYTE_MAP_CTRL(1), TEGRA210_AMX_BYTE_MAP_CTRL(2), @@ -655,6 +679,8 @@ static struct snd_kcontrol_new tegra210_amx_map_controls[] = { TEGRA210_AMX_BYTE_MAP_CTRL(61), TEGRA210_AMX_BYTE_MAP_CTRL(62), TEGRA210_AMX_BYTE_MAP_CTRL(63), + + TEGRA210_AMX_OUTPUT_CHANNELS_CTRL(1), }; static struct snd_soc_codec_driver tegra210_amx_codec = { @@ -663,8 +689,8 @@ static struct snd_soc_codec_driver tegra210_amx_codec = { .num_dapm_widgets = ARRAY_SIZE(tegra210_amx_widgets), .dapm_routes = tegra210_amx_routes, .num_dapm_routes = ARRAY_SIZE(tegra210_amx_routes), - .controls = tegra210_amx_map_controls, - .num_controls = ARRAY_SIZE(tegra210_amx_map_controls), + .controls = tegra210_amx_controls, + .num_controls = ARRAY_SIZE(tegra210_amx_controls), .idle_bias_off = 1, }; diff --git a/sound/soc/tegra-alt/tegra210_sfc_alt.c b/sound/soc/tegra-alt/tegra210_sfc_alt.c index f1abe278..8a4120d4 100644 --- a/sound/soc/tegra-alt/tegra210_sfc_alt.c +++ b/sound/soc/tegra-alt/tegra210_sfc_alt.c @@ -311,8 +311,19 @@ static int tegra210_sfc_set_audio_cif(struct tegra210_sfc *sfc, return -EINVAL; } + if (sfc->stereo_conv_input > 0 && 2 == channels && + (reg == TEGRA210_SFC_AXBAR_RX_CIF_CTRL)) { + cif_conf.stereo_conv = sfc->stereo_conv_input - 1; + cif_conf.client_channels = 1; + } else if (sfc->mono_conv_output > 0 && 2 == channels && + (reg == TEGRA210_SFC_AXBAR_TX_CIF_CTRL)) { + cif_conf.mono_conv = sfc->mono_conv_output - 1; + cif_conf.client_channels = 1; + } else { + cif_conf.client_channels = channels; + } + cif_conf.audio_channels = channels; - cif_conf.client_channels = channels; cif_conf.audio_bits = audio_bits; if (sfc->format_in && (reg == TEGRA210_SFC_AXBAR_RX_CIF_CTRL)) cif_conf.audio_bits = tegra210_sfc_fmt_values[sfc->format_in]; @@ -556,6 +567,46 @@ static int tegra210_sfc_init_put(struct snd_kcontrol *kcontrol, return 0; } +static int tegra210_sfc_get_stereo_conv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_sfc *sfc = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = sfc->stereo_conv_input; + return 0; +} + +static int tegra210_sfc_put_stereo_conv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_sfc *sfc = snd_soc_codec_get_drvdata(codec); + + sfc->stereo_conv_input = ucontrol->value.integer.value[0]; + return 0; +} + +static int tegra210_sfc_get_mono_conv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_sfc *sfc = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = sfc->mono_conv_output; + return 0; +} + +static int tegra210_sfc_put_mono_conv(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct tegra210_sfc *sfc = snd_soc_codec_get_drvdata(codec); + + sfc->mono_conv_output = ucontrol->value.integer.value[0]; + return 0; +} + static int tegra210_sfc_codec_probe(struct snd_soc_codec *codec) { struct tegra210_sfc *sfc = snd_soc_codec_get_drvdata(codec); @@ -624,11 +675,29 @@ static const char * const tegra210_sfc_format_text[] = { "32", }; +static const char * const tegra210_sfc_stereo_conv_text[] = { + "None", "CH0", "CH1", "AVG", +}; + +static const char * const tegra210_sfc_mono_conv_text[] = { + "None", "ZERO", "COPY", +}; + static const struct soc_enum tegra210_sfc_format_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(tegra210_sfc_format_text), tegra210_sfc_format_text); +static const struct soc_enum tegra210_sfc_stereo_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra210_sfc_stereo_conv_text), + tegra210_sfc_stereo_conv_text); + +static const struct soc_enum tegra210_sfc_mono_conv_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, + ARRAY_SIZE(tegra210_sfc_mono_conv_text), + tegra210_sfc_mono_conv_text); + static const struct snd_kcontrol_new tegra210_sfc_controls[] = { SOC_SINGLE_EXT("input rate", 0, 0, 192000, 0, tegra210_sfc_get_srate, tegra210_sfc_put_srate), @@ -638,6 +707,10 @@ static const struct snd_kcontrol_new tegra210_sfc_controls[] = { 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, + tegra210_sfc_get_stereo_conv, tegra210_sfc_put_stereo_conv), + SOC_ENUM_EXT("output mono conv", tegra210_sfc_mono_conv_enum, + tegra210_sfc_get_mono_conv, tegra210_sfc_put_mono_conv), }; static struct snd_soc_codec_driver tegra210_sfc_codec = {