Lines Matching +full:mbhc +full:- +full:headphone +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"
76 /* Holds type of Headset - Mono/Stereo */
78 /* Holds mbhc detection method - ADC/Legacy */
82 static inline int wcd_mbhc_write_field(const struct wcd_mbhc *mbhc, in wcd_mbhc_write_field() argument
85 if (!mbhc->fields[field].reg) in wcd_mbhc_write_field()
88 return snd_soc_component_write_field(mbhc->component, in wcd_mbhc_write_field()
89 mbhc->fields[field].reg, in wcd_mbhc_write_field()
90 mbhc->fields[field].mask, val); in wcd_mbhc_write_field()
93 static inline int wcd_mbhc_read_field(const struct wcd_mbhc *mbhc, int field) in wcd_mbhc_read_field() argument
95 if (!mbhc->fields[field].reg) in wcd_mbhc_read_field()
98 return snd_soc_component_read_field(mbhc->component, in wcd_mbhc_read_field()
99 mbhc->fields[field].reg, in wcd_mbhc_read_field()
100 mbhc->fields[field].mask); in wcd_mbhc_read_field()
103 static void wcd_program_hs_vref(struct wcd_mbhc *mbhc) in wcd_program_hs_vref() argument
105 u32 reg_val = ((mbhc->cfg->v_hs_max - HS_VREF_MIN_VAL) / 100); in wcd_program_hs_vref()
107 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_VREF, reg_val); in wcd_program_hs_vref()
110 static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias) in wcd_program_btn_threshold() argument
112 struct snd_soc_component *component = mbhc->component; in wcd_program_btn_threshold()
114 mbhc->mbhc_cb->set_btn_thr(component, mbhc->cfg->btn_low, in wcd_program_btn_threshold()
115 mbhc->cfg->btn_high, in wcd_program_btn_threshold()
116 mbhc->cfg->num_btn, micbias); in wcd_program_btn_threshold()
119 static void wcd_mbhc_curr_micbias_control(const struct wcd_mbhc *mbhc, in wcd_mbhc_curr_micbias_control() argument
129 if (mbhc->mbhc_cb->mbhc_micbias_control) in wcd_mbhc_curr_micbias_control()
134 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0); in wcd_mbhc_curr_micbias_control()
135 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); in wcd_mbhc_curr_micbias_control()
137 wcd_program_btn_threshold(mbhc, false); in wcd_mbhc_curr_micbias_control()
140 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); in wcd_mbhc_curr_micbias_control()
141 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); in wcd_mbhc_curr_micbias_control()
143 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 2); in wcd_mbhc_curr_micbias_control()
145 wcd_program_btn_threshold(mbhc, true); in wcd_mbhc_curr_micbias_control()
148 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); in wcd_mbhc_curr_micbias_control()
149 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); in wcd_mbhc_curr_micbias_control()
150 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 1); in wcd_mbhc_curr_micbias_control()
152 wcd_program_btn_threshold(mbhc, true); in wcd_mbhc_curr_micbias_control()
155 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); in wcd_mbhc_curr_micbias_control()
156 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); in wcd_mbhc_curr_micbias_control()
157 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0); in wcd_mbhc_curr_micbias_control()
160 dev_err(mbhc->dev, "%s: Invalid parameter", __func__); in wcd_mbhc_curr_micbias_control()
165 int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event) in wcd_mbhc_event_notify() argument
171 if (!mbhc) in wcd_mbhc_event_notify()
174 component = mbhc->component; in wcd_mbhc_event_notify()
176 if (mbhc->mbhc_cb->micbias_enable_status) in wcd_mbhc_event_notify()
177 micbias2 = mbhc->mbhc_cb->micbias_enable_status(component, MIC_BIAS_2); in wcd_mbhc_event_notify()
182 mbhc->is_hs_recording = true; in wcd_mbhc_event_notify()
186 if (mbhc->mbhc_cb->mbhc_micbias_control) { in wcd_mbhc_event_notify()
187 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN)) in wcd_mbhc_event_notify()
188 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); in wcd_mbhc_event_notify()
190 mbhc->is_hs_recording = true; in wcd_mbhc_event_notify()
191 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); in wcd_mbhc_event_notify()
200 if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) { in wcd_mbhc_event_notify()
201 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN)) in wcd_mbhc_event_notify()
202 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); in wcd_mbhc_event_notify()
207 mbhc->is_hs_recording = false; in wcd_mbhc_event_notify()
210 if (!mbhc->mbhc_cb->mbhc_micbias_control) in wcd_mbhc_event_notify()
211 mbhc->is_hs_recording = false; in wcd_mbhc_event_notify()
214 if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) || in wcd_mbhc_event_notify()
215 (test_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state))) in wcd_mbhc_event_notify()
217 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP); in wcd_mbhc_event_notify()
220 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS); in wcd_mbhc_event_notify()
224 clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state); in wcd_mbhc_event_notify()
229 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); in wcd_mbhc_event_notify()
232 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS); in wcd_mbhc_event_notify()
235 clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state); in wcd_mbhc_event_notify()
239 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); in wcd_mbhc_event_notify()
242 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS); in wcd_mbhc_event_notify()
245 set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state); in wcd_mbhc_event_notify()
249 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); in wcd_mbhc_event_notify()
252 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP); in wcd_mbhc_event_notify()
255 set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state); in wcd_mbhc_event_notify()
259 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB); in wcd_mbhc_event_notify()
262 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP); in wcd_mbhc_event_notify()
271 static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc) in wcd_cancel_btn_work() argument
273 return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork); in wcd_cancel_btn_work()
276 static void wcd_micbias_disable(struct wcd_mbhc *mbhc) in wcd_micbias_disable() argument
278 struct snd_soc_component *component = mbhc->component; in wcd_micbias_disable()
280 if (mbhc->mbhc_cb->mbhc_micbias_control) in wcd_micbias_disable()
281 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE); in wcd_micbias_disable()
283 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) in wcd_micbias_disable()
284 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, false); in wcd_micbias_disable()
286 if (mbhc->mbhc_cb->set_micbias_value) { in wcd_micbias_disable()
287 mbhc->mbhc_cb->set_micbias_value(component); in wcd_micbias_disable()
288 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0); in wcd_micbias_disable()
292 static void wcd_mbhc_report_plug_removal(struct wcd_mbhc *mbhc, in wcd_mbhc_report_plug_removal() argument
295 mbhc->hph_status &= ~jack_type; in wcd_mbhc_report_plug_removal()
300 if (!wcd_cancel_btn_work(mbhc) && mbhc->buttons_pressed) { in wcd_mbhc_report_plug_removal()
301 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed); in wcd_mbhc_report_plug_removal()
302 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK; in wcd_mbhc_report_plug_removal()
305 wcd_micbias_disable(mbhc); in wcd_mbhc_report_plug_removal()
306 mbhc->hph_type = WCD_MBHC_HPH_NONE; in wcd_mbhc_report_plug_removal()
307 mbhc->zl = mbhc->zr = 0; in wcd_mbhc_report_plug_removal()
308 snd_soc_jack_report(mbhc->jack, mbhc->hph_status, WCD_MBHC_JACK_MASK); in wcd_mbhc_report_plug_removal()
309 mbhc->current_plug = MBHC_PLUG_TYPE_NONE; in wcd_mbhc_report_plug_removal()
310 mbhc->force_linein = false; in wcd_mbhc_report_plug_removal()
313 static void wcd_mbhc_compute_impedance(struct wcd_mbhc *mbhc) in wcd_mbhc_compute_impedance() argument
316 if (!mbhc->impedance_detect) in wcd_mbhc_compute_impedance()
319 if (mbhc->cfg->linein_th != 0) { in wcd_mbhc_compute_impedance()
320 u8 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN); in wcd_mbhc_compute_impedance()
321 /* Set MUX_CTL to AUTO for Z-det */ in wcd_mbhc_compute_impedance()
323 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); in wcd_mbhc_compute_impedance()
324 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO); in wcd_mbhc_compute_impedance()
325 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); in wcd_mbhc_compute_impedance()
326 mbhc->mbhc_cb->compute_impedance(mbhc->component, &mbhc->zl, &mbhc->zr); in wcd_mbhc_compute_impedance()
327 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en); in wcd_mbhc_compute_impedance()
331 static void wcd_mbhc_report_plug_insertion(struct wcd_mbhc *mbhc, in wcd_mbhc_report_plug_insertion() argument
337 * Headphone to headset shouldn't report headphone in wcd_mbhc_report_plug_insertion()
340 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET && in wcd_mbhc_report_plug_insertion()
342 mbhc->hph_status &= ~SND_JACK_HEADSET; in wcd_mbhc_report_plug_insertion()
347 mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE; in wcd_mbhc_report_plug_insertion()
350 mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET; in wcd_mbhc_report_plug_insertion()
351 mbhc->jiffies_atreport = jiffies; in wcd_mbhc_report_plug_insertion()
354 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; in wcd_mbhc_report_plug_insertion()
361 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN); in wcd_mbhc_report_plug_insertion()
364 wcd_mbhc_compute_impedance(mbhc); in wcd_mbhc_report_plug_insertion()
365 if ((mbhc->zl > mbhc->cfg->linein_th) && in wcd_mbhc_report_plug_insertion()
366 (mbhc->zr > mbhc->cfg->linein_th) && in wcd_mbhc_report_plug_insertion()
369 mbhc->force_linein = true; in wcd_mbhc_report_plug_insertion()
370 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; in wcd_mbhc_report_plug_insertion()
371 if (mbhc->hph_status) { in wcd_mbhc_report_plug_insertion()
372 mbhc->hph_status &= ~(SND_JACK_HEADSET | in wcd_mbhc_report_plug_insertion()
374 snd_soc_jack_report(mbhc->jack, mbhc->hph_status, in wcd_mbhc_report_plug_insertion()
383 * as headphone. in wcd_mbhc_report_plug_insertion()
385 if (is_pa_on && mbhc->force_linein) { in wcd_mbhc_report_plug_insertion()
387 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH; in wcd_mbhc_report_plug_insertion()
388 if (mbhc->hph_status) { in wcd_mbhc_report_plug_insertion()
389 mbhc->hph_status &= ~(SND_JACK_HEADSET | in wcd_mbhc_report_plug_insertion()
391 snd_soc_jack_report(mbhc->jack, mbhc->hph_status, in wcd_mbhc_report_plug_insertion()
396 mbhc->hph_status |= jack_type; in wcd_mbhc_report_plug_insertion()
398 if (jack_type == SND_JACK_HEADPHONE && mbhc->mbhc_cb->mbhc_micb_ramp_control) in wcd_mbhc_report_plug_insertion()
399 mbhc->mbhc_cb->mbhc_micb_ramp_control(mbhc->component, false); in wcd_mbhc_report_plug_insertion()
401 snd_soc_jack_report(mbhc->jack, (mbhc->hph_status | SND_JACK_MECHANICAL), in wcd_mbhc_report_plug_insertion()
405 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion, in wcd_mbhc_report_plug() argument
409 WARN_ON(!mutex_is_locked(&mbhc->lock)); in wcd_mbhc_report_plug()
412 wcd_mbhc_report_plug_removal(mbhc, jack_type); in wcd_mbhc_report_plug()
414 wcd_mbhc_report_plug_insertion(mbhc, jack_type); in wcd_mbhc_report_plug()
418 static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc, in wcd_cancel_hs_detect_plug() argument
421 mbhc->hs_detect_work_stop = true; in wcd_cancel_hs_detect_plug()
422 mutex_unlock(&mbhc->lock); in wcd_cancel_hs_detect_plug()
424 mutex_lock(&mbhc->lock); in wcd_cancel_hs_detect_plug()
427 static void wcd_mbhc_cancel_pending_work(struct wcd_mbhc *mbhc) in wcd_mbhc_cancel_pending_work() argument
430 wcd_cancel_btn_work(mbhc); in wcd_mbhc_cancel_pending_work()
432 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); in wcd_mbhc_cancel_pending_work()
435 static void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc) in wcd_mbhc_elec_hs_report_unplug() argument
437 wcd_mbhc_cancel_pending_work(mbhc); in wcd_mbhc_elec_hs_report_unplug()
439 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); in wcd_mbhc_elec_hs_report_unplug()
444 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); in wcd_mbhc_elec_hs_report_unplug()
445 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_NONE); in wcd_mbhc_elec_hs_report_unplug()
447 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); in wcd_mbhc_elec_hs_report_unplug()
448 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 3); in wcd_mbhc_elec_hs_report_unplug()
451 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1); in wcd_mbhc_elec_hs_report_unplug()
452 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr); in wcd_mbhc_elec_hs_report_unplug()
455 static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc, in wcd_mbhc_find_plug_and_report() argument
458 if (mbhc->current_plug == plug_type) in wcd_mbhc_find_plug_and_report()
461 mutex_lock(&mbhc->lock); in wcd_mbhc_find_plug_and_report()
465 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE); in wcd_mbhc_find_plug_and_report()
468 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET); in wcd_mbhc_find_plug_and_report()
471 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT); in wcd_mbhc_find_plug_and_report()
474 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) in wcd_mbhc_find_plug_and_report()
475 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE); in wcd_mbhc_find_plug_and_report()
476 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) in wcd_mbhc_find_plug_and_report()
477 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET); in wcd_mbhc_find_plug_and_report()
481 mbhc->current_plug, plug_type); in wcd_mbhc_find_plug_and_report()
484 mutex_unlock(&mbhc->lock); in wcd_mbhc_find_plug_and_report()
487 static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc, in wcd_schedule_hs_detect_plug() argument
490 WARN_ON(!mutex_is_locked(&mbhc->lock)); in wcd_schedule_hs_detect_plug()
491 mbhc->hs_detect_work_stop = false; in wcd_schedule_hs_detect_plug()
495 static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc) in wcd_mbhc_adc_detect_plug_type() argument
497 struct snd_soc_component *component = mbhc->component; in wcd_mbhc_adc_detect_plug_type()
499 WARN_ON(!mutex_is_locked(&mbhc->lock)); in wcd_mbhc_adc_detect_plug_type()
501 if (mbhc->mbhc_cb->hph_pull_down_ctrl) in wcd_mbhc_adc_detect_plug_type()
502 mbhc->mbhc_cb->hph_pull_down_ctrl(component, false); in wcd_mbhc_adc_detect_plug_type()
504 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0); in wcd_mbhc_adc_detect_plug_type()
506 if (mbhc->mbhc_cb->mbhc_micbias_control) { in wcd_mbhc_adc_detect_plug_type()
507 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, in wcd_mbhc_adc_detect_plug_type()
509 wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); in wcd_mbhc_adc_detect_plug_type()
515 struct wcd_mbhc *mbhc = container_of(work, struct wcd_mbhc, mbhc_plug_detect_work); in mbhc_plug_detect_fn() local
516 struct snd_soc_component *component = mbhc->component; in mbhc_plug_detect_fn()
520 mutex_lock(&mbhc->lock); in mbhc_plug_detect_fn()
522 mbhc->in_swch_irq_handler = true; in mbhc_plug_detect_fn()
524 wcd_mbhc_cancel_pending_work(mbhc); in mbhc_plug_detect_fn()
526 detection_type = wcd_mbhc_read_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE); in mbhc_plug_detect_fn()
529 wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, !detection_type); in mbhc_plug_detect_fn()
532 if (mbhc->mbhc_cb->mbhc_micb_ramp_control) in mbhc_plug_detect_fn()
533 mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true); in mbhc_plug_detect_fn()
536 if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) in mbhc_plug_detect_fn()
539 mbhc->mbhc_cb->mbhc_bias(component, true); in mbhc_plug_detect_fn()
540 mbhc->is_btn_press = false; in mbhc_plug_detect_fn()
541 wcd_mbhc_adc_detect_plug_type(mbhc); in mbhc_plug_detect_fn()
544 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); in mbhc_plug_detect_fn()
545 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); in mbhc_plug_detect_fn()
546 mbhc->extn_cable_hph_rem = false; in mbhc_plug_detect_fn()
548 if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE) in mbhc_plug_detect_fn()
551 mbhc->is_btn_press = false; in mbhc_plug_detect_fn()
552 switch (mbhc->current_plug) { in mbhc_plug_detect_fn()
560 if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC) in mbhc_plug_detect_fn()
561 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 0); in mbhc_plug_detect_fn()
565 dev_err(mbhc->dev, "Ground and Mic Swapped on plug\n"); in mbhc_plug_detect_fn()
568 dev_err(mbhc->dev, "Invalid current plug: %d\n", in mbhc_plug_detect_fn()
569 mbhc->current_plug); in mbhc_plug_detect_fn()
572 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); in mbhc_plug_detect_fn()
573 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); in mbhc_plug_detect_fn()
574 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1); in mbhc_plug_detect_fn()
575 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0); in mbhc_plug_detect_fn()
576 wcd_mbhc_report_plug(mbhc, 0, jack_type); in mbhc_plug_detect_fn()
580 mbhc->in_swch_irq_handler = false; in mbhc_plug_detect_fn()
581 mutex_unlock(&mbhc->lock); in mbhc_plug_detect_fn()
586 struct wcd_mbhc *mbhc = data; in wcd_mbhc_mech_plug_detect_irq() local
588 if (!mbhc->cfg->typec_analog_mux) in wcd_mbhc_mech_plug_detect_irq()
589 schedule_work(&mbhc->mbhc_plug_detect_work); in wcd_mbhc_mech_plug_detect_irq()
594 int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc) in wcd_mbhc_typec_report_unplug() argument
597 if (!mbhc || !mbhc->cfg->typec_analog_mux) in wcd_mbhc_typec_report_unplug()
598 return -EINVAL; in wcd_mbhc_typec_report_unplug()
600 if (mbhc->mbhc_cb->clk_setup) in wcd_mbhc_typec_report_unplug()
601 mbhc->mbhc_cb->clk_setup(mbhc->component, false); in wcd_mbhc_typec_report_unplug()
603 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0); in wcd_mbhc_typec_report_unplug()
604 wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, 0); in wcd_mbhc_typec_report_unplug()
606 schedule_work(&mbhc->mbhc_plug_detect_work); in wcd_mbhc_typec_report_unplug()
612 int wcd_mbhc_typec_report_plug(struct wcd_mbhc *mbhc) in wcd_mbhc_typec_report_plug() argument
614 if (!mbhc || !mbhc->cfg->typec_analog_mux) in wcd_mbhc_typec_report_plug()
615 return -EINVAL; in wcd_mbhc_typec_report_plug()
617 if (mbhc->mbhc_cb->clk_setup) in wcd_mbhc_typec_report_plug()
618 mbhc->mbhc_cb->clk_setup(mbhc->component, true); in wcd_mbhc_typec_report_plug()
619 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1); in wcd_mbhc_typec_report_plug()
621 schedule_work(&mbhc->mbhc_plug_detect_work); in wcd_mbhc_typec_report_plug()
627 static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc) in wcd_mbhc_get_button_mask() argument
632 btn = wcd_mbhc_read_field(mbhc, WCD_MBHC_BTN_RESULT); in wcd_mbhc_get_button_mask()
663 struct wcd_mbhc *mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork); in wcd_btn_long_press_fn() local
665 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) in wcd_btn_long_press_fn()
666 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed, in wcd_btn_long_press_fn()
667 mbhc->buttons_pressed); in wcd_btn_long_press_fn()
672 struct wcd_mbhc *mbhc = data; in wcd_mbhc_btn_press_handler() local
676 mutex_lock(&mbhc->lock); in wcd_mbhc_btn_press_handler()
677 wcd_cancel_btn_work(mbhc); in wcd_mbhc_btn_press_handler()
678 mbhc->is_btn_press = true; in wcd_mbhc_btn_press_handler()
679 msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport); in wcd_mbhc_btn_press_handler()
686 if (mbhc->in_swch_irq_handler) in wcd_mbhc_btn_press_handler()
690 if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) in wcd_mbhc_btn_press_handler()
693 mask = wcd_mbhc_get_button_mask(mbhc); in wcd_mbhc_btn_press_handler()
694 mbhc->buttons_pressed |= mask; in wcd_mbhc_btn_press_handler()
695 if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, msecs_to_jiffies(400)) == 0) in wcd_mbhc_btn_press_handler()
698 mutex_unlock(&mbhc->lock); in wcd_mbhc_btn_press_handler()
704 struct wcd_mbhc *mbhc = data; in wcd_mbhc_btn_release_handler() local
707 mutex_lock(&mbhc->lock); in wcd_mbhc_btn_release_handler()
708 if (mbhc->is_btn_press) in wcd_mbhc_btn_release_handler()
709 mbhc->is_btn_press = false; in wcd_mbhc_btn_release_handler()
713 if (!(mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK)) in wcd_mbhc_btn_release_handler()
716 ret = wcd_cancel_btn_work(mbhc); in wcd_mbhc_btn_release_handler()
718 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed); in wcd_mbhc_btn_release_handler()
720 if (!mbhc->in_swch_irq_handler) { in wcd_mbhc_btn_release_handler()
722 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed, in wcd_mbhc_btn_release_handler()
723 mbhc->buttons_pressed); in wcd_mbhc_btn_release_handler()
724 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed); in wcd_mbhc_btn_release_handler()
727 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK; in wcd_mbhc_btn_release_handler()
729 mutex_unlock(&mbhc->lock); in wcd_mbhc_btn_release_handler()
734 static irqreturn_t wcd_mbhc_hph_ocp_irq(struct wcd_mbhc *mbhc, bool hphr) in wcd_mbhc_hph_ocp_irq() argument
738 dev_err(mbhc->dev, "MBHC Over Current on %s detected\n", in wcd_mbhc_hph_ocp_irq()
741 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 0); in wcd_mbhc_hph_ocp_irq()
742 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 1); in wcd_mbhc_hph_ocp_irq()
757 static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) in wcd_mbhc_initialise() argument
759 struct snd_soc_component *component = mbhc->component; in wcd_mbhc_initialise()
762 ret = pm_runtime_get_sync(component->dev); in wcd_mbhc_initialise()
763 if (ret < 0 && ret != -EACCES) { in wcd_mbhc_initialise()
764 dev_err_ratelimited(component->dev, in wcd_mbhc_initialise()
767 pm_runtime_put_noidle(component->dev); in wcd_mbhc_initialise()
771 mutex_lock(&mbhc->lock); in wcd_mbhc_initialise()
773 if (mbhc->cfg->typec_analog_mux) in wcd_mbhc_initialise()
774 mbhc->swap_thr = GND_MIC_USBC_SWAP_THRESHOLD; in wcd_mbhc_initialise()
776 mbhc->swap_thr = GND_MIC_SWAP_THRESHOLD; in wcd_mbhc_initialise()
779 if (mbhc->mbhc_cb->hph_pull_up_control_v2) in wcd_mbhc_initialise()
780 mbhc->mbhc_cb->hph_pull_up_control_v2(component, in wcd_mbhc_initialise()
781 mbhc->cfg->typec_analog_mux ? in wcd_mbhc_initialise()
783 else if (mbhc->mbhc_cb->hph_pull_up_control) in wcd_mbhc_initialise()
784 mbhc->mbhc_cb->hph_pull_up_control(component, in wcd_mbhc_initialise()
785 mbhc->cfg->typec_analog_mux ? in wcd_mbhc_initialise()
788 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, in wcd_mbhc_initialise()
789 mbhc->cfg->typec_analog_mux ? 0 : 3); in wcd_mbhc_initialise()
791 wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh); in wcd_mbhc_initialise()
792 wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh); in wcd_mbhc_initialise()
793 wcd_mbhc_write_field(mbhc, WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1); in wcd_mbhc_initialise()
794 if (mbhc->cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl) in wcd_mbhc_initialise()
795 mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true); in wcd_mbhc_initialise()
796 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1); in wcd_mbhc_initialise()
799 if (mbhc->cfg->typec_analog_mux) in wcd_mbhc_initialise()
800 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0); in wcd_mbhc_initialise()
802 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1); in wcd_mbhc_initialise()
804 if (mbhc->cfg->typec_analog_mux) in wcd_mbhc_initialise()
806 wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 4); in wcd_mbhc_initialise()
809 wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6); in wcd_mbhc_initialise()
812 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2); in wcd_mbhc_initialise()
815 mbhc->mbhc_cb->mbhc_bias(component, true); in wcd_mbhc_initialise()
816 /* enable MBHC clock */ in wcd_mbhc_initialise()
817 if (mbhc->mbhc_cb->clk_setup) in wcd_mbhc_initialise()
818 mbhc->mbhc_cb->clk_setup(component, in wcd_mbhc_initialise()
819 mbhc->cfg->typec_analog_mux ? false : true); in wcd_mbhc_initialise()
822 wcd_program_hs_vref(mbhc); in wcd_mbhc_initialise()
824 wcd_program_btn_threshold(mbhc, false); in wcd_mbhc_initialise()
826 mutex_unlock(&mbhc->lock); in wcd_mbhc_initialise()
828 pm_runtime_mark_last_busy(component->dev); in wcd_mbhc_initialise()
829 pm_runtime_put_autosuspend(component->dev); in wcd_mbhc_initialise()
834 static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc) in wcd_mbhc_get_micbias() argument
838 if (mbhc->mbhc_cb->get_micbias_val) { in wcd_mbhc_get_micbias()
839 mbhc->mbhc_cb->get_micbias_val(mbhc->component, &micbias); in wcd_mbhc_get_micbias()
842 /* Read MBHC Micbias (Mic Bias2) voltage */ in wcd_mbhc_get_micbias()
843 vout_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_MICB2_VOUT); in wcd_mbhc_get_micbias()
860 static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc) in wcd_measure_adc_continuous() argument
867 /* Pre-requisites for ADC continuous measurement */ in wcd_measure_adc_continuous()
869 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0x00); in wcd_measure_adc_continuous()
871 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 1); in wcd_measure_adc_continuous()
873 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN); in wcd_measure_adc_continuous()
875 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); in wcd_measure_adc_continuous()
876 /* Disable MBHC FSM */ in wcd_measure_adc_continuous()
877 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); in wcd_measure_adc_continuous()
879 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_IN2P); in wcd_measure_adc_continuous()
880 /* Enable MBHC FSM */ in wcd_measure_adc_continuous()
881 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); in wcd_measure_adc_continuous()
883 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1); in wcd_measure_adc_continuous()
885 while (retry--) { in wcd_measure_adc_continuous()
888 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT); in wcd_measure_adc_continuous()
892 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en); in wcd_measure_adc_continuous()
894 output_mv = wcd_get_voltage_from_adc(adc_result, wcd_mbhc_get_micbias(mbhc)); in wcd_measure_adc_continuous()
899 static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl) in wcd_measure_adc_once() argument
901 struct device *dev = mbhc->dev; in wcd_measure_adc_once()
910 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); in wcd_measure_adc_once()
912 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN); in wcd_measure_adc_once()
914 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); in wcd_measure_adc_once()
915 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); in wcd_measure_adc_once()
917 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, mux_ctl); in wcd_measure_adc_once()
918 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); in wcd_measure_adc_once()
919 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1); in wcd_measure_adc_once()
921 while (retry--) { in wcd_measure_adc_once()
926 adc_timeout = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_TIMEOUT); in wcd_measure_adc_once()
931 adc_complete = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_COMPLETE); in wcd_measure_adc_once()
936 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT); in wcd_measure_adc_once()
940 wcd_mbhc_get_micbias(mbhc)); in wcd_measure_adc_once()
945 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en); in wcd_measure_adc_once()
950 ret = -EINVAL; in wcd_measure_adc_once()
959 static int wcd_check_cross_conn(struct wcd_mbhc *mbhc) in wcd_check_cross_conn() argument
965 /* If PA is enabled, dont check for cross-connection */ in wcd_check_cross_conn()
966 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN)) in wcd_check_cross_conn()
967 return -EINVAL; in wcd_check_cross_conn()
970 elect_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC); in wcd_check_cross_conn()
971 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0); in wcd_check_cross_conn()
974 adc_mode = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_MODE); in wcd_check_cross_conn()
976 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN); in wcd_check_cross_conn()
978 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN); in wcd_check_cross_conn()
981 hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L); in wcd_check_cross_conn()
986 hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R); in wcd_check_cross_conn()
994 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0); in wcd_check_cross_conn()
996 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO); in wcd_check_cross_conn()
997 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1); in wcd_check_cross_conn()
999 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en); in wcd_check_cross_conn()
1001 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, adc_mode); in wcd_check_cross_conn()
1003 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en); in wcd_check_cross_conn()
1005 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl); in wcd_check_cross_conn()
1010 static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc) in wcd_mbhc_adc_get_hs_thres() argument
1014 micbias_mv = wcd_mbhc_get_micbias(mbhc); in wcd_mbhc_adc_get_hs_thres()
1015 if (mbhc->cfg->hs_thr) { in wcd_mbhc_adc_get_hs_thres()
1016 if (mbhc->cfg->micb_mv == micbias_mv) in wcd_mbhc_adc_get_hs_thres()
1017 hs_threshold = mbhc->cfg->hs_thr; in wcd_mbhc_adc_get_hs_thres()
1019 hs_threshold = (mbhc->cfg->hs_thr * in wcd_mbhc_adc_get_hs_thres()
1020 micbias_mv) / mbhc->cfg->micb_mv; in wcd_mbhc_adc_get_hs_thres()
1028 static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc) in wcd_mbhc_adc_get_hph_thres() argument
1032 micbias_mv = wcd_mbhc_get_micbias(mbhc); in wcd_mbhc_adc_get_hph_thres()
1033 if (mbhc->cfg->hph_thr) { in wcd_mbhc_adc_get_hph_thres()
1034 if (mbhc->cfg->micb_mv == micbias_mv) in wcd_mbhc_adc_get_hph_thres()
1035 hph_threshold = mbhc->cfg->hph_thr; in wcd_mbhc_adc_get_hph_thres()
1037 hph_threshold = (mbhc->cfg->hph_thr * in wcd_mbhc_adc_get_hph_thres()
1038 micbias_mv) / mbhc->cfg->micb_mv; in wcd_mbhc_adc_get_hph_thres()
1046 static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc, in wcd_mbhc_adc_update_fsm_source() argument
1053 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); in wcd_mbhc_adc_update_fsm_source()
1056 if (mbhc->mbhc_cb->micbias_enable_status) in wcd_mbhc_adc_update_fsm_source()
1057 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc->component, in wcd_mbhc_adc_update_fsm_source()
1060 if (!mbhc->is_hs_recording && !micbias2) in wcd_mbhc_adc_update_fsm_source()
1061 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3); in wcd_mbhc_adc_update_fsm_source()
1064 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); in wcd_mbhc_adc_update_fsm_source()
1070 static void wcd_mbhc_bcs_enable(struct wcd_mbhc *mbhc, int plug_type, bool enable) in wcd_mbhc_bcs_enable() argument
1075 if (mbhc->mbhc_cb->bcs_enable) in wcd_mbhc_bcs_enable()
1076 mbhc->mbhc_cb->bcs_enable(mbhc->component, enable); in wcd_mbhc_bcs_enable()
1083 static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result) in wcd_mbhc_get_plug_from_adc() argument
1089 hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc); in wcd_mbhc_get_plug_from_adc()
1090 hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc); in wcd_mbhc_get_plug_from_adc()
1102 static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc) in wcd_mbhc_get_spl_hs_thres() argument
1106 micbias_mv = wcd_mbhc_get_micbias(mbhc); in wcd_mbhc_get_spl_hs_thres()
1107 if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) { in wcd_mbhc_get_spl_hs_thres()
1108 if (mbhc->cfg->micb_mv == micbias_mv) in wcd_mbhc_get_spl_hs_thres()
1109 hs_threshold = mbhc->cfg->hs_thr; in wcd_mbhc_get_spl_hs_thres()
1111 hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv; in wcd_mbhc_get_spl_hs_thres()
1119 static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc) in wcd_mbhc_check_for_spl_headset() argument
1124 if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) in wcd_mbhc_check_for_spl_headset()
1128 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true); in wcd_mbhc_check_for_spl_headset()
1131 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); in wcd_mbhc_check_for_spl_headset()
1132 hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc); in wcd_mbhc_check_for_spl_headset()
1133 hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc); in wcd_mbhc_check_for_spl_headset()
1140 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false); in wcd_mbhc_check_for_spl_headset()
1150 struct wcd_mbhc *mbhc; in wcd_correct_swch_plug() local
1160 mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch); in wcd_correct_swch_plug()
1161 component = mbhc->component; in wcd_correct_swch_plug()
1163 ret = pm_runtime_get_sync(component->dev); in wcd_correct_swch_plug()
1164 if (ret < 0 && ret != -EACCES) { in wcd_correct_swch_plug()
1165 dev_err_ratelimited(component->dev, in wcd_correct_swch_plug()
1168 pm_runtime_put_noidle(component->dev); in wcd_correct_swch_plug()
1171 micbias_mv = wcd_mbhc_get_micbias(mbhc); in wcd_correct_swch_plug()
1172 hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); in wcd_correct_swch_plug()
1175 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); in wcd_correct_swch_plug()
1179 cross_conn = wcd_check_cross_conn(mbhc); in wcd_correct_swch_plug()
1181 } while (try < mbhc->swap_thr); in wcd_correct_swch_plug()
1185 dev_err(mbhc->dev, "cross connection found, Plug type %d\n", in wcd_correct_swch_plug()
1191 output_mv = wcd_measure_adc_continuous(mbhc); in wcd_correct_swch_plug()
1192 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); in wcd_correct_swch_plug()
1195 * Report plug type if it is either headset or headphone in wcd_correct_swch_plug()
1200 wcd_mbhc_find_plug_and_report(mbhc, plug_type); in wcd_correct_swch_plug()
1203 wcd_mbhc_find_plug_and_report(mbhc, plug_type); in wcd_correct_swch_plug()
1204 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); in wcd_correct_swch_plug()
1205 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); in wcd_correct_swch_plug()
1206 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1); in wcd_correct_swch_plug()
1215 wcd_mbhc_bcs_enable(mbhc, plug_type, false); in wcd_correct_swch_plug()
1220 if (mbhc->hs_detect_work_stop) { in wcd_correct_swch_plug()
1221 wcd_micbias_disable(mbhc); in wcd_correct_swch_plug()
1230 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); in wcd_correct_swch_plug()
1231 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); in wcd_correct_swch_plug()
1232 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN); in wcd_correct_swch_plug()
1235 is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc); in wcd_correct_swch_plug()
1236 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); in wcd_correct_swch_plug()
1239 hs_threshold *= wcd_mbhc_get_micbias(mbhc); in wcd_correct_swch_plug()
1246 cross_conn = wcd_check_cross_conn(mbhc); in wcd_correct_swch_plug()
1247 if (cross_conn > 0) { /* cross-connection */ in wcd_correct_swch_plug()
1249 if (pt_gnd_mic_swap_cnt < mbhc->swap_thr) in wcd_correct_swch_plug()
1255 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv); in wcd_correct_swch_plug()
1260 if (pt_gnd_mic_swap_cnt == mbhc->swap_thr) { in wcd_correct_swch_plug()
1262 if (mbhc->cfg->swap_gnd_mic) { in wcd_correct_swch_plug()
1263 if (mbhc->cfg->swap_gnd_mic(component, true)) in wcd_correct_swch_plug()
1270 if (output_mv > hs_threshold || mbhc->force_linein) in wcd_correct_swch_plug()
1274 wcd_mbhc_bcs_enable(mbhc, plug_type, true); in wcd_correct_swch_plug()
1280 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1); in wcd_correct_swch_plug()
1283 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); in wcd_correct_swch_plug()
1284 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); in wcd_correct_swch_plug()
1285 wcd_mbhc_find_plug_and_report(mbhc, plug_type); in wcd_correct_swch_plug()
1293 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1); in wcd_correct_swch_plug()
1295 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0); in wcd_correct_swch_plug()
1297 if (mbhc->mbhc_cb->mbhc_micbias_control) in wcd_correct_swch_plug()
1298 wcd_mbhc_adc_update_fsm_source(mbhc, plug_type); in wcd_correct_swch_plug()
1301 if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) in wcd_correct_swch_plug()
1302 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE); in wcd_correct_swch_plug()
1305 * If plug type is corrected from special headset to headphone, in wcd_correct_swch_plug()
1310 wcd_micbias_disable(mbhc); in wcd_correct_swch_plug()
1312 * Enable ADC COMPLETE interrupt for HEADPHONE. in wcd_correct_swch_plug()
1316 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr); in wcd_correct_swch_plug()
1319 if (mbhc->mbhc_cb->hph_pull_down_ctrl) in wcd_correct_swch_plug()
1320 mbhc->mbhc_cb->hph_pull_down_ctrl(component, true); in wcd_correct_swch_plug()
1322 pm_runtime_mark_last_busy(component->dev); in wcd_correct_swch_plug()
1323 pm_runtime_put_autosuspend(component->dev); in wcd_correct_swch_plug()
1328 struct wcd_mbhc *mbhc = data; in wcd_mbhc_adc_hs_rem_irq() local
1332 mutex_lock(&mbhc->lock); in wcd_mbhc_adc_hs_rem_irq()
1334 adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc); in wcd_mbhc_adc_hs_rem_irq()
1343 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P); in wcd_mbhc_adc_hs_rem_irq()
1352 * HEADPHONE, need to reject the ADC COMPLETE interrupt which in wcd_mbhc_adc_hs_rem_irq()
1353 * follows ELEC_REM one when HEADPHONE is removed. in wcd_mbhc_adc_hs_rem_irq()
1355 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) in wcd_mbhc_adc_hs_rem_irq()
1356 mbhc->extn_cable_hph_rem = true; in wcd_mbhc_adc_hs_rem_irq()
1358 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0); in wcd_mbhc_adc_hs_rem_irq()
1359 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0); in wcd_mbhc_adc_hs_rem_irq()
1360 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0); in wcd_mbhc_adc_hs_rem_irq()
1361 wcd_mbhc_elec_hs_report_unplug(mbhc); in wcd_mbhc_adc_hs_rem_irq()
1362 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0); in wcd_mbhc_adc_hs_rem_irq()
1365 mutex_unlock(&mbhc->lock); in wcd_mbhc_adc_hs_rem_irq()
1371 struct wcd_mbhc *mbhc = data; in wcd_mbhc_adc_hs_ins_irq() local
1376 * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE, in wcd_mbhc_adc_hs_ins_irq()
1378 * when HEADPHONE is removed. in wcd_mbhc_adc_hs_ins_irq()
1380 if (mbhc->extn_cable_hph_rem == true) { in wcd_mbhc_adc_hs_ins_irq()
1381 mbhc->extn_cable_hph_rem = false; in wcd_mbhc_adc_hs_ins_irq()
1386 clamp_state = wcd_mbhc_read_field(mbhc, WCD_MBHC_IN2P_CLAMP_STATE); in wcd_mbhc_adc_hs_ins_irq()
1394 } while (--clamp_retry); in wcd_mbhc_adc_hs_ins_irq()
1397 * If current plug is headphone then there is no chance to in wcd_mbhc_adc_hs_ins_irq()
1399 * headset not headphone. in wcd_mbhc_adc_hs_ins_irq()
1401 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) { in wcd_mbhc_adc_hs_ins_irq()
1402 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); in wcd_mbhc_adc_hs_ins_irq()
1403 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1); in wcd_mbhc_adc_hs_ins_irq()
1404 wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET); in wcd_mbhc_adc_hs_ins_irq()
1411 int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr) in wcd_mbhc_get_impedance() argument
1413 *zl = mbhc->zl; in wcd_mbhc_get_impedance()
1414 *zr = mbhc->zr; in wcd_mbhc_get_impedance()
1419 return -EINVAL; in wcd_mbhc_get_impedance()
1423 void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type) in wcd_mbhc_set_hph_type() argument
1425 mbhc->hph_type = hph_type; in wcd_mbhc_set_hph_type()
1429 int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc) in wcd_mbhc_get_hph_type() argument
1431 return mbhc->hph_type; in wcd_mbhc_get_hph_type()
1435 int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *cfg, in wcd_mbhc_start() argument
1438 if (!mbhc || !cfg || !jack) in wcd_mbhc_start()
1439 return -EINVAL; in wcd_mbhc_start()
1441 mbhc->cfg = cfg; in wcd_mbhc_start()
1442 mbhc->jack = jack; in wcd_mbhc_start()
1444 return wcd_mbhc_initialise(mbhc); in wcd_mbhc_start()
1448 void wcd_mbhc_stop(struct wcd_mbhc *mbhc) in wcd_mbhc_stop() argument
1450 mbhc->current_plug = MBHC_PLUG_TYPE_NONE; in wcd_mbhc_stop()
1451 mbhc->hph_status = 0; in wcd_mbhc_stop()
1452 disable_irq_nosync(mbhc->intr_ids->hph_left_ocp); in wcd_mbhc_stop()
1453 disable_irq_nosync(mbhc->intr_ids->hph_right_ocp); in wcd_mbhc_stop()
1459 struct device_node *np = dev->of_node; in wcd_dt_parse_mbhc_data()
1460 int ret, i, microvolt; in wcd_dt_parse_mbhc_data() local
1462 if (of_property_read_bool(np, "qcom,hphl-jack-type-normally-closed")) in wcd_dt_parse_mbhc_data()
1463 cfg->hphl_swh = false; in wcd_dt_parse_mbhc_data()
1465 cfg->hphl_swh = true; in wcd_dt_parse_mbhc_data()
1467 if (of_property_read_bool(np, "qcom,ground-jack-type-normally-closed")) in wcd_dt_parse_mbhc_data()
1468 cfg->gnd_swh = false; in wcd_dt_parse_mbhc_data()
1470 cfg->gnd_swh = true; in wcd_dt_parse_mbhc_data()
1472 ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt", in wcd_dt_parse_mbhc_data()
1473 &microvolt); in wcd_dt_parse_mbhc_data()
1475 dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n"); in wcd_dt_parse_mbhc_data()
1477 cfg->hs_thr = microvolt/1000; in wcd_dt_parse_mbhc_data()
1479 ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt", in wcd_dt_parse_mbhc_data()
1480 &microvolt); in wcd_dt_parse_mbhc_data()
1482 dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt entry\n"); in wcd_dt_parse_mbhc_data()
1484 cfg->hph_thr = microvolt/1000; in wcd_dt_parse_mbhc_data()
1487 "qcom,mbhc-buttons-vthreshold-microvolt", in wcd_dt_parse_mbhc_data()
1488 &cfg->btn_high[0], in wcd_dt_parse_mbhc_data()
1491 dev_err(dev, "missing qcom,mbhc-buttons-vthreshold-microvolt entry\n"); in wcd_dt_parse_mbhc_data()
1495 cfg->btn_high[i] = 500000; in wcd_dt_parse_mbhc_data()
1498 cfg->btn_high[i] = cfg->btn_high[i]/1000; in wcd_dt_parse_mbhc_data()
1511 struct device *dev = component->dev; in wcd_mbhc_init()
1512 struct wcd_mbhc *mbhc; in wcd_mbhc_init() local
1515 if (!intr_ids || !fields || !mbhc_cb || !mbhc_cb->mbhc_bias || !mbhc_cb->set_btn_thr) { in wcd_mbhc_init()
1516 dev_err(dev, "%s: Insufficient mbhc configuration\n", __func__); in wcd_mbhc_init()
1517 return ERR_PTR(-EINVAL); in wcd_mbhc_init()
1520 mbhc = kzalloc(sizeof(*mbhc), GFP_KERNEL); in wcd_mbhc_init()
1521 if (!mbhc) in wcd_mbhc_init()
1522 return ERR_PTR(-ENOMEM); in wcd_mbhc_init()
1524 mbhc->component = component; in wcd_mbhc_init()
1525 mbhc->dev = dev; in wcd_mbhc_init()
1526 mbhc->intr_ids = intr_ids; in wcd_mbhc_init()
1527 mbhc->mbhc_cb = mbhc_cb; in wcd_mbhc_init()
1528 mbhc->fields = fields; in wcd_mbhc_init()
1529 mbhc->mbhc_detection_logic = WCD_DETECTION_ADC; in wcd_mbhc_init()
1531 if (mbhc_cb->compute_impedance) in wcd_mbhc_init()
1532 mbhc->impedance_detect = impedance_det_en; in wcd_mbhc_init()
1534 INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_long_press_fn); in wcd_mbhc_init()
1536 mutex_init(&mbhc->lock); in wcd_mbhc_init()
1538 INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug); in wcd_mbhc_init()
1539 INIT_WORK(&mbhc->mbhc_plug_detect_work, mbhc_plug_detect_fn); in wcd_mbhc_init()
1541 ret = request_threaded_irq(mbhc->intr_ids->mbhc_sw_intr, NULL, in wcd_mbhc_init()
1544 "mbhc sw intr", mbhc); in wcd_mbhc_init()
1548 ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_press_intr, NULL, in wcd_mbhc_init()
1551 "Button Press detect", mbhc); in wcd_mbhc_init()
1555 ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_release_intr, NULL, in wcd_mbhc_init()
1558 "Button Release detect", mbhc); in wcd_mbhc_init()
1562 ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_ins_intr, NULL, in wcd_mbhc_init()
1565 "Elect Insert", mbhc); in wcd_mbhc_init()
1569 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr); in wcd_mbhc_init()
1571 ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_rem_intr, NULL, in wcd_mbhc_init()
1574 "Elect Remove", mbhc); in wcd_mbhc_init()
1578 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr); in wcd_mbhc_init()
1580 ret = request_threaded_irq(mbhc->intr_ids->hph_left_ocp, NULL, in wcd_mbhc_init()
1583 "HPH_L OCP detect", mbhc); in wcd_mbhc_init()
1587 ret = request_threaded_irq(mbhc->intr_ids->hph_right_ocp, NULL, in wcd_mbhc_init()
1590 "HPH_R OCP detect", mbhc); in wcd_mbhc_init()
1594 return mbhc; in wcd_mbhc_init()
1597 free_irq(mbhc->intr_ids->hph_left_ocp, mbhc); in wcd_mbhc_init()
1599 free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc); in wcd_mbhc_init()
1601 free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc); in wcd_mbhc_init()
1603 free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc); in wcd_mbhc_init()
1605 free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc); in wcd_mbhc_init()
1607 free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc); in wcd_mbhc_init()
1609 kfree(mbhc); in wcd_mbhc_init()
1611 dev_err(dev, "Failed to request mbhc interrupts %d\n", ret); in wcd_mbhc_init()
1617 void wcd_mbhc_deinit(struct wcd_mbhc *mbhc) in wcd_mbhc_deinit() argument
1619 free_irq(mbhc->intr_ids->hph_right_ocp, mbhc); in wcd_mbhc_deinit()
1620 free_irq(mbhc->intr_ids->hph_left_ocp, mbhc); in wcd_mbhc_deinit()
1621 free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc); in wcd_mbhc_deinit()
1622 free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc); in wcd_mbhc_deinit()
1623 free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc); in wcd_mbhc_deinit()
1624 free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc); in wcd_mbhc_deinit()
1625 free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc); in wcd_mbhc_deinit()
1627 mutex_lock(&mbhc->lock); in wcd_mbhc_deinit()
1628 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch); in wcd_mbhc_deinit()
1629 cancel_work_sync(&mbhc->mbhc_plug_detect_work); in wcd_mbhc_deinit()
1630 mutex_unlock(&mbhc->lock); in wcd_mbhc_deinit()
1632 kfree(mbhc); in wcd_mbhc_deinit()
1648 MODULE_DESCRIPTION("wcd MBHC v2 module");