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

Commit ec74a6c1 authored by Walter Yang's avatar Walter Yang Committed by Banajit Goswami
Browse files

ASoC: mbhc: change detection for cross connection and special headset



Update the detection sequence for cross connection and special headset
to cover corner cases including slow/normal insertion of different
types of accessory.

Change-Id: I66ff3f17950b4126da6bd1246a45b45f816031c5
CRs-Fixed: 2010478
Signed-off-by: default avatarWalter Yang <yandongy@codeaurora.org>
parent 038e6615
Loading
Loading
Loading
Loading
+93 −50
Original line number Diff line number Diff line
@@ -382,15 +382,16 @@ static bool wcd_mbhc_adc_check_for_spl_headset(struct wcd_mbhc *mbhc,
	}

	/* MB2 back to 1.8v if the type is not special headset */
	if (!spl_hs) {
	if (*spl_hs_cnt != WCD_MBHC_SPL_HS_CNT) {
		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
				mbhc->mbhc_cfg->mbhc_micbias, false);
		/* Add 10ms delay for micbias to settle */
		usleep_range(10000, 10100);
	} else {
		pr_debug("%s: Detected special HS (%d)\n", __func__, spl_hs);
	}

	if (spl_hs)
		pr_debug("%s: Detected special HS (%d)\n", __func__, spl_hs);

exit:
	pr_debug("%s: leave\n", __func__);
	return spl_hs;
@@ -401,28 +402,63 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
	int delay = 0;
	bool ret = false;
	bool is_spl_hs = false;
	int spl_hs_count = 0;
	int output_mv = 0;
	int adc_threshold = 0;

	/*
	 * Increase micbias to 2.7V to detect headsets with
	 * threshold on microphone
	 */
	if (mbhc->mbhc_cb->mbhc_micbias_control &&
	    !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
		pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n",
			 __func__);
		return false;
	} else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
		ret = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
							MIC_BIAS_2, true);
		if (ret) {
			pr_err("%s: mbhc_micb_ctrl_thr_mic failed, ret: %d\n",
				__func__, ret);
			return false;
		}
	}

	adc_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
			  wcd_mbhc_get_micbias(mbhc)) /
			  WCD_MBHC_ADC_MICBIAS_MV);

	while (!is_spl_hs) {
		delay += 50;
		if (mbhc->hs_detect_work_stop) {
			pr_debug("%s: stop requested: %d\n", __func__,
					mbhc->hs_detect_work_stop);
			break;
		}
		delay += 50;
		/* Wait for 50ms for FSM to update result */
		msleep(50);
		is_spl_hs = wcd_mbhc_adc_check_for_spl_headset(mbhc,
							       &spl_hs_count);
		if (is_spl_hs)
			pr_debug("%s: Spl headset detected in %d msecs\n",
		output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
		if (output_mv <= adc_threshold) {
			pr_debug("%s: Special headset detected in %d msecs\n",
					__func__, delay);
			is_spl_hs = true;
		}

		if (delay == SPECIAL_HS_DETECT_TIME_MS) {
			pr_debug("%s: Spl headset not found in 2 sec\n",
				 __func__);
			break;
		}
	}
	if (is_spl_hs) {
		pr_debug("%s: Headset with threshold found\n",  __func__);
		mbhc->micbias_enable = true;
		ret = true;
	}
	if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
	    !mbhc->micbias_enable)
		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec, MIC_BIAS_2,
						      false);
	pr_debug("%s: leave, micb_enable: %d\n", __func__,
		  mbhc->micbias_enable);

@@ -533,19 +569,6 @@ static int wcd_mbhc_get_plug_from_adc(int adc_result)
	return plug_type;
}

static int wcd_mbhc_get_plug_type(struct wcd_mbhc *mbhc)
{
	int result_mv = 0;

	/*
	 * Use ADC single mode to minimize the chance of missing out
	 * btn press/release for HEADSET type during correct work.
	 */
	result_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);

	return wcd_mbhc_get_plug_from_adc(result_mv);
}

static void wcd_correct_swch_plug(struct work_struct *work)
{
	struct wcd_mbhc *mbhc;
@@ -553,7 +576,8 @@ static void wcd_correct_swch_plug(struct work_struct *work)
	enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
	unsigned long timeout;
	bool wrk_complete = false;
	int gnd_mic_swap_cnt = 0;
	int pt_gnd_mic_swap_cnt = 0;
	int no_gnd_mic_swap_cnt = 0;
	bool is_pa_on = false, spl_hs = false;
	int ret = 0;
	int spl_hs_count = 0;
@@ -647,9 +671,12 @@ static void wcd_correct_swch_plug(struct work_struct *work)
			spl_hs = wcd_mbhc_adc_check_for_spl_headset(mbhc,
								&spl_hs_count);

			if (spl_hs_count == WCD_MBHC_SPL_HS_CNT)
			if (spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
				output_mv = WCD_MBHC_ADC_HS_THRESHOLD_MV;
				spl_hs = true;
				mbhc->micbias_enable = true;
			}
		}

		if (mbhc->mbhc_cb->hph_pa_on_status)
			is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec);
@@ -660,9 +687,14 @@ static void wcd_correct_swch_plug(struct work_struct *work)
			ret = wcd_check_cross_conn(mbhc);
			if (ret < 0)
				continue;
			if (ret > 0) {
				/* Found cross connection, swap mic/gnd */
				if (gnd_mic_swap_cnt > GND_MIC_SWAP_THRESHOLD) {
			else if (ret > 0) {
				pt_gnd_mic_swap_cnt++;
				no_gnd_mic_swap_cnt = 0;
				if (pt_gnd_mic_swap_cnt <
						GND_MIC_SWAP_THRESHOLD) {
					continue;
				} else if (pt_gnd_mic_swap_cnt >
					   GND_MIC_SWAP_THRESHOLD) {
					/*
					 * This is due to GND/MIC switch didn't
					 * work,  Report unsupported plug.
@@ -671,37 +703,47 @@ static void wcd_correct_swch_plug(struct work_struct *work)
						 __func__);
					plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
					goto report;
				}
				gnd_mic_swap_cnt++;
				if (mbhc->mbhc_cfg->swap_gnd_mic &&
					mbhc->mbhc_cfg->swap_gnd_mic(codec)) {
					pr_debug("%s: US_EU gpio present,flip switch\n"
						, __func__);
					continue;
				} else {
					plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
				}
			} else {
				gnd_mic_swap_cnt++;
				plug_type = wcd_mbhc_get_plug_type(mbhc);
				if ((gnd_mic_swap_cnt <=
				no_gnd_mic_swap_cnt++;
				pt_gnd_mic_swap_cnt = 0;
				plug_type = wcd_mbhc_get_plug_from_adc(
						output_mv);
				if ((no_gnd_mic_swap_cnt <
				    GND_MIC_SWAP_THRESHOLD) &&
				    (spl_hs_count != WCD_MBHC_SPL_HS_CNT)) {
					continue;
				} else {
					gnd_mic_swap_cnt = 0;
					no_gnd_mic_swap_cnt = 0;
				}
			}
			if ((pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) &&
				(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
				/*
				 * if switch is toggled, check again,
				 * otherwise report unsupported plug
				 */
				if (mbhc->mbhc_cfg->swap_gnd_mic &&
					mbhc->mbhc_cfg->swap_gnd_mic(codec)) {
					pr_debug("%s: US_EU gpio present,flip switch\n"
						, __func__);
					continue;
				}
			}
		}

		if (!spl_hs && (plug_type == MBHC_PLUG_TYPE_HIGH_HPH)) {
		if (output_mv > WCD_MBHC_ADC_HS_THRESHOLD_MV) {
			pr_debug("%s: cable is extension cable\n", __func__);
			plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
			wrk_complete = true;
		} else {
			pr_debug("%s: cable might be headset: %d\n", __func__,
				 plug_type);
			if (plug_type != MBHC_PLUG_TYPE_GND_MIC_SWAP) {
				if (!spl_hs)
					plug_type =
						wcd_mbhc_get_plug_type(mbhc);
				else
					plug_type = MBHC_PLUG_TYPE_HEADSET;
				plug_type = wcd_mbhc_get_plug_from_adc(
						output_mv);
				/*
				 * Report headset only if not already reported
				 * and if there is not button press without
@@ -710,11 +752,12 @@ static void wcd_correct_swch_plug(struct work_struct *work)
				if ((mbhc->current_plug !=
				      MBHC_PLUG_TYPE_HEADSET) &&
				     (mbhc->current_plug !=
				     MBHC_PLUG_TYPE_ANC_HEADPHONE)) {
					if (plug_type == MBHC_PLUG_TYPE_HEADSET)
				     MBHC_PLUG_TYPE_ANC_HEADPHONE) &&
				    !wcd_swch_level_remove(mbhc)) {
					pr_debug("%s: cable is %s headset\n",
						 __func__,
							((spl_hs) ?
						((spl_hs_count ==
							WCD_MBHC_SPL_HS_CNT) ?
							"special ":""));
					goto report;
				}