Lines Matching defs:mbhc
14 #include "wcd-mbhc-v2.h"
74 /* Holds mbhc detection method - ADC/Legacy */
78 static inline int wcd_mbhc_write_field(const struct wcd_mbhc *mbhc,
81 if (!mbhc->fields[field].reg)
84 return snd_soc_component_write_field(mbhc->component,
85 mbhc->fields[field].reg,
86 mbhc->fields[field].mask, val);
89 static inline int wcd_mbhc_read_field(const struct wcd_mbhc *mbhc, int field)
91 if (!mbhc->fields[field].reg)
94 return snd_soc_component_read_field(mbhc->component,
95 mbhc->fields[field].reg,
96 mbhc->fields[field].mask);
99 static void wcd_program_hs_vref(struct wcd_mbhc *mbhc)
101 u32 reg_val = ((mbhc->cfg->v_hs_max - HS_VREF_MIN_VAL) / 100);
103 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_VREF, reg_val);
106 static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias)
108 struct snd_soc_component *component = mbhc->component;
110 mbhc->mbhc_cb->set_btn_thr(component, mbhc->cfg->btn_low,
111 mbhc->cfg->btn_high,
112 mbhc->cfg->num_btn, micbias);
115 static void wcd_mbhc_curr_micbias_control(const struct wcd_mbhc *mbhc,
125 if (mbhc->mbhc_cb->mbhc_micbias_control)
130 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
131 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
133 wcd_program_btn_threshold(mbhc, false);
136 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
137 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
139 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 2);
141 wcd_program_btn_threshold(mbhc, true);
144 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
145 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
146 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 1);
148 wcd_program_btn_threshold(mbhc, true);
151 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
152 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
153 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
156 dev_err(mbhc->dev, "%s: Invalid parameter", __func__);
161 int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event)
167 if (!mbhc)
170 component = mbhc->component;
172 if (mbhc->mbhc_cb->micbias_enable_status)
173 micbias2 = mbhc->mbhc_cb->micbias_enable_status(component, MIC_BIAS_2);
178 mbhc->is_hs_recording = true;
182 if (mbhc->mbhc_cb->mbhc_micbias_control) {
183 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
184 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
186 mbhc->is_hs_recording = true;
187 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
196 if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) {
197 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
198 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
203 mbhc->is_hs_recording = false;
206 if (!mbhc->mbhc_cb->mbhc_micbias_control)
207 mbhc->is_hs_recording = false;
210 if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) ||
211 (test_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state)))
213 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
216 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
220 clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
225 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
228 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
231 clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
235 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
238 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
241 set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
245 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
248 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
251 set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
255 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
258 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
267 static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc)
269 return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
272 static void wcd_micbias_disable(struct wcd_mbhc *mbhc)
274 struct snd_soc_component *component = mbhc->component;
276 if (mbhc->mbhc_cb->mbhc_micbias_control)
277 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
279 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
280 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, false);
282 if (mbhc->mbhc_cb->set_micbias_value) {
283 mbhc->mbhc_cb->set_micbias_value(component);
284 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
288 static void wcd_mbhc_report_plug_removal(struct wcd_mbhc *mbhc,
291 mbhc->hph_status &= ~jack_type;
296 if (!wcd_cancel_btn_work(mbhc) && mbhc->buttons_pressed) {
297 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
298 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
301 wcd_micbias_disable(mbhc);
302 mbhc->hph_type = WCD_MBHC_HPH_NONE;
303 mbhc->zl = mbhc->zr = 0;
304 snd_soc_jack_report(mbhc->jack, mbhc->hph_status, WCD_MBHC_JACK_MASK);
305 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
306 mbhc->force_linein = false;
309 static void wcd_mbhc_compute_impedance(struct wcd_mbhc *mbhc)
312 if (!mbhc->impedance_detect)
315 if (mbhc->cfg->linein_th != 0) {
316 u8 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
319 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
320 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
321 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
322 mbhc->mbhc_cb->compute_impedance(mbhc->component, &mbhc->zl, &mbhc->zr);
323 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
327 static void wcd_mbhc_report_plug_insertion(struct wcd_mbhc *mbhc,
336 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
338 mbhc->hph_status &= ~SND_JACK_HEADSET;
343 mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
346 mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
347 mbhc->jiffies_atreport = jiffies;
350 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
357 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
360 wcd_mbhc_compute_impedance(mbhc);
361 if ((mbhc->zl > mbhc->cfg->linein_th) &&
362 (mbhc->zr > mbhc->cfg->linein_th) &&
365 mbhc->force_linein = true;
366 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
367 if (mbhc->hph_status) {
368 mbhc->hph_status &= ~(SND_JACK_HEADSET |
370 snd_soc_jack_report(mbhc->jack, mbhc->hph_status,
381 if (is_pa_on && mbhc->force_linein) {
383 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
384 if (mbhc->hph_status) {
385 mbhc->hph_status &= ~(SND_JACK_HEADSET |
387 snd_soc_jack_report(mbhc->jack, mbhc->hph_status,
392 mbhc->hph_status |= jack_type;
394 if (jack_type == SND_JACK_HEADPHONE && mbhc->mbhc_cb->mbhc_micb_ramp_control)
395 mbhc->mbhc_cb->mbhc_micb_ramp_control(mbhc->component, false);
397 snd_soc_jack_report(mbhc->jack, (mbhc->hph_status | SND_JACK_MECHANICAL),
401 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
405 WARN_ON(!mutex_is_locked(&mbhc->lock));
408 wcd_mbhc_report_plug_removal(mbhc, jack_type);
410 wcd_mbhc_report_plug_insertion(mbhc, jack_type);
414 static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
417 mbhc->hs_detect_work_stop = true;
418 mutex_unlock(&mbhc->lock);
420 mutex_lock(&mbhc->lock);
423 static void wcd_mbhc_cancel_pending_work(struct wcd_mbhc *mbhc)
426 wcd_cancel_btn_work(mbhc);
428 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
431 static void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc)
433 wcd_mbhc_cancel_pending_work(mbhc);
435 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
440 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
441 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_NONE);
443 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
444 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 3);
447 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
448 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
451 static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
454 if (mbhc->current_plug == plug_type)
457 mutex_lock(&mbhc->lock);
461 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
464 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET);
467 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
470 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
471 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
472 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
473 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
477 mbhc->current_plug, plug_type);
480 mutex_unlock(&mbhc->lock);
483 static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
486 WARN_ON(!mutex_is_locked(&mbhc->lock));
487 mbhc->hs_detect_work_stop = false;
491 static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc)
493 struct snd_soc_component *component = mbhc->component;
495 WARN_ON(!mutex_is_locked(&mbhc->lock));
497 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
498 mbhc->mbhc_cb->hph_pull_down_ctrl(component, false);
500 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
502 if (mbhc->mbhc_cb->mbhc_micbias_control) {
503 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2,
505 wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
513 struct wcd_mbhc *mbhc = data;
516 component = mbhc->component;
517 mutex_lock(&mbhc->lock);
519 mbhc->in_swch_irq_handler = true;
521 wcd_mbhc_cancel_pending_work(mbhc);
523 detection_type = wcd_mbhc_read_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE);
526 wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, !detection_type);
529 if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
530 mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true);
533 if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
536 mbhc->mbhc_cb->mbhc_bias(component, true);
537 mbhc->is_btn_press = false;
538 wcd_mbhc_adc_detect_plug_type(mbhc);
541 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
542 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
543 mbhc->extn_cable_hph_rem = false;
545 if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE)
548 mbhc->is_btn_press = false;
549 switch (mbhc->current_plug) {
557 if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC)
558 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 0);
562 dev_err(mbhc->dev, "Ground and Mic Swapped on plug\n");
565 dev_err(mbhc->dev, "Invalid current plug: %d\n",
566 mbhc->current_plug);
569 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
570 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
571 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
572 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
573 wcd_mbhc_report_plug(mbhc, 0, jack_type);
577 mbhc->in_swch_irq_handler = false;
578 mutex_unlock(&mbhc->lock);
582 static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc)
587 btn = wcd_mbhc_read_field(mbhc, WCD_MBHC_BTN_RESULT);
618 struct wcd_mbhc *mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork);
620 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
621 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
622 mbhc->buttons_pressed);
627 struct wcd_mbhc *mbhc = data;
631 mutex_lock(&mbhc->lock);
632 wcd_cancel_btn_work(mbhc);
633 mbhc->is_btn_press = true;
634 msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
641 if (mbhc->in_swch_irq_handler)
645 if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET)
648 mask = wcd_mbhc_get_button_mask(mbhc);
649 mbhc->buttons_pressed |= mask;
650 if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, msecs_to_jiffies(400)) == 0)
653 mutex_unlock(&mbhc->lock);
659 struct wcd_mbhc *mbhc = data;
662 mutex_lock(&mbhc->lock);
663 if (mbhc->is_btn_press)
664 mbhc->is_btn_press = false;
668 if (!(mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK))
671 ret = wcd_cancel_btn_work(mbhc);
673 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
675 if (!mbhc->in_swch_irq_handler) {
677 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
678 mbhc->buttons_pressed);
679 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
682 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
684 mutex_unlock(&mbhc->lock);
689 static irqreturn_t wcd_mbhc_hph_ocp_irq(struct wcd_mbhc *mbhc, bool hphr)
693 dev_err(mbhc->dev, "MBHC Over Current on %s detected\n",
696 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 0);
697 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 1);
712 static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
714 struct snd_soc_component *component = mbhc->component;
726 mutex_lock(&mbhc->lock);
729 if (mbhc->mbhc_cb->hph_pull_up_control_v2)
730 mbhc->mbhc_cb->hph_pull_up_control_v2(component,
732 else if (mbhc->mbhc_cb->hph_pull_up_control)
733 mbhc->mbhc_cb->hph_pull_up_control(component, I_DEFAULT);
735 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
737 wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh);
738 wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh);
739 wcd_mbhc_write_field(mbhc, WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
740 if (mbhc->cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl)
741 mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true);
742 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
744 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
747 wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6);
750 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2);
753 mbhc->mbhc_cb->mbhc_bias(component, true);
755 if (mbhc->mbhc_cb->clk_setup)
756 mbhc->mbhc_cb->clk_setup(component, true);
759 wcd_program_hs_vref(mbhc);
761 wcd_program_btn_threshold(mbhc, false);
763 mutex_unlock(&mbhc->lock);
771 static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc)
775 if (mbhc->mbhc_cb->get_micbias_val) {
776 mbhc->mbhc_cb->get_micbias_val(mbhc->component, &micbias);
780 vout_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_MICB2_VOUT);
797 static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
806 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
808 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 1);
810 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
812 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
814 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
816 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_IN2P);
818 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
820 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
825 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
829 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
831 output_mv = wcd_get_voltage_from_adc(adc_result, wcd_mbhc_get_micbias(mbhc));
836 static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl)
838 struct device *dev = mbhc->dev;
847 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
849 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
851 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
852 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
854 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, mux_ctl);
855 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
856 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
863 adc_timeout = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_TIMEOUT);
868 adc_complete = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_COMPLETE);
873 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
877 wcd_mbhc_get_micbias(mbhc));
882 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
896 static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
903 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN))
907 elect_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC);
908 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
911 adc_mode = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_MODE);
913 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
915 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
918 hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L);
923 hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R);
931 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
933 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
934 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
936 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
938 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, adc_mode);
940 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
942 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
947 static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc)
951 micbias_mv = wcd_mbhc_get_micbias(mbhc);
952 if (mbhc->cfg->hs_thr) {
953 if (mbhc->cfg->micb_mv == micbias_mv)
954 hs_threshold = mbhc->cfg->hs_thr;
956 hs_threshold = (mbhc->cfg->hs_thr *
957 micbias_mv) / mbhc->cfg->micb_mv;
965 static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc)
969 micbias_mv = wcd_mbhc_get_micbias(mbhc);
970 if (mbhc->cfg->hph_thr) {
971 if (mbhc->cfg->micb_mv == micbias_mv)
972 hph_threshold = mbhc->cfg->hph_thr;
974 hph_threshold = (mbhc->cfg->hph_thr *
975 micbias_mv) / mbhc->cfg->micb_mv;
983 static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc,
990 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
993 if (mbhc->mbhc_cb->micbias_enable_status)
994 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc->component,
997 if (!mbhc->is_hs_recording && !micbias2)
998 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
1001 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
1007 static void wcd_mbhc_bcs_enable(struct wcd_mbhc *mbhc, int plug_type, bool enable)
1012 if (mbhc->mbhc_cb->bcs_enable)
1013 mbhc->mbhc_cb->bcs_enable(mbhc->component, enable);
1020 static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result)
1026 hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc);
1027 hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc);
1039 static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc)
1043 micbias_mv = wcd_mbhc_get_micbias(mbhc);
1044 if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) {
1045 if (mbhc->cfg->micb_mv == micbias_mv)
1046 hs_threshold = mbhc->cfg->hs_thr;
1048 hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv;
1056 static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc)
1061 if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
1065 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true);
1068 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1069 hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc);
1070 hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc);
1077 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false);
1087 struct wcd_mbhc *mbhc;
1097 mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
1098 component = mbhc->component;
1108 micbias_mv = wcd_mbhc_get_micbias(mbhc);
1109 hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1112 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1116 cross_conn = wcd_check_cross_conn(mbhc);
1122 dev_err(mbhc->dev, "cross connection found, Plug type %d\n",
1128 output_mv = wcd_measure_adc_continuous(mbhc);
1129 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1137 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1140 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1141 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1142 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1143 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1152 wcd_mbhc_bcs_enable(mbhc, plug_type, false);
1157 if (mbhc->hs_detect_work_stop) {
1158 wcd_micbias_disable(mbhc);
1167 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1168 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1169 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
1172 is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc);
1173 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1176 hs_threshold *= wcd_mbhc_get_micbias(mbhc);
1183 cross_conn = wcd_check_cross_conn(mbhc);
1192 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1199 if (mbhc->cfg->swap_gnd_mic) {
1200 if (mbhc->cfg->swap_gnd_mic(component, true))
1207 if (output_mv > hs_threshold || mbhc->force_linein)
1211 wcd_mbhc_bcs_enable(mbhc, plug_type, true);
1217 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1);
1220 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1221 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1222 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1230 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1232 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1234 if (mbhc->mbhc_cb->mbhc_micbias_control)
1235 wcd_mbhc_adc_update_fsm_source(mbhc, plug_type);
1238 if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/)
1239 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
1247 wcd_micbias_disable(mbhc);
1253 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
1256 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
1257 mbhc->mbhc_cb->hph_pull_down_ctrl(component, true);
1265 struct wcd_mbhc *mbhc = data;
1269 mutex_lock(&mbhc->lock);
1271 adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1280 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1292 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
1293 mbhc->extn_cable_hph_rem = true;
1295 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1296 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1297 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1298 wcd_mbhc_elec_hs_report_unplug(mbhc);
1299 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
1302 mutex_unlock(&mbhc->lock);
1308 struct wcd_mbhc *mbhc = data;
1317 if (mbhc->extn_cable_hph_rem == true) {
1318 mbhc->extn_cable_hph_rem = false;
1323 clamp_state = wcd_mbhc_read_field(mbhc, WCD_MBHC_IN2P_CLAMP_STATE);
1338 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
1339 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1340 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1341 wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
1348 int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr)
1350 *zl = mbhc->zl;
1351 *zr = mbhc->zr;
1360 void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type)
1362 mbhc->hph_type = hph_type;
1366 int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc)
1368 return mbhc->hph_type;
1372 int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *cfg,
1375 if (!mbhc || !cfg || !jack)
1378 mbhc->cfg = cfg;
1379 mbhc->jack = jack;
1381 return wcd_mbhc_initialise(mbhc);
1385 void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
1387 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
1388 mbhc->hph_status = 0;
1389 disable_irq_nosync(mbhc->intr_ids->hph_left_ocp);
1390 disable_irq_nosync(mbhc->intr_ids->hph_right_ocp);
1409 ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt",
1412 dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n");
1416 ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt",
1419 dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt entry\n");
1424 "qcom,mbhc-buttons-vthreshold-microvolt",
1428 dev_err(dev, "missing qcom,mbhc-buttons-vthreshold-microvolt entry\n");
1449 struct wcd_mbhc *mbhc;
1453 dev_err(dev, "%s: Insufficient mbhc configuration\n", __func__);
1457 mbhc = kzalloc(sizeof(*mbhc), GFP_KERNEL);
1458 if (!mbhc)
1461 mbhc->component = component;
1462 mbhc->dev = dev;
1463 mbhc->intr_ids = intr_ids;
1464 mbhc->mbhc_cb = mbhc_cb;
1465 mbhc->fields = fields;
1466 mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
1469 mbhc->impedance_detect = impedance_det_en;
1471 INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_long_press_fn);
1473 mutex_init(&mbhc->lock);
1475 INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
1477 ret = request_threaded_irq(mbhc->intr_ids->mbhc_sw_intr, NULL,
1480 "mbhc sw intr", mbhc);
1484 ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_press_intr, NULL,
1487 "Button Press detect", mbhc);
1491 ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_release_intr, NULL,
1494 "Button Release detect", mbhc);
1498 ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_ins_intr, NULL,
1501 "Elect Insert", mbhc);
1505 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1507 ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_rem_intr, NULL,
1510 "Elect Remove", mbhc);
1514 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
1516 ret = request_threaded_irq(mbhc->intr_ids->hph_left_ocp, NULL,
1519 "HPH_L OCP detect", mbhc);
1523 ret = request_threaded_irq(mbhc->intr_ids->hph_right_ocp, NULL,
1526 "HPH_R OCP detect", mbhc);
1530 return mbhc;
1533 free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
1535 free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
1537 free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
1539 free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
1541 free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
1543 free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
1545 kfree(mbhc);
1547 dev_err(dev, "Failed to request mbhc interrupts %d\n", ret);
1553 void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
1555 free_irq(mbhc->intr_ids->hph_right_ocp, mbhc);
1556 free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
1557 free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
1558 free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
1559 free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
1560 free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
1561 free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
1563 mutex_lock(&mbhc->lock);
1564 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
1565 mutex_unlock(&mbhc->lock);
1567 kfree(mbhc);