Loading sound/soc/codecs/msm8x16-wcd.c +6 −0 Original line number Diff line number Diff line Loading @@ -256,6 +256,12 @@ static struct wcd_mbhc_register 0, 0, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL", MSM8X16_WCD_A_ANALOG_MICB_2_EN, 0x20, 5, 0), WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN", 0, 0, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", 0, 0, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", 0, 0, 0, 0), }; struct msm8x16_wcd_spmi { Loading sound/soc/codecs/wcd-mbhc-v2.c +146 −20 Original line number Diff line number Diff line Loading @@ -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 | \ Loading @@ -50,6 +52,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, Loading Loading @@ -569,7 +572,7 @@ 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, mbhc->codec, MIC_BIAS_2, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( Loading Loading @@ -602,7 +605,7 @@ 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, mbhc->codec, MIC_BIAS_2, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( Loading Loading @@ -634,6 +637,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); } Loading @@ -649,8 +653,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 && Loading Loading @@ -690,9 +696,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); Loading @@ -717,11 +812,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 */ Loading Loading @@ -808,7 +910,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 Loading Loading @@ -856,16 +959,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; Loading Loading @@ -901,6 +1006,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; Loading Loading @@ -1132,8 +1238,10 @@ correct_plug_type: * and if there is not button press without * release */ if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET && 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__); Loading @@ -1152,8 +1260,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; } Loading @@ -1168,6 +1278,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); Loading @@ -1182,7 +1296,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, Loading Loading @@ -1223,7 +1337,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); Loading Loading @@ -1350,6 +1465,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 */ Loading Loading @@ -1734,7 +1860,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; } Loading sound/soc/codecs/wcd-mbhc-v2.h +8 −1 Original line number Diff line number Diff line Loading @@ -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, }; Loading @@ -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 { Loading Loading @@ -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 { Loading Loading @@ -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 *); Loading sound/soc/codecs/wcd9335.c +16 −2 Original line number Diff line number Diff line Loading @@ -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 = { Loading Loading @@ -1366,7 +1377,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; Loading @@ -1377,7 +1388,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 Loading Loading @@ -12259,6 +12270,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 Loading
sound/soc/codecs/msm8x16-wcd.c +6 −0 Original line number Diff line number Diff line Loading @@ -256,6 +256,12 @@ static struct wcd_mbhc_register 0, 0, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL", MSM8X16_WCD_A_ANALOG_MICB_2_EN, 0x20, 5, 0), WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN", 0, 0, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS", 0, 0, 0, 0), WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL", 0, 0, 0, 0), }; struct msm8x16_wcd_spmi { Loading
sound/soc/codecs/wcd-mbhc-v2.c +146 −20 Original line number Diff line number Diff line Loading @@ -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 | \ Loading @@ -50,6 +52,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, Loading Loading @@ -569,7 +572,7 @@ 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, mbhc->codec, MIC_BIAS_2, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( Loading Loading @@ -602,7 +605,7 @@ 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, mbhc->codec, MIC_BIAS_2, MICB_DISABLE); if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic( Loading Loading @@ -634,6 +637,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); } Loading @@ -649,8 +653,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 && Loading Loading @@ -690,9 +696,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); Loading @@ -717,11 +812,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 */ Loading Loading @@ -808,7 +910,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 Loading Loading @@ -856,16 +959,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; Loading Loading @@ -901,6 +1006,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; Loading Loading @@ -1132,8 +1238,10 @@ correct_plug_type: * and if there is not button press without * release */ if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET && 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__); Loading @@ -1152,8 +1260,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; } Loading @@ -1168,6 +1278,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); Loading @@ -1182,7 +1296,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, Loading Loading @@ -1223,7 +1337,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); Loading Loading @@ -1350,6 +1465,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 */ Loading Loading @@ -1734,7 +1860,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; } Loading
sound/soc/codecs/wcd-mbhc-v2.h +8 −1 Original line number Diff line number Diff line Loading @@ -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, }; Loading @@ -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 { Loading Loading @@ -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 { Loading Loading @@ -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 *); Loading
sound/soc/codecs/wcd9335.c +16 −2 Original line number Diff line number Diff line Loading @@ -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 = { Loading Loading @@ -1366,7 +1377,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; Loading @@ -1377,7 +1388,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 Loading Loading @@ -12259,6 +12270,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