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