[ Upstream commit 1e112c35e3c96db7c8ca6ddaa96574f00c06e7db ]

The slot_width is a property for the bus while the constraint for
SNDRV_PCM_HW_PARAM_SAMPLE_BITS is for the in memory format.

Applying slot_width constraint to sample_bits works most of the time, but
it will blacklist valid formats in some cases.

With slot_width 24 we can support S24_3LE and S24_LE formats as they both
look the same on the bus, but a a 24 constraint on sample_bits would not
allow S24_LE as it is stored in 32bits in memory.

Implement a simple hw_rule function to allow all formats which require less
or equal number of bits on the bus as slot_width (if configured).

Signed-off-by: Peter Ujfalusi <peter.ujfal...@ti.com>
Link: https://lore.kernel.org/r/20190726064244.3762-2-peter.ujfal...@ti.com
Signed-off-by: Mark Brown <broo...@kernel.org>
Signed-off-by: Sasha Levin <sas...@kernel.org>
---
 sound/soc/davinci/davinci-mcasp.c | 43 ++++++++++++++++++++++++-------
 1 file changed, 34 insertions(+), 9 deletions(-)

diff --git a/sound/soc/davinci/davinci-mcasp.c 
b/sound/soc/davinci/davinci-mcasp.c
index 160b2764b2ad8..6a8c279a4b20b 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -1150,6 +1150,28 @@ static int davinci_mcasp_trigger(struct 
snd_pcm_substream *substream,
        return ret;
 }
 
+static int davinci_mcasp_hw_rule_slot_width(struct snd_pcm_hw_params *params,
+                                           struct snd_pcm_hw_rule *rule)
+{
+       struct davinci_mcasp_ruledata *rd = rule->private;
+       struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
+       struct snd_mask nfmt;
+       int i, slot_width;
+
+       snd_mask_none(&nfmt);
+       slot_width = rd->mcasp->slot_width;
+
+       for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
+               if (snd_mask_test(fmt, i)) {
+                       if (snd_pcm_format_width(i) <= slot_width) {
+                               snd_mask_set(&nfmt, i);
+                       }
+               }
+       }
+
+       return snd_mask_refine(fmt, &nfmt);
+}
+
 static const unsigned int davinci_mcasp_dai_rates[] = {
        8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000,
        88200, 96000, 176400, 192000,
@@ -1257,7 +1279,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream 
*substream,
        struct davinci_mcasp_ruledata *ruledata =
                                        &mcasp->ruledata[substream->stream];
        u32 max_channels = 0;
-       int i, dir;
+       int i, dir, ret;
        int tdm_slots = mcasp->tdm_slots;
 
        /* Do not allow more then one stream per direction */
@@ -1286,6 +1308,7 @@ static int davinci_mcasp_startup(struct snd_pcm_substream 
*substream,
                        max_channels++;
        }
        ruledata->serializers = max_channels;
+       ruledata->mcasp = mcasp;
        max_channels *= tdm_slots;
        /*
         * If the already active stream has less channels than the calculated
@@ -1311,20 +1334,22 @@ static int davinci_mcasp_startup(struct 
snd_pcm_substream *substream,
                                   0, SNDRV_PCM_HW_PARAM_CHANNELS,
                                   &mcasp->chconstr[substream->stream]);
 
-       if (mcasp->slot_width)
-               snd_pcm_hw_constraint_minmax(substream->runtime,
-                                            SNDRV_PCM_HW_PARAM_SAMPLE_BITS,
-                                            8, mcasp->slot_width);
+       if (mcasp->slot_width) {
+               /* Only allow formats require <= slot_width bits on the bus */
+               ret = snd_pcm_hw_rule_add(substream->runtime, 0,
+                                         SNDRV_PCM_HW_PARAM_FORMAT,
+                                         davinci_mcasp_hw_rule_slot_width,
+                                         ruledata,
+                                         SNDRV_PCM_HW_PARAM_FORMAT, -1);
+               if (ret)
+                       return ret;
+       }
 
        /*
         * If we rely on implicit BCLK divider setting we should
         * set constraints based on what we can provide.
         */
        if (mcasp->bclk_master && mcasp->bclk_div == 0 && mcasp->sysclk_freq) {
-               int ret;
-
-               ruledata->mcasp = mcasp;
-
                ret = snd_pcm_hw_rule_add(substream->runtime, 0,
                                          SNDRV_PCM_HW_PARAM_RATE,
                                          davinci_mcasp_hw_rule_rate,
-- 
2.20.1



Reply via email to