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