ASoC: wcd9310: Turn off mclk during clock transition
The clock is not usable when
- clock source changes between external MCLK and internal RCO.
- bandgap mode changes to fast mode.
When listed operations are about to happen, turn off master clock and
turn on again later to prevent codec hardware fails into bad state.
CRs-fixed: 352187
Change-Id: I4d310f32fa20ac86e0d8eb5492b2d5c036260ba6
Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org>
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 2d5eab2..18f80ca 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -1741,6 +1741,10 @@
(choice == TABLA_BANDGAP_AUDIO_MODE)) {
tabla_codec_enable_audio_mode_bandgap(codec);
} else if (choice == TABLA_BANDGAP_MBHC_MODE) {
+ /* bandgap mode becomes fast,
+ * mclk should be off or clk buff source souldn't be VBG
+ * Let's turn off mclk always */
+ WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
0x2);
snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
@@ -1770,9 +1774,10 @@
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
pr_debug("%s\n", __func__);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
- ndelay(160);
+ usleep_range(50, 50);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
+ usleep_range(50, 50);
tabla->clock_active = false;
}
@@ -1813,21 +1818,23 @@
pr_debug("%s: enable = %d\n", __func__, enable);
if (enable) {
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
+ /* bandgap mode to fast */
snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
usleep_range(5, 5);
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
- 0x80);
+ 0x80);
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
- 0x80);
+ 0x80);
usleep_range(10, 10);
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
- usleep_range(20, 20);
+ usleep_range(10000, 10000);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
} else {
snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
- 0);
+ 0);
snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
- snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
+ /* clk source to ext clk and clk buff ref to VBG */
+ snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x0C, 0x04);
}
tabla->config_mode_active = enable ? true : false;
@@ -1835,29 +1842,32 @@
}
static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
- int config_mode)
+ int config_mode)
{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
pr_debug("%s: config_mode = %d\n", __func__, config_mode);
+ /* transit to RCO requires mclk off */
+ WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
if (config_mode) {
+ /* enable RCO and switch to it */
tabla_codec_enable_config_mode(codec, 1);
- snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
- snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
usleep_range(1000, 1000);
- } else
+ } else {
+ /* switch to MCLK */
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
- if (!config_mode && tabla->mbhc_polling_active) {
- snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
- tabla_codec_enable_config_mode(codec, 0);
-
+ if (tabla->mbhc_polling_active) {
+ snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
+ tabla_codec_enable_config_mode(codec, 0);
+ }
}
- snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
+ snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x01, 0x01);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
+ /* on MCLK */
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
usleep_range(50, 50);
@@ -3689,16 +3699,18 @@
if (mclk_enable) {
tabla->mclk_enabled = true;
- if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
+ if (tabla->mbhc_polling_active) {
tabla_codec_pause_hs_polling(codec);
+ tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec,
- TABLA_BANDGAP_AUDIO_MODE);
+ TABLA_BANDGAP_AUDIO_MODE);
tabla_codec_enable_clock_block(codec, 0);
tabla_codec_calibrate_hs_polling(codec);
tabla_codec_start_hs_polling(codec);
} else {
+ tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec,
- TABLA_BANDGAP_AUDIO_MODE);
+ TABLA_BANDGAP_AUDIO_MODE);
tabla_codec_enable_clock_block(codec, 0);
}
} else {
@@ -3712,21 +3724,20 @@
tabla->mclk_enabled = false;
if (tabla->mbhc_polling_active) {
- if (!tabla->mclk_enabled) {
- tabla_codec_pause_hs_polling(codec);
- tabla_codec_enable_bandgap(codec,
- TABLA_BANDGAP_MBHC_MODE);
- tabla_enable_rx_bias(codec, 1);
- tabla_codec_enable_clock_block(codec, 1);
- tabla_codec_calibrate_hs_polling(codec);
- tabla_codec_start_hs_polling(codec);
- }
+ tabla_codec_pause_hs_polling(codec);
+ tabla_codec_disable_clock_block(codec);
+ tabla_codec_enable_bandgap(codec,
+ TABLA_BANDGAP_MBHC_MODE);
+ tabla_enable_rx_bias(codec, 1);
+ tabla_codec_enable_clock_block(codec, 1);
+ tabla_codec_calibrate_hs_polling(codec);
+ tabla_codec_start_hs_polling(codec);
snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
0x05, 0x01);
} else {
tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec,
- TABLA_BANDGAP_OFF);
+ TABLA_BANDGAP_OFF);
}
}
if (dapm)
@@ -4762,6 +4773,7 @@
}
if (!tabla->mclk_enabled) {
+ tabla_codec_disable_clock_block(codec);
tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
tabla_enable_rx_bias(codec, 1);
tabla_codec_enable_clock_block(codec, 1);