diff --git a/asoc/codecs/wcd-mbhc-adc.c b/asoc/codecs/wcd-mbhc-adc.c index e44eec9fa5..ad414770a2 100644 --- a/asoc/codecs/wcd-mbhc-adc.c +++ b/asoc/codecs/wcd-mbhc-adc.c @@ -895,6 +895,8 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) struct wcd_mbhc *mbhc = data; unsigned long timeout; int adc_threshold, output_mv, retry = 0; + bool hphpa_on = false; + u8 moisture_status = 0; pr_debug("%s: enter\n", __func__); WCD_MBHC_RSC_LOCK(mbhc); @@ -928,17 +930,59 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) goto exit; } - /* - * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE, - * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one - * when HEADPHONE is removed. - */ - if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) - mbhc->extn_cable_hph_rem = true; - WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0); - WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0); - WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0); - wcd_mbhc_elec_hs_report_unplug(mbhc); + if (mbhc->mbhc_cfg->moisture_en) { + if (mbhc->mbhc_cb->hph_pa_on_status) + if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec)) { + hphpa_on = true; + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_HPHL_PA_EN, 0); + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_HPH_PA_EN, 0); + } + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_GND, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_GND, 1); + /* wait for 50ms to get moisture status */ + usleep_range(50000, 50100); + + WCD_MBHC_REG_READ(WCD_MBHC_MOISTURE_STATUS, moisture_status); + } + + if (mbhc->mbhc_cfg->moisture_en && !moisture_status) { + pr_debug("%s: moisture present in jack\n", __func__); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MECH_DETECTION_TYPE, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + mbhc->btn_press_intr = false; + mbhc->is_btn_press = false; + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET); + else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); + else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED); + else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) + wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT); + } else { + /* + * ADC COMPLETE and ELEC_REM interrupts are both enabled for + * HEADPHONE, need to reject the ADC COMPLETE interrupt which + * follows ELEC_REM one when HEADPHONE is removed. + */ + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) + mbhc->extn_cable_hph_rem = true; + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0); + wcd_mbhc_elec_hs_report_unplug(mbhc); + + if (hphpa_on) { + hphpa_on = false; + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPH_PA_EN, 1); + } + } exit: WCD_MBHC_RSC_UNLOCK(mbhc); pr_debug("%s: leave\n", __func__); diff --git a/asoc/codecs/wcd-mbhc-legacy.c b/asoc/codecs/wcd-mbhc-legacy.c index 745e2e81a5..a72f64b408 100644 --- a/asoc/codecs/wcd-mbhc-legacy.c +++ b/asoc/codecs/wcd-mbhc-legacy.c @@ -794,6 +794,8 @@ static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data) unsigned long timeout; bool removed = true; int retry = 0; + bool hphpa_on = false; + u8 moisture_status = 0; pr_debug("%s: enter\n", __func__); @@ -830,29 +832,78 @@ static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data) WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result); if (removed) { - if (!(hphl_sch && mic_sch && hs_comp_result)) { - /* - * extension cable is still plugged in - * report it as LINEOUT device - */ - goto report_unplug; + if (mbhc->mbhc_cfg->moisture_en) { + if (mbhc->mbhc_cb->hph_pa_on_status) + if ( + mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec)) { + hphpa_on = true; + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_HPHL_PA_EN, 0); + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_HPH_PA_EN, 0); + } + + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_GND, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_GND, 1); + /* wait for 50ms to get moisture status */ + usleep_range(50000, 50100); + + WCD_MBHC_REG_READ( + WCD_MBHC_MOISTURE_STATUS, moisture_status); + } + + if (mbhc->mbhc_cfg->moisture_en && !moisture_status) { + pr_debug("%s: moisture present in jack\n", __func__); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0); + WCD_MBHC_REG_UPDATE_BITS( + WCD_MBHC_MECH_DETECTION_TYPE, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + mbhc->btn_press_intr = false; + mbhc->is_btn_press = false; + if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) + wcd_mbhc_report_plug( + mbhc, 0, SND_JACK_HEADSET); + else if (mbhc->current_plug == + MBHC_PLUG_TYPE_HEADPHONE) + wcd_mbhc_report_plug( + mbhc, 0, SND_JACK_HEADPHONE); + else if (mbhc->current_plug == + MBHC_PLUG_TYPE_GND_MIC_SWAP) + wcd_mbhc_report_plug( + mbhc, 0, SND_JACK_UNSUPPORTED); + else if (mbhc->current_plug == + MBHC_PLUG_TYPE_HIGH_HPH) + wcd_mbhc_report_plug( + mbhc, 0, SND_JACK_LINEOUT); } else { - if (!mic_sch) { - mic_trigerred++; - pr_debug("%s: Removal MIC trigerred %d\n", - __func__, mic_trigerred); - } - if (!hphl_sch) { - hphl_trigerred++; - pr_debug("%s: Removal HPHL trigerred %d\n", - __func__, hphl_trigerred); - } - if (mic_trigerred && hphl_trigerred) { + if (!(hphl_sch && mic_sch && hs_comp_result)) { /* * extension cable is still plugged in * report it as LINEOUT device */ goto report_unplug; + } else { + if (!mic_sch) { + mic_trigerred++; + pr_debug( + "%s: Removal MIC trigerred %d\n", + __func__, mic_trigerred); + } + if (!hphl_sch) { + hphl_trigerred++; + pr_debug( + "%s: Removal HPHL trigerred %d\n", + __func__, hphl_trigerred); + } + if (mic_trigerred && hphl_trigerred) { + /* + * extension cable is still plugged in + * report it as LINEOUT device + */ + goto report_unplug; + } } } } @@ -863,6 +914,11 @@ exit: report_unplug: wcd_mbhc_elec_hs_report_unplug(mbhc); + if (hphpa_on) { + hphpa_on = false; + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPH_PA_EN, 1); + } hphl_trigerred = 0; mic_trigerred = 0; WCD_MBHC_RSC_UNLOCK(mbhc); diff --git a/asoc/codecs/wcd-mbhc-v2.c b/asoc/codecs/wcd-mbhc-v2.c index 6b3dd8626d..339d0f3d42 100644 --- a/asoc/codecs/wcd-mbhc-v2.c +++ b/asoc/codecs/wcd-mbhc-v2.c @@ -550,7 +550,7 @@ void wcd_mbhc_hs_elec_irq(struct wcd_mbhc *mbhc, int irq_type, } EXPORT_SYMBOL(wcd_mbhc_hs_elec_irq); -static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, +void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, enum snd_jack_types jack_type) { struct snd_soc_codec *codec = mbhc->codec; @@ -725,6 +725,7 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, } pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status); } +EXPORT_SYMBOL(wcd_mbhc_report_plug); void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc) { diff --git a/asoc/codecs/wcd-mbhc-v2.h b/asoc/codecs/wcd-mbhc-v2.h index c8714fc3ab..32dc78ca0a 100644 --- a/asoc/codecs/wcd-mbhc-v2.h +++ b/asoc/codecs/wcd-mbhc-v2.h @@ -16,6 +16,7 @@ #include #include #include "wcdcal-hwdep.h" +#include #define TOMBAK_MBHC_NC 0 #define TOMBAK_MBHC_NO 1 @@ -204,6 +205,9 @@ enum wcd_mbhc_register_function { WCD_MBHC_ANC_DET_EN, WCD_MBHC_FSM_STATUS, WCD_MBHC_MUX_CTL, + WCD_MBHC_MOISTURE_STATUS, + WCD_MBHC_HPHR_GND, + WCD_MBHC_HPHL_GND, WCD_MBHC_HPHL_OCP_DET_EN, WCD_MBHC_HPHR_OCP_DET_EN, WCD_MBHC_HPHL_OCP_STATUS, @@ -594,5 +598,7 @@ void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc, struct snd_soc_jack *jack, int status, int mask); int wcd_cancel_btn_work(struct wcd_mbhc *mbhc); int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc); +void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, + enum snd_jack_types jack_type); #endif /* __WCD_MBHC_V2_H__ */ diff --git a/asoc/codecs/wcd9335.c b/asoc/codecs/wcd9335.c index 21de9f5f6d..19877b96b0 100644 --- a/asoc/codecs/wcd9335.c +++ b/asoc/codecs/wcd9335.c @@ -650,6 +650,12 @@ static struct wcd_mbhc_register 0, 0, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", WCD9335_MBHC_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS", + WCD9335_MBHC_FSM_STATUS, 0X20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND", + WCD9335_HPH_PA_CTL2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND", + WCD9335_HPH_PA_CTL2, 0x10, 4, 0), }; static const struct wcd_mbhc_intr intr_ids = { diff --git a/asoc/codecs/wcd934x/wcd934x-mbhc.c b/asoc/codecs/wcd934x/wcd934x-mbhc.c index 4eb14de310..807d4ea58e 100644 --- a/asoc/codecs/wcd934x/wcd934x-mbhc.c +++ b/asoc/codecs/wcd934x/wcd934x-mbhc.c @@ -120,6 +120,12 @@ static struct wcd_mbhc_register WCD934X_MBHC_STATUS_SPARE_1, 0x01, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", WCD934X_MBHC_NEW_CTL_2, 0x70, 4, 0), + WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_STATUS", + WCD934X_MBHC_NEW_FSM_STATUS, 0x20, 5, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHR_GND", + WCD934X_HPH_PA_CTL2, 0x40, 6, 0), + WCD_MBHC_REGISTER("WCD_MBHC_HPHL_GND", + WCD934X_HPH_PA_CTL2, 0x10, 4, 0), WCD_MBHC_REGISTER("WCD_MBHC_HPHL_OCP_DET_EN", WCD934X_HPH_L_TEST, 0x01, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_HPHR_OCP_DET_EN",