ASoC: cs42l42: PLL must be running when changing MCLK_SRC_SEL

Both SCLK and PLL clocks must be running to drive the glitch-free mux
behind MCLK_SRC_SEL and complete the switchover.

This patch moves the writing of MCLK_SRC_SEL to when the PLL is started
and stopped, so that it only transitions while the PLL is running.
The unconditional write MCLK_SRC_SEL=0 in cs42l42_mute_stream() is safe
because if the PLL is not running MCLK_SRC_SEL is already 0.

Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Fixes: 43fc357199 ("ASoC: cs42l42: Set clock source for both ways of stream")
Link: https://lore.kernel.org/r/20210805161111.10410-1-rf@opensource.cirrus.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Richard Fitzgerald 2021-08-05 17:11:04 +01:00 committed by Mark Brown
parent 8b353bbeae
commit f1040e86f8
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 19 additions and 7 deletions

View File

@ -619,6 +619,8 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
if (pll_ratio_table[i].sclk == clk) {
cs42l42->pll_config = i;
/* Configure the internal sample rate */
snd_soc_component_update_bits(component, CS42L42_MCLK_CTL,
CS42L42_INTERNAL_FS_MASK,
@ -627,14 +629,9 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
(pll_ratio_table[i].mclk_int !=
24000000)) <<
CS42L42_INTERNAL_FS_SHIFT);
/* Set the MCLK src (PLL or SCLK) and the divide
* ratio
*/
snd_soc_component_update_bits(component, CS42L42_MCLK_SRC_SEL,
CS42L42_MCLK_SRC_SEL_MASK |
CS42L42_MCLKDIV_MASK,
(pll_ratio_table[i].mclk_src_sel
<< CS42L42_MCLK_SRC_SEL_SHIFT) |
(pll_ratio_table[i].mclk_div <<
CS42L42_MCLKDIV_SHIFT));
/* Set up the LRCLK */
@ -892,13 +889,21 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
*/
regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_osc_seq,
ARRAY_SIZE(cs42l42_to_osc_seq));
/* Must disconnect PLL before stopping it */
snd_soc_component_update_bits(component,
CS42L42_MCLK_SRC_SEL,
CS42L42_MCLK_SRC_SEL_MASK,
0);
usleep_range(100, 200);
snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
CS42L42_PLL_START_MASK, 0);
}
} else {
if (!cs42l42->stream_use) {
/* SCLK must be running before codec unmute */
if ((cs42l42->bclk < 11289600) && (cs42l42->sclk < 11289600)) {
if (pll_ratio_table[cs42l42->pll_config].mclk_src_sel) {
snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
CS42L42_PLL_START_MASK, 1);
@ -919,6 +924,12 @@ static int cs42l42_mute_stream(struct snd_soc_dai *dai, int mute, int stream)
CS42L42_PLL_LOCK_TIMEOUT_US);
if (ret < 0)
dev_warn(component->dev, "PLL failed to lock: %d\n", ret);
/* PLL must be running to drive glitchless switch logic */
snd_soc_component_update_bits(component,
CS42L42_MCLK_SRC_SEL,
CS42L42_MCLK_SRC_SEL_MASK,
CS42L42_MCLK_SRC_SEL_MASK);
}
/* Mark SCLK as present, turn off internal oscillator */

View File

@ -775,6 +775,7 @@ struct cs42l42_private {
struct gpio_desc *reset_gpio;
struct completion pdn_done;
struct snd_soc_jack *jack;
int pll_config;
int bclk;
u32 sclk;
u32 srate;