Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: es8316: Enable support for MCLK div by 2

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>

authored by

Marian Postevca and committed by
Mark Brown
869f3078 a43c0dc1

+36 -10
+33 -10
sound/soc/codecs/es8316.c
··· 469 469 u8 bclk_divider; 470 470 u16 lrck_divider; 471 471 int i; 472 + unsigned int clk = es8316->sysclk / 2; 473 + bool clk_valid = false; 472 474 473 - /* Validate supported sample rates that are autodetected from MCLK */ 474 - for (i = 0; i < ARRAY_SIZE(supported_mclk_lrck_ratios); i++) { 475 - const unsigned int ratio = supported_mclk_lrck_ratios[i]; 475 + /* We will start with halved sysclk and see if we can use it 476 + * for proper clocking. This is to minimise the risk of running 477 + * the CODEC with a too high frequency. We have an SKU where 478 + * the sysclk frequency is 48Mhz and this causes the sound to be 479 + * sped up. If we can run with a halved sysclk, we will use it, 480 + * if we can't use it, then full sysclk will be used. 481 + */ 482 + do { 483 + /* Validate supported sample rates that are autodetected from MCLK */ 484 + for (i = 0; i < ARRAY_SIZE(supported_mclk_lrck_ratios); i++) { 485 + const unsigned int ratio = supported_mclk_lrck_ratios[i]; 476 486 477 - if (es8316->sysclk % ratio != 0) 478 - continue; 479 - if (es8316->sysclk / ratio == params_rate(params)) 480 - break; 487 + if (clk % ratio != 0) 488 + continue; 489 + if (clk / ratio == params_rate(params)) 490 + break; 491 + } 492 + if (i == ARRAY_SIZE(supported_mclk_lrck_ratios)) { 493 + if (clk == es8316->sysclk) 494 + return -EINVAL; 495 + clk = es8316->sysclk; 496 + } else { 497 + clk_valid = true; 498 + } 499 + } while (!clk_valid); 500 + 501 + if (clk != es8316->sysclk) { 502 + snd_soc_component_update_bits(component, ES8316_CLKMGR_CLKSW, 503 + ES8316_CLKMGR_CLKSW_MCLK_DIV, 504 + ES8316_CLKMGR_CLKSW_MCLK_DIV); 481 505 } 482 - if (i == ARRAY_SIZE(supported_mclk_lrck_ratios)) 483 - return -EINVAL; 484 - lrck_divider = es8316->sysclk / params_rate(params); 506 + 507 + lrck_divider = clk / params_rate(params); 485 508 bclk_divider = lrck_divider / 4; 486 509 switch (params_format(params)) { 487 510 case SNDRV_PCM_FORMAT_S16_LE:
+3
sound/soc/codecs/es8316.h
··· 129 129 #define ES8316_GPIO_FLAG_GM_NOT_SHORTED 0x02 130 130 #define ES8316_GPIO_FLAG_HP_NOT_INSERTED 0x04 131 131 132 + /* ES8316_CLKMGR_CLKSW */ 133 + #define ES8316_CLKMGR_CLKSW_MCLK_DIV 0x80 134 + 132 135 #endif