]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
tegra-alt: add controls for CIF channel config
authorViraj Karandikar <vkarandikar@nvidia.com>
Fri, 19 Jun 2015 11:31:07 +0000 (17:01 +0530)
committerSumit Bhattacharya <sumitb@nvidia.com>
Wed, 5 Aug 2015 10:50:11 +0000 (03:50 -0700)
Add controls for configuring CIF channels for AMX and ADMAIF.

Add controls for CIF stereo/mono conversion for SFC.

Remove non-zero check in put_byte_map() to update byte mask.
Due to this check, byte 0 map wasn't getting updated for valid
value of 0.

Bug 200100724

Change-Id: I37b96594464f699db93552f5c1e148c51e963c5e
Signed-off-by: Viraj Karandikar <vkarandikar@nvidia.com>
Reviewed-on: http://git-master/r/760115
(cherry picked from commit 8c2d36d0303aac45553cc64c148d8c62a8bcf880)
Reviewed-on: http://git-master/r/772770
Reviewed-by: Ravindra Lokhande <rlokhande@nvidia.com>
Reviewed-by: Sumit Bhattacharya <sumitb@nvidia.com>
sound/soc/tegra-alt/tegra210_admaif_alt.c
sound/soc/tegra-alt/tegra210_admaif_alt.h
sound/soc/tegra-alt/tegra210_amx_alt.c
sound/soc/tegra-alt/tegra210_amx_alt.h
sound/soc/tegra-alt/tegra210_sfc_alt.c
sound/soc/tegra-alt/tegra210_sfc_alt.h

index 84ebdb86277c36d2c9f6bd485f45902b94ee8640..932633dbac522c00c3696aadd2e7fe2e95c2a86b 100644 (file)
@@ -266,8 +266,13 @@ static int tegra210_admaif_hw_params(struct snd_pcm_substream *substream,
        unsigned int reg, fifo_ctrl, fifo_size;
        int valid_bit;
 
-       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_S16_LE:
@@ -425,6 +430,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);
@@ -593,6 +626,23 @@ static const struct snd_soc_dapm_route tegra210_admaif_routes[] = {
        ADMAIF_ROUTES(10)
 };
 
+#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)
+};
+
 static int tegra210_admaif_codec_probe(struct snd_soc_codec *codec)
 {
        struct tegra210_admaif *admaif = snd_soc_codec_get_drvdata(codec);
@@ -614,6 +664,8 @@ static struct snd_soc_codec_driver tegra210_admaif_codec = {
        .num_dapm_widgets = ARRAY_SIZE(tegra210_admaif_widgets),
        .dapm_routes = tegra210_admaif_routes,
        .num_dapm_routes = ARRAY_SIZE(tegra210_admaif_routes),
+       .controls = tegra210_admaif_controls,
+       .num_controls = ARRAY_SIZE(tegra210_admaif_controls),
        .idle_bias_off = 1,
 };
 
@@ -667,7 +719,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;
        }
@@ -677,7 +729,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;
        }
index f200dabe970631c4762088efc291bf75921893f5..f42bd450eb2437218440cae8c55e321c5f41aa9b 100644 (file)
@@ -103,6 +103,7 @@ struct tegra210_admaif {
        struct tegra_alt_pcm_dma_params *capture_dma_data;
        struct tegra_alt_pcm_dma_params *playback_dma_data;
        const struct tegra210_admaif_soc_data *soc_data;
+       int override_channels[TEGRA210_ADMAIF_CHANNEL_COUNT];
 };
 
 #endif
index 88610189dbc46c6ea2b3cd530c93dd553c929301..bfa4469a4939d0b7751caed47a46936bad4c1bee 100644 (file)
@@ -311,14 +311,20 @@ 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;
 
-       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;
 
@@ -355,15 +361,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));
 
@@ -398,10 +402,9 @@ 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;
 
-       ret = tegra210_amx_set_audio_cif(amx, params,
+       ret = tegra210_amx_set_audio_cif(dai, params,
                                TEGRA210_AMX_AXBAR_TX_CIF_CTRL);
 
        return ret;
@@ -490,24 +493,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);
@@ -593,7 +611,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),
@@ -658,6 +681,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 = {
@@ -666,8 +691,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,
 };
 
index d28c9d4e3e4bd7b1bb029946719ad369dff1e59b..73baf966a39f2a5e3614bb1beeefc4cc981ded26 100644 (file)
 /*
  * Those defines are not in register field.
  */
+#define TEGRA210_AMX_NUM_INPUTS                                        4
 #define TEGRA210_AMX_RAM_DEPTH                                 16
 #define TEGRA210_AMX_MAP_STREAM_NUMBER_SHIFT   6
 #define TEGRA210_AMX_MAP_STREAM_NUMBER_MASK            (0x3 << TEGRA210_AMX_MAP_STREAM_NUMBER_SHIFT)
@@ -180,8 +181,9 @@ struct tegra210_amx_soc_data {
 
 struct tegra210_amx {
        struct regmap *regmap;
-       unsigned int map[16];
+       unsigned int map[TEGRA210_AMX_RAM_DEPTH];
        unsigned int byte_mask[2];
+       int output_channels;
        const struct tegra210_amx_soc_data *soc_data;
 };
 
index 74be76b97d9fcc87243c19bb3e2d85ebdb8a6e09..8cfd5479c44b21a5a18aa8f46817ac841279fec5 100644 (file)
@@ -309,18 +309,29 @@ 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.mono_conv = 0;
+               cif_conf.stereo_conv = 0;
+               cif_conf.client_channels = channels;
+       }
+
        cif_conf.threshold = 0;
        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];
        cif_conf.client_bits = TEGRA210_AUDIOCIF_BITS_32;
        cif_conf.expand = 0;
-       cif_conf.stereo_conv = 0;
        cif_conf.replicate = 0;
        cif_conf.truncate = 0;
-       cif_conf.mono_conv = 0;
 
        sfc->soc_data->set_audio_cif(sfc->regmap, reg, &cif_conf);
 
@@ -560,6 +571,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);
@@ -634,11 +685,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),
@@ -648,6 +717,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 = {
index 1d33f20a8738378a0b8bebe70ecc07333f2ff1c4..38f479504253c5ac9547664a109ec60544ca4b2f 100644 (file)
@@ -105,6 +105,8 @@ struct tegra210_sfc {
        struct regmap *regmap;
        struct snd_pcm_hw_params in_hw_params;
        struct snd_pcm_hw_params out_hw_params;
+       int stereo_conv_input;
+       int mono_conv_output;
        const struct tegra210_sfc_soc_data *soc_data;
 };