ASoC: es8316: Enable support for MCLK div by 2
authorMarian Postevca <posteuca@mutex.one>
Tue, 29 Aug 2023 22:01:14 +0000 (01:01 +0300)
committerMark Brown <broonie@kernel.org>
Mon, 11 Sep 2023 00:24:09 +0000 (01:24 +0100)
To properly support a line of Huawei laptops with an AMD CPU
and an ES8336 codec connected to the ACP3X module, we need
to enable the codec option to divide the MCLK by 2.
This is needed because for at least one SKU that has a 48Mhz
MCLK the sound is distorted unless the MCLK div by 2 option
is enabled.

The option to divide the MCLK will first be tried. If no suitable
clocking can be generated from this frequency, then the normal
non-halved MCLK frequency will be tried.

Signed-off-by: Marian Postevca <posteuca@mutex.one>
Link: https://lore.kernel.org/r/20230829220116.1159-4-posteuca@mutex.one
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/es8316.c
sound/soc/codecs/es8316.h

index a1c3e10c3cf1045834ae1b963e5502a398ad221e..e53b2856d6250b7f5b2f85fcdb6f69a237aedbf0 100644 (file)
@@ -469,19 +469,42 @@ static int es8316_pcm_hw_params(struct snd_pcm_substream *substream,
        u8 bclk_divider;
        u16 lrck_divider;
        int i;
+       unsigned int clk = es8316->sysclk / 2;
+       bool clk_valid = false;
+
+       /* We will start with halved sysclk and see if we can use it
+        * for proper clocking. This is to minimise the risk of running
+        * the CODEC with a too high frequency. We have an SKU where
+        * the sysclk frequency is 48Mhz and this causes the sound to be
+        * sped up. If we can run with a halved sysclk, we will use it,
+        * if we can't use it, then full sysclk will be used.
+        */
+       do {
+               /* Validate supported sample rates that are autodetected from MCLK */
+               for (i = 0; i < ARRAY_SIZE(supported_mclk_lrck_ratios); i++) {
+                       const unsigned int ratio = supported_mclk_lrck_ratios[i];
+
+                       if (clk % ratio != 0)
+                               continue;
+                       if (clk / ratio == params_rate(params))
+                               break;
+               }
+               if (i == ARRAY_SIZE(supported_mclk_lrck_ratios)) {
+                       if (clk == es8316->sysclk)
+                               return -EINVAL;
+                       clk = es8316->sysclk;
+               } else {
+                       clk_valid = true;
+               }
+       } while (!clk_valid);
 
-       /* Validate supported sample rates that are autodetected from MCLK */
-       for (i = 0; i < ARRAY_SIZE(supported_mclk_lrck_ratios); i++) {
-               const unsigned int ratio = supported_mclk_lrck_ratios[i];
-
-               if (es8316->sysclk % ratio != 0)
-                       continue;
-               if (es8316->sysclk / ratio == params_rate(params))
-                       break;
+       if (clk != es8316->sysclk) {
+               snd_soc_component_update_bits(component, ES8316_CLKMGR_CLKSW,
+                                             ES8316_CLKMGR_CLKSW_MCLK_DIV,
+                                             ES8316_CLKMGR_CLKSW_MCLK_DIV);
        }
-       if (i == ARRAY_SIZE(supported_mclk_lrck_ratios))
-               return -EINVAL;
-       lrck_divider = es8316->sysclk / params_rate(params);
+
+       lrck_divider = clk / params_rate(params);
        bclk_divider = lrck_divider / 4;
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S16_LE:
index c335138e2837897297f603e0d89d6bbc1b616f72..0ff16f94869006c2b4558bd9ba668653ddd9f340 100644 (file)
 #define ES8316_GPIO_FLAG_GM_NOT_SHORTED                0x02
 #define ES8316_GPIO_FLAG_HP_NOT_INSERTED       0x04
 
+/* ES8316_CLKMGR_CLKSW */
+#define ES8316_CLKMGR_CLKSW_MCLK_DIV   0x80
+
 #endif