blob: cc54362fa88049d65580073972454968551c2c78 [file] [log] [blame]
Banajit Goswamide8271c2017-01-18 00:28:59 -08001/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/slab.h>
15#include <linux/of_gpio.h>
16#include <linux/platform_device.h>
17#include <linux/device.h>
18#include <linux/printk.h>
19#include <linux/ratelimit.h>
20#include <linux/list.h>
21#include <linux/bitops.h>
22#include <linux/delay.h>
23#include <linux/pm_runtime.h>
24#include <linux/kernel.h>
25#include <linux/input.h>
26#include <linux/firmware.h>
27#include <linux/completion.h>
28#include <sound/soc.h>
29#include <sound/jack.h>
30#include "wcd-mbhc-v2.h"
31#include "wcdcal-hwdep.h"
32
33#define WCD_MBHC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
34 SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
35 SND_JACK_MECHANICAL | SND_JACK_MICROPHONE2 | \
36 SND_JACK_UNSUPPORTED)
37
38#define WCD_MBHC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
39 SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
40 SND_JACK_BTN_4 | SND_JACK_BTN_5)
41#define OCP_ATTEMPT 20
42#define HS_DETECT_PLUG_TIME_MS (3 * 1000)
43#define SPECIAL_HS_DETECT_TIME_MS (2 * 1000)
44#define MBHC_BUTTON_PRESS_THRESHOLD_MIN 250
45#define GND_MIC_SWAP_THRESHOLD 4
46#define WCD_FAKE_REMOVAL_MIN_PERIOD_MS 100
47#define HS_VREF_MIN_VAL 1400
48#define FW_READ_ATTEMPTS 15
49#define FW_READ_TIMEOUT 4000000
50#define FAKE_REM_RETRY_ATTEMPTS 3
51#define MAX_IMPED 60000
52
53#define WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS 50
54#define ANC_DETECT_RETRY_CNT 7
55#define WCD_MBHC_SPL_HS_CNT 1
56
57static int det_extn_cable_en;
58module_param(det_extn_cable_en, int, 0664);
59MODULE_PARM_DESC(det_extn_cable_en, "enable/disable extn cable detect");
60
61enum wcd_mbhc_cs_mb_en_flag {
62 WCD_MBHC_EN_CS = 0,
63 WCD_MBHC_EN_MB,
64 WCD_MBHC_EN_PULLUP,
65 WCD_MBHC_EN_NONE,
66};
67
68static void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc,
69 struct snd_soc_jack *jack, int status, int mask)
70{
71 snd_soc_jack_report(jack, status, mask);
72}
73
74static void __hphocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status,
75 int irq)
76{
77 struct snd_soc_codec *codec = mbhc->codec;
78
79 dev_dbg(codec->dev, "%s: clear ocp status %x\n",
80 __func__, jack_status);
81
82 if (mbhc->hph_status & jack_status) {
83 mbhc->hph_status &= ~jack_status;
84 wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
85 mbhc->hph_status, WCD_MBHC_JACK_MASK);
86 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0);
87 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1);
88 /*
89 * reset retry counter as PA is turned off signifying
90 * start of new OCP detection session
91 */
92 if (mbhc->intr_ids->hph_left_ocp)
93 mbhc->hphlocp_cnt = 0;
94 else
95 mbhc->hphrocp_cnt = 0;
96 mbhc->mbhc_cb->irq_control(codec, irq, true);
97 }
98}
99
100static void hphrocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status)
101{
102 __hphocp_off_report(mbhc, SND_JACK_OC_HPHR,
103 mbhc->intr_ids->hph_right_ocp);
104}
105
106static void hphlocp_off_report(struct wcd_mbhc *mbhc, u32 jack_status)
107{
108 __hphocp_off_report(mbhc, SND_JACK_OC_HPHL,
109 mbhc->intr_ids->hph_left_ocp);
110}
111
112static void wcd_program_hs_vref(struct wcd_mbhc *mbhc)
113{
114 struct wcd_mbhc_plug_type_cfg *plug_type_cfg;
115 struct snd_soc_codec *codec = mbhc->codec;
116 u32 reg_val;
117
118 plug_type_cfg = WCD_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
119 reg_val = ((plug_type_cfg->v_hs_max - HS_VREF_MIN_VAL) / 100);
120
121 dev_dbg(codec->dev, "%s: reg_val = %x\n", __func__, reg_val);
122 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_VREF, reg_val);
123}
124
125static void wcd_program_btn_threshold(const struct wcd_mbhc *mbhc, bool micbias)
126{
127 struct wcd_mbhc_btn_detect_cfg *btn_det;
128 struct snd_soc_codec *codec = mbhc->codec;
129 struct snd_soc_card *card = codec->component.card;
130 s16 *btn_low, *btn_high;
131
132 if (mbhc->mbhc_cfg->calibration == NULL) {
133 dev_err(card->dev, "%s: calibration data is NULL\n", __func__);
134 return;
135 }
136
137 btn_det = WCD_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
138 btn_low = btn_det->_v_btn_low;
139 btn_high = ((void *)&btn_det->_v_btn_low) +
140 (sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn);
141
142 mbhc->mbhc_cb->set_btn_thr(codec, btn_low, btn_high, btn_det->num_btn,
143 micbias);
144}
145
146static void wcd_enable_curr_micbias(const struct wcd_mbhc *mbhc,
147 const enum wcd_mbhc_cs_mb_en_flag cs_mb_en)
148{
149
150 /*
151 * Some codecs handle micbias/pullup enablement in codec
152 * drivers itself and micbias is not needed for regular
153 * plug type detection. So if micbias_control callback function
154 * is defined, just return.
155 */
156 if (mbhc->mbhc_cb->mbhc_micbias_control)
157 return;
158
159 pr_debug("%s: enter, cs_mb_en: %d\n", __func__, cs_mb_en);
160
161 switch (cs_mb_en) {
162 case WCD_MBHC_EN_CS:
163 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
164 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
165 /* Program Button threshold registers as per CS */
166 wcd_program_btn_threshold(mbhc, false);
167 break;
168 case WCD_MBHC_EN_MB:
169 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
170 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
171
172 /* Disable PULL_UP_EN & enable MICBIAS */
173 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 2);
174 /* Program Button threshold registers as per MICBIAS */
175 wcd_program_btn_threshold(mbhc, true);
176 break;
177 case WCD_MBHC_EN_PULLUP:
178 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
179 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
180 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 1);
181 /* Program Button threshold registers as per MICBIAS */
182 wcd_program_btn_threshold(mbhc, true);
183 break;
184 case WCD_MBHC_EN_NONE:
185 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
186 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
187 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
188 break;
189 default:
190 pr_debug("%s: Invalid parameter", __func__);
191 break;
192 }
193
194 pr_debug("%s: exit\n", __func__);
195}
196
197static const char *wcd_mbhc_get_event_string(int event)
198{
199 switch (event) {
200 case WCD_EVENT_PRE_MICBIAS_2_OFF:
201 return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_OFF);
202 case WCD_EVENT_POST_MICBIAS_2_OFF:
203 return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_OFF);
204 case WCD_EVENT_PRE_MICBIAS_2_ON:
205 return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_MICBIAS_2_ON);
206 case WCD_EVENT_POST_MICBIAS_2_ON:
207 return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_MICBIAS_2_ON);
208 case WCD_EVENT_PRE_HPHL_PA_ON:
209 return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_ON);
210 case WCD_EVENT_POST_HPHL_PA_OFF:
211 return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHL_PA_OFF);
212 case WCD_EVENT_PRE_HPHR_PA_ON:
213 return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_ON);
214 case WCD_EVENT_POST_HPHR_PA_OFF:
215 return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_HPHR_PA_OFF);
216 case WCD_EVENT_PRE_HPHR_PA_OFF:
217 return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHR_PA_OFF);
218 case WCD_EVENT_PRE_HPHL_PA_OFF:
219 return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_HPHL_PA_OFF);
220 case WCD_EVENT_POST_DAPM_MICBIAS_2_ON:
221 return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_ON);
222 case WCD_EVENT_PRE_DAPM_MICBIAS_2_ON:
223 return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_ON);
224 case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF:
225 return WCD_MBHC_STRINGIFY(WCD_EVENT_POST_DAPM_MICBIAS_2_OFF);
226 case WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF:
227 return WCD_MBHC_STRINGIFY(WCD_EVENT_PRE_DAPM_MICBIAS_2_OFF);
228 case WCD_EVENT_OCP_OFF:
229 return WCD_MBHC_STRINGIFY(WCD_EVENT_OCP_OFF);
230 case WCD_EVENT_OCP_ON:
231 return WCD_MBHC_STRINGIFY(WCD_EVENT_OCP_ON);
232 case WCD_EVENT_INVALID:
233 default:
234 return WCD_MBHC_STRINGIFY(WCD_EVENT_INVALID);
235 }
236}
237
238static int wcd_event_notify(struct notifier_block *self, unsigned long val,
239 void *data)
240{
241 struct wcd_mbhc *mbhc = (struct wcd_mbhc *)data;
242 enum wcd_notify_event event = (enum wcd_notify_event)val;
243 struct snd_soc_codec *codec = mbhc->codec;
244 bool micbias2 = false;
245 bool micbias1 = false;
246 u8 fsm_en = 0;
247
248 pr_debug("%s: event %s (%d)\n", __func__,
249 wcd_mbhc_get_event_string(event), event);
250 if (mbhc->mbhc_cb->micbias_enable_status) {
251 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
252 MIC_BIAS_2);
253 micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
254 MIC_BIAS_1);
255 }
256 switch (event) {
257 /* MICBIAS usage change */
258 case WCD_EVENT_POST_DAPM_MICBIAS_2_ON:
259 mbhc->is_hs_recording = true;
260 pr_debug("%s: is_capture: %d\n", __func__,
261 mbhc->is_hs_recording);
262 break;
263 case WCD_EVENT_POST_MICBIAS_2_ON:
264 if (!mbhc->micbias_enable)
265 goto out_micb_en;
266 if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) {
267 mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
268 MBHC_COMMON_MICB_PRECHARGE,
269 true);
270 mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
271 MBHC_COMMON_MICB_SET_VAL,
272 true);
273 /*
274 * Special headset needs MICBIAS as 2.7V so wait for
275 * 50 msec for the MICBIAS to reach 2.7 volts.
276 */
277 msleep(50);
278 }
279 if (mbhc->mbhc_cb->set_auto_zeroing)
280 mbhc->mbhc_cb->set_auto_zeroing(codec, true);
281 if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
282 mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
283 MBHC_COMMON_MICB_PRECHARGE,
284 false);
285out_micb_en:
286 /* Disable current source if micbias enabled */
287 if (mbhc->mbhc_cb->mbhc_micbias_control) {
288 WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en);
289 if (fsm_en)
290 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL,
291 0);
292 } else {
293 mbhc->is_hs_recording = true;
294 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
295 }
296 /* configure cap settings properly when micbias is enabled */
297 if (mbhc->mbhc_cb->set_cap_mode)
298 mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true);
299 break;
300 case WCD_EVENT_PRE_MICBIAS_2_OFF:
301 /*
302 * Before MICBIAS_2 is turned off, if FSM is enabled,
303 * make sure current source is enabled so as to detect
304 * button press/release events
305 */
306 if (mbhc->mbhc_cb->mbhc_micbias_control &&
307 !mbhc->micbias_enable) {
308 WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en);
309 if (fsm_en)
310 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL,
311 3);
312 }
313 break;
314 /* MICBIAS usage change */
315 case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF:
316 mbhc->is_hs_recording = false;
317 pr_debug("%s: is_capture: %d\n", __func__,
318 mbhc->is_hs_recording);
319 break;
320 case WCD_EVENT_POST_MICBIAS_2_OFF:
321 if (!mbhc->mbhc_cb->mbhc_micbias_control)
322 mbhc->is_hs_recording = false;
323 if (mbhc->micbias_enable) {
324 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
325 break;
326 }
327
328 if (mbhc->mbhc_cb->set_auto_zeroing)
329 mbhc->mbhc_cb->set_auto_zeroing(codec, false);
330 if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable)
331 mbhc->mbhc_cb->set_micbias_value(codec);
332 /* Enable PULL UP if PA's are enabled */
333 if ((test_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state)) ||
334 (test_bit(WCD_MBHC_EVENT_PA_HPHR,
335 &mbhc->event_state)))
336 /* enable pullup and cs, disable mb */
337 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP);
338 else
339 /* enable current source and disable mb, pullup*/
340 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
341
342 /* configure cap settings properly when micbias is disabled */
343 if (mbhc->mbhc_cb->set_cap_mode)
344 mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false);
345 break;
346 case WCD_EVENT_PRE_HPHL_PA_OFF:
347 mutex_lock(&mbhc->hphl_pa_lock);
348 break;
349 case WCD_EVENT_POST_HPHL_PA_OFF:
350 clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
351 if (mbhc->hph_status & SND_JACK_OC_HPHL)
352 hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
353 clear_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
354 /* check if micbias is enabled */
355 if (micbias2)
356 /* Disable cs, pullup & enable micbias */
357 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
358 else
359 /* Disable micbias, pullup & enable cs */
360 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
361 mutex_unlock(&mbhc->hphl_pa_lock);
362 break;
363 case WCD_EVENT_PRE_HPHR_PA_OFF:
364 mutex_lock(&mbhc->hphr_pa_lock);
365 break;
366 case WCD_EVENT_POST_HPHR_PA_OFF:
367 clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
368 if (mbhc->hph_status & SND_JACK_OC_HPHR)
369 hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
370 clear_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
371 /* check if micbias is enabled */
372 if (micbias2)
373 /* Disable cs, pullup & enable micbias */
374 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
375 else
376 /* Disable micbias, pullup & enable cs */
377 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
378 mutex_unlock(&mbhc->hphr_pa_lock);
379 break;
380 case WCD_EVENT_PRE_HPHL_PA_ON:
381 set_bit(WCD_MBHC_EVENT_PA_HPHL, &mbhc->event_state);
382 /* check if micbias is enabled */
383 if (micbias2)
384 /* Disable cs, pullup & enable micbias */
385 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
386 else
387 /* Disable micbias, enable pullup & cs */
388 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP);
389 break;
390 case WCD_EVENT_PRE_HPHR_PA_ON:
391 set_bit(WCD_MBHC_EVENT_PA_HPHR, &mbhc->event_state);
392 /* check if micbias is enabled */
393 if (micbias2)
394 /* Disable cs, pullup & enable micbias */
395 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
396 else
397 /* Disable micbias, enable pullup & cs */
398 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_PULLUP);
399 break;
400 case WCD_EVENT_OCP_OFF:
401 mbhc->mbhc_cb->irq_control(mbhc->codec,
402 mbhc->intr_ids->hph_left_ocp,
403 false);
404 break;
405 case WCD_EVENT_OCP_ON:
406 mbhc->mbhc_cb->irq_control(mbhc->codec,
407 mbhc->intr_ids->hph_left_ocp,
408 true);
409 break;
410 default:
411 break;
412 }
413 return 0;
414}
415
416static int wcd_cancel_btn_work(struct wcd_mbhc *mbhc)
417{
418 int r;
419
420 r = cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
421 /*
422 * if scheduled mbhc.mbhc_btn_dwork is canceled from here,
423 * we have to unlock from here instead btn_work
424 */
425 if (r)
426 mbhc->mbhc_cb->lock_sleep(mbhc, false);
427 return r;
428}
429
430static bool wcd_swch_level_remove(struct wcd_mbhc *mbhc)
431{
432 u16 result2 = 0;
433
434 WCD_MBHC_REG_READ(WCD_MBHC_SWCH_LEVEL_REMOVE, result2);
435 return (result2) ? true : false;
436}
437
438/* should be called under interrupt context that hold suspend */
439static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
440 struct work_struct *work)
441{
442 pr_debug("%s: scheduling correct_swch_plug\n", __func__);
443 WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
444 mbhc->hs_detect_work_stop = false;
445 mbhc->mbhc_cb->lock_sleep(mbhc, true);
446 schedule_work(work);
447}
448
449/* called under codec_resource_lock acquisition */
450static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
451 struct work_struct *work)
452{
453 pr_debug("%s: Canceling correct_plug_swch\n", __func__);
454 mbhc->hs_detect_work_stop = true;
455 WCD_MBHC_RSC_UNLOCK(mbhc);
456 if (cancel_work_sync(work)) {
457 pr_debug("%s: correct_plug_swch is canceled\n",
458 __func__);
459 mbhc->mbhc_cb->lock_sleep(mbhc, false);
460 }
461 WCD_MBHC_RSC_LOCK(mbhc);
462}
463
464static void wcd_mbhc_clr_and_turnon_hph_padac(struct wcd_mbhc *mbhc)
465{
466 bool pa_turned_on = false;
467 u8 wg_time = 0;
468
469 WCD_MBHC_REG_READ(WCD_MBHC_HPH_CNP_WG_TIME, wg_time);
470 wg_time += 1;
471
472 mutex_lock(&mbhc->hphr_pa_lock);
473 if (test_and_clear_bit(WCD_MBHC_HPHR_PA_OFF_ACK,
474 &mbhc->hph_pa_dac_state)) {
475 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
476 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_PA_EN, 1);
477 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_OCP_DET_EN, 1);
478 pa_turned_on = true;
479 }
480 mutex_unlock(&mbhc->hphr_pa_lock);
481 mutex_lock(&mbhc->hphl_pa_lock);
482 if (test_and_clear_bit(WCD_MBHC_HPHL_PA_OFF_ACK,
483 &mbhc->hph_pa_dac_state)) {
484 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
485 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1);
486 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_OCP_DET_EN, 1);
487 pa_turned_on = true;
488 }
489 mutex_unlock(&mbhc->hphl_pa_lock);
490
491 if (pa_turned_on) {
492 pr_debug("%s: PA was turned on by MBHC and not by DAPM\n",
493 __func__);
494 usleep_range(wg_time * 1000, wg_time * 1000 + 50);
495 }
496}
497
498static bool wcd_mbhc_is_hph_pa_on(struct wcd_mbhc *mbhc)
499{
500 bool hph_pa_on = false;
501
502 WCD_MBHC_REG_READ(WCD_MBHC_HPH_PA_EN, hph_pa_on);
503
504 return (hph_pa_on) ? true : false;
505}
506
507static void wcd_mbhc_set_and_turnoff_hph_padac(struct wcd_mbhc *mbhc)
508{
509 u8 wg_time = 0;
510
511 WCD_MBHC_REG_READ(WCD_MBHC_HPH_CNP_WG_TIME, wg_time);
512 wg_time += 1;
513
514 /* If headphone PA is on, check if userspace receives
515 * removal event to sync-up PA's state
516 */
517 if (wcd_mbhc_is_hph_pa_on(mbhc)) {
518 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
519 set_bit(WCD_MBHC_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
520 set_bit(WCD_MBHC_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
521 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_OCP_DET_EN, 0);
522 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_OCP_DET_EN, 0);
523 } else {
524 pr_debug("%s PA is off\n", __func__);
525 }
526 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPH_PA_EN, 0);
527 usleep_range(wg_time * 1000, wg_time * 1000 + 50);
528}
529
530int wcd_mbhc_get_impedance(struct wcd_mbhc *mbhc, uint32_t *zl,
531 uint32_t *zr)
532{
533 *zl = mbhc->zl;
534 *zr = mbhc->zr;
535
536 if (*zl && *zr)
537 return 0;
538 else
539 return -EINVAL;
540}
541
542static void wcd_mbhc_hs_elec_irq(struct wcd_mbhc *mbhc, int irq_type,
543 bool enable)
544{
545 int irq;
546
547 WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
548
549 if (irq_type == WCD_MBHC_ELEC_HS_INS)
550 irq = mbhc->intr_ids->mbhc_hs_ins_intr;
551 else if (irq_type == WCD_MBHC_ELEC_HS_REM)
552 irq = mbhc->intr_ids->mbhc_hs_rem_intr;
553 else {
554 pr_debug("%s: irq_type: %d, enable: %d\n",
555 __func__, irq_type, enable);
556 return;
557 }
558
559 pr_debug("%s: irq: %d, enable: %d, intr_status:%lu\n",
560 __func__, irq, enable, mbhc->intr_status);
561 if ((test_bit(irq_type, &mbhc->intr_status)) != enable) {
562 mbhc->mbhc_cb->irq_control(mbhc->codec, irq, enable);
563 if (enable)
564 set_bit(irq_type, &mbhc->intr_status);
565 else
566 clear_bit(irq_type, &mbhc->intr_status);
567 }
568}
569
570static void wcd_mbhc_report_plug(struct wcd_mbhc *mbhc, int insertion,
571 enum snd_jack_types jack_type)
572{
573 WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
574
575 pr_debug("%s: enter insertion %d hph_status %x\n",
576 __func__, insertion, mbhc->hph_status);
577 if (!insertion) {
578 /* Report removal */
579 mbhc->hph_status &= ~jack_type;
580 /*
581 * cancel possibly scheduled btn work and
582 * report release if we reported button press
583 */
584 if (wcd_cancel_btn_work(mbhc)) {
585 pr_debug("%s: button press is canceled\n", __func__);
586 } else if (mbhc->buttons_pressed) {
587 pr_debug("%s: release of button press%d\n",
588 __func__, jack_type);
589 wcd_mbhc_jack_report(mbhc, &mbhc->button_jack, 0,
590 mbhc->buttons_pressed);
591 mbhc->buttons_pressed &=
592 ~WCD_MBHC_JACK_BUTTON_MASK;
593 }
594
595 if (mbhc->micbias_enable) {
596 if (mbhc->mbhc_cb->mbhc_micbias_control)
597 mbhc->mbhc_cb->mbhc_micbias_control(
598 mbhc->codec, MIC_BIAS_2,
599 MICB_DISABLE);
600 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
601 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
602 mbhc->codec,
603 MIC_BIAS_2, false);
604 if (mbhc->mbhc_cb->set_micbias_value) {
605 mbhc->mbhc_cb->set_micbias_value(mbhc->codec);
606 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
607 }
608 mbhc->micbias_enable = false;
609 }
610
611 mbhc->hph_type = WCD_MBHC_HPH_NONE;
612 mbhc->zl = mbhc->zr = 0;
613 pr_debug("%s: Reporting removal %d(%x)\n", __func__,
614 jack_type, mbhc->hph_status);
615 wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
616 mbhc->hph_status, WCD_MBHC_JACK_MASK);
617 wcd_mbhc_set_and_turnoff_hph_padac(mbhc);
618 hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
619 hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
620 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
621 } else {
622 /*
623 * Report removal of current jack type.
624 * Headphone to headset shouldn't report headphone
625 * removal.
626 */
627 if (mbhc->mbhc_cfg->detect_extn_cable &&
628 (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH ||
629 jack_type == SND_JACK_LINEOUT) &&
630 (mbhc->hph_status && mbhc->hph_status != jack_type)) {
631
632 if (mbhc->micbias_enable) {
633 if (mbhc->mbhc_cb->mbhc_micbias_control)
634 mbhc->mbhc_cb->mbhc_micbias_control(
635 mbhc->codec, MIC_BIAS_2,
636 MICB_DISABLE);
637 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
638 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
639 mbhc->codec,
640 MIC_BIAS_2, false);
641 if (mbhc->mbhc_cb->set_micbias_value) {
642 mbhc->mbhc_cb->set_micbias_value(
643 mbhc->codec);
644 WCD_MBHC_REG_UPDATE_BITS(
645 WCD_MBHC_MICB_CTRL, 0);
646 }
647 mbhc->micbias_enable = false;
648 }
649 mbhc->hph_type = WCD_MBHC_HPH_NONE;
650 mbhc->zl = mbhc->zr = 0;
651 pr_debug("%s: Reporting removal (%x)\n",
652 __func__, mbhc->hph_status);
653 wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
654 0, WCD_MBHC_JACK_MASK);
655
656 if (mbhc->hph_status == SND_JACK_LINEOUT) {
657
658 pr_debug("%s: Enable micbias\n", __func__);
659 /* Disable current source and enable micbias */
660 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
661 pr_debug("%s: set up elec removal detection\n",
662 __func__);
663 WCD_MBHC_REG_UPDATE_BITS(
664 WCD_MBHC_ELECT_DETECTION_TYPE,
665 0);
666 usleep_range(200, 210);
667 wcd_mbhc_hs_elec_irq(mbhc,
668 WCD_MBHC_ELEC_HS_REM,
669 true);
670 }
671 mbhc->hph_status &= ~(SND_JACK_HEADSET |
672 SND_JACK_LINEOUT |
673 SND_JACK_ANC_HEADPHONE |
674 SND_JACK_UNSUPPORTED);
675 }
676
677 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET &&
678 jack_type == SND_JACK_HEADPHONE)
679 mbhc->hph_status &= ~SND_JACK_HEADSET;
680
681 /* Report insertion */
682 if (jack_type == SND_JACK_HEADPHONE)
683 mbhc->current_plug = MBHC_PLUG_TYPE_HEADPHONE;
684 else if (jack_type == SND_JACK_UNSUPPORTED)
685 mbhc->current_plug = MBHC_PLUG_TYPE_GND_MIC_SWAP;
686 else if (jack_type == SND_JACK_HEADSET) {
687 mbhc->current_plug = MBHC_PLUG_TYPE_HEADSET;
688 mbhc->jiffies_atreport = jiffies;
689 } else if (jack_type == SND_JACK_LINEOUT) {
690 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
691 } else if (jack_type == SND_JACK_ANC_HEADPHONE)
692 mbhc->current_plug = MBHC_PLUG_TYPE_ANC_HEADPHONE;
693
694 if (mbhc->impedance_detect &&
695 mbhc->mbhc_cb->compute_impedance &&
696 (mbhc->mbhc_cfg->linein_th != 0)) {
697 mbhc->mbhc_cb->compute_impedance(mbhc,
698 &mbhc->zl, &mbhc->zr);
699 if ((mbhc->zl > mbhc->mbhc_cfg->linein_th &&
700 mbhc->zl < MAX_IMPED) &&
701 (mbhc->zr > mbhc->mbhc_cfg->linein_th &&
702 mbhc->zr < MAX_IMPED) &&
703 (jack_type == SND_JACK_HEADPHONE)) {
704 jack_type = SND_JACK_LINEOUT;
705 mbhc->current_plug = MBHC_PLUG_TYPE_HIGH_HPH;
706 if (mbhc->hph_status) {
707 mbhc->hph_status &= ~(SND_JACK_HEADSET |
708 SND_JACK_LINEOUT |
709 SND_JACK_UNSUPPORTED);
710 wcd_mbhc_jack_report(mbhc,
711 &mbhc->headset_jack,
712 mbhc->hph_status,
713 WCD_MBHC_JACK_MASK);
714 }
715 pr_debug("%s: Marking jack type as SND_JACK_LINEOUT\n",
716 __func__);
717 }
718 }
719
720 mbhc->hph_status |= jack_type;
721
722 pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
723 jack_type, mbhc->hph_status);
724 wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
725 (mbhc->hph_status | SND_JACK_MECHANICAL),
726 WCD_MBHC_JACK_MASK);
727 wcd_mbhc_clr_and_turnon_hph_padac(mbhc);
728 }
729 pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status);
730}
731
732static bool wcd_mbhc_detect_anc_plug_type(struct wcd_mbhc *mbhc)
733{
734 bool anc_mic_found = false;
735 u16 val, hs_comp_res, btn_status = 0;
736 unsigned long retry = 0;
737 int valid_plug_cnt = 0, invalid_plug_cnt = 0;
738 int btn_status_cnt = 0;
739 bool is_check_btn_press = false;
740
741
742 if (mbhc->mbhc_cfg->anc_micbias < MIC_BIAS_1 ||
743 mbhc->mbhc_cfg->anc_micbias > MIC_BIAS_4)
744 return false;
745
746 if (!mbhc->mbhc_cb->mbhc_micbias_control)
747 return false;
748
749 WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, val);
750
751 if (val)
752 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
753
754 mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
755 mbhc->mbhc_cfg->anc_micbias,
756 MICB_ENABLE);
757 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x2);
758 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 1);
759 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
760 /*
761 * wait for button debounce time 20ms. If 4-pole plug is inserted
762 * into 5-pole jack, then there will be a button press interrupt
763 * during anc plug detection. In that case though Hs_comp_res is 0,
764 * it should not be declared as ANC plug type
765 */
766 usleep_range(20000, 20100);
767
768 /*
769 * After enabling FSM, to handle slow insertion scenarios,
770 * check hs_comp_result for few times to see if the IN3 voltage
771 * is below the Vref
772 */
773 do {
774 if (wcd_swch_level_remove(mbhc)) {
775 pr_debug("%s: Switch level is low\n", __func__);
776 goto exit;
777 }
778 pr_debug("%s: Retry attempt %lu\n", __func__, retry + 1);
779 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
780
781 if (!hs_comp_res) {
782 valid_plug_cnt++;
783 is_check_btn_press = true;
784 } else
785 invalid_plug_cnt++;
786 /* Wait 1ms before taking another reading */
787 usleep_range(1000, 1100);
788
789 WCD_MBHC_REG_READ(WCD_MBHC_FSM_STATUS, btn_status);
790 if (btn_status)
791 btn_status_cnt++;
792
793 retry++;
794 } while (retry < ANC_DETECT_RETRY_CNT);
795
796 pr_debug("%s: valid: %d, invalid: %d, btn_status_cnt: %d\n",
797 __func__, valid_plug_cnt, invalid_plug_cnt, btn_status_cnt);
798
799 /* decision logic */
800 if ((valid_plug_cnt > invalid_plug_cnt) && is_check_btn_press &&
801 (btn_status_cnt == 0))
802 anc_mic_found = true;
803exit:
804 if (!val)
805 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
806
807 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 0);
808
809 mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
810 mbhc->mbhc_cfg->anc_micbias,
811 MICB_DISABLE);
812 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x0);
813 pr_debug("%s: anc mic %sfound\n", __func__,
814 anc_mic_found ? "" : "not ");
815 return anc_mic_found;
816}
817
818static void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc,
819 enum wcd_mbhc_plug_type plug_type)
820{
821 bool anc_mic_found = false;
822 enum snd_jack_types jack_type;
823
824 pr_debug("%s: enter current_plug(%d) new_plug(%d)\n",
825 __func__, mbhc->current_plug, plug_type);
826
827 WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
828
829 if (mbhc->current_plug == plug_type) {
830 pr_debug("%s: cable already reported, exit\n", __func__);
831 goto exit;
832 }
833
834 if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
835 /*
836 * Nothing was reported previously
837 * report a headphone or unsupported
838 */
839 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
840 } else if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
841 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
842 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
843 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
844 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
845 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED);
846 } else if (plug_type == MBHC_PLUG_TYPE_HEADSET) {
847 if (mbhc->mbhc_cfg->enable_anc_mic_detect)
848 anc_mic_found = wcd_mbhc_detect_anc_plug_type(mbhc);
849
850 jack_type = SND_JACK_HEADSET;
851 if (anc_mic_found)
852 jack_type = SND_JACK_ANC_HEADPHONE;
853
854 /*
855 * If Headphone was reported previously, this will
856 * only report the mic line
857 */
858 wcd_mbhc_report_plug(mbhc, 1, jack_type);
859 } else if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
860 if (mbhc->mbhc_cfg->detect_extn_cable) {
861 /* High impedance device found. Report as LINEOUT */
862 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
863 pr_debug("%s: setup mic trigger for further detection\n",
864 __func__);
865
866 /* Disable HW FSM and current source */
867 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
868 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
869 /* Setup for insertion detection */
870 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
871 1);
872 /*
873 * Enable HPHL trigger and MIC Schmitt triggers
874 * and request for elec insertion interrupts
875 */
876 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC,
877 3);
878 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
879 true);
880 } else {
881 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
882 }
883 } else {
884 WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
885 mbhc->current_plug, plug_type);
886 }
887exit:
888 pr_debug("%s: leave\n", __func__);
889}
890
891/* To determine if cross connection occurred */
892static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
893{
894 u16 swap_res = 0;
895 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_NONE;
896 s16 reg1 = 0;
897 bool hphl_sch_res = 0, hphr_sch_res = 0;
898
899 if (wcd_swch_level_remove(mbhc)) {
900 pr_debug("%s: Switch level is low\n", __func__);
901 return -EINVAL;
902 }
903
904 /* If PA is enabled, dont check for cross-connection */
905 if (mbhc->mbhc_cb->hph_pa_on_status)
906 if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec))
907 return false;
908
909 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, reg1);
910 /*
911 * Check if there is any cross connection,
912 * Micbias and schmitt trigger (HPHL-HPHR)
913 * needs to be enabled. For some codecs like wcd9335,
914 * pull-up will already be enabled when this function
915 * is called for cross-connection identification. No
916 * need to enable micbias in that case.
917 */
918 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
919 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 2);
920
921 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, swap_res);
922 pr_debug("%s: swap_res%x\n", __func__, swap_res);
923
924 /*
925 * Read reg hphl and hphr schmitt result with cross connection
926 * bit. These bits will both be "0" in case of cross connection
927 * otherwise, they stay at 1
928 */
929 WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch_res);
930 WCD_MBHC_REG_READ(WCD_MBHC_HPHR_SCHMT_RESULT, hphr_sch_res);
931 if (!(hphl_sch_res || hphr_sch_res)) {
932 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
933 pr_debug("%s: Cross connection identified\n", __func__);
934 } else {
935 pr_debug("%s: No Cross connection found\n", __func__);
936 }
937
938 /* Disable schmitt trigger and restore micbias */
939 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, reg1);
940 pr_debug("%s: leave, plug type: %d\n", __func__, plug_type);
941
942 return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false;
943}
944
945static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
946{
947 struct snd_soc_codec *codec = mbhc->codec;
948 int delay = 0, rc;
949 bool ret = false;
950 u16 hs_comp_res;
951 bool is_spl_hs = false;
952
953 /*
954 * Increase micbias to 2.7V to detect headsets with
955 * threshold on microphone
956 */
957 if (mbhc->mbhc_cb->mbhc_micbias_control &&
958 !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
959 pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n",
960 __func__);
961 return false;
962 } else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
963 rc = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec,
964 MIC_BIAS_2, true);
965 if (rc) {
966 pr_err("%s: Micbias control for thr mic failed, rc: %d\n",
967 __func__, rc);
968 return false;
969 }
970 }
971
972 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
973
974 pr_debug("%s: special headset, start register writes\n", __func__);
975
976 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
977 while (!is_spl_hs) {
978 if (mbhc->hs_detect_work_stop) {
979 pr_debug("%s: stop requested: %d\n", __func__,
980 mbhc->hs_detect_work_stop);
981 break;
982 }
983 delay = delay + 50;
984 if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) {
985 mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
986 MBHC_COMMON_MICB_PRECHARGE,
987 true);
988 mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
989 MBHC_COMMON_MICB_SET_VAL,
990 true);
991 }
992 /* Wait for 50msec for MICBIAS to settle down */
993 msleep(50);
994 if (mbhc->mbhc_cb->set_auto_zeroing)
995 mbhc->mbhc_cb->set_auto_zeroing(codec, true);
996 /* Wait for 50msec for FSM to update result values */
997 msleep(50);
998 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
999 if (!(hs_comp_res)) {
1000 pr_debug("%s: Special headset detected in %d msecs\n",
1001 __func__, (delay * 2));
1002 is_spl_hs = true;
1003 }
1004 if (delay == SPECIAL_HS_DETECT_TIME_MS) {
1005 pr_debug("%s: Spl headset did not get detect in 4 sec\n",
1006 __func__);
1007 break;
1008 }
1009 }
1010 if (is_spl_hs) {
1011 pr_debug("%s: Headset with threshold found\n", __func__);
1012 mbhc->micbias_enable = true;
1013 ret = true;
1014 }
1015 if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
1016 mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
1017 MBHC_COMMON_MICB_PRECHARGE,
1018 false);
1019 if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable)
1020 mbhc->mbhc_cb->set_micbias_value(codec);
1021 if (mbhc->mbhc_cb->set_auto_zeroing)
1022 mbhc->mbhc_cb->set_auto_zeroing(codec, false);
1023
1024 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
1025 !mbhc->micbias_enable)
1026 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(codec, MIC_BIAS_2,
1027 false);
1028
1029 pr_debug("%s: leave, micb_enable: %d\n", __func__,
1030 mbhc->micbias_enable);
1031 return ret;
1032}
1033
1034static void wcd_mbhc_update_fsm_source(struct wcd_mbhc *mbhc,
1035 enum wcd_mbhc_plug_type plug_type)
1036{
1037 bool micbias2;
1038
1039 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
1040 MIC_BIAS_2);
1041 switch (plug_type) {
1042 case MBHC_PLUG_TYPE_HEADPHONE:
1043 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
1044 break;
1045 case MBHC_PLUG_TYPE_HEADSET:
1046 case MBHC_PLUG_TYPE_ANC_HEADPHONE:
1047 if (!mbhc->is_hs_recording && !micbias2)
1048 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
1049 break;
1050 default:
1051 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
1052 break;
1053
1054 };
1055}
1056
1057static void wcd_enable_mbhc_supply(struct wcd_mbhc *mbhc,
1058 enum wcd_mbhc_plug_type plug_type)
1059{
1060
1061 struct snd_soc_codec *codec = mbhc->codec;
1062
1063 /*
1064 * Do not disable micbias if recording is going on or
1065 * headset is inserted on the other side of the extn
1066 * cable. If headset has been detected current source
1067 * needs to be kept enabled for button detection to work.
1068 * If the accessory type is invalid or unsupported, we
1069 * dont need to enable either of them.
1070 */
1071 if (det_extn_cable_en && mbhc->is_extn_cable &&
1072 mbhc->mbhc_cb && mbhc->mbhc_cb->extn_use_mb &&
1073 mbhc->mbhc_cb->extn_use_mb(codec)) {
1074 if (plug_type == MBHC_PLUG_TYPE_HEADPHONE ||
1075 plug_type == MBHC_PLUG_TYPE_HEADSET)
1076 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
1077 } else {
1078 if (plug_type == MBHC_PLUG_TYPE_HEADSET) {
1079 if (mbhc->is_hs_recording || mbhc->micbias_enable)
1080 wcd_enable_curr_micbias(mbhc,
1081 WCD_MBHC_EN_MB);
1082 else if ((test_bit(WCD_MBHC_EVENT_PA_HPHL,
1083 &mbhc->event_state)) ||
1084 (test_bit(WCD_MBHC_EVENT_PA_HPHR,
1085 &mbhc->event_state)))
1086 wcd_enable_curr_micbias(mbhc,
1087 WCD_MBHC_EN_PULLUP);
1088 else
1089 wcd_enable_curr_micbias(mbhc,
1090 WCD_MBHC_EN_CS);
1091 } else if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
1092 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
1093 } else {
1094 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_NONE);
1095 }
1096 }
1097}
1098
1099static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc,
1100 int *spl_hs_cnt)
1101{
1102 u16 hs_comp_res_1_8v = 0, hs_comp_res_2_7v = 0;
1103 bool spl_hs = false;
1104
1105 if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
1106 goto exit;
1107
1108 /* Read back hs_comp_res @ 1.8v Micbias */
1109 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_1_8v);
1110 if (!hs_comp_res_1_8v) {
1111 spl_hs = false;
1112 goto exit;
1113 }
1114
1115 /* Bump up MB2 to 2.7v */
1116 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
1117 mbhc->mbhc_cfg->mbhc_micbias, true);
1118 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
1119 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
1120 usleep_range(10000, 10100);
1121
1122 /* Read back HS_COMP_RESULT */
1123 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_2_7v);
1124 if (!hs_comp_res_2_7v && hs_comp_res_1_8v)
1125 spl_hs = true;
1126
1127 if (spl_hs && spl_hs_cnt)
1128 *spl_hs_cnt += 1;
1129
1130 /* MB2 back to 1.8v */
1131 if (*spl_hs_cnt != WCD_MBHC_SPL_HS_CNT) {
1132 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
1133 mbhc->mbhc_cfg->mbhc_micbias, false);
1134 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
1135 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
1136 usleep_range(10000, 10100);
1137 }
1138
1139 if (spl_hs)
1140 pr_debug("%s: Detected special HS (%d)\n", __func__, spl_hs);
1141
1142exit:
1143 return spl_hs;
1144}
1145
1146static void wcd_correct_swch_plug(struct work_struct *work)
1147{
1148 struct wcd_mbhc *mbhc;
1149 struct snd_soc_codec *codec;
1150 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
1151 unsigned long timeout;
1152 u16 hs_comp_res = 0, hphl_sch = 0, mic_sch = 0, btn_result = 0;
1153 bool wrk_complete = false;
1154 int pt_gnd_mic_swap_cnt = 0;
1155 int no_gnd_mic_swap_cnt = 0;
1156 bool is_pa_on = false, spl_hs = false;
1157 bool micbias2 = false;
1158 bool micbias1 = false;
1159 int ret = 0;
1160 int rc, spl_hs_count = 0;
1161
1162 pr_debug("%s: enter\n", __func__);
1163
1164 mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
1165 codec = mbhc->codec;
1166
1167 /*
1168 * Enable micbias/pullup for detection in correct work.
1169 * This work will get scheduled from detect_plug_type which
1170 * will already request for pullup/micbias. If the pullup/micbias
1171 * is handled with ref-counts by individual codec drivers, there is
1172 * no need to enabale micbias/pullup here
1173 */
1174
1175 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
1176
1177
1178 if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
1179 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
1180 goto correct_plug_type;
1181 }
1182
1183 /* Enable HW FSM */
1184 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
1185 /*
1186 * Check for any button press interrupts before starting 3-sec
1187 * loop.
1188 */
1189 rc = wait_for_completion_timeout(&mbhc->btn_press_compl,
1190 msecs_to_jiffies(WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS));
1191
1192 WCD_MBHC_REG_READ(WCD_MBHC_BTN_RESULT, btn_result);
1193 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
1194
1195 if (!rc) {
1196 pr_debug("%s No btn press interrupt\n", __func__);
1197 if (!btn_result && !hs_comp_res)
1198 plug_type = MBHC_PLUG_TYPE_HEADSET;
1199 else if (!btn_result && hs_comp_res)
1200 plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1201 else
1202 plug_type = MBHC_PLUG_TYPE_INVALID;
1203 } else {
1204 if (!btn_result && !hs_comp_res)
1205 plug_type = MBHC_PLUG_TYPE_HEADPHONE;
1206 else
1207 plug_type = MBHC_PLUG_TYPE_INVALID;
1208 }
1209
1210 pr_debug("%s: Valid plug found, plug type is %d\n",
1211 __func__, plug_type);
1212 if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
1213 plug_type == MBHC_PLUG_TYPE_HEADPHONE) &&
1214 (!wcd_swch_level_remove(mbhc))) {
1215 WCD_MBHC_RSC_LOCK(mbhc);
1216 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1217 WCD_MBHC_RSC_UNLOCK(mbhc);
1218 }
1219
1220correct_plug_type:
1221
1222 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
1223 while (!time_after(jiffies, timeout)) {
1224 if (mbhc->hs_detect_work_stop) {
1225 pr_debug("%s: stop requested: %d\n", __func__,
1226 mbhc->hs_detect_work_stop);
1227 wcd_enable_curr_micbias(mbhc,
1228 WCD_MBHC_EN_NONE);
1229 if (mbhc->micbias_enable) {
1230 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
1231 mbhc->codec, MIC_BIAS_2, false);
1232 if (mbhc->mbhc_cb->set_micbias_value)
1233 mbhc->mbhc_cb->set_micbias_value(
1234 mbhc->codec);
1235 mbhc->micbias_enable = false;
1236 }
1237 goto exit;
1238 }
1239 if (mbhc->btn_press_intr) {
1240 wcd_cancel_btn_work(mbhc);
1241 mbhc->btn_press_intr = false;
1242 }
1243 /* Toggle FSM */
1244 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
1245 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
1246
1247 /* allow sometime and re-check stop requested again */
1248 msleep(20);
1249 if (mbhc->hs_detect_work_stop) {
1250 pr_debug("%s: stop requested: %d\n", __func__,
1251 mbhc->hs_detect_work_stop);
1252 wcd_enable_curr_micbias(mbhc,
1253 WCD_MBHC_EN_NONE);
1254 if (mbhc->micbias_enable) {
1255 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
1256 mbhc->codec, MIC_BIAS_2, false);
1257 if (mbhc->mbhc_cb->set_micbias_value)
1258 mbhc->mbhc_cb->set_micbias_value(
1259 mbhc->codec);
1260 mbhc->micbias_enable = false;
1261 }
1262 goto exit;
1263 }
1264 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
1265
1266 pr_debug("%s: hs_comp_res: %x\n", __func__, hs_comp_res);
1267 if (mbhc->mbhc_cb->hph_pa_on_status)
1268 is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(codec);
1269
1270 /*
1271 * instead of hogging system by contineous polling, wait for
1272 * sometime and re-check stop request again.
1273 */
1274 msleep(180);
1275 if (hs_comp_res && (spl_hs_count < WCD_MBHC_SPL_HS_CNT)) {
1276 spl_hs = wcd_mbhc_check_for_spl_headset(mbhc,
1277 &spl_hs_count);
1278
1279 if (spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
1280 hs_comp_res = 0;
1281 spl_hs = true;
1282 mbhc->micbias_enable = true;
1283 }
1284 }
1285
1286 if ((!hs_comp_res) && (!is_pa_on)) {
1287 /* Check for cross connection*/
1288 ret = wcd_check_cross_conn(mbhc);
1289 if (ret < 0) {
1290 continue;
1291 } else if (ret > 0) {
1292 pt_gnd_mic_swap_cnt++;
1293 no_gnd_mic_swap_cnt = 0;
1294 if (pt_gnd_mic_swap_cnt <
1295 GND_MIC_SWAP_THRESHOLD) {
1296 continue;
1297 } else if (pt_gnd_mic_swap_cnt >
1298 GND_MIC_SWAP_THRESHOLD) {
1299 /*
1300 * This is due to GND/MIC switch didn't
1301 * work, Report unsupported plug.
1302 */
1303 pr_debug("%s: switch did not work\n",
1304 __func__);
1305 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1306 goto report;
1307 } else {
1308 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1309 }
1310 } else {
1311 no_gnd_mic_swap_cnt++;
1312 pt_gnd_mic_swap_cnt = 0;
1313 plug_type = MBHC_PLUG_TYPE_HEADSET;
1314 if ((no_gnd_mic_swap_cnt <
1315 GND_MIC_SWAP_THRESHOLD) &&
1316 (spl_hs_count != WCD_MBHC_SPL_HS_CNT)) {
1317 continue;
1318 } else {
1319 no_gnd_mic_swap_cnt = 0;
1320 }
1321 }
1322 if ((pt_gnd_mic_swap_cnt == GND_MIC_SWAP_THRESHOLD) &&
1323 (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
1324 /*
1325 * if switch is toggled, check again,
1326 * otherwise report unsupported plug
1327 */
1328 if (mbhc->mbhc_cfg->swap_gnd_mic &&
1329 mbhc->mbhc_cfg->swap_gnd_mic(codec)) {
1330 pr_debug("%s: US_EU gpio present,flip switch\n"
1331 , __func__);
1332 continue;
1333 }
1334 }
1335 }
1336
1337 WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
1338 WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
1339 if (hs_comp_res && !(hphl_sch || mic_sch)) {
1340 pr_debug("%s: cable is extension cable\n", __func__);
1341 plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
1342 wrk_complete = true;
1343 } else {
1344 pr_debug("%s: cable might be headset: %d\n", __func__,
1345 plug_type);
1346 if (!(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
1347 plug_type = MBHC_PLUG_TYPE_HEADSET;
1348 /*
1349 * Report headset only if not already reported
1350 * and if there is not button press without
1351 * release
1352 */
1353 if (((mbhc->current_plug !=
1354 MBHC_PLUG_TYPE_HEADSET) &&
1355 (mbhc->current_plug !=
1356 MBHC_PLUG_TYPE_ANC_HEADPHONE)) &&
1357 !wcd_swch_level_remove(mbhc) &&
1358 !mbhc->btn_press_intr) {
1359 pr_debug("%s: cable is %sheadset\n",
1360 __func__,
1361 ((spl_hs_count ==
1362 WCD_MBHC_SPL_HS_CNT) ?
1363 "special ":""));
1364 goto report;
1365 }
1366 }
1367 wrk_complete = false;
1368 }
1369 }
1370 if (!wrk_complete && mbhc->btn_press_intr) {
1371 pr_debug("%s: Can be slow insertion of headphone\n", __func__);
1372 wcd_cancel_btn_work(mbhc);
1373 plug_type = MBHC_PLUG_TYPE_HEADPHONE;
1374 }
1375 /*
1376 * If plug_tye is headset, we might have already reported either in
1377 * detect_plug-type or in above while loop, no need to report again
1378 */
1379 if (!wrk_complete && ((plug_type == MBHC_PLUG_TYPE_HEADSET) ||
1380 (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE))) {
1381 pr_debug("%s: plug_type:0x%x already reported\n",
1382 __func__, mbhc->current_plug);
1383 goto enable_supply;
1384 }
1385
1386 if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH &&
1387 (!det_extn_cable_en)) {
1388 if (wcd_is_special_headset(mbhc)) {
1389 pr_debug("%s: Special headset found %d\n",
1390 __func__, plug_type);
1391 plug_type = MBHC_PLUG_TYPE_HEADSET;
1392 goto report;
1393 }
1394 }
1395
1396report:
1397 if (wcd_swch_level_remove(mbhc)) {
1398 pr_debug("%s: Switch level is low\n", __func__);
1399 goto exit;
1400 }
1401 if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP && mbhc->btn_press_intr) {
1402 pr_debug("%s: insertion of headphone with swap\n", __func__);
1403 wcd_cancel_btn_work(mbhc);
1404 plug_type = MBHC_PLUG_TYPE_HEADPHONE;
1405 }
1406 pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n",
1407 __func__, plug_type, wrk_complete,
1408 mbhc->btn_press_intr);
1409 WCD_MBHC_RSC_LOCK(mbhc);
1410 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
1411 WCD_MBHC_RSC_UNLOCK(mbhc);
1412enable_supply:
1413 if (mbhc->mbhc_cb->mbhc_micbias_control)
1414 wcd_mbhc_update_fsm_source(mbhc, plug_type);
1415 else
1416 wcd_enable_mbhc_supply(mbhc, plug_type);
1417exit:
1418 if (mbhc->mbhc_cb->mbhc_micbias_control &&
1419 !mbhc->micbias_enable)
1420 mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
1421 MICB_DISABLE);
1422 if (mbhc->mbhc_cb->micbias_enable_status) {
1423 micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
1424 MIC_BIAS_1);
1425 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
1426 MIC_BIAS_2);
1427 }
1428
1429 if (mbhc->mbhc_cfg->detect_extn_cable &&
1430 ((plug_type == MBHC_PLUG_TYPE_HEADPHONE) ||
1431 (plug_type == MBHC_PLUG_TYPE_HEADSET)) &&
1432 !mbhc->hs_detect_work_stop) {
1433 WCD_MBHC_RSC_LOCK(mbhc);
1434 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, true);
1435 WCD_MBHC_RSC_UNLOCK(mbhc);
1436 }
1437 if (mbhc->mbhc_cb->set_cap_mode)
1438 mbhc->mbhc_cb->set_cap_mode(codec, micbias1, micbias2);
1439
1440 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
1441 mbhc->mbhc_cb->hph_pull_down_ctrl(codec, true);
1442
1443 mbhc->mbhc_cb->lock_sleep(mbhc, false);
1444 pr_debug("%s: leave\n", __func__);
1445}
1446
1447/* called under codec_resource_lock acquisition */
1448static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
1449{
1450 struct snd_soc_codec *codec = mbhc->codec;
1451 enum wcd_mbhc_plug_type plug_type;
1452 bool micbias1 = false;
1453 int cross_conn;
1454 int try = 0;
1455
1456 pr_debug("%s: enter\n", __func__);
1457 WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
1458
1459 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
1460 mbhc->mbhc_cb->hph_pull_down_ctrl(codec, false);
1461
1462 if (mbhc->mbhc_cb->micbias_enable_status)
1463 micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
1464 MIC_BIAS_1);
1465
1466 if (mbhc->mbhc_cb->set_cap_mode)
1467 mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true);
1468
1469 if (mbhc->mbhc_cb->mbhc_micbias_control)
1470 mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
1471 MICB_ENABLE);
1472 else
1473 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
1474
1475 do {
1476 cross_conn = wcd_check_cross_conn(mbhc);
1477 try++;
1478 } while (try < GND_MIC_SWAP_THRESHOLD);
1479
1480 if (cross_conn > 0) {
1481 pr_debug("%s: cross con found, start polling\n",
1482 __func__);
1483 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
1484 if (!mbhc->current_plug)
1485 mbhc->current_plug = plug_type;
1486 pr_debug("%s: Plug found, plug type is %d\n",
1487 __func__, plug_type);
1488 }
1489
1490 /* Re-initialize button press completion object */
1491 reinit_completion(&mbhc->btn_press_compl);
1492 wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
1493 pr_debug("%s: leave\n", __func__);
1494}
1495
1496static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc)
1497{
1498 bool detection_type = 0;
1499 bool micbias1 = false;
1500 struct snd_soc_codec *codec = mbhc->codec;
1501
1502 dev_dbg(codec->dev, "%s: enter\n", __func__);
1503
1504 WCD_MBHC_RSC_LOCK(mbhc);
1505
1506 mbhc->in_swch_irq_handler = true;
1507
1508 /* cancel pending button press */
1509 if (wcd_cancel_btn_work(mbhc))
1510 pr_debug("%s: button press is canceled\n", __func__);
1511
1512 WCD_MBHC_REG_READ(WCD_MBHC_MECH_DETECTION_TYPE, detection_type);
1513
1514 /* Set the detection type appropriately */
1515 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MECH_DETECTION_TYPE,
1516 !detection_type);
1517
1518 pr_debug("%s: mbhc->current_plug: %d detection_type: %d\n", __func__,
1519 mbhc->current_plug, detection_type);
1520 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
1521
1522 if (mbhc->mbhc_cb->micbias_enable_status)
1523 micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
1524 MIC_BIAS_1);
1525
1526 if ((mbhc->current_plug == MBHC_PLUG_TYPE_NONE) &&
1527 detection_type) {
1528 /* Make sure MASTER_BIAS_CTL is enabled */
1529 mbhc->mbhc_cb->mbhc_bias(codec, true);
1530
1531 if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
1532 mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
1533 MBHC_COMMON_MICB_TAIL_CURR, true);
1534
1535 if (!mbhc->mbhc_cfg->hs_ext_micbias &&
1536 mbhc->mbhc_cb->micb_internal)
1537 /*
1538 * Enable Tx2 RBias if the headset
1539 * is using internal micbias
1540 */
1541 mbhc->mbhc_cb->micb_internal(codec, 1, true);
1542
1543 /* Remove micbias pulldown */
1544 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_PULLDOWN_CTRL, 0);
1545 /* Apply trim if needed on the device */
1546 if (mbhc->mbhc_cb->trim_btn_reg)
1547 mbhc->mbhc_cb->trim_btn_reg(codec);
1548 /* Enable external voltage source to micbias if present */
1549 if (mbhc->mbhc_cb->enable_mb_source)
1550 mbhc->mbhc_cb->enable_mb_source(mbhc, true);
1551 mbhc->btn_press_intr = false;
1552 wcd_mbhc_detect_plug_type(mbhc);
1553 } else if ((mbhc->current_plug != MBHC_PLUG_TYPE_NONE)
1554 && !detection_type) {
1555 /* Disable external voltage source to micbias if present */
1556 if (mbhc->mbhc_cb->enable_mb_source)
1557 mbhc->mbhc_cb->enable_mb_source(mbhc, false);
1558 /* Disable HW FSM */
1559 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
1560 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
1561 if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
1562 mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec,
1563 MBHC_COMMON_MICB_TAIL_CURR, false);
1564
1565 if (mbhc->mbhc_cb->set_cap_mode)
1566 mbhc->mbhc_cb->set_cap_mode(codec, micbias1, false);
1567
1568 mbhc->btn_press_intr = false;
1569 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
1570 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM,
1571 false);
1572 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
1573 false);
1574 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
1575 1);
1576 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
1577 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
1578 } else if (mbhc->current_plug == MBHC_PLUG_TYPE_GND_MIC_SWAP) {
1579 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED);
1580 } else if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
1581 /* make sure to turn off Rbias */
1582 if (mbhc->mbhc_cb->micb_internal)
1583 mbhc->mbhc_cb->micb_internal(codec, 1, false);
1584
1585 /* Pulldown micbias */
1586 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_PULLDOWN_CTRL, 1);
1587 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM,
1588 false);
1589 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
1590 false);
1591 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
1592 1);
1593 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
1594 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_HEADSET);
1595 } else if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH) {
1596 mbhc->is_extn_cable = false;
1597 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM,
1598 false);
1599 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
1600 false);
1601 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
1602 1);
1603 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
1604 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_LINEOUT);
1605 } else if (mbhc->current_plug == MBHC_PLUG_TYPE_ANC_HEADPHONE) {
1606 mbhc->mbhc_cb->irq_control(codec,
1607 mbhc->intr_ids->mbhc_hs_rem_intr,
1608 false);
1609 mbhc->mbhc_cb->irq_control(codec,
1610 mbhc->intr_ids->mbhc_hs_ins_intr,
1611 false);
1612 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
1613 0);
1614 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
1615 wcd_mbhc_report_plug(mbhc, 0, SND_JACK_ANC_HEADPHONE);
1616 }
1617 } else if (!detection_type) {
1618 /* Disable external voltage source to micbias if present */
1619 if (mbhc->mbhc_cb->enable_mb_source)
1620 mbhc->mbhc_cb->enable_mb_source(mbhc, false);
1621 /* Disable HW FSM */
1622 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
1623 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
1624 }
1625
1626 mbhc->in_swch_irq_handler = false;
1627 WCD_MBHC_RSC_UNLOCK(mbhc);
1628 pr_debug("%s: leave\n", __func__);
1629}
1630
1631static irqreturn_t wcd_mbhc_mech_plug_detect_irq(int irq, void *data)
1632{
1633 int r = IRQ_HANDLED;
1634 struct wcd_mbhc *mbhc = data;
1635
1636 pr_debug("%s: enter\n", __func__);
1637 if (unlikely((mbhc->mbhc_cb->lock_sleep(mbhc, true)) == false)) {
1638 pr_warn("%s: failed to hold suspend\n", __func__);
1639 r = IRQ_NONE;
1640 } else {
1641 /* Call handler */
1642 wcd_mbhc_swch_irq_handler(mbhc);
1643 mbhc->mbhc_cb->lock_sleep(mbhc, false);
1644 }
1645 pr_debug("%s: leave %d\n", __func__, r);
1646 return r;
1647}
1648
1649static int wcd_mbhc_get_button_mask(struct wcd_mbhc *mbhc)
1650{
1651 int mask = 0;
1652 int btn;
1653
1654 btn = mbhc->mbhc_cb->map_btn_code_to_num(mbhc->codec);
1655
1656 switch (btn) {
1657 case 0:
1658 mask = SND_JACK_BTN_0;
1659 break;
1660 case 1:
1661 mask = SND_JACK_BTN_1;
1662 break;
1663 case 2:
1664 mask = SND_JACK_BTN_2;
1665 break;
1666 case 3:
1667 mask = SND_JACK_BTN_3;
1668 break;
1669 case 4:
1670 mask = SND_JACK_BTN_4;
1671 break;
1672 case 5:
1673 mask = SND_JACK_BTN_5;
1674 break;
1675 default:
1676 break;
1677 }
1678
1679 return mask;
1680}
1681
1682static irqreturn_t wcd_mbhc_hs_ins_irq(int irq, void *data)
1683{
1684 struct wcd_mbhc *mbhc = data;
1685 bool detection_type = 0, hphl_sch = 0, mic_sch = 0;
1686 u16 elect_result = 0;
1687 static u16 hphl_trigerred;
1688 static u16 mic_trigerred;
1689
1690 pr_debug("%s: enter\n", __func__);
1691 if (!mbhc->mbhc_cfg->detect_extn_cable) {
1692 pr_debug("%s: Returning as Extension cable feature not enabled\n",
1693 __func__);
1694 return IRQ_HANDLED;
1695 }
1696 WCD_MBHC_RSC_LOCK(mbhc);
1697
1698 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_DETECTION_TYPE, detection_type);
1699 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, elect_result);
1700
1701 pr_debug("%s: detection_type %d, elect_result %x\n", __func__,
1702 detection_type, elect_result);
1703 if (detection_type) {
1704 /* check if both Left and MIC Schmitt triggers are triggered */
1705 WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
1706 WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
1707 if (hphl_sch && mic_sch) {
1708 /* Go for plug type determination */
1709 pr_debug("%s: Go for plug type determination\n",
1710 __func__);
1711 goto determine_plug;
1712
1713 } else {
1714 if (mic_sch) {
1715 mic_trigerred++;
1716 pr_debug("%s: Insertion MIC trigerred %d\n",
1717 __func__, mic_trigerred);
1718 WCD_MBHC_REG_UPDATE_BITS(
1719 WCD_MBHC_ELECT_SCHMT_ISRC,
1720 0);
1721 msleep(20);
1722 WCD_MBHC_REG_UPDATE_BITS(
1723 WCD_MBHC_ELECT_SCHMT_ISRC,
1724 1);
1725 }
1726 if (hphl_sch) {
1727 hphl_trigerred++;
1728 pr_debug("%s: Insertion HPHL trigerred %d\n",
1729 __func__, hphl_trigerred);
1730 }
1731 if (mic_trigerred && hphl_trigerred) {
1732 /* Go for plug type determination */
1733 pr_debug("%s: Go for plug type determination\n",
1734 __func__);
1735 goto determine_plug;
1736 }
1737 }
1738 }
1739 WCD_MBHC_RSC_UNLOCK(mbhc);
1740 pr_debug("%s: leave\n", __func__);
1741 return IRQ_HANDLED;
1742
1743determine_plug:
1744 /*
1745 * Disable HPHL trigger and MIC Schmitt triggers.
1746 * Setup for insertion detection.
1747 */
1748 pr_debug("%s: Disable insertion interrupt\n", __func__);
1749 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
1750 false);
1751
1752 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
1753 hphl_trigerred = 0;
1754 mic_trigerred = 0;
1755 mbhc->is_extn_cable = true;
1756 mbhc->btn_press_intr = false;
1757 wcd_mbhc_detect_plug_type(mbhc);
1758 WCD_MBHC_RSC_UNLOCK(mbhc);
1759 pr_debug("%s: leave\n", __func__);
1760 return IRQ_HANDLED;
1761}
1762
1763static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data)
1764{
1765 struct wcd_mbhc *mbhc = data;
1766 u8 hs_comp_result = 0, hphl_sch = 0, mic_sch = 0;
1767 static u16 hphl_trigerred;
1768 static u16 mic_trigerred;
1769 unsigned long timeout;
1770 bool removed = true;
1771 int retry = 0;
1772
1773 pr_debug("%s: enter\n", __func__);
1774
1775 WCD_MBHC_RSC_LOCK(mbhc);
1776
1777 timeout = jiffies +
1778 msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
1779 do {
1780 retry++;
1781 /*
1782 * read the result register every 10ms to look for
1783 * any change in HS_COMP_RESULT bit
1784 */
1785 usleep_range(10000, 10100);
1786 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result);
1787 pr_debug("%s: Check result reg for fake removal: hs_comp_res %x\n",
1788 __func__, hs_comp_result);
1789 if ((!hs_comp_result) &&
1790 retry > FAKE_REM_RETRY_ATTEMPTS) {
1791 removed = false;
1792 break;
1793 }
1794 } while (!time_after(jiffies, timeout));
1795
1796 if (wcd_swch_level_remove(mbhc)) {
1797 pr_debug("%s: Switch level is low ", __func__);
1798 goto exit;
1799 }
1800 pr_debug("%s: headset %s actually removed\n", __func__,
1801 removed ? "" : "not ");
1802
1803 WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
1804 WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
1805 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result);
1806
1807 if (removed) {
1808 if (!(hphl_sch && mic_sch && hs_comp_result)) {
1809 /*
1810 * extension cable is still plugged in
1811 * report it as LINEOUT device
1812 */
1813 goto report_unplug;
1814 } else {
1815 if (!mic_sch) {
1816 mic_trigerred++;
1817 pr_debug("%s: Removal MIC trigerred %d\n",
1818 __func__, mic_trigerred);
1819 }
1820 if (!hphl_sch) {
1821 hphl_trigerred++;
1822 pr_debug("%s: Removal HPHL trigerred %d\n",
1823 __func__, hphl_trigerred);
1824 }
1825 if (mic_trigerred && hphl_trigerred) {
1826 /*
1827 * extension cable is still plugged in
1828 * report it as LINEOUT device
1829 */
1830 goto report_unplug;
1831 }
1832 }
1833 }
1834exit:
1835 WCD_MBHC_RSC_UNLOCK(mbhc);
1836 pr_debug("%s: leave\n", __func__);
1837 return IRQ_HANDLED;
1838
1839report_unplug:
1840
1841 /* cancel pending button press */
1842 if (wcd_cancel_btn_work(mbhc))
1843 pr_debug("%s: button press is canceled\n", __func__);
1844 /* cancel correct work function */
1845 wcd_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
1846
1847 pr_debug("%s: Report extension cable\n", __func__);
1848 wcd_mbhc_report_plug(mbhc, 1, SND_JACK_LINEOUT);
1849 /*
1850 * If PA is enabled HPHL schmitt trigger can
1851 * be unreliable, make sure to disable it
1852 */
1853 if (test_bit(WCD_MBHC_EVENT_PA_HPHL,
1854 &mbhc->event_state))
1855 wcd_mbhc_set_and_turnoff_hph_padac(mbhc);
1856 /*
1857 * Disable HPHL trigger and MIC Schmitt triggers.
1858 * Setup for insertion detection.
1859 */
1860 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM,
1861 false);
1862 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_NONE);
1863 /* Disable HW FSM */
1864 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
1865 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 3);
1866
1867 /* Set the detection type appropriately */
1868 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, 1);
1869 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
1870 true);
1871 hphl_trigerred = 0;
1872 mic_trigerred = 0;
1873 WCD_MBHC_RSC_UNLOCK(mbhc);
1874 pr_debug("%s: leave\n", __func__);
1875 return IRQ_HANDLED;
1876}
1877
1878static void wcd_btn_lpress_fn(struct work_struct *work)
1879{
1880 struct delayed_work *dwork;
1881 struct wcd_mbhc *mbhc;
1882 s16 btn_result = 0;
1883
1884 pr_debug("%s: Enter\n", __func__);
1885
1886 dwork = to_delayed_work(work);
1887 mbhc = container_of(dwork, struct wcd_mbhc, mbhc_btn_dwork);
1888
1889 WCD_MBHC_REG_READ(WCD_MBHC_BTN_RESULT, btn_result);
1890 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET) {
1891 pr_debug("%s: Reporting long button press event, btn_result: %d\n",
1892 __func__, btn_result);
1893 wcd_mbhc_jack_report(mbhc, &mbhc->button_jack,
1894 mbhc->buttons_pressed, mbhc->buttons_pressed);
1895 }
1896 pr_debug("%s: leave\n", __func__);
1897 mbhc->mbhc_cb->lock_sleep(mbhc, false);
1898}
1899
1900static bool wcd_mbhc_fw_validate(const void *data, size_t size)
1901{
1902 u32 cfg_offset;
1903 struct wcd_mbhc_btn_detect_cfg *btn_cfg;
1904 struct firmware_cal fw;
1905
1906 fw.data = (void *)data;
1907 fw.size = size;
1908
1909 if (fw.size < WCD_MBHC_CAL_MIN_SIZE)
1910 return false;
1911
1912 /*
1913 * Previous check guarantees that there is enough fw data up
1914 * to num_btn
1915 */
1916 btn_cfg = WCD_MBHC_CAL_BTN_DET_PTR(fw.data);
1917 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw.data);
1918 if (fw.size < (cfg_offset + WCD_MBHC_CAL_BTN_SZ(btn_cfg)))
1919 return false;
1920
1921 return true;
1922}
1923
1924static irqreturn_t wcd_mbhc_btn_press_handler(int irq, void *data)
1925{
1926 struct wcd_mbhc *mbhc = data;
1927 int mask;
1928 unsigned long msec_val;
1929
1930 pr_debug("%s: enter\n", __func__);
1931 complete(&mbhc->btn_press_compl);
1932 WCD_MBHC_RSC_LOCK(mbhc);
1933 /* send event to sw intr handler*/
1934 mbhc->is_btn_press = true;
1935 wcd_cancel_btn_work(mbhc);
1936 if (wcd_swch_level_remove(mbhc)) {
1937 pr_debug("%s: Switch level is low ", __func__);
1938 goto done;
1939 }
1940 mbhc->btn_press_intr = true;
1941
1942 msec_val = jiffies_to_msecs(jiffies - mbhc->jiffies_atreport);
1943 pr_debug("%s: msec_val = %ld\n", __func__, msec_val);
1944 if (msec_val < MBHC_BUTTON_PRESS_THRESHOLD_MIN) {
1945 pr_debug("%s: Too short, ignore button press\n", __func__);
1946 goto done;
1947 }
1948
1949 /* If switch interrupt already kicked in, ignore button press */
1950 if (mbhc->in_swch_irq_handler) {
1951 pr_debug("%s: Swtich level changed, ignore button press\n",
1952 __func__);
1953 goto done;
1954 }
1955 if (mbhc->current_plug != MBHC_PLUG_TYPE_HEADSET) {
1956 pr_debug("%s: Plug isn't headset, ignore button press\n",
1957 __func__);
1958 goto done;
1959 }
1960 mask = wcd_mbhc_get_button_mask(mbhc);
1961 mbhc->buttons_pressed |= mask;
1962 mbhc->mbhc_cb->lock_sleep(mbhc, true);
1963 if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
1964 msecs_to_jiffies(400)) == 0) {
1965 WARN(1, "Button pressed twice without release event\n");
1966 mbhc->mbhc_cb->lock_sleep(mbhc, false);
1967 }
1968done:
1969 pr_debug("%s: leave\n", __func__);
1970 WCD_MBHC_RSC_UNLOCK(mbhc);
1971 return IRQ_HANDLED;
1972}
1973
1974static irqreturn_t wcd_mbhc_release_handler(int irq, void *data)
1975{
1976 struct wcd_mbhc *mbhc = data;
1977 int ret;
1978
1979 pr_debug("%s: enter\n", __func__);
1980 WCD_MBHC_RSC_LOCK(mbhc);
1981 if (wcd_swch_level_remove(mbhc)) {
1982 pr_debug("%s: Switch level is low ", __func__);
1983 goto exit;
1984 }
1985
1986 if (mbhc->btn_press_intr) {
1987 mbhc->btn_press_intr = false;
1988 } else {
1989 pr_debug("%s: This release is for fake btn press\n", __func__);
1990 goto exit;
1991 }
1992
1993 /*
1994 * If current plug is headphone then there is no chance to
1995 * get btn release interrupt, so connected cable should be
1996 * headset not headphone.
1997 */
1998 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
1999 wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
2000 goto exit;
2001
2002 }
2003 if (mbhc->buttons_pressed & WCD_MBHC_JACK_BUTTON_MASK) {
2004 ret = wcd_cancel_btn_work(mbhc);
2005 if (ret == 0) {
2006 pr_debug("%s: Reporting long button release event\n",
2007 __func__);
2008 wcd_mbhc_jack_report(mbhc, &mbhc->button_jack,
2009 0, mbhc->buttons_pressed);
2010 } else {
2011 if (mbhc->in_swch_irq_handler) {
2012 pr_debug("%s: Switch irq kicked in, ignore\n",
2013 __func__);
2014 } else {
2015 pr_debug("%s: Reporting btn press\n",
2016 __func__);
2017 wcd_mbhc_jack_report(mbhc,
2018 &mbhc->button_jack,
2019 mbhc->buttons_pressed,
2020 mbhc->buttons_pressed);
2021 pr_debug("%s: Reporting btn release\n",
2022 __func__);
2023 wcd_mbhc_jack_report(mbhc,
2024 &mbhc->button_jack,
2025 0, mbhc->buttons_pressed);
2026 }
2027 }
2028 mbhc->buttons_pressed &= ~WCD_MBHC_JACK_BUTTON_MASK;
2029 }
2030exit:
2031 pr_debug("%s: leave\n", __func__);
2032 WCD_MBHC_RSC_UNLOCK(mbhc);
2033 return IRQ_HANDLED;
2034}
2035
2036static irqreturn_t wcd_mbhc_hphl_ocp_irq(int irq, void *data)
2037{
2038 struct wcd_mbhc *mbhc = data;
2039 int val;
2040
2041 pr_debug("%s: received HPHL OCP irq\n", __func__);
2042 if (mbhc) {
2043 if (mbhc->mbhc_cb->hph_register_recovery) {
2044 if (mbhc->mbhc_cb->hph_register_recovery(mbhc)) {
2045 WCD_MBHC_REG_READ(WCD_MBHC_HPHR_OCP_STATUS,
2046 val);
2047 if ((val != -EINVAL) && val)
2048 mbhc->is_hph_ocp_pending = true;
2049 goto done;
2050 }
2051 }
2052
2053 if (mbhc->hphlocp_cnt < OCP_ATTEMPT) {
2054 mbhc->hphlocp_cnt++;
2055 pr_debug("%s: retry, hphlocp_cnt: %d\n", __func__,
2056 mbhc->hphlocp_cnt);
2057 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0);
2058 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1);
2059 } else {
2060 mbhc->mbhc_cb->irq_control(mbhc->codec,
2061 mbhc->intr_ids->hph_left_ocp,
2062 false);
2063 mbhc->hph_status |= SND_JACK_OC_HPHL;
2064 wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
2065 mbhc->hph_status,
2066 WCD_MBHC_JACK_MASK);
2067 }
2068 } else {
2069 pr_err("%s: Bad wcd9xxx_spmi private data\n", __func__);
2070 }
2071done:
2072 return IRQ_HANDLED;
2073}
2074
2075static irqreturn_t wcd_mbhc_hphr_ocp_irq(int irq, void *data)
2076{
2077 struct wcd_mbhc *mbhc = data;
2078
2079 pr_debug("%s: received HPHR OCP irq\n", __func__);
2080
2081 if (!mbhc) {
2082 pr_err("%s: Bad mbhc private data\n", __func__);
2083 goto done;
2084 }
2085
2086 if (mbhc->is_hph_ocp_pending) {
2087 mbhc->is_hph_ocp_pending = false;
2088 goto done;
2089 }
2090
2091 if (mbhc->mbhc_cb->hph_register_recovery) {
2092 if (mbhc->mbhc_cb->hph_register_recovery(mbhc))
2093 /* register corruption, hence reset registers */
2094 goto done;
2095 }
2096 if (mbhc->hphrocp_cnt < OCP_ATTEMPT) {
2097 mbhc->hphrocp_cnt++;
2098 pr_debug("%s: retry, hphrocp_cnt: %d\n", __func__,
2099 mbhc->hphrocp_cnt);
2100 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 0);
2101 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_OCP_FSM_EN, 1);
2102 } else {
2103 mbhc->mbhc_cb->irq_control(mbhc->codec,
2104 mbhc->intr_ids->hph_right_ocp,
2105 false);
2106 mbhc->hph_status |= SND_JACK_OC_HPHR;
2107 wcd_mbhc_jack_report(mbhc, &mbhc->headset_jack,
2108 mbhc->hph_status, WCD_MBHC_JACK_MASK);
2109 }
2110done:
2111 return IRQ_HANDLED;
2112}
2113
2114static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc)
2115{
2116 int ret = 0;
2117 struct snd_soc_codec *codec = mbhc->codec;
2118
2119 pr_debug("%s: enter\n", __func__);
2120 WCD_MBHC_RSC_LOCK(mbhc);
2121
2122 /* enable HS detection */
2123 if (mbhc->mbhc_cb->hph_pull_up_control)
2124 mbhc->mbhc_cb->hph_pull_up_control(codec, I_DEFAULT);
2125 else
2126 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_CTRL, 3);
2127
2128 if (mbhc->mbhc_cfg->moisture_en && mbhc->mbhc_cb->mbhc_moisture_config)
2129 mbhc->mbhc_cb->mbhc_moisture_config(mbhc);
2130
2131 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PLUG_TYPE, mbhc->hphl_swh);
2132 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_GND_PLUG_TYPE, mbhc->gnd_swh);
2133 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_SW_HPH_LP_100K_TO_GND, 1);
2134 if (mbhc->mbhc_cfg->gnd_det_en && mbhc->mbhc_cb->mbhc_gnd_det_ctrl)
2135 mbhc->mbhc_cb->mbhc_gnd_det_ctrl(codec, true);
2136 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL, 1);
2137 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1);
2138
2139 /* Insertion debounce set to 96ms */
2140 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_INSREM_DBNC, 6);
2141 /* Button Debounce set to 16ms */
2142 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_DBNC, 2);
2143
2144 /* Enable micbias ramp */
2145 if (mbhc->mbhc_cb->mbhc_micb_ramp_control)
2146 mbhc->mbhc_cb->mbhc_micb_ramp_control(codec, true);
2147 /* enable bias */
2148 mbhc->mbhc_cb->mbhc_bias(codec, true);
2149 /* enable MBHC clock */
2150 if (mbhc->mbhc_cb->clk_setup)
2151 mbhc->mbhc_cb->clk_setup(codec, true);
2152
2153 /* program HS_VREF value */
2154 wcd_program_hs_vref(mbhc);
2155
2156 wcd_program_btn_threshold(mbhc, false);
2157
2158 INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
2159
2160 init_completion(&mbhc->btn_press_compl);
2161
2162 WCD_MBHC_RSC_UNLOCK(mbhc);
2163 pr_debug("%s: leave\n", __func__);
2164 return ret;
2165}
2166
2167static void wcd_mbhc_fw_read(struct work_struct *work)
2168{
2169 struct delayed_work *dwork;
2170 struct wcd_mbhc *mbhc;
2171 struct snd_soc_codec *codec;
2172 const struct firmware *fw;
2173 struct firmware_cal *fw_data = NULL;
2174 int ret = -1, retry = 0;
2175 bool use_default_cal = false;
2176
2177 dwork = to_delayed_work(work);
2178 mbhc = container_of(dwork, struct wcd_mbhc, mbhc_firmware_dwork);
2179 codec = mbhc->codec;
2180
2181 while (retry < FW_READ_ATTEMPTS) {
2182 retry++;
2183 pr_debug("%s:Attempt %d to request MBHC firmware\n",
2184 __func__, retry);
2185 if (mbhc->mbhc_cb->get_hwdep_fw_cal)
2186 fw_data = mbhc->mbhc_cb->get_hwdep_fw_cal(mbhc,
2187 WCD9XXX_MBHC_CAL);
2188 if (!fw_data)
2189 ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin",
2190 codec->dev);
2191 /*
2192 * if request_firmware and hwdep cal both fail then
2193 * sleep for 4sec for the userspace to send data to kernel
2194 * retry for few times before bailing out
2195 */
2196 if ((ret != 0) && !fw_data) {
2197 usleep_range(FW_READ_TIMEOUT, FW_READ_TIMEOUT +
2198 WCD_MBHC_USLEEP_RANGE_MARGIN_US);
2199 } else {
2200 pr_debug("%s: MBHC Firmware read successful\n",
2201 __func__);
2202 break;
2203 }
2204 }
2205 if (!fw_data)
2206 pr_debug("%s: using request_firmware\n", __func__);
2207 else
2208 pr_debug("%s: using hwdep cal\n", __func__);
2209
2210 if (ret != 0 && !fw_data) {
2211 pr_err("%s: Cannot load MBHC firmware use default cal\n",
2212 __func__);
2213 use_default_cal = true;
2214 }
2215 if (!use_default_cal) {
2216 const void *data;
2217 size_t size;
2218
2219 if (fw_data) {
2220 data = fw_data->data;
2221 size = fw_data->size;
2222 } else {
2223 data = fw->data;
2224 size = fw->size;
2225 }
2226 if (wcd_mbhc_fw_validate(data, size) == false) {
2227 pr_err("%s: Invalid MBHC cal data size use default cal\n",
2228 __func__);
2229 if (!fw_data)
2230 release_firmware(fw);
2231 } else {
2232 if (fw_data) {
2233 mbhc->mbhc_cfg->calibration =
2234 (void *)fw_data->data;
2235 mbhc->mbhc_cal = fw_data;
2236 } else {
2237 mbhc->mbhc_cfg->calibration =
2238 (void *)fw->data;
2239 mbhc->mbhc_fw = fw;
2240 }
2241 }
2242
2243 }
2244
2245 (void) wcd_mbhc_initialise(mbhc);
2246}
2247
2248int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc)
2249{
2250 enum snd_jack_types type;
2251 int i, ret, result = 0;
2252 int *btn_key_code;
2253
2254 btn_key_code = mbhc->mbhc_cfg->key_code;
2255
2256 for (i = 0 ; i < WCD_MBHC_KEYCODE_NUM ; i++) {
2257 if (btn_key_code[i] != 0) {
2258 switch (i) {
2259 case 0:
2260 type = SND_JACK_BTN_0;
2261 break;
2262 case 1:
2263 type = SND_JACK_BTN_1;
2264 break;
2265 case 2:
2266 type = SND_JACK_BTN_2;
2267 break;
2268 case 3:
2269 type = SND_JACK_BTN_3;
2270 break;
2271 case 4:
2272 type = SND_JACK_BTN_4;
2273 break;
2274 case 5:
2275 type = SND_JACK_BTN_5;
2276 break;
2277 default:
2278 WARN_ONCE(1, "Wrong button number:%d\n", i);
2279 result = -1;
2280 return result;
2281 }
2282 ret = snd_jack_set_key(mbhc->button_jack.jack,
2283 type,
2284 btn_key_code[i]);
2285 if (ret) {
2286 pr_err("%s: Failed to set code for %d\n",
2287 __func__, btn_key_code[i]);
2288 result = -1;
2289 return result;
2290 }
2291 input_set_capability(
2292 mbhc->button_jack.jack->input_dev,
2293 EV_KEY, btn_key_code[i]);
2294 pr_debug("%s: set btn%d key code:%d\n", __func__,
2295 i, btn_key_code[i]);
2296 }
2297 }
2298 if (btn_key_code[0])
2299 mbhc->is_btn_already_regd = true;
2300 return result;
2301}
2302
2303int wcd_mbhc_start(struct wcd_mbhc *mbhc,
2304 struct wcd_mbhc_config *mbhc_cfg)
2305{
2306 int rc = 0;
2307
2308 pr_debug("%s: enter\n", __func__);
2309 /* update the mbhc config */
2310 mbhc->mbhc_cfg = mbhc_cfg;
2311
2312 /* Set btn key code */
2313 if ((!mbhc->is_btn_already_regd) && wcd_mbhc_set_keycode(mbhc))
2314 pr_err("Set btn key code error!!!\n");
2315
2316 if (!mbhc->mbhc_cfg->read_fw_bin ||
2317 (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_fw) ||
2318 (mbhc->mbhc_cfg->read_fw_bin && mbhc->mbhc_cal)) {
2319 rc = wcd_mbhc_initialise(mbhc);
2320 } else {
2321 if (!mbhc->mbhc_fw || !mbhc->mbhc_cal)
2322 schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
2323 usecs_to_jiffies(FW_READ_TIMEOUT));
2324 else
2325 pr_err("%s: Skipping to read mbhc fw, 0x%pK %pK\n",
2326 __func__, mbhc->mbhc_fw, mbhc->mbhc_cal);
2327 }
2328 pr_debug("%s: leave %d\n", __func__, rc);
2329 return rc;
2330}
2331EXPORT_SYMBOL(wcd_mbhc_start);
2332
2333void wcd_mbhc_stop(struct wcd_mbhc *mbhc)
2334{
2335 pr_debug("%s: enter\n", __func__);
2336 if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) {
2337 if (mbhc->mbhc_cb && mbhc->mbhc_cb->skip_imped_detect)
2338 mbhc->mbhc_cb->skip_imped_detect(mbhc->codec);
2339 }
2340 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
2341 mbhc->hph_status = 0;
2342 if (mbhc->mbhc_cb && mbhc->mbhc_cb->irq_control) {
2343 mbhc->mbhc_cb->irq_control(mbhc->codec,
2344 mbhc->intr_ids->hph_left_ocp,
2345 false);
2346 mbhc->mbhc_cb->irq_control(mbhc->codec,
2347 mbhc->intr_ids->hph_right_ocp,
2348 false);
2349 }
2350 if (mbhc->mbhc_fw || mbhc->mbhc_cal) {
2351 cancel_delayed_work_sync(&mbhc->mbhc_firmware_dwork);
2352 if (!mbhc->mbhc_cal)
2353 release_firmware(mbhc->mbhc_fw);
2354 mbhc->mbhc_fw = NULL;
2355 mbhc->mbhc_cal = NULL;
2356 }
2357 pr_debug("%s: leave\n", __func__);
2358}
2359EXPORT_SYMBOL(wcd_mbhc_stop);
2360
2361/*
2362 * wcd_mbhc_init : initialize MBHC internal structures.
2363 *
2364 * NOTE: mbhc->mbhc_cfg is not YET configure so shouldn't be used
2365 */
2366int wcd_mbhc_init(struct wcd_mbhc *mbhc, struct snd_soc_codec *codec,
2367 const struct wcd_mbhc_cb *mbhc_cb,
2368 const struct wcd_mbhc_intr *mbhc_cdc_intr_ids,
2369 struct wcd_mbhc_register *wcd_mbhc_regs,
2370 bool impedance_det_en)
2371{
2372 int ret = 0;
2373 int hph_swh = 0;
2374 int gnd_swh = 0;
2375 struct snd_soc_card *card = codec->component.card;
2376 const char *hph_switch = "qcom,msm-mbhc-hphl-swh";
2377 const char *gnd_switch = "qcom,msm-mbhc-gnd-swh";
2378
2379 pr_debug("%s: enter\n", __func__);
2380
2381 ret = of_property_read_u32(card->dev->of_node, hph_switch, &hph_swh);
2382 if (ret) {
2383 dev_err(card->dev,
2384 "%s: missing %s in dt node\n", __func__, hph_switch);
2385 goto err;
2386 }
2387
2388 ret = of_property_read_u32(card->dev->of_node, gnd_switch, &gnd_swh);
2389 if (ret) {
2390 dev_err(card->dev,
2391 "%s: missing %s in dt node\n", __func__, gnd_switch);
2392 goto err;
2393 }
2394
2395 mbhc->in_swch_irq_handler = false;
2396 mbhc->current_plug = MBHC_PLUG_TYPE_NONE;
2397 mbhc->is_btn_press = false;
2398 mbhc->codec = codec;
2399 mbhc->intr_ids = mbhc_cdc_intr_ids;
2400 mbhc->impedance_detect = impedance_det_en;
2401 mbhc->hphl_swh = hph_swh;
2402 mbhc->gnd_swh = gnd_swh;
2403 mbhc->micbias_enable = false;
2404 mbhc->mbhc_cb = mbhc_cb;
2405 mbhc->btn_press_intr = false;
2406 mbhc->is_hs_recording = false;
2407 mbhc->is_extn_cable = false;
2408 mbhc->hph_type = WCD_MBHC_HPH_NONE;
2409 mbhc->wcd_mbhc_regs = wcd_mbhc_regs;
2410
2411 if (mbhc->intr_ids == NULL) {
2412 pr_err("%s: Interrupt mapping not provided\n", __func__);
2413 return -EINVAL;
2414 }
2415 if (!mbhc->wcd_mbhc_regs) {
2416 dev_err(codec->dev, "%s: mbhc registers are not defined\n",
2417 __func__);
2418 return -EINVAL;
2419 }
2420
2421 /* Check if IRQ and other required callbacks are defined or not */
2422 if (!mbhc_cb || !mbhc_cb->request_irq || !mbhc_cb->irq_control ||
2423 !mbhc_cb->free_irq || !mbhc_cb->map_btn_code_to_num ||
2424 !mbhc_cb->lock_sleep || !mbhc_cb->mbhc_bias ||
2425 !mbhc_cb->set_btn_thr) {
2426 dev_err(codec->dev, "%s: required mbhc callbacks are not defined\n",
2427 __func__);
2428 return -EINVAL;
2429 }
2430
2431 if (mbhc->headset_jack.jack == NULL) {
2432 ret = snd_soc_card_jack_new(codec->component.card,
2433 "Headset Jack", WCD_MBHC_JACK_MASK,
2434 &mbhc->headset_jack, NULL, 0);
2435 if (ret) {
2436 pr_err("%s: Failed to create new jack\n", __func__);
2437 return ret;
2438 }
2439
2440 ret = snd_soc_card_jack_new(codec->component.card,
2441 "Button Jack",
2442 WCD_MBHC_JACK_BUTTON_MASK,
2443 &mbhc->button_jack, NULL, 0);
2444 if (ret) {
2445 pr_err("Failed to create new jack\n");
2446 return ret;
2447 }
2448
2449 ret = snd_jack_set_key(mbhc->button_jack.jack,
2450 SND_JACK_BTN_0,
2451 KEY_MEDIA);
2452 if (ret) {
2453 pr_err("%s: Failed to set code for btn-0\n",
2454 __func__);
2455 return ret;
2456 }
2457
2458 set_bit(INPUT_PROP_NO_DUMMY_RELEASE,
2459 mbhc->button_jack.jack->input_dev->propbit);
2460
2461 INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
2462 wcd_mbhc_fw_read);
2463 INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd_btn_lpress_fn);
2464 }
2465 mutex_init(&mbhc->hphl_pa_lock);
2466 mutex_init(&mbhc->hphr_pa_lock);
2467
2468 /* Register event notifier */
2469 mbhc->nblock.notifier_call = wcd_event_notify;
2470 if (mbhc->mbhc_cb->register_notifier) {
2471 ret = mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock,
2472 true);
2473 if (ret) {
2474 pr_err("%s: Failed to register notifier %d\n",
2475 __func__, ret);
2476 return ret;
2477 }
2478 }
2479
2480 init_waitqueue_head(&mbhc->wait_btn_press);
2481 mutex_init(&mbhc->codec_resource_lock);
2482
2483 ret = mbhc->mbhc_cb->request_irq(codec, mbhc->intr_ids->mbhc_sw_intr,
2484 wcd_mbhc_mech_plug_detect_irq,
2485 "mbhc sw intr", mbhc);
2486 if (ret) {
2487 pr_err("%s: Failed to request irq %d, ret = %d\n", __func__,
2488 mbhc->intr_ids->mbhc_sw_intr, ret);
2489 goto err_mbhc_sw_irq;
2490 }
2491
2492 ret = mbhc->mbhc_cb->request_irq(codec,
2493 mbhc->intr_ids->mbhc_btn_press_intr,
2494 wcd_mbhc_btn_press_handler,
2495 "Button Press detect",
2496 mbhc);
2497 if (ret) {
2498 pr_err("%s: Failed to request irq %d\n", __func__,
2499 mbhc->intr_ids->mbhc_btn_press_intr);
2500 goto err_btn_press_irq;
2501 }
2502
2503 ret = mbhc->mbhc_cb->request_irq(codec,
2504 mbhc->intr_ids->mbhc_btn_release_intr,
2505 wcd_mbhc_release_handler,
2506 "Button Release detect", mbhc);
2507 if (ret) {
2508 pr_err("%s: Failed to request irq %d\n", __func__,
2509 mbhc->intr_ids->mbhc_btn_release_intr);
2510 goto err_btn_release_irq;
2511 }
2512
2513 ret = mbhc->mbhc_cb->request_irq(codec,
2514 mbhc->intr_ids->mbhc_hs_ins_intr,
2515 wcd_mbhc_hs_ins_irq,
2516 "Elect Insert", mbhc);
2517 if (ret) {
2518 pr_err("%s: Failed to request irq %d\n", __func__,
2519 mbhc->intr_ids->mbhc_hs_ins_intr);
2520 goto err_mbhc_hs_ins_irq;
2521 }
2522 mbhc->mbhc_cb->irq_control(codec, mbhc->intr_ids->mbhc_hs_ins_intr,
2523 false);
2524 clear_bit(WCD_MBHC_ELEC_HS_INS, &mbhc->intr_status);
2525
2526 ret = mbhc->mbhc_cb->request_irq(codec,
2527 mbhc->intr_ids->mbhc_hs_rem_intr,
2528 wcd_mbhc_hs_rem_irq,
2529 "Elect Remove", mbhc);
2530 if (ret) {
2531 pr_err("%s: Failed to request irq %d\n", __func__,
2532 mbhc->intr_ids->mbhc_hs_rem_intr);
2533 goto err_mbhc_hs_rem_irq;
2534 }
2535 mbhc->mbhc_cb->irq_control(codec, mbhc->intr_ids->mbhc_hs_rem_intr,
2536 false);
2537 clear_bit(WCD_MBHC_ELEC_HS_REM, &mbhc->intr_status);
2538
2539 ret = mbhc->mbhc_cb->request_irq(codec, mbhc->intr_ids->hph_left_ocp,
2540 wcd_mbhc_hphl_ocp_irq, "HPH_L OCP detect",
2541 mbhc);
2542 if (ret) {
2543 pr_err("%s: Failed to request irq %d\n", __func__,
2544 mbhc->intr_ids->hph_left_ocp);
2545 goto err_hphl_ocp_irq;
2546 }
2547
2548 ret = mbhc->mbhc_cb->request_irq(codec, mbhc->intr_ids->hph_right_ocp,
2549 wcd_mbhc_hphr_ocp_irq, "HPH_R OCP detect",
2550 mbhc);
2551 if (ret) {
2552 pr_err("%s: Failed to request irq %d\n", __func__,
2553 mbhc->intr_ids->hph_right_ocp);
2554 goto err_hphr_ocp_irq;
2555 }
2556
2557 pr_debug("%s: leave ret %d\n", __func__, ret);
2558 return ret;
2559
2560err_hphr_ocp_irq:
2561 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_left_ocp, mbhc);
2562err_hphl_ocp_irq:
2563 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
2564err_mbhc_hs_rem_irq:
2565 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
2566err_mbhc_hs_ins_irq:
2567 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_btn_release_intr,
2568 mbhc);
2569err_btn_release_irq:
2570 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_btn_press_intr,
2571 mbhc);
2572err_btn_press_irq:
2573 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_sw_intr, mbhc);
2574err_mbhc_sw_irq:
2575 if (mbhc->mbhc_cb->register_notifier)
2576 mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false);
2577 mutex_destroy(&mbhc->codec_resource_lock);
2578err:
2579 pr_debug("%s: leave ret %d\n", __func__, ret);
2580 return ret;
2581}
2582EXPORT_SYMBOL(wcd_mbhc_init);
2583
2584void wcd_mbhc_deinit(struct wcd_mbhc *mbhc)
2585{
2586 struct snd_soc_codec *codec = mbhc->codec;
2587
2588 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_sw_intr, mbhc);
2589 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_btn_press_intr,
2590 mbhc);
2591 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_btn_release_intr,
2592 mbhc);
2593 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_hs_ins_intr, mbhc);
2594 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->mbhc_hs_rem_intr, mbhc);
2595 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_left_ocp, mbhc);
2596 mbhc->mbhc_cb->free_irq(codec, mbhc->intr_ids->hph_right_ocp, mbhc);
2597 if (mbhc->mbhc_cb && mbhc->mbhc_cb->register_notifier)
2598 mbhc->mbhc_cb->register_notifier(mbhc, &mbhc->nblock, false);
2599 mutex_destroy(&mbhc->codec_resource_lock);
2600 mutex_destroy(&mbhc->hphl_pa_lock);
2601 mutex_destroy(&mbhc->hphr_pa_lock);
2602}
2603EXPORT_SYMBOL(wcd_mbhc_deinit);
2604
2605MODULE_DESCRIPTION("wcd MBHC v2 module");
2606MODULE_LICENSE("GPL v2");