Browse Source

Merge "ASoC: wcd-mbhc: update electrical removal detection logic"

Linux Build Service Account 7 years ago
parent
commit
50091ca0c6

+ 55 - 11
asoc/codecs/wcd-mbhc-adc.c

@@ -915,6 +915,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);
@@ -948,17 +950,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__);

+ 73 - 17
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);

+ 2 - 1
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)
 {

+ 6 - 0
asoc/codecs/wcd-mbhc-v2.h

@@ -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,
@@ -596,5 +600,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__ */

+ 6 - 0
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 = {

+ 6 - 0
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",