Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 35132a38 authored by Simmi Pateriya's avatar Simmi Pateriya
Browse files

ASoC: wcd: fix issues in extension cable



Prevent false button press on removal of headset from
the extension cable by cancelling the work in the
removal handler. If PA is enabled by dapm while we
enable schmitt trigger, it can cause continuous
electrical insertion interrupts from HPHL. To avoid
this make sure the PA's are off before enabling schmitt
trigger. Do not touch button press interrupt flag anywhere.

Change-Id: I9793af29f6580b9f5ab6d9f602cdcd156cb8dce8
Signed-off-by: default avatarSimmi Pateriya <simmip@codeaurora.org>
Signed-off-by: default avatarYeleswarapu Nagaradhesh <nagaradh@codeaurora.org>
parent 65ea13bc
Loading
Loading
Loading
Loading
+46 −28
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@
#define HS_VREF_MIN_VAL 1400
#define FW_READ_ATTEMPTS 15
#define FW_READ_TIMEOUT 4000000
#define FAKE_REM_RETRY_ATTEMPTS 3

static int det_extn_cable_en;
module_param(det_extn_cable_en, int,
@@ -464,7 +465,7 @@ static void wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
	struct snd_soc_codec *codec = mbhc->codec;
	s16 impedance_l, impedance_r;
	s16 impedance_l_fixed;
	s16 reg0, reg1, reg2;
	s16 reg0, reg1, reg2, reg3, reg4;
	bool high = false;

	pr_debug("%s: enter\n", __func__);
@@ -473,11 +474,16 @@ static void wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
	reg0 = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MBHC_DBNC_TIMER);
	reg1 = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MBHC_BTN2_ZDETH_CTL);
	reg2 = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2);
	reg3 = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN);
	reg4 = snd_soc_read(codec, MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL);

	/* disable FSM */
	/* disable FSM and micbias*/
	snd_soc_update_bits(codec,
			MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
			0x80, 0x00);
	snd_soc_update_bits(codec,
			MSM8X16_WCD_A_ANALOG_MICB_2_EN,
			0x80, 0x00);
	/*
	 * Enable legacy electrical detection current sources
	 * and disable fast ramp and enable manual switching
@@ -628,13 +634,8 @@ static void wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
			0x02, 0x00);

exit:
	/*
	 * Enable the FSM and button source back for
	 * button detection.
	 */
	snd_soc_update_bits(codec,
			MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
			0xFF, 0xB0);
	snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL, reg4);
	snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MICB_2_EN, reg3);
	snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MBHC_BTN2_ZDETH_CTL, reg1);
	snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MBHC_DBNC_TIMER, reg0);
	snd_soc_write(codec, MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2, reg2);
@@ -775,6 +776,11 @@ static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,

	WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);

	if (mbhc->current_plug == plug_type) {
		pr_debug("%s: cable already reported, exit\n", __func__);
		goto exit;
	}

	if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
		/*
		 * Nothing was reported previously
@@ -828,6 +834,7 @@ static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
		WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
		     mbhc->current_plug, plug_type);
	}
exit:
	pr_debug("%s: leave\n", __func__);
}

@@ -1035,7 +1042,7 @@ static void wcd_correct_swch_plug(struct work_struct *work)
			wrk_complete = false;
		}
	}
	if (mbhc->btn_press_intr) {
	if (!wrk_complete && mbhc->btn_press_intr) {
		pr_debug("%s: Can be slow insertion of headphone\n", __func__);
		plug_type = MBHC_PLUG_TYPE_HEADPHONE;
	}
@@ -1307,10 +1314,6 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
			snd_soc_update_bits(codec,
					MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
					0x06, 0x00);
			/* Enable current source */
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
				0x30, 0x30);
			wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
		} else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) {
			wcd9xxx_spmi_disable_irq(
@@ -1323,10 +1326,6 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
			snd_soc_update_bits(codec,
					MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_2,
					0x06, 0x00);
			/* Enable current source */
			snd_soc_update_bits(codec,
				MSM8X16_WCD_A_ANALOG_MBHC_FSM_CTL,
				0x30, 0x30);
			wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT);
		}
	} else if (!detection_type) {
@@ -1467,6 +1466,12 @@ determine_plug:
		0x80, 0x80);
	hphl_trigerred = 0;
	mic_trigerred = 0;
	/*
	 * even if controls comes here, it is taking more than
	 * debounce time to detect cable as headphone, so wait
	 * for 20msec for the mic line to stabilize
	 */
	msleep(20);
	wcd_mbhc_detect_plug_type(mbhc);
	WCD_MBHC_RSC_UNLOCK(mbhc);
	pr_debug("%s: leave\n", __func__);
@@ -1482,20 +1487,27 @@ static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data)
	static u16 mic_trigerred;
	unsigned long timeout;
	bool removed = true;
	int retry = 0;

	pr_debug("%s: enter\n", __func__);

	WCD_MBHC_RSC_LOCK(mbhc);

	wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
	timeout = jiffies +
		  msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
	do {
		retry++;
		/*
		 * read the result2 register every 10ms to look for
		 * any change in HS_COMP_RESULT bit
		 */
		usleep_range(10000, 10100);
		result2 = (snd_soc_read(codec,
			MSM8X16_WCD_A_ANALOG_MBHC_ZDET_ELECT_RESULT));
		pr_debug("%s: check result2 for fake removal: %x\n",
			 __func__, result2);
		if (!(result2 & 0x01)) {
		if ((!(result2 & 0x01)) &&
		    retry > FAKE_REM_RETRY_ATTEMPTS) {
			removed = false;
			break;
		}
@@ -1537,7 +1549,21 @@ static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data)

report_unplug:

	/* cancel pending button press */
	if (wcd_cancel_btn_work(mbhc))
		pr_debug("%s: button press is canceled\n", __func__);
	/* cancel correct work function */
	wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);

	pr_debug("%s: Report extension cable\n", __func__);
	wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
	/*
	 * If PA is enabled HPHL schmitt trigger can
	 * be unreliable, make sure to disable it
	 */
	if (test_bit(WCD_MBHC_EVENT_PA_HPHL,
		&mbhc->event_state))
		wcd_mbhc_set_and_turnoff_hph_padac(mbhc);
	/*
	 * Disable HPHL trigger and MIC Schmitt triggers.
	 * Setup for insertion detection.
@@ -1555,7 +1581,6 @@ report_unplug:
	snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_MBHC_DET_CTL_1,
				0x01, 0x01);
	wcd9xxx_spmi_enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
	wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
	hphl_trigerred = 0;
	mic_trigerred = 0;
	WCD_MBHC_RSC_UNLOCK(mbhc);
@@ -1644,13 +1669,6 @@ irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
		goto done;
	}
	if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) {
		if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) {
			pr_debug("%s: Ignore this button press\n",
					__func__);
			mbhc->btn_press_intr = false;
			mbhc->is_btn_press = false;
			goto done;
		}
		pr_debug("%s: Plug isn't headset, ignore button press\n",
				__func__);
		goto done;