ASoC: cs42l42: Constrain sample rate to prevent illegal SCLK
authorRichard Fitzgerald <rf@opensource.cirrus.com>
Thu, 5 Aug 2021 16:11:06 +0000 (17:11 +0100)
committerMark Brown <broonie@kernel.org>
Thu, 5 Aug 2021 19:17:15 +0000 (20:17 +0100)
The lowest valid SCLK corresponds to 44.1 kHz at 16-bit. Sample
rates less than this would produce SCLK below the minimum when using
a normal I2S frame. A constraint must be applied to prevent this.

The constraint is not applied if the machine driver sets SCLK, to
allow setups where the host generates additional bits per LRCLK
phase to increase the SCLK frequency. In these cases the machine
driver would always have to inform this driver of the actual SCLK,
and it must select a legal SCLK.

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Link: https://lore.kernel.org/r/20210805161111.10410-3-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/cs42l42.c

index 02486329a57038d47ea08a86ade8e52e912e037e..29e0c8dc8466ec12fbc138b55e85b968d73cbbba 100644 (file)
@@ -807,6 +807,25 @@ static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
        return 0;
 }
 
+static int cs42l42_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct cs42l42_private *cs42l42 = snd_soc_component_get_drvdata(component);
+
+       /*
+        * Sample rates < 44.1 kHz would produce an out-of-range SCLK with
+        * a standard I2S frame. If the machine driver sets SCLK it must be
+        * legal.
+        */
+       if (cs42l42->sclk)
+               return 0;
+
+       /* Machine driver has not set a SCLK, limit bottom end to 44.1 kHz */
+       return snd_pcm_hw_constraint_minmax(substream->runtime,
+                                           SNDRV_PCM_HW_PARAM_RATE,
+                                           44100, 192000);
+}
+
 static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream,
                                struct snd_pcm_hw_params *params,
                                struct snd_soc_dai *dai)
@@ -966,8 +985,8 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
                         SNDRV_PCM_FMTBIT_S24_LE |\
                         SNDRV_PCM_FMTBIT_S32_LE )
 
-
 static const struct snd_soc_dai_ops cs42l42_ops = {
+       .startup        = cs42l42_dai_startup,
        .hw_params      = cs42l42_pcm_hw_params,
        .set_fmt        = cs42l42_set_dai_fmt,
        .set_sysclk     = cs42l42_set_sysclk,