diff --git a/sound/soc/tegra-alt/include/tegra210_admaif_alt.h b/sound/soc/tegra-alt/include/tegra210_admaif_alt.h index b8befa6c..5afe983e 100644 --- a/sound/soc/tegra-alt/include/tegra210_admaif_alt.h +++ b/sound/soc/tegra-alt/include/tegra210_admaif_alt.h @@ -158,6 +158,11 @@ enum { DATA_32BIT }; +enum { + ADMAIF_RX_PATH, + ADMAIF_TX_PATH, + ADMAIF_PATHS, +}; struct tegra_admaif_soc_data { unsigned int num_ch; @@ -177,9 +182,10 @@ struct tegra_admaif { struct tegra_alt_pcm_dma_params *capture_dma_data; struct tegra_alt_pcm_dma_params *playback_dma_data; const struct tegra_admaif_soc_data *soc_data; - int *override_channels; - int *tx_mono_to_stereo; - int *rx_stereo_to_mono; + unsigned int *audio_ch_override[ADMAIF_PATHS]; + unsigned int *client_ch_override[ADMAIF_PATHS]; + unsigned int *mono_to_stereo[ADMAIF_PATHS]; + unsigned int *stereo_to_mono[ADMAIF_PATHS]; int reg_dump_flag; void __iomem *base_addr; }; diff --git a/sound/soc/tegra-alt/include/tegra210_i2s_alt.h b/sound/soc/tegra-alt/include/tegra210_i2s_alt.h index 42e75444..4c32215a 100644 --- a/sound/soc/tegra-alt/include/tegra210_i2s_alt.h +++ b/sound/soc/tegra-alt/include/tegra210_i2s_alt.h @@ -206,10 +206,11 @@ struct tegra210_i2s { struct notifier_block slgc_notifier; int num_supplies; int bclk_ratio; - int format_in; + int audio_fmt_override[I2S_PATHS]; int codec_bit_format; int sample_rate_via_control; - int channels_via_control; + int audio_ch_override[I2S_PATHS]; + int client_ch_override; /* common for both TX and RX */ int stereo_to_mono[I2S_PATHS]; int mono_to_stereo[I2S_PATHS]; unsigned int fsync_width; diff --git a/sound/soc/tegra-alt/tegra210_admaif_alt.c b/sound/soc/tegra-alt/tegra210_admaif_alt.c index 435e4ef2..d5c7661d 100644 --- a/sound/soc/tegra-alt/tegra210_admaif_alt.c +++ b/sound/soc/tegra-alt/tegra210_admaif_alt.c @@ -318,7 +318,7 @@ static int tegra_admaif_hw_params(struct snd_pcm_substream *substream, struct device *dev = dai->dev; struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai); struct tegra210_xbar_cif_conf cif_conf; - unsigned int reg; + unsigned int reg, path; int valid_bit, channels; memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); @@ -354,40 +354,26 @@ static int tegra_admaif_hw_params(struct snd_pcm_substream *substream, cif_conf.audio_channels = channels; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + path = ADMAIF_TX_PATH; reg = CH_TX_REG(TEGRA_ADMAIF_CHAN_ACIF_TX_CTRL, dai->id); - - /* For playback path, if client channel is 1 and mono to - * stereo control was non-zero, then audio channels will be - * set to 2 for mono to stereo conversion. - */ - if ((admaif->tx_mono_to_stereo[dai->id] > 0) && - (channels == 1)) { - cif_conf.mono_conv = - admaif->tx_mono_to_stereo[dai->id] - 1; - cif_conf.audio_channels = 2; - } } else { + path = ADMAIF_RX_PATH; reg = CH_RX_REG(TEGRA_ADMAIF_CHAN_ACIF_RX_CTRL, dai->id); - - /* The override channels are needed only for capture path as - * the audio and client channels can be different on RX path. - */ - if (admaif->override_channels[dai->id] > 0) { - cif_conf.audio_channels = - admaif->override_channels[dai->id]; - } - - /* For capture path, if client channel is 1 and audio channel - * is 2, only then stereo to mono settings will take effect. - */ - if ((admaif->rx_stereo_to_mono[dai->id] > 0) && - (cif_conf.audio_channels == 2) && (channels == 1)) { - cif_conf.stereo_conv = - admaif->rx_stereo_to_mono[dai->id] - 1; - } } + if (admaif->audio_ch_override[path][dai->id]) + cif_conf.audio_channels = + admaif->audio_ch_override[path][dai->id]; + + if (admaif->client_ch_override[path][dai->id]) + cif_conf.client_channels = + admaif->client_ch_override[path][dai->id]; + + cif_conf.mono_conv = admaif->mono_to_stereo[path][dai->id]; + cif_conf.stereo_conv = admaif->stereo_to_mono[path][dai->id]; + tegra_admaif_set_pack_mode(admaif->regmap, reg, valid_bit); + tegra210_xbar_set_cif(admaif->regmap, reg, &cif_conf); return 0; @@ -504,29 +490,26 @@ static int tegra_admaif_get_format(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec); - int i; - char buf[50]; + long *uctl_val = &ucontrol->value.integer.value[0]; - if (strstr(kcontrol->id.name, "Channels")) - ucontrol->value.integer.value[0] = - admaif->override_channels[mc->reg]; - else { - for (i = 0 ; i < admaif->soc_data->num_ch; i++) { - snprintf(buf, 50, "ADMAIF%d Capture 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 Playback mono to stereo", i+1); - if (strstr(kcontrol->id.name, buf)) { - ucontrol->value.integer.value[0] = - admaif->tx_mono_to_stereo[i]; - break; - } - } - } + if (strstr(kcontrol->id.name, "Playback Audio Channels")) + *uctl_val = admaif->audio_ch_override[ADMAIF_TX_PATH][mc->reg]; + else if (strstr(kcontrol->id.name, "Capture Audio Channels")) + *uctl_val = admaif->audio_ch_override[ADMAIF_RX_PATH][mc->reg]; + else if (strstr(kcontrol->id.name, "Playback Client Channels")) + *uctl_val = admaif->client_ch_override[ADMAIF_TX_PATH][mc->reg]; + else if (strstr(kcontrol->id.name, "Capture Client Channels")) + *uctl_val = admaif->client_ch_override[ADMAIF_RX_PATH][mc->reg]; + else if (strstr(kcontrol->id.name, "Playback mono to stereo")) + *uctl_val = admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg]; + else if (strstr(kcontrol->id.name, "Playback stereo to mono")) + *uctl_val = admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg]; + else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + *uctl_val = admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg]; + else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + *uctl_val = admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg]; return 0; } @@ -536,31 +519,27 @@ static int tegra_admaif_put_format(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; + struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value; struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tegra_admaif *admaif = snd_soc_codec_get_drvdata(codec); int value = ucontrol->value.integer.value[0]; - int i; - char buf[50]; - 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 < admaif->soc_data->num_ch; i++) { - snprintf(buf, 50, "ADMAIF%d Capture stereo to mono", i+1); - if (strstr(kcontrol->id.name, buf)) { - admaif->rx_stereo_to_mono[i] = value; - break; - } - snprintf(buf, 50, "ADMAIF%d Playback mono to stereo", i+1); - if (strstr(kcontrol->id.name, buf)) { - admaif->tx_mono_to_stereo[i] = value; - break; - } - } - } + if (strstr(kcontrol->id.name, "Playback Audio Channels")) + admaif->audio_ch_override[ADMAIF_TX_PATH][mc->reg] = value; + else if (strstr(kcontrol->id.name, "Capture Audio Channels")) + admaif->audio_ch_override[ADMAIF_RX_PATH][mc->reg] = value; + else if (strstr(kcontrol->id.name, "Playback Client Channels")) + admaif->client_ch_override[ADMAIF_TX_PATH][mc->reg] = value; + else if (strstr(kcontrol->id.name, "Capture Client Channels")) + admaif->client_ch_override[ADMAIF_RX_PATH][mc->reg] = value; + else if (strstr(kcontrol->id.name, "Playback mono to stereo")) + admaif->mono_to_stereo[ADMAIF_TX_PATH][ec->reg] = value; + else if (strstr(kcontrol->id.name, "Playback stereo to mono")) + admaif->stereo_to_mono[ADMAIF_TX_PATH][ec->reg] = value; + else if (strstr(kcontrol->id.name, "Capture mono to stereo")) + admaif->mono_to_stereo[ADMAIF_RX_PATH][ec->reg] = value; + else if (strstr(kcontrol->id.name, "Capture stereo to mono")) + admaif->stereo_to_mono[ADMAIF_RX_PATH][ec->reg] = value; return 0; } @@ -886,11 +865,11 @@ static const struct snd_soc_dapm_route tegra_admaif_routes[] = { }; static const char * const tegra_admaif_stereo_conv_text[] = { - "None", "CH0", "CH1", "AVG", + "CH0", "CH1", "AVG", }; static const char * const tegra_admaif_mono_conv_text[] = { - "None", "ZERO", "COPY", + "ZERO", "COPY", }; static const struct soc_enum tegra_admaif_mono_conv_enum = @@ -903,19 +882,48 @@ static const struct soc_enum tegra_admaif_stereo_conv_enum = ARRAY_SIZE(tegra_admaif_stereo_conv_text), tegra_admaif_stereo_conv_text); -#define TEGRA_ADMAIF_CHANNEL_CTRL(reg) \ - SOC_SINGLE_EXT("ADMAIF" #reg " Channels", reg - 1, 0, 16, 0, \ - tegra_admaif_get_format, tegra_admaif_put_format) +#define TEGRA_ADMAIF_CHANNEL_CTRL(reg) \ + SOC_SINGLE_EXT("ADMAIF" #reg " Playback Audio Channels", reg - 1, \ + 0, 16, 0, tegra_admaif_get_format, \ + tegra_admaif_put_format), \ + SOC_SINGLE_EXT("ADMAIF" #reg " Capture Audio Channels", reg - 1, \ + 0, 16, 0, tegra_admaif_get_format, \ + tegra_admaif_put_format), \ + SOC_SINGLE_EXT("ADMAIF" #reg " Playback Client Channels", reg - 1, \ + 0, 16, 0, tegra_admaif_get_format, \ + tegra_admaif_put_format), \ + SOC_SINGLE_EXT("ADMAIF" #reg " Capture Client Channels", reg - 1, \ + 0, 16, 0, tegra_admaif_get_format, \ + tegra_admaif_put_format) -#define TEGRA_ADMAIF_TX_CIF_CTRL(reg) \ - SOC_ENUM_EXT("ADMAIF" #reg " Playback mono to stereo conv", \ - tegra_admaif_mono_conv_enum, tegra_admaif_get_format, \ - tegra_admaif_put_format) +/* + * below macro is added to avoid looping over all ADMAIFx controls related + * to mono/stereo conversions in get()/put() callbacks. + */ +#define NV_SOC_ENUM_EXT(xname, xreg, xhandler_get, xhandler_put, xenum_text) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .info = snd_soc_info_enum_double, \ + .name = xname, \ + .get = xhandler_get, \ + .put = xhandler_put, \ + .private_value = (unsigned long)&(struct soc_enum) \ + SOC_ENUM_SINGLE(xreg, 0, ARRAY_SIZE(xenum_text), xenum_text) \ +} -#define TEGRA_ADMAIF_RX_CIF_CTRL(reg) \ - SOC_ENUM_EXT("ADMAIF" #reg " Capture stereo to mono conv", \ - tegra_admaif_stereo_conv_enum, tegra_admaif_get_format, \ - tegra_admaif_put_format) +#define TEGRA_ADMAIF_CIF_CTRL(reg) \ + NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback mono to stereo conv", reg - 1,\ + tegra_admaif_get_format, tegra_admaif_put_format, \ + tegra_admaif_mono_conv_text), \ + NV_SOC_ENUM_EXT("ADMAIF" #reg " Playback stereo to mono conv", reg - 1,\ + tegra_admaif_get_format, tegra_admaif_put_format, \ + tegra_admaif_stereo_conv_text), \ + NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture mono to stereo conv", reg - 1, \ + tegra_admaif_get_format, tegra_admaif_put_format, \ + tegra_admaif_mono_conv_text), \ + NV_SOC_ENUM_EXT("ADMAIF" #reg " Capture stereo to mono conv", reg - 1, \ + tegra_admaif_get_format, tegra_admaif_put_format, \ + tegra_admaif_stereo_conv_text) static struct snd_kcontrol_new tegra210_admaif_controls[] = { TEGRA_ADMAIF_CHANNEL_CTRL(1), @@ -928,26 +936,16 @@ static struct snd_kcontrol_new tegra210_admaif_controls[] = { TEGRA_ADMAIF_CHANNEL_CTRL(8), TEGRA_ADMAIF_CHANNEL_CTRL(9), TEGRA_ADMAIF_CHANNEL_CTRL(10), - TEGRA_ADMAIF_RX_CIF_CTRL(1), - TEGRA_ADMAIF_RX_CIF_CTRL(2), - TEGRA_ADMAIF_RX_CIF_CTRL(3), - TEGRA_ADMAIF_RX_CIF_CTRL(4), - TEGRA_ADMAIF_RX_CIF_CTRL(5), - TEGRA_ADMAIF_RX_CIF_CTRL(6), - TEGRA_ADMAIF_RX_CIF_CTRL(7), - TEGRA_ADMAIF_RX_CIF_CTRL(8), - TEGRA_ADMAIF_RX_CIF_CTRL(9), - TEGRA_ADMAIF_RX_CIF_CTRL(10), - TEGRA_ADMAIF_TX_CIF_CTRL(1), - TEGRA_ADMAIF_TX_CIF_CTRL(2), - TEGRA_ADMAIF_TX_CIF_CTRL(3), - TEGRA_ADMAIF_TX_CIF_CTRL(4), - TEGRA_ADMAIF_TX_CIF_CTRL(5), - TEGRA_ADMAIF_TX_CIF_CTRL(6), - TEGRA_ADMAIF_TX_CIF_CTRL(7), - TEGRA_ADMAIF_TX_CIF_CTRL(8), - TEGRA_ADMAIF_TX_CIF_CTRL(9), - TEGRA_ADMAIF_TX_CIF_CTRL(10), + TEGRA_ADMAIF_CIF_CTRL(1), + TEGRA_ADMAIF_CIF_CTRL(2), + TEGRA_ADMAIF_CIF_CTRL(3), + TEGRA_ADMAIF_CIF_CTRL(4), + TEGRA_ADMAIF_CIF_CTRL(5), + TEGRA_ADMAIF_CIF_CTRL(6), + TEGRA_ADMAIF_CIF_CTRL(7), + TEGRA_ADMAIF_CIF_CTRL(8), + TEGRA_ADMAIF_CIF_CTRL(9), + TEGRA_ADMAIF_CIF_CTRL(10), SOC_SINGLE_EXT("APE Reg Dump", SND_SOC_NOPM, 0, 1, 0, tegra210_ape_dump_reg_get, tegra210_ape_dump_reg_put), }; @@ -973,46 +971,26 @@ static struct snd_kcontrol_new tegra186_admaif_controls[] = { TEGRA_ADMAIF_CHANNEL_CTRL(18), TEGRA_ADMAIF_CHANNEL_CTRL(19), TEGRA_ADMAIF_CHANNEL_CTRL(20), - TEGRA_ADMAIF_RX_CIF_CTRL(1), - TEGRA_ADMAIF_RX_CIF_CTRL(2), - TEGRA_ADMAIF_RX_CIF_CTRL(3), - TEGRA_ADMAIF_RX_CIF_CTRL(4), - TEGRA_ADMAIF_RX_CIF_CTRL(5), - TEGRA_ADMAIF_RX_CIF_CTRL(6), - TEGRA_ADMAIF_RX_CIF_CTRL(7), - TEGRA_ADMAIF_RX_CIF_CTRL(8), - TEGRA_ADMAIF_RX_CIF_CTRL(9), - TEGRA_ADMAIF_RX_CIF_CTRL(10), - TEGRA_ADMAIF_RX_CIF_CTRL(11), - TEGRA_ADMAIF_RX_CIF_CTRL(12), - TEGRA_ADMAIF_RX_CIF_CTRL(13), - TEGRA_ADMAIF_RX_CIF_CTRL(14), - TEGRA_ADMAIF_RX_CIF_CTRL(15), - TEGRA_ADMAIF_RX_CIF_CTRL(16), - TEGRA_ADMAIF_RX_CIF_CTRL(17), - TEGRA_ADMAIF_RX_CIF_CTRL(18), - TEGRA_ADMAIF_RX_CIF_CTRL(19), - TEGRA_ADMAIF_RX_CIF_CTRL(20), - TEGRA_ADMAIF_TX_CIF_CTRL(1), - TEGRA_ADMAIF_TX_CIF_CTRL(2), - TEGRA_ADMAIF_TX_CIF_CTRL(3), - TEGRA_ADMAIF_TX_CIF_CTRL(4), - TEGRA_ADMAIF_TX_CIF_CTRL(5), - TEGRA_ADMAIF_TX_CIF_CTRL(6), - TEGRA_ADMAIF_TX_CIF_CTRL(7), - TEGRA_ADMAIF_TX_CIF_CTRL(8), - TEGRA_ADMAIF_TX_CIF_CTRL(9), - TEGRA_ADMAIF_TX_CIF_CTRL(10), - TEGRA_ADMAIF_TX_CIF_CTRL(11), - TEGRA_ADMAIF_TX_CIF_CTRL(12), - TEGRA_ADMAIF_TX_CIF_CTRL(13), - TEGRA_ADMAIF_TX_CIF_CTRL(14), - TEGRA_ADMAIF_TX_CIF_CTRL(15), - TEGRA_ADMAIF_TX_CIF_CTRL(16), - TEGRA_ADMAIF_TX_CIF_CTRL(17), - TEGRA_ADMAIF_TX_CIF_CTRL(18), - TEGRA_ADMAIF_TX_CIF_CTRL(19), - TEGRA_ADMAIF_TX_CIF_CTRL(20), + TEGRA_ADMAIF_CIF_CTRL(1), + TEGRA_ADMAIF_CIF_CTRL(2), + TEGRA_ADMAIF_CIF_CTRL(3), + TEGRA_ADMAIF_CIF_CTRL(4), + TEGRA_ADMAIF_CIF_CTRL(5), + TEGRA_ADMAIF_CIF_CTRL(6), + TEGRA_ADMAIF_CIF_CTRL(7), + TEGRA_ADMAIF_CIF_CTRL(8), + TEGRA_ADMAIF_CIF_CTRL(9), + TEGRA_ADMAIF_CIF_CTRL(10), + TEGRA_ADMAIF_CIF_CTRL(11), + TEGRA_ADMAIF_CIF_CTRL(12), + TEGRA_ADMAIF_CIF_CTRL(13), + TEGRA_ADMAIF_CIF_CTRL(14), + TEGRA_ADMAIF_CIF_CTRL(15), + TEGRA_ADMAIF_CIF_CTRL(16), + TEGRA_ADMAIF_CIF_CTRL(17), + TEGRA_ADMAIF_CIF_CTRL(18), + TEGRA_ADMAIF_CIF_CTRL(19), + TEGRA_ADMAIF_CIF_CTRL(20), SOC_SINGLE_EXT("APE Reg Dump", SND_SOC_NOPM, 0, 1, 0, tegra210_ape_dump_reg_get, tegra210_ape_dump_reg_put), }; @@ -1107,23 +1085,31 @@ static int tegra_admaif_probe(struct platform_device *pdev) if (!admaif->playback_dma_data) return -ENOMEM; - admaif->override_channels = devm_kzalloc(&pdev->dev, - sizeof(int) * admaif->soc_data->num_ch, - GFP_KERNEL); - if (!admaif->override_channels) - return -ENOMEM; + for (i = 0; i < ADMAIF_PATHS; i++) { + admaif->audio_ch_override[i] = + devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch, + sizeof(unsigned int), GFP_KERNEL); + if (!admaif->audio_ch_override[i]) + return -ENOMEM; - admaif->tx_mono_to_stereo = devm_kzalloc(&pdev->dev, - sizeof(int) * admaif->soc_data->num_ch, - GFP_KERNEL); - if (!admaif->tx_mono_to_stereo) - return -ENOMEM; + admaif->client_ch_override[i] = + devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch, + sizeof(unsigned int), GFP_KERNEL); + if (!admaif->client_ch_override[i]) + return -ENOMEM; - admaif->rx_stereo_to_mono = devm_kzalloc(&pdev->dev, - sizeof(int) * admaif->soc_data->num_ch, - GFP_KERNEL); - if (!admaif->rx_stereo_to_mono) - return -ENOMEM; + admaif->mono_to_stereo[i] = + devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch, + sizeof(unsigned int), GFP_KERNEL); + if (!admaif->mono_to_stereo[i]) + return -ENOMEM; + + admaif->stereo_to_mono[i] = + devm_kcalloc(&pdev->dev, admaif->soc_data->num_ch, + sizeof(unsigned int), GFP_KERNEL); + if (!admaif->stereo_to_mono[i]) + return -ENOMEM; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(&pdev->dev, res); diff --git a/sound/soc/tegra-alt/tegra210_i2s_alt.c b/sound/soc/tegra-alt/tegra210_i2s_alt.c index ce3af260..3a48f266 100644 --- a/sound/soc/tegra-alt/tegra210_i2s_alt.c +++ b/sound/soc/tegra-alt/tegra210_i2s_alt.c @@ -370,32 +370,35 @@ static int tegra210_i2s_get_format(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct tegra210_i2s *i2s = snd_soc_codec_get_drvdata(codec); + long *uctl_val = &ucontrol->value.integer.value[0]; /* get the format control flag */ - if (strstr(kcontrol->id.name, "input")) - ucontrol->value.integer.value[0] = i2s->format_in; + if (strstr(kcontrol->id.name, "Playback Audio Bit Format")) + *uctl_val = i2s->audio_fmt_override[I2S_RX_PATH]; + else if (strstr(kcontrol->id.name, "Capture Audio Bit Format")) + *uctl_val = i2s->audio_fmt_override[I2S_TX_PATH]; else if (strstr(kcontrol->id.name, "codec")) - ucontrol->value.integer.value[0] = i2s->codec_bit_format; + *uctl_val = i2s->codec_bit_format; else if (strstr(kcontrol->id.name, "Sample Rate")) - ucontrol->value.integer.value[0] = i2s->sample_rate_via_control; - else if (strstr(kcontrol->id.name, "Channels")) - ucontrol->value.integer.value[0] = i2s->channels_via_control; + *uctl_val = i2s->sample_rate_via_control; + else if (strstr(kcontrol->id.name, "Playback Audio Channels")) + *uctl_val = i2s->audio_ch_override[I2S_RX_PATH]; + else if (strstr(kcontrol->id.name, "Capture Audio Channels")) + *uctl_val = i2s->audio_ch_override[I2S_TX_PATH]; + else if (strstr(kcontrol->id.name, "Client Channels")) + *uctl_val = i2s->client_ch_override; else if (strstr(kcontrol->id.name, "Capture stereo to mono")) - ucontrol->value.integer.value[0] = - i2s->stereo_to_mono[I2S_TX_PATH]; + *uctl_val = i2s->stereo_to_mono[I2S_TX_PATH]; else if (strstr(kcontrol->id.name, "Capture mono to stereo")) - ucontrol->value.integer.value[0] = - i2s->mono_to_stereo[I2S_TX_PATH]; + *uctl_val = i2s->mono_to_stereo[I2S_TX_PATH]; else if (strstr(kcontrol->id.name, "Playback stereo to mono")) - ucontrol->value.integer.value[0] = - i2s->stereo_to_mono[I2S_RX_PATH]; + *uctl_val = i2s->stereo_to_mono[I2S_RX_PATH]; else if (strstr(kcontrol->id.name, "Playback mono to stereo")) - ucontrol->value.integer.value[0] = - i2s->mono_to_stereo[I2S_RX_PATH]; + *uctl_val = i2s->mono_to_stereo[I2S_RX_PATH]; else if (strstr(kcontrol->id.name, "Playback FIFO threshold")) - ucontrol->value.integer.value[0] = i2s->rx_fifo_th; + *uctl_val = i2s->rx_fifo_th; else if (strstr(kcontrol->id.name, "BCLK Ratio")) - ucontrol->value.integer.value[0] = i2s->bclk_ratio; + *uctl_val = i2s->bclk_ratio; return 0; } @@ -408,14 +411,20 @@ static int tegra210_i2s_put_format(struct snd_kcontrol *kcontrol, int value = ucontrol->value.integer.value[0]; /* set the format control flag */ - if (strstr(kcontrol->id.name, "input")) - i2s->format_in = value; + if (strstr(kcontrol->id.name, "Playback Audio Bit Format")) + i2s->audio_fmt_override[I2S_RX_PATH] = value; + else if (strstr(kcontrol->id.name, "Capture Audio Bit Format")) + i2s->audio_fmt_override[I2S_TX_PATH] = value; else if (strstr(kcontrol->id.name, "codec")) i2s->codec_bit_format = value; else if (strstr(kcontrol->id.name, "Sample Rate")) i2s->sample_rate_via_control = value; - else if (strstr(kcontrol->id.name, "Channels")) - i2s->channels_via_control = value; + else if (strstr(kcontrol->id.name, "Playback Audio Channels")) + i2s->audio_ch_override[I2S_RX_PATH] = value; + else if (strstr(kcontrol->id.name, "Capture Audio Channels")) + i2s->audio_ch_override[I2S_TX_PATH] = value; + else if (strstr(kcontrol->id.name, "Client Channels")) + i2s->client_ch_override = value; else if (strstr(kcontrol->id.name, "Capture stereo to mono")) i2s->stereo_to_mono[I2S_TX_PATH] = value; else if (strstr(kcontrol->id.name, "Capture mono to stereo")) @@ -512,7 +521,7 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, struct device *dev = dai->dev; struct tegra210_i2s *i2s = snd_soc_dai_get_drvdata(dai); unsigned int mask, val, reg, frame_format, rx_mask, tx_mask; - int ret, sample_size, channels, srate, i2sclock, bitcnt, max_th; + int ret, sample_size, channels, srate, i2sclock, bitcnt, max_th, path; struct tegra210_xbar_cif_conf cif_conf; memset(&cif_conf, 0, sizeof(struct tegra210_xbar_cif_conf)); @@ -523,6 +532,9 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } + cif_conf.audio_channels = channels; + cif_conf.client_channels = channels; + mask = TEGRA210_I2S_CTRL_BIT_SIZE_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: @@ -567,27 +579,37 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, if (i2s->sample_rate_via_control) srate = i2s->sample_rate_via_control; - if (i2s->channels_via_control) { - channels = i2s->channels_via_control; - rx_mask = tx_mask = (1 << channels) - 1; + /* + * For playback I2S RX-CIF and for capture TX-CIF is used. + * With reference to AHUB, for I2S, SNDRV_PCM_STREAM_CAPTURE stream is + * actually for playback. + */ + path = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) ? + I2S_RX_PATH : I2S_TX_PATH; + + if (i2s->audio_ch_override[path]) { + cif_conf.audio_channels = i2s->audio_ch_override[path]; + rx_mask = tx_mask = (1 << cif_conf.audio_channels) - 1; } else { rx_mask = i2s->rx_mask; tx_mask = i2s->tx_mask; } + if (i2s->client_ch_override) + cif_conf.client_channels = i2s->client_ch_override; + + if (i2s->audio_fmt_override[path]) + cif_conf.audio_bits = + tegra210_i2s_fmt_values[i2s->audio_fmt_override[path]]; + regmap_read(i2s->regmap, TEGRA210_I2S_CTRL, &val); frame_format = val & TEGRA210_I2S_CTRL_FRAME_FORMAT_MASK; - if (frame_format == TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE) { - tegra210_i2s_set_slot_ctrl(i2s->regmap, channels, tx_mask, - rx_mask); - cif_conf.audio_channels = channels; - cif_conf.client_channels = channels; - } else { - cif_conf.audio_channels = channels; - cif_conf.client_channels = (channels == 1) ? 2 : channels; - } + if (frame_format == TEGRA210_I2S_CTRL_FRAME_FORMAT_FSYNC_MODE) + tegra210_i2s_set_slot_ctrl(i2s->regmap, + cif_conf.client_channels, + tx_mask, rx_mask); i2sclock = srate * sample_size * cif_conf.client_channels; @@ -620,44 +642,24 @@ static int tegra210_i2s_hw_params(struct snd_pcm_substream *substream, /* As a COCEC DAI, CAPTURE is transmit */ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + unsigned int audio_ch = cif_conf.audio_channels; + reg = TEGRA210_I2S_AXBAR_RX_CIF_CTRL; - if (i2s->mono_to_stereo[I2S_RX_PATH] > 0) { - cif_conf.audio_channels = 1; - cif_conf.client_channels = 2; - cif_conf.mono_conv = - i2s->mono_to_stereo[I2S_RX_PATH] - 1; - } else if (i2s->stereo_to_mono[I2S_RX_PATH] > 0) { - cif_conf.audio_channels = 2; - cif_conf.client_channels = 1; - cif_conf.stereo_conv = - i2s->stereo_to_mono[I2S_RX_PATH] - 1; - } /* RX FIFO threshold interms of frames */ - max_th = (TEGRA210_I2S_RX_FIFO_DEPTH / channels) - 1; - if (i2s->rx_fifo_th > max_th) { /* error handling */ - cif_conf.threshold = max_th; - i2s->rx_fifo_th = max_th; - } else - cif_conf.threshold = i2s->rx_fifo_th; - } else { - if (i2s->mono_to_stereo[I2S_TX_PATH] > 0) { - cif_conf.audio_channels = 2; - cif_conf.client_channels = 1; - cif_conf.mono_conv = - i2s->mono_to_stereo[I2S_TX_PATH] - 1; - } else if (i2s->stereo_to_mono[I2S_TX_PATH] > 0) { - cif_conf.audio_channels = 1; - cif_conf.client_channels = 2; - cif_conf.stereo_conv = - i2s->stereo_to_mono[I2S_TX_PATH] - 1; - } + max_th = (TEGRA210_I2S_RX_FIFO_DEPTH / audio_ch) - 1; + if (max_th < 0) + return -EINVAL; - if (i2s->format_in) - cif_conf.audio_bits = - tegra210_i2s_fmt_values[i2s->format_in]; + if (i2s->rx_fifo_th > max_th) /* error handling */ + i2s->rx_fifo_th = max_th; + + cif_conf.threshold = i2s->rx_fifo_th; + } else reg = TEGRA210_I2S_AXBAR_TX_CIF_CTRL; - } + + cif_conf.stereo_conv = i2s->stereo_to_mono[path]; + cif_conf.mono_conv = i2s->mono_to_stereo[path]; tegra210_xbar_set_cif(i2s->regmap, reg, &cif_conf); @@ -829,11 +831,11 @@ static int tegra210_i2s_fsync_width_put(struct snd_kcontrol *kcontrol, } static const char * const tegra210_i2s_stereo_conv_text[] = { - "None", "CH0", "CH1", "AVG", + "CH0", "CH1", "AVG", }; static const char * const tegra210_i2s_mono_conv_text[] = { - "None", "ZERO", "COPY", + "ZERO", "COPY", }; static const struct soc_enum tegra210_i2s_mono_conv_enum = @@ -856,15 +858,21 @@ static const struct soc_enum tegra210_i2s_stereo_conv_enum = static const struct snd_kcontrol_new tegra210_i2s_controls[] = { SOC_SINGLE_EXT("Loopback", SND_SOC_NOPM, 0, 1, 0, tegra210_i2s_loopback_get, tegra210_i2s_loopback_put), - SOC_ENUM_EXT("input bit format", tegra210_i2s_format_enum, - tegra210_i2s_get_format, tegra210_i2s_put_format), + SOC_ENUM_EXT("Playback Audio Bit Format", tegra210_i2s_format_enum, + tegra210_i2s_get_format, tegra210_i2s_put_format), + SOC_ENUM_EXT("Capture Audio Bit Format", tegra210_i2s_format_enum, + tegra210_i2s_get_format, tegra210_i2s_put_format), SOC_ENUM_EXT("codec bit format", tegra210_i2s_format_enum, tegra210_i2s_get_format, tegra210_i2s_put_format), SOC_SINGLE_EXT("fsync width", SND_SOC_NOPM, 0, 255, 0, tegra210_i2s_fsync_width_get, tegra210_i2s_fsync_width_put), SOC_SINGLE_EXT("Sample Rate", 0, 0, 192000, 0, tegra210_i2s_get_format, tegra210_i2s_put_format), - SOC_SINGLE_EXT("Channels", 0, 0, 16, 0, + SOC_SINGLE_EXT("Playback Audio Channels", 0, 0, 16, 0, + tegra210_i2s_get_format, tegra210_i2s_put_format), + SOC_SINGLE_EXT("Capture Audio Channels", 0, 0, 16, 0, + tegra210_i2s_get_format, tegra210_i2s_put_format), + SOC_SINGLE_EXT("Client Channels", 0, 0, 16, 0, tegra210_i2s_get_format, tegra210_i2s_put_format), SOC_SINGLE_EXT("BCLK Ratio", SND_SOC_NOPM, 0, INT_MAX, 0, tegra210_i2s_get_bclk_ratio,