Unverified Commit f1040e86 authored by Richard Fitzgerald's avatar Richard Fitzgerald Committed by Mark Brown
Browse files

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: default avatarRichard Fitzgerald <rf@opensource.cirrus.com>
Fixes: 43fc3571 ("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: default avatarMark Brown <broonie@kernel.org>
parent 8b353bbe
Loading
Loading
Loading
Loading
+18 −7
Original line number Diff line number Diff line
@@ -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 */
+1 −0
Original line number Diff line number Diff line
@@ -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;