Merge "ASoC: wcd9xxx: Enable voltage source for micbias for headset detection"
diff --git a/sound/soc/codecs/msm8x10-wcd.c b/sound/soc/codecs/msm8x10-wcd.c
index 93c18ba..d1aedbe 100644
--- a/sound/soc/codecs/msm8x10-wcd.c
+++ b/sound/soc/codecs/msm8x10-wcd.c
@@ -2661,6 +2661,30 @@
0x80, on ? 0x80 : 0x00);
}
+static int msm8x10_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
+ bool turn_on)
+{
+ int ret = 0;
+
+ if (turn_on)
+ ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
+ "MICBIAS_REGULATOR");
+ else
+ ret = snd_soc_dapm_disable_pin(&codec->dapm,
+ "MICBIAS_REGULATOR");
+
+ snd_soc_dapm_sync(&codec->dapm);
+
+ if (ret)
+ dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
+ __func__, turn_on ? "enable" : "disabled");
+ else
+ dev_dbg(codec->dev, "%s: %s external micbias source\n",
+ __func__, turn_on ? "Enabled" : "Disabled");
+
+ return ret;
+}
+
static const struct wcd9xxx_mbhc_cb mbhc_cb = {
.enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
.cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
@@ -2672,6 +2696,7 @@
.get_cdc_type = msm8x10_wcd_get_cdc_type,
.enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
.enable_mbhc_txfe = msm8x10_wcd_mbhc_txfe,
+ .enable_mb_source = msm8x10_wcd_enable_ext_mb_source,
};
static void delayed_hs_detect_fn(struct work_struct *work)
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.c b/sound/soc/codecs/wcd9xxx-mbhc.c
index c1e696d..01f0f25 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.c
+++ b/sound/soc/codecs/wcd9xxx-mbhc.c
@@ -184,9 +184,11 @@
return mbhc->polling_active;
}
-static void wcd9xxx_turn_onoff_override(struct snd_soc_codec *codec, bool on)
+static void wcd9xxx_turn_onoff_override(struct wcd9xxx_mbhc *mbhc, bool on)
{
- snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
+ struct snd_soc_codec *codec = mbhc->codec;
+ snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
+ 0x04, on ? 0x04 : 0x00);
}
/* called under codec_resource_lock acquisition */
@@ -296,7 +298,7 @@
override = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
0x04;
if (!override)
- wcd9xxx_turn_onoff_override(codec, true);
+ wcd9xxx_turn_onoff_override(mbhc, true);
/* Adjust threshold if Mic Bias voltage changes */
if (d->micb_mv != VDDIO_MICBIAS_MV) {
cfilt_k_val = __wcd9xxx_resmgr_get_k_val(mbhc,
@@ -338,7 +340,7 @@
snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
0x10, 0x00);
if (!override)
- wcd9xxx_turn_onoff_override(codec, false);
+ wcd9xxx_turn_onoff_override(mbhc, false);
if (restartpolling)
wcd9xxx_start_hs_polling(mbhc);
@@ -1070,6 +1072,9 @@
}
btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
+ /* Enable external voltage source to micbias if present */
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+ mbhc->mbhc_cb->enable_mb_source(codec, true);
/*
* Request BG and clock.
@@ -1184,6 +1189,8 @@
static void wcd9xxx_cleanup_hs_polling(struct wcd9xxx_mbhc *mbhc)
{
+
+ pr_debug("%s: enter\n", __func__);
WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
wcd9xxx_shutdown_hs_removal_detect(mbhc);
@@ -1194,8 +1201,13 @@
wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
+ /* Disable external voltage source to micbias if present */
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+ mbhc->mbhc_cb->enable_mb_source(mbhc->codec, false);
+
mbhc->polling_active = false;
mbhc->mbhc_state = MBHC_STATE_NONE;
+ pr_debug("%s: leave\n", __func__);
}
/* called under codec_resource_lock acquisition */
@@ -1988,7 +2000,6 @@
static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc)
{
enum wcd9xxx_mbhc_plug_type plug_type;
- struct snd_soc_codec *codec = mbhc->codec;
bool current_source_enable;
pr_debug("%s: enter\n", __func__);
@@ -2002,9 +2013,9 @@
plug_type = wcd9xxx_codec_cs_get_plug_type(mbhc, false);
wcd9xxx_turn_onoff_current_source(mbhc, false, false);
} else {
- wcd9xxx_turn_onoff_override(codec, true);
+ wcd9xxx_turn_onoff_override(mbhc, true);
plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
- wcd9xxx_turn_onoff_override(codec, false);
+ wcd9xxx_turn_onoff_override(mbhc, false);
}
if (wcd9xxx_swch_level_remove(mbhc)) {
@@ -2015,13 +2026,16 @@
if (plug_type == PLUG_TYPE_INVALID ||
plug_type == PLUG_TYPE_GND_MIC_SWAP) {
+ wcd9xxx_cleanup_hs_polling(mbhc);
wcd9xxx_schedule_hs_detect_plug(mbhc,
&mbhc->correct_plug_swch);
} else if (plug_type == PLUG_TYPE_HEADPHONE) {
wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
+ wcd9xxx_cleanup_hs_polling(mbhc);
wcd9xxx_schedule_hs_detect_plug(mbhc,
&mbhc->correct_plug_swch);
} else if (plug_type == PLUG_TYPE_HIGH_HPH) {
+ wcd9xxx_cleanup_hs_polling(mbhc);
wcd9xxx_schedule_hs_detect_plug(mbhc,
&mbhc->correct_plug_swch);
} else {
@@ -2643,7 +2657,7 @@
wcd9xxx_turn_onoff_current_source(mbhc, true,
false);
else
- wcd9xxx_turn_onoff_override(codec, true);
+ wcd9xxx_turn_onoff_override(mbhc, true);
timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
while (!time_after(jiffies, timeout)) {
@@ -2728,7 +2742,7 @@
wcd9xxx_turn_onoff_current_source(mbhc, false,
false);
else
- wcd9xxx_turn_onoff_override(codec, false);
+ wcd9xxx_turn_onoff_override(mbhc, false);
/*
* The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
*/
@@ -2754,7 +2768,7 @@
if (!correction && current_source_enable)
wcd9xxx_turn_onoff_current_source(mbhc, false, highhph);
else if (!correction)
- wcd9xxx_turn_onoff_override(codec, false);
+ wcd9xxx_turn_onoff_override(mbhc, false);
wcd9xxx_onoff_ext_mclk(mbhc, false);
@@ -2853,7 +2867,7 @@
snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
0x08, 0x00);
/* Turn off override */
- wcd9xxx_turn_onoff_override(codec, false);
+ wcd9xxx_turn_onoff_override(mbhc, false);
}
}
@@ -3443,7 +3457,13 @@
* LDOH and CFILT are already configured during pdata handling.
* Only need to make sure CFILT and bandgap are in Fast mode.
* Need to restore defaults once calculation is done.
+ *
+ * In case when Micbias is powered by external source, request
+ * turn on the external voltage source for Calibration.
*/
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+ mbhc->mbhc_cb->enable_mb_source(codec, true);
+
cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
if (mbhc->mbhc_cb && mbhc->mbhc_cb->cfilt_fast_mode)
mbhc->mbhc_cb->cfilt_fast_mode(codec, mbhc);
@@ -3563,6 +3583,9 @@
0x80, 0x80);
usleep_range(100, 100);
+ if (mbhc->mbhc_cb && mbhc->mbhc_cb->enable_mb_source)
+ mbhc->mbhc_cb->enable_mb_source(codec, false);
+
wcd9xxx_enable_irq(mbhc->resmgr->core_res, WCD9XXX_IRQ_MBHC_POTENTIAL);
wcd9xxx_turn_onoff_rel_detection(codec, true);
@@ -4287,7 +4310,7 @@
wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
- wcd9xxx_turn_onoff_override(codec, true);
+ wcd9xxx_turn_onoff_override(mbhc, true);
pr_debug("%s: Setting impedance detection\n", __func__);
/* Codec specific setup for L0, R0, L1 and R1 measurements */
@@ -4338,7 +4361,7 @@
wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
WCD9XXX_BG_CLK_UNLOCK(mbhc->resmgr);
- wcd9xxx_turn_onoff_override(codec, false);
+ wcd9xxx_turn_onoff_override(mbhc, false);
mbhc->mbhc_cb->compute_impedance(l, r, zl, zr);
pr_debug("%s: L0: 0x%x(%d), L1: 0x%x(%d), L2: 0x%x(%d)\n",
diff --git a/sound/soc/codecs/wcd9xxx-mbhc.h b/sound/soc/codecs/wcd9xxx-mbhc.h
index 2e502cd..161c83d 100644
--- a/sound/soc/codecs/wcd9xxx-mbhc.h
+++ b/sound/soc/codecs/wcd9xxx-mbhc.h
@@ -251,6 +251,7 @@
enum mbhc_impedance_detect_stages stage);
void (*compute_impedance) (s16 *, s16 *, uint32_t *, uint32_t *);
void (*enable_mbhc_txfe) (struct snd_soc_codec *, bool);
+ int (*enable_mb_source) (struct snd_soc_codec *, bool);
};
struct wcd9xxx_mbhc {