1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
4 #include <linux/module.h>
5 #include <linux/init.h>
6 #include <linux/slab.h>
7 #include <linux/device.h>
8 #include <linux/printk.h>
9 #include <linux/delay.h>
10 #include <linux/kernel.h>
11 #include <sound/soc.h>
12 #include <sound/jack.h>
13 #include "wcd-mbhc-v2.h"
15 #define HS_DETECT_PLUG_TIME_MS (3 * 1000)
16 #define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250
17 #define GND_MIC_SWAP_THRESHOLD 4
18 #define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100
19 #define HPHL_CROSS_CONN_THRESHOLD 100
20 #define HS_VREF_MIN_VAL 1400
21 #define FAKE_REM_RETRY_ATTEMPTS 3
22 #define WCD_MBHC_ADC_HS_THRESHOLD_MV 1700
23 #define WCD_MBHC_ADC_HPH_THRESHOLD_MV 75
24 #define WCD_MBHC_ADC_MICBIAS_MV 1800
25 #define WCD_MBHC_FAKE_INS_RETRY 4
27 #define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | \
30 #define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
31 SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
32 SND_JACK_BTN_4 | SND_JACK_BTN_5)
34 enum wcd_mbhc_adc_mux_ctl {
46 struct snd_soc_component *component;
47 struct snd_soc_jack *jack;
48 struct wcd_mbhc_config *cfg;
49 const struct wcd_mbhc_cb *mbhc_cb;
50 const struct wcd_mbhc_intr *intr_ids;
51 struct wcd_mbhc_field *fields;
52 /* Delayed work to report long button press */
53 struct delayed_work mbhc_btn_dwork;
54 /* Work to correct accessory type */
55 struct work_struct correct_plug_swch;
58 u32 hph_status; /* track headhpone status */
61 bool in_swch_irq_handler;
62 bool hs_detect_work_stop;
64 bool extn_cable_hph_rem;
66 bool impedance_detect;
67 unsigned long event_state;
68 unsigned long jiffies_atreport;
69 /* impedance of hphl and hphr */
71 /* Holds type of Headset - Mono/Stereo */
72 enum wcd_mbhc_hph_type hph_type;
73 /* Holds mbhc detection method - ADC/Legacy */
74 int mbhc_detection_logic;
77 static inline int wcd_mbhc_write_field(const struct wcd_mbhc *mbhc,
80 if (!mbhc->fields[field].reg)
83 return snd_soc_component_write_field(mbhc->component,
84 mbhc->fields[field].reg,
85 mbhc->fields[field].mask, val);
88 static inline int wcd_mbhc_read_field(const struct wcd_mbhc *mbhc, int field)
90 if (!mbhc->fields[field].reg)
93 return snd_soc_component_read_field(mbhc->component,
94 mbhc->fields[field].reg,
95 mbhc->fields[field].mask);
98 static void wcd_program_hs_vref(struct wcd_mbhc *mbhc)
100 u32 reg_val = ((mbhc->cfg->v_hs_max - HS_VREF_MIN_VAL) / 100);
102 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_VREF, reg_val);
105 static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias)
107 struct snd_soc_component *component = mbhc->component;
109 mbhc->mbhc_cb->set_btn_thr(component, mbhc->cfg->btn_low,
111 mbhc->cfg->num_btn, micbias);
114 static void wcd_mbhc_curr_micbias_control(const struct wcd_mbhc *mbhc,
115 const enum wcd_mbhc_cs_mb_en_flag cs_mb_en)
119 * Some codecs handle micbias/pullup enablement in codec
120 * drivers itself and micbias is not needed for regular
121 * plug type detection. So if micbias_control callback function
122 * is defined, just return.
124 if (mbhc->mbhc_cb->mbhc_micbias_control)
129 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
130 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
131 /* Program Button threshold registers as per CS */
132 wcd_program_btn_threshold(mbhc, false);
135 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
136 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
137 /* Disable PULL_UP_EN & enable MICBIAS */
138 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 2);
139 /* Program Button threshold registers as per MICBIAS */
140 wcd_program_btn_threshold(mbhc, true);
142 case WCD_MBHC_EN_PULLUP:
143 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
144 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
145 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 1);
146 /* Program Button threshold registers as per MICBIAS */
147 wcd_program_btn_threshold(mbhc, true);
149 case WCD_MBHC_EN_NONE:
150 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
151 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
152 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
155 dev_err(mbhc->dev, "%s: Invalid parameter", __func__);
160 int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event)
163 struct snd_soc_component *component;
164 bool micbias2 = false;
169 component = mbhc->component;
171 if (mbhc->mbhc_cb->micbias_enable_status)
172 micbias2 = mbhc->mbhc_cb->micbias_enable_status(component, MIC_BIAS_2);
175 /* MICBIAS usage change */
176 case WCD_EVENT_POST_DAPM_MICBIAS_2_ON:
177 mbhc->is_hs_recording = true;
179 case WCD_EVENT_POST_MICBIAS_2_ON:
180 /* Disable current source if micbias2 enabled */
181 if (mbhc->mbhc_cb->mbhc_micbias_control) {
182 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
183 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
185 mbhc->is_hs_recording = true;
186 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
189 case WCD_EVENT_PRE_MICBIAS_2_OFF:
191 * Before MICBIAS_2 is turned off, if FSM is enabled,
192 * make sure current source is enabled so as to detect
193 * button press/release events
195 if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) {
196 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
197 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
200 /* MICBIAS usage change */
201 case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF:
202 mbhc->is_hs_recording = false;
204 case WCD_EVENT_POST_MICBIAS_2_OFF:
205 if (!mbhc->mbhc_cb->mbhc_micbias_control)
206 mbhc->is_hs_recording = false;
208 /* Enable PULL UP if PA's are enabled */
209 if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) ||
210 (test_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state)))
211 /* enable pullup and cs, disable mb */
212 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
214 /* enable current source and disable mb, pullup*/
215 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
218 case WCD_EVENT_POST_HPHL_PA_OFF:
219 clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
221 /* check if micbias is enabled */
223 /* Disable cs, pullup & enable micbias */
224 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
226 /* Disable micbias, pullup & enable cs */
227 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
229 case WCD_EVENT_POST_HPHR_PA_OFF:
230 clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
231 /* check if micbias is enabled */
233 /* Disable cs, pullup & enable micbias */
234 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
236 /* Disable micbias, pullup & enable cs */
237 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
239 case WCD_EVENT_PRE_HPHL_PA_ON:
240 set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
241 /* check if micbias is enabled */
243 /* Disable cs, pullup & enable micbias */
244 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
246 /* Disable micbias, enable pullup & cs */
247 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
249 case WCD_EVENT_PRE_HPHR_PA_ON:
250 set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
251 /* check if micbias is enabled */
253 /* Disable cs, pullup & enable micbias */
254 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
256 /* Disable micbias, enable pullup & cs */
257 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
264 EXPORT_SYMBOL_GPL(wcd_mbhc_event_notify);
266 static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc)
268 return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
271 static void wcd_micbias_disable(struct wcd_mbhc *mbhc)
273 struct snd_soc_component *component = mbhc->component;
275 if (mbhc->mbhc_cb->mbhc_micbias_control)
276 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
278 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
279 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, false);
281 if (mbhc->mbhc_cb->set_micbias_value) {
282 mbhc->mbhc_cb->set_micbias_value(component);
283 wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
287 static void wcd_mbhc_report_plug_removal(struct wcd_mbhc *mbhc,
288 enum snd_jack_types jack_type)
290 mbhc->hph_status &= ~jack_type;
292 * cancel possibly scheduled btn work and
293 * report release if we reported button press
295 if (!wcd_cancel_btn_work(mbhc) && mbhc->buttons_pressed) {
296 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
297 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
300 wcd_micbias_disable(mbhc);
301 mbhc->hph_type = WCD_MBHC_HPH_NONE;
302 mbhc->zl = mbhc->zr = 0;
303 snd_soc_jack_report(mbhc->jack, mbhc->hph_status, WCD_MBHC_JACK_MASK);
304 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
305 mbhc->force_linein = false;
308 static void wcd_mbhc_compute_impedance(struct wcd_mbhc *mbhc)
311 if (!mbhc->impedance_detect)
314 if (mbhc->cfg->linein_th != 0) {
315 u8 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
316 /* Set MUX_CTL to AUTO for Z-det */
318 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
319 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
320 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
321 mbhc->mbhc_cb->compute_impedance(mbhc->component, &mbhc->zl, &mbhc->zr);
322 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
326 static void wcd_mbhc_report_plug_insertion(struct wcd_mbhc *mbhc,
327 enum snd_jack_types jack_type)
331 * Report removal of current jack type.
332 * Headphone to headset shouldn't report headphone
335 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
336 jack_type == SND_JACK_HEADPHONE)
337 mbhc->hph_status &= ~SND_JACK_HEADSET;
339 /* Report insertion */
341 case SND_JACK_HEADPHONE:
342 mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
344 case SND_JACK_HEADSET:
345 mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
346 mbhc->jiffies_atreport = jiffies;
348 case SND_JACK_LINEOUT:
349 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
356 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
359 wcd_mbhc_compute_impedance(mbhc);
360 if ((mbhc->zl > mbhc->cfg->linein_th) &&
361 (mbhc->zr > mbhc->cfg->linein_th) &&
362 (jack_type == SND_JACK_HEADPHONE)) {
363 jack_type = SND_JACK_LINEOUT;
364 mbhc->force_linein = true;
365 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
366 if (mbhc->hph_status) {
367 mbhc->hph_status &= ~(SND_JACK_HEADSET |
369 snd_soc_jack_report(mbhc->jack, mbhc->hph_status,
375 /* Do not calculate impedance again for lineout
376 * as during playback pa is on and impedance values
377 * will not be correct resulting in lineout detected
380 if (is_pa_on && mbhc->force_linein) {
381 jack_type = SND_JACK_LINEOUT;
382 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
383 if (mbhc->hph_status) {
384 mbhc->hph_status &= ~(SND_JACK_HEADSET |
386 snd_soc_jack_report(mbhc->jack, mbhc->hph_status,
391 mbhc->hph_status |= jack_type;
393 if (jack_type == SND_JACK_HEADPHONE && mbhc->mbhc_cb->mbhc_micb_ramp_control)
394 mbhc->mbhc_cb->mbhc_micb_ramp_control(mbhc->component, false);
396 snd_soc_jack_report(mbhc->jack, (mbhc->hph_status | SND_JACK_MECHANICAL),
400 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
401 enum snd_jack_types jack_type)
404 WARN_ON(!mutex_is_locked(&mbhc->lock));
406 if (!insertion) /* Report removal */
407 wcd_mbhc_report_plug_removal(mbhc, jack_type);
409 wcd_mbhc_report_plug_insertion(mbhc, jack_type);
413 static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
414 struct work_struct *work)
416 mbhc->hs_detect_work_stop = true;
417 mutex_unlock(&mbhc->lock);
418 cancel_work_sync(work);
419 mutex_lock(&mbhc->lock);
422 static void wcd_mbhc_cancel_pending_work(struct wcd_mbhc *mbhc)
424 /* cancel pending button press */
425 wcd_cancel_btn_work(mbhc);
426 /* cancel correct work function */
427 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
430 static void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc)
432 wcd_mbhc_cancel_pending_work(mbhc);
433 /* Report extension cable */
434 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
436 * Disable HPHL trigger and MIC Schmitt triggers.
437 * Setup for insertion detection.
439 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
440 wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_NONE);
442 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
443 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 3);
445 /* Set the detection type appropriately */
446 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
447 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
450 static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
451 enum wcd_mbhc_plug_type plug_type)
453 if (mbhc->current_plug == plug_type)
456 mutex_lock(&mbhc->lock);
459 case MBHC_PLUG_TYPE_HEADPHONE:
460 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
462 case MBHC_PLUG_TYPE_HEADSET:
463 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET);
465 case MBHC_PLUG_TYPE_HIGH_HPH:
466 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
468 case MBHC_PLUG_TYPE_GND_MIC_SWAP:
469 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
470 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
471 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
472 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
475 WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
476 mbhc->current_plug, plug_type);
479 mutex_unlock(&mbhc->lock);
482 static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
483 struct work_struct *work)
485 WARN_ON(!mutex_is_locked(&mbhc->lock));
486 mbhc->hs_detect_work_stop = false;
490 static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc)
492 struct snd_soc_component *component = mbhc->component;
494 WARN_ON(!mutex_is_locked(&mbhc->lock));
496 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
497 mbhc->mbhc_cb->hph_pull_down_ctrl(component, false);
499 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
501 if (mbhc->mbhc_cb->mbhc_micbias_control) {
502 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2,
504 wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
508 static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
510 struct snd_soc_component *component;
511 enum snd_jack_types jack_type;
512 struct wcd_mbhc *mbhc = data;
515 component = mbhc->component;
516 mutex_lock(&mbhc->lock);
518 mbhc->in_swch_irq_handler = true;
520 wcd_mbhc_cancel_pending_work(mbhc);
522 detection_type = wcd_mbhc_read_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE);
524 /* Set the detection type appropriately */
525 wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, !detection_type);
527 /* Enable micbias ramp */
528 if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
529 mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true);
531 if (detection_type) {
532 if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
534 /* Make sure MASTER_BIAS_CTL is enabled */
535 mbhc->mbhc_cb->mbhc_bias(component, true);
536 mbhc->is_btn_press = false;
537 wcd_mbhc_adc_detect_plug_type(mbhc);
540 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
541 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
542 mbhc->extn_cable_hph_rem = false;
544 if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE)
547 mbhc->is_btn_press = false;
548 switch (mbhc->current_plug) {
549 case MBHC_PLUG_TYPE_HEADPHONE:
550 jack_type = SND_JACK_HEADPHONE;
552 case MBHC_PLUG_TYPE_HEADSET:
553 jack_type = SND_JACK_HEADSET;
555 case MBHC_PLUG_TYPE_HIGH_HPH:
556 if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC)
557 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 0);
558 jack_type = SND_JACK_LINEOUT;
560 case MBHC_PLUG_TYPE_GND_MIC_SWAP:
561 dev_err(mbhc->dev, "Ground and Mic Swapped on plug\n");
564 dev_err(mbhc->dev, "Invalid current plug: %d\n",
568 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
569 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
570 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
571 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
572 wcd_mbhc_report_plug(mbhc, 0, jack_type);
576 mbhc->in_swch_irq_handler = false;
577 mutex_unlock(&mbhc->lock);
581 static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc)
586 btn = wcd_mbhc_read_field(mbhc, WCD_MBHC_BTN_RESULT);
590 mask = SND_JACK_BTN_0;
593 mask = SND_JACK_BTN_1;
596 mask = SND_JACK_BTN_2;
599 mask = SND_JACK_BTN_3;
602 mask = SND_JACK_BTN_4;
605 mask = SND_JACK_BTN_5;
614 static void wcd_btn_long_press_fn(struct work_struct *work)
616 struct delayed_work *dwork = to_delayed_work(work);
617 struct wcd_mbhc *mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork);
619 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
620 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
621 mbhc->buttons_pressed);
624 static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
626 struct wcd_mbhc *mbhc = data;
628 unsigned long msec_val;
630 mutex_lock(&mbhc->lock);
631 wcd_cancel_btn_work(mbhc);
632 mbhc->is_btn_press = true;
633 msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
635 /* Too short, ignore button press */
636 if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN)
639 /* If switch interrupt already kicked in, ignore button press */
640 if (mbhc->in_swch_irq_handler)
643 /* Plug isn't headset, ignore button press */
644 if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET)
647 mask = wcd_mbhc_get_button_mask(mbhc);
648 mbhc->buttons_pressed |= mask;
649 if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, msecs_to_jiffies(400)) == 0)
650 WARN(1, "Button pressed twice without release event\n");
652 mutex_unlock(&mbhc->lock);
656 static irqreturn_t wcd_mbhc_btn_release_handler(int irq, void *data)
658 struct wcd_mbhc *mbhc = data;
661 mutex_lock(&mbhc->lock);
662 if (mbhc->is_btn_press)
663 mbhc->is_btn_press = false;
664 else /* fake btn press */
667 if (!(mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK))
670 ret = wcd_cancel_btn_work(mbhc);
671 if (ret == 0) { /* Reporting long button release event */
672 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
674 if (!mbhc->in_swch_irq_handler) {
675 /* Reporting btn press n Release */
676 snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
677 mbhc->buttons_pressed);
678 snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
681 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
683 mutex_unlock(&mbhc->lock);
688 static irqreturn_t wcd_mbhc_hph_ocp_irq(struct wcd_mbhc *mbhc, bool hphr)
691 /* TODO Find a better way to report this to Userspace */
692 dev_err(mbhc->dev, "MBHC Over Current on %s detected\n",
693 hphr ? "HPHR" : "HPHL");
695 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 0);
696 wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 1);
701 static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
703 return wcd_mbhc_hph_ocp_irq(data, false);
706 static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
708 return wcd_mbhc_hph_ocp_irq(data, true);
711 static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
713 struct snd_soc_component *component = mbhc->component;
715 mutex_lock(&mbhc->lock);
717 /* enable HS detection */
718 if (mbhc->mbhc_cb->hph_pull_up_control_v2)
719 mbhc->mbhc_cb->hph_pull_up_control_v2(component,
720 HS_PULLUP_I_DEFAULT);
721 else if (mbhc->mbhc_cb->hph_pull_up_control)
722 mbhc->mbhc_cb->hph_pull_up_control(component, I_DEFAULT);
724 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
726 wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh);
727 wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh);
728 wcd_mbhc_write_field(mbhc, WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
729 if (mbhc->cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl)
730 mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true);
731 wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
733 wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
735 /* Insertion debounce set to 96ms */
736 wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6);
738 /* Button Debounce set to 16ms */
739 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2);
742 mbhc->mbhc_cb->mbhc_bias(component, true);
743 /* enable MBHC clock */
744 if (mbhc->mbhc_cb->clk_setup)
745 mbhc->mbhc_cb->clk_setup(component, true);
747 /* program HS_VREF value */
748 wcd_program_hs_vref(mbhc);
750 wcd_program_btn_threshold(mbhc, false);
752 mutex_unlock(&mbhc->lock);
757 static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc)
761 if (mbhc->mbhc_cb->get_micbias_val) {
762 mbhc->mbhc_cb->get_micbias_val(mbhc->component, &micbias);
765 /* Read MBHC Micbias (Mic Bias2) voltage */
766 vout_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_MICB2_VOUT);
767 /* Formula for getting micbias from vout
768 * micbias = 1.0V + VOUT_CTL * 50mV
770 micbias = 1000 + (vout_ctl * 50);
775 static int wcd_get_voltage_from_adc(u8 val, int micbias)
777 /* Formula for calculating voltage from ADC
778 * Voltage = ADC_RESULT*12.5mV*V_MICBIAS/1.8
780 return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10));
783 static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
790 /* Pre-requisites for ADC continuous measurement */
791 /* Read legacy electircal detection and disable */
792 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
793 /* Set ADC to continuous measurement */
794 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 1);
795 /* Read ADC Enable bit to restore after adc measurement */
796 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
797 /* Disable ADC_ENABLE bit */
798 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
799 /* Disable MBHC FSM */
800 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
801 /* Set the MUX selection to IN2P */
802 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_IN2P);
803 /* Enable MBHC FSM */
804 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
805 /* Enable ADC_ENABLE bit */
806 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
809 /* wait for 3 msec before reading ADC result */
810 usleep_range(3000, 3100);
811 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
814 /* Restore ADC Enable */
815 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
816 /* Get voltage from ADC result */
817 output_mv = wcd_get_voltage_from_adc(adc_result, wcd_mbhc_get_micbias(mbhc));
822 static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl)
824 struct device *dev = mbhc->dev;
833 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
834 /* Read ADC Enable bit to restore after adc measurement */
835 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
836 /* Trigger ADC one time measurement */
837 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
838 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
839 /* Set the appropriate MUX selection */
840 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, mux_ctl);
841 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
842 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
845 /* wait for 600usec to get adc results */
846 usleep_range(600, 610);
848 /* check for ADC Timeout */
849 adc_timeout = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_TIMEOUT);
853 /* Read ADC complete bit */
854 adc_complete = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_COMPLETE);
858 /* Read ADC result */
859 adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
861 /* Get voltage from ADC result */
862 output_mv = wcd_get_voltage_from_adc(adc_result,
863 wcd_mbhc_get_micbias(mbhc));
867 /* Restore ADC Enable */
868 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
871 dev_err(dev, "%s: adc complete: %d, adc timeout: %d\n",
872 __func__, adc_complete, adc_timeout);
881 /* To determine if cross connection occurred */
882 static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
884 u8 adc_mode, elect_ctl, adc_en, fsm_en;
885 int hphl_adc_res, hphr_adc_res;
886 bool is_cross_conn = false;
888 /* If PA is enabled, dont check for cross-connection */
889 if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN))
892 /* Read legacy electircal detection and disable */
893 elect_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC);
894 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
896 /* Read and set ADC to single measurement */
897 adc_mode = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_MODE);
898 /* Read ADC Enable bit to restore after adc measurement */
899 adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
900 /* Read FSM status */
901 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
903 /* Get adc result for HPH L */
904 hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L);
905 if (hphl_adc_res < 0)
908 /* Get adc result for HPH R in mV */
909 hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R);
910 if (hphr_adc_res < 0)
913 if (hphl_adc_res > HPHL_CROSS_CONN_THRESHOLD ||
914 hphr_adc_res > HPHL_CROSS_CONN_THRESHOLD)
915 is_cross_conn = true;
917 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
918 /* Set the MUX selection to Auto */
919 wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
920 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
921 /* Restore ADC Enable */
922 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
923 /* Restore ADC mode */
924 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, adc_mode);
925 /* Restore FSM state */
926 wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
927 /* Restore electrical detection */
928 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
930 return is_cross_conn;
933 static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc)
935 int hs_threshold, micbias_mv;
937 micbias_mv = wcd_mbhc_get_micbias(mbhc);
938 if (mbhc->cfg->hs_thr) {
939 if (mbhc->cfg->micb_mv == micbias_mv)
940 hs_threshold = mbhc->cfg->hs_thr;
942 hs_threshold = (mbhc->cfg->hs_thr *
943 micbias_mv) / mbhc->cfg->micb_mv;
945 hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
946 micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
951 static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc)
953 int hph_threshold, micbias_mv;
955 micbias_mv = wcd_mbhc_get_micbias(mbhc);
956 if (mbhc->cfg->hph_thr) {
957 if (mbhc->cfg->micb_mv == micbias_mv)
958 hph_threshold = mbhc->cfg->hph_thr;
960 hph_threshold = (mbhc->cfg->hph_thr *
961 micbias_mv) / mbhc->cfg->micb_mv;
963 hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV *
964 micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
966 return hph_threshold;
969 static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc,
970 enum wcd_mbhc_plug_type plug_type)
972 bool micbias2 = false;
975 case MBHC_PLUG_TYPE_HEADPHONE:
976 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
978 case MBHC_PLUG_TYPE_HEADSET:
979 if (mbhc->mbhc_cb->micbias_enable_status)
980 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc->component,
983 if (!mbhc->is_hs_recording && !micbias2)
984 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
987 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
993 static void wcd_mbhc_bcs_enable(struct wcd_mbhc *mbhc, int plug_type, bool enable)
996 case MBHC_PLUG_TYPE_HEADSET:
997 case MBHC_PLUG_TYPE_HEADPHONE:
998 if (mbhc->mbhc_cb->bcs_enable)
999 mbhc->mbhc_cb->bcs_enable(mbhc->component, enable);
1006 static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result)
1009 enum wcd_mbhc_plug_type plug_type;
1010 u32 hph_thr, hs_thr;
1012 hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc);
1013 hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc);
1015 if (adc_result < hph_thr)
1016 plug_type = MBHC_PLUG_TYPE_HEADPHONE;
1017 else if (adc_result > hs_thr)
1018 plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1020 plug_type = MBHC_PLUG_TYPE_HEADSET;
1025 static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc)
1027 int hs_threshold, micbias_mv;
1029 micbias_mv = wcd_mbhc_get_micbias(mbhc);
1030 if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) {
1031 if (mbhc->cfg->micb_mv == micbias_mv)
1032 hs_threshold = mbhc->cfg->hs_thr;
1034 hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv;
1036 hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * micbias_mv) /
1037 WCD_MBHC_ADC_MICBIAS_MV);
1039 return hs_threshold;
1042 static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc)
1044 bool is_spl_hs = false;
1045 int output_mv, hs_threshold, hph_threshold;
1047 if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
1050 /* Bump up MIC_BIAS2 to 2.7V */
1051 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true);
1052 usleep_range(10000, 10100);
1054 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1055 hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc);
1056 hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc);
1058 if (!(output_mv > hs_threshold || output_mv < hph_threshold))
1061 /* Back MIC_BIAS2 to 1.8v if the type is not special headset */
1063 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false);
1064 /* Add 10ms delay for micbias to settle */
1065 usleep_range(10000, 10100);
1071 static void wcd_correct_swch_plug(struct work_struct *work)
1073 struct wcd_mbhc *mbhc;
1074 struct snd_soc_component *component;
1075 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
1076 unsigned long timeout;
1077 int pt_gnd_mic_swap_cnt = 0;
1078 int output_mv, cross_conn, hs_threshold, try = 0, micbias_mv;
1079 bool is_spl_hs = false;
1082 mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
1083 component = mbhc->component;
1085 micbias_mv = wcd_mbhc_get_micbias(mbhc);
1086 hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1088 /* Mask ADC COMPLETE interrupt */
1089 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1091 /* Check for cross connection */
1093 cross_conn = wcd_check_cross_conn(mbhc);
1095 } while (try < GND_MIC_SWAP_THRESHOLD);
1097 if (cross_conn > 0) {
1098 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1099 dev_err(mbhc->dev, "cross connection found, Plug type %d\n",
1101 goto correct_plug_type;
1104 /* Find plug type */
1105 output_mv = wcd_measure_adc_continuous(mbhc);
1106 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1109 * Report plug type if it is either headset or headphone
1110 * else start the 3 sec loop
1112 switch (plug_type) {
1113 case MBHC_PLUG_TYPE_HEADPHONE:
1114 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1116 case MBHC_PLUG_TYPE_HEADSET:
1117 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1118 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1119 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1120 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1128 /* Disable BCS slow insertion detection */
1129 wcd_mbhc_bcs_enable(mbhc, plug_type, false);
1131 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
1133 while (!time_after(jiffies, timeout)) {
1134 if (mbhc->hs_detect_work_stop) {
1135 wcd_micbias_disable(mbhc);
1141 * Use ADC single mode to minimize the chance of missing out
1142 * btn press/release for HEADSET type during correct work.
1144 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1145 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1146 is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
1148 if (output_mv > hs_threshold && !is_spl_hs) {
1149 is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc);
1150 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1153 hs_threshold *= wcd_mbhc_get_micbias(mbhc);
1154 hs_threshold /= micbias_mv;
1158 if ((output_mv <= hs_threshold) && !is_pa_on) {
1159 /* Check for cross connection*/
1160 cross_conn = wcd_check_cross_conn(mbhc);
1161 if (cross_conn > 0) { /* cross-connection */
1162 pt_gnd_mic_swap_cnt++;
1163 if (pt_gnd_mic_swap_cnt < GND_MIC_SWAP_THRESHOLD)
1166 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1167 } else if (!cross_conn) { /* no cross connection */
1168 pt_gnd_mic_swap_cnt = 0;
1169 plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1171 } else if (cross_conn < 0) /* Error */
1174 if (pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) {
1175 /* US_EU gpio present, flip switch */
1176 if (mbhc->cfg->swap_gnd_mic) {
1177 if (mbhc->cfg->swap_gnd_mic(component, true))
1183 /* cable is extension cable */
1184 if (output_mv > hs_threshold || mbhc->force_linein)
1185 plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1188 wcd_mbhc_bcs_enable(mbhc, plug_type, true);
1190 if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
1192 plug_type = MBHC_PLUG_TYPE_HEADSET;
1194 wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1);
1197 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1198 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1199 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1202 * Set DETECTION_DONE bit for HEADSET
1203 * so that btn press/release interrupt can be generated.
1204 * For other plug type, clear the bit.
1206 if (plug_type == MBHC_PLUG_TYPE_HEADSET)
1207 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1209 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1211 if (mbhc->mbhc_cb->mbhc_micbias_control)
1212 wcd_mbhc_adc_update_fsm_source(mbhc, plug_type);
1215 if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/)
1216 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
1219 * If plug type is corrected from special headset to headphone,
1220 * clear the micbias enable flag, set micbias back to 1.8V and
1223 if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
1224 wcd_micbias_disable(mbhc);
1226 * Enable ADC COMPLETE interrupt for HEADPHONE.
1227 * Btn release may happen after the correct work, ADC COMPLETE
1228 * interrupt needs to be captured to correct plug type.
1230 enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
1233 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
1234 mbhc->mbhc_cb->hph_pull_down_ctrl(component, true);
1237 static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data)
1239 struct wcd_mbhc *mbhc = data;
1240 unsigned long timeout;
1241 int adc_threshold, output_mv, retry = 0;
1243 mutex_lock(&mbhc->lock);
1244 timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
1245 adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1250 * read output_mv every 10ms to look for
1251 * any change in IN2_P
1253 usleep_range(10000, 10100);
1254 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1256 /* Check for fake removal */
1257 if ((output_mv <= adc_threshold) && retry > FAKE_REM_RETRY_ATTEMPTS)
1259 } while (!time_after(jiffies, timeout));
1262 * ADC COMPLETE and ELEC_REM interrupts are both enabled for
1263 * HEADPHONE, need to reject the ADC COMPLETE interrupt which
1264 * follows ELEC_REM one when HEADPHONE is removed.
1266 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
1267 mbhc->extn_cable_hph_rem = true;
1269 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1270 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1271 wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1272 wcd_mbhc_elec_hs_report_unplug(mbhc);
1273 wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
1276 mutex_unlock(&mbhc->lock);
1280 static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data)
1282 struct wcd_mbhc *mbhc = data;
1284 u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY;
1287 * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE,
1288 * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one
1289 * when HEADPHONE is removed.
1291 if (mbhc->extn_cable_hph_rem == true) {
1292 mbhc->extn_cable_hph_rem = false;
1297 clamp_state = wcd_mbhc_read_field(mbhc, WCD_MBHC_IN2P_CLAMP_STATE);
1301 * check clamp for 120ms but at 30ms chunks to leave
1302 * room for other interrupts to be processed
1304 usleep_range(30000, 30100);
1305 } while (--clamp_retry);
1308 * If current plug is headphone then there is no chance to
1309 * get ADC complete interrupt, so connected cable should be
1310 * headset not headphone.
1312 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
1313 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1314 wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1315 wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
1322 int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, uint32_t *zr)
1332 EXPORT_SYMBOL(wcd_mbhc_get_impedance);
1334 void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type)
1336 mbhc->hph_type = hph_type;
1338 EXPORT_SYMBOL(wcd_mbhc_set_hph_type);
1340 int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc)
1342 return mbhc->hph_type;
1344 EXPORT_SYMBOL(wcd_mbhc_get_hph_type);
1346 int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *cfg,
1347 struct snd_soc_jack *jack)
1349 if (!mbhc || !cfg || !jack)
1355 return wcd_mbhc_initialise(mbhc);
1357 EXPORT_SYMBOL(wcd_mbhc_start);
1359 void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
1361 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
1362 mbhc->hph_status = 0;
1363 disable_irq_nosync(mbhc->intr_ids->hph_left_ocp);
1364 disable_irq_nosync(mbhc->intr_ids->hph_right_ocp);
1366 EXPORT_SYMBOL(wcd_mbhc_stop);
1368 int wcd_dt_parse_mbhc_data(struct device *dev, struct wcd_mbhc_config *cfg)
1370 struct device_node *np = dev->of_node;
1371 int ret, i, microvolt;
1373 if (of_property_read_bool(np, "qcom,hphl-jack-type-normally-closed"))
1374 cfg->hphl_swh = false;
1376 cfg->hphl_swh = true;
1378 if (of_property_read_bool(np, "qcom,ground-jack-type-normally-closed"))
1379 cfg->gnd_swh = false;
1381 cfg->gnd_swh = true;
1383 ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt",
1386 dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n");
1388 cfg->hs_thr = microvolt/1000;
1390 ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt",
1393 dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt entry\n");
1395 cfg->hph_thr = microvolt/1000;
1397 ret = of_property_read_u32_array(np,
1398 "qcom,mbhc-buttons-vthreshold-microvolt",
1400 WCD_MBHC_DEF_BUTTONS);
1402 dev_err(dev, "missing qcom,mbhc-buttons-vthreshold-microvolt entry\n");
1404 for (i = 0; i < WCD_MBHC_DEF_BUTTONS; i++) {
1405 if (ret) /* default voltage */
1406 cfg->btn_high[i] = 500000;
1408 /* Micro to Milli Volts */
1409 cfg->btn_high[i] = cfg->btn_high[i]/1000;
1414 EXPORT_SYMBOL(wcd_dt_parse_mbhc_data);
1416 struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
1417 const struct wcd_mbhc_cb *mbhc_cb,
1418 const struct wcd_mbhc_intr *intr_ids,
1419 struct wcd_mbhc_field *fields,
1420 bool impedance_det_en)
1422 struct device *dev = component->dev;
1423 struct wcd_mbhc *mbhc;
1426 if (!intr_ids || !fields || !mbhc_cb || !mbhc_cb->mbhc_bias || !mbhc_cb->set_btn_thr) {
1427 dev_err(dev, "%s: Insufficient mbhc configuration\n", __func__);
1428 return ERR_PTR(-EINVAL);
1431 mbhc = devm_kzalloc(dev, sizeof(*mbhc), GFP_KERNEL);
1433 return ERR_PTR(-ENOMEM);
1435 mbhc->component = component;
1437 mbhc->intr_ids = intr_ids;
1438 mbhc->mbhc_cb = mbhc_cb;
1439 mbhc->fields = fields;
1440 mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
1442 if (mbhc_cb->compute_impedance)
1443 mbhc->impedance_detect = impedance_det_en;
1445 INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_long_press_fn);
1447 mutex_init(&mbhc->lock);
1449 INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
1451 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_sw_intr, NULL,
1452 wcd_mbhc_mech_plug_detect_irq,
1453 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1454 "mbhc sw intr", mbhc);
1458 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_press_intr, NULL,
1459 wcd_mbhc_btn_press_handler,
1460 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1461 "Button Press detect", mbhc);
1465 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_btn_release_intr, NULL,
1466 wcd_mbhc_btn_release_handler,
1467 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1468 "Button Release detect", mbhc);
1472 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_ins_intr, NULL,
1473 wcd_mbhc_adc_hs_ins_irq,
1474 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1475 "Elect Insert", mbhc);
1479 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1481 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->mbhc_hs_rem_intr, NULL,
1482 wcd_mbhc_adc_hs_rem_irq,
1483 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1484 "Elect Remove", mbhc);
1488 disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
1490 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_left_ocp, NULL,
1491 wcd_mbhc_hphl_ocp_irq,
1492 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1493 "HPH_L OCP detect", mbhc);
1497 ret = devm_request_threaded_irq(dev, mbhc->intr_ids->hph_right_ocp, NULL,
1498 wcd_mbhc_hphr_ocp_irq,
1499 IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1500 "HPH_R OCP detect", mbhc);
1506 dev_err(dev, "Failed to request mbhc interrupts %d\n", ret);
1508 return ERR_PTR(ret);
1510 EXPORT_SYMBOL(wcd_mbhc_init);
1512 void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
1514 mutex_lock(&mbhc->lock);
1515 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
1516 mutex_unlock(&mbhc->lock);
1518 EXPORT_SYMBOL(wcd_mbhc_deinit);
1520 static int __init mbhc_init(void)
1525 static void __exit mbhc_exit(void)
1529 module_init(mbhc_init);
1530 module_exit(mbhc_exit);
1532 MODULE_DESCRIPTION("wcd MBHC v2 module");
1533 MODULE_LICENSE("GPL");