ASoC: pcm3168a: Use fixup instead of constraint for channels and formats
authorPeter Ujfalusi <peter.ujfalusi@ti.com>
Tue, 8 Oct 2019 11:57:20 +0000 (14:57 +0300)
committerMark Brown <broonie@kernel.org>
Tue, 8 Oct 2019 12:39:17 +0000 (13:39 +0100)
The snd_pcm_hw_constraint_minmax() works fine when a single codec is
connected to a single CPU DAI, but in multicodec or DPCM setup the
constraints placed by the driver will apply to the whole PCM stream (FE
included) and thus prevents more than 8 playback channels for example.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Link: https://lore.kernel.org/r/20191008115720.7135-1-peter.ujfalusi@ti.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/pcm3168a.c

index 88b75695fbf7f582a46d837877d9522a385b61c4..708dac27fefffde7593d9149670f128868d8071e 100644 (file)
@@ -62,6 +62,7 @@ struct pcm3168a_priv {
        unsigned long sysclk;
 
        struct pcm3168a_io_params io_params[2];
+       struct snd_soc_dai_driver dai_drv[2];
 };
 
 static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" };
@@ -314,6 +315,37 @@ static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai,
        return 0;
 }
 
+static void pcm3168a_update_fixup_pcm_stream(struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
+       u64 formats = SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE;
+       unsigned int channel_max = dai->id == PCM3168A_DAI_DAC ? 8 : 6;
+
+       if (!pcm3168a->io_params[dai->id].fmt)
+               return;
+
+       if (pcm3168a->io_params[dai->id].fmt == PCM3168A_FMT_RIGHT_J) {
+               /* S16_LE is only supported in RIGHT_J mode */
+               formats |= SNDRV_PCM_FMTBIT_S16_LE;
+
+               /*
+                * If multi DIN/DOUT is not selected, RIGHT_J can only support
+                * two channels (no TDM support)
+                */
+               if (pcm3168a->io_params[dai->id].tdm_slots != 2)
+                       channel_max = 2;
+       }
+
+       if (dai->id == PCM3168A_DAI_DAC) {
+               dai->driver->playback.channels_max = channel_max;
+               dai->driver->playback.formats = formats;
+       } else {
+               dai->driver->capture.channels_max = channel_max;
+               dai->driver->capture.formats = formats;
+       }
+}
+
 static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
 {
        struct snd_soc_component *component = dai->component;
@@ -376,6 +408,8 @@ static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format)
 
        regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift);
 
+       pcm3168a_update_fixup_pcm_stream(dai);
+
        return 0;
 }
 
@@ -409,6 +443,8 @@ static int pcm3168a_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
        else
                io_params->tdm_mask = rx_mask;
 
+       pcm3168a_update_fixup_pcm_stream(dai);
+
        return 0;
 }
 
@@ -530,63 +566,7 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int pcm3168a_startup(struct snd_pcm_substream *substream,
-                           struct snd_soc_dai *dai)
-{
-       struct snd_soc_component *component = dai->component;
-       struct pcm3168a_priv *pcm3168a = snd_soc_component_get_drvdata(component);
-       unsigned int sample_min;
-       unsigned int channel_max;
-       unsigned int channel_maxs[] = {
-               8, /* DAC */
-               6  /* ADC */
-       };
-
-       /*
-        * Available Data Bits
-        *
-        * RIGHT_J : 24 / 16
-        * LEFT_J  : 24
-        * I2S     : 24
-        *
-        * TDM available
-        *
-        * I2S
-        * LEFT_J
-        */
-       switch (pcm3168a->io_params[dai->id].fmt) {
-       case PCM3168A_FMT_RIGHT_J:
-               sample_min  = 16;
-               channel_max =  2;
-               break;
-       case PCM3168A_FMT_LEFT_J:
-       case PCM3168A_FMT_I2S:
-       case PCM3168A_FMT_DSP_A:
-       case PCM3168A_FMT_DSP_B:
-               sample_min  = 24;
-               channel_max = channel_maxs[dai->id];
-               break;
-       default:
-               sample_min  = 24;
-               channel_max =  2;
-       }
-
-       snd_pcm_hw_constraint_minmax(substream->runtime,
-                                    SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                    sample_min, 32);
-
-       /* Allow all channels in multi DIN/DOUT mode */
-       if (pcm3168a->io_params[dai->id].tdm_slots == 2)
-               channel_max = channel_maxs[dai->id];
-
-       snd_pcm_hw_constraint_minmax(substream->runtime,
-                                    SNDRV_PCM_HW_PARAM_CHANNELS,
-                                    2, channel_max);
-
-       return 0;
-}
 static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
-       .startup        = pcm3168a_startup,
        .set_fmt        = pcm3168a_set_dai_fmt,
        .set_sysclk     = pcm3168a_set_dai_sysclk,
        .hw_params      = pcm3168a_hw_params,
@@ -776,8 +756,10 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap)
        pm_runtime_enable(dev);
        pm_runtime_idle(dev);
 
-       ret = devm_snd_soc_register_component(dev, &pcm3168a_driver, pcm3168a_dais,
-                       ARRAY_SIZE(pcm3168a_dais));
+       memcpy(pcm3168a->dai_drv, pcm3168a_dais, sizeof(pcm3168a->dai_drv));
+       ret = devm_snd_soc_register_component(dev, &pcm3168a_driver,
+                                             pcm3168a->dai_drv,
+                                             ARRAY_SIZE(pcm3168a->dai_drv));
        if (ret) {
                dev_err(dev, "failed to register component: %d\n", ret);
                goto err_regulator;