xref: /linux/sound/soc/codecs/wcd-mbhc-v2.c (revision 6af91e3d2cfc8bb579b1aa2d22cd91f8c34acdf6)
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/pm_runtime.h>
9 #include <linux/printk.h>
10 #include <linux/delay.h>
11 #include <linux/kernel.h>
12 #include <sound/soc.h>
13 #include <sound/jack.h>
14 #include "wcd-mbhc-v2.h"
15 
16 #define HS_DETECT_PLUG_TIME_MS		(3 * 1000)
17 #define MBHC_BUTTON_PRESS_THRESHOLD_MIN	250
18 #define GND_MIC_SWAP_THRESHOLD		4
19 #define GND_MIC_USBC_SWAP_THRESHOLD	2
20 #define WCD_FAKE_REMOVAL_MIN_PERIOD_MS	100
21 #define HPHL_CROSS_CONN_THRESHOLD	100
22 #define HS_VREF_MIN_VAL			1400
23 #define FAKE_REM_RETRY_ATTEMPTS		3
24 #define WCD_MBHC_ADC_HS_THRESHOLD_MV	1700
25 #define WCD_MBHC_ADC_HPH_THRESHOLD_MV	75
26 #define WCD_MBHC_ADC_MICBIAS_MV		1800
27 #define WCD_MBHC_FAKE_INS_RETRY		4
28 
29 #define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | \
30 			   SND_JACK_MECHANICAL)
31 
32 #define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
33 				  SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
34 				  SND_JACK_BTN_4 | SND_JACK_BTN_5)
35 
36 enum wcd_mbhc_adc_mux_ctl {
37 	MUX_CTL_AUTO = 0,
38 	MUX_CTL_IN2P,
39 	MUX_CTL_IN3P,
40 	MUX_CTL_IN4P,
41 	MUX_CTL_HPH_L,
42 	MUX_CTL_HPH_R,
43 	MUX_CTL_NONE,
44 };
45 
46 struct wcd_mbhc {
47 	struct device *dev;
48 	struct snd_soc_component *component;
49 	struct snd_soc_jack *jack;
50 	struct wcd_mbhc_config *cfg;
51 	const struct wcd_mbhc_cb *mbhc_cb;
52 	const struct wcd_mbhc_intr *intr_ids;
53 	const struct wcd_mbhc_field *fields;
54 	/* Delayed work to report long button press */
55 	struct delayed_work mbhc_btn_dwork;
56 	/* Work to handle plug report */
57 	struct work_struct mbhc_plug_detect_work;
58 	/* Work to correct accessory type */
59 	struct work_struct correct_plug_swch;
60 	struct mutex lock;
61 	int buttons_pressed;
62 	u32 hph_status; /* track headhpone status */
63 	u8 current_plug;
64 	unsigned int swap_thr;
65 	bool is_btn_press;
66 	bool in_swch_irq_handler;
67 	bool hs_detect_work_stop;
68 	bool is_hs_recording;
69 	bool extn_cable_hph_rem;
70 	bool force_linein;
71 	bool impedance_detect;
72 	unsigned long event_state;
73 	unsigned long jiffies_atreport;
74 	/* impedance of hphl and hphr */
75 	uint32_t zl, zr;
76 	/* Holds type of Headset - Mono/Stereo */
77 	enum wcd_mbhc_hph_type hph_type;
78 	/* Holds mbhc detection method - ADC/Legacy */
79 	int mbhc_detection_logic;
80 };
81 
82 static inline int wcd_mbhc_write_field(const struct wcd_mbhc *mbhc,
83 				       int field, int val)
84 {
85 	if (!mbhc->fields[field].reg)
86 		return 0;
87 
88 	return snd_soc_component_write_field(mbhc->component,
89 					     mbhc->fields[field].reg,
90 					     mbhc->fields[field].mask, val);
91 }
92 
93 static inline int wcd_mbhc_read_field(const struct wcd_mbhc *mbhc, int field)
94 {
95 	if (!mbhc->fields[field].reg)
96 		return 0;
97 
98 	return snd_soc_component_read_field(mbhc->component,
99 					    mbhc->fields[field].reg,
100 					    mbhc->fields[field].mask);
101 }
102 
103 static void wcd_program_hs_vref(struct wcd_mbhc *mbhc)
104 {
105 	u32 reg_val = ((mbhc->cfg->v_hs_max - HS_VREF_MIN_VAL) / 100);
106 
107 	wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_VREF, reg_val);
108 }
109 
110 static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias)
111 {
112 	struct snd_soc_component *component = mbhc->component;
113 
114 	mbhc->mbhc_cb->set_btn_thr(component, mbhc->cfg->btn_low,
115 				   mbhc->cfg->btn_high,
116 				   mbhc->cfg->num_btn, micbias);
117 }
118 
119 static void wcd_mbhc_curr_micbias_control(const struct wcd_mbhc *mbhc,
120 					  const enum wcd_mbhc_cs_mb_en_flag cs_mb_en)
121 {
122 
123 	/*
124 	 * Some codecs handle micbias/pullup enablement in codec
125 	 * drivers itself and micbias is not needed for regular
126 	 * plug type detection. So if micbias_control callback function
127 	 * is defined, just return.
128 	 */
129 	if (mbhc->mbhc_cb->mbhc_micbias_control)
130 		return;
131 
132 	switch (cs_mb_en) {
133 	case WCD_MBHC_EN_CS:
134 		wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
135 		wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
136 		/* Program Button threshold registers as per CS */
137 		wcd_program_btn_threshold(mbhc, false);
138 		break;
139 	case WCD_MBHC_EN_MB:
140 		wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
141 		wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
142 		/* Disable PULL_UP_EN & enable MICBIAS */
143 		wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 2);
144 		/* Program Button threshold registers as per MICBIAS */
145 		wcd_program_btn_threshold(mbhc, true);
146 		break;
147 	case WCD_MBHC_EN_PULLUP:
148 		wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
149 		wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
150 		wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 1);
151 		/* Program Button threshold registers as per MICBIAS */
152 		wcd_program_btn_threshold(mbhc, true);
153 		break;
154 	case WCD_MBHC_EN_NONE:
155 		wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
156 		wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
157 		wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
158 		break;
159 	default:
160 		dev_err(mbhc->dev, "%s: Invalid parameter", __func__);
161 		break;
162 	}
163 }
164 
165 int wcd_mbhc_event_notify(struct wcd_mbhc *mbhc, unsigned long event)
166 {
167 
168 	struct snd_soc_component *component;
169 	bool micbias2 = false;
170 
171 	if (!mbhc)
172 		return 0;
173 
174 	component = mbhc->component;
175 
176 	if (mbhc->mbhc_cb->micbias_enable_status)
177 		micbias2 = mbhc->mbhc_cb->micbias_enable_status(component, MIC_BIAS_2);
178 
179 	switch (event) {
180 	/* MICBIAS usage change */
181 	case WCD_EVENT_POST_DAPM_MICBIAS_2_ON:
182 		mbhc->is_hs_recording = true;
183 		break;
184 	case WCD_EVENT_POST_MICBIAS_2_ON:
185 		/* Disable current source if micbias2 enabled */
186 		if (mbhc->mbhc_cb->mbhc_micbias_control) {
187 			if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
188 				wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
189 		} else {
190 			mbhc->is_hs_recording = true;
191 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
192 		}
193 		break;
194 	case WCD_EVENT_PRE_MICBIAS_2_OFF:
195 		/*
196 		 * Before MICBIAS_2 is turned off, if FSM is enabled,
197 		 * make sure current source is enabled so as to detect
198 		 * button press/release events
199 		 */
200 		if (mbhc->mbhc_cb->mbhc_micbias_control/* && !mbhc->micbias_enable*/) {
201 			if (wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN))
202 				wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
203 		}
204 		break;
205 	/* MICBIAS usage change */
206 	case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF:
207 		mbhc->is_hs_recording = false;
208 		break;
209 	case WCD_EVENT_POST_MICBIAS_2_OFF:
210 		if (!mbhc->mbhc_cb->mbhc_micbias_control)
211 			mbhc->is_hs_recording = false;
212 
213 		/* Enable PULL UP if PA's are enabled */
214 		if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) ||
215 		    (test_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state)))
216 			/* enable pullup and cs, disable mb */
217 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
218 		else
219 			/* enable current source and disable mb, pullup*/
220 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
221 
222 		break;
223 	case WCD_EVENT_POST_HPHL_PA_OFF:
224 		clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
225 
226 		/* check if micbias is enabled */
227 		if (micbias2)
228 			/* Disable cs, pullup & enable micbias */
229 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
230 		else
231 			/* Disable micbias, pullup & enable cs */
232 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
233 		break;
234 	case WCD_EVENT_POST_HPHR_PA_OFF:
235 		clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
236 		/* check if micbias is enabled */
237 		if (micbias2)
238 			/* Disable cs, pullup & enable micbias */
239 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
240 		else
241 			/* Disable micbias, pullup & enable cs */
242 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_CS);
243 		break;
244 	case WCD_EVENT_PRE_HPHL_PA_ON:
245 		set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
246 		/* check if micbias is enabled */
247 		if (micbias2)
248 			/* Disable cs, pullup & enable micbias */
249 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
250 		else
251 			/* Disable micbias, enable pullup & cs */
252 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
253 		break;
254 	case WCD_EVENT_PRE_HPHR_PA_ON:
255 		set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
256 		/* check if micbias is enabled */
257 		if (micbias2)
258 			/* Disable cs, pullup & enable micbias */
259 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_MB);
260 		else
261 			/* Disable micbias, enable pullup & cs */
262 			wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_PULLUP);
263 		break;
264 	default:
265 		break;
266 	}
267 	return 0;
268 }
269 EXPORT_SYMBOL_GPL(wcd_mbhc_event_notify);
270 
271 static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc)
272 {
273 	return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
274 }
275 
276 static void wcd_micbias_disable(struct wcd_mbhc *mbhc)
277 {
278 	struct snd_soc_component *component = mbhc->component;
279 
280 	if (mbhc->mbhc_cb->mbhc_micbias_control)
281 		mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
282 
283 	if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
284 		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2, false);
285 
286 	if (mbhc->mbhc_cb->set_micbias_value) {
287 		mbhc->mbhc_cb->set_micbias_value(component);
288 		wcd_mbhc_write_field(mbhc, WCD_MBHC_MICB_CTRL, 0);
289 	}
290 }
291 
292 static void wcd_mbhc_report_plug_removal(struct wcd_mbhc *mbhc,
293 					 enum snd_jack_types jack_type)
294 {
295 	mbhc->hph_status &= ~jack_type;
296 	/*
297 	 * cancel possibly scheduled btn work and
298 	 * report release if we reported button press
299 	 */
300 	if (!wcd_cancel_btn_work(mbhc) && mbhc->buttons_pressed) {
301 		snd_soc_jack_report(mbhc->jack, 0, mbhc->buttons_pressed);
302 		mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
303 	}
304 
305 	wcd_micbias_disable(mbhc);
306 	mbhc->hph_type = WCD_MBHC_HPH_NONE;
307 	mbhc->zl = mbhc->zr = 0;
308 	snd_soc_jack_report(mbhc->jack, mbhc->hph_status, WCD_MBHC_JACK_MASK);
309 	mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
310 	mbhc->force_linein = false;
311 }
312 
313 static void wcd_mbhc_compute_impedance(struct wcd_mbhc *mbhc)
314 {
315 
316 	if (!mbhc->impedance_detect)
317 		return;
318 
319 	if (mbhc->cfg->linein_th != 0) {
320 		u8 fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
321 		/* Set MUX_CTL to AUTO for Z-det */
322 
323 		wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
324 		wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
325 		wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
326 		mbhc->mbhc_cb->compute_impedance(mbhc->component, &mbhc->zl, &mbhc->zr);
327 		wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
328 	}
329 }
330 
331 static void wcd_mbhc_report_plug_insertion(struct wcd_mbhc *mbhc,
332 					   enum snd_jack_types jack_type)
333 {
334 	bool is_pa_on;
335 	/*
336 	 * Report removal of current jack type.
337 	 * Headphone to headset shouldn't report headphone
338 	 * removal.
339 	 */
340 	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
341 	    jack_type == SND_JACK_HEADPHONE)
342 		mbhc->hph_status &= ~SND_JACK_HEADSET;
343 
344 	/* Report insertion */
345 	switch (jack_type) {
346 	case SND_JACK_HEADPHONE:
347 		mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
348 		break;
349 	case SND_JACK_HEADSET:
350 		mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
351 		mbhc->jiffies_atreport = jiffies;
352 		break;
353 	case SND_JACK_LINEOUT:
354 		mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
355 		break;
356 	default:
357 		break;
358 	}
359 
360 
361 	is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
362 
363 	if (!is_pa_on) {
364 		wcd_mbhc_compute_impedance(mbhc);
365 		if ((mbhc->zl > mbhc->cfg->linein_th) &&
366 		    (mbhc->zr > mbhc->cfg->linein_th) &&
367 		    (jack_type == SND_JACK_HEADPHONE)) {
368 			jack_type = SND_JACK_LINEOUT;
369 			mbhc->force_linein = true;
370 			mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
371 			if (mbhc->hph_status) {
372 				mbhc->hph_status &= ~(SND_JACK_HEADSET |
373 						      SND_JACK_LINEOUT);
374 				snd_soc_jack_report(mbhc->jack,	mbhc->hph_status,
375 						    WCD_MBHC_JACK_MASK);
376 			}
377 		}
378 	}
379 
380 	/* Do not calculate impedance again for lineout
381 	 * as during playback pa is on and impedance values
382 	 * will not be correct resulting in lineout detected
383 	 * as headphone.
384 	 */
385 	if (is_pa_on && mbhc->force_linein) {
386 		jack_type = SND_JACK_LINEOUT;
387 		mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
388 		if (mbhc->hph_status) {
389 			mbhc->hph_status &= ~(SND_JACK_HEADSET |
390 					      SND_JACK_LINEOUT);
391 			snd_soc_jack_report(mbhc->jack,	mbhc->hph_status,
392 					    WCD_MBHC_JACK_MASK);
393 		}
394 	}
395 
396 	mbhc->hph_status |= jack_type;
397 
398 	if (jack_type == SND_JACK_HEADPHONE && mbhc->mbhc_cb->mbhc_micb_ramp_control)
399 		mbhc->mbhc_cb->mbhc_micb_ramp_control(mbhc->component, false);
400 
401 	snd_soc_jack_report(mbhc->jack, (mbhc->hph_status | SND_JACK_MECHANICAL),
402 			    WCD_MBHC_JACK_MASK);
403 }
404 
405 static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
406 				 enum snd_jack_types jack_type)
407 {
408 
409 	WARN_ON(!mutex_is_locked(&mbhc->lock));
410 
411 	if (!insertion) /* Report removal */
412 		wcd_mbhc_report_plug_removal(mbhc, jack_type);
413 	else
414 		wcd_mbhc_report_plug_insertion(mbhc, jack_type);
415 
416 }
417 
418 static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
419 				      struct work_struct *work)
420 {
421 	mbhc->hs_detect_work_stop = true;
422 	mutex_unlock(&mbhc->lock);
423 	cancel_work_sync(work);
424 	mutex_lock(&mbhc->lock);
425 }
426 
427 static void wcd_mbhc_cancel_pending_work(struct wcd_mbhc *mbhc)
428 {
429 	/* cancel pending button press */
430 	wcd_cancel_btn_work(mbhc);
431 	/* cancel correct work function */
432 	wcd_cancel_hs_detect_plug(mbhc,	&mbhc->correct_plug_swch);
433 }
434 
435 static void wcd_mbhc_elec_hs_report_unplug(struct wcd_mbhc *mbhc)
436 {
437 	wcd_mbhc_cancel_pending_work(mbhc);
438 	/* Report extension cable */
439 	wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
440 	/*
441 	 * Disable HPHL trigger and MIC Schmitt triggers.
442 	 * Setup for insertion detection.
443 	 */
444 	disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
445 	wcd_mbhc_curr_micbias_control(mbhc, WCD_MBHC_EN_NONE);
446 	/* Disable HW FSM */
447 	wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
448 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 3);
449 
450 	/* Set the detection type appropriately */
451 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
452 	enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
453 }
454 
455 static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
456 				   enum wcd_mbhc_plug_type plug_type)
457 {
458 	if (mbhc->current_plug == plug_type)
459 		return;
460 
461 	mutex_lock(&mbhc->lock);
462 
463 	switch (plug_type) {
464 	case MBHC_PLUG_TYPE_HEADPHONE:
465 		wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
466 		break;
467 	case MBHC_PLUG_TYPE_HEADSET:
468 		wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADSET);
469 		break;
470 	case MBHC_PLUG_TYPE_HIGH_HPH:
471 		wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
472 		break;
473 	case MBHC_PLUG_TYPE_GND_MIC_SWAP:
474 		if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
475 			wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
476 		if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
477 			wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
478 		break;
479 	default:
480 		WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
481 		     mbhc->current_plug, plug_type);
482 		break;
483 	}
484 	mutex_unlock(&mbhc->lock);
485 }
486 
487 static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
488 					    struct work_struct *work)
489 {
490 	WARN_ON(!mutex_is_locked(&mbhc->lock));
491 	mbhc->hs_detect_work_stop = false;
492 	schedule_work(work);
493 }
494 
495 static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc)
496 {
497 	struct snd_soc_component *component = mbhc->component;
498 
499 	WARN_ON(!mutex_is_locked(&mbhc->lock));
500 
501 	if (mbhc->mbhc_cb->hph_pull_down_ctrl)
502 		mbhc->mbhc_cb->hph_pull_down_ctrl(component, false);
503 
504 	wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
505 
506 	if (mbhc->mbhc_cb->mbhc_micbias_control) {
507 		mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2,
508 						    MICB_ENABLE);
509 		wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
510 	}
511 }
512 
513 static void mbhc_plug_detect_fn(struct work_struct *work)
514 {
515 	struct wcd_mbhc *mbhc = container_of(work, struct wcd_mbhc, mbhc_plug_detect_work);
516 	struct snd_soc_component *component = mbhc->component;
517 	enum snd_jack_types jack_type;
518 	bool detection_type;
519 
520 	mutex_lock(&mbhc->lock);
521 
522 	mbhc->in_swch_irq_handler = true;
523 
524 	wcd_mbhc_cancel_pending_work(mbhc);
525 
526 	detection_type = wcd_mbhc_read_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE);
527 
528 	/* Set the detection type appropriately */
529 	wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, !detection_type);
530 
531 	/* Enable micbias ramp */
532 	if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
533 		mbhc->mbhc_cb->mbhc_micb_ramp_control(component, true);
534 
535 	if (detection_type) {
536 		if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
537 			goto exit;
538 		/* Make sure MASTER_BIAS_CTL is enabled */
539 		mbhc->mbhc_cb->mbhc_bias(component, true);
540 		mbhc->is_btn_press = false;
541 		wcd_mbhc_adc_detect_plug_type(mbhc);
542 	} else {
543 		/* Disable HW FSM */
544 		wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
545 		wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
546 		mbhc->extn_cable_hph_rem = false;
547 
548 		if (mbhc->current_plug == MBHC_PLUG_TYPE_NONE)
549 			goto exit;
550 
551 		mbhc->is_btn_press = false;
552 		switch (mbhc->current_plug) {
553 		case MBHC_PLUG_TYPE_HEADPHONE:
554 			jack_type = SND_JACK_HEADPHONE;
555 			break;
556 		case MBHC_PLUG_TYPE_HEADSET:
557 			jack_type = SND_JACK_HEADSET;
558 			break;
559 		case MBHC_PLUG_TYPE_HIGH_HPH:
560 			if (mbhc->mbhc_detection_logic == WCD_DETECTION_ADC)
561 				wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 0);
562 			jack_type = SND_JACK_LINEOUT;
563 			break;
564 		case MBHC_PLUG_TYPE_GND_MIC_SWAP:
565 			dev_err(mbhc->dev, "Ground and Mic Swapped on plug\n");
566 			goto exit;
567 		default:
568 			dev_err(mbhc->dev, "Invalid current plug: %d\n",
569 				mbhc->current_plug);
570 			goto exit;
571 		}
572 		disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
573 		disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
574 		wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_DETECTION_TYPE, 1);
575 		wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
576 		wcd_mbhc_report_plug(mbhc, 0, jack_type);
577 	}
578 
579 exit:
580 	mbhc->in_swch_irq_handler = false;
581 	mutex_unlock(&mbhc->lock);
582 }
583 
584 static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
585 {
586 	struct wcd_mbhc *mbhc = data;
587 
588 	if (!mbhc->cfg->typec_analog_mux)
589 		schedule_work(&mbhc->mbhc_plug_detect_work);
590 
591 	return IRQ_HANDLED;
592 }
593 
594 int wcd_mbhc_typec_report_unplug(struct wcd_mbhc *mbhc)
595 {
596 
597 	if (!mbhc || !mbhc->cfg->typec_analog_mux)
598 		return -EINVAL;
599 
600 	if (mbhc->mbhc_cb->clk_setup)
601 		mbhc->mbhc_cb->clk_setup(mbhc->component, false);
602 
603 	wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0);
604 	wcd_mbhc_write_field(mbhc, WCD_MBHC_MECH_DETECTION_TYPE, 0);
605 
606 	schedule_work(&mbhc->mbhc_plug_detect_work);
607 
608 	return 0;
609 }
610 EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_unplug);
611 
612 int wcd_mbhc_typec_report_plug(struct wcd_mbhc *mbhc)
613 {
614 	if (!mbhc || !mbhc->cfg->typec_analog_mux)
615 		return -EINVAL;
616 
617 	if (mbhc->mbhc_cb->clk_setup)
618 		mbhc->mbhc_cb->clk_setup(mbhc->component, true);
619 	wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
620 
621 	schedule_work(&mbhc->mbhc_plug_detect_work);
622 
623 	return 0;
624 }
625 EXPORT_SYMBOL_GPL(wcd_mbhc_typec_report_plug);
626 
627 static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc)
628 {
629 	int mask = 0;
630 	int btn;
631 
632 	btn = wcd_mbhc_read_field(mbhc, WCD_MBHC_BTN_RESULT);
633 
634 	switch (btn) {
635 	case 0:
636 		mask = SND_JACK_BTN_0;
637 		break;
638 	case 1:
639 		mask = SND_JACK_BTN_1;
640 		break;
641 	case 2:
642 		mask = SND_JACK_BTN_2;
643 		break;
644 	case 3:
645 		mask = SND_JACK_BTN_3;
646 		break;
647 	case 4:
648 		mask = SND_JACK_BTN_4;
649 		break;
650 	case 5:
651 		mask = SND_JACK_BTN_5;
652 		break;
653 	default:
654 		break;
655 	}
656 
657 	return mask;
658 }
659 
660 static void wcd_btn_long_press_fn(struct work_struct *work)
661 {
662 	struct delayed_work *dwork = to_delayed_work(work);
663 	struct wcd_mbhc *mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork);
664 
665 	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
666 		snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
667 				    mbhc->buttons_pressed);
668 }
669 
670 static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
671 {
672 	struct wcd_mbhc *mbhc = data;
673 	int mask;
674 	unsigned long msec_val;
675 
676 	mutex_lock(&mbhc->lock);
677 	wcd_cancel_btn_work(mbhc);
678 	mbhc->is_btn_press = true;
679 	msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
680 
681 	/* Too short, ignore button press */
682 	if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN)
683 		goto done;
684 
685 	/* If switch interrupt already kicked in, ignore button press */
686 	if (mbhc->in_swch_irq_handler)
687 		goto done;
688 
689 	/* Plug isn't headset, ignore button press */
690 	if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET)
691 		goto done;
692 
693 	mask = wcd_mbhc_get_button_mask(mbhc);
694 	mbhc->buttons_pressed |= mask;
695 	if (schedule_delayed_work(&mbhc->mbhc_btn_dwork, msecs_to_jiffies(400)) == 0)
696 		WARN(1, "Button pressed twice without release event\n");
697 done:
698 	mutex_unlock(&mbhc->lock);
699 	return IRQ_HANDLED;
700 }
701 
702 static irqreturn_t wcd_mbhc_btn_release_handler(int irq, void *data)
703 {
704 	struct wcd_mbhc *mbhc = data;
705 	int ret;
706 
707 	mutex_lock(&mbhc->lock);
708 	if (mbhc->is_btn_press)
709 		mbhc->is_btn_press = false;
710 	else /* fake btn press */
711 		goto exit;
712 
713 	if (!(mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK))
714 		goto exit;
715 
716 	ret = wcd_cancel_btn_work(mbhc);
717 	if (ret == 0) { /* Reporting long button release event */
718 		snd_soc_jack_report(mbhc->jack,	0, mbhc->buttons_pressed);
719 	} else {
720 		if (!mbhc->in_swch_irq_handler) {
721 			/* Reporting btn press n Release */
722 			snd_soc_jack_report(mbhc->jack, mbhc->buttons_pressed,
723 					    mbhc->buttons_pressed);
724 			snd_soc_jack_report(mbhc->jack,	0, mbhc->buttons_pressed);
725 		}
726 	}
727 	mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
728 exit:
729 	mutex_unlock(&mbhc->lock);
730 
731 	return IRQ_HANDLED;
732 }
733 
734 static irqreturn_t wcd_mbhc_hph_ocp_irq(struct wcd_mbhc *mbhc, bool hphr)
735 {
736 
737 	/* TODO Find a better way to report this to Userspace */
738 	dev_err(mbhc->dev, "MBHC Over Current on %s detected\n",
739 		hphr ? "HPHR" : "HPHL");
740 
741 	wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 0);
742 	wcd_mbhc_write_field(mbhc, WCD_MBHC_OCP_FSM_EN, 1);
743 
744 	return IRQ_HANDLED;
745 }
746 
747 static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
748 {
749 	return wcd_mbhc_hph_ocp_irq(data, false);
750 }
751 
752 static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
753 {
754 	return wcd_mbhc_hph_ocp_irq(data, true);
755 }
756 
757 static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
758 {
759 	struct snd_soc_component *component = mbhc->component;
760 	int ret;
761 
762 	ret = pm_runtime_get_sync(component->dev);
763 	if (ret < 0 && ret != -EACCES) {
764 		dev_err_ratelimited(component->dev,
765 				    "pm_runtime_get_sync failed in %s, ret %d\n",
766 				    __func__, ret);
767 		pm_runtime_put_noidle(component->dev);
768 		return ret;
769 	}
770 
771 	mutex_lock(&mbhc->lock);
772 
773 	if (mbhc->cfg->typec_analog_mux)
774 		mbhc->swap_thr = GND_MIC_USBC_SWAP_THRESHOLD;
775 	else
776 		mbhc->swap_thr = GND_MIC_SWAP_THRESHOLD;
777 
778 	/* setup HS detection */
779 	if (mbhc->mbhc_cb->hph_pull_up_control_v2)
780 		mbhc->mbhc_cb->hph_pull_up_control_v2(component,
781 				mbhc->cfg->typec_analog_mux ?
782 					HS_PULLUP_I_OFF : HS_PULLUP_I_DEFAULT);
783 	else if (mbhc->mbhc_cb->hph_pull_up_control)
784 		mbhc->mbhc_cb->hph_pull_up_control(component,
785 				mbhc->cfg->typec_analog_mux ?
786 					I_OFF : I_DEFAULT);
787 	else
788 		wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_CTRL,
789 				mbhc->cfg->typec_analog_mux ? 0 : 3);
790 
791 	wcd_mbhc_write_field(mbhc, WCD_MBHC_HPHL_PLUG_TYPE, mbhc->cfg->hphl_swh);
792 	wcd_mbhc_write_field(mbhc, WCD_MBHC_GND_PLUG_TYPE, mbhc->cfg->gnd_swh);
793 	wcd_mbhc_write_field(mbhc, WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
794 	if (mbhc->cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl)
795 		mbhc->mbhc_cb->mbhc_gnd_det_ctrl(component, true);
796 	wcd_mbhc_write_field(mbhc, WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
797 
798 	/* Plug detect is triggered manually if analog goes through USBCC */
799 	if (mbhc->cfg->typec_analog_mux)
800 		wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 0);
801 	else
802 		wcd_mbhc_write_field(mbhc, WCD_MBHC_L_DET_EN, 1);
803 
804 	if (mbhc->cfg->typec_analog_mux)
805 		/* Insertion debounce set to 48ms */
806 		wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 4);
807 	else
808 		/* Insertion debounce set to 96ms */
809 		wcd_mbhc_write_field(mbhc, WCD_MBHC_INSREM_DBNC, 6);
810 
811 	/* Button Debounce set to 16ms */
812 	wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_DBNC, 2);
813 
814 	/* enable bias */
815 	mbhc->mbhc_cb->mbhc_bias(component, true);
816 	/* enable MBHC clock */
817 	if (mbhc->mbhc_cb->clk_setup)
818 		mbhc->mbhc_cb->clk_setup(component,
819 				mbhc->cfg->typec_analog_mux ? false : true);
820 
821 	/* program HS_VREF value */
822 	wcd_program_hs_vref(mbhc);
823 
824 	wcd_program_btn_threshold(mbhc, false);
825 
826 	mutex_unlock(&mbhc->lock);
827 
828 	pm_runtime_mark_last_busy(component->dev);
829 	pm_runtime_put_autosuspend(component->dev);
830 
831 	return 0;
832 }
833 
834 static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc)
835 {
836 	int micbias = 0;
837 
838 	if (mbhc->mbhc_cb->get_micbias_val) {
839 		mbhc->mbhc_cb->get_micbias_val(mbhc->component, &micbias);
840 	} else {
841 		u8 vout_ctl = 0;
842 		/* Read MBHC Micbias (Mic Bias2) voltage */
843 		vout_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_MICB2_VOUT);
844 		/* Formula for getting micbias from vout
845 		 * micbias = 1.0V + VOUT_CTL * 50mV
846 		 */
847 		micbias = 1000 + (vout_ctl * 50);
848 	}
849 	return micbias;
850 }
851 
852 static int wcd_get_voltage_from_adc(u8 val, int micbias)
853 {
854 	/* Formula for calculating voltage from ADC
855 	 * Voltage = ADC_RESULT*12.5mV*V_MICBIAS/1.8
856 	 */
857 	return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10));
858 }
859 
860 static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
861 {
862 	u8 adc_result;
863 	int output_mv;
864 	int retry = 3;
865 	u8 adc_en;
866 
867 	/* Pre-requisites for ADC continuous measurement */
868 	/* Read legacy electircal detection and disable */
869 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
870 	/* Set ADC to continuous measurement */
871 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 1);
872 	/* Read ADC Enable bit to restore after adc measurement */
873 	adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
874 	/* Disable ADC_ENABLE bit */
875 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
876 	/* Disable MBHC FSM */
877 	wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
878 	/* Set the MUX selection to IN2P */
879 	wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_IN2P);
880 	/* Enable MBHC FSM */
881 	wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
882 	/* Enable ADC_ENABLE bit */
883 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
884 
885 	while (retry--) {
886 		/* wait for 3 msec before reading ADC result */
887 		usleep_range(3000, 3100);
888 		adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
889 	}
890 
891 	/* Restore ADC Enable */
892 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
893 	/* Get voltage from ADC result */
894 	output_mv = wcd_get_voltage_from_adc(adc_result, wcd_mbhc_get_micbias(mbhc));
895 
896 	return output_mv;
897 }
898 
899 static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl)
900 {
901 	struct device *dev = mbhc->dev;
902 	u8 adc_timeout = 0;
903 	u8 adc_complete = 0;
904 	u8 adc_result;
905 	int retry = 6;
906 	int ret;
907 	int output_mv = 0;
908 	u8 adc_en;
909 
910 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
911 	/* Read ADC Enable bit to restore after adc measurement */
912 	adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
913 	/* Trigger ADC one time measurement */
914 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
915 	wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
916 	/* Set the appropriate MUX selection */
917 	wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, mux_ctl);
918 	wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
919 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 1);
920 
921 	while (retry--) {
922 		/* wait for 600usec to get adc results */
923 		usleep_range(600, 610);
924 
925 		/* check for ADC Timeout */
926 		adc_timeout = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_TIMEOUT);
927 		if (adc_timeout)
928 			continue;
929 
930 		/* Read ADC complete bit */
931 		adc_complete = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_COMPLETE);
932 		if (!adc_complete)
933 			continue;
934 
935 		/* Read ADC result */
936 		adc_result = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_RESULT);
937 
938 		/* Get voltage from ADC result */
939 		output_mv = wcd_get_voltage_from_adc(adc_result,
940 						wcd_mbhc_get_micbias(mbhc));
941 		break;
942 	}
943 
944 	/* Restore ADC Enable */
945 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
946 
947 	if (retry <= 0) {
948 		dev_err(dev, "%s: adc complete: %d, adc timeout: %d\n",
949 			__func__, adc_complete, adc_timeout);
950 		ret = -EINVAL;
951 	} else {
952 		ret = output_mv;
953 	}
954 
955 	return ret;
956 }
957 
958 /* To determine if cross connection occurred */
959 static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
960 {
961 	u8 adc_mode, elect_ctl, adc_en, fsm_en;
962 	int hphl_adc_res, hphr_adc_res;
963 	bool is_cross_conn = false;
964 
965 	/* If PA is enabled, dont check for cross-connection */
966 	if (wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN))
967 		return -EINVAL;
968 
969 	/* Read legacy electircal detection and disable */
970 	elect_ctl = wcd_mbhc_read_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC);
971 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, 0);
972 
973 	/* Read and set ADC to single measurement */
974 	adc_mode = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_MODE);
975 	/* Read ADC Enable bit to restore after adc measurement */
976 	adc_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_ADC_EN);
977 	/* Read FSM status */
978 	fsm_en = wcd_mbhc_read_field(mbhc, WCD_MBHC_FSM_EN);
979 
980 	/* Get adc result for HPH L */
981 	hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L);
982 	if (hphl_adc_res < 0)
983 		return hphl_adc_res;
984 
985 	/* Get adc result for HPH R in mV */
986 	hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R);
987 	if (hphr_adc_res < 0)
988 		return hphr_adc_res;
989 
990 	if (hphl_adc_res > HPHL_CROSS_CONN_THRESHOLD ||
991 	    hphr_adc_res > HPHL_CROSS_CONN_THRESHOLD)
992 		is_cross_conn = true;
993 
994 	wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 0);
995 	/* Set the MUX selection to Auto */
996 	wcd_mbhc_write_field(mbhc, WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
997 	wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, 1);
998 	/* Restore ADC Enable */
999 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, adc_en);
1000 	/* Restore ADC mode */
1001 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, adc_mode);
1002 	/* Restore FSM state */
1003 	wcd_mbhc_write_field(mbhc, WCD_MBHC_FSM_EN, fsm_en);
1004 	/* Restore electrical detection */
1005 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
1006 
1007 	return is_cross_conn;
1008 }
1009 
1010 static int wcd_mbhc_adc_get_hs_thres(struct wcd_mbhc *mbhc)
1011 {
1012 	int hs_threshold, micbias_mv;
1013 
1014 	micbias_mv = wcd_mbhc_get_micbias(mbhc);
1015 	if (mbhc->cfg->hs_thr) {
1016 		if (mbhc->cfg->micb_mv == micbias_mv)
1017 			hs_threshold = mbhc->cfg->hs_thr;
1018 		else
1019 			hs_threshold = (mbhc->cfg->hs_thr *
1020 				micbias_mv) / mbhc->cfg->micb_mv;
1021 	} else {
1022 		hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
1023 			micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
1024 	}
1025 	return hs_threshold;
1026 }
1027 
1028 static int wcd_mbhc_adc_get_hph_thres(struct wcd_mbhc *mbhc)
1029 {
1030 	int hph_threshold, micbias_mv;
1031 
1032 	micbias_mv = wcd_mbhc_get_micbias(mbhc);
1033 	if (mbhc->cfg->hph_thr) {
1034 		if (mbhc->cfg->micb_mv == micbias_mv)
1035 			hph_threshold = mbhc->cfg->hph_thr;
1036 		else
1037 			hph_threshold = (mbhc->cfg->hph_thr *
1038 				micbias_mv) / mbhc->cfg->micb_mv;
1039 	} else {
1040 		hph_threshold = ((WCD_MBHC_ADC_HPH_THRESHOLD_MV *
1041 			micbias_mv) / WCD_MBHC_ADC_MICBIAS_MV);
1042 	}
1043 	return hph_threshold;
1044 }
1045 
1046 static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc,
1047 					   enum wcd_mbhc_plug_type plug_type)
1048 {
1049 	bool micbias2 = false;
1050 
1051 	switch (plug_type) {
1052 	case MBHC_PLUG_TYPE_HEADPHONE:
1053 		wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
1054 		break;
1055 	case MBHC_PLUG_TYPE_HEADSET:
1056 		if (mbhc->mbhc_cb->micbias_enable_status)
1057 			micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc->component,
1058 									MIC_BIAS_2);
1059 
1060 		if (!mbhc->is_hs_recording && !micbias2)
1061 			wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 3);
1062 		break;
1063 	default:
1064 		wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
1065 		break;
1066 
1067 	}
1068 }
1069 
1070 static void wcd_mbhc_bcs_enable(struct wcd_mbhc *mbhc, int plug_type, bool enable)
1071 {
1072 	switch (plug_type) {
1073 	case MBHC_PLUG_TYPE_HEADSET:
1074 	case MBHC_PLUG_TYPE_HEADPHONE:
1075 		if (mbhc->mbhc_cb->bcs_enable)
1076 			mbhc->mbhc_cb->bcs_enable(mbhc->component, enable);
1077 		break;
1078 	default:
1079 		break;
1080 	}
1081 }
1082 
1083 static int wcd_mbhc_get_plug_from_adc(struct wcd_mbhc *mbhc, int adc_result)
1084 
1085 {
1086 	enum wcd_mbhc_plug_type plug_type;
1087 	u32 hph_thr, hs_thr;
1088 
1089 	hs_thr = wcd_mbhc_adc_get_hs_thres(mbhc);
1090 	hph_thr = wcd_mbhc_adc_get_hph_thres(mbhc);
1091 
1092 	if (adc_result < hph_thr)
1093 		plug_type = MBHC_PLUG_TYPE_HEADPHONE;
1094 	else if (adc_result > hs_thr)
1095 		plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1096 	else
1097 		plug_type = MBHC_PLUG_TYPE_HEADSET;
1098 
1099 	return plug_type;
1100 }
1101 
1102 static int wcd_mbhc_get_spl_hs_thres(struct wcd_mbhc *mbhc)
1103 {
1104 	int hs_threshold, micbias_mv;
1105 
1106 	micbias_mv = wcd_mbhc_get_micbias(mbhc);
1107 	if (mbhc->cfg->hs_thr && mbhc->cfg->micb_mv != WCD_MBHC_ADC_MICBIAS_MV) {
1108 		if (mbhc->cfg->micb_mv == micbias_mv)
1109 			hs_threshold = mbhc->cfg->hs_thr;
1110 		else
1111 			hs_threshold = (mbhc->cfg->hs_thr * micbias_mv) / mbhc->cfg->micb_mv;
1112 	} else {
1113 		hs_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV * micbias_mv) /
1114 							WCD_MBHC_ADC_MICBIAS_MV);
1115 	}
1116 	return hs_threshold;
1117 }
1118 
1119 static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc)
1120 {
1121 	bool is_spl_hs = false;
1122 	int output_mv, hs_threshold, hph_threshold;
1123 
1124 	if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
1125 		return false;
1126 
1127 	/* Bump up MIC_BIAS2 to 2.7V */
1128 	mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, true);
1129 	usleep_range(10000, 10100);
1130 
1131 	output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1132 	hs_threshold = wcd_mbhc_get_spl_hs_thres(mbhc);
1133 	hph_threshold = wcd_mbhc_adc_get_hph_thres(mbhc);
1134 
1135 	if (!(output_mv > hs_threshold || output_mv < hph_threshold))
1136 		is_spl_hs = true;
1137 
1138 	/* Back MIC_BIAS2 to 1.8v if the type is not special headset */
1139 	if (!is_spl_hs) {
1140 		mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component, MIC_BIAS_2, false);
1141 		/* Add 10ms delay for micbias to settle */
1142 		usleep_range(10000, 10100);
1143 	}
1144 
1145 	return is_spl_hs;
1146 }
1147 
1148 static void wcd_correct_swch_plug(struct work_struct *work)
1149 {
1150 	struct wcd_mbhc *mbhc;
1151 	struct snd_soc_component *component;
1152 	enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
1153 	unsigned long timeout;
1154 	int pt_gnd_mic_swap_cnt = 0;
1155 	int output_mv, cross_conn, hs_threshold, try = 0, micbias_mv;
1156 	bool is_spl_hs = false;
1157 	bool is_pa_on;
1158 	int ret;
1159 
1160 	mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
1161 	component = mbhc->component;
1162 
1163 	ret = pm_runtime_get_sync(component->dev);
1164 	if (ret < 0 && ret != -EACCES) {
1165 		dev_err_ratelimited(component->dev,
1166 				    "pm_runtime_get_sync failed in %s, ret %d\n",
1167 				    __func__, ret);
1168 		pm_runtime_put_noidle(component->dev);
1169 		return;
1170 	}
1171 	micbias_mv = wcd_mbhc_get_micbias(mbhc);
1172 	hs_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1173 
1174 	/* Mask ADC COMPLETE interrupt */
1175 	disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1176 
1177 	/* Check for cross connection */
1178 	do {
1179 		cross_conn = wcd_check_cross_conn(mbhc);
1180 		try++;
1181 	} while (try < mbhc->swap_thr);
1182 
1183 	if (cross_conn > 0) {
1184 		plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1185 		dev_err(mbhc->dev, "cross connection found, Plug type %d\n",
1186 			plug_type);
1187 		goto correct_plug_type;
1188 	}
1189 
1190 	/* Find plug type */
1191 	output_mv = wcd_measure_adc_continuous(mbhc);
1192 	plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1193 
1194 	/*
1195 	 * Report plug type if it is either headset or headphone
1196 	 * else start the 3 sec loop
1197 	 */
1198 	switch (plug_type) {
1199 	case MBHC_PLUG_TYPE_HEADPHONE:
1200 		wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1201 		break;
1202 	case MBHC_PLUG_TYPE_HEADSET:
1203 		wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1204 		wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1205 		wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1206 		wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1207 		break;
1208 	default:
1209 		break;
1210 	}
1211 
1212 correct_plug_type:
1213 
1214 	/* Disable BCS slow insertion detection */
1215 	wcd_mbhc_bcs_enable(mbhc, plug_type, false);
1216 
1217 	timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
1218 
1219 	while (!time_after(jiffies, timeout)) {
1220 		if (mbhc->hs_detect_work_stop) {
1221 			wcd_micbias_disable(mbhc);
1222 			goto exit;
1223 		}
1224 
1225 		msleep(180);
1226 		/*
1227 		 * Use ADC single mode to minimize the chance of missing out
1228 		 * btn press/release for HEADSET type during correct work.
1229 		 */
1230 		output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1231 		plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1232 		is_pa_on = wcd_mbhc_read_field(mbhc, WCD_MBHC_HPH_PA_EN);
1233 
1234 		if (output_mv > hs_threshold && !is_spl_hs) {
1235 			is_spl_hs = wcd_mbhc_check_for_spl_headset(mbhc);
1236 			output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1237 
1238 			if (is_spl_hs) {
1239 				hs_threshold *= wcd_mbhc_get_micbias(mbhc);
1240 				hs_threshold /= micbias_mv;
1241 			}
1242 		}
1243 
1244 		if ((output_mv <= hs_threshold) && !is_pa_on) {
1245 			/* Check for cross connection*/
1246 			cross_conn = wcd_check_cross_conn(mbhc);
1247 			if (cross_conn > 0) { /* cross-connection */
1248 				pt_gnd_mic_swap_cnt++;
1249 				if (pt_gnd_mic_swap_cnt < mbhc->swap_thr)
1250 					continue;
1251 				else
1252 					plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1253 			} else if (!cross_conn) { /* no cross connection */
1254 				pt_gnd_mic_swap_cnt = 0;
1255 				plug_type = wcd_mbhc_get_plug_from_adc(mbhc, output_mv);
1256 				continue;
1257 			} else /* Error if (cross_conn < 0) */
1258 				continue;
1259 
1260 			if (pt_gnd_mic_swap_cnt == mbhc->swap_thr) {
1261 				/* US_EU gpio present, flip switch */
1262 				if (mbhc->cfg->swap_gnd_mic) {
1263 					if (mbhc->cfg->swap_gnd_mic(component, true))
1264 						continue;
1265 				}
1266 			}
1267 		}
1268 
1269 		/* cable is extension cable */
1270 		if (output_mv > hs_threshold || mbhc->force_linein)
1271 			plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1272 	}
1273 
1274 	wcd_mbhc_bcs_enable(mbhc, plug_type, true);
1275 
1276 	if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
1277 		if (is_spl_hs)
1278 			plug_type = MBHC_PLUG_TYPE_HEADSET;
1279 		else
1280 			wcd_mbhc_write_field(mbhc, WCD_MBHC_ELECT_ISRC_EN, 1);
1281 	}
1282 
1283 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1284 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1285 	wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1286 
1287 	/*
1288 	 * Set DETECTION_DONE bit for HEADSET
1289 	 * so that btn press/release interrupt can be generated.
1290 	 * For other plug type, clear the bit.
1291 	 */
1292 	if (plug_type == MBHC_PLUG_TYPE_HEADSET)
1293 		wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1294 	else
1295 		wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1296 
1297 	if (mbhc->mbhc_cb->mbhc_micbias_control)
1298 		wcd_mbhc_adc_update_fsm_source(mbhc, plug_type);
1299 
1300 exit:
1301 	if (mbhc->mbhc_cb->mbhc_micbias_control/* &&  !mbhc->micbias_enable*/)
1302 		mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2, MICB_DISABLE);
1303 
1304 	/*
1305 	 * If plug type is corrected from special headset to headphone,
1306 	 * clear the micbias enable flag, set micbias back to 1.8V and
1307 	 * disable micbias.
1308 	 */
1309 	if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
1310 		wcd_micbias_disable(mbhc);
1311 		/*
1312 		 * Enable ADC COMPLETE interrupt for HEADPHONE.
1313 		 * Btn release may happen after the correct work, ADC COMPLETE
1314 		 * interrupt needs to be captured to correct plug type.
1315 		 */
1316 		enable_irq(mbhc->intr_ids->mbhc_hs_ins_intr);
1317 	}
1318 
1319 	if (mbhc->mbhc_cb->hph_pull_down_ctrl)
1320 		mbhc->mbhc_cb->hph_pull_down_ctrl(component, true);
1321 
1322 	pm_runtime_mark_last_busy(component->dev);
1323 	pm_runtime_put_autosuspend(component->dev);
1324 }
1325 
1326 static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data)
1327 {
1328 	struct wcd_mbhc *mbhc = data;
1329 	unsigned long timeout;
1330 	int adc_threshold, output_mv, retry = 0;
1331 
1332 	mutex_lock(&mbhc->lock);
1333 	timeout = jiffies + msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
1334 	adc_threshold = wcd_mbhc_adc_get_hs_thres(mbhc);
1335 
1336 	do {
1337 		retry++;
1338 		/*
1339 		 * read output_mv every 10ms to look for
1340 		 * any change in IN2_P
1341 		 */
1342 		usleep_range(10000, 10100);
1343 		output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
1344 
1345 		/* Check for fake removal */
1346 		if ((output_mv <= adc_threshold) && retry > FAKE_REM_RETRY_ATTEMPTS)
1347 			goto exit;
1348 	} while (!time_after(jiffies, timeout));
1349 
1350 	/*
1351 	 * ADC COMPLETE and ELEC_REM interrupts are both enabled for
1352 	 * HEADPHONE, need to reject the ADC COMPLETE interrupt which
1353 	 * follows ELEC_REM one when HEADPHONE is removed.
1354 	 */
1355 	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
1356 		mbhc->extn_cable_hph_rem = true;
1357 
1358 	wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 0);
1359 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_MODE, 0);
1360 	wcd_mbhc_write_field(mbhc, WCD_MBHC_ADC_EN, 0);
1361 	wcd_mbhc_elec_hs_report_unplug(mbhc);
1362 	wcd_mbhc_write_field(mbhc, WCD_MBHC_BTN_ISRC_CTL, 0);
1363 
1364 exit:
1365 	mutex_unlock(&mbhc->lock);
1366 	return IRQ_HANDLED;
1367 }
1368 
1369 static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data)
1370 {
1371 	struct wcd_mbhc *mbhc = data;
1372 	u8 clamp_state;
1373 	u8 clamp_retry = WCD_MBHC_FAKE_INS_RETRY;
1374 
1375 	/*
1376 	 * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE,
1377 	 * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one
1378 	 * when HEADPHONE is removed.
1379 	 */
1380 	if (mbhc->extn_cable_hph_rem == true) {
1381 		mbhc->extn_cable_hph_rem = false;
1382 		return IRQ_HANDLED;
1383 	}
1384 
1385 	do {
1386 		clamp_state = wcd_mbhc_read_field(mbhc, WCD_MBHC_IN2P_CLAMP_STATE);
1387 		if (clamp_state)
1388 			return IRQ_HANDLED;
1389 		/*
1390 		 * check clamp for 120ms but at 30ms chunks to leave
1391 		 * room for other interrupts to be processed
1392 		 */
1393 		usleep_range(30000, 30100);
1394 	} while (--clamp_retry);
1395 
1396 	/*
1397 	 * If current plug is headphone then there is no chance to
1398 	 * get ADC complete interrupt, so connected cable should be
1399 	 * headset not headphone.
1400 	 */
1401 	if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
1402 		disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1403 		wcd_mbhc_write_field(mbhc, WCD_MBHC_DETECTION_DONE, 1);
1404 		wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
1405 		return IRQ_HANDLED;
1406 	}
1407 
1408 	return IRQ_HANDLED;
1409 }
1410 
1411 int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,	uint32_t *zr)
1412 {
1413 	*zl = mbhc->zl;
1414 	*zr = mbhc->zr;
1415 
1416 	if (*zl && *zr)
1417 		return 0;
1418 	else
1419 		return -EINVAL;
1420 }
1421 EXPORT_SYMBOL(wcd_mbhc_get_impedance);
1422 
1423 void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type)
1424 {
1425 	mbhc->hph_type = hph_type;
1426 }
1427 EXPORT_SYMBOL(wcd_mbhc_set_hph_type);
1428 
1429 int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc)
1430 {
1431 	return mbhc->hph_type;
1432 }
1433 EXPORT_SYMBOL(wcd_mbhc_get_hph_type);
1434 
1435 int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *cfg,
1436 		   struct snd_soc_jack *jack)
1437 {
1438 	if (!mbhc || !cfg || !jack)
1439 		return -EINVAL;
1440 
1441 	mbhc->cfg = cfg;
1442 	mbhc->jack = jack;
1443 
1444 	return wcd_mbhc_initialise(mbhc);
1445 }
1446 EXPORT_SYMBOL(wcd_mbhc_start);
1447 
1448 void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
1449 {
1450 	mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
1451 	mbhc->hph_status = 0;
1452 	disable_irq_nosync(mbhc->intr_ids->hph_left_ocp);
1453 	disable_irq_nosync(mbhc->intr_ids->hph_right_ocp);
1454 }
1455 EXPORT_SYMBOL(wcd_mbhc_stop);
1456 
1457 int wcd_dt_parse_mbhc_data(struct device *dev, struct wcd_mbhc_config *cfg)
1458 {
1459 	struct device_node *np = dev->of_node;
1460 	int ret, i, microvolt;
1461 
1462 	if (of_property_read_bool(np, "qcom,hphl-jack-type-normally-closed"))
1463 		cfg->hphl_swh = false;
1464 	else
1465 		cfg->hphl_swh = true;
1466 
1467 	if (of_property_read_bool(np, "qcom,ground-jack-type-normally-closed"))
1468 		cfg->gnd_swh = false;
1469 	else
1470 		cfg->gnd_swh = true;
1471 
1472 	ret = of_property_read_u32(np, "qcom,mbhc-headset-vthreshold-microvolt",
1473 				   &microvolt);
1474 	if (ret)
1475 		dev_dbg(dev, "missing qcom,mbhc-hs-mic-max-vthreshold--microvolt in dt node\n");
1476 	else
1477 		cfg->hs_thr = microvolt/1000;
1478 
1479 	ret = of_property_read_u32(np, "qcom,mbhc-headphone-vthreshold-microvolt",
1480 				   &microvolt);
1481 	if (ret)
1482 		dev_dbg(dev, "missing qcom,mbhc-hs-mic-min-vthreshold-microvolt	entry\n");
1483 	else
1484 		cfg->hph_thr = microvolt/1000;
1485 
1486 	ret = of_property_read_u32_array(np,
1487 					 "qcom,mbhc-buttons-vthreshold-microvolt",
1488 					 &cfg->btn_high[0],
1489 					 WCD_MBHC_DEF_BUTTONS);
1490 	if (ret)
1491 		dev_err(dev, "missing qcom,mbhc-buttons-vthreshold-microvolt entry\n");
1492 
1493 	for (i = 0; i < WCD_MBHC_DEF_BUTTONS; i++) {
1494 		if (ret) /* default voltage */
1495 			cfg->btn_high[i] = 500000;
1496 		else
1497 			/* Micro to Milli Volts */
1498 			cfg->btn_high[i] = cfg->btn_high[i]/1000;
1499 	}
1500 
1501 	return 0;
1502 }
1503 EXPORT_SYMBOL(wcd_dt_parse_mbhc_data);
1504 
1505 struct wcd_mbhc *wcd_mbhc_init(struct snd_soc_component *component,
1506 			       const struct wcd_mbhc_cb *mbhc_cb,
1507 			       const struct wcd_mbhc_intr *intr_ids,
1508 			       const struct wcd_mbhc_field *fields,
1509 			       bool impedance_det_en)
1510 {
1511 	struct device *dev = component->dev;
1512 	struct wcd_mbhc *mbhc;
1513 	int ret;
1514 
1515 	if (!intr_ids || !fields || !mbhc_cb || !mbhc_cb->mbhc_bias || !mbhc_cb->set_btn_thr) {
1516 		dev_err(dev, "%s: Insufficient mbhc configuration\n", __func__);
1517 		return ERR_PTR(-EINVAL);
1518 	}
1519 
1520 	mbhc = kzalloc(sizeof(*mbhc), GFP_KERNEL);
1521 	if (!mbhc)
1522 		return ERR_PTR(-ENOMEM);
1523 
1524 	mbhc->component = component;
1525 	mbhc->dev = dev;
1526 	mbhc->intr_ids = intr_ids;
1527 	mbhc->mbhc_cb = mbhc_cb;
1528 	mbhc->fields = fields;
1529 	mbhc->mbhc_detection_logic = WCD_DETECTION_ADC;
1530 
1531 	if (mbhc_cb->compute_impedance)
1532 		mbhc->impedance_detect = impedance_det_en;
1533 
1534 	INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_long_press_fn);
1535 
1536 	mutex_init(&mbhc->lock);
1537 
1538 	INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
1539 	INIT_WORK(&mbhc->mbhc_plug_detect_work, mbhc_plug_detect_fn);
1540 
1541 	ret = request_threaded_irq(mbhc->intr_ids->mbhc_sw_intr, NULL,
1542 					wcd_mbhc_mech_plug_detect_irq,
1543 					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1544 					"mbhc sw intr", mbhc);
1545 	if (ret)
1546 		goto err_free_mbhc;
1547 
1548 	ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_press_intr, NULL,
1549 					wcd_mbhc_btn_press_handler,
1550 					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1551 					"Button Press detect", mbhc);
1552 	if (ret)
1553 		goto err_free_sw_intr;
1554 
1555 	ret = request_threaded_irq(mbhc->intr_ids->mbhc_btn_release_intr, NULL,
1556 					wcd_mbhc_btn_release_handler,
1557 					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1558 					"Button Release detect", mbhc);
1559 	if (ret)
1560 		goto err_free_btn_press_intr;
1561 
1562 	ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_ins_intr, NULL,
1563 					wcd_mbhc_adc_hs_ins_irq,
1564 					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1565 					"Elect Insert", mbhc);
1566 	if (ret)
1567 		goto err_free_btn_release_intr;
1568 
1569 	disable_irq_nosync(mbhc->intr_ids->mbhc_hs_ins_intr);
1570 
1571 	ret = request_threaded_irq(mbhc->intr_ids->mbhc_hs_rem_intr, NULL,
1572 					wcd_mbhc_adc_hs_rem_irq,
1573 					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1574 					"Elect Remove", mbhc);
1575 	if (ret)
1576 		goto err_free_hs_ins_intr;
1577 
1578 	disable_irq_nosync(mbhc->intr_ids->mbhc_hs_rem_intr);
1579 
1580 	ret = request_threaded_irq(mbhc->intr_ids->hph_left_ocp, NULL,
1581 					wcd_mbhc_hphl_ocp_irq,
1582 					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1583 					"HPH_L OCP detect", mbhc);
1584 	if (ret)
1585 		goto err_free_hs_rem_intr;
1586 
1587 	ret = request_threaded_irq(mbhc->intr_ids->hph_right_ocp, NULL,
1588 					wcd_mbhc_hphr_ocp_irq,
1589 					IRQF_ONESHOT | IRQF_TRIGGER_RISING,
1590 					"HPH_R OCP detect", mbhc);
1591 	if (ret)
1592 		goto err_free_hph_left_ocp;
1593 
1594 	return mbhc;
1595 
1596 err_free_hph_left_ocp:
1597 	free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
1598 err_free_hs_rem_intr:
1599 	free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
1600 err_free_hs_ins_intr:
1601 	free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
1602 err_free_btn_release_intr:
1603 	free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
1604 err_free_btn_press_intr:
1605 	free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
1606 err_free_sw_intr:
1607 	free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
1608 err_free_mbhc:
1609 	kfree(mbhc);
1610 
1611 	dev_err(dev, "Failed to request mbhc interrupts %d\n", ret);
1612 
1613 	return ERR_PTR(ret);
1614 }
1615 EXPORT_SYMBOL(wcd_mbhc_init);
1616 
1617 void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
1618 {
1619 	free_irq(mbhc->intr_ids->hph_right_ocp, mbhc);
1620 	free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
1621 	free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
1622 	free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
1623 	free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
1624 	free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
1625 	free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
1626 
1627 	mutex_lock(&mbhc->lock);
1628 	wcd_cancel_hs_detect_plug(mbhc,	&mbhc->correct_plug_swch);
1629 	cancel_work_sync(&mbhc->mbhc_plug_detect_work);
1630 	mutex_unlock(&mbhc->lock);
1631 
1632 	kfree(mbhc);
1633 }
1634 EXPORT_SYMBOL(wcd_mbhc_deinit);
1635 
1636 static int __init mbhc_init(void)
1637 {
1638 	return 0;
1639 }
1640 
1641 static void __exit mbhc_exit(void)
1642 {
1643 }
1644 
1645 module_init(mbhc_init);
1646 module_exit(mbhc_exit);
1647 
1648 MODULE_DESCRIPTION("wcd MBHC v2 module");
1649 MODULE_LICENSE("GPL");
1650