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 <mwang@codeaurora.org>
This commit is contained in:
Meng Wang
2018-01-12 13:17:59 +08:00
committad av Meng Wang
förälder e039f16fa4
incheckning 37621b06ee
3 ändrade filer med 83 tillägg och 43 borttagningar

Visa fil

@@ -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++;
/*