mirror of
https://github.com/torvalds/linux.git
synced 2024-11-29 23:51:37 +00:00
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:
parent
8b353bbeae
commit
f1040e86f8
@ -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 */
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user