ASoC: wcd-mbhc: Add support for 5-pole plug detection
MBHC hardware block on WCD9335 supports 5-pole plug detection. Add support for 5-pole plug detection in MBHC driver. Change-Id: Ia2620b5cc3ef5065f350549d29cde063fdd1bf04 Signed-off-by: Phani Kumar Uppalapati <phaniu@codeaurora.org>
This commit is contained in:
parent
ed642a40cd
commit
f359b9f372
3 changed files with 170 additions and 23 deletions
|
@ -32,7 +32,9 @@
|
|||
|
||||
#define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
|
||||
SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
|
||||
SND_JACK_UNSUPPORTED | SND_JACK_MECHANICAL)
|
||||
SND_JACK_MECHANICAL | SND_JACK_MICROPHONE2 | \
|
||||
SND_JACK_UNSUPPORTED)
|
||||
|
||||
#define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
|
||||
SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
|
||||
SND_JACK_BTN_4 | SND_JACK_BTN_5 )
|
||||
|
@ -49,6 +51,7 @@
|
|||
#define MAX_IMPED 60000
|
||||
|
||||
#define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50
|
||||
#define ANC_DETECT_RETRY_CNT 7
|
||||
|
||||
static int det_extn_cable_en;
|
||||
module_param(det_extn_cable_en, int,
|
||||
|
@ -568,8 +571,8 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
|
|||
if (mbhc->micbias_enable) {
|
||||
if (mbhc->mbhc_cb->mbhc_micbias_control)
|
||||
mbhc->mbhc_cb->mbhc_micbias_control(
|
||||
mbhc->codec,
|
||||
MICB_DISABLE);
|
||||
mbhc->codec, MIC_BIAS_2,
|
||||
MICB_DISABLE);
|
||||
if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
|
||||
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
|
||||
mbhc->codec,
|
||||
|
@ -601,12 +604,12 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
|
|||
if (mbhc->micbias_enable) {
|
||||
if (mbhc->mbhc_cb->mbhc_micbias_control)
|
||||
mbhc->mbhc_cb->mbhc_micbias_control(
|
||||
mbhc->codec,
|
||||
MICB_DISABLE);
|
||||
mbhc->codec, MIC_BIAS_2,
|
||||
MICB_DISABLE);
|
||||
if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
|
||||
mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
|
||||
mbhc->codec,
|
||||
MIC_BIAS_2, false);
|
||||
mbhc->codec,
|
||||
MIC_BIAS_2, false);
|
||||
mbhc->micbias_enable = false;
|
||||
}
|
||||
mbhc->hph_type = WCD_MBHC_HPH_NONE;
|
||||
|
@ -633,6 +636,7 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
|
|||
}
|
||||
mbhc->hph_status &= ~(SND_JACK_HEADSET |
|
||||
SND_JACK_LINEOUT |
|
||||
SND_JACK_ANC_HEADPHONE |
|
||||
SND_JACK_UNSUPPORTED);
|
||||
}
|
||||
|
||||
|
@ -648,8 +652,10 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
|
|||
else if (jack_type == SND_JACK_HEADSET) {
|
||||
mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
|
||||
mbhc->jiffies_atreport = jiffies;
|
||||
} else if (jack_type == SND_JACK_LINEOUT)
|
||||
} else if (jack_type == SND_JACK_LINEOUT) {
|
||||
mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
|
||||
} else if (jack_type == SND_JACK_ANC_HEADPHONE)
|
||||
mbhc->current_plug = MBHC_PLUG_TYPE_ANC_HEADPHONE;
|
||||
|
||||
if (mbhc->impedance_detect &&
|
||||
mbhc->mbhc_cb->compute_impedance &&
|
||||
|
@ -689,9 +695,98 @@ static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
|
|||
pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status);
|
||||
}
|
||||
|
||||
static bool wcd_mbhc_detect_anc_plug_type(struct wcd_mbhc *mbhc)
|
||||
{
|
||||
bool anc_mic_found = false;
|
||||
u16 val, hs_comp_res, btn_status = 0;
|
||||
unsigned long retry = 0;
|
||||
int valid_plug_cnt = 0, invalid_plug_cnt = 0;
|
||||
int btn_status_cnt = 0;
|
||||
bool is_check_btn_press = false;
|
||||
|
||||
|
||||
if (mbhc->mbhc_cfg->anc_micbias < MIC_BIAS_1 ||
|
||||
mbhc->mbhc_cfg->anc_micbias > MIC_BIAS_4)
|
||||
return false;
|
||||
|
||||
if (!mbhc->mbhc_cb->mbhc_micbias_control)
|
||||
return false;
|
||||
|
||||
WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, val);
|
||||
|
||||
if (val)
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
|
||||
|
||||
mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
|
||||
mbhc->mbhc_cfg->anc_micbias,
|
||||
MICB_ENABLE);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x2);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 1);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
|
||||
/*
|
||||
* wait for button debounce time 20ms. If 4-pole plug is inserted
|
||||
* into 5-pole jack, then there will be a button press interrupt
|
||||
* during anc plug detection. In that case though Hs_comp_res is 0,
|
||||
* it should not be declared as ANC plug type
|
||||
*/
|
||||
usleep_range(20000, 20100);
|
||||
|
||||
/*
|
||||
* After enabling FSM, to handle slow insertion scenarios,
|
||||
* check hs_comp_result for few times to see if the IN3 voltage
|
||||
* is below the Vref
|
||||
*/
|
||||
do {
|
||||
if (wcd_swch_level_remove(mbhc)) {
|
||||
pr_debug("%s: Switch level is low\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
pr_debug("%s: Retry attempt %lu\n", __func__, retry + 1);
|
||||
WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
|
||||
|
||||
if (!hs_comp_res) {
|
||||
valid_plug_cnt++;
|
||||
is_check_btn_press = true;
|
||||
} else
|
||||
invalid_plug_cnt++;
|
||||
/* Wait 1ms before taking another reading */
|
||||
usleep_range(1000, 1100);
|
||||
|
||||
WCD_MBHC_REG_READ(WCD_MBHC_FSM_STATUS, btn_status);
|
||||
if (btn_status)
|
||||
btn_status_cnt++;
|
||||
|
||||
retry++;
|
||||
} while (retry < ANC_DETECT_RETRY_CNT);
|
||||
|
||||
pr_debug("%s: valid: %d, invalid: %d, btn_status_cnt: %d\n",
|
||||
__func__, valid_plug_cnt, invalid_plug_cnt, btn_status_cnt);
|
||||
|
||||
/* decision logic */
|
||||
if ((valid_plug_cnt > invalid_plug_cnt) && is_check_btn_press &&
|
||||
(btn_status_cnt == 0))
|
||||
anc_mic_found = true;
|
||||
exit:
|
||||
if (!val)
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
|
||||
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 0);
|
||||
|
||||
mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
|
||||
mbhc->mbhc_cfg->anc_micbias,
|
||||
MICB_DISABLE);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x0);
|
||||
pr_debug("%s: anc mic %sfound\n", __func__,
|
||||
anc_mic_found ? "" : "not ");
|
||||
return anc_mic_found;
|
||||
}
|
||||
|
||||
static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
|
||||
enum wcd_mbhc_plug_type plug_type)
|
||||
{
|
||||
bool anc_mic_found;
|
||||
enum snd_jack_types jack_type;
|
||||
|
||||
pr_debug("%s: enter current_plug(%d) new_plug(%d)\n",
|
||||
__func__, mbhc->current_plug, plug_type);
|
||||
|
||||
|
@ -716,11 +811,18 @@ static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
|
|||
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
|
||||
wcd_mbhc_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED);
|
||||
} else if (plug_type == MBHC_PLUG_TYPE_HEADSET) {
|
||||
if (mbhc->mbhc_cfg->enable_anc_mic_detect)
|
||||
anc_mic_found = wcd_mbhc_detect_anc_plug_type(mbhc);
|
||||
|
||||
jack_type = SND_JACK_HEADSET;
|
||||
if (anc_mic_found)
|
||||
jack_type = SND_JACK_ANC_HEADPHONE;
|
||||
|
||||
/*
|
||||
* If Headphone was reported previously, this will
|
||||
* only report the mic line
|
||||
*/
|
||||
wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET);
|
||||
wcd_mbhc_report_plug(mbhc, 1, jack_type);
|
||||
} else if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
|
||||
if (mbhc->mbhc_cfg->detect_extn_cable) {
|
||||
/* High impedance device found. Report as LINEOUT */
|
||||
|
@ -807,7 +909,8 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
|
|||
struct snd_soc_codec *codec = mbhc->codec;
|
||||
int delay = 0, rc;
|
||||
bool ret = false;
|
||||
bool hs_comp_res;
|
||||
u16 hs_comp_res;
|
||||
bool is_spl_hs = false;
|
||||
|
||||
/*
|
||||
* Increase micbias to 2.7V to detect headsets with
|
||||
|
@ -855,16 +958,18 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
|
|||
/* Wait for 50msec for FSM to update result values */
|
||||
msleep(50);
|
||||
WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
|
||||
if (!(hs_comp_res))
|
||||
if (!(hs_comp_res)) {
|
||||
pr_debug("%s: Special headset detected in %d msecs\n",
|
||||
__func__, (delay * 2));
|
||||
is_spl_hs = true;
|
||||
}
|
||||
if (delay == SPECIAL_HS_DETECT_TIME_MS) {
|
||||
pr_debug("%s: Spl headset didnt get detect in 4 sec\n",
|
||||
__func__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!(hs_comp_res)) {
|
||||
if (is_spl_hs) {
|
||||
pr_debug("%s: Headset with threshold found\n", __func__);
|
||||
mbhc->micbias_enable = true;
|
||||
ret = true;
|
||||
|
@ -900,6 +1005,7 @@ static void wcd_mbhc_update_fsm_source(struct wcd_mbhc *mbhc,
|
|||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
|
||||
break;
|
||||
case MBHC_PLUG_TYPE_HEADSET:
|
||||
case MBHC_PLUG_TYPE_ANC_HEADPHONE:
|
||||
if (!mbhc->is_hs_recording && !micbias2)
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
|
||||
break;
|
||||
|
@ -1131,9 +1237,11 @@ correct_plug_type:
|
|||
* and if there is not button press without
|
||||
* release
|
||||
*/
|
||||
if (mbhc->current_plug !=
|
||||
MBHC_PLUG_TYPE_HEADSET &&
|
||||
!mbhc->btn_press_intr) {
|
||||
if (((mbhc->current_plug !=
|
||||
MBHC_PLUG_TYPE_HEADSET) &&
|
||||
(mbhc->current_plug !=
|
||||
MBHC_PLUG_TYPE_ANC_HEADPHONE)) &&
|
||||
!mbhc->btn_press_intr) {
|
||||
pr_debug("%s: cable is headset\n",
|
||||
__func__);
|
||||
goto report;
|
||||
|
@ -1151,8 +1259,10 @@ correct_plug_type:
|
|||
* If plug_tye is headset, we might have already reported either in
|
||||
* detect_plug-type or in above while loop, no need to report again
|
||||
*/
|
||||
if (!wrk_complete && plug_type == MBHC_PLUG_TYPE_HEADSET) {
|
||||
pr_debug("%s: Headset already reported\n", __func__);
|
||||
if (!wrk_complete && ((plug_type == MBHC_PLUG_TYPE_HEADSET) ||
|
||||
(plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE))) {
|
||||
pr_debug("%s: plug_type:0x%x already reported\n",
|
||||
__func__, mbhc->current_plug);
|
||||
goto enable_supply;
|
||||
}
|
||||
|
||||
|
@ -1167,6 +1277,10 @@ correct_plug_type:
|
|||
}
|
||||
|
||||
report:
|
||||
if (wcd_swch_level_remove(mbhc)) {
|
||||
pr_debug("%s: Switch level is low\n", __func__);
|
||||
goto exit;
|
||||
}
|
||||
pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n",
|
||||
__func__, plug_type, wrk_complete,
|
||||
mbhc->btn_press_intr);
|
||||
|
@ -1181,7 +1295,7 @@ enable_supply:
|
|||
exit:
|
||||
if (mbhc->mbhc_cb->mbhc_micbias_control &&
|
||||
!mbhc->micbias_enable)
|
||||
mbhc->mbhc_cb->mbhc_micbias_control(codec,
|
||||
mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
|
||||
MICB_DISABLE);
|
||||
if (mbhc->mbhc_cb->micbias_enable_status) {
|
||||
micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
|
||||
|
@ -1222,7 +1336,8 @@ static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
|
|||
mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true);
|
||||
|
||||
if (mbhc->mbhc_cb->mbhc_micbias_control)
|
||||
mbhc->mbhc_cb->mbhc_micbias_control(codec, MICB_ENABLE);
|
||||
mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
|
||||
MICB_ENABLE);
|
||||
else
|
||||
wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
|
||||
|
||||
|
@ -1349,6 +1464,17 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
|
|||
1);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
|
||||
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT);
|
||||
} else if (mbhc->current_plug == MBHC_PLUG_TYPE_ANC_HEADPHONE) {
|
||||
mbhc->mbhc_cb->irq_control(codec,
|
||||
mbhc->intr_ids->mbhc_hs_rem_intr,
|
||||
false);
|
||||
mbhc->mbhc_cb->irq_control(codec,
|
||||
mbhc->intr_ids->mbhc_hs_ins_intr,
|
||||
false);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
|
||||
0);
|
||||
WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
|
||||
wcd_mbhc_report_plug(mbhc, 0, SND_JACK_ANC_HEADPHONE);
|
||||
}
|
||||
} else if (!detection_type) {
|
||||
/* Disable external voltage source to micbias if present */
|
||||
|
@ -1727,7 +1853,7 @@ static irqreturn_t wcd_mbhc_release_handler(int irq, void *data)
|
|||
* headset not headphone.
|
||||
*/
|
||||
if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
|
||||
wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET);
|
||||
wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
|
||||
goto exit;
|
||||
|
||||
}
|
||||
|
|
|
@ -64,6 +64,9 @@ enum wcd_mbhc_register_function {
|
|||
WCD_MBHC_SWCH_LEVEL_REMOVE,
|
||||
WCD_MBHC_MOISTURE_VREF,
|
||||
WCD_MBHC_PULLDOWN_CTRL,
|
||||
WCD_MBHC_ANC_DET_EN,
|
||||
WCD_MBHC_FSM_STATUS,
|
||||
WCD_MBHC_MUX_CTL,
|
||||
WCD_MBHC_REG_FUNC_MAX,
|
||||
};
|
||||
|
||||
|
@ -74,6 +77,7 @@ enum wcd_mbhc_plug_type {
|
|||
MBHC_PLUG_TYPE_HEADPHONE,
|
||||
MBHC_PLUG_TYPE_HIGH_HPH,
|
||||
MBHC_PLUG_TYPE_GND_MIC_SWAP,
|
||||
MBHC_PLUG_TYPE_ANC_HEADPHONE,
|
||||
};
|
||||
|
||||
enum pa_dac_ack_flags {
|
||||
|
@ -249,6 +253,9 @@ struct wcd_mbhc_config {
|
|||
int key_code[WCD_MBHC_KEYCODE_NUM];
|
||||
uint32_t linein_th;
|
||||
struct wcd_mbhc_moisture_cfg moist_cfg;
|
||||
int mbhc_micbias;
|
||||
int anc_micbias;
|
||||
bool enable_anc_mic_detect;
|
||||
};
|
||||
|
||||
struct wcd_mbhc_intr {
|
||||
|
@ -349,7 +356,7 @@ struct wcd_mbhc_cb {
|
|||
int num_btn, bool);
|
||||
void (*hph_pull_up_control)(struct snd_soc_codec *,
|
||||
enum mbhc_hs_pullup_iref);
|
||||
int (*mbhc_micbias_control)(struct snd_soc_codec *, int req);
|
||||
int (*mbhc_micbias_control)(struct snd_soc_codec *, int, int req);
|
||||
void (*mbhc_micb_ramp_control)(struct snd_soc_codec *, bool);
|
||||
void (*skip_imped_detect)(struct snd_soc_codec *);
|
||||
bool (*extn_use_mb)(struct snd_soc_codec *);
|
||||
|
|
|
@ -621,6 +621,17 @@ static struct wcd_mbhc_register
|
|||
0, 0, 0, 0),
|
||||
WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
|
||||
0, 0, 0, 0),
|
||||
WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
|
||||
WCD9335_ANA_MBHC_ZDET, 0x01, 0, 0),
|
||||
/*
|
||||
* MBHC FSM status register is only available in Tasha 2.0.
|
||||
* So, init with 0 later once the version is known, then values
|
||||
* will be updated.
|
||||
*/
|
||||
WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
|
||||
0, 0, 0, 0),
|
||||
WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
|
||||
WCD9335_MBHC_CTL_2, 0x70, 4, 0),
|
||||
};
|
||||
|
||||
static const struct wcd_mbhc_intr intr_ids = {
|
||||
|
@ -1367,7 +1378,7 @@ static int tasha_micbias_control(struct snd_soc_codec *codec,
|
|||
}
|
||||
|
||||
static int tasha_mbhc_request_micbias(struct snd_soc_codec *codec,
|
||||
int req)
|
||||
int micb_num, int req)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -1378,7 +1389,7 @@ static int tasha_mbhc_request_micbias(struct snd_soc_codec *codec,
|
|||
if (req == MICB_ENABLE)
|
||||
tasha_cdc_mclk_enable(codec, true, false);
|
||||
|
||||
ret = tasha_micbias_control(codec, MIC_BIAS_2, req, false);
|
||||
ret = tasha_micbias_control(codec, micb_num, req, false);
|
||||
|
||||
/*
|
||||
* Release vote for mclk while requesting for
|
||||
|
@ -12303,6 +12314,9 @@ static int tasha_codec_probe(struct snd_soc_codec *codec)
|
|||
0x0C;
|
||||
wcd_mbhc_registers[WCD_MBHC_MOISTURE_VREF].offset =
|
||||
2;
|
||||
wcd_mbhc_registers[WCD_MBHC_FSM_STATUS].reg =
|
||||
WCD9335_MBHC_FSM_STATUS;
|
||||
wcd_mbhc_registers[WCD_MBHC_FSM_STATUS].mask = 0x01;
|
||||
}
|
||||
ret = wcd_mbhc_init(&tasha->mbhc, codec, &mbhc_cb, &intr_ids,
|
||||
wcd_mbhc_registers, TASHA_ZDET_SUPPORTED);
|
||||
|
|
Loading…
Add table
Reference in a new issue