Lines Matching +full:mbhc +full:- +full:headset +full:- +full:vthreshold +full:- +full:microvolt

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