mirror of https://gitee.com/openkylin/linux.git
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++) {
|
for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) {
|
||||||
if (pll_ratio_table[i].sclk == clk) {
|
if (pll_ratio_table[i].sclk == clk) {
|
||||||
|
cs42l42->pll_config = i;
|
||||||
|
|
||||||
/* Configure the internal sample rate */
|
/* Configure the internal sample rate */
|
||||||
snd_soc_component_update_bits(component, CS42L42_MCLK_CTL,
|
snd_soc_component_update_bits(component, CS42L42_MCLK_CTL,
|
||||||
CS42L42_INTERNAL_FS_MASK,
|
CS42L42_INTERNAL_FS_MASK,
|
||||||
|
@ -627,14 +629,9 @@ static int cs42l42_pll_config(struct snd_soc_component *component)
|
||||||
(pll_ratio_table[i].mclk_int !=
|
(pll_ratio_table[i].mclk_int !=
|
||||||
24000000)) <<
|
24000000)) <<
|
||||||
CS42L42_INTERNAL_FS_SHIFT);
|
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,
|
snd_soc_component_update_bits(component, CS42L42_MCLK_SRC_SEL,
|
||||||
CS42L42_MCLK_SRC_SEL_MASK |
|
|
||||||
CS42L42_MCLKDIV_MASK,
|
CS42L42_MCLKDIV_MASK,
|
||||||
(pll_ratio_table[i].mclk_src_sel
|
|
||||||
<< CS42L42_MCLK_SRC_SEL_SHIFT) |
|
|
||||||
(pll_ratio_table[i].mclk_div <<
|
(pll_ratio_table[i].mclk_div <<
|
||||||
CS42L42_MCLKDIV_SHIFT));
|
CS42L42_MCLKDIV_SHIFT));
|
||||||
/* Set up the LRCLK */
|
/* 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,
|
regmap_multi_reg_write(cs42l42->regmap, cs42l42_to_osc_seq,
|
||||||
ARRAY_SIZE(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,
|
snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
|
||||||
CS42L42_PLL_START_MASK, 0);
|
CS42L42_PLL_START_MASK, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!cs42l42->stream_use) {
|
if (!cs42l42->stream_use) {
|
||||||
/* SCLK must be running before codec unmute */
|
/* 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,
|
snd_soc_component_update_bits(component, CS42L42_PLL_CTL1,
|
||||||
CS42L42_PLL_START_MASK, 1);
|
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);
|
CS42L42_PLL_LOCK_TIMEOUT_US);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
dev_warn(component->dev, "PLL failed to lock: %d\n", ret);
|
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 */
|
/* Mark SCLK as present, turn off internal oscillator */
|
||||||
|
|
|
@ -775,6 +775,7 @@ struct cs42l42_private {
|
||||||
struct gpio_desc *reset_gpio;
|
struct gpio_desc *reset_gpio;
|
||||||
struct completion pdn_done;
|
struct completion pdn_done;
|
||||||
struct snd_soc_jack *jack;
|
struct snd_soc_jack *jack;
|
||||||
|
int pll_config;
|
||||||
int bclk;
|
int bclk;
|
||||||
u32 sclk;
|
u32 sclk;
|
||||||
u32 srate;
|
u32 srate;
|
||||||
|
|
Loading…
Reference in New Issue