ASoC: wcd-mbhc: update electrical removal detection logic

when moisture is in jack, removing of the plug result in
electrical removal interrupt. So, update electrical interrupt
handler to handle mechanical removal based on moisture status.

CRs-Fixed: 2058106
Change-Id: I9cfbfbaf04783f0edcadb14d7828759020745289
Signed-off-by: Meng Wang <mwang@codeaurora.org>
This commit is contained in:
Meng Wang 2017-09-19 10:21:57 +08:00
parent 7cc0186011
commit 6f90162f22
6 changed files with 148 additions and 29 deletions

View file

@ -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__);

View file

@ -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 @@ static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data)
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);

View file

@ -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)
{

View file

@ -16,6 +16,7 @@
#include <linux/stringify.h>
#include <linux/power_supply.h>
#include "wcdcal-hwdep.h"
#include <sound/jack.h>
#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__ */

View file

@ -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 = {

View file

@ -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",