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