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