blob: 49884ebd89bdac8635a70fa9b13bc662e042e32c [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Vatsal Buchaa8f9dc92019-04-18 16:43:08 +05302/* Copyright (c) 2015-2018, 2019, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05303 */
4#include <linux/module.h>
5#include <linux/init.h>
6#include <linux/slab.h>
7#include <linux/of_gpio.h>
8#include <linux/platform_device.h>
9#include <linux/device.h>
10#include <linux/printk.h>
11#include <linux/ratelimit.h>
12#include <linux/list.h>
13#include <linux/bitops.h>
14#include <linux/delay.h>
15#include <linux/pm_runtime.h>
16#include <linux/kernel.h>
17#include <linux/input.h>
18#include <linux/firmware.h>
19#include <linux/completion.h>
20#include <sound/soc.h>
21#include <sound/jack.h>
22#include "wcd-mbhc-legacy.h"
Meng Wang11a25cf2018-10-31 14:11:26 +080023#include <asoc/wcd-mbhc-v2.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053024
25static int det_extn_cable_en;
26module_param(det_extn_cable_en, int, 0664);
27MODULE_PARM_DESC(det_extn_cable_en, "enable/disable extn cable detect");
28
29static bool wcd_mbhc_detect_anc_plug_type(struct wcd_mbhc *mbhc)
30{
31 bool anc_mic_found = false;
32 u16 val, hs_comp_res, btn_status = 0;
33 unsigned long retry = 0;
34 int valid_plug_cnt = 0, invalid_plug_cnt = 0;
35 int btn_status_cnt = 0;
36 bool is_check_btn_press = false;
37
38
39 if (mbhc->mbhc_cfg->anc_micbias < MIC_BIAS_1 ||
40 mbhc->mbhc_cfg->anc_micbias > MIC_BIAS_4)
41 return false;
42
43 if (!mbhc->mbhc_cb->mbhc_micbias_control)
44 return false;
45
46 WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, val);
47
48 if (val)
49 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
50
Meng Wang15c825d2018-09-06 10:49:18 +080051 mbhc->mbhc_cb->mbhc_micbias_control(mbhc->component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053052 mbhc->mbhc_cfg->anc_micbias,
53 MICB_ENABLE);
54 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x2);
55 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 1);
56 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
57 /*
58 * wait for button debounce time 20ms. If 4-pole plug is inserted
59 * into 5-pole jack, then there will be a button press interrupt
60 * during anc plug detection. In that case though Hs_comp_res is 0,
61 * it should not be declared as ANC plug type
62 */
63 usleep_range(20000, 20100);
64
65 /*
66 * After enabling FSM, to handle slow insertion scenarios,
67 * check hs_comp_result for few times to see if the IN3 voltage
68 * is below the Vref
69 */
70 do {
71 if (wcd_swch_level_remove(mbhc)) {
72 pr_debug("%s: Switch level is low\n", __func__);
73 goto exit;
74 }
75 pr_debug("%s: Retry attempt %lu\n", __func__, retry + 1);
76 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
77
78 if (!hs_comp_res) {
79 valid_plug_cnt++;
80 is_check_btn_press = true;
81 } else
82 invalid_plug_cnt++;
83 /* Wait 1ms before taking another reading */
84 usleep_range(1000, 1100);
85
86 WCD_MBHC_REG_READ(WCD_MBHC_FSM_STATUS, btn_status);
87 if (btn_status)
88 btn_status_cnt++;
89
90 retry++;
91 } while (retry < ANC_DETECT_RETRY_CNT);
92
93 pr_debug("%s: valid: %d, invalid: %d, btn_status_cnt: %d\n",
94 __func__, valid_plug_cnt, invalid_plug_cnt, btn_status_cnt);
95
96 /* decision logic */
97 if ((valid_plug_cnt > invalid_plug_cnt) && is_check_btn_press &&
98 (btn_status_cnt == 0))
99 anc_mic_found = true;
100exit:
101 if (!val)
102 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
103
104 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 0);
105
Meng Wang15c825d2018-09-06 10:49:18 +0800106 mbhc->mbhc_cb->mbhc_micbias_control(mbhc->component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530107 mbhc->mbhc_cfg->anc_micbias,
108 MICB_DISABLE);
109 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, 0x0);
110 pr_debug("%s: anc mic %sfound\n", __func__,
111 anc_mic_found ? "" : "not ");
112 return anc_mic_found;
113}
114
115/* To determine if cross connection occurred */
116static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
117{
118 u16 swap_res = 0;
119 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_NONE;
120 s16 reg1 = 0;
121 bool hphl_sch_res = 0, hphr_sch_res = 0;
122
123 if (wcd_swch_level_remove(mbhc)) {
124 pr_debug("%s: Switch level is low\n", __func__);
125 return -EINVAL;
126 }
127
128 /* If PA is enabled, dont check for cross-connection */
129 if (mbhc->mbhc_cb->hph_pa_on_status)
Meng Wang15c825d2018-09-06 10:49:18 +0800130 if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->component))
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530131 return false;
132
133 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, reg1);
134 /*
135 * Check if there is any cross connection,
136 * Micbias and schmitt trigger (HPHL-HPHR)
137 * needs to be enabled. For some codecs like wcd9335,
138 * pull-up will already be enabled when this function
139 * is called for cross-connection identification. No
140 * need to enable micbias in that case.
141 */
142 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
143 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 2);
144
145 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, swap_res);
146 pr_debug("%s: swap_res%x\n", __func__, swap_res);
147
148 /*
149 * Read reg hphl and hphr schmitt result with cross connection
150 * bit. These bits will both be "0" in case of cross connection
151 * otherwise, they stay at 1
152 */
153 WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch_res);
154 WCD_MBHC_REG_READ(WCD_MBHC_HPHR_SCHMT_RESULT, hphr_sch_res);
155 if (!(hphl_sch_res || hphr_sch_res)) {
156 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
157 pr_debug("%s: Cross connection identified\n", __func__);
158 } else {
159 pr_debug("%s: No Cross connection found\n", __func__);
160 }
161
162 /* Disable schmitt trigger and restore micbias */
163 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, reg1);
164 pr_debug("%s: leave, plug type: %d\n", __func__, plug_type);
165
166 return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false;
167}
168
169static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
170{
Meng Wang15c825d2018-09-06 10:49:18 +0800171 struct snd_soc_component *component = mbhc->component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530172 int delay = 0, rc;
173 bool ret = false;
174 u16 hs_comp_res;
175 bool is_spl_hs = false;
176
177 /*
178 * Increase micbias to 2.7V to detect headsets with
179 * threshold on microphone
180 */
181 if (mbhc->mbhc_cb->mbhc_micbias_control &&
182 !mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
183 pr_debug("%s: callback fn micb_ctrl_thr_mic not defined\n",
184 __func__);
185 return false;
186 } else if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic) {
Meng Wang15c825d2018-09-06 10:49:18 +0800187 rc = mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530188 MIC_BIAS_2, true);
189 if (rc) {
190 pr_err("%s: Micbias control for thr mic failed, rc: %d\n",
191 __func__, rc);
192 return false;
193 }
194 }
195
196 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
197
198 pr_debug("%s: special headset, start register writes\n", __func__);
199
200 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
201 while (!is_spl_hs) {
202 if (mbhc->hs_detect_work_stop) {
203 pr_debug("%s: stop requested: %d\n", __func__,
204 mbhc->hs_detect_work_stop);
205 break;
206 }
207 delay = delay + 50;
208 if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) {
Meng Wang15c825d2018-09-06 10:49:18 +0800209 mbhc->mbhc_cb->mbhc_common_micb_ctrl(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530210 MBHC_COMMON_MICB_PRECHARGE,
211 true);
Meng Wang15c825d2018-09-06 10:49:18 +0800212 mbhc->mbhc_cb->mbhc_common_micb_ctrl(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530213 MBHC_COMMON_MICB_SET_VAL,
214 true);
215 }
216 /* Wait for 50msec for MICBIAS to settle down */
217 msleep(50);
218 if (mbhc->mbhc_cb->set_auto_zeroing)
Meng Wang15c825d2018-09-06 10:49:18 +0800219 mbhc->mbhc_cb->set_auto_zeroing(component, true);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530220 /* Wait for 50msec for FSM to update result values */
221 msleep(50);
222 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
223 if (!(hs_comp_res)) {
224 pr_debug("%s: Special headset detected in %d msecs\n",
225 __func__, (delay * 2));
226 is_spl_hs = true;
227 }
228 if (delay == SPECIAL_HS_DETECT_TIME_MS) {
229 pr_debug("%s: Spl headset didn't get detect in 4 sec\n",
230 __func__);
231 break;
232 }
233 }
234 if (is_spl_hs) {
235 pr_debug("%s: Headset with threshold found\n", __func__);
236 mbhc->micbias_enable = true;
237 ret = true;
238 }
239 if (mbhc->mbhc_cb->mbhc_common_micb_ctrl)
Meng Wang15c825d2018-09-06 10:49:18 +0800240 mbhc->mbhc_cb->mbhc_common_micb_ctrl(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530241 MBHC_COMMON_MICB_PRECHARGE,
242 false);
243 if (mbhc->mbhc_cb->set_micbias_value && !mbhc->micbias_enable)
Meng Wang15c825d2018-09-06 10:49:18 +0800244 mbhc->mbhc_cb->set_micbias_value(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530245 if (mbhc->mbhc_cb->set_auto_zeroing)
Meng Wang15c825d2018-09-06 10:49:18 +0800246 mbhc->mbhc_cb->set_auto_zeroing(component, false);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530247
248 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
249 !mbhc->micbias_enable)
Meng Wang15c825d2018-09-06 10:49:18 +0800250 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(component, MIC_BIAS_2,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530251 false);
252
253 pr_debug("%s: leave, micb_enable: %d\n", __func__,
254 mbhc->micbias_enable);
255 return ret;
256}
257
258static void wcd_mbhc_update_fsm_source(struct wcd_mbhc *mbhc,
259 enum wcd_mbhc_plug_type plug_type)
260{
261 bool micbias2;
262
263 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
264 MIC_BIAS_2);
265 switch (plug_type) {
266 case MBHC_PLUG_TYPE_HEADPHONE:
267 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
268 break;
269 case MBHC_PLUG_TYPE_HEADSET:
270 case MBHC_PLUG_TYPE_ANC_HEADPHONE:
271 if (!mbhc->is_hs_recording && !micbias2)
272 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
273 break;
274 default:
275 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
276 break;
277
278 };
279}
280
281static void wcd_enable_mbhc_supply(struct wcd_mbhc *mbhc,
282 enum wcd_mbhc_plug_type plug_type)
283{
284
Meng Wang15c825d2018-09-06 10:49:18 +0800285 struct snd_soc_component *component = mbhc->component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530286
287 /*
288 * Do not disable micbias if recording is going on or
289 * headset is inserted on the other side of the extn
290 * cable. If headset has been detected current source
291 * needs to be kept enabled for button detection to work.
292 * If the accessory type is invalid or unsupported, we
293 * dont need to enable either of them.
294 */
295 if (det_extn_cable_en && mbhc->is_extn_cable &&
296 mbhc->mbhc_cb && mbhc->mbhc_cb->extn_use_mb &&
Meng Wang15c825d2018-09-06 10:49:18 +0800297 mbhc->mbhc_cb->extn_use_mb(component)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530298 if (plug_type == MBHC_PLUG_TYPE_HEADPHONE ||
299 plug_type == MBHC_PLUG_TYPE_HEADSET)
300 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
301 } else {
302 if (plug_type == MBHC_PLUG_TYPE_HEADSET) {
303 if (mbhc->is_hs_recording || mbhc->micbias_enable) {
304 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
305 } else if ((test_bit(WCD_MBHC_EVENT_PA_HPHL,
306 &mbhc->event_state)) ||
307 (test_bit(WCD_MBHC_EVENT_PA_HPHR,
308 &mbhc->event_state))) {
309 wcd_enable_curr_micbias(mbhc,
310 WCD_MBHC_EN_PULLUP);
311 } else {
312 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
313 }
314 } else if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
315 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_CS);
316 } else {
317 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_NONE);
318 }
319 }
320}
321
322static bool wcd_mbhc_check_for_spl_headset(struct wcd_mbhc *mbhc,
323 int *spl_hs_cnt)
324{
325 u16 hs_comp_res_1_8v = 0, hs_comp_res_2_7v = 0;
326 bool spl_hs = false;
327
328 if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
329 goto done;
330
331 if (!spl_hs_cnt) {
332 pr_err("%s: spl_hs_cnt is NULL\n", __func__);
333 goto done;
334 }
335 /* Read back hs_comp_res @ 1.8v Micbias */
336 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_1_8v);
337 if (!hs_comp_res_1_8v) {
338 spl_hs = false;
339 goto done;
340 }
341
342 /* Bump up MB2 to 2.7v */
Meng Wang15c825d2018-09-06 10:49:18 +0800343 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530344 mbhc->mbhc_cfg->mbhc_micbias, true);
345 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
346 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
347 usleep_range(10000, 10100);
348
349 /* Read back HS_COMP_RESULT */
350 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res_2_7v);
351 if (!hs_comp_res_2_7v && hs_comp_res_1_8v)
352 spl_hs = true;
353
354 if (spl_hs)
355 *spl_hs_cnt += 1;
356
357 /* MB2 back to 1.8v */
358 if (*spl_hs_cnt != WCD_MBHC_SPL_HS_CNT) {
Meng Wang15c825d2018-09-06 10:49:18 +0800359 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530360 mbhc->mbhc_cfg->mbhc_micbias, false);
361 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
362 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
363 usleep_range(10000, 10100);
364 }
365
366 if (spl_hs)
367 pr_debug("%s: Detected special HS (%d)\n", __func__, spl_hs);
368
369done:
370 return spl_hs;
371}
372
373/* should be called under interrupt context that hold suspend */
374static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
375 struct work_struct *work)
376{
377 pr_debug("%s: scheduling correct_swch_plug\n", __func__);
378 WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
379 mbhc->hs_detect_work_stop = false;
380 mbhc->mbhc_cb->lock_sleep(mbhc, true);
381 schedule_work(work);
382}
383
384/* called under codec_resource_lock acquisition */
385static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
386 struct work_struct *work)
387{
388 pr_debug("%s: Canceling correct_plug_swch\n", __func__);
389 mbhc->hs_detect_work_stop = true;
390 WCD_MBHC_RSC_UNLOCK(mbhc);
391 if (cancel_work_sync(work)) {
392 pr_debug("%s: correct_plug_swch is canceled\n",
393 __func__);
394 mbhc->mbhc_cb->lock_sleep(mbhc, false);
395 }
396 WCD_MBHC_RSC_LOCK(mbhc);
397}
398
399/* called under codec_resource_lock acquisition */
400static void wcd_mbhc_detect_plug_type(struct wcd_mbhc *mbhc)
401{
Meng Wang15c825d2018-09-06 10:49:18 +0800402 struct snd_soc_component *component = mbhc->component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530403 bool micbias1 = false;
404
405 pr_debug("%s: enter\n", __func__);
406 WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
407
408 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
Meng Wang15c825d2018-09-06 10:49:18 +0800409 mbhc->mbhc_cb->hph_pull_down_ctrl(component, false);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530410
411 if (mbhc->mbhc_cb->micbias_enable_status)
412 micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
413 MIC_BIAS_1);
414
415 if (mbhc->mbhc_cb->set_cap_mode)
Meng Wang15c825d2018-09-06 10:49:18 +0800416 mbhc->mbhc_cb->set_cap_mode(component, micbias1, true);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530417
418 if (mbhc->mbhc_cb->mbhc_micbias_control)
Meng Wang15c825d2018-09-06 10:49:18 +0800419 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530420 MICB_ENABLE);
421 else
422 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
423
424 /* Re-initialize button press completion object */
425 reinit_completion(&mbhc->btn_press_compl);
426 wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
427 pr_debug("%s: leave\n", __func__);
428}
429
430static void wcd_correct_swch_plug(struct work_struct *work)
431{
432 struct wcd_mbhc *mbhc;
Meng Wang15c825d2018-09-06 10:49:18 +0800433 struct snd_soc_component *component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530434 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
435 unsigned long timeout;
436 u16 hs_comp_res = 0, hphl_sch = 0, mic_sch = 0, btn_result = 0;
437 bool wrk_complete = false;
438 int pt_gnd_mic_swap_cnt = 0;
439 int no_gnd_mic_swap_cnt = 0;
440 bool is_pa_on = false, spl_hs = false, spl_hs_reported = false;
441 bool micbias2 = false;
442 bool micbias1 = false;
443 int ret = 0;
444 int rc, spl_hs_count = 0;
445 int cross_conn;
446 int try = 0;
447
448 pr_debug("%s: enter\n", __func__);
449
450 mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
Meng Wang15c825d2018-09-06 10:49:18 +0800451 component = mbhc->component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530452
453 /*
454 * Enable micbias/pullup for detection in correct work.
455 * This work will get scheduled from detect_plug_type which
456 * will already request for pullup/micbias. If the pullup/micbias
457 * is handled with ref-counts by individual codec drivers, there is
458 * no need to enabale micbias/pullup here
459 */
460
461 wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB);
462
463 /* Enable HW FSM */
464 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
465 /*
466 * Check for any button press interrupts before starting 3-sec
467 * loop.
468 */
469 rc = wait_for_completion_timeout(&mbhc->btn_press_compl,
470 msecs_to_jiffies(WCD_MBHC_BTN_PRESS_COMPL_TIMEOUT_MS));
471
472 WCD_MBHC_REG_READ(WCD_MBHC_BTN_RESULT, btn_result);
473 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
474
475 if (!rc) {
476 pr_debug("%s No btn press interrupt\n", __func__);
477 if (!btn_result && !hs_comp_res)
478 plug_type = MBHC_PLUG_TYPE_HEADSET;
479 else if (!btn_result && hs_comp_res)
480 plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
481 else
482 plug_type = MBHC_PLUG_TYPE_INVALID;
483 } else {
484 if (!btn_result && !hs_comp_res)
485 plug_type = MBHC_PLUG_TYPE_HEADPHONE;
486 else
487 plug_type = MBHC_PLUG_TYPE_INVALID;
488 }
489
490 do {
491 cross_conn = wcd_check_cross_conn(mbhc);
492 try++;
Karthikeyan Mani5392d802017-11-08 20:32:38 -0800493 } while (try < mbhc->swap_thr);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530494
495 /*
496 * Check for cross connection 4 times.
497 * Consider the result of the fourth iteration.
498 */
499 if (cross_conn > 0) {
500 pr_debug("%s: cross con found, start polling\n",
501 __func__);
502 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
503 pr_debug("%s: Plug found, plug type is %d\n",
504 __func__, plug_type);
505 goto correct_plug_type;
506 }
507
508 if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
509 plug_type == MBHC_PLUG_TYPE_HEADPHONE) &&
510 (!wcd_swch_level_remove(mbhc))) {
511 WCD_MBHC_RSC_LOCK(mbhc);
512 if (mbhc->current_plug == MBHC_PLUG_TYPE_HIGH_HPH)
513 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE,
514 0);
515 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
516 WCD_MBHC_RSC_UNLOCK(mbhc);
517 }
518
519correct_plug_type:
520
521 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
522 while (!time_after(jiffies, timeout)) {
523 if (mbhc->hs_detect_work_stop) {
524 pr_debug("%s: stop requested: %d\n", __func__,
525 mbhc->hs_detect_work_stop);
526 wcd_enable_curr_micbias(mbhc,
527 WCD_MBHC_EN_NONE);
Ramprasad Katkam76c5b452018-01-25 14:57:20 +0530528 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
529 mbhc->micbias_enable) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530530 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
Meng Wang15c825d2018-09-06 10:49:18 +0800531 mbhc->component, MIC_BIAS_2, false);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530532 if (mbhc->mbhc_cb->set_micbias_value)
533 mbhc->mbhc_cb->set_micbias_value(
Meng Wang15c825d2018-09-06 10:49:18 +0800534 mbhc->component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530535 mbhc->micbias_enable = false;
536 }
537 goto exit;
538 }
539 if (mbhc->btn_press_intr) {
540 wcd_cancel_btn_work(mbhc);
541 mbhc->btn_press_intr = false;
542 }
543 /* Toggle FSM */
544 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
545 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
546
547 /* allow sometime and re-check stop requested again */
548 msleep(20);
549 if (mbhc->hs_detect_work_stop) {
550 pr_debug("%s: stop requested: %d\n", __func__,
551 mbhc->hs_detect_work_stop);
552 wcd_enable_curr_micbias(mbhc,
553 WCD_MBHC_EN_NONE);
Ramprasad Katkam76c5b452018-01-25 14:57:20 +0530554 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic &&
555 mbhc->micbias_enable) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530556 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
Meng Wang15c825d2018-09-06 10:49:18 +0800557 mbhc->component, MIC_BIAS_2, false);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530558 if (mbhc->mbhc_cb->set_micbias_value)
559 mbhc->mbhc_cb->set_micbias_value(
Meng Wang15c825d2018-09-06 10:49:18 +0800560 mbhc->component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530561 mbhc->micbias_enable = false;
562 }
563 goto exit;
564 }
565 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_res);
566
567 pr_debug("%s: hs_comp_res: %x\n", __func__, hs_comp_res);
568 if (mbhc->mbhc_cb->hph_pa_on_status)
Meng Wang15c825d2018-09-06 10:49:18 +0800569 is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530570
571 /*
572 * instead of hogging system by contineous polling, wait for
573 * sometime and re-check stop request again.
574 */
575 msleep(180);
576 if (hs_comp_res && (spl_hs_count < WCD_MBHC_SPL_HS_CNT)) {
577 spl_hs = wcd_mbhc_check_for_spl_headset(mbhc,
578 &spl_hs_count);
579
580 if (spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
581 hs_comp_res = 0;
582 spl_hs = true;
583 mbhc->micbias_enable = true;
584 }
585 }
586
587 if ((!hs_comp_res) && (!is_pa_on)) {
588 /* Check for cross connection*/
589 ret = wcd_check_cross_conn(mbhc);
590 if (ret < 0) {
591 continue;
592 } else if (ret > 0) {
593 pt_gnd_mic_swap_cnt++;
594 no_gnd_mic_swap_cnt = 0;
595 if (pt_gnd_mic_swap_cnt <
Karthikeyan Mani5392d802017-11-08 20:32:38 -0800596 mbhc->swap_thr) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530597 continue;
598 } else if (pt_gnd_mic_swap_cnt >
Karthikeyan Mani5392d802017-11-08 20:32:38 -0800599 mbhc->swap_thr) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530600 /*
601 * This is due to GND/MIC switch didn't
602 * work, Report unsupported plug.
603 */
604 pr_debug("%s: switch didn't work\n",
605 __func__);
606 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
607 goto report;
608 } else {
609 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
610 }
611 } else {
612 no_gnd_mic_swap_cnt++;
613 pt_gnd_mic_swap_cnt = 0;
614 plug_type = MBHC_PLUG_TYPE_HEADSET;
615 if ((no_gnd_mic_swap_cnt <
616 GND_MIC_SWAP_THRESHOLD) &&
617 (spl_hs_count != WCD_MBHC_SPL_HS_CNT)) {
618 continue;
619 } else {
620 no_gnd_mic_swap_cnt = 0;
621 }
622 }
Karthikeyan Mani5392d802017-11-08 20:32:38 -0800623 if ((pt_gnd_mic_swap_cnt == mbhc->swap_thr) &&
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530624 (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
625 /*
626 * if switch is toggled, check again,
627 * otherwise report unsupported plug
628 */
629 if (mbhc->mbhc_cfg->swap_gnd_mic &&
Meng Wang15c825d2018-09-06 10:49:18 +0800630 mbhc->mbhc_cfg->swap_gnd_mic(component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530631 true)) {
632 pr_debug("%s: US_EU gpio present,flip switch\n"
633 , __func__);
634 continue;
635 }
636 }
637 }
638
639 WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
640 WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
641 if (hs_comp_res && !(hphl_sch || mic_sch)) {
642 pr_debug("%s: cable is extension cable\n", __func__);
643 plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
644 wrk_complete = true;
645 } else {
646 pr_debug("%s: cable might be headset: %d\n", __func__,
647 plug_type);
648 if (!(plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP)) {
649 plug_type = MBHC_PLUG_TYPE_HEADSET;
650 if (!spl_hs_reported &&
651 spl_hs_count == WCD_MBHC_SPL_HS_CNT) {
652 spl_hs_reported = true;
653 WCD_MBHC_RSC_LOCK(mbhc);
654 wcd_mbhc_find_plug_and_report(mbhc,
655 plug_type);
656 WCD_MBHC_RSC_UNLOCK(mbhc);
657 continue;
658 } else if (spl_hs_reported)
659 continue;
660 /*
661 * Report headset only if not already reported
662 * and if there is not button press without
663 * release
664 */
665 if (((mbhc->current_plug !=
666 MBHC_PLUG_TYPE_HEADSET) &&
667 (mbhc->current_plug !=
668 MBHC_PLUG_TYPE_ANC_HEADPHONE)) &&
669 !wcd_swch_level_remove(mbhc) &&
670 !mbhc->btn_press_intr) {
671 pr_debug("%s: cable is %sheadset\n",
672 __func__,
673 ((spl_hs_count ==
674 WCD_MBHC_SPL_HS_CNT) ?
675 "special ":""));
676 goto report;
677 }
678 }
679 wrk_complete = false;
680 }
681 }
682 if (!wrk_complete && mbhc->btn_press_intr) {
683 pr_debug("%s: Can be slow insertion of headphone\n", __func__);
684 wcd_cancel_btn_work(mbhc);
Vatsal Buchad6d62b82017-12-12 14:22:31 +0530685 /* Report as headphone only if previously
686 * not reported as lineout
687 */
688 if (!mbhc->force_linein)
689 plug_type = MBHC_PLUG_TYPE_HEADPHONE;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530690 }
691 /*
692 * If plug_tye is headset, we might have already reported either in
693 * detect_plug-type or in above while loop, no need to report again
694 */
695 if (!wrk_complete && ((plug_type == MBHC_PLUG_TYPE_HEADSET) ||
696 (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE))) {
697 pr_debug("%s: plug_type:0x%x already reported\n",
698 __func__, mbhc->current_plug);
699 goto enable_supply;
700 }
701
702 if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH &&
703 (!det_extn_cable_en)) {
704 if (wcd_is_special_headset(mbhc)) {
705 pr_debug("%s: Special headset found %d\n",
706 __func__, plug_type);
707 plug_type = MBHC_PLUG_TYPE_HEADSET;
708 goto report;
709 }
710 }
711
712report:
713 if (wcd_swch_level_remove(mbhc)) {
714 pr_debug("%s: Switch level is low\n", __func__);
715 goto exit;
716 }
717 if (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP && mbhc->btn_press_intr) {
718 pr_debug("%s: insertion of headphone with swap\n", __func__);
719 wcd_cancel_btn_work(mbhc);
720 plug_type = MBHC_PLUG_TYPE_HEADPHONE;
721 }
722 pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n",
723 __func__, plug_type, wrk_complete,
724 mbhc->btn_press_intr);
725 WCD_MBHC_RSC_LOCK(mbhc);
726 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
727 WCD_MBHC_RSC_UNLOCK(mbhc);
728enable_supply:
729 if (mbhc->mbhc_cb->mbhc_micbias_control)
730 wcd_mbhc_update_fsm_source(mbhc, plug_type);
731 else
732 wcd_enable_mbhc_supply(mbhc, plug_type);
733exit:
734 if (mbhc->mbhc_cb->mbhc_micbias_control &&
735 !mbhc->micbias_enable)
Meng Wang15c825d2018-09-06 10:49:18 +0800736 mbhc->mbhc_cb->mbhc_micbias_control(component, MIC_BIAS_2,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530737 MICB_DISABLE);
738
739 /*
740 * If plug type is corrected from special headset to headphone,
741 * clear the micbias enable flag, set micbias back to 1.8V and
742 * disable micbias.
743 */
744 if (plug_type == MBHC_PLUG_TYPE_HEADPHONE &&
745 mbhc->micbias_enable) {
746 if (mbhc->mbhc_cb->mbhc_micbias_control)
747 mbhc->mbhc_cb->mbhc_micbias_control(
Meng Wang15c825d2018-09-06 10:49:18 +0800748 component, MIC_BIAS_2,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530749 MICB_DISABLE);
750 if (mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
751 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
Meng Wang15c825d2018-09-06 10:49:18 +0800752 component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530753 MIC_BIAS_2, false);
754 if (mbhc->mbhc_cb->set_micbias_value) {
Meng Wang15c825d2018-09-06 10:49:18 +0800755 mbhc->mbhc_cb->set_micbias_value(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530756 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MICB_CTRL, 0);
757 }
758 mbhc->micbias_enable = false;
759 }
760
761 if (mbhc->mbhc_cb->micbias_enable_status) {
762 micbias1 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
763 MIC_BIAS_1);
764 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
765 MIC_BIAS_2);
766 }
767
768 if (mbhc->mbhc_cfg->detect_extn_cable &&
769 ((plug_type == MBHC_PLUG_TYPE_HEADPHONE) ||
770 (plug_type == MBHC_PLUG_TYPE_HEADSET)) &&
771 !mbhc->hs_detect_work_stop) {
772 WCD_MBHC_RSC_LOCK(mbhc);
773 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, true);
774 WCD_MBHC_RSC_UNLOCK(mbhc);
775 }
776 if (mbhc->mbhc_cb->set_cap_mode)
Meng Wang15c825d2018-09-06 10:49:18 +0800777 mbhc->mbhc_cb->set_cap_mode(component, micbias1, micbias2);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530778
779 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
Meng Wang15c825d2018-09-06 10:49:18 +0800780 mbhc->mbhc_cb->hph_pull_down_ctrl(component, true);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530781
782 mbhc->mbhc_cb->lock_sleep(mbhc, false);
783 pr_debug("%s: leave\n", __func__);
784}
785
786static irqreturn_t wcd_mbhc_hs_rem_irq(int irq, void *data)
787{
788 struct wcd_mbhc *mbhc = data;
789 u8 hs_comp_result = 0, hphl_sch = 0, mic_sch = 0;
790 static u16 hphl_trigerred;
791 static u16 mic_trigerred;
792 unsigned long timeout;
793 bool removed = true;
794 int retry = 0;
Meng Wang6f901622017-09-19 10:21:57 +0800795 bool hphpa_on = false;
796 u8 moisture_status = 0;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530797
798 pr_debug("%s: enter\n", __func__);
799
800 WCD_MBHC_RSC_LOCK(mbhc);
801
802 timeout = jiffies +
803 msecs_to_jiffies(WCD_FAKE_REMOVAL_MIN_PERIOD_MS);
804 do {
805 retry++;
806 /*
807 * read the result register every 10ms to look for
808 * any change in HS_COMP_RESULT bit
809 */
810 usleep_range(10000, 10100);
811 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result);
812 pr_debug("%s: Check result reg for fake removal: hs_comp_res %x\n",
813 __func__, hs_comp_result);
814 if ((!hs_comp_result) &&
815 retry > FAKE_REM_RETRY_ATTEMPTS) {
816 removed = false;
817 break;
818 }
819 } while (!time_after(jiffies, timeout));
820
821 if (wcd_swch_level_remove(mbhc)) {
822 pr_debug("%s: Switch level is low ", __func__);
823 goto exit;
824 }
825 pr_debug("%s: headset %s actually removed\n", __func__,
826 removed ? "" : "not ");
827
828 WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
829 WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
830 WCD_MBHC_REG_READ(WCD_MBHC_HS_COMP_RESULT, hs_comp_result);
831
832 if (removed) {
Meng Wang6f901622017-09-19 10:21:57 +0800833 if (mbhc->mbhc_cfg->moisture_en) {
834 if (mbhc->mbhc_cb->hph_pa_on_status)
835 if (
Meng Wang15c825d2018-09-06 10:49:18 +0800836 mbhc->mbhc_cb->hph_pa_on_status(
837 mbhc->component)) {
Meng Wang6f901622017-09-19 10:21:57 +0800838 hphpa_on = true;
839 WCD_MBHC_REG_UPDATE_BITS(
840 WCD_MBHC_HPHL_PA_EN, 0);
841 WCD_MBHC_REG_UPDATE_BITS(
842 WCD_MBHC_HPH_PA_EN, 0);
843 }
844
845 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_GND, 1);
846 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_GND, 1);
847 /* wait for 50ms to get moisture status */
848 usleep_range(50000, 50100);
849
850 WCD_MBHC_REG_READ(
851 WCD_MBHC_MOISTURE_STATUS, moisture_status);
852 }
853
854 if (mbhc->mbhc_cfg->moisture_en && !moisture_status) {
855 pr_debug("%s: moisture present in jack\n", __func__);
856 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 0);
857 WCD_MBHC_REG_UPDATE_BITS(
858 WCD_MBHC_MECH_DETECTION_TYPE, 1);
859 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1);
860 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
861 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
862 mbhc->btn_press_intr = false;
863 mbhc->is_btn_press = false;
864 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET)
865 wcd_mbhc_report_plug(
866 mbhc, 0, SND_JACK_HEADSET);
867 else if (mbhc->current_plug ==
868 MBHC_PLUG_TYPE_HEADPHONE)
869 wcd_mbhc_report_plug(
870 mbhc, 0, SND_JACK_HEADPHONE);
871 else if (mbhc->current_plug ==
872 MBHC_PLUG_TYPE_GND_MIC_SWAP)
873 wcd_mbhc_report_plug(
874 mbhc, 0, SND_JACK_UNSUPPORTED);
875 else if (mbhc->current_plug ==
876 MBHC_PLUG_TYPE_HIGH_HPH)
877 wcd_mbhc_report_plug(
878 mbhc, 0, SND_JACK_LINEOUT);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530879 } else {
Meng Wang6f901622017-09-19 10:21:57 +0800880 if (!(hphl_sch && mic_sch && hs_comp_result)) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530881 /*
882 * extension cable is still plugged in
883 * report it as LINEOUT device
884 */
885 goto report_unplug;
Meng Wang6f901622017-09-19 10:21:57 +0800886 } else {
887 if (!mic_sch) {
888 mic_trigerred++;
889 pr_debug(
890 "%s: Removal MIC trigerred %d\n",
891 __func__, mic_trigerred);
892 }
893 if (!hphl_sch) {
894 hphl_trigerred++;
895 pr_debug(
896 "%s: Removal HPHL trigerred %d\n",
897 __func__, hphl_trigerred);
898 }
899 if (mic_trigerred && hphl_trigerred) {
900 /*
901 * extension cable is still plugged in
902 * report it as LINEOUT device
903 */
904 goto report_unplug;
905 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530906 }
907 }
908 }
909exit:
910 WCD_MBHC_RSC_UNLOCK(mbhc);
911 pr_debug("%s: leave\n", __func__);
912 return IRQ_HANDLED;
913
914report_unplug:
915 wcd_mbhc_elec_hs_report_unplug(mbhc);
Meng Wang6f901622017-09-19 10:21:57 +0800916 if (hphpa_on) {
917 hphpa_on = false;
918 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHL_PA_EN, 1);
Vatsal Buchaa8f9dc92019-04-18 16:43:08 +0530919 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_HPHR_PA_EN, 1);
Meng Wang6f901622017-09-19 10:21:57 +0800920 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530921 hphl_trigerred = 0;
922 mic_trigerred = 0;
923 WCD_MBHC_RSC_UNLOCK(mbhc);
924 pr_debug("%s: leave\n", __func__);
925 return IRQ_HANDLED;
926}
927
928static irqreturn_t wcd_mbhc_hs_ins_irq(int irq, void *data)
929{
930 struct wcd_mbhc *mbhc = data;
931 bool detection_type = 0, hphl_sch = 0, mic_sch = 0;
932 u16 elect_result = 0;
933 static u16 hphl_trigerred;
934 static u16 mic_trigerred;
935
936 pr_debug("%s: enter\n", __func__);
937 if (!mbhc->mbhc_cfg->detect_extn_cable) {
938 pr_debug("%s: Returning as Extension cable feature not enabled\n",
939 __func__);
940 return IRQ_HANDLED;
941 }
942 WCD_MBHC_RSC_LOCK(mbhc);
943
944 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_DETECTION_TYPE, detection_type);
945 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_RESULT, elect_result);
946
947 pr_debug("%s: detection_type %d, elect_result %x\n", __func__,
948 detection_type, elect_result);
949 if (detection_type) {
950 /* check if both Left and MIC Schmitt triggers are triggered */
951 WCD_MBHC_REG_READ(WCD_MBHC_HPHL_SCHMT_RESULT, hphl_sch);
952 WCD_MBHC_REG_READ(WCD_MBHC_MIC_SCHMT_RESULT, mic_sch);
953 if (hphl_sch && mic_sch) {
954 /* Go for plug type determination */
955 pr_debug("%s: Go for plug type determination\n",
956 __func__);
957 goto determine_plug;
958
959 } else {
960 if (mic_sch) {
961 mic_trigerred++;
962 pr_debug("%s: Insertion MIC trigerred %d\n",
963 __func__, mic_trigerred);
964 WCD_MBHC_REG_UPDATE_BITS(
965 WCD_MBHC_ELECT_SCHMT_ISRC,
966 0);
967 msleep(20);
968 WCD_MBHC_REG_UPDATE_BITS(
969 WCD_MBHC_ELECT_SCHMT_ISRC,
970 1);
971 }
972 if (hphl_sch) {
973 hphl_trigerred++;
974 pr_debug("%s: Insertion HPHL trigerred %d\n",
975 __func__, hphl_trigerred);
976 }
977 if (mic_trigerred && hphl_trigerred) {
978 /* Go for plug type determination */
979 pr_debug("%s: Go for plug type determination\n",
980 __func__);
981 goto determine_plug;
982 }
983 }
984 }
985 WCD_MBHC_RSC_UNLOCK(mbhc);
986 pr_debug("%s: leave\n", __func__);
987 return IRQ_HANDLED;
988
989determine_plug:
990 /*
991 * Disable HPHL trigger and MIC Schmitt triggers.
992 * Setup for insertion detection.
993 */
994 pr_debug("%s: Disable insertion interrupt\n", __func__);
995 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
996 false);
997
998 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
999 hphl_trigerred = 0;
1000 mic_trigerred = 0;
1001 mbhc->is_extn_cable = true;
1002 mbhc->btn_press_intr = false;
1003 wcd_mbhc_detect_plug_type(mbhc);
1004 WCD_MBHC_RSC_UNLOCK(mbhc);
1005 pr_debug("%s: leave\n", __func__);
1006 return IRQ_HANDLED;
1007}
1008
1009static struct wcd_mbhc_fn mbhc_fn = {
1010 .wcd_mbhc_hs_ins_irq = wcd_mbhc_hs_ins_irq,
1011 .wcd_mbhc_hs_rem_irq = wcd_mbhc_hs_rem_irq,
1012 .wcd_mbhc_detect_plug_type = wcd_mbhc_detect_plug_type,
1013 .wcd_mbhc_detect_anc_plug_type = wcd_mbhc_detect_anc_plug_type,
1014 .wcd_cancel_hs_detect_plug = wcd_cancel_hs_detect_plug,
1015};
1016
1017/* Function: wcd_mbhc_legacy_init
1018 * @mbhc: MBHC function pointer
1019 * Description: Initialize MBHC legacy based function pointers to MBHC structure
1020 */
1021void wcd_mbhc_legacy_init(struct wcd_mbhc *mbhc)
1022{
1023 if (!mbhc) {
1024 pr_err("%s: mbhc is NULL\n", __func__);
1025 return;
1026 }
1027 mbhc->mbhc_fn = &mbhc_fn;
1028 INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
1029}
1030EXPORT_SYMBOL(wcd_mbhc_legacy_init);