ASoC: msm8960: Make MCLK as DAPM Supply
For proper codec turn on, MCLK should be enabled before any of the
codec blocks are enabled. To avoid click and pops, MCLK should be
disabled after all the codec blocks are disabled.
CRs-Fixed: 305458
Signed-off-by: Kiran Kandi <kkandi@codeaurora.org>
diff --git a/sound/soc/codecs/wcd9310.c b/sound/soc/codecs/wcd9310.c
index 516e425..b077cf4 100644
--- a/sound/soc/codecs/wcd9310.c
+++ b/sound/soc/codecs/wcd9310.c
@@ -49,14 +49,13 @@
struct tabla_priv {
struct snd_soc_codec *codec;
- u32 ref_cnt;
u32 adc_count;
- u32 rx_count;
u32 cfilt1_cnt;
u32 cfilt2_cnt;
u32 cfilt3_cnt;
-
+ u32 rx_bias_count;
enum tabla_bandgap_type bandgap_type;
+ bool mclk_enabled;
bool clock_active;
bool config_mode_active;
bool mbhc_polling_active;
@@ -987,6 +986,42 @@
return 0;
}
+
+static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
+{
+ struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
+
+ if (enable) {
+ tabla->rx_bias_count++;
+ if (tabla->rx_bias_count == 1)
+ snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
+ 0x80, 0x80);
+ } else {
+ tabla->rx_bias_count--;
+ if (!tabla->rx_bias_count)
+ snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
+ 0x80, 0x00);
+ }
+}
+
+static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ pr_debug("%s %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ tabla_enable_rx_bias(codec, 1);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ tabla_enable_rx_bias(codec, 0);
+ break;
+ }
+ return 0;
+}
+
static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
/*RX stuff */
SND_SOC_DAPM_OUTPUT("EAR"),
@@ -1096,6 +1131,10 @@
tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_PRE_PMD),
+ SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
+ tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
/* TX */
SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
@@ -1344,6 +1383,12 @@
{"LINEOUT4 DAC", "Switch", "RX4 MIX1"},
{"LINEOUT5 DAC", "Switch", "RX7 MIX1"},
+ {"CP", NULL, "RX_BIAS"},
+ {"LINEOUT1 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT2 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT3 DAC", NULL, "RX_BIAS"},
+ {"LINEOUT4 DAC", NULL, "RX_BIAS"},
+
{"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
{"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
{"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
@@ -1651,72 +1696,59 @@
static int tabla_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_codec *codec = dai->codec;
- struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- int ret = 0;
+ pr_debug("%s(): substream = %s stream = %d\n" , __func__,
+ substream->name, substream->stream);
- pr_debug("%s()\n", __func__);
-
- if (!codec) {
- pr_err("Error, no codec found\n");
- return -EINVAL;
- }
- tabla->ref_cnt++;
-
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- tabla->rx_count++;
- if (tabla->rx_count == 1)
- snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
- 0x80);
- }
-
- if (tabla->mbhc_polling_active && (tabla->ref_cnt == 1)) {
- tabla_codec_pause_hs_polling(codec);
- tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
- tabla_codec_enable_clock_block(codec, 0);
- tabla_codec_calibrate_hs_polling(codec);
- tabla_codec_start_hs_polling(codec);
- }
-
- return ret;
+ return 0;
}
static void tabla_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
- struct snd_soc_codec *codec = dai->codec;
+ pr_debug("%s(): substream = %s stream = %d\n" , __func__,
+ substream->name, substream->stream);
+}
+
+int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
+{
struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
- pr_debug("%s()\n", __func__);
+ pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
- if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
- /* Disable LDO */
- } else {
- tabla->rx_count--;
- if (!tabla->rx_count)
- snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
- 0x00);
- }
+ if (mclk_enable) {
+ tabla->mclk_enabled = true;
- if (!tabla->ref_cnt) {
- pr_err("Error, trying to shutdown codec when already down\n");
- return;
- }
- tabla->ref_cnt--;
-
- if (tabla->mbhc_polling_active) {
- if (!tabla->ref_cnt) {
+ if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
tabla_codec_pause_hs_polling(codec);
tabla_codec_enable_bandgap(codec,
- TABLA_BANDGAP_MBHC_MODE);
- snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80,
- 0x80);
- tabla_codec_enable_clock_block(codec, 1);
+ TABLA_BANDGAP_AUDIO_MODE);
+ tabla_codec_enable_clock_block(codec, 0);
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 {
+
+ if (!tabla->mclk_enabled) {
+ pr_err("Error, MCLK already diabled\n");
+ return -EINVAL;
+ }
+ 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);
+ }
+ snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
+ 0x05, 0x01);
+ }
}
+ return 0;
}
static int tabla_digital_mute(struct snd_soc_dai *codec_dai, int mute)
@@ -1942,9 +1974,9 @@
tabla->mbhc_polling_active = true;
- if (!tabla->ref_cnt) {
+ if (!tabla->mclk_enabled) {
tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
- snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS, 0x80, 0x80);
+ tabla_enable_rx_bias(codec, 1);
tabla_codec_enable_clock_block(codec, 1);
}
@@ -2207,7 +2239,7 @@
struct tabla_mbhc_calibration *calibration = tabla->calibration;
int micbias_mbhc_reg;
- if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
+ if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
tabla_codec_enable_config_mode(codec, 1);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
@@ -2235,7 +2267,7 @@
calibration->shutdown_plug_removal);
snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
- if (!tabla->ref_cnt && !tabla->mbhc_polling_active)
+ if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
tabla_codec_enable_config_mode(codec, 0);
snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
@@ -2247,7 +2279,7 @@
tabla_codec_shutdown_hs_removal_detect(codec);
- if (!tabla->ref_cnt) {
+ if (!tabla->mclk_enabled) {
snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
tabla_codec_enable_clock_block(codec, 0);
@@ -2651,7 +2683,7 @@
snd_soc_codec_set_drvdata(codec, tabla);
- tabla->ref_cnt = 0;
+ tabla->mclk_enabled = false;
tabla->bandgap_type = TABLA_BANDGAP_OFF;
tabla->clock_active = false;
tabla->config_mode_active = false;
diff --git a/sound/soc/codecs/wcd9310.h b/sound/soc/codecs/wcd9310.h
index 681b766..8c6555b 100644
--- a/sound/soc/codecs/wcd9310.h
+++ b/sound/soc/codecs/wcd9310.h
@@ -60,3 +60,5 @@
u32 reserved[3];
u32 num_anc_slots;
};
+
+extern int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable);
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 23283b5..5ee8477 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -202,8 +202,59 @@
return 0;
}
+static int msm8960_mclk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ pr_debug("%s: event = %d\n", __func__, event);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+
+ clk_users++;
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+ if (clk_users != 1)
+ return 0;
+
+ codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
+ if (codec_clk) {
+ clk_set_rate(codec_clk, 12288000);
+ clk_enable(codec_clk);
+ tabla_mclk_enable(w->codec, 1);
+
+ } else {
+ pr_err("%s: Error setting Tabla MCLK\n", __func__);
+ clk_users--;
+ return -EINVAL;
+ }
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+
+ pr_debug("%s: clk_users = %d\n", __func__, clk_users);
+
+ if (clk_users == 0)
+ return 0;
+
+ clk_users--;
+
+ if (!clk_users) {
+ pr_debug("%s: disabling MCLK. clk_users = %d\n",
+ __func__, clk_users);
+
+ clk_disable(codec_clk);
+ clk_put(codec_clk);
+ tabla_mclk_enable(w->codec, 0);
+ }
+ break;
+ }
+ return 0;
+}
+
static const struct snd_soc_dapm_widget msm8960_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
+ msm8960_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
SND_SOC_DAPM_SPK("Ext Spk Bottom", msm8960_spkramp_event),
SND_SOC_DAPM_SPK("Ext Spk Top", msm8960_spkramp_event),
@@ -223,8 +274,11 @@
};
static const struct snd_soc_dapm_route common_audio_map[] = {
- /* Speaker path */
+ {"RX_BIAS", NULL, "MCLK"},
+ {"LDO_H", NULL, "MCLK"},
+
+ /* Speaker path */
{"Ext Spk Bottom", NULL, "LINEOUT1"},
{"Ext Spk Bottom", NULL, "LINEOUT3"},
@@ -566,28 +620,15 @@
static int msm8960_startup(struct snd_pcm_substream *substream)
{
- if (clk_users++)
- return 0;
-
- codec_clk = clk_get(NULL, "i2s_spkr_osr_clk");
- if (codec_clk) {
- clk_set_rate(codec_clk, 12288000);
- clk_enable(codec_clk);
- } else {
- pr_err("%s: Error setting Tabla MCLK\n", __func__);
- clk_users--;
- return -EINVAL;
- }
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
return 0;
}
static void msm8960_shutdown(struct snd_pcm_substream *substream)
{
- clk_users--;
- if (!clk_users) {
- clk_disable(codec_clk);
- clk_put(codec_clk);
- }
+ pr_debug("%s(): substream = %s stream = %d\n", __func__,
+ substream->name, substream->stream);
}
static struct snd_soc_ops msm8960_be_ops = {