]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: wm8524: enable constraints when sysclk is configured.
authorShengjiu Wang <shengjiu.wang@nxp.com>
Fri, 20 Jun 2025 02:14:03 +0000 (10:14 +0800)
committerMark Brown <broonie@kernel.org>
Mon, 23 Jun 2025 16:12:54 +0000 (17:12 +0100)
In some cases, the sysclk won't be configured on init, and sysclk can be
changed in hw_params() according to different sample rate, for example,
for 44kHz sample rate, the sysclk is 11.2896MHz, for 48kHz sample rate,
the sysclk is 12.288MHz.

In order to support the above case, only enable constraints when sysclk
is configured, and check the rate in hw_params.

So overall there are three cases that need to be considered:
- call set_sysclk() on init, then constraints will be initialized.
- don't call set_sysclk() on init, but call it after startup(), then
  constraints will be configured, the constraints can be cleared with
  call set_sysclk() again in shutdown().
- don't call set_sysclk() in the whole flow, then there are no any
  constraints. The clocks depend on cpu dai.

Enlarge the WM8524_NUM_RATES to 12, as the supported rate range is 8kHz
to 192kHz.

Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
Reviewed-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://patch.msgid.link/20250620021403.624303-1-shengjiu.wang@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/wm8524.c

index 403e513f3fa8b046c45b91d90ffce97398e14078..6b1a7450b0acc675d6f4336298475b04dcadfd88 100644 (file)
@@ -21,7 +21,7 @@
 #include <sound/soc.h>
 #include <sound/initval.h>
 
-#define WM8524_NUM_RATES 7
+#define WM8524_NUM_RATES 12
 
 /* codec private data */
 struct wm8524_priv {
@@ -46,7 +46,7 @@ static const struct snd_soc_dapm_route wm8524_dapm_routes[] = {
 static const struct {
        int value;
        int ratio;
-} lrclk_ratios[WM8524_NUM_RATES] = {
+} lrclk_ratios[] = {
        { 1, 128 },
        { 2, 192 },
        { 3, 256 },
@@ -63,17 +63,12 @@ static int wm8524_startup(struct snd_pcm_substream *substream,
        struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
 
        /* The set of sample rates that can be supported depends on the
-        * MCLK supplied to the CODEC - enforce this.
+        * MCLK supplied to the CODEC.
         */
-       if (!wm8524->sysclk) {
-               dev_err(component->dev,
-                       "No MCLK configured, call set_sysclk() on init\n");
-               return -EINVAL;
-       }
-
-       snd_pcm_hw_constraint_list(substream->runtime, 0,
-                                  SNDRV_PCM_HW_PARAM_RATE,
-                                  &wm8524->rate_constraint);
+       if (wm8524->sysclk)
+               snd_pcm_hw_constraint_list(substream->runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_RATE,
+                                          &wm8524->rate_constraint);
 
        gpiod_set_value_cansleep(wm8524->mute, 1);
 
@@ -97,9 +92,11 @@ static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai,
        unsigned int val;
        int i, j = 0;
 
+       wm8524->rate_constraint.count = 0;
        wm8524->sysclk = freq;
+       if (!wm8524->sysclk)
+               return 0;
 
-       wm8524->rate_constraint.count = 0;
        for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) {
                val = freq / lrclk_ratios[i].ratio;
                /* Check that it's a standard rate since core can't
@@ -108,9 +105,13 @@ static int wm8524_set_dai_sysclk(struct snd_soc_dai *codec_dai,
                 */
                switch (val) {
                case 8000:
+               case 11025:
+               case 16000:
+               case 22050:
                case 32000:
                case 44100:
                case 48000:
+               case 64000:
                case 88200:
                case 96000:
                case 176400:
@@ -157,6 +158,33 @@ static int wm8524_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
        return 0;
 }
 
+static int wm8524_hw_params(struct snd_pcm_substream *substream,
+                           struct snd_pcm_hw_params *params,
+                           struct snd_soc_dai *dai)
+{
+       struct snd_soc_component *component = dai->component;
+       struct wm8524_priv *wm8524 = snd_soc_component_get_drvdata(component);
+       int i;
+
+       /* If sysclk is not configured, no need to check the rate */
+       if (!wm8524->sysclk)
+               return 0;
+
+       /* Find a supported LRCLK rate */
+       for (i = 0; i < wm8524->rate_constraint.count; i++) {
+               if (wm8524->rate_constraint.list[i] == params_rate(params))
+                       break;
+       }
+
+       if (i == wm8524->rate_constraint.count) {
+               dev_err(component->dev, "LRCLK %d unsupported with MCLK %d\n",
+                       params_rate(params), wm8524->sysclk);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 #define WM8524_RATES SNDRV_PCM_RATE_8000_192000
 
 #define WM8524_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
@@ -169,6 +197,7 @@ static const struct snd_soc_dai_ops wm8524_dai_ops = {
        .set_sysclk     = wm8524_set_dai_sysclk,
        .set_fmt        = wm8524_set_fmt,
        .mute_stream    = wm8524_mute_stream,
+       .hw_params      = wm8524_hw_params,
 };
 
 static struct snd_soc_dai_driver wm8524_dai = {