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
35enum 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
45struct 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
78static 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
89static 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
99static 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
106static 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
115static 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
161int 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}
265EXPORT_SYMBOL_GPL(wcd_mbhc_event_notify);
266
267static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc)
268{
269	return cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
270}
271
272static 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
288static 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
309static 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
327static 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
401static 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
414static 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
423static 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
431static 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
451static 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
483static 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
491static 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
509static 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
576exit:
577	mbhc->in_swch_irq_handler = false;
578	mutex_unlock(&mbhc->lock);
579	return IRQ_HANDLED;
580}
581
582static 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
615static 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
625static 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");
652done:
653	mutex_unlock(&mbhc->lock);
654	return IRQ_HANDLED;
655}
656
657static 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;
683exit:
684	mutex_unlock(&mbhc->lock);
685
686	return IRQ_HANDLED;
687}
688
689static 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
702static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
703{
704	return wcd_mbhc_hph_ocp_irq(data, false);
705}
706
707static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
708{
709	return wcd_mbhc_hph_ocp_irq(data, true);
710}
711
712static 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
771static 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
789static 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
797static 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
836static 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 */
896static 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
947static 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
965static 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
983static 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
1007static 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
1020static 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
1039static 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
1056static 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
1085static 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
1149correct_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
1237exit:
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
1263static 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
1301exit:
1302	mutex_unlock(&mbhc->lock);
1303	return IRQ_HANDLED;
1304}
1305
1306static 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
1348int 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}
1358EXPORT_SYMBOL(wcd_mbhc_get_impedance);
1359
1360void wcd_mbhc_set_hph_type(struct wcd_mbhc *mbhc, int hph_type)
1361{
1362	mbhc->hph_type = hph_type;
1363}
1364EXPORT_SYMBOL(wcd_mbhc_set_hph_type);
1365
1366int wcd_mbhc_get_hph_type(struct wcd_mbhc *mbhc)
1367{
1368	return mbhc->hph_type;
1369}
1370EXPORT_SYMBOL(wcd_mbhc_get_hph_type);
1371
1372int 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}
1383EXPORT_SYMBOL(wcd_mbhc_start);
1384
1385void 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}
1392EXPORT_SYMBOL(wcd_mbhc_stop);
1393
1394int 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}
1440EXPORT_SYMBOL(wcd_dt_parse_mbhc_data);
1441
1442struct 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
1532err_free_hph_left_ocp:
1533	free_irq(mbhc->intr_ids->hph_left_ocp, mbhc);
1534err_free_hs_rem_intr:
1535	free_irq(mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
1536err_free_hs_ins_intr:
1537	free_irq(mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
1538err_free_btn_release_intr:
1539	free_irq(mbhc->intr_ids->mbhc_btn_release_intr, mbhc);
1540err_free_btn_press_intr:
1541	free_irq(mbhc->intr_ids->mbhc_btn_press_intr, mbhc);
1542err_free_sw_intr:
1543	free_irq(mbhc->intr_ids->mbhc_sw_intr, mbhc);
1544err_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}
1551EXPORT_SYMBOL(wcd_mbhc_init);
1552
1553void 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}
1569EXPORT_SYMBOL(wcd_mbhc_deinit);
1570
1571static int __init mbhc_init(void)
1572{
1573	return 0;
1574}
1575
1576static void __exit mbhc_exit(void)
1577{
1578}
1579
1580module_init(mbhc_init);
1581module_exit(mbhc_exit);
1582
1583MODULE_DESCRIPTION("wcd MBHC v2 module");
1584MODULE_LICENSE("GPL");
1585