From 37621b06ee1a74fcfcc6668ac5df79c17625169f Mon Sep 17 00:00:00 2001 From: Meng Wang Date: Fri, 12 Jan 2018 13:17:59 +0800 Subject: [PATCH] ASoC: wcd-mbhc: correct special headset detection logic When detecting special headset, vref for special headset is set based on headset threshold reference 1800mv or based on regular micbias settings from device tree. Scale threshold reference as per the special headset micbias voltage. Change-Id: Ic4cc24e18efeb420b53a2154707c9399eb886181 Signed-off-by: Meng Wang --- asoc/codecs/wcd-mbhc-adc.c | 112 ++++++++++++++++++----------- asoc/codecs/wcd934x/wcd934x-mbhc.c | 11 ++- include/asoc/wcd-mbhc-v2.h | 3 +- 3 files changed, 83 insertions(+), 43 deletions(-) diff --git a/asoc/codecs/wcd-mbhc-adc.c b/asoc/codecs/wcd-mbhc-adc.c index 4ab510c7e0..4a2c928a90 100644 --- a/asoc/codecs/wcd-mbhc-adc.c +++ b/asoc/codecs/wcd-mbhc-adc.c @@ -343,14 +343,66 @@ done: return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false; } +static int wcd_mbhc_adc_get_spl_hs_thres(struct wcd_mbhc *mbhc) +{ + int hs_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->hs_thr && mbhc->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) { + if (mbhc->micb_mv == micbias_mv) + hs_threshold = mbhc->hs_thr; + else + hs_threshold = (mbhc->hs_thr * + micbias_mv) / mbhc->micb_mv; + } else { + hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * + micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); + } + return hs_threshold; +} + +static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc) +{ + int hs_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->hs_thr) { + if (mbhc->micb_mv == micbias_mv) + hs_threshold = mbhc->hs_thr; + else + hs_threshold = (mbhc->hs_thr * + micbias_mv) / mbhc->micb_mv; + } else { + hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * + micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); + } + return hs_threshold; +} + +static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc) +{ + int hph_threshold, micbias_mv; + + micbias_mv = wcd_mbhc_get_micbias(mbhc); + if (mbhc->hph_thr) { + if (mbhc->micb_mv == micbias_mv) + hph_threshold = mbhc->hph_thr; + else + hph_threshold = (mbhc->hph_thr * + micbias_mv) / mbhc->micb_mv; + } else { + hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV * + micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV); + } + return hph_threshold; +} + static bool wcd_mbhc_adc_check_for_spl_headset(struct wcd_mbhc *mbhc, int *spl_hs_cnt) { bool spl_hs = false; int output_mv = 0; int adc_threshold = 0, adc_hph_threshold = 0; - struct snd_soc_component *component = mbhc->component; - struct wcd9xxx_pdata *pdata = dev_get_platdata(component->dev->parent); pr_debug("%s: enter\n", __func__); if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) @@ -366,20 +418,8 @@ static bool wcd_mbhc_adc_check_for_spl_headset(struct wcd_mbhc *mbhc, * btn press/relesae for HEADSET type during correct work. */ output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); - - if (mbhc->hs_thr && - (pdata->micbias.micb2_mv != WCD_MBHC_ADC_MICBIAS_MV)) - adc_threshold = mbhc->hs_thr; - else - adc_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * - wcd_mbhc_get_micbias(mbhc))/WCD_MBHC_ADC_MICBIAS_MV); - - if (mbhc->hph_thr) - adc_hph_threshold = mbhc->hph_thr; - else - adc_hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV * - wcd_mbhc_get_micbias(mbhc))/ - WCD_MBHC_ADC_MICBIAS_MV); + adc_threshold = wcd_mbhc_adc_get_spl_hs_thres(mbhc); + adc_hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc); if (output_mv > adc_threshold || output_mv < adc_hph_threshold) { spl_hs = false; @@ -412,8 +452,6 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) bool is_spl_hs = false; int output_mv = 0; int adc_threshold = 0; - struct snd_soc_component *component = mbhc->component; - struct wcd9xxx_pdata *pdata = dev_get_platdata(component->dev->parent); /* * Increase micbias to 2.7V to detect headsets with @@ -433,13 +471,7 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) return false; } } - if (mbhc->hs_thr && - (pdata->micbias.micb2_mv != WCD_MBHC_ADC_MICBIAS_MV)) - adc_threshold = mbhc->hs_thr; - else - adc_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * - wcd_mbhc_get_micbias(mbhc)) / - WCD_MBHC_ADC_MICBIAS_MV); + adc_threshold = wcd_mbhc_adc_get_spl_hs_thres(mbhc); while (!is_spl_hs) { if (mbhc->hs_detect_work_stop) { @@ -573,15 +605,8 @@ static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result) enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID; u32 hph_thr = 0, hs_thr = 0; - if (mbhc->hs_thr) - hs_thr = mbhc->hs_thr; - else - hs_thr = WCD_MBHC_ADC_HS_THRESHOLD_MV; - - if (mbhc->hph_thr) - hph_thr = mbhc->hph_thr; - else - hph_thr = WCD_MBHC_ADC_HPH_THRESHOLD_MV; + hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc); + hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc); if (adc_result < hph_thr) plug_type = MBHC_PLUG_TYPE_HEADPHONE; @@ -609,12 +634,16 @@ static void wcd_correct_swch_plug(struct work_struct *work) int output_mv = 0; int cross_conn; int try = 0; + int hs_threshold, micbias_mv; pr_debug("%s: enter\n", __func__); mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); component = mbhc->component; + micbias_mv = wcd_mbhc_get_micbias(mbhc); + hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); + WCD_MBHC_RSC_LOCK(mbhc); /* Mask ADC COMPLETE interrupt */ wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false); @@ -691,13 +720,15 @@ correct_plug_type: */ plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); - if ((output_mv > WCD_MBHC_ADC_HS_THRESHOLD_MV) && + if ((output_mv > hs_threshold) && (spl_hs_count < WCD_MBHC_SPL_HS_CNT)) { spl_hs = wcd_mbhc_adc_check_for_spl_headset(mbhc, &spl_hs_count); + output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); if (spl_hs_count == WCD_MBHC_SPL_HS_CNT) { - output_mv = WCD_MBHC_ADC_HS_THRESHOLD_MV; + hs_threshold = (hs_threshold * + wcd_mbhc_get_micbias(mbhc)) / micbias_mv; spl_hs = true; mbhc->micbias_enable = true; } @@ -707,7 +738,7 @@ correct_plug_type: is_pa_on = mbhc->mbhc_cb->hph_pa_on_status( mbhc->component); - if ((output_mv <= WCD_MBHC_ADC_HS_THRESHOLD_MV) && + if ((output_mv <= hs_threshold) && (!is_pa_on)) { /* Check for cross connection*/ ret = wcd_check_cross_conn(mbhc); @@ -761,7 +792,7 @@ correct_plug_type: } } - if (output_mv > WCD_MBHC_ADC_HS_THRESHOLD_MV) { + if (output_mv > hs_threshold) { pr_debug("%s: cable is extension cable\n", __func__); plug_type = MBHC_PLUG_TYPE_HIGH_HPH; wrk_complete = true; @@ -926,9 +957,8 @@ static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data) timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS); - adc_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * - wcd_mbhc_get_micbias(mbhc)) / - WCD_MBHC_ADC_MICBIAS_MV); + adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); + do { retry++; /* diff --git a/asoc/codecs/wcd934x/wcd934x-mbhc.c b/asoc/codecs/wcd934x/wcd934x-mbhc.c index f00e4c0a98..d777d8d564 100644 --- a/asoc/codecs/wcd934x/wcd934x-mbhc.c +++ b/asoc/codecs/wcd934x/wcd934x-mbhc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. */ #include #include @@ -1102,6 +1102,7 @@ int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct wcd934x_mbhc *wcd934x_mbhc; struct wcd_mbhc *wcd_mbhc; int ret; + struct wcd9xxx_pdata *pdata; wcd934x_mbhc = devm_kzalloc(component->dev, sizeof(struct wcd934x_mbhc), GFP_KERNEL); @@ -1122,6 +1123,14 @@ int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, /* Setting default mbhc detection logic to ADC for Tavil */ wcd_mbhc->mbhc_detection_logic = WCD_DETECTION_ADC; + pdata = dev_get_platdata(component->dev->parent); + if (!pdata) { + dev_err(component->dev, "%s: pdata pointer is NULL\n", __func__); + ret = -EINVAL; + goto err; + } + wcd_mbhc->micb_mv = pdata->micbias.micb2_mv; + ret = wcd_mbhc_init(wcd_mbhc, component, &mbhc_cb, &intr_ids, wcd_mbhc_registers, TAVIL_ZDET_SUPPORTED); diff --git a/include/asoc/wcd-mbhc-v2.h b/include/asoc/wcd-mbhc-v2.h index c98cdda944..9341e3d3c7 100644 --- a/include/asoc/wcd-mbhc-v2.h +++ b/include/asoc/wcd-mbhc-v2.h @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. */ #ifndef __WCD_MBHC_V2_H__ #define __WCD_MBHC_V2_H__ @@ -540,6 +540,7 @@ struct wcd_mbhc { bool gnd_swh; /*track GND switch NC / NO */ u32 hs_thr; u32 hph_thr; + u32 micb_mv; u32 swap_thr; u32 moist_vref; u32 moist_iref;