blob: 2c7d667873db49f3355591e1b7c544be3d9a54ea [file] [log] [blame]
Sudheer Papothifc7d3f42016-12-06 03:42:10 +05301/* Copyright (c) 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-adc.h"
31#include "wcd-mbhc-v2.h"
32
33#define WCD_MBHC_ADC_HS_THRESHOLD_MV 1700
34#define WCD_MBHC_ADC_HPH_THRESHOLD_MV 75
35#define WCD_MBHC_ADC_MICBIAS_MV 1800
36
37static int wcd_mbhc_get_micbias(struct wcd_mbhc *mbhc)
38{
39 int micbias = 0;
40 u8 vout_ctl = 0;
41
42 /* Read MBHC Micbias (Mic Bias2) voltage */
43 WCD_MBHC_REG_READ(WCD_MBHC_MICB2_VOUT, vout_ctl);
44
45 /* Formula for getting micbias from vout
46 * micbias = 1.0V + VOUT_CTL * 50mV
47 */
48 micbias = 1000 + (vout_ctl * 50);
49 pr_debug("%s: vout_ctl: %d, micbias: %d\n",
50 __func__, vout_ctl, micbias);
51
52 return micbias;
53}
54
55static int wcd_get_voltage_from_adc(u8 val, int micbias)
56{
57 /* Formula for calculating voltage from ADC
58 * Voltage = ADC_RESULT*12.5mV*V_MICBIAS/1.8
59 */
60 return ((val * 125 * micbias)/(WCD_MBHC_ADC_MICBIAS_MV * 10));
61}
62
63static int wcd_measure_adc_continuous(struct wcd_mbhc *mbhc)
64{
65 u8 adc_result = 0;
66 int output_mv = 0;
67 int retry = 3;
Walter Yang038e6612017-03-09 20:54:07 +080068 u8 adc_en = 0;
Sudheer Papothifc7d3f42016-12-06 03:42:10 +053069
70 pr_debug("%s: enter\n", __func__);
71
72 /* Pre-requisites for ADC continuous measurement */
73 /* Read legacy electircal detection and disable */
74 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
75 /* Set ADC to continuous measurement */
76 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 1);
Walter Yang038e6612017-03-09 20:54:07 +080077 /* Read ADC Enable bit to restore after adc measurement */
78 WCD_MBHC_REG_READ(WCD_MBHC_ADC_EN, adc_en);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +053079 /* Disable ADC_ENABLE bit */
80 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
81 /* Disable MBHC FSM */
82 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
83 /* Set the MUX selection to IN2P */
84 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_IN2P);
85 /* Enable MBHC FSM */
86 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
87 /* Enable ADC_ENABLE bit */
88 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 1);
89
90 while (retry--) {
91 /* wait for 3 msec before reading ADC result */
92 usleep_range(3000, 3100);
93
94 /* Read ADC result */
95 WCD_MBHC_REG_READ(WCD_MBHC_ADC_RESULT, adc_result);
96 }
97
Walter Yang038e6612017-03-09 20:54:07 +080098 /* Restore ADC Enable */
99 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, adc_en);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530100 /* Get voltage from ADC result */
101 output_mv = wcd_get_voltage_from_adc(adc_result,
102 wcd_mbhc_get_micbias(mbhc));
103 pr_debug("%s: adc_result: 0x%x, output_mv: %d\n",
104 __func__, adc_result, output_mv);
105
106 return output_mv;
107}
108
109static int wcd_measure_adc_once(struct wcd_mbhc *mbhc, int mux_ctl)
110{
111 u8 adc_timeout = 0;
112 u8 adc_complete = 0;
113 u8 adc_result = 0;
Walter Yang038e6612017-03-09 20:54:07 +0800114 int retry = 6;
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530115 int ret = 0;
116 int output_mv = 0;
Walter Yang038e6612017-03-09 20:54:07 +0800117 u8 adc_en = 0;
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530118
119 pr_debug("%s: enter\n", __func__);
120
121 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
Walter Yang038e6612017-03-09 20:54:07 +0800122 /* Read ADC Enable bit to restore after adc measurement */
123 WCD_MBHC_REG_READ(WCD_MBHC_ADC_EN, adc_en);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530124 /* Trigger ADC one time measurement */
125 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
126 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
127 /* Set the appropriate MUX selection */
128 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, mux_ctl);
129 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
130 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 1);
131
132 while (retry--) {
Walter Yang038e6612017-03-09 20:54:07 +0800133 /* wait for 600usec to get adc results */
134 usleep_range(600, 610);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530135
136 /* check for ADC Timeout */
137 WCD_MBHC_REG_READ(WCD_MBHC_ADC_TIMEOUT, adc_timeout);
138 if (adc_timeout)
139 continue;
140
141 /* Read ADC complete bit */
142 WCD_MBHC_REG_READ(WCD_MBHC_ADC_COMPLETE, adc_complete);
143 if (!adc_complete)
144 continue;
145
146 /* Read ADC result */
147 WCD_MBHC_REG_READ(WCD_MBHC_ADC_RESULT, adc_result);
148
149 pr_debug("%s: ADC result: 0x%x\n", __func__, adc_result);
150 /* Get voltage from ADC result */
151 output_mv = wcd_get_voltage_from_adc(adc_result,
152 wcd_mbhc_get_micbias(mbhc));
153 break;
154 }
155
Walter Yang038e6612017-03-09 20:54:07 +0800156 /* Restore ADC Enable */
157 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, adc_en);
158
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530159 if (retry <= 0) {
160 pr_err("%s: adc complete: %d, adc timeout: %d\n",
161 __func__, adc_complete, adc_timeout);
162 ret = -EINVAL;
163 } else {
164 pr_debug("%s: adc complete: %d, adc timeout: %d output_mV: %d\n",
165 __func__, adc_complete, adc_timeout, output_mv);
166 ret = output_mv;
167 }
168
169 pr_debug("%s: leave\n", __func__);
170
171 return ret;
172}
173
174static bool wcd_mbhc_adc_detect_anc_plug_type(struct wcd_mbhc *mbhc)
175{
176 bool anc_mic_found = false;
177 u16 fsm_en = 0;
178 u8 det = 0;
179 unsigned long retry = 0;
180 int valid_plug_cnt = 0, invalid_plug_cnt = 0;
181 int ret = 0;
182 u8 elect_ctl = 0;
183 u8 adc_mode = 0;
184 u8 vref = 0;
185 int vref_mv[] = {1650, 1500, 1600, 1700};
186
187 if (mbhc->mbhc_cfg->anc_micbias < MIC_BIAS_1 ||
188 mbhc->mbhc_cfg->anc_micbias > MIC_BIAS_4)
189 return false;
190
191 if (!mbhc->mbhc_cb->mbhc_micbias_control)
192 return false;
193
194 /* Disable Detection done for ADC operation */
195 WCD_MBHC_REG_READ(WCD_MBHC_DETECTION_DONE, det);
196 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0);
197
198 /* Mask ADC COMPLETE interrupt */
199 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
200
201 WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en);
202 mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
203 mbhc->mbhc_cfg->anc_micbias,
204 MICB_ENABLE);
205
206 /* Read legacy electircal detection and disable */
207 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
208 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
209
210 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 1);
211 WCD_MBHC_REG_READ(WCD_MBHC_ADC_MODE, adc_mode);
212
213 /*
214 * wait for button debounce time 20ms. If 4-pole plug is inserted
215 * into 5-pole jack, then there will be a button press interrupt
216 * during anc plug detection. In that case though Hs_comp_res is 0,
217 * it should not be declared as ANC plug type
218 */
219 usleep_range(20000, 20100);
220
221 /*
222 * After enabling FSM, to handle slow insertion scenarios,
223 * check IN3 voltage is below the Vref
224 */
225 WCD_MBHC_REG_READ(WCD_MBHC_HS_VREF, vref);
226
227 do {
228 if (wcd_swch_level_remove(mbhc)) {
229 pr_debug("%s: Switch level is low\n", __func__);
230 goto done;
231 }
232 pr_debug("%s: Retry attempt %lu\n", __func__, retry + 1);
233 ret = wcd_measure_adc_once(mbhc, MUX_CTL_IN3P);
234 /* TODO - check the logic */
235 if (ret && (ret < vref_mv[vref]))
236 valid_plug_cnt++;
237 else
238 invalid_plug_cnt++;
239 retry++;
240 } while (retry < ANC_DETECT_RETRY_CNT);
241
242 pr_debug("%s: valid: %d, invalid: %d\n", __func__, valid_plug_cnt,
243 invalid_plug_cnt);
244
245 /* decision logic */
246 if (valid_plug_cnt > invalid_plug_cnt)
247 anc_mic_found = true;
248done:
249 /* Restore ADC mode */
250 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, adc_mode);
251 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ANC_DET_EN, 0);
252 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
253 /* Set the MUX selection to AUTO */
254 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
255 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
256 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, fsm_en);
257 /* Restore detection done */
258 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, det);
259
260 /* Restore electrical detection */
261 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
262
263 mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec,
264 mbhc->mbhc_cfg->anc_micbias,
265 MICB_DISABLE);
266 pr_debug("%s: anc mic %sfound\n", __func__,
267 anc_mic_found ? "" : "not ");
268
269 return anc_mic_found;
270}
271
272/* To determine if cross connection occurred */
273static int wcd_check_cross_conn(struct wcd_mbhc *mbhc)
274{
275 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_NONE;
276 int hphl_adc_res = 0, hphr_adc_res = 0;
277 u8 fsm_en = 0;
278 int ret = 0;
279 u8 adc_mode = 0;
280 u8 elect_ctl = 0;
281 u8 adc_en = 0;
282
283 pr_debug("%s: enter\n", __func__);
284 /* Check for button press and plug detection */
285 if (wcd_swch_level_remove(mbhc)) {
286 pr_debug("%s: Switch level is low\n", __func__);
287 return -EINVAL;
288 }
289
290 /* If PA is enabled, dont check for cross-connection */
291 if (mbhc->mbhc_cb->hph_pa_on_status)
292 if (mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec))
293 return -EINVAL;
294
295 /* Read legacy electircal detection and disable */
296 WCD_MBHC_REG_READ(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
297 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0x00);
298
299 /* Read and set ADC to single measurement */
300 WCD_MBHC_REG_READ(WCD_MBHC_ADC_MODE, adc_mode);
301 /* Read ADC Enable bit to restore after adc measurement */
302 WCD_MBHC_REG_READ(WCD_MBHC_ADC_EN, adc_en);
303 /* Read FSM status */
304 WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en);
305
306 /* Get adc result for HPH L */
307 hphl_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_L);
308 if (hphl_adc_res < 0) {
309 pr_err("%s: hphl_adc_res adc measurement failed\n", __func__);
310 ret = hphl_adc_res;
311 goto done;
312 }
313
314 /* Get adc result for HPH R in mV */
315 hphr_adc_res = wcd_measure_adc_once(mbhc, MUX_CTL_HPH_R);
316 if (hphr_adc_res < 0) {
317 pr_err("%s: hphr_adc_res adc measurement failed\n", __func__);
318 ret = hphr_adc_res;
319 goto done;
320 }
321
322 if (hphl_adc_res > 100 && hphr_adc_res > 100) {
323 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
324 pr_debug("%s: Cross connection identified\n", __func__);
325 } else {
326 pr_debug("%s: No Cross connection found\n", __func__);
327 }
328
329done:
330 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0);
331 /* Set the MUX selection to Auto */
332 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MUX_CTL, MUX_CTL_AUTO);
333 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 1);
334
335 /* Restore ADC Enable */
336 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, adc_en);
337
338 /* Restore ADC mode */
339 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, adc_mode);
340
341 /* Restore FSM state */
342 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, fsm_en);
343
344 /* Restore electrical detection */
345 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, elect_ctl);
346
347 pr_debug("%s: leave, plug type: %d\n", __func__, plug_type);
348
349 return (plug_type == MBHC_PLUG_TYPE_GND_MIC_SWAP) ? true : false;
350}
351
352static bool wcd_mbhc_adc_check_for_spl_headset(struct wcd_mbhc *mbhc,
353 int *spl_hs_cnt)
354{
355 bool spl_hs = false;
356 int output_mv = 0;
357 int adc_threshold = 0;
358
359 pr_debug("%s: enter\n", __func__);
360 if (!mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic)
361 goto exit;
362
363 /* Bump up MB2 to 2.7V */
364 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
365 mbhc->mbhc_cfg->mbhc_micbias, true);
Walter Yang038e6612017-03-09 20:54:07 +0800366 usleep_range(10000, 10100);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530367
Walter Yang038e6612017-03-09 20:54:07 +0800368 /*
369 * Use ADC single mode to minimize the chance of missing out
370 * btn press/relesae for HEADSET type during correct work.
371 */
372 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530373 adc_threshold = ((WCD_MBHC_ADC_HS_THRESHOLD_MV *
374 wcd_mbhc_get_micbias(mbhc))/WCD_MBHC_ADC_MICBIAS_MV);
375
376 if (output_mv > adc_threshold) {
377 spl_hs = false;
378 } else {
379 spl_hs = true;
380 if (spl_hs_cnt)
381 *spl_hs_cnt += 1;
382 }
383
384 /* MB2 back to 1.8v if the type is not special headset */
385 if (!spl_hs) {
386 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(mbhc->codec,
387 mbhc->mbhc_cfg->mbhc_micbias, false);
388 /* Add 10ms delay for micbias to settle */
389 usleep_range(10000, 10100);
390 } else {
391 pr_debug("%s: Detected special HS (%d)\n", __func__, spl_hs);
392 }
393
394exit:
395 pr_debug("%s: leave\n", __func__);
396 return spl_hs;
397}
398
399static bool wcd_is_special_headset(struct wcd_mbhc *mbhc)
400{
401 int delay = 0;
402 bool ret = false;
403 bool is_spl_hs = false;
404 int spl_hs_count = 0;
405
406 while (!is_spl_hs) {
407 delay += 50;
408 if (mbhc->hs_detect_work_stop) {
409 pr_debug("%s: stop requested: %d\n", __func__,
410 mbhc->hs_detect_work_stop);
411 break;
412 }
413 /* Wait for 50ms for FSM to update result */
414 msleep(50);
415 is_spl_hs = wcd_mbhc_adc_check_for_spl_headset(mbhc,
416 &spl_hs_count);
417 if (is_spl_hs)
418 pr_debug("%s: Spl headset detected in %d msecs\n",
419 __func__, delay);
420 if (delay == SPECIAL_HS_DETECT_TIME_MS) {
421 pr_debug("%s: Spl headset not found in 2 sec\n",
422 __func__);
423 break;
424 }
425 }
426 pr_debug("%s: leave, micb_enable: %d\n", __func__,
427 mbhc->micbias_enable);
428
429 return ret;
430}
431
432static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc,
433 enum wcd_mbhc_plug_type plug_type)
434{
435 bool micbias2;
436
437 micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc,
438 MIC_BIAS_2);
439 switch (plug_type) {
440 case MBHC_PLUG_TYPE_HEADPHONE:
441 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
442 break;
443 case MBHC_PLUG_TYPE_HEADSET:
444 case MBHC_PLUG_TYPE_ANC_HEADPHONE:
445 if (!mbhc->is_hs_recording && !micbias2)
446 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3);
447 break;
448 default:
449 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0);
450 break;
451
452 };
453}
454
455/* should be called under interrupt context that hold suspend */
456static void wcd_schedule_hs_detect_plug(struct wcd_mbhc *mbhc,
457 struct work_struct *work)
458{
459 pr_debug("%s: scheduling correct_swch_plug\n", __func__);
460 WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
461 mbhc->hs_detect_work_stop = false;
462 mbhc->mbhc_cb->lock_sleep(mbhc, true);
463 schedule_work(work);
464}
465
466/* called under codec_resource_lock acquisition */
467static void wcd_cancel_hs_detect_plug(struct wcd_mbhc *mbhc,
468 struct work_struct *work)
469{
470 pr_debug("%s: Canceling correct_plug_swch\n", __func__);
471 mbhc->hs_detect_work_stop = true;
472 WCD_MBHC_RSC_UNLOCK(mbhc);
473 if (cancel_work_sync(work)) {
474 pr_debug("%s: correct_plug_swch is canceled\n",
475 __func__);
476 mbhc->mbhc_cb->lock_sleep(mbhc, false);
477 }
478 WCD_MBHC_RSC_LOCK(mbhc);
479}
480
481/* called under codec_resource_lock acquisition */
482static void wcd_mbhc_adc_detect_plug_type(struct wcd_mbhc *mbhc)
483{
484 struct snd_soc_codec *codec = mbhc->codec;
485
486 pr_debug("%s: enter\n", __func__);
487 WCD_MBHC_RSC_ASSERT_LOCKED(mbhc);
488
489 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
490 mbhc->mbhc_cb->hph_pull_down_ctrl(codec, false);
491
492 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0);
493
494 if (mbhc->mbhc_cb->mbhc_micbias_control) {
495 mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
496 MICB_ENABLE);
497 } else {
498 pr_err("%s: Mic Bias is not enabled\n", __func__);
499 return;
500 }
501
502 /* Re-initialize button press completion object */
503 reinit_completion(&mbhc->btn_press_compl);
504 wcd_schedule_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
505 pr_debug("%s: leave\n", __func__);
506}
507
508static void wcd_micbias_disable(struct wcd_mbhc *mbhc)
509{
510 if (mbhc->micbias_enable) {
511 mbhc->mbhc_cb->mbhc_micb_ctrl_thr_mic(
512 mbhc->codec, MIC_BIAS_2, false);
513 if (mbhc->mbhc_cb->set_micbias_value)
514 mbhc->mbhc_cb->set_micbias_value(
515 mbhc->codec);
516 mbhc->micbias_enable = false;
517 }
518}
519
520static int wcd_mbhc_get_plug_from_adc(int adc_result)
521
522{
523 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
524
525 if (adc_result < WCD_MBHC_ADC_HPH_THRESHOLD_MV)
526 plug_type = MBHC_PLUG_TYPE_HEADPHONE;
527 else if (adc_result > WCD_MBHC_ADC_HS_THRESHOLD_MV)
528 plug_type = MBHC_PLUG_TYPE_HIGH_HPH;
529 else
530 plug_type = MBHC_PLUG_TYPE_HEADSET;
531 pr_debug("%s: plug type is %d found\n", __func__, plug_type);
532
533 return plug_type;
534}
535
536static int wcd_mbhc_get_plug_type(struct wcd_mbhc *mbhc)
537{
538 int result_mv = 0;
539
Walter Yang038e6612017-03-09 20:54:07 +0800540 /*
541 * Use ADC single mode to minimize the chance of missing out
542 * btn press/release for HEADSET type during correct work.
543 */
544 result_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530545
546 return wcd_mbhc_get_plug_from_adc(result_mv);
547}
548
549static void wcd_correct_swch_plug(struct work_struct *work)
550{
551 struct wcd_mbhc *mbhc;
552 struct snd_soc_codec *codec;
553 enum wcd_mbhc_plug_type plug_type = MBHC_PLUG_TYPE_INVALID;
554 unsigned long timeout;
555 bool wrk_complete = false;
556 int gnd_mic_swap_cnt = 0;
557 bool is_pa_on = false, spl_hs = false;
558 int ret = 0;
559 int spl_hs_count = 0;
560 int output_mv = 0;
561 int cross_conn;
562 int try = 0;
563
564 pr_debug("%s: enter\n", __func__);
565
566 mbhc = container_of(work, struct wcd_mbhc, correct_plug_swch);
567 codec = mbhc->codec;
568
569 WCD_MBHC_RSC_LOCK(mbhc);
570 /* Mask ADC COMPLETE interrupt */
571 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
572 WCD_MBHC_RSC_UNLOCK(mbhc);
573
574 /* Check for cross connection */
575 do {
576 cross_conn = wcd_check_cross_conn(mbhc);
577 try++;
578 } while (try < GND_MIC_SWAP_THRESHOLD);
579
580 if (cross_conn > 0) {
581 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
582 pr_debug("%s: cross connection found, Plug type %d\n",
583 __func__, plug_type);
584 goto correct_plug_type;
585 }
586 /* Find plug type */
Walter Yang038e6612017-03-09 20:54:07 +0800587 output_mv = wcd_measure_adc_continuous(mbhc);
588 plug_type = wcd_mbhc_get_plug_from_adc(output_mv);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530589
590 /*
591 * Report plug type if it is either headset or headphone
592 * else start the 3 sec loop
593 */
594 if ((plug_type == MBHC_PLUG_TYPE_HEADSET ||
595 plug_type == MBHC_PLUG_TYPE_HEADPHONE) &&
596 (!wcd_swch_level_remove(mbhc))) {
597 WCD_MBHC_RSC_LOCK(mbhc);
598 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
599 WCD_MBHC_RSC_UNLOCK(mbhc);
600 }
601
Walter Yang038e6612017-03-09 20:54:07 +0800602 /*
603 * Set DETECTION_DONE bit for HEADSET and ANC_HEADPHONE,
604 * so that btn press/release interrupt can be generated.
605 */
606 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADSET ||
607 mbhc->current_plug == MBHC_PLUG_TYPE_ANC_HEADPHONE) {
608 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
609 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
610 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 1);
611 }
612
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530613correct_plug_type:
614 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
615 while (!time_after(jiffies, timeout)) {
616 if (mbhc->hs_detect_work_stop) {
617 pr_debug("%s: stop requested: %d\n", __func__,
618 mbhc->hs_detect_work_stop);
619 wcd_micbias_disable(mbhc);
620 goto exit;
621 }
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530622
623 /* allow sometime and re-check stop requested again */
624 msleep(20);
625 if (mbhc->hs_detect_work_stop) {
626 pr_debug("%s: stop requested: %d\n", __func__,
627 mbhc->hs_detect_work_stop);
628 wcd_micbias_disable(mbhc);
629 goto exit;
630 }
631
632 msleep(180);
Walter Yang038e6612017-03-09 20:54:07 +0800633 /*
634 * Use ADC single mode to minimize the chance of missing out
635 * btn press/release for HEADSET type during correct work.
636 */
637 output_mv = wcd_measure_adc_once(mbhc, MUX_CTL_IN2P);
638
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530639 /*
640 * instead of hogging system by contineous polling, wait for
641 * sometime and re-check stop request again.
642 */
643 plug_type = wcd_mbhc_get_plug_from_adc(output_mv);
644
645 if ((output_mv > WCD_MBHC_ADC_HS_THRESHOLD_MV) &&
646 (spl_hs_count < WCD_MBHC_SPL_HS_CNT)) {
647 spl_hs = wcd_mbhc_adc_check_for_spl_headset(mbhc,
648 &spl_hs_count);
649
650 if (spl_hs_count == WCD_MBHC_SPL_HS_CNT)
651 mbhc->micbias_enable = true;
652 }
653
654 if (mbhc->mbhc_cb->hph_pa_on_status)
655 is_pa_on = mbhc->mbhc_cb->hph_pa_on_status(mbhc->codec);
656
657 if ((output_mv <= WCD_MBHC_ADC_HS_THRESHOLD_MV) &&
658 (!is_pa_on)) {
659 /* Check for cross connection*/
660 ret = wcd_check_cross_conn(mbhc);
661 if (ret < 0)
662 continue;
663 if (ret > 0) {
664 /* Found cross connection, swap mic/gnd */
665 if (gnd_mic_swap_cnt > GND_MIC_SWAP_THRESHOLD) {
666 /*
667 * This is due to GND/MIC switch didn't
668 * work, Report unsupported plug.
669 */
670 pr_debug("%s: switch did not work\n",
671 __func__);
672 plug_type = MBHC_PLUG_TYPE_GND_MIC_SWAP;
673 goto report;
674 }
675 gnd_mic_swap_cnt++;
676 if (mbhc->mbhc_cfg->swap_gnd_mic &&
677 mbhc->mbhc_cfg->swap_gnd_mic(codec)) {
678 pr_debug("%s: US_EU gpio present,flip switch\n"
679 , __func__);
680 continue;
681 }
682 } else {
683 gnd_mic_swap_cnt++;
684 plug_type = wcd_mbhc_get_plug_type(mbhc);
685 if ((gnd_mic_swap_cnt <=
686 GND_MIC_SWAP_THRESHOLD) &&
687 (spl_hs_count != WCD_MBHC_SPL_HS_CNT)) {
688 continue;
689 } else {
690 gnd_mic_swap_cnt = 0;
691 }
692 }
693 }
694
695 if (!spl_hs && (plug_type == MBHC_PLUG_TYPE_HIGH_HPH)) {
696 pr_debug("%s: cable is extension cable\n", __func__);
697 wrk_complete = true;
698 } else {
699 if (plug_type != MBHC_PLUG_TYPE_GND_MIC_SWAP) {
700 if (!spl_hs)
701 plug_type =
702 wcd_mbhc_get_plug_type(mbhc);
703 else
704 plug_type = MBHC_PLUG_TYPE_HEADSET;
705 /*
706 * Report headset only if not already reported
707 * and if there is not button press without
708 * release
709 */
Walter Yang038e6612017-03-09 20:54:07 +0800710 if ((mbhc->current_plug !=
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530711 MBHC_PLUG_TYPE_HEADSET) &&
712 (mbhc->current_plug !=
Walter Yang038e6612017-03-09 20:54:07 +0800713 MBHC_PLUG_TYPE_ANC_HEADPHONE)) {
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530714 if (plug_type == MBHC_PLUG_TYPE_HEADSET)
715 pr_debug("%s: cable is %s headset\n",
716 __func__,
717 ((spl_hs) ?
718 "special ":""));
719 goto report;
720 }
721 }
722 wrk_complete = false;
723 }
724 }
725 if (!wrk_complete) {
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530726 /*
727 * If plug_tye is headset, we might have already reported either
728 * in detect_plug-type or in above while loop, no need to report
729 * again
730 */
731 if ((plug_type == MBHC_PLUG_TYPE_HEADSET) ||
732 (plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE)) {
733 pr_debug("%s: plug_type:0x%x already reported\n",
734 __func__, mbhc->current_plug);
735 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
736 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
737 goto enable_supply;
738 }
739 }
740 if (plug_type == MBHC_PLUG_TYPE_HIGH_HPH) {
741 if (wcd_is_special_headset(mbhc)) {
742 pr_debug("%s: Special headset found %d\n",
743 __func__, plug_type);
744 plug_type = MBHC_PLUG_TYPE_HEADSET;
745 } else {
746 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 1);
747 }
748 }
749
750report:
751 if (wcd_swch_level_remove(mbhc)) {
752 pr_debug("%s: Switch level is low\n", __func__);
753 goto exit;
754 }
Walter Yang038e6612017-03-09 20:54:07 +0800755
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530756 pr_debug("%s: Valid plug found, plug type %d wrk_cmpt %d btn_intr %d\n",
757 __func__, plug_type, wrk_complete,
758 mbhc->btn_press_intr);
759
760 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
761 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
762
763 WCD_MBHC_RSC_LOCK(mbhc);
764 wcd_mbhc_find_plug_and_report(mbhc, plug_type);
765 WCD_MBHC_RSC_UNLOCK(mbhc);
766enable_supply:
Walter Yang038e6612017-03-09 20:54:07 +0800767 /*
768 * Set DETECTION_DONE bit for HEADSET and ANC_HEADPHONE,
769 * so that btn press/release interrupt can be generated.
770 * For other plug type, clear the bit.
771 */
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530772 if (plug_type == MBHC_PLUG_TYPE_HEADSET ||
773 plug_type == MBHC_PLUG_TYPE_ANC_HEADPHONE)
774 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 1);
Walter Yang038e6612017-03-09 20:54:07 +0800775 else
776 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530777
778 if (mbhc->mbhc_cb->mbhc_micbias_control)
779 wcd_mbhc_adc_update_fsm_source(mbhc, plug_type);
780exit:
781 if (mbhc->mbhc_cb->mbhc_micbias_control &&
782 !mbhc->micbias_enable)
783 mbhc->mbhc_cb->mbhc_micbias_control(codec, MIC_BIAS_2,
784 MICB_DISABLE);
785 if (mbhc->mbhc_cfg->detect_extn_cable &&
786 ((plug_type == MBHC_PLUG_TYPE_HEADPHONE) ||
787 (plug_type == MBHC_PLUG_TYPE_HEADSET)) &&
788 !mbhc->hs_detect_work_stop) {
789 WCD_MBHC_RSC_LOCK(mbhc);
790 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_REM, true);
791 WCD_MBHC_RSC_UNLOCK(mbhc);
792 }
793
Walter Yang038e6612017-03-09 20:54:07 +0800794 /*
795 * Enable ADC COMPLETE interrupt for HEADPHONE.
796 * Btn release may happen after the correct work, ADC COMPLETE
797 * interrupt needs to be captured to correct plug type.
798 */
799 if (plug_type == MBHC_PLUG_TYPE_HEADPHONE) {
800 WCD_MBHC_RSC_LOCK(mbhc);
801 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS,
802 true);
803 WCD_MBHC_RSC_UNLOCK(mbhc);
804 }
805
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530806 if (mbhc->mbhc_cb->hph_pull_down_ctrl)
807 mbhc->mbhc_cb->hph_pull_down_ctrl(codec, true);
808
809 mbhc->mbhc_cb->lock_sleep(mbhc, false);
810 pr_debug("%s: leave\n", __func__);
811}
812
813static irqreturn_t wcd_mbhc_adc_hs_rem_irq(int irq, void *data)
814{
815 struct wcd_mbhc *mbhc = data;
816
817 pr_debug("%s: enter\n", __func__);
818 WCD_MBHC_RSC_LOCK(mbhc);
Walter Yang038e6612017-03-09 20:54:07 +0800819 /*
820 * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE,
821 * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one
822 * when HEADPHONE is removed.
823 */
824 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE)
825 mbhc->extn_cable_hph_rem = true;
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530826 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 0);
827 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_MODE, 0);
828 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ADC_EN, 0);
829 wcd_mbhc_elec_hs_report_unplug(mbhc);
830 WCD_MBHC_RSC_UNLOCK(mbhc);
831 pr_debug("%s: leave\n", __func__);
832 return IRQ_HANDLED;
833}
834
835static irqreturn_t wcd_mbhc_adc_hs_ins_irq(int irq, void *data)
836{
837 struct wcd_mbhc *mbhc = data;
838
839 pr_debug("%s: enter\n", __func__);
Walter Yang038e6612017-03-09 20:54:07 +0800840
841 /*
842 * ADC COMPLETE and ELEC_REM interrupts are both enabled for HEADPHONE,
843 * need to reject the ADC COMPLETE interrupt which follows ELEC_REM one
844 * when HEADPHONE is removed.
845 */
846 if (mbhc->extn_cable_hph_rem == true) {
847 mbhc->extn_cable_hph_rem = false;
848 pr_debug("%s: leave\n", __func__);
849 return IRQ_HANDLED;
850 }
851
852 WCD_MBHC_RSC_LOCK(mbhc);
853 /*
854 * If current plug is headphone then there is no chance to
855 * get ADC complete interrupt, so connected cable should be
856 * headset not headphone.
857 */
858 if (mbhc->current_plug == MBHC_PLUG_TYPE_HEADPHONE) {
859 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
860 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_DETECTION_DONE, 1);
861 wcd_mbhc_find_plug_and_report(mbhc, MBHC_PLUG_TYPE_HEADSET);
862 WCD_MBHC_RSC_UNLOCK(mbhc);
863 return IRQ_HANDLED;
864 }
865
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530866 if (!mbhc->mbhc_cfg->detect_extn_cable) {
867 pr_debug("%s: Returning as Extension cable feature not enabled\n",
868 __func__);
Walter Yang038e6612017-03-09 20:54:07 +0800869 WCD_MBHC_RSC_UNLOCK(mbhc);
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530870 return IRQ_HANDLED;
871 }
Walter Yang038e6612017-03-09 20:54:07 +0800872
Sudheer Papothifc7d3f42016-12-06 03:42:10 +0530873 pr_debug("%s: Disable electrical headset insertion interrupt\n",
874 __func__);
875 wcd_mbhc_hs_elec_irq(mbhc, WCD_MBHC_ELEC_HS_INS, false);
876 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0);
877 WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_ISRC_EN, 0);
878 mbhc->is_extn_cable = true;
879 mbhc->btn_press_intr = false;
880 wcd_mbhc_adc_detect_plug_type(mbhc);
881 WCD_MBHC_RSC_UNLOCK(mbhc);
882 pr_debug("%s: leave\n", __func__);
883 return IRQ_HANDLED;
884}
885
886static struct wcd_mbhc_fn mbhc_fn = {
887 .wcd_mbhc_hs_ins_irq = wcd_mbhc_adc_hs_ins_irq,
888 .wcd_mbhc_hs_rem_irq = wcd_mbhc_adc_hs_rem_irq,
889 .wcd_mbhc_detect_plug_type = wcd_mbhc_adc_detect_plug_type,
890 .wcd_mbhc_detect_anc_plug_type = wcd_mbhc_adc_detect_anc_plug_type,
891 .wcd_cancel_hs_detect_plug = wcd_cancel_hs_detect_plug,
892};
893
894/* Function: wcd_mbhc_adc_init
895 * @mbhc: MBHC function pointer
896 * Description: Initialize MBHC ADC related function pointers to MBHC structure
897 */
898void wcd_mbhc_adc_init(struct wcd_mbhc *mbhc)
899{
900 if (!mbhc) {
901 pr_err("%s: mbhc is NULL\n", __func__);
902 return;
903 }
904 mbhc->mbhc_fn = &mbhc_fn;
905 INIT_WORK(&mbhc->correct_plug_swch, wcd_correct_swch_plug);
906}
907EXPORT_SYMBOL(wcd_mbhc_adc_init);