xref: /openbmc/linux/sound/soc/codecs/wcd-mbhc-v2.c (revision dd21bfa4)
1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (c) 2015-2021, The Linux Foundation. All rights reserved.
3 
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"
14 
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
26 
27 #define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | \
28 			   SND_JACK_MECHANICAL)
29 
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)
33 
34 enum wcd_mbhc_adc_mux_ctl {
35 	MUX_CTL_AUTO = 0,
36 	MUX_CTL_IN2P,
37 	MUX_CTL_IN3P,
38 	MUX_CTL_IN4P,
39 	MUX_CTL_HPH_L,
40 	MUX_CTL_HPH_R,
41 	MUX_CTL_NONE,
42 };
43 
44 struct wcd_mbhc {
45 	struct device *dev;
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;
56 	struct mutex lock;
57 	int buttons_pressed;
58 	u32 hph_status; /* track headhpone status */
59 	u8 current_plug;
60 	bool is_btn_press;
61 	bool in_swch_irq_handler;
62 	bool hs_detect_work_stop;
63 	bool is_hs_recording;
64 	bool extn_cable_hph_rem;
65 	bool force_linein;
66 	bool impedance_detect;
67 	unsigned long event_state;
68 	unsigned long jiffies_atreport;
69 	/* impedance of hphl and hphr */
70 	uint32_t zl, zr;
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;
75 };
76 
77 static inline int wcd_mbhc_write_field(const struct wcd_mbhc *mbhc,
78 				       int field, int val)
79 {
80 	if (!mbhc->fields[field].reg)
81 		return 0;
82 
83 	return snd_soc_component_write_field(mbhc->component,
84 					     mbhc->fields[field].reg,
85 					     mbhc->fields[field].mask, val);
86 }
87 
88 static inline int wcd_mbhc_read_field(const struct wcd_mbhc *mbhc, int field)
89 {
90 	if (!mbhc->fields[field].reg)
91 		return 0;
92 
93 	return snd_soc_component_read_field(mbhc->component,
94 					    mbhc->fields[field].reg,
95 					    mbhc->fields[field].mask);
96 }
97 
98 static void wcd_program_hs_vref(struct wcd_mbhc *mbhc)
99 {
100 	u32 reg_val = ((mbhc->cfg->v_hs_max - HS_VREF_MIN_VAL) / 100);
101 
102 	wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_VREF, reg_val);
103 }
104 
105 static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias)
106 {
107 	struct snd_soc_component *component = mbhc->component;
108 
109 	mbhc->mbhc_cb->set_btn_thr(component, mbhc->cfg->btn_low,
110 				   mbhc->cfg->btn_high,
111 				   mbhc->cfg->num_btn, micbias);
112 }
113 
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)
116 {
117 
118 	/*
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.
123 	 */
124 	if (mbhc->mbhc_cb->mbhc_micbias_control)
125 		return;
126 
127 	switch (cs_mb_en) {
128 	case WCD_MBHC_EN_CS:
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);
133 		break;
134 	case WCD_MBHC_EN_MB:
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);
141 		break;
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);
148 		break;
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);
153 		break;
154 	default:
155 		dev_err(mbhc->dev, "%s: Invalid parameter", __func__);
156 		break;
157 	}
158 }
159 
160 int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event)
161 {
162 
163 	struct snd_soc_component *component;
164 	bool micbias2 = false;
165 
166 	if (!mbhc)
167 		return 0;
168 
169 	component = mbhc->component;
170 
171 	if (mbhc->mbhc_cb->micbias_enable_status)
172 		micbias2 = mbhc->mbhc_cb->micbias_enable_status(component, MIC_BIAS_2);
173 
174 	switch (event) {
175 	/* MICBIAS usage change */
176 	case WCD_EVENT_POST_DAPM_MICBIAS_2_ON:
177 		mbhc->is_hs_recording = true;
178 		break;
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);
184 		} else {
185 			mbhc->is_hs_recording = true;
186 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
187 		}
188 		break;
189 	case WCD_EVENT_PRE_MICBIAS_2_OFF:
190 		/*
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
194 		 */
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);
198 		}
199 		break;
200 	/* MICBIAS usage change */
201 	case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF:
202 		mbhc->is_hs_recording = false;
203 		break;
204 	case WCD_EVENT_POST_MICBIAS_2_OFF:
205 		if (!mbhc->mbhc_cb->mbhc_micbias_control)
206 			mbhc->is_hs_recording = false;
207 
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);
213 		else
214 			/* enable current source and disable mb, pullup*/
215 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
216 
217 		break;
218 	case WCD_EVENT_POST_HPHL_PA_OFF:
219 		clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
220 
221 		/* check if micbias is enabled */
222 		if (micbias2)
223 			/* Disable cs, pullup & enable micbias */
224 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
225 		else
226 			/* Disable micbias, pullup & enable cs */
227 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
228 		break;
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 */
232 		if (micbias2)
233 			/* Disable cs, pullup & enable micbias */
234 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
235 		else
236 			/* Disable micbias, pullup & enable cs */
237 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
238 		break;
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 */
242 		if (micbias2)
243 			/* Disable cs, pullup & enable micbias */
244 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
245 		else
246 			/* Disable micbias, enable pullup & cs */
247 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
248 		break;
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 */
252 		if (micbias2)
253 			/* Disable cs, pullup & enable micbias */
254 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
255 		else
256 			/* Disable micbias, enable pullup & cs */
257 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
258 		break;
259 	default:
260 		break;
261 	}
262 	return 0;
263 }
264 EXPORT_SYMBOL_GPL(wcd_mbhc_event_notify);
265 
266 static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc)
267 {
268 	return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
269 }
270 
271 static void wcd_micbias_disable(struct wcd_mbhc *mbhc)
272 {
273 	struct snd_soc_component *component = mbhc->component;
274 
275 	if (mbhc->mbhc_cb->mbhc_micbias_control)
276 		mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
277 
278 	if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
279 		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, false);
280 
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);
284 	}
285 }
286 
287 static void wcd_mbhc_report_plug_removal(struct wcd_mbhc *mbhc,
288 					 enum snd_jack_types jack_type)
289 {
290 	mbhc->hph_status &= ~jack_type;
291 	/*
292 	 * cancel possibly scheduled btn work and
293 	 * report release if we reported button press
294 	 */
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;
298 	}
299 
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;
306 }
307 
308 static void wcd_mbhc_compute_impedance(struct wcd_mbhc *mbhc)
309 {
310 
311 	if (!mbhc->impedance_detect)
312 		return;
313 
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 */
317 
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);
323 	}
324 }
325 
326 static void wcd_mbhc_report_plug_insertion(struct wcd_mbhc *mbhc,
327 					   enum snd_jack_types jack_type)
328 {
329 	bool is_pa_on;
330 	/*
331 	 * Report removal of current jack type.
332 	 * Headphone to headset shouldn't report headphone
333 	 * removal.
334 	 */
335 	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
336 	    jack_type == SND_JACK_HEADPHONE)
337 		mbhc->hph_status &= ~SND_JACK_HEADSET;
338 
339 	/* Report insertion */
340 	switch (jack_type) {
341 	case SND_JACK_HEADPHONE:
342 		mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
343 		break;
344 	case SND_JACK_HEADSET:
345 		mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
346 		mbhc->jiffies_atreport = jiffies;
347 		break;
348 	case SND_JACK_LINEOUT:
349 		mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
350 		break;
351 	default:
352 		break;
353 	}
354 
355 
356 	is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
357 
358 	if (!is_pa_on) {
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 |
368 						      SND_JACK_LINEOUT);
369 				snd_soc_jack_report(mbhc->jack,	mbhc->hph_status,
370 						    WCD_MBHC_JACK_MASK);
371 			}
372 		}
373 	}
374 
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
378 	 * as headphone.
379 	 */
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 |
385 					      SND_JACK_LINEOUT);
386 			snd_soc_jack_report(mbhc->jack,	mbhc->hph_status,
387 					    WCD_MBHC_JACK_MASK);
388 		}
389 	}
390 
391 	mbhc->hph_status |= jack_type;
392 
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);
395 
396 	snd_soc_jack_report(mbhc->jack, (mbhc->hph_status | SND_JACK_MECHANICAL),
397 			    WCD_MBHC_JACK_MASK);
398 }
399 
400 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
401 				 enum snd_jack_types jack_type)
402 {
403 
404 	WARN_ON(!mutex_is_locked(&mbhc->lock));
405 
406 	if (!insertion) /* Report removal */
407 		wcd_mbhc_report_plug_removal(mbhc, jack_type);
408 	else
409 		wcd_mbhc_report_plug_insertion(mbhc, jack_type);
410 
411 }
412 
413 static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
414 				      struct work_struct *work)
415 {
416 	mbhc->hs_detect_work_stop = true;
417 	mutex_unlock(&mbhc->lock);
418 	cancel_work_sync(work);
419 	mutex_lock(&mbhc->lock);
420 }
421 
422 static void wcd_mbhc_cancel_pending_work(struct wcd_mbhc *mbhc)
423 {
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);
428 }
429 
430 static void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc)
431 {
432 	wcd_mbhc_cancel_pending_work(mbhc);
433 	/* Report extension cable */
434 	wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
435 	/*
436 	 * Disable HPHL trigger and MIC Schmitt triggers.
437 	 * Setup for insertion detection.
438 	 */
439 	disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
440 	wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_NONE);
441 	/* Disable HW FSM */
442 	wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
443 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 3);
444 
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);
448 }
449 
450 static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
451 				   enum wcd_mbhc_plug_type plug_type)
452 {
453 	if (mbhc->current_plug == plug_type)
454 		return;
455 
456 	mutex_lock(&mbhc->lock);
457 
458 	switch (plug_type) {
459 	case MBHC_PLUG_TYPE_HEADPHONE:
460 		wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
461 		break;
462 	case MBHC_PLUG_TYPE_HEADSET:
463 		wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET);
464 		break;
465 	case MBHC_PLUG_TYPE_HIGH_HPH:
466 		wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
467 		break;
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);
473 		break;
474 	default:
475 		WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
476 		     mbhc->current_plug, plug_type);
477 		break;
478 	}
479 	mutex_unlock(&mbhc->lock);
480 }
481 
482 static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
483 					    struct work_struct *work)
484 {
485 	WARN_ON(!mutex_is_locked(&mbhc->lock));
486 	mbhc->hs_detect_work_stop = false;
487 	schedule_work(work);
488 }
489 
490 static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc)
491 {
492 	struct snd_soc_component *component = mbhc->component;
493 
494 	WARN_ON(!mutex_is_locked(&mbhc->lock));
495 
496 	if (mbhc->mbhc_cb->hph_pull_down_ctrl)
497 		mbhc->mbhc_cb->hph_pull_down_ctrl(component, false);
498 
499 	wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
500 
501 	if (mbhc->mbhc_cb->mbhc_micbias_control) {
502 		mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2,
503 						    MICB_ENABLE);
504 		wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
505 	}
506 }
507 
508 static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
509 {
510 	struct snd_soc_component *component;
511 	enum snd_jack_types jack_type;
512 	struct wcd_mbhc *mbhc = data;
513 	bool detection_type;
514 
515 	component = mbhc->component;
516 	mutex_lock(&mbhc->lock);
517 
518 	mbhc->in_swch_irq_handler = true;
519 
520 	wcd_mbhc_cancel_pending_work(mbhc);
521 
522 	detection_type = wcd_mbhc_read_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE);
523 
524 	/* Set the detection type appropriately */
525 	wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, !detection_type);
526 
527 	/* Enable micbias ramp */
528 	if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
529 		mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true);
530 
531 	if (detection_type) {
532 		if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
533 			goto exit;
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);
538 	} else {
539 		/* Disable HW FSM */
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;
543 
544 		if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE)
545 			goto exit;
546 
547 		mbhc->is_btn_press = false;
548 		switch (mbhc->current_plug) {
549 		case MBHC_PLUG_TYPE_HEADPHONE:
550 			jack_type = SND_JACK_HEADPHONE;
551 			break;
552 		case MBHC_PLUG_TYPE_HEADSET:
553 			jack_type = SND_JACK_HEADSET;
554 			break;
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;
559 			break;
560 		case MBHC_PLUG_TYPE_GND_MIC_SWAP:
561 			dev_err(mbhc->dev, "Ground and Mic Swapped on plug\n");
562 			goto exit;
563 		default:
564 			dev_err(mbhc->dev, "Invalid current plug: %d\n",
565 				mbhc->current_plug);
566 			goto exit;
567 		}
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);
573 	}
574 
575 exit:
576 	mbhc->in_swch_irq_handler = false;
577 	mutex_unlock(&mbhc->lock);
578 	return IRQ_HANDLED;
579 }
580 
581 static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc)
582 {
583 	int mask = 0;
584 	int btn;
585 
586 	btn = wcd_mbhc_read_field(mbhc, WCD_MBHC_BTN_RESULT);
587 
588 	switch (btn) {
589 	case 0:
590 		mask = SND_JACK_BTN_0;
591 		break;
592 	case 1:
593 		mask = SND_JACK_BTN_1;
594 		break;
595 	case 2:
596 		mask = SND_JACK_BTN_2;
597 		break;
598 	case 3:
599 		mask = SND_JACK_BTN_3;
600 		break;
601 	case 4:
602 		mask = SND_JACK_BTN_4;
603 		break;
604 	case 5:
605 		mask = SND_JACK_BTN_5;
606 		break;
607 	default:
608 		break;
609 	}
610 
611 	return mask;
612 }
613 
614 static void wcd_btn_long_press_fn(struct work_struct *work)
615 {
616 	struct delayed_work *dwork = to_delayed_work(work);
617 	struct wcd_mbhc *mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork);
618 
619 	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
620 		snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
621 				    mbhc->buttons_pressed);
622 }
623 
624 static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
625 {
626 	struct wcd_mbhc *mbhc = data;
627 	int mask;
628 	unsigned long msec_val;
629 
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);
634 
635 	/* Too short, ignore button press */
636 	if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN)
637 		goto done;
638 
639 	/* If switch interrupt already kicked in, ignore button press */
640 	if (mbhc->in_swch_irq_handler)
641 		goto done;
642 
643 	/* Plug isn't headset, ignore button press */
644 	if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET)
645 		goto done;
646 
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");
651 done:
652 	mutex_unlock(&mbhc->lock);
653 	return IRQ_HANDLED;
654 }
655 
656 static irqreturn_t wcd_mbhc_btn_release_handler(int irq, void *data)
657 {
658 	struct wcd_mbhc *mbhc = data;
659 	int ret;
660 
661 	mutex_lock(&mbhc->lock);
662 	if (mbhc->is_btn_press)
663 		mbhc->is_btn_press = false;
664 	else /* fake btn press */
665 		goto exit;
666 
667 	if (!(mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK))
668 		goto exit;
669 
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);
673 	} else {
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);
679 		}
680 	}
681 	mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
682 exit:
683 	mutex_unlock(&mbhc->lock);
684 
685 	return IRQ_HANDLED;
686 }
687 
688 static irqreturn_t wcd_mbhc_hph_ocp_irq(struct wcd_mbhc *mbhc, bool hphr)
689 {
690 
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");
694 
695 	wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 0);
696 	wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 1);
697 
698 	return IRQ_HANDLED;
699 }
700 
701 static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
702 {
703 	return wcd_mbhc_hph_ocp_irq(data, false);
704 }
705 
706 static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
707 {
708 	return wcd_mbhc_hph_ocp_irq(data, true);
709 }
710 
711 static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
712 {
713 	struct snd_soc_component *component = mbhc->component;
714 
715 	mutex_lock(&mbhc->lock);
716 
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);
723 	else
724 		wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
725 
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);
732 
733 	wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
734 
735 	/* Insertion debounce set to 96ms */
736 	wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6);
737 
738 	/* Button Debounce set to 16ms */
739 	wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2);
740 
741 	/* enable bias */
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);
746 
747 	/* program HS_VREF value */
748 	wcd_program_hs_vref(mbhc);
749 
750 	wcd_program_btn_threshold(mbhc, false);
751 
752 	mutex_unlock(&mbhc->lock);
753 
754 	return 0;
755 }
756 
757 static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc)
758 {
759 	int micbias = 0;
760 
761 	if (mbhc->mbhc_cb->get_micbias_val) {
762 		mbhc->mbhc_cb->get_micbias_val(mbhc->component, &micbias);
763 	} else {
764 		u8 vout_ctl = 0;
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
769 		 */
770 		micbias = 1000 + (vout_ctl * 50);
771 	}
772 	return micbias;
773 }
774 
775 static int wcd_get_voltage_from_adc(u8 val, int micbias)
776 {
777 	/* Formula for calculating voltage from ADC
778 	 * Voltage = ADC_RESULT*12.5mV*V_MICBIAS/1.8
779 	 */
780 	return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10));
781 }
782 
783 static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
784 {
785 	u8 adc_result;
786 	int output_mv;
787 	int retry = 3;
788 	u8 adc_en;
789 
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);
807 
808 	while (retry--) {
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);
812 	}
813 
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));
818 
819 	return output_mv;
820 }
821 
822 static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl)
823 {
824 	struct device *dev = mbhc->dev;
825 	u8 adc_timeout = 0;
826 	u8 adc_complete = 0;
827 	u8 adc_result;
828 	int retry = 6;
829 	int ret;
830 	int output_mv = 0;
831 	u8 adc_en;
832 
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);
843 
844 	while (retry--) {
845 		/* wait for 600usec to get adc results */
846 		usleep_range(600, 610);
847 
848 		/* check for ADC Timeout */
849 		adc_timeout = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_TIMEOUT);
850 		if (adc_timeout)
851 			continue;
852 
853 		/* Read ADC complete bit */
854 		adc_complete = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_COMPLETE);
855 		if (!adc_complete)
856 			continue;
857 
858 		/* Read ADC result */
859 		adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
860 
861 		/* Get voltage from ADC result */
862 		output_mv = wcd_get_voltage_from_adc(adc_result,
863 						wcd_mbhc_get_micbias(mbhc));
864 		break;
865 	}
866 
867 	/* Restore ADC Enable */
868 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
869 
870 	if (retry <= 0) {
871 		dev_err(dev, "%s: adc complete: %d, adc timeout: %d\n",
872 			__func__, adc_complete, adc_timeout);
873 		ret = -EINVAL;
874 	} else {
875 		ret = output_mv;
876 	}
877 
878 	return ret;
879 }
880 
881 /* To determine if cross connection occurred */
882 static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
883 {
884 	u8 adc_mode, elect_ctl, adc_en, fsm_en;
885 	int hphl_adc_res, hphr_adc_res;
886 	bool is_cross_conn = false;
887 
888 	/* If PA is enabled, dont check for cross-connection */
889 	if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN))
890 		return -EINVAL;
891 
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);
895 
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);
902 
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)
906 		return hphl_adc_res;
907 
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)
911 		return hphr_adc_res;
912 
913 	if (hphl_adc_res > HPHL_CROSS_CONN_THRESHOLD ||
914 	    hphr_adc_res > HPHL_CROSS_CONN_THRESHOLD)
915 		is_cross_conn = true;
916 
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);
929 
930 	return is_cross_conn;
931 }
932 
933 static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc)
934 {
935 	int hs_threshold, micbias_mv;
936 
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;
941 		else
942 			hs_threshold = (mbhc->cfg->hs_thr *
943 				micbias_mv) / mbhc->cfg->micb_mv;
944 	} else {
945 		hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
946 			micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
947 	}
948 	return hs_threshold;
949 }
950 
951 static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc)
952 {
953 	int hph_threshold, micbias_mv;
954 
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;
959 		else
960 			hph_threshold = (mbhc->cfg->hph_thr *
961 				micbias_mv) / mbhc->cfg->micb_mv;
962 	} else {
963 		hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV *
964 			micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
965 	}
966 	return hph_threshold;
967 }
968 
969 static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc,
970 					   enum wcd_mbhc_plug_type plug_type)
971 {
972 	bool micbias2 = false;
973 
974 	switch (plug_type) {
975 	case MBHC_PLUG_TYPE_HEADPHONE:
976 		wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
977 		break;
978 	case MBHC_PLUG_TYPE_HEADSET:
979 		if (mbhc->mbhc_cb->micbias_enable_status)
980 			micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc->component,
981 									MIC_BIAS_2);
982 
983 		if (!mbhc->is_hs_recording && !micbias2)
984 			wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
985 		break;
986 	default:
987 		wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
988 		break;
989 
990 	}
991 }
992 
993 static void wcd_mbhc_bcs_enable(struct wcd_mbhc *mbhc, int plug_type, bool enable)
994 {
995 	switch (plug_type) {
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);
1000 		break;
1001 	default:
1002 		break;
1003 	}
1004 }
1005 
1006 static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result)
1007 
1008 {
1009 	enum wcd_mbhc_plug_type plug_type;
1010 	u32 hph_thr, hs_thr;
1011 
1012 	hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc);
1013 	hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc);
1014 
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;
1019 	else
1020 		plug_type = MBHC_PLUG_TYPE_HEADSET;
1021 
1022 	return plug_type;
1023 }
1024 
1025 static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc)
1026 {
1027 	int hs_threshold, micbias_mv;
1028 
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;
1033 		else
1034 			hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv;
1035 	} else {
1036 		hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * micbias_mv) /
1037 							WCD_MBHC_ADC_MICBIAS_MV);
1038 	}
1039 	return hs_threshold;
1040 }
1041 
1042 static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc)
1043 {
1044 	bool is_spl_hs = false;
1045 	int output_mv, hs_threshold, hph_threshold;
1046 
1047 	if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
1048 		return false;
1049 
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);
1053 
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);
1057 
1058 	if (!(output_mv > hs_threshold || output_mv < hph_threshold))
1059 		is_spl_hs = true;
1060 
1061 	/* Back MIC_BIAS2 to 1.8v if the type is not special headset */
1062 	if (!is_spl_hs) {
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);
1066 	}
1067 
1068 	return is_spl_hs;
1069 }
1070 
1071 static void wcd_correct_swch_plug(struct work_struct *work)
1072 {
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;
1080 	bool is_pa_on;
1081 
1082 	mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
1083 	component = mbhc->component;
1084 
1085 	micbias_mv = wcd_mbhc_get_micbias(mbhc);
1086 	hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1087 
1088 	/* Mask ADC COMPLETE interrupt */
1089 	disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1090 
1091 	/* Check for cross connection */
1092 	do {
1093 		cross_conn = wcd_check_cross_conn(mbhc);
1094 		try++;
1095 	} while (try < GND_MIC_SWAP_THRESHOLD);
1096 
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",
1100 			plug_type);
1101 		goto correct_plug_type;
1102 	}
1103 
1104 	/* Find plug type */
1105 	output_mv = wcd_measure_adc_continuous(mbhc);
1106 	plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1107 
1108 	/*
1109 	 * Report plug type if it is either headset or headphone
1110 	 * else start the 3 sec loop
1111 	 */
1112 	switch (plug_type) {
1113 	case MBHC_PLUG_TYPE_HEADPHONE:
1114 		wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1115 		break;
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);
1121 		break;
1122 	default:
1123 		break;
1124 	}
1125 
1126 correct_plug_type:
1127 
1128 	/* Disable BCS slow insertion detection */
1129 	wcd_mbhc_bcs_enable(mbhc, plug_type, false);
1130 
1131 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
1132 
1133 	while (!time_after(jiffies, timeout)) {
1134 		if (mbhc->hs_detect_work_stop) {
1135 			wcd_micbias_disable(mbhc);
1136 			goto exit;
1137 		}
1138 
1139 		msleep(180);
1140 		/*
1141 		 * Use ADC single mode to minimize the chance of missing out
1142 		 * btn press/release for HEADSET type during correct work.
1143 		 */
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);
1147 
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);
1151 
1152 			if (is_spl_hs) {
1153 				hs_threshold *= wcd_mbhc_get_micbias(mbhc);
1154 				hs_threshold /= micbias_mv;
1155 			}
1156 		}
1157 
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)
1164 					continue;
1165 				else
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);
1170 				continue;
1171 			} else if (cross_conn < 0) /* Error */
1172 				continue;
1173 
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))
1178 						continue;
1179 				}
1180 			}
1181 		}
1182 
1183 		/* cable is extension cable */
1184 		if (output_mv > hs_threshold || mbhc->force_linein)
1185 			plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1186 	}
1187 
1188 	wcd_mbhc_bcs_enable(mbhc, plug_type, true);
1189 
1190 	if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
1191 		if (is_spl_hs)
1192 			plug_type = MBHC_PLUG_TYPE_HEADSET;
1193 		else
1194 			wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1);
1195 	}
1196 
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);
1200 
1201 	/*
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.
1205 	 */
1206 	if (plug_type == MBHC_PLUG_TYPE_HEADSET)
1207 		wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1208 	else
1209 		wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1210 
1211 	if (mbhc->mbhc_cb->mbhc_micbias_control)
1212 		wcd_mbhc_adc_update_fsm_source(mbhc, plug_type);
1213 
1214 exit:
1215 	if (mbhc->mbhc_cb->mbhc_micbias_control/* &&  !mbhc->micbias_enable*/)
1216 		mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
1217 
1218 	/*
1219 	 * If plug type is corrected from special headset to headphone,
1220 	 * clear the micbias enable flag, set micbias back to 1.8V and
1221 	 * disable micbias.
1222 	 */
1223 	if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
1224 		wcd_micbias_disable(mbhc);
1225 		/*
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.
1229 		 */
1230 		enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
1231 	}
1232 
1233 	if (mbhc->mbhc_cb->hph_pull_down_ctrl)
1234 		mbhc->mbhc_cb->hph_pull_down_ctrl(component, true);
1235 }
1236 
1237 static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data)
1238 {
1239 	struct wcd_mbhc *mbhc = data;
1240 	unsigned long timeout;
1241 	int adc_threshold, output_mv, retry = 0;
1242 
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);
1246 
1247 	do {
1248 		retry++;
1249 		/*
1250 		 * read output_mv every 10ms to look for
1251 		 * any change in IN2_P
1252 		 */
1253 		usleep_range(10000, 10100);
1254 		output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1255 
1256 		/* Check for fake removal */
1257 		if ((output_mv <= adc_threshold) && retry > FAKE_REM_RETRY_ATTEMPTS)
1258 			goto exit;
1259 	} while (!time_after(jiffies, timeout));
1260 
1261 	/*
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.
1265 	 */
1266 	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
1267 		mbhc->extn_cable_hph_rem = true;
1268 
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);
1274 
1275 exit:
1276 	mutex_unlock(&mbhc->lock);
1277 	return IRQ_HANDLED;
1278 }
1279 
1280 static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data)
1281 {
1282 	struct wcd_mbhc *mbhc = data;
1283 	u8 clamp_state = 0;
1284 	u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY;
1285 
1286 	/*
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.
1290 	 */
1291 	if (mbhc->extn_cable_hph_rem == true) {
1292 		mbhc->extn_cable_hph_rem = false;
1293 		return IRQ_HANDLED;
1294 	}
1295 
1296 	do {
1297 		clamp_state = wcd_mbhc_read_field(mbhc, WCD_MBHC_IN2P_CLAMP_STATE);
1298 		if (clamp_state)
1299 			return IRQ_HANDLED;
1300 		/*
1301 		 * check clamp for 120ms but at 30ms chunks to leave
1302 		 * room for other interrupts to be processed
1303 		 */
1304 		usleep_range(30000, 30100);
1305 	} while (--clamp_retry);
1306 
1307 	/*
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.
1311 	 */
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);
1316 		return IRQ_HANDLED;
1317 	}
1318 
1319 	return IRQ_HANDLED;
1320 }
1321 
1322 int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,	uint32_t *zr)
1323 {
1324 	*zl = mbhc->zl;
1325 	*zr = mbhc->zr;
1326 
1327 	if (*zl && *zr)
1328 		return 0;
1329 	else
1330 		return -EINVAL;
1331 }
1332 EXPORT_SYMBOL(wcd_mbhc_get_impedance);
1333 
1334 void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type)
1335 {
1336 	mbhc->hph_type = hph_type;
1337 }
1338 EXPORT_SYMBOL(wcd_mbhc_set_hph_type);
1339 
1340 int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc)
1341 {
1342 	return mbhc->hph_type;
1343 }
1344 EXPORT_SYMBOL(wcd_mbhc_get_hph_type);
1345 
1346 int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *cfg,
1347 		   struct snd_soc_jack *jack)
1348 {
1349 	if (!mbhc || !cfg || !jack)
1350 		return -EINVAL;
1351 
1352 	mbhc->cfg = cfg;
1353 	mbhc->jack = jack;
1354 
1355 	return wcd_mbhc_initialise(mbhc);
1356 }
1357 EXPORT_SYMBOL(wcd_mbhc_start);
1358 
1359 void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
1360 {
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);
1365 }
1366 EXPORT_SYMBOL(wcd_mbhc_stop);
1367 
1368 int wcd_dt_parse_mbhc_data(struct device *dev, struct wcd_mbhc_config *cfg)
1369 {
1370 	struct device_node *np = dev->of_node;
1371 	int ret, i, microvolt;
1372 
1373 	if (of_property_read_bool(np, "qcom,hphl-jack-type-normally-closed"))
1374 		cfg->hphl_swh = false;
1375 	else
1376 		cfg->hphl_swh = true;
1377 
1378 	if (of_property_read_bool(np, "qcom,ground-jack-type-normally-closed"))
1379 		cfg->gnd_swh = false;
1380 	else
1381 		cfg->gnd_swh = true;
1382 
1383 	ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt",
1384 				   &microvolt);
1385 	if (ret)
1386 		dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n");
1387 	else
1388 		cfg->hs_thr = microvolt/1000;
1389 
1390 	ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt",
1391 				   &microvolt);
1392 	if (ret)
1393 		dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt	entry\n");
1394 	else
1395 		cfg->hph_thr = microvolt/1000;
1396 
1397 	ret = of_property_read_u32_array(np,
1398 					 "qcom,mbhc-buttons-vthreshold-microvolt",
1399 					 &cfg->btn_high[0],
1400 					 WCD_MBHC_DEF_BUTTONS);
1401 	if (ret)
1402 		dev_err(dev, "missing qcom,mbhc-buttons-vthreshold-microvolt entry\n");
1403 
1404 	for (i = 0; i < WCD_MBHC_DEF_BUTTONS; i++) {
1405 		if (ret) /* default voltage */
1406 			cfg->btn_high[i] = 500000;
1407 		else
1408 			/* Micro to Milli Volts */
1409 			cfg->btn_high[i] = cfg->btn_high[i]/1000;
1410 	}
1411 
1412 	return 0;
1413 }
1414 EXPORT_SYMBOL(wcd_dt_parse_mbhc_data);
1415 
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)
1421 {
1422 	struct device *dev = component->dev;
1423 	struct wcd_mbhc *mbhc;
1424 	int ret;
1425 
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);
1429 	}
1430 
1431 	mbhc = devm_kzalloc(dev, sizeof(*mbhc), GFP_KERNEL);
1432 	if (!mbhc)
1433 		return ERR_PTR(-ENOMEM);
1434 
1435 	mbhc->component = component;
1436 	mbhc->dev = dev;
1437 	mbhc->intr_ids = intr_ids;
1438 	mbhc->mbhc_cb = mbhc_cb;
1439 	mbhc->fields = fields;
1440 	mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
1441 
1442 	if (mbhc_cb->compute_impedance)
1443 		mbhc->impedance_detect = impedance_det_en;
1444 
1445 	INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_long_press_fn);
1446 
1447 	mutex_init(&mbhc->lock);
1448 
1449 	INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
1450 
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);
1455 	if (ret)
1456 		goto err;
1457 
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);
1462 	if (ret)
1463 		goto err;
1464 
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);
1469 	if (ret)
1470 		goto err;
1471 
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);
1476 	if (ret)
1477 		goto err;
1478 
1479 	disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1480 
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);
1485 	if (ret)
1486 		goto err;
1487 
1488 	disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
1489 
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);
1494 	if (ret)
1495 		goto err;
1496 
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);
1501 	if (ret)
1502 		goto err;
1503 
1504 	return mbhc;
1505 err:
1506 	dev_err(dev, "Failed to request mbhc interrupts %d\n", ret);
1507 
1508 	return ERR_PTR(ret);
1509 }
1510 EXPORT_SYMBOL(wcd_mbhc_init);
1511 
1512 void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
1513 {
1514 	mutex_lock(&mbhc->lock);
1515 	wcd_cancel_hs_detect_plug(mbhc,	&mbhc->correct_plug_swch);
1516 	mutex_unlock(&mbhc->lock);
1517 }
1518 EXPORT_SYMBOL(wcd_mbhc_deinit);
1519 
1520 static int __init mbhc_init(void)
1521 {
1522 	return 0;
1523 }
1524 
1525 static void __exit mbhc_exit(void)
1526 {
1527 }
1528 
1529 module_init(mbhc_init);
1530 module_exit(mbhc_exit);
1531 
1532 MODULE_DESCRIPTION("wcd MBHC v2 module");
1533 MODULE_LICENSE("GPL");
1534