blob: 5be67cff362fcee7fbd6273d72597b8d829265c8 [file] [log] [blame]
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Joonwoo Parka8890262012-10-15 12:04:27 -07002 *
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/firmware.h>
15#include <linux/slab.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/debugfs.h>
21#include <linux/mfd/wcd9xxx/core.h>
22#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
23#include <linux/mfd/wcd9xxx/wcd9320_registers.h>
24#include <linux/mfd/wcd9xxx/pdata.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/soc.h>
28#include <sound/soc-dapm.h>
29#include <sound/tlv.h>
30#include <linux/bitops.h>
31#include <linux/delay.h>
32#include <linux/pm_runtime.h>
33#include <linux/kernel.h>
34#include <linux/gpio.h>
35#include "wcd9320.h"
Simmi Pateriya0a44d842013-04-03 01:12:42 +053036#include "wcd9306.h"
Joonwoo Parka8890262012-10-15 12:04:27 -070037#include "wcd9xxx-mbhc.h"
38#include "wcd9xxx-resmgr.h"
39
40#define WCD9XXX_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
Joonwoo Park80a01172012-10-15 16:05:23 -070041 SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
42 SND_JACK_UNSUPPORTED)
Joonwoo Parka8890262012-10-15 12:04:27 -070043#define WCD9XXX_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
44 SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
45 SND_JACK_BTN_4 | SND_JACK_BTN_5 | \
46 SND_JACK_BTN_6 | SND_JACK_BTN_7)
47
48#define NUM_DCE_PLUG_DETECT 3
Joonwoo Parkccccba72013-04-26 11:19:46 -070049#define NUM_DCE_PLUG_INS_DETECT 5
Joonwoo Parka8890262012-10-15 12:04:27 -070050#define NUM_ATTEMPTS_INSERT_DETECT 25
51#define NUM_ATTEMPTS_TO_REPORT 5
52
53#define FAKE_INS_LOW 10
54#define FAKE_INS_HIGH 80
55#define FAKE_INS_HIGH_NO_SWCH 150
56#define FAKE_REMOVAL_MIN_PERIOD_MS 50
57#define FAKE_INS_DELTA_SCALED_MV 300
58
59#define BUTTON_MIN 0x8000
60#define STATUS_REL_DETECTION 0x0C
61
62#define HS_DETECT_PLUG_TIME_MS (5 * 1000)
63#define HS_DETECT_PLUG_INERVAL_MS 100
64#define SWCH_REL_DEBOUNCE_TIME_MS 50
65#define SWCH_IRQ_DEBOUNCE_TIME_US 5000
66
67#define GND_MIC_SWAP_THRESHOLD 2
68#define OCP_ATTEMPT 1
69
70#define FW_READ_ATTEMPTS 15
71#define FW_READ_TIMEOUT 2000000
72
Joonwoo Park2e6bd1e2012-10-18 13:48:55 -070073#define BUTTON_POLLING_SUPPORTED true
Joonwoo Parka8890262012-10-15 12:04:27 -070074
75#define MCLK_RATE_12288KHZ 12288000
76#define MCLK_RATE_9600KHZ 9600000
Joonwoo Parka8890262012-10-15 12:04:27 -070077
78#define DEFAULT_DCE_STA_WAIT 55
79#define DEFAULT_DCE_WAIT 60000
80#define DEFAULT_STA_WAIT 5000
81
82#define VDDIO_MICBIAS_MV 1800
83
Joonwoo Parkccccba72013-04-26 11:19:46 -070084#define WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US 5000
85
Joonwoo Park20bc9da2013-01-16 12:58:06 -080086#define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
Joonwoo Parkaec97c72013-05-14 16:51:02 -070087#define WCD9XXX_MUX_SWITCH_READY_WAIT_MS 50
Joonwoo Park20bc9da2013-01-16 12:58:06 -080088#define WCD9XXX_MEAS_DELTA_MAX_MV 50
Joonwoo Park141d6182013-03-05 12:25:46 -080089#define WCD9XXX_MEAS_INVALD_RANGE_LOW_MV 20
90#define WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV 80
Joonwoo Park20bc9da2013-01-16 12:58:06 -080091#define WCD9XXX_GM_SWAP_THRES_MIN_MV 150
Joonwoo Park479347a2013-04-15 18:01:05 -070092#define WCD9XXX_GM_SWAP_THRES_MAX_MV 650
Joonwoo Parkccccba72013-04-26 11:19:46 -070093#define WCD9XXX_THRESHOLD_MIC_THRESHOLD 200
Joonwoo Park20bc9da2013-01-16 12:58:06 -080094
95#define WCD9XXX_USLEEP_RANGE_MARGIN_US 1000
96
Joonwoo Parkccccba72013-04-26 11:19:46 -070097static bool detect_use_vddio_switch = true;
Joonwoo Park20bc9da2013-01-16 12:58:06 -080098
99struct wcd9xxx_mbhc_detect {
100 u16 dce;
101 u16 sta;
102 u16 hphl_status;
103 bool swap_gnd;
104 bool vddio;
105 bool hwvalue;
106 /* internal purpose from here */
107 bool _above_no_mic;
108 bool _below_v_hs_max;
109 s16 _vdces;
110 enum wcd9xxx_mbhc_plug_type _type;
111};
112
Joonwoo Parka8890262012-10-15 12:04:27 -0700113enum meas_type {
114 STA = 0,
115 DCE,
116};
117
118enum {
119 MBHC_USE_HPHL_TRIGGER = 1,
120 MBHC_USE_MB_TRIGGER = 2
121};
122
123/*
124 * Flags to track of PA and DAC state.
125 * PA and DAC should be tracked separately as AUXPGA loopback requires
126 * only PA to be turned on without DAC being on.
127 */
128enum pa_dac_ack_flags {
129 WCD9XXX_HPHL_PA_OFF_ACK = 0,
130 WCD9XXX_HPHR_PA_OFF_ACK,
131 WCD9XXX_HPHL_DAC_OFF_ACK,
132 WCD9XXX_HPHR_DAC_OFF_ACK
133};
134
Joonwoo Park73375212013-05-07 12:42:44 -0700135enum wcd9xxx_current_v_idx {
136 WCD9XXX_CURRENT_V_INS_H,
137 WCD9XXX_CURRENT_V_INS_HU,
138 WCD9XXX_CURRENT_V_B1_H,
139 WCD9XXX_CURRENT_V_B1_HU,
140 WCD9XXX_CURRENT_V_BR_H,
141};
142
Joonwoo Parka8890262012-10-15 12:04:27 -0700143static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
144{
145 return mbhc->polling_active;
146}
147
148static void wcd9xxx_turn_onoff_override(struct snd_soc_codec *codec, bool on)
149{
150 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
151}
152
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530153static int wcd9xxx_enable_mux_bias_block(struct snd_soc_codec *codec,
154 struct wcd9xxx_mbhc *mbhc)
155{
156 switch (mbhc->mbhc_version) {
157 case WCD9XXX_MBHC_VERSION_TAIKO:
158 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
159 0x80, 0x80);
160 break;
161 case WCD9XXX_MBHC_VERSION_TAPAN:
162 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
163 0x80, 0x00);
164 break;
165 default:
166 return -EINVAL;
167 }
168 return 0;
169}
170
171static int wcd9xxx_put_cfilt_fast_mode(struct snd_soc_codec *codec,
172 struct wcd9xxx_mbhc *mbhc)
173{
174 switch (mbhc->mbhc_version) {
175 case WCD9XXX_MBHC_VERSION_TAIKO:
176 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
177 0x70, 0x00);
178 break;
179 case WCD9XXX_MBHC_VERSION_TAPAN:
180 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
181 0x70, 0x70);
182 break;
183 default:
184 return -EINVAL;
185 }
186 return 0;
187}
188
189static int wcd9xxx_codec_specific_cal_setup(struct snd_soc_codec *codec,
190 struct wcd9xxx_mbhc *mbhc)
191{
192 switch (mbhc->mbhc_version) {
193 case WCD9XXX_MBHC_VERSION_TAIKO:
194 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
195 0x04, 0x04);
196 break;
197 case WCD9XXX_MBHC_VERSION_TAPAN:
198 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
199 0x0C, 0x04);
200 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
201 /* Make sure the calibration is ON */
202 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_val,
203 0x02, 0x02);
204 break;
205 default:
206 return -EINVAL;
207 }
208 return 0;
209}
210
Joonwoo Parka8890262012-10-15 12:04:27 -0700211/* called under codec_resource_lock acquisition */
212static void wcd9xxx_pause_hs_polling(struct wcd9xxx_mbhc *mbhc)
213{
214 struct snd_soc_codec *codec = mbhc->codec;
215
216 pr_debug("%s: enter\n", __func__);
217 if (!mbhc->polling_active) {
218 pr_debug("polling not active, nothing to pause\n");
219 return;
220 }
221
222 /* Soft reset MBHC block */
223 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
224 pr_debug("%s: leave\n", __func__);
225}
226
227/* called under codec_resource_lock acquisition */
228static void wcd9xxx_start_hs_polling(struct wcd9xxx_mbhc *mbhc)
229{
230 struct snd_soc_codec *codec = mbhc->codec;
231 int mbhc_state = mbhc->mbhc_state;
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530232 int ret;
Joonwoo Parka8890262012-10-15 12:04:27 -0700233
234 pr_debug("%s: enter\n", __func__);
235 if (!mbhc->polling_active) {
236 pr_debug("Polling is not active, do not start polling\n");
237 return;
238 }
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +0530239
240 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530241 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
242 if (ret) {
243 pr_err("%s: Error returned, ret: %d\n", __func__, ret);
244 return;
245 }
246
Joonwoo Parka8890262012-10-15 12:04:27 -0700247 if (!mbhc->no_mic_headset_override &&
248 mbhc_state == MBHC_STATE_POTENTIAL) {
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530249 pr_debug("%s recovering MBHC state machine\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -0700250 mbhc->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
251 /* set to max button press threshold */
252 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL, 0x7F);
253 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, 0xFF);
254 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL, 0x7F);
255 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, 0xFF);
256 /* set to max */
257 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
258 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
259 }
260
261 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
262 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
263 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
264 pr_debug("%s: leave\n", __func__);
265}
266
267/* called under codec_resource_lock acquisition */
268static void __wcd9xxx_switch_micbias(struct wcd9xxx_mbhc *mbhc,
269 int vddio_switch, bool restartpolling,
270 bool checkpolling)
271{
272 int cfilt_k_val;
273 bool override;
274 struct snd_soc_codec *codec;
Joonwoo Park73375212013-05-07 12:42:44 -0700275 struct mbhc_internal_cal_data *d = &mbhc->mbhc_data;
Joonwoo Parka8890262012-10-15 12:04:27 -0700276
277 codec = mbhc->codec;
278
Joonwoo Parkccccba72013-04-26 11:19:46 -0700279 if (mbhc->micbias_enable) {
280 pr_debug("%s: micbias is already on\n", __func__);
281 return;
282 }
283
Joonwoo Parka8890262012-10-15 12:04:27 -0700284 if (vddio_switch && !mbhc->mbhc_micbias_switched &&
285 (!checkpolling || mbhc->polling_active)) {
286 if (restartpolling)
287 wcd9xxx_pause_hs_polling(mbhc);
288 override = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
289 0x04;
290 if (!override)
291 wcd9xxx_turn_onoff_override(codec, true);
292 /* Adjust threshold if Mic Bias voltage changes */
Joonwoo Park73375212013-05-07 12:42:44 -0700293 if (d->micb_mv != VDDIO_MICBIAS_MV) {
Joonwoo Parka8890262012-10-15 12:04:27 -0700294 cfilt_k_val = wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
295 VDDIO_MICBIAS_MV);
296 usleep_range(10000, 10000);
297 snd_soc_update_bits(codec,
298 mbhc->mbhc_bias_regs.cfilt_val,
299 0xFC, (cfilt_k_val << 2));
300 usleep_range(10000, 10000);
Joonwoo Park73375212013-05-07 12:42:44 -0700301 /* Threshods for insertion/removal */
Joonwoo Parka8890262012-10-15 12:04:27 -0700302 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700303 d->v_ins_hu[MBHC_V_IDX_VDDIO] & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700304 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700305 (d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
Joonwoo Parka8890262012-10-15 12:04:27 -0700306 0xFF);
Joonwoo Park73375212013-05-07 12:42:44 -0700307 /* Threshods for button press */
308 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
309 d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
310 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
311 (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
312 0xFF);
313 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
314 d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
315 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
316 (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
317 0xFF);
318 /* Threshods for button release */
319 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
320 d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
321 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
322 (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700323 pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
324 __func__);
325 }
326
327 /* Enable MIC BIAS Switch to VDDIO */
328 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
329 0x80, 0x80);
330 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
331 0x10, 0x00);
332 if (!override)
333 wcd9xxx_turn_onoff_override(codec, false);
334 if (restartpolling)
335 wcd9xxx_start_hs_polling(mbhc);
336
337 mbhc->mbhc_micbias_switched = true;
338 pr_debug("%s: VDDIO switch enabled\n", __func__);
339 } else if (!vddio_switch && mbhc->mbhc_micbias_switched) {
340 if ((!checkpolling || mbhc->polling_active) &&
341 restartpolling)
342 wcd9xxx_pause_hs_polling(mbhc);
343 /* Reprogram thresholds */
Joonwoo Park73375212013-05-07 12:42:44 -0700344 if (d->micb_mv != VDDIO_MICBIAS_MV) {
Joonwoo Parka8890262012-10-15 12:04:27 -0700345 cfilt_k_val =
346 wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
Joonwoo Park73375212013-05-07 12:42:44 -0700347 d->micb_mv);
Joonwoo Parka8890262012-10-15 12:04:27 -0700348 snd_soc_update_bits(codec,
349 mbhc->mbhc_bias_regs.cfilt_val,
350 0xFC, (cfilt_k_val << 2));
351 usleep_range(10000, 10000);
Joonwoo Park73375212013-05-07 12:42:44 -0700352 /* Revert threshods for insertion/removal */
Joonwoo Parka8890262012-10-15 12:04:27 -0700353 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700354 d->v_ins_hu[MBHC_V_IDX_CFILT] & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700355 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700356 (d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
357 0xFF);
358 /* Revert threshods for button press */
359 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
360 d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
361 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
362 (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
363 0xFF);
364 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
365 d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
366 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
367 (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
368 0xFF);
369 /* Revert threshods for button release */
370 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
371 d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
372 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
373 (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700374 pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
375 __func__);
376 }
377
378 /* Disable MIC BIAS Switch to VDDIO */
379 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x80,
380 0x00);
381 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x10,
382 0x00);
383
384 if ((!checkpolling || mbhc->polling_active) && restartpolling)
385 wcd9xxx_start_hs_polling(mbhc);
386
387 mbhc->mbhc_micbias_switched = false;
388 pr_debug("%s: VDDIO switch disabled\n", __func__);
389 }
390}
391
392static void wcd9xxx_switch_micbias(struct wcd9xxx_mbhc *mbhc, int vddio_switch)
393{
394 return __wcd9xxx_switch_micbias(mbhc, vddio_switch, true, true);
395}
396
Joonwoo Park73375212013-05-07 12:42:44 -0700397static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
398 const enum wcd9xxx_current_v_idx idx)
Joonwoo Parka8890262012-10-15 12:04:27 -0700399{
Joonwoo Park73375212013-05-07 12:42:44 -0700400 enum mbhc_v_index vidx;
401 s16 ret = -EINVAL;
402
Joonwoo Parka8890262012-10-15 12:04:27 -0700403 if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
404 mbhc->mbhc_micbias_switched)
Joonwoo Park73375212013-05-07 12:42:44 -0700405 vidx = MBHC_V_IDX_VDDIO;
Joonwoo Parka8890262012-10-15 12:04:27 -0700406 else
Joonwoo Park73375212013-05-07 12:42:44 -0700407 vidx = MBHC_V_IDX_CFILT;
408
409 switch (idx) {
410 case WCD9XXX_CURRENT_V_INS_H:
411 ret = (s16)mbhc->mbhc_data.v_ins_h[vidx];
412 break;
413 case WCD9XXX_CURRENT_V_INS_HU:
414 ret = (s16)mbhc->mbhc_data.v_ins_hu[vidx];
415 break;
416 case WCD9XXX_CURRENT_V_B1_H:
417 ret = (s16)mbhc->mbhc_data.v_b1_h[vidx];
418 break;
419 case WCD9XXX_CURRENT_V_B1_HU:
420 ret = (s16)mbhc->mbhc_data.v_b1_hu[vidx];
421 break;
422 case WCD9XXX_CURRENT_V_BR_H:
423 ret = (s16)mbhc->mbhc_data.v_brh[vidx];
424 break;
425 }
426
427 return ret;
Joonwoo Parka8890262012-10-15 12:04:27 -0700428}
429
430void *wcd9xxx_mbhc_cal_btn_det_mp(
431 const struct wcd9xxx_mbhc_btn_detect_cfg *btn_det,
432 const enum wcd9xxx_mbhc_btn_det_mem mem)
433{
434 void *ret = &btn_det->_v_btn_low;
435
436 switch (mem) {
437 case MBHC_BTN_DET_GAIN:
438 ret += sizeof(btn_det->_n_cic);
439 case MBHC_BTN_DET_N_CIC:
440 ret += sizeof(btn_det->_n_ready);
441 case MBHC_BTN_DET_N_READY:
442 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
443 case MBHC_BTN_DET_V_BTN_HIGH:
444 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
445 case MBHC_BTN_DET_V_BTN_LOW:
446 /* do nothing */
447 break;
448 default:
449 ret = NULL;
450 }
451
452 return ret;
453}
454EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_cal_btn_det_mp);
455
456static void wcd9xxx_calibrate_hs_polling(struct wcd9xxx_mbhc *mbhc)
457{
458 struct snd_soc_codec *codec = mbhc->codec;
Joonwoo Park73375212013-05-07 12:42:44 -0700459 const s16 v_ins_hu = wcd9xxx_get_current_v(mbhc,
460 WCD9XXX_CURRENT_V_INS_HU);
461 const s16 v_b1_hu = wcd9xxx_get_current_v(mbhc,
462 WCD9XXX_CURRENT_V_B1_HU);
463 const s16 v_b1_h = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
464 const s16 v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
Joonwoo Parka8890262012-10-15 12:04:27 -0700465
466 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
467 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
468 (v_ins_hu >> 8) & 0xFF);
Joonwoo Park73375212013-05-07 12:42:44 -0700469 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700470 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700471 (v_b1_hu >> 8) & 0xFF);
472 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700473 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700474 (v_b1_h >> 8) & 0xFF);
475 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700476 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700477 (v_brh >> 8) & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700478 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
479 mbhc->mbhc_data.v_brl & 0xFF);
480 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
481 (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
482}
483
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530484static int wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
Joonwoo Parka8890262012-10-15 12:04:27 -0700485 bool fast)
486{
487 struct snd_soc_codec *codec = mbhc->codec;
488 u8 reg_mode_val, cur_mode_val;
489
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530490 switch (mbhc->mbhc_version) {
491 case WCD9XXX_MBHC_VERSION_TAIKO:
492 if (fast)
493 reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
494 else
495 reg_mode_val = WCD9XXX_CFILT_SLOW_MODE;
Joonwoo Parka8890262012-10-15 12:04:27 -0700496
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530497 cur_mode_val =
498 snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x40;
Joonwoo Parka8890262012-10-15 12:04:27 -0700499
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530500 if (cur_mode_val != reg_mode_val) {
501 if (mbhc->polling_active)
502 wcd9xxx_pause_hs_polling(mbhc);
503 snd_soc_update_bits(codec,
504 mbhc->mbhc_bias_regs.cfilt_ctl,
505 0x40, reg_mode_val);
506 if (mbhc->polling_active)
507 wcd9xxx_start_hs_polling(mbhc);
508 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
509 cur_mode_val, reg_mode_val);
510 } else {
511 pr_debug("%s: CFILT Value is already %x\n",
512 __func__, cur_mode_val);
513 }
514 break;
515 case WCD9XXX_MBHC_VERSION_TAPAN:
516 if (fast)
517 reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
518 else
519 reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
520
521 cur_mode_val =
522 snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x70;
523
524 if (cur_mode_val != reg_mode_val) {
525 if (mbhc->polling_active)
526 wcd9xxx_pause_hs_polling(mbhc);
527 snd_soc_update_bits(codec,
528 mbhc->mbhc_bias_regs.cfilt_ctl,
529 0x70, reg_mode_val);
530 if (mbhc->polling_active)
531 wcd9xxx_start_hs_polling(mbhc);
532 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
533 cur_mode_val, reg_mode_val);
534 } else {
535 pr_debug("%s: CFILT Value is already %x\n",
536 __func__, cur_mode_val);
537 }
538 break;
539 default:
540 return -EINVAL;
Joonwoo Parka8890262012-10-15 12:04:27 -0700541 }
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530542 return 0;
Joonwoo Parka8890262012-10-15 12:04:27 -0700543}
544
Joonwoo Park3699ca32013-02-08 12:06:15 -0800545static void wcd9xxx_jack_report(struct wcd9xxx_mbhc *mbhc,
546 struct snd_soc_jack *jack, int status, int mask)
Joonwoo Parka8890262012-10-15 12:04:27 -0700547{
Joonwoo Parkaf21f032013-03-05 18:07:40 -0800548 if (jack == &mbhc->headset_jack) {
Joonwoo Park3699ca32013-02-08 12:06:15 -0800549 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
550 WCD9XXX_COND_HPH_MIC,
551 status & SND_JACK_MICROPHONE);
Joonwoo Parkaf21f032013-03-05 18:07:40 -0800552 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
553 WCD9XXX_COND_HPH,
554 status & SND_JACK_HEADPHONE);
555 }
Joonwoo Park3699ca32013-02-08 12:06:15 -0800556
Joonwoo Parka8890262012-10-15 12:04:27 -0700557 snd_soc_jack_report_no_dapm(jack, status, mask);
558}
559
560static void __hphocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status,
561 int irq)
562{
563 struct snd_soc_codec *codec;
564
565 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
566 codec = mbhc->codec;
567 if (mbhc->hph_status & jack_status) {
568 mbhc->hph_status &= ~jack_status;
Joonwoo Park3699ca32013-02-08 12:06:15 -0800569 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -0700570 mbhc->hph_status, WCD9XXX_JACK_MASK);
571 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
572 0x00);
573 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
574 0x10);
575 /*
576 * reset retry counter as PA is turned off signifying
577 * start of new OCP detection session
578 */
579 if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
580 mbhc->hphlocp_cnt = 0;
581 else
582 mbhc->hphrocp_cnt = 0;
583 wcd9xxx_enable_irq(codec->control_data, irq);
584 }
585}
586
587static void hphrocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status)
588{
589 __hphocp_off_report(mbhc, SND_JACK_OC_HPHR,
590 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
591}
592
593static void hphlocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status)
594{
595 __hphocp_off_report(mbhc, SND_JACK_OC_HPHL,
596 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
597}
598
599static void wcd9xxx_get_mbhc_micbias_regs(struct wcd9xxx_mbhc *mbhc,
600 struct mbhc_micbias_regs *micbias_regs)
601{
602 unsigned int cfilt;
603 struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
604
605 switch (mbhc->mbhc_cfg->micbias) {
606 case MBHC_MICBIAS1:
607 cfilt = pdata->micbias.bias1_cfilt_sel;
608 micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
609 micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
610 micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
611 break;
612 case MBHC_MICBIAS2:
613 cfilt = pdata->micbias.bias2_cfilt_sel;
614 micbias_regs->mbhc_reg = WCD9XXX_A_MICB_2_MBHC;
615 micbias_regs->int_rbias = WCD9XXX_A_MICB_2_INT_RBIAS;
616 micbias_regs->ctl_reg = WCD9XXX_A_MICB_2_CTL;
617 break;
618 case MBHC_MICBIAS3:
619 cfilt = pdata->micbias.bias3_cfilt_sel;
620 micbias_regs->mbhc_reg = WCD9XXX_A_MICB_3_MBHC;
621 micbias_regs->int_rbias = WCD9XXX_A_MICB_3_INT_RBIAS;
622 micbias_regs->ctl_reg = WCD9XXX_A_MICB_3_CTL;
623 break;
624 case MBHC_MICBIAS4:
625 cfilt = pdata->micbias.bias4_cfilt_sel;
626 micbias_regs->mbhc_reg = mbhc->resmgr->reg_addr->micb_4_mbhc;
627 micbias_regs->int_rbias =
628 mbhc->resmgr->reg_addr->micb_4_int_rbias;
629 micbias_regs->ctl_reg = mbhc->resmgr->reg_addr->micb_4_ctl;
630 break;
631 default:
632 /* Should never reach here */
633 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
634 return;
635 }
636
637 micbias_regs->cfilt_sel = cfilt;
638
639 switch (cfilt) {
640 case WCD9XXX_CFILT1_SEL:
641 micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
642 micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
643 mbhc->mbhc_data.micb_mv =
644 mbhc->resmgr->pdata->micbias.cfilt1_mv;
645 break;
646 case WCD9XXX_CFILT2_SEL:
647 micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_2_VAL;
648 micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_2_CTL;
649 mbhc->mbhc_data.micb_mv =
650 mbhc->resmgr->pdata->micbias.cfilt2_mv;
651 break;
652 case WCD9XXX_CFILT3_SEL:
653 micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_3_VAL;
654 micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_3_CTL;
655 mbhc->mbhc_data.micb_mv =
656 mbhc->resmgr->pdata->micbias.cfilt3_mv;
657 break;
658 }
659}
660
661static void wcd9xxx_clr_and_turnon_hph_padac(struct wcd9xxx_mbhc *mbhc)
662{
663 bool pa_turned_on = false;
664 struct snd_soc_codec *codec = mbhc->codec;
665 u8 wg_time;
666
667 wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) ;
668 wg_time += 1;
669
670 if (test_and_clear_bit(WCD9XXX_HPHR_DAC_OFF_ACK,
671 &mbhc->hph_pa_dac_state)) {
672 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
673 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_DAC_CTL,
674 0xC0, 0xC0);
675 }
676 if (test_and_clear_bit(WCD9XXX_HPHL_DAC_OFF_ACK,
677 &mbhc->hph_pa_dac_state)) {
678 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
679 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL,
680 0xC0, 0xC0);
681 }
682
683 if (test_and_clear_bit(WCD9XXX_HPHR_PA_OFF_ACK,
684 &mbhc->hph_pa_dac_state)) {
685 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
686 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x10,
687 1 << 4);
688 pa_turned_on = true;
689 }
690 if (test_and_clear_bit(WCD9XXX_HPHL_PA_OFF_ACK,
691 &mbhc->hph_pa_dac_state)) {
692 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
693 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x20, 1
694 << 5);
695 pa_turned_on = true;
696 }
697
698 if (pa_turned_on) {
699 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
700 __func__);
701 usleep_range(wg_time * 1000, wg_time * 1000);
702 }
703}
704
705static int wcd9xxx_cancel_btn_work(struct wcd9xxx_mbhc *mbhc)
706{
707 int r;
708 r = cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
709 if (r)
710 /* if scheduled mbhc.mbhc_btn_dwork is canceled from here,
711 * we have to unlock from here instead btn_work */
712 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
713 return r;
714}
715
716static bool wcd9xxx_is_hph_dac_on(struct snd_soc_codec *codec, int left)
717{
718 u8 hph_reg_val = 0;
719 if (left)
720 hph_reg_val = snd_soc_read(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL);
721 else
722 hph_reg_val = snd_soc_read(codec, WCD9XXX_A_RX_HPH_R_DAC_CTL);
723
724 return (hph_reg_val & 0xC0) ? true : false;
725}
726
727static bool wcd9xxx_is_hph_pa_on(struct snd_soc_codec *codec)
728{
729 u8 hph_reg_val = 0;
730 hph_reg_val = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_EN);
731
732 return (hph_reg_val & 0x30) ? true : false;
733}
734
735/* called under codec_resource_lock acquisition */
736static void wcd9xxx_set_and_turnoff_hph_padac(struct wcd9xxx_mbhc *mbhc)
737{
738 u8 wg_time;
739 struct snd_soc_codec *codec = mbhc->codec;
740
741 wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME);
742 wg_time += 1;
743
744 /* If headphone PA is on, check if userspace receives
745 * removal event to sync-up PA's state */
746 if (wcd9xxx_is_hph_pa_on(codec)) {
747 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
748 set_bit(WCD9XXX_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
749 set_bit(WCD9XXX_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
750 } else {
751 pr_debug("%s PA is off\n", __func__);
752 }
753
754 if (wcd9xxx_is_hph_dac_on(codec, 1))
755 set_bit(WCD9XXX_HPHL_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
756 if (wcd9xxx_is_hph_dac_on(codec, 0))
757 set_bit(WCD9XXX_HPHR_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
758
759 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30, 0x00);
Joonwoo Park67c0dbf2013-01-25 10:47:38 -0800760 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL, 0x80, 0x00);
Joonwoo Parka8890262012-10-15 12:04:27 -0700761 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xC0, 0x00);
762 usleep_range(wg_time * 1000, wg_time * 1000);
763}
764
765static void wcd9xxx_insert_detect_setup(struct wcd9xxx_mbhc *mbhc, bool ins)
766{
767 if (!mbhc->mbhc_cfg->insert_detect)
768 return;
769 pr_debug("%s: Setting up %s detection\n", __func__,
770 ins ? "insert" : "removal");
Joonwoo Park2e6bd1e2012-10-18 13:48:55 -0700771 /* Disable detection to avoid glitch */
772 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 0);
Simmi Pateriya2397f5c2013-03-25 12:21:55 +0530773 if (mbhc->mbhc_cfg->gpio_level_insert)
774 snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
775 (0x68 | (ins ? (1 << 1) : 0)));
776 else
777 snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
778 (0x6C | (ins ? (1 << 1) : 0)));
Joonwoo Park2e6bd1e2012-10-18 13:48:55 -0700779 /* Re-enable detection */
780 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 1);
Joonwoo Parka8890262012-10-15 12:04:27 -0700781}
782
783/* called under codec_resource_lock acquisition */
784static void wcd9xxx_report_plug(struct wcd9xxx_mbhc *mbhc, int insertion,
785 enum snd_jack_types jack_type)
786{
787 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
788
Joonwoo Park80a01172012-10-15 16:05:23 -0700789 pr_debug("%s: enter insertion %d hph_status %x\n",
790 __func__, insertion, mbhc->hph_status);
Joonwoo Parka8890262012-10-15 12:04:27 -0700791 if (!insertion) {
792 /* Report removal */
793 mbhc->hph_status &= ~jack_type;
794 /*
795 * cancel possibly scheduled btn work and
796 * report release if we reported button press
797 */
798 if (wcd9xxx_cancel_btn_work(mbhc))
799 pr_debug("%s: button press is canceled\n", __func__);
800 else if (mbhc->buttons_pressed) {
801 pr_debug("%s: release of button press%d\n",
802 __func__, jack_type);
Joonwoo Park3699ca32013-02-08 12:06:15 -0800803 wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
Joonwoo Parka8890262012-10-15 12:04:27 -0700804 mbhc->buttons_pressed);
805 mbhc->buttons_pressed &=
806 ~WCD9XXX_JACK_BUTTON_MASK;
807 }
Joonwoo Parkccccba72013-04-26 11:19:46 -0700808
809 if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
810 pr_debug("%s: Disabling micbias\n", __func__);
811 mbhc->micbias_enable_cb(mbhc->codec, false);
812 mbhc->micbias_enable = false;
813 }
Joonwoo Parka8890262012-10-15 12:04:27 -0700814 pr_debug("%s: Reporting removal %d(%x)\n", __func__,
815 jack_type, mbhc->hph_status);
Joonwoo Park3699ca32013-02-08 12:06:15 -0800816 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
Joonwoo Parka8890262012-10-15 12:04:27 -0700817 WCD9XXX_JACK_MASK);
818 wcd9xxx_set_and_turnoff_hph_padac(mbhc);
819 hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
820 hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
821 mbhc->current_plug = PLUG_TYPE_NONE;
822 mbhc->polling_active = false;
823 } else {
Joonwoo Park80a01172012-10-15 16:05:23 -0700824 if (mbhc->mbhc_cfg->detect_extn_cable) {
825 /* Report removal of current jack type */
Joonwoo Park20bc9da2013-01-16 12:58:06 -0800826 if (mbhc->hph_status && mbhc->hph_status != jack_type) {
Joonwoo Parkccccba72013-04-26 11:19:46 -0700827 if (mbhc->micbias_enable &&
828 mbhc->micbias_enable_cb &&
829 mbhc->hph_status == SND_JACK_HEADSET) {
830 pr_debug("%s: Disabling micbias\n",
831 __func__);
832 mbhc->micbias_enable_cb(mbhc->codec,
833 false);
834 mbhc->micbias_enable = false;
835 }
Joonwoo Park80a01172012-10-15 16:05:23 -0700836 pr_debug("%s: Reporting removal (%x)\n",
Joonwoo Parkccccba72013-04-26 11:19:46 -0700837 __func__, mbhc->hph_status);
Joonwoo Park3699ca32013-02-08 12:06:15 -0800838 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Park80a01172012-10-15 16:05:23 -0700839 0, WCD9XXX_JACK_MASK);
840 mbhc->hph_status = 0;
841 }
842 }
Joonwoo Parka8890262012-10-15 12:04:27 -0700843 /* Report insertion */
844 mbhc->hph_status |= jack_type;
845
846 if (jack_type == SND_JACK_HEADPHONE) {
847 mbhc->current_plug = PLUG_TYPE_HEADPHONE;
848 } else if (jack_type == SND_JACK_UNSUPPORTED) {
849 mbhc->current_plug = PLUG_TYPE_GND_MIC_SWAP;
850 } else if (jack_type == SND_JACK_HEADSET) {
851 mbhc->polling_active = BUTTON_POLLING_SUPPORTED;
852 mbhc->current_plug = PLUG_TYPE_HEADSET;
Joonwoo Park80a01172012-10-15 16:05:23 -0700853 } else if (jack_type == SND_JACK_LINEOUT) {
854 mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
Joonwoo Parka8890262012-10-15 12:04:27 -0700855 }
Joonwoo Parkccccba72013-04-26 11:19:46 -0700856
857 if (mbhc->micbias_enable && mbhc->micbias_enable_cb) {
858 pr_debug("%s: Enabling micbias\n", __func__);
859 mbhc->micbias_enable_cb(mbhc->codec, true);
860 }
Joonwoo Parka8890262012-10-15 12:04:27 -0700861 pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
862 jack_type, mbhc->hph_status);
Joonwoo Park3699ca32013-02-08 12:06:15 -0800863 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -0700864 mbhc->hph_status, WCD9XXX_JACK_MASK);
865 wcd9xxx_clr_and_turnon_hph_padac(mbhc);
866 }
867 /* Setup insert detect */
868 wcd9xxx_insert_detect_setup(mbhc, !insertion);
Joonwoo Park80a01172012-10-15 16:05:23 -0700869
870 pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status);
Joonwoo Parka8890262012-10-15 12:04:27 -0700871}
872
873/* should be called under interrupt context that hold suspend */
874static void wcd9xxx_schedule_hs_detect_plug(struct wcd9xxx_mbhc *mbhc,
875 struct work_struct *work)
876{
877 pr_debug("%s: scheduling wcd9xxx_correct_swch_plug\n", __func__);
878 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
879 mbhc->hs_detect_work_stop = false;
880 wcd9xxx_lock_sleep(mbhc->resmgr->core);
881 schedule_work(work);
882}
883
884/* called under codec_resource_lock acquisition */
885static void wcd9xxx_cancel_hs_detect_plug(struct wcd9xxx_mbhc *mbhc,
886 struct work_struct *work)
887{
888 pr_debug("%s: Canceling correct_plug_swch\n", __func__);
889 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
890 mbhc->hs_detect_work_stop = true;
891 wmb();
892 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
893 if (cancel_work_sync(work)) {
894 pr_debug("%s: correct_plug_swch is canceled\n",
895 __func__);
896 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
897 }
898 WCD9XXX_BCL_LOCK(mbhc->resmgr);
899}
900
Joonwoo Park73375212013-05-07 12:42:44 -0700901static s16 scale_v_micb_vddio(struct wcd9xxx_mbhc *mbhc, int v, bool tovddio)
902{
903 int r;
904 int vddio_k, mb_k;
905 vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
906 mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
907 if (tovddio)
Joonwoo Park520a0f92013-05-14 19:39:58 -0700908 r = v * (vddio_k + 4) / (mb_k + 4);
Joonwoo Park73375212013-05-07 12:42:44 -0700909 else
Joonwoo Park520a0f92013-05-14 19:39:58 -0700910 r = v * (mb_k + 4) / (vddio_k + 4);
Joonwoo Park73375212013-05-07 12:42:44 -0700911 return r;
912}
913
Joonwoo Parka8890262012-10-15 12:04:27 -0700914static s16 wcd9xxx_get_current_v_hs_max(struct wcd9xxx_mbhc *mbhc)
915{
916 s16 v_hs_max;
917 struct wcd9xxx_mbhc_plug_type_cfg *plug_type;
918
919 plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
920 if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
921 mbhc->mbhc_micbias_switched)
Joonwoo Park73375212013-05-07 12:42:44 -0700922 v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max, true);
Joonwoo Parka8890262012-10-15 12:04:27 -0700923 else
924 v_hs_max = plug_type->v_hs_max;
925 return v_hs_max;
926}
927
Joonwoo Parka8890262012-10-15 12:04:27 -0700928static short wcd9xxx_read_sta_result(struct snd_soc_codec *codec)
929{
930 u8 bias_msb, bias_lsb;
931 short bias_value;
932
933 bias_msb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B3_STATUS);
934 bias_lsb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B2_STATUS);
935 bias_value = (bias_msb << 8) | bias_lsb;
936 return bias_value;
937}
938
939static short wcd9xxx_read_dce_result(struct snd_soc_codec *codec)
940{
941 u8 bias_msb, bias_lsb;
942 short bias_value;
943
944 bias_msb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B5_STATUS);
945 bias_lsb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B4_STATUS);
946 bias_value = (bias_msb << 8) | bias_lsb;
947 return bias_value;
948}
949
950static void wcd9xxx_turn_onoff_rel_detection(struct snd_soc_codec *codec,
951 bool on)
952{
953 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
954}
955
956static short __wcd9xxx_codec_sta_dce(struct wcd9xxx_mbhc *mbhc, int dce,
957 bool override_bypass, bool noreldetection)
958{
959 short bias_value;
960 struct snd_soc_codec *codec = mbhc->codec;
961
962 wcd9xxx_disable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
963 if (noreldetection)
964 wcd9xxx_turn_onoff_rel_detection(codec, false);
965
966 /* Turn on the override */
967 if (!override_bypass)
968 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
969 if (dce) {
970 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
971 0x8);
972 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
973 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
974 0x0);
975 usleep_range(mbhc->mbhc_data.t_sta_dce,
976 mbhc->mbhc_data.t_sta_dce);
977 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
978 usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce);
979 bias_value = wcd9xxx_read_dce_result(codec);
980 } else {
981 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
982 0x8);
983 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
984 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
985 0x0);
986 usleep_range(mbhc->mbhc_data.t_sta_dce,
987 mbhc->mbhc_data.t_sta_dce);
988 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
989 usleep_range(mbhc->mbhc_data.t_sta,
990 mbhc->mbhc_data.t_sta);
991 bias_value = wcd9xxx_read_sta_result(codec);
992 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
993 0x8);
994 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x0);
995 }
996 /* Turn off the override after measuring mic voltage */
997 if (!override_bypass)
998 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04,
999 0x00);
1000
1001 if (noreldetection)
1002 wcd9xxx_turn_onoff_rel_detection(codec, true);
1003 wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
1004
1005 return bias_value;
1006}
1007
1008static short wcd9xxx_codec_sta_dce(struct wcd9xxx_mbhc *mbhc, int dce,
1009 bool norel)
1010{
1011 return __wcd9xxx_codec_sta_dce(mbhc, dce, false, norel);
1012}
1013
Joonwoo Park520a0f92013-05-14 19:39:58 -07001014static s32 __wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
1015 u16 bias_value, s16 z)
Joonwoo Parka8890262012-10-15 12:04:27 -07001016{
Joonwoo Park520a0f92013-05-14 19:39:58 -07001017 s16 value, mb;
Joonwoo Parka8890262012-10-15 12:04:27 -07001018 s32 mv;
1019
1020 value = bias_value;
1021 if (dce) {
Joonwoo Parka8890262012-10-15 12:04:27 -07001022 mb = (mbhc->mbhc_data.dce_mb);
1023 mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
1024 } else {
Joonwoo Parka8890262012-10-15 12:04:27 -07001025 mb = (mbhc->mbhc_data.sta_mb);
1026 mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
1027 }
1028
1029 return mv;
1030}
1031
Joonwoo Park520a0f92013-05-14 19:39:58 -07001032static s32 wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
1033 u16 bias_value)
1034{
1035 s16 z;
1036 z = dce ? (s16)mbhc->mbhc_data.dce_z : (s16)mbhc->mbhc_data.sta_z;
1037 return __wcd9xxx_codec_sta_dce_v(mbhc, dce, bias_value, z);
1038}
1039
Joonwoo Parka8890262012-10-15 12:04:27 -07001040/* called only from interrupt which is under codec_resource_lock acquisition */
1041static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc)
1042{
1043 struct snd_soc_codec *codec = mbhc->codec;
1044 short bias_value;
1045 u8 cfilt_mode;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301046 int ret;
Joonwoo Parka8890262012-10-15 12:04:27 -07001047
1048 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1049
1050 pr_debug("%s: enter\n", __func__);
1051 if (!mbhc->mbhc_cfg->calibration) {
1052 pr_err("%s: Error, no calibration exists\n", __func__);
1053 return -ENODEV;
1054 }
1055
1056 /*
1057 * Request BG and clock.
1058 * These will be released by wcd9xxx_cleanup_hs_polling
1059 */
1060 wcd9xxx_resmgr_get_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
1061 wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
1062
1063 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x01);
1064
1065 /* Make sure CFILT is in fast mode, save current mode */
1066 cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301067 ret = wcd9xxx_put_cfilt_fast_mode(codec, mbhc);
1068 if (ret)
1069 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07001070 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05301071 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301072 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
1073 if (ret)
1074 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07001075
1076 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x80, 0x80);
1077 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1078 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1079
1080 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x80, 0x00);
1081 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1082 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
1083
1084 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
1085 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1086
1087 wcd9xxx_calibrate_hs_polling(mbhc);
1088
1089 /* don't flip override */
1090 bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301091 snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
Joonwoo Parka8890262012-10-15 12:04:27 -07001092 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
1093
1094 return bias_value;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301095
1096gen_err:
1097 pr_err("%s: Error returned, ret: %d\n", __func__, ret);
1098 return ret;
Joonwoo Parka8890262012-10-15 12:04:27 -07001099}
1100
1101static void wcd9xxx_shutdown_hs_removal_detect(struct wcd9xxx_mbhc *mbhc)
1102{
1103 struct snd_soc_codec *codec = mbhc->codec;
1104 const struct wcd9xxx_mbhc_general_cfg *generic =
1105 WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
1106
1107 /* Need MBHC clock */
1108 wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
1109
1110 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
1111 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Joonwoo Park2cee50a2013-05-15 14:09:06 -07001112 __wcd9xxx_switch_micbias(mbhc, 0, false, false);
Joonwoo Parka8890262012-10-15 12:04:27 -07001113
1114 usleep_range(generic->t_shutdown_plug_rem,
1115 generic->t_shutdown_plug_rem);
1116
1117 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
1118
1119 /* Put requested CLK back */
1120 wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
1121
1122 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x00);
1123}
1124
1125static void wcd9xxx_cleanup_hs_polling(struct wcd9xxx_mbhc *mbhc)
1126{
1127 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1128
1129 wcd9xxx_shutdown_hs_removal_detect(mbhc);
1130
1131 /* Release clock and BG requested by wcd9xxx_mbhc_setup_hs_polling */
1132 wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
1133 wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
1134
1135 mbhc->polling_active = false;
1136 mbhc->mbhc_state = MBHC_STATE_NONE;
1137}
1138
Joonwoo Parka8890262012-10-15 12:04:27 -07001139/* called under codec_resource_lock acquisition */
1140static void wcd9xxx_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
1141{
1142 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01, on);
1143 if (on)
1144 usleep_range(5000, 5000);
1145}
1146
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -07001147static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
1148{
Joonwoo Parkccccba72013-04-26 11:19:46 -07001149 pr_debug("%s: vddio %d\n", __func__, on);
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -07001150 if (on) {
1151 snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
1152 1 << 7, 1 << 7);
1153 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
1154 1 << 4, 0);
1155 } else {
1156 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
1157 1 << 4, 1 << 4);
1158 snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
1159 1 << 7, 0);
1160 }
1161 if (on)
1162 usleep_range(10000, 10000);
1163}
1164
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001165static int wcd9xxx_hphl_status(struct wcd9xxx_mbhc *mbhc)
1166{
1167 u16 hph, status;
1168 struct snd_soc_codec *codec = mbhc->codec;
1169
1170 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1171 hph = snd_soc_read(codec, WCD9XXX_A_MBHC_HPH);
1172 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x12, 0x02);
1173 usleep_range(WCD9XXX_HPHL_STATUS_READY_WAIT_US,
1174 WCD9XXX_HPHL_STATUS_READY_WAIT_US +
1175 WCD9XXX_USLEEP_RANGE_MARGIN_US);
1176 status = snd_soc_read(codec, WCD9XXX_A_RX_HPH_L_STATUS);
1177 snd_soc_write(codec, WCD9XXX_A_MBHC_HPH, hph);
1178 return status;
1179}
1180
1181/*
1182 * wcd9xxx_find_plug_type : Find out and return the best plug type with given
1183 * list of wcd9xxx_mbhc_detect structure.
1184 */
1185static enum wcd9xxx_mbhc_plug_type
1186wcd9xxx_find_plug_type(struct wcd9xxx_mbhc *mbhc,
1187 struct wcd9xxx_mbhc_detect *dt, const int size)
1188{
1189 int i;
1190 int ch;
1191 enum wcd9xxx_mbhc_plug_type type;
1192 int vdce;
Joonwoo Parkccccba72013-04-26 11:19:46 -07001193 struct wcd9xxx_mbhc_detect *d, *dprev, *dgnd = NULL, *dvddio = NULL;
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001194 int maxv = 0, minv = 0;
1195 const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
1196 WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
1197 const s16 hs_max = plug_type->v_hs_max;
1198 const s16 no_mic = plug_type->v_no_mic;
1199
1200 for (i = 0, d = dt, ch = 0; i < size; i++, d++) {
1201 vdce = wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce);
1202 if (d->vddio)
1203 d->_vdces = scale_v_micb_vddio(mbhc, vdce, false);
1204 else
1205 d->_vdces = vdce;
1206
1207 if (d->_vdces >= no_mic && d->_vdces < hs_max)
1208 d->_type = PLUG_TYPE_HEADSET;
1209 else if (d->_vdces < no_mic)
1210 d->_type = PLUG_TYPE_HEADPHONE;
1211 else
1212 d->_type = PLUG_TYPE_HIGH_HPH;
1213
1214 ch += d->hphl_status & 0x01;
Joonwoo Parkccccba72013-04-26 11:19:46 -07001215 if (!d->swap_gnd && !d->hwvalue && !d->vddio) {
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001216 if (maxv < d->_vdces)
1217 maxv = d->_vdces;
1218 if (!minv || minv > d->_vdces)
1219 minv = d->_vdces;
1220 }
1221
1222 pr_debug("%s: DCE #%d, %04x, V %04d(%04d), GND %d, VDDIO %d, HPHL %d TYPE %d\n",
1223 __func__, i, d->dce, vdce, d->_vdces,
1224 d->swap_gnd, d->vddio, d->hphl_status & 0x01,
1225 d->_type);
Joonwoo Park141d6182013-03-05 12:25:46 -08001226
1227
1228 /*
1229 * If GND and MIC prongs are aligned to HPHR and GND of
1230 * headphone, codec measures the voltage based on
1231 * impedance between HPHR and GND which results in ~80mv.
1232 * Avoid this.
1233 */
1234 if (d->_vdces >= WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
1235 d->_vdces <= WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV) {
1236 pr_debug("%s: within invalid range\n", __func__);
1237 type = PLUG_TYPE_INVALID;
1238 goto exit;
1239 }
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001240 }
1241 if (ch != size && ch > 0) {
1242 pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
1243 type = PLUG_TYPE_INVALID;
1244 goto exit;
1245 }
1246
Phani Kumar Uppalapatiec818fe2013-03-13 15:39:03 -07001247 for (i = 0, d = dt; i < size; i++, d++) {
Joonwoo Parkccccba72013-04-26 11:19:46 -07001248 if (d->vddio) {
1249 dvddio = d;
1250 continue;
1251 }
1252
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001253 if ((i > 0) && (d->_type != dprev->_type)) {
1254 pr_debug("%s: Invalid, inconsistent types\n", __func__);
1255 type = PLUG_TYPE_INVALID;
1256 goto exit;
1257 }
1258
1259 if (!d->swap_gnd && !d->hwvalue &&
1260 (abs(minv - d->_vdces) > WCD9XXX_MEAS_DELTA_MAX_MV ||
1261 abs(maxv - d->_vdces) > WCD9XXX_MEAS_DELTA_MAX_MV)) {
1262 pr_debug("%s: Invalid, delta %dmv, %dmv and %dmv\n",
1263 __func__, d->_vdces, minv, maxv);
1264 type = PLUG_TYPE_INVALID;
1265 goto exit;
1266 } else if (d->swap_gnd) {
1267 dgnd = d;
1268 }
1269 dprev = d;
1270 }
1271
1272 WARN_ON(i != size);
1273 type = dt->_type;
1274 if (type == PLUG_TYPE_HEADSET && dgnd) {
1275 if ((dgnd->_vdces + WCD9XXX_GM_SWAP_THRES_MIN_MV <
1276 minv) &&
1277 (dgnd->_vdces + WCD9XXX_GM_SWAP_THRES_MAX_MV >
1278 maxv))
1279 type = PLUG_TYPE_GND_MIC_SWAP;
1280 }
Phani Kumar Uppalapatiec818fe2013-03-13 15:39:03 -07001281 if (((type == PLUG_TYPE_HEADSET || type == PLUG_TYPE_HEADPHONE) &&
1282 ch != size) || (type == PLUG_TYPE_GND_MIC_SWAP && ch)) {
1283 pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
1284 __func__, type);
1285 type = PLUG_TYPE_INVALID;
1286 }
Joonwoo Parkccccba72013-04-26 11:19:46 -07001287 if (type == PLUG_TYPE_HEADSET && dvddio) {
1288 if ((dvddio->_vdces > hs_max) ||
1289 (dvddio->_vdces > minv + WCD9XXX_THRESHOLD_MIC_THRESHOLD)) {
1290 pr_debug("%s: Headset with threshold on MIC detected\n",
1291 __func__);
1292 if (mbhc->mbhc_cfg->micbias_enable_flags &
1293 (1 << MBHC_MICBIAS_ENABLE_THRESHOLD_HEADSET))
1294 mbhc->micbias_enable = true;
1295 } else {
1296 pr_debug("%s: Headset with regular MIC detected\n",
1297 __func__);
1298 if (mbhc->mbhc_cfg->micbias_enable_flags &
1299 (1 << MBHC_MICBIAS_ENABLE_REGULAR_HEADSET))
1300 mbhc->micbias_enable = true;
1301 }
1302 }
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001303exit:
Joonwoo Parkccccba72013-04-26 11:19:46 -07001304 pr_debug("%s: Plug type %d detected, micbias_enable %d\n", __func__,
1305 type, mbhc->micbias_enable);
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001306 return type;
1307}
1308
Joonwoo Parkccccba72013-04-26 11:19:46 -07001309/*
1310 * Pull down MBHC micbias for provided duration in microsecond.
1311 */
1312static int wcd9xxx_pull_down_micbias(struct wcd9xxx_mbhc *mbhc, int us)
1313{
1314 bool micbiasconn = false;
1315 struct snd_soc_codec *codec = mbhc->codec;
1316 const u16 ctlreg = mbhc->mbhc_bias_regs.ctl_reg;
1317
1318 /*
1319 * Disable MBHC to micbias connection to pull down
1320 * micbias and pull down micbias for a moment.
1321 */
1322 if ((snd_soc_read(mbhc->codec, ctlreg) & 0x01)) {
1323 WARN_ONCE(1, "MBHC micbias is already pulled down unexpectedly\n");
1324 return -EFAULT;
1325 }
1326
1327 if ((snd_soc_read(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL) & 1 << 4)) {
1328 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
1329 1 << 4, 0);
1330 micbiasconn = true;
1331 }
1332
1333 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
1334
1335 /*
1336 * Pull down for 1ms to discharge bias. Give small margin (10us) to be
1337 * able to get consistent result across DCEs.
1338 */
1339 usleep_range(1000, 1000 + 10);
1340
1341 if (micbiasconn)
1342 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
1343 1 << 4, 1 << 4);
1344 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
1345 usleep_range(us, us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
1346
1347 return 0;
1348}
1349
Joonwoo Parka8890262012-10-15 12:04:27 -07001350static enum wcd9xxx_mbhc_plug_type
1351wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
1352{
1353 int i;
Joonwoo Parka8890262012-10-15 12:04:27 -07001354 struct wcd9xxx_mbhc_plug_type_cfg *plug_type_ptr;
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001355 struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT];
1356 enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
Joonwoo Parka8890262012-10-15 12:04:27 -07001357 struct snd_soc_codec *codec = mbhc->codec;
Joonwoo Parka8890262012-10-15 12:04:27 -07001358
Joonwoo Park80a01172012-10-15 16:05:23 -07001359 pr_debug("%s: enter\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001360 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1361
1362 /* make sure override is on */
1363 WARN_ON(!(snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x04));
1364
1365 /* GND and MIC swap detection requires at least 2 rounds of DCE */
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001366 BUG_ON(NUM_DCE_PLUG_INS_DETECT < 2);
Joonwoo Parka8890262012-10-15 12:04:27 -07001367
1368 plug_type_ptr =
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001369 WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
Joonwoo Parka8890262012-10-15 12:04:27 -07001370
Joonwoo Parkccccba72013-04-26 11:19:46 -07001371 /*
1372 * cfilter in fast mode requires 1ms to charge up and down micbias
1373 * fully.
1374 */
1375 (void) wcd9xxx_pull_down_micbias(mbhc,
1376 WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001377 rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
1378 rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc);
1379 rt[0].swap_gnd = false;
1380 rt[0].vddio = false;
1381 rt[0].hwvalue = true;
1382 for (i = 1; i < NUM_DCE_PLUG_INS_DETECT; i++) {
1383 rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 2);
1384 if (detect_use_vddio_switch)
Joonwoo Parkccccba72013-04-26 11:19:46 -07001385 rt[i].vddio = (i == 1);
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001386 else
1387 rt[i].vddio = false;
1388 rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
1389 rt[i].hwvalue = false;
1390 if (rt[i].swap_gnd)
1391 wcd9xxx_codec_hphr_gnd_switch(codec, true);
1392 if (rt[i].vddio)
1393 wcd9xxx_onoff_vddio_switch(mbhc, true);
Joonwoo Parkccccba72013-04-26 11:19:46 -07001394 /*
1395 * Pull down micbias to detect headset with mic which has
1396 * threshold and to have more consistent voltage measurements.
1397 *
1398 * cfilter in fast mode requires 1ms to charge up and down
1399 * micbias fully.
1400 */
1401 (void) wcd9xxx_pull_down_micbias(mbhc,
1402 WCD9XXX_MICBIAS_PULLDOWN_SETTLE_US);
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001403 rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
1404 if (rt[i].vddio)
1405 wcd9xxx_onoff_vddio_switch(mbhc, false);
1406 if (rt[i].swap_gnd)
1407 wcd9xxx_codec_hphr_gnd_switch(codec, false);
Joonwoo Parka8890262012-10-15 12:04:27 -07001408 }
1409
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001410 type = wcd9xxx_find_plug_type(mbhc, rt, ARRAY_SIZE(rt));
Joonwoo Parka8890262012-10-15 12:04:27 -07001411
Joonwoo Park80a01172012-10-15 16:05:23 -07001412 pr_debug("%s: leave\n", __func__);
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001413 return type;
Joonwoo Parka8890262012-10-15 12:04:27 -07001414}
1415
1416static bool wcd9xxx_swch_level_remove(struct wcd9xxx_mbhc *mbhc)
1417{
1418 if (mbhc->mbhc_cfg->gpio)
1419 return (gpio_get_value_cansleep(mbhc->mbhc_cfg->gpio) !=
1420 mbhc->mbhc_cfg->gpio_level_insert);
1421 else if (mbhc->mbhc_cfg->insert_detect)
1422 return snd_soc_read(mbhc->codec,
1423 WCD9XXX_A_MBHC_INSERT_DET_STATUS) &
1424 (1 << 2);
1425 else
1426 WARN(1, "Invalid jack detection configuration\n");
1427
1428 return true;
1429}
1430
1431static bool is_clk_active(struct snd_soc_codec *codec)
1432{
1433 return !!(snd_soc_read(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL) & 0x05);
1434}
1435
1436static int wcd9xxx_enable_hs_detect(struct wcd9xxx_mbhc *mbhc,
1437 int insertion, int trigger, bool padac_off)
1438{
1439 struct snd_soc_codec *codec = mbhc->codec;
1440 int central_bias_enabled = 0;
1441 const struct wcd9xxx_mbhc_general_cfg *generic =
1442 WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
1443 const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
1444 WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
1445
Joonwoo Park80a01172012-10-15 16:05:23 -07001446 pr_debug("%s: enter insertion(%d) trigger(0x%x)\n",
1447 __func__, insertion, trigger);
1448
Joonwoo Parka8890262012-10-15 12:04:27 -07001449 if (!mbhc->mbhc_cfg->calibration) {
1450 pr_err("Error, no wcd9xxx calibration\n");
1451 return -EINVAL;
1452 }
1453
1454 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0);
1455
1456 /*
1457 * Make sure mic bias and Mic line schmitt trigger
1458 * are turned OFF
1459 */
1460 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
1461 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
1462
1463 if (insertion) {
1464 wcd9xxx_switch_micbias(mbhc, 0);
1465
1466 /* DAPM can manipulate PA/DAC bits concurrently */
1467 if (padac_off == true)
1468 wcd9xxx_set_and_turnoff_hph_padac(mbhc);
1469
1470 if (trigger & MBHC_USE_HPHL_TRIGGER) {
1471 /* Enable HPH Schmitt Trigger */
1472 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x11,
1473 0x11);
1474 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x0C,
1475 plug_det->hph_current << 2);
1476 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x02,
1477 0x02);
1478 }
1479 if (trigger & MBHC_USE_MB_TRIGGER) {
1480 /* enable the mic line schmitt trigger */
1481 snd_soc_update_bits(codec,
1482 mbhc->mbhc_bias_regs.mbhc_reg,
1483 0x60, plug_det->mic_current << 5);
1484 snd_soc_update_bits(codec,
1485 mbhc->mbhc_bias_regs.mbhc_reg,
1486 0x80, 0x80);
1487 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
1488 snd_soc_update_bits(codec,
1489 mbhc->mbhc_bias_regs.ctl_reg, 0x01,
1490 0x00);
1491 snd_soc_update_bits(codec,
1492 mbhc->mbhc_bias_regs.mbhc_reg,
1493 0x10, 0x10);
1494 }
1495
1496 /* setup for insetion detection */
1497 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x2, 0);
1498 } else {
1499 pr_debug("setup for removal detection\n");
1500 /* Make sure the HPH schmitt trigger is OFF */
1501 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x12, 0x00);
1502
1503 /* enable the mic line schmitt trigger */
1504 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg,
1505 0x01, 0x00);
1506 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x60,
1507 plug_det->mic_current << 5);
1508 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
1509 0x80, 0x80);
1510 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
1511 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
1512 0x10, 0x10);
1513
1514 /* Setup for low power removal detection */
1515 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x2,
1516 0x2);
1517 }
1518
1519 if (snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x4) {
1520 /* called by interrupt */
1521 if (!is_clk_active(codec)) {
1522 wcd9xxx_resmgr_enable_config_mode(codec, 1);
1523 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
1524 0x06, 0);
1525 usleep_range(generic->t_shutdown_plug_rem,
1526 generic->t_shutdown_plug_rem);
1527 wcd9xxx_resmgr_enable_config_mode(codec, 0);
1528 } else
1529 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
1530 0x06, 0);
1531 }
1532
1533 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.int_rbias, 0x80, 0);
1534
1535 /* If central bandgap disabled */
1536 if (!(snd_soc_read(codec, WCD9XXX_A_PIN_CTL_OE1) & 1)) {
1537 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE1, 0x3, 0x3);
1538 usleep_range(generic->t_bg_fast_settle,
1539 generic->t_bg_fast_settle);
1540 central_bias_enabled = 1;
1541 }
1542
1543 /* If LDO_H disabled */
1544 if (snd_soc_read(codec, WCD9XXX_A_PIN_CTL_OE0) & 0x80) {
1545 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE0, 0x10, 0);
1546 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE0, 0x80, 0x80);
1547 usleep_range(generic->t_ldoh, generic->t_ldoh);
1548 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE0, 0x80, 0);
1549
1550 if (central_bias_enabled)
1551 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE1, 0x1,
1552 0);
1553 }
1554
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301555 if (mbhc->resmgr->reg_addr->micb_4_mbhc)
1556 snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
1557 0x3, mbhc->mbhc_cfg->micbias);
Joonwoo Parka8890262012-10-15 12:04:27 -07001558
1559 wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_INSERTION);
1560 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
Joonwoo Park80a01172012-10-15 16:05:23 -07001561 pr_debug("%s: leave\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001562
1563 return 0;
1564}
1565
1566/* called under codec_resource_lock acquisition */
1567static void wcd9xxx_find_plug_and_report(struct wcd9xxx_mbhc *mbhc,
1568 enum wcd9xxx_mbhc_plug_type plug_type)
1569{
Joonwoo Park80a01172012-10-15 16:05:23 -07001570 pr_debug("%s: enter current_plug(%d) new_plug(%d)\n",
1571 __func__, mbhc->current_plug, plug_type);
1572
Joonwoo Parka8890262012-10-15 12:04:27 -07001573 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1574
1575 if (plug_type == PLUG_TYPE_HEADPHONE &&
1576 mbhc->current_plug == PLUG_TYPE_NONE) {
1577 /*
1578 * Nothing was reported previously
1579 * report a headphone or unsupported
1580 */
1581 wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
1582 wcd9xxx_cleanup_hs_polling(mbhc);
1583 } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
Joonwoo Park80a01172012-10-15 16:05:23 -07001584 if (!mbhc->mbhc_cfg->detect_extn_cable) {
1585 if (mbhc->current_plug == PLUG_TYPE_HEADSET)
1586 wcd9xxx_report_plug(mbhc, 0,
1587 SND_JACK_HEADSET);
1588 else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE)
1589 wcd9xxx_report_plug(mbhc, 0,
1590 SND_JACK_HEADPHONE);
1591 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001592 wcd9xxx_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED);
1593 wcd9xxx_cleanup_hs_polling(mbhc);
1594 } else if (plug_type == PLUG_TYPE_HEADSET) {
1595 /*
1596 * If Headphone was reported previously, this will
1597 * only report the mic line
1598 */
1599 wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
1600 msleep(100);
Joonwoo Park2cee50a2013-05-15 14:09:06 -07001601
1602 /* if PA is already on, switch micbias source to VDDIO */
1603 if (mbhc->event_state &
1604 (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR))
1605 __wcd9xxx_switch_micbias(mbhc, 1, false, false);
Joonwoo Parka8890262012-10-15 12:04:27 -07001606 wcd9xxx_start_hs_polling(mbhc);
1607 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
Joonwoo Park80a01172012-10-15 16:05:23 -07001608 if (mbhc->mbhc_cfg->detect_extn_cable) {
1609 /* High impedance device found. Report as LINEOUT*/
1610 wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
1611 wcd9xxx_cleanup_hs_polling(mbhc);
1612 pr_debug("%s: setup mic trigger for further detection\n",
1613 __func__);
1614 mbhc->lpi_enabled = true;
1615 /*
1616 * Do not enable HPHL trigger. If playback is active,
1617 * it might lead to continuous false HPHL triggers
1618 */
1619 wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER,
1620 false);
1621 } else {
1622 if (mbhc->current_plug == PLUG_TYPE_NONE)
1623 wcd9xxx_report_plug(mbhc, 1,
1624 SND_JACK_HEADPHONE);
1625 wcd9xxx_cleanup_hs_polling(mbhc);
1626 pr_debug("setup mic trigger for further detection\n");
1627 mbhc->lpi_enabled = true;
1628 wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER |
1629 MBHC_USE_HPHL_TRIGGER,
1630 false);
1631 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001632 } else {
1633 WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
1634 mbhc->current_plug, plug_type);
1635 }
Joonwoo Park80a01172012-10-15 16:05:23 -07001636 pr_debug("%s: leave\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001637}
1638
1639/* called under codec_resource_lock acquisition */
1640static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc)
1641{
1642 enum wcd9xxx_mbhc_plug_type plug_type;
1643 struct snd_soc_codec *codec = mbhc->codec;
1644
1645 pr_debug("%s: enter\n", __func__);
1646
1647 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1648
1649 wcd9xxx_turn_onoff_override(codec, true);
1650 plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
1651 wcd9xxx_turn_onoff_override(codec, false);
1652
1653 if (wcd9xxx_swch_level_remove(mbhc)) {
1654 pr_debug("%s: Switch level is low when determining plug\n",
1655 __func__);
1656 return;
1657 }
1658
1659 if (plug_type == PLUG_TYPE_INVALID ||
1660 plug_type == PLUG_TYPE_GND_MIC_SWAP) {
1661 wcd9xxx_schedule_hs_detect_plug(mbhc,
1662 &mbhc->correct_plug_swch);
1663 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
1664 wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
1665 wcd9xxx_schedule_hs_detect_plug(mbhc,
1666 &mbhc->correct_plug_swch);
Phani Kumar Uppalapatida7c7ab2013-04-10 16:38:19 -07001667 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
1668 wcd9xxx_schedule_hs_detect_plug(mbhc,
1669 &mbhc->correct_plug_swch);
Joonwoo Parka8890262012-10-15 12:04:27 -07001670 } else {
1671 pr_debug("%s: Valid plug found, determine plug type %d\n",
1672 __func__, plug_type);
1673 wcd9xxx_find_plug_and_report(mbhc, plug_type);
1674 }
Joonwoo Park80a01172012-10-15 16:05:23 -07001675 pr_debug("%s: leave\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001676}
1677
1678/* called under codec_resource_lock acquisition */
1679static void wcd9xxx_mbhc_detect_plug_type(struct wcd9xxx_mbhc *mbhc)
1680{
1681 struct snd_soc_codec *codec = mbhc->codec;
1682 const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
1683 WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
1684
Joonwoo Park80a01172012-10-15 16:05:23 -07001685 pr_debug("%s: enter\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001686 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1687
1688 /*
1689 * Turn on the override,
1690 * wcd9xxx_mbhc_setup_hs_polling requires override on
1691 */
1692 wcd9xxx_turn_onoff_override(codec, true);
1693 if (plug_det->t_ins_complete > 20)
1694 msleep(plug_det->t_ins_complete);
1695 else
1696 usleep_range(plug_det->t_ins_complete * 1000,
1697 plug_det->t_ins_complete * 1000);
1698 /* Turn off the override */
1699 wcd9xxx_turn_onoff_override(codec, false);
1700
1701 if (wcd9xxx_swch_level_remove(mbhc))
1702 pr_debug("%s: Switch level low when determining plug\n",
1703 __func__);
1704 else
1705 wcd9xxx_mbhc_decide_swch_plug(mbhc);
Joonwoo Park80a01172012-10-15 16:05:23 -07001706 pr_debug("%s: leave\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001707}
1708
1709/* called only from interrupt which is under codec_resource_lock acquisition */
1710static void wcd9xxx_hs_insert_irq_swch(struct wcd9xxx_mbhc *mbhc,
1711 bool is_removal)
1712{
1713 if (!is_removal) {
1714 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
1715
1716 rmb();
1717 if (mbhc->lpi_enabled)
1718 msleep(100);
1719
1720 rmb();
1721 if (!mbhc->lpi_enabled) {
1722 pr_debug("%s: lpi is disabled\n", __func__);
1723 } else if (!wcd9xxx_swch_level_remove(mbhc)) {
1724 pr_debug("%s: Valid insertion, detect plug type\n",
1725 __func__);
1726 wcd9xxx_mbhc_decide_swch_plug(mbhc);
1727 } else {
1728 pr_debug("%s: Invalid insertion stop plug detection\n",
1729 __func__);
1730 }
Joonwoo Park80a01172012-10-15 16:05:23 -07001731 } else if (mbhc->mbhc_cfg->detect_extn_cable) {
1732 pr_debug("%s: Removal\n", __func__);
1733 if (!wcd9xxx_swch_level_remove(mbhc)) {
1734 /*
1735 * Switch indicates, something is still inserted.
1736 * This could be extension cable i.e. headset is
1737 * removed from extension cable.
1738 */
1739 /* cancel detect plug */
1740 wcd9xxx_cancel_hs_detect_plug(mbhc,
1741 &mbhc->correct_plug_swch);
1742 wcd9xxx_mbhc_decide_swch_plug(mbhc);
1743 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001744 } else {
1745 pr_err("%s: Switch IRQ used, invalid MBHC Removal\n", __func__);
1746 }
1747}
1748
1749static bool is_valid_mic_voltage(struct wcd9xxx_mbhc *mbhc, s32 mic_mv)
1750{
1751 const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
1752 WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
1753 const s16 v_hs_max = wcd9xxx_get_current_v_hs_max(mbhc);
1754
1755 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
1756 && (mic_mv < v_hs_max)) ? true : false;
1757}
1758
1759/*
1760 * called under codec_resource_lock acquisition
1761 * returns true if mic voltage range is back to normal insertion
1762 * returns false either if timedout or removed
1763 */
1764static bool wcd9xxx_hs_remove_settle(struct wcd9xxx_mbhc *mbhc)
1765{
1766 int i;
1767 bool timedout, settled = false;
1768 s32 mic_mv[NUM_DCE_PLUG_DETECT];
1769 short mb_v[NUM_DCE_PLUG_DETECT];
1770 unsigned long retry = 0, timeout;
1771
1772 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
1773 while (!(timedout = time_after(jiffies, timeout))) {
1774 retry++;
1775 if (wcd9xxx_swch_level_remove(mbhc)) {
1776 pr_debug("%s: Switch indicates removal\n", __func__);
1777 break;
1778 }
1779
1780 if (retry > 1)
1781 msleep(250);
1782 else
1783 msleep(50);
1784
1785 if (wcd9xxx_swch_level_remove(mbhc)) {
1786 pr_debug("%s: Switch indicates removal\n", __func__);
1787 break;
1788 }
1789
1790 for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
1791 mb_v[i] = wcd9xxx_codec_sta_dce(mbhc, 1, true);
1792 mic_mv[i] = wcd9xxx_codec_sta_dce_v(mbhc, 1 , mb_v[i]);
1793 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
1794 __func__, retry, mic_mv[i], mb_v[i]);
1795 }
1796
1797 if (wcd9xxx_swch_level_remove(mbhc)) {
1798 pr_debug("%s: Switcn indicates removal\n", __func__);
1799 break;
1800 }
1801
1802 if (mbhc->current_plug == PLUG_TYPE_NONE) {
1803 pr_debug("%s : headset/headphone is removed\n",
1804 __func__);
1805 break;
1806 }
1807
1808 for (i = 0; i < NUM_DCE_PLUG_DETECT; i++)
1809 if (!is_valid_mic_voltage(mbhc, mic_mv[i]))
1810 break;
1811
1812 if (i == NUM_DCE_PLUG_DETECT) {
1813 pr_debug("%s: MIC voltage settled\n", __func__);
1814 settled = true;
1815 msleep(200);
1816 break;
1817 }
1818 }
1819
1820 if (timedout)
1821 pr_debug("%s: Microphone did not settle in %d seconds\n",
1822 __func__, HS_DETECT_PLUG_TIME_MS);
1823 return settled;
1824}
1825
1826/* called only from interrupt which is under codec_resource_lock acquisition */
1827static void wcd9xxx_hs_remove_irq_swch(struct wcd9xxx_mbhc *mbhc)
1828{
Joonwoo Park80a01172012-10-15 16:05:23 -07001829 pr_debug("%s: enter\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001830 if (wcd9xxx_hs_remove_settle(mbhc))
1831 wcd9xxx_start_hs_polling(mbhc);
Joonwoo Park80a01172012-10-15 16:05:23 -07001832 pr_debug("%s: leave\n", __func__);
1833}
1834
1835/* called only from interrupt which is under codec_resource_lock acquisition */
1836static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc)
1837{
1838 short bias_value;
1839 bool removed = true;
1840 struct snd_soc_codec *codec = mbhc->codec;
1841 const struct wcd9xxx_mbhc_general_cfg *generic =
1842 WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
1843 int min_us = FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
1844
1845 pr_debug("%s: enter\n", __func__);
1846 if (mbhc->current_plug != PLUG_TYPE_HEADSET) {
1847 pr_debug("%s(): Headset is not inserted, ignore removal\n",
1848 __func__);
1849 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
1850 0x08, 0x08);
1851 return;
1852 }
1853
1854 usleep_range(generic->t_shutdown_plug_rem,
1855 generic->t_shutdown_plug_rem);
1856
1857 do {
1858 bias_value = wcd9xxx_codec_sta_dce(mbhc, 1, true);
1859 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
1860 wcd9xxx_codec_sta_dce_v(mbhc, 1, bias_value), min_us);
Joonwoo Park73375212013-05-07 12:42:44 -07001861 if (bias_value <
1862 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H)) {
Joonwoo Park80a01172012-10-15 16:05:23 -07001863 pr_debug("%s: checking false removal\n", __func__);
1864 msleep(500);
1865 removed = !wcd9xxx_hs_remove_settle(mbhc);
1866 pr_debug("%s: headset %sactually removed\n", __func__,
1867 removed ? "" : "not ");
1868 break;
1869 }
1870 min_us -= mbhc->mbhc_data.t_dce;
1871 } while (min_us > 0);
1872
1873 if (removed) {
1874 if (mbhc->mbhc_cfg->detect_extn_cable) {
1875 if (!wcd9xxx_swch_level_remove(mbhc)) {
1876 /*
1877 * extension cable is still plugged in
1878 * report it as LINEOUT device
1879 */
1880 wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
1881 wcd9xxx_cleanup_hs_polling(mbhc);
1882 wcd9xxx_enable_hs_detect(mbhc, 1,
1883 MBHC_USE_MB_TRIGGER,
1884 false);
1885 }
1886 } else {
1887 /* Cancel possibly running hs_detect_work */
1888 wcd9xxx_cancel_hs_detect_plug(mbhc,
1889 &mbhc->correct_plug_noswch);
1890 /*
1891 * If this removal is not false, first check the micbias
1892 * switch status and switch it to LDOH if it is already
1893 * switched to VDDIO.
1894 */
1895 wcd9xxx_switch_micbias(mbhc, 0);
1896
1897 wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
1898 wcd9xxx_cleanup_hs_polling(mbhc);
1899 wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER |
1900 MBHC_USE_HPHL_TRIGGER,
1901 true);
1902 }
1903 } else {
1904 wcd9xxx_start_hs_polling(mbhc);
1905 }
1906 pr_debug("%s: leave\n", __func__);
1907}
1908
1909/* called only from interrupt which is under codec_resource_lock acquisition */
1910static void wcd9xxx_hs_insert_irq_extn(struct wcd9xxx_mbhc *mbhc,
1911 bool is_mb_trigger)
1912{
1913 /* Cancel possibly running hs_detect_work */
1914 wcd9xxx_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
1915
1916 if (is_mb_trigger) {
1917 pr_debug("%s: Waiting for Headphone left trigger\n", __func__);
1918 wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_HPHL_TRIGGER, false);
1919 } else {
1920 pr_debug("%s: HPHL trigger received, detecting plug type\n",
1921 __func__);
1922 wcd9xxx_mbhc_detect_plug_type(mbhc);
1923 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001924}
1925
1926static irqreturn_t wcd9xxx_hs_remove_irq(int irq, void *data)
1927{
Joonwoo Parka8890262012-10-15 12:04:27 -07001928 struct wcd9xxx_mbhc *mbhc = data;
1929
1930 pr_debug("%s: enter, removal interrupt\n", __func__);
1931 WCD9XXX_BCL_LOCK(mbhc->resmgr);
Joonwoo Park3699ca32013-02-08 12:06:15 -08001932 /*
1933 * While we don't know whether MIC is there or not, let the resmgr know
1934 * so micbias can be disabled temporarily
1935 */
Joonwoo Parkaf21f032013-03-05 18:07:40 -08001936 if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
Joonwoo Park3699ca32013-02-08 12:06:15 -08001937 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1938 WCD9XXX_COND_HPH_MIC, false);
Joonwoo Parkaf21f032013-03-05 18:07:40 -08001939 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1940 WCD9XXX_COND_HPH, false);
1941 } else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
1942 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1943 WCD9XXX_COND_HPH, false);
1944 }
Joonwoo Park3699ca32013-02-08 12:06:15 -08001945
Joonwoo Park80a01172012-10-15 16:05:23 -07001946 if (mbhc->mbhc_cfg->detect_extn_cable &&
1947 !wcd9xxx_swch_level_remove(mbhc))
1948 wcd9xxx_hs_remove_irq_noswch(mbhc);
1949 else
1950 wcd9xxx_hs_remove_irq_swch(mbhc);
Joonwoo Parka8890262012-10-15 12:04:27 -07001951
Joonwoo Parkaf21f032013-03-05 18:07:40 -08001952 if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
1953 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1954 WCD9XXX_COND_HPH, true);
Joonwoo Park3699ca32013-02-08 12:06:15 -08001955 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1956 WCD9XXX_COND_HPH_MIC, true);
Joonwoo Parkaf21f032013-03-05 18:07:40 -08001957 } else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
1958 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1959 WCD9XXX_COND_HPH, true);
1960 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001961 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
1962
1963 return IRQ_HANDLED;
1964}
1965
1966static irqreturn_t wcd9xxx_hs_insert_irq(int irq, void *data)
1967{
1968 bool is_mb_trigger, is_removal;
1969 struct wcd9xxx_mbhc *mbhc = data;
1970 struct snd_soc_codec *codec = mbhc->codec;
1971
1972 pr_debug("%s: enter\n", __func__);
1973 WCD9XXX_BCL_LOCK(mbhc->resmgr);
1974 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
1975
1976 is_mb_trigger = !!(snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg) &
1977 0x10);
1978 is_removal = !!(snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_INT_CTL) & 0x02);
1979 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
1980
1981 /* Turn off both HPH and MIC line schmitt triggers */
1982 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
1983 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
1984 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
1985
Joonwoo Park80a01172012-10-15 16:05:23 -07001986 if (mbhc->mbhc_cfg->detect_extn_cable &&
1987 mbhc->current_plug == PLUG_TYPE_HIGH_HPH)
1988 wcd9xxx_hs_insert_irq_extn(mbhc, is_mb_trigger);
1989 else
1990 wcd9xxx_hs_insert_irq_swch(mbhc, is_removal);
Joonwoo Parka8890262012-10-15 12:04:27 -07001991
1992 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
1993 return IRQ_HANDLED;
1994}
1995
1996static void wcd9xxx_btn_lpress_fn(struct work_struct *work)
1997{
1998 struct delayed_work *dwork;
1999 short bias_value;
2000 int dce_mv, sta_mv;
2001 struct wcd9xxx_mbhc *mbhc;
2002
2003 pr_debug("%s:\n", __func__);
2004
2005 dwork = to_delayed_work(work);
2006 mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_btn_dwork);
2007
2008 bias_value = wcd9xxx_read_sta_result(mbhc->codec);
2009 sta_mv = wcd9xxx_codec_sta_dce_v(mbhc, 0, bias_value);
2010
2011 bias_value = wcd9xxx_read_dce_result(mbhc->codec);
2012 dce_mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, bias_value);
2013 pr_debug("%s: STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
2014
2015 pr_debug("%s: Reporting long button press event\n", __func__);
Joonwoo Park3699ca32013-02-08 12:06:15 -08002016 wcd9xxx_jack_report(mbhc, &mbhc->button_jack, mbhc->buttons_pressed,
Joonwoo Parka8890262012-10-15 12:04:27 -07002017 mbhc->buttons_pressed);
2018
2019 pr_debug("%s: leave\n", __func__);
2020 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
2021}
2022
2023static void wcd9xxx_mbhc_insert_work(struct work_struct *work)
2024{
2025 struct delayed_work *dwork;
2026 struct wcd9xxx_mbhc *mbhc;
2027 struct snd_soc_codec *codec;
2028 struct wcd9xxx *core;
2029
2030 dwork = to_delayed_work(work);
2031 mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_insert_dwork);
2032 codec = mbhc->codec;
2033 core = mbhc->resmgr->core;
2034
2035 pr_debug("%s:\n", __func__);
2036
2037 /* Turn off both HPH and MIC line schmitt triggers */
2038 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
2039 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
2040 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
2041 wcd9xxx_disable_irq_sync(core, WCD9XXX_IRQ_MBHC_INSERTION);
2042 wcd9xxx_mbhc_detect_plug_type(mbhc);
2043 wcd9xxx_unlock_sleep(core);
2044}
2045
2046static bool wcd9xxx_mbhc_fw_validate(const struct firmware *fw)
2047{
2048 u32 cfg_offset;
2049 struct wcd9xxx_mbhc_imped_detect_cfg *imped_cfg;
2050 struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
2051
2052 if (fw->size < WCD9XXX_MBHC_CAL_MIN_SIZE)
2053 return false;
2054
2055 /*
2056 * Previous check guarantees that there is enough fw data up
2057 * to num_btn
2058 */
2059 btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(fw->data);
2060 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
2061 if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_BTN_SZ(btn_cfg)))
2062 return false;
2063
2064 /*
2065 * Previous check guarantees that there is enough fw data up
2066 * to start of impedance detection configuration
2067 */
2068 imped_cfg = WCD9XXX_MBHC_CAL_IMPED_DET_PTR(fw->data);
2069 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
2070
2071 if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_MIN_SZ))
2072 return false;
2073
2074 if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_SZ(imped_cfg)))
2075 return false;
2076
2077 return true;
2078}
2079
2080static u16 wcd9xxx_codec_v_sta_dce(struct wcd9xxx_mbhc *mbhc,
2081 enum meas_type dce, s16 vin_mv)
2082{
2083 s16 diff, zero;
2084 u32 mb_mv, in;
2085 u16 value;
2086
2087 mb_mv = mbhc->mbhc_data.micb_mv;
2088
2089 if (mb_mv == 0) {
2090 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
2091 return -EINVAL;
2092 }
2093
2094 if (dce) {
2095 diff = (mbhc->mbhc_data.dce_mb) - (mbhc->mbhc_data.dce_z);
2096 zero = (mbhc->mbhc_data.dce_z);
2097 } else {
2098 diff = (mbhc->mbhc_data.sta_mb) - (mbhc->mbhc_data.sta_z);
2099 zero = (mbhc->mbhc_data.sta_z);
2100 }
2101 in = (u32) diff * vin_mv;
2102
2103 value = (u16) (in / mb_mv) + zero;
2104 return value;
2105}
2106
2107static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc)
2108{
2109 struct snd_soc_codec *codec;
Joonwoo Park73375212013-05-07 12:42:44 -07002110 s16 adj_v_hs_max;
2111 s16 btn_mv = 0, btn_mv_sta[MBHC_V_IDX_NUM], btn_mv_dce[MBHC_V_IDX_NUM];
Joonwoo Parka8890262012-10-15 12:04:27 -07002112 struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
2113 struct wcd9xxx_mbhc_plug_type_cfg *plug_type;
2114 u16 *btn_high;
2115 int i;
2116
2117 pr_debug("%s: enter\n", __func__);
2118 codec = mbhc->codec;
2119 btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
2120 plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
2121
Joonwoo Park73375212013-05-07 12:42:44 -07002122 mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_CFILT] =
Joonwoo Parka8890262012-10-15 12:04:27 -07002123 wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max);
Joonwoo Park73375212013-05-07 12:42:44 -07002124 mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_CFILT] =
Joonwoo Parka8890262012-10-15 12:04:27 -07002125 wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max);
2126
2127 mbhc->mbhc_data.v_inval_ins_low = FAKE_INS_LOW;
2128 mbhc->mbhc_data.v_inval_ins_high = FAKE_INS_HIGH;
2129
2130 if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
Joonwoo Park73375212013-05-07 12:42:44 -07002131 adj_v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max,
2132 true);
2133 mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_VDDIO] =
2134 wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max);
2135 mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_VDDIO] =
2136 wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max);
Joonwoo Parka8890262012-10-15 12:04:27 -07002137 mbhc->mbhc_data.v_inval_ins_low =
2138 scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_low,
2139 false);
2140 mbhc->mbhc_data.v_inval_ins_high =
2141 scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_high,
2142 false);
2143 }
2144
2145 btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
2146 MBHC_BTN_DET_V_BTN_HIGH);
2147 for (i = 0; i < btn_det->num_btn; i++)
2148 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
2149
Joonwoo Park73375212013-05-07 12:42:44 -07002150 btn_mv_sta[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_sta;
2151 btn_mv_dce[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_cic;
2152 btn_mv_sta[MBHC_V_IDX_VDDIO] =
2153 scale_v_micb_vddio(mbhc, btn_mv_sta[MBHC_V_IDX_CFILT], true);
2154 btn_mv_dce[MBHC_V_IDX_VDDIO] =
2155 scale_v_micb_vddio(mbhc, btn_mv_dce[MBHC_V_IDX_CFILT], true);
Joonwoo Parka8890262012-10-15 12:04:27 -07002156
Joonwoo Park73375212013-05-07 12:42:44 -07002157 mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_CFILT] =
2158 wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT]);
2159 mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT] =
2160 wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT]);
2161 mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_VDDIO] =
2162 wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO]);
2163 mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO] =
2164 wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO]);
Joonwoo Parka8890262012-10-15 12:04:27 -07002165
Joonwoo Park73375212013-05-07 12:42:44 -07002166 mbhc->mbhc_data.v_brh[MBHC_V_IDX_CFILT] =
2167 mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT];
2168 mbhc->mbhc_data.v_brh[MBHC_V_IDX_VDDIO] =
2169 mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO];
Joonwoo Parka8890262012-10-15 12:04:27 -07002170
Joonwoo Parka8890262012-10-15 12:04:27 -07002171 mbhc->mbhc_data.v_brl = BUTTON_MIN;
2172
2173 mbhc->mbhc_data.v_no_mic =
2174 wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_no_mic);
2175 pr_debug("%s: leave\n", __func__);
2176}
2177
2178static void wcd9xxx_onoff_ext_mclk(struct wcd9xxx_mbhc *mbhc, bool on)
2179{
2180 /*
2181 * XXX: {codec}_mclk_enable holds WCD9XXX_BCL_LOCK,
2182 * therefore wcd9xxx_onoff_ext_mclk caller SHOULDN'T hold
2183 * WCD9XXX_BCL_LOCK when it calls wcd9xxx_onoff_ext_mclk()
2184 */
2185 mbhc->mbhc_cfg->mclk_cb_fn(mbhc->codec, on, false);
2186}
2187
2188static void wcd9xxx_correct_swch_plug(struct work_struct *work)
2189{
2190 struct wcd9xxx_mbhc *mbhc;
2191 struct snd_soc_codec *codec;
Joonwoo Park80a01172012-10-15 16:05:23 -07002192 enum wcd9xxx_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
Joonwoo Parka8890262012-10-15 12:04:27 -07002193 unsigned long timeout;
2194 int retry = 0, pt_gnd_mic_swap_cnt = 0;
2195 bool correction = false;
2196
2197 pr_debug("%s: enter\n", __func__);
2198
2199 mbhc = container_of(work, struct wcd9xxx_mbhc, correct_plug_swch);
2200 codec = mbhc->codec;
2201
2202 wcd9xxx_onoff_ext_mclk(mbhc, true);
2203
2204 /*
2205 * Keep override on during entire plug type correction work.
2206 *
2207 * This is okay under the assumption that any switch irqs which use
2208 * MBHC block cancel and sync this work so override is off again
2209 * prior to switch interrupt handler's MBHC block usage.
2210 * Also while this correction work is running, we can guarantee
2211 * DAPM doesn't use any MBHC block as this work only runs with
2212 * headphone detection.
2213 */
2214 wcd9xxx_turn_onoff_override(codec, true);
2215
2216 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
2217 while (!time_after(jiffies, timeout)) {
2218 ++retry;
2219 rmb();
2220 if (mbhc->hs_detect_work_stop) {
2221 pr_debug("%s: stop requested\n", __func__);
2222 break;
2223 }
2224
2225 msleep(HS_DETECT_PLUG_INERVAL_MS);
2226 if (wcd9xxx_swch_level_remove(mbhc)) {
2227 pr_debug("%s: Switch level is low\n", __func__);
2228 break;
2229 }
2230
2231 /* can race with removal interrupt */
2232 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2233 plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
2234 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2235
Joonwoo Park80a01172012-10-15 16:05:23 -07002236 pr_debug("%s: attempt(%d) current_plug(%d) new_plug(%d)\n",
2237 __func__, retry, mbhc->current_plug, plug_type);
Joonwoo Parka8890262012-10-15 12:04:27 -07002238 if (plug_type == PLUG_TYPE_INVALID) {
2239 pr_debug("Invalid plug in attempt # %d\n", retry);
Joonwoo Park80a01172012-10-15 16:05:23 -07002240 if (!mbhc->mbhc_cfg->detect_extn_cable &&
2241 retry == NUM_ATTEMPTS_TO_REPORT &&
Joonwoo Parka8890262012-10-15 12:04:27 -07002242 mbhc->current_plug == PLUG_TYPE_NONE) {
2243 wcd9xxx_report_plug(mbhc, 1,
2244 SND_JACK_HEADPHONE);
2245 }
2246 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
2247 pr_debug("Good headphone detected, continue polling\n");
Joonwoo Park80a01172012-10-15 16:05:23 -07002248 if (mbhc->mbhc_cfg->detect_extn_cable) {
2249 if (mbhc->current_plug != plug_type)
2250 wcd9xxx_report_plug(mbhc, 1,
2251 SND_JACK_HEADPHONE);
2252 } else if (mbhc->current_plug == PLUG_TYPE_NONE) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002253 wcd9xxx_report_plug(mbhc, 1,
2254 SND_JACK_HEADPHONE);
Joonwoo Park80a01172012-10-15 16:05:23 -07002255 }
Phani Kumar Uppalapatida7c7ab2013-04-10 16:38:19 -07002256 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
2257 pr_debug("%s: High HPH detected, continue polling\n",
2258 __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07002259 } else {
2260 if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
2261 pt_gnd_mic_swap_cnt++;
2262 if (pt_gnd_mic_swap_cnt <
2263 GND_MIC_SWAP_THRESHOLD)
2264 continue;
2265 else if (pt_gnd_mic_swap_cnt >
2266 GND_MIC_SWAP_THRESHOLD) {
2267 /*
2268 * This is due to GND/MIC switch didn't
2269 * work, Report unsupported plug
2270 */
2271 } else if (mbhc->mbhc_cfg->swap_gnd_mic) {
2272 /*
2273 * if switch is toggled, check again,
2274 * otherwise report unsupported plug
2275 */
2276 if (mbhc->mbhc_cfg->swap_gnd_mic(codec))
2277 continue;
2278 }
2279 } else
2280 pt_gnd_mic_swap_cnt = 0;
2281
2282 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2283 /* Turn off override */
2284 wcd9xxx_turn_onoff_override(codec, false);
2285 /*
2286 * The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
2287 */
2288 wcd9xxx_find_plug_and_report(mbhc, plug_type);
2289 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2290 pr_debug("Attempt %d found correct plug %d\n", retry,
2291 plug_type);
2292 correction = true;
2293 break;
2294 }
2295 }
2296
Phani Kumar Uppalapatida7c7ab2013-04-10 16:38:19 -07002297 if (plug_type == PLUG_TYPE_HIGH_HPH) {
2298 pr_debug("%s: polling is done, still HPH, so enabling MIC trigger\n",
2299 __func__);
2300 wcd9xxx_find_plug_and_report(mbhc, plug_type);
2301 }
Joonwoo Parka8890262012-10-15 12:04:27 -07002302 /* Turn off override */
2303 if (!correction)
2304 wcd9xxx_turn_onoff_override(codec, false);
2305
2306 wcd9xxx_onoff_ext_mclk(mbhc, false);
Joonwoo Park80a01172012-10-15 16:05:23 -07002307
2308 if (mbhc->mbhc_cfg->detect_extn_cable) {
2309 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2310 if (mbhc->current_plug == PLUG_TYPE_HEADPHONE ||
2311 mbhc->current_plug == PLUG_TYPE_GND_MIC_SWAP ||
2312 mbhc->current_plug == PLUG_TYPE_INVALID ||
2313 plug_type == PLUG_TYPE_INVALID) {
2314 /* Enable removal detection */
2315 wcd9xxx_cleanup_hs_polling(mbhc);
2316 wcd9xxx_enable_hs_detect(mbhc, 0, 0, false);
2317 }
2318 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2319 }
2320 pr_debug("%s: leave current_plug(%d)\n", __func__, mbhc->current_plug);
Joonwoo Parka8890262012-10-15 12:04:27 -07002321 /* unlock sleep */
2322 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
2323}
2324
2325static void wcd9xxx_swch_irq_handler(struct wcd9xxx_mbhc *mbhc)
2326{
2327 bool insert;
2328 bool is_removed = false;
2329 struct snd_soc_codec *codec = mbhc->codec;
2330
2331 pr_debug("%s: enter\n", __func__);
2332
2333 mbhc->in_swch_irq_handler = true;
2334 /* Wait here for debounce time */
2335 usleep_range(SWCH_IRQ_DEBOUNCE_TIME_US, SWCH_IRQ_DEBOUNCE_TIME_US);
2336
2337 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2338
2339 /* cancel pending button press */
2340 if (wcd9xxx_cancel_btn_work(mbhc))
2341 pr_debug("%s: button press is canceled\n", __func__);
2342
2343 insert = !wcd9xxx_swch_level_remove(mbhc);
2344 pr_debug("%s: Current plug type %d, insert %d\n", __func__,
2345 mbhc->current_plug, insert);
2346 if ((mbhc->current_plug == PLUG_TYPE_NONE) && insert) {
2347 mbhc->lpi_enabled = false;
2348 wmb();
2349
2350 /* cancel detect plug */
2351 wcd9xxx_cancel_hs_detect_plug(mbhc,
2352 &mbhc->correct_plug_swch);
2353
2354 /* Disable Mic Bias pull down and HPH Switch to GND */
2355 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01,
2356 0x00);
2357 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01, 0x00);
2358 wcd9xxx_mbhc_detect_plug_type(mbhc);
2359 } else if ((mbhc->current_plug != PLUG_TYPE_NONE) && !insert) {
2360 mbhc->lpi_enabled = false;
2361 wmb();
2362
2363 /* cancel detect plug */
2364 wcd9xxx_cancel_hs_detect_plug(mbhc,
2365 &mbhc->correct_plug_swch);
2366
2367 if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
2368 wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
2369 is_removed = true;
2370 } else if (mbhc->current_plug == PLUG_TYPE_GND_MIC_SWAP) {
2371 wcd9xxx_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED);
2372 is_removed = true;
2373 } else if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
2374 wcd9xxx_pause_hs_polling(mbhc);
2375 wcd9xxx_cleanup_hs_polling(mbhc);
2376 wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
2377 is_removed = true;
Joonwoo Park80a01172012-10-15 16:05:23 -07002378 } else if (mbhc->current_plug == PLUG_TYPE_HIGH_HPH) {
2379 wcd9xxx_report_plug(mbhc, 0, SND_JACK_LINEOUT);
2380 is_removed = true;
Joonwoo Parka8890262012-10-15 12:04:27 -07002381 }
2382
2383 if (is_removed) {
2384 /* Enable Mic Bias pull down and HPH Switch to GND */
2385 snd_soc_update_bits(codec,
2386 mbhc->mbhc_bias_regs.ctl_reg, 0x01,
2387 0x01);
2388 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01,
2389 0x01);
2390 /* Make sure mic trigger is turned off */
2391 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg,
2392 0x01, 0x01);
2393 snd_soc_update_bits(codec,
2394 mbhc->mbhc_bias_regs.mbhc_reg,
2395 0x90, 0x00);
2396 /* Reset MBHC State Machine */
2397 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
2398 0x08, 0x08);
2399 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
2400 0x08, 0x00);
2401 /* Turn off override */
2402 wcd9xxx_turn_onoff_override(codec, false);
2403 }
2404 }
2405
2406 mbhc->in_swch_irq_handler = false;
2407 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2408 pr_debug("%s: leave\n", __func__);
2409}
2410
2411static irqreturn_t wcd9xxx_mech_plug_detect_irq(int irq, void *data)
2412{
2413 int r = IRQ_HANDLED;
2414 struct wcd9xxx_mbhc *mbhc = data;
2415
2416 pr_debug("%s: enter\n", __func__);
2417 if (unlikely(wcd9xxx_lock_sleep(mbhc->resmgr->core) == false)) {
2418 pr_warn("%s: failed to hold suspend\n", __func__);
2419 r = IRQ_NONE;
2420 } else {
2421 /* Call handler */
2422 wcd9xxx_swch_irq_handler(mbhc);
2423 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
2424 }
2425
2426 pr_debug("%s: leave %d\n", __func__, r);
2427 return r;
2428}
2429
2430/* called under codec_resource_lock acquisition */
2431static void wcd9xxx_codec_drive_v_to_micbias(struct wcd9xxx_mbhc *mbhc,
2432 int usec)
2433{
2434 int cfilt_k_val;
2435 bool set = true;
2436
2437 if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2438 mbhc->mbhc_micbias_switched) {
2439 pr_debug("%s: set mic V to micbias V\n", __func__);
2440 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
2441 0x2, 0x2);
2442 wcd9xxx_turn_onoff_override(mbhc->codec, true);
2443 while (1) {
2444 cfilt_k_val =
2445 wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
2446 set ? mbhc->mbhc_data.micb_mv :
2447 VDDIO_MICBIAS_MV);
2448 snd_soc_update_bits(mbhc->codec,
2449 mbhc->mbhc_bias_regs.cfilt_val,
2450 0xFC, (cfilt_k_val << 2));
2451 if (!set)
2452 break;
2453 usleep_range(usec, usec);
2454 set = false;
2455 }
2456 wcd9xxx_turn_onoff_override(mbhc->codec, false);
2457 }
2458}
2459
2460static int wcd9xxx_is_fake_press(struct wcd9xxx_mbhc *mbhc)
2461{
2462 int i;
Joonwoo Park73375212013-05-07 12:42:44 -07002463 s16 mb_v;
Joonwoo Parka8890262012-10-15 12:04:27 -07002464 int r = 0;
2465 const int dces = NUM_DCE_PLUG_DETECT;
Joonwoo Park73375212013-05-07 12:42:44 -07002466 const s16 v_ins_hu =
2467 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
2468 const s16 v_ins_h =
2469 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
2470 const s16 v_b1_hu =
2471 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
2472 const s16 v_b1_h =
2473 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
Joonwoo Parka8890262012-10-15 12:04:27 -07002474
2475 for (i = 0; i < dces; i++) {
2476 usleep_range(10000, 10000);
2477 if (i == 0) {
2478 mb_v = wcd9xxx_codec_sta_dce(mbhc, 0, true);
2479 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
2480 wcd9xxx_codec_sta_dce_v(mbhc, 0, mb_v));
Joonwoo Park73375212013-05-07 12:42:44 -07002481 if (mb_v < v_b1_hu || mb_v > v_ins_hu) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002482 r = 1;
2483 break;
2484 }
2485 } else {
2486 mb_v = wcd9xxx_codec_sta_dce(mbhc, 1, true);
2487 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
2488 wcd9xxx_codec_sta_dce_v(mbhc, 1, mb_v));
Joonwoo Park73375212013-05-07 12:42:44 -07002489 if (mb_v < v_b1_h || mb_v > v_ins_h) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002490 r = 1;
2491 break;
2492 }
2493 }
2494 }
2495
2496 return r;
2497}
2498
2499/* called under codec_resource_lock acquisition */
2500static int wcd9xxx_determine_button(const struct wcd9xxx_mbhc *mbhc,
2501 const s32 micmv)
2502{
2503 s16 *v_btn_low, *v_btn_high;
2504 struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
2505 int i, btn = -1;
2506
2507 btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
2508 v_btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
2509 MBHC_BTN_DET_V_BTN_LOW);
2510 v_btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
2511 MBHC_BTN_DET_V_BTN_HIGH);
2512
2513 for (i = 0; i < btn_det->num_btn; i++) {
2514 if ((v_btn_low[i] <= micmv) && (v_btn_high[i] >= micmv)) {
2515 btn = i;
2516 break;
2517 }
2518 }
2519
2520 if (btn == -1)
2521 pr_debug("%s: couldn't find button number for mic mv %d\n",
2522 __func__, micmv);
2523
2524 return btn;
2525}
2526
2527static int wcd9xxx_get_button_mask(const int btn)
2528{
2529 int mask = 0;
2530 switch (btn) {
2531 case 0:
2532 mask = SND_JACK_BTN_0;
2533 break;
2534 case 1:
2535 mask = SND_JACK_BTN_1;
2536 break;
2537 case 2:
2538 mask = SND_JACK_BTN_2;
2539 break;
2540 case 3:
2541 mask = SND_JACK_BTN_3;
2542 break;
2543 case 4:
2544 mask = SND_JACK_BTN_4;
2545 break;
2546 case 5:
2547 mask = SND_JACK_BTN_5;
2548 break;
2549 case 6:
2550 mask = SND_JACK_BTN_6;
2551 break;
2552 case 7:
2553 mask = SND_JACK_BTN_7;
2554 break;
2555 }
2556 return mask;
2557}
2558
Joonwoo Park520a0f92013-05-14 19:39:58 -07002559void wcd9xxx_get_z(struct wcd9xxx_mbhc *mbhc, s16 *dce_z, s16 *sta_z)
2560{
2561 s16 reg0, reg1;
2562 struct snd_soc_codec *codec = mbhc->codec;
2563
2564 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
2565 /* Pull down micbias to ground and disconnect vddio switch */
2566 reg0 = snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg);
2567 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x81, 0x1);
2568 reg1 = snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg);
2569 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 1 << 7, 0);
2570
2571 /* Disconnect override from micbias */
2572 snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
2573 usleep_range(1000, 1000 + 1000);
2574 *sta_z = wcd9xxx_codec_sta_dce(mbhc, 0, false);
2575 *dce_z = wcd9xxx_codec_sta_dce(mbhc, 1, false);
2576
2577 /* Connect override from micbias */
2578 snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 4);
2579 /* Disable pull down micbias to ground */
2580 snd_soc_write(codec, mbhc->mbhc_bias_regs.mbhc_reg, reg1);
2581 snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
2582}
2583
Joonwoo Parka8890262012-10-15 12:04:27 -07002584irqreturn_t wcd9xxx_dce_handler(int irq, void *data)
2585{
2586 int i, mask;
Joonwoo Parka8890262012-10-15 12:04:27 -07002587 bool vddio;
2588 u8 mbhc_status;
Joonwoo Park520a0f92013-05-14 19:39:58 -07002589 s16 dce_z, sta_z;
Joonwoo Parka8890262012-10-15 12:04:27 -07002590 int btn = -1, meas = 0;
2591 struct wcd9xxx_mbhc *mbhc = data;
2592 const struct wcd9xxx_mbhc_btn_detect_cfg *d =
2593 WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
2594 short btnmeas[d->n_btn_meas + 1];
Joonwoo Park520a0f92013-05-14 19:39:58 -07002595 short dce[d->n_btn_meas + 1], sta;
2596 s32 mv[d->n_btn_meas + 1], mv_s[d->n_btn_meas + 1];
2597 s32 stamv, stamv_s;
Joonwoo Parka8890262012-10-15 12:04:27 -07002598 struct snd_soc_codec *codec = mbhc->codec;
2599 struct wcd9xxx *core = mbhc->resmgr->core;
2600 int n_btn_meas = d->n_btn_meas;
2601
2602 pr_debug("%s: enter\n", __func__);
2603
2604 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2605 mbhc_status = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_STATUS) & 0x3E;
2606
2607 if (mbhc->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
2608 pr_debug("%s: mbhc is being recovered, skip button press\n",
2609 __func__);
2610 goto done;
2611 }
2612
2613 mbhc->mbhc_state = MBHC_STATE_POTENTIAL;
2614
2615 if (!mbhc->polling_active) {
2616 pr_warn("%s: mbhc polling is not active, skip button press\n",
2617 __func__);
2618 goto done;
2619 }
2620
Joonwoo Parka8890262012-10-15 12:04:27 -07002621 /* If switch nterrupt already kicked in, ignore button press */
2622 if (mbhc->in_swch_irq_handler) {
2623 pr_debug("%s: Swtich level changed, ignore button press\n",
2624 __func__);
2625 btn = -1;
2626 goto done;
2627 }
2628
2629 /* Measure scaled HW DCE */
2630 vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2631 mbhc->mbhc_micbias_switched);
Joonwoo Parka8890262012-10-15 12:04:27 -07002632
2633 /* Measure scaled HW STA */
Joonwoo Park520a0f92013-05-14 19:39:58 -07002634 dce[0] = wcd9xxx_read_dce_result(codec);
Joonwoo Parka8890262012-10-15 12:04:27 -07002635 sta = wcd9xxx_read_sta_result(codec);
Joonwoo Parka8890262012-10-15 12:04:27 -07002636 if (mbhc_status != STATUS_REL_DETECTION) {
2637 if (mbhc->mbhc_last_resume &&
2638 !time_after(jiffies, mbhc->mbhc_last_resume + HZ)) {
2639 pr_debug("%s: Button is released after resume\n",
2640 __func__);
2641 n_btn_meas = 0;
2642 } else {
2643 pr_debug("%s: Button is released without resume",
2644 __func__);
Joonwoo Park520a0f92013-05-14 19:39:58 -07002645 wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
2646 stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
2647 if (vddio)
2648 stamv_s = scale_v_micb_vddio(mbhc, stamv,
2649 false);
2650 else
2651 stamv_s = stamv;
2652 mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0],
2653 dce_z);
2654 mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0],
2655 false) : mv[0];
2656 btn = wcd9xxx_determine_button(mbhc, mv_s[0]);
Joonwoo Parka8890262012-10-15 12:04:27 -07002657 if (btn != wcd9xxx_determine_button(mbhc, stamv_s))
2658 btn = -1;
2659 goto done;
2660 }
2661 }
2662
Joonwoo Park520a0f92013-05-14 19:39:58 -07002663 for (meas = 1; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1)));
2664 meas++)
2665 dce[meas] = wcd9xxx_codec_sta_dce(mbhc, 1, false);
2666
2667 wcd9xxx_get_z(mbhc, &dce_z, &sta_z);
2668
2669 stamv = __wcd9xxx_codec_sta_dce_v(mbhc, 0, sta, sta_z);
2670 if (vddio)
2671 stamv_s = scale_v_micb_vddio(mbhc, stamv, false);
2672 else
2673 stamv_s = stamv;
Joonwoo Parka8890262012-10-15 12:04:27 -07002674 pr_debug("%s: Meas HW - STA 0x%x,%d,%d\n", __func__,
Joonwoo Park520a0f92013-05-14 19:39:58 -07002675 sta & 0xFFFF, stamv, stamv_s);
Joonwoo Parka8890262012-10-15 12:04:27 -07002676
2677 /* determine pressed button */
Joonwoo Park520a0f92013-05-14 19:39:58 -07002678 mv[0] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[0], dce_z);
2679 mv_s[0] = vddio ? scale_v_micb_vddio(mbhc, mv[0], false) : mv[0];
2680 btnmeas[0] = wcd9xxx_determine_button(mbhc, mv_s[0]);
Joonwoo Parka8890262012-10-15 12:04:27 -07002681 pr_debug("%s: Meas HW - DCE 0x%x,%d,%d button %d\n", __func__,
Joonwoo Park520a0f92013-05-14 19:39:58 -07002682 dce[0] & 0xFFFF, mv[0], mv_s[0], btnmeas[0]);
Joonwoo Parka8890262012-10-15 12:04:27 -07002683 if (n_btn_meas == 0)
2684 btn = btnmeas[0];
Joonwoo Park520a0f92013-05-14 19:39:58 -07002685 for (meas = 1; (n_btn_meas && d->n_btn_meas &&
2686 (meas < (d->n_btn_meas + 1))); meas++) {
2687 mv[meas] = __wcd9xxx_codec_sta_dce_v(mbhc, 1, dce[meas], dce_z);
2688 mv_s[meas] = vddio ? scale_v_micb_vddio(mbhc, mv[meas], false) :
2689 mv[meas];
2690 btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s[meas]);
Joonwoo Parka8890262012-10-15 12:04:27 -07002691 pr_debug("%s: Meas %d - DCE 0x%x,%d,%d button %d\n",
Joonwoo Park520a0f92013-05-14 19:39:58 -07002692 __func__, meas, dce[meas] & 0xFFFF, mv[meas],
2693 mv_s[meas], btnmeas[meas]);
Joonwoo Parka8890262012-10-15 12:04:27 -07002694 /*
2695 * if large enough measurements are collected,
2696 * start to check if last all n_btn_con measurements were
2697 * in same button low/high range
2698 */
2699 if (meas + 1 >= d->n_btn_con) {
2700 for (i = 0; i < d->n_btn_con; i++)
2701 if ((btnmeas[meas] < 0) ||
2702 (btnmeas[meas] != btnmeas[meas - i]))
2703 break;
2704 if (i == d->n_btn_con) {
2705 /* button pressed */
2706 btn = btnmeas[meas];
2707 break;
2708 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
2709 /*
2710 * if left measurements are less than n_btn_con,
2711 * it's impossible to find button number
2712 */
2713 break;
2714 }
2715 }
2716 }
2717
2718 if (btn >= 0) {
2719 if (mbhc->in_swch_irq_handler) {
2720 pr_debug(
2721 "%s: Switch irq triggered, ignore button press\n",
2722 __func__);
2723 goto done;
2724 }
2725 mask = wcd9xxx_get_button_mask(btn);
2726 mbhc->buttons_pressed |= mask;
2727 wcd9xxx_lock_sleep(core);
2728 if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
2729 msecs_to_jiffies(400)) == 0) {
2730 WARN(1, "Button pressed twice without release event\n");
2731 wcd9xxx_unlock_sleep(core);
2732 }
2733 } else {
2734 pr_debug("%s: bogus button press, too short press?\n",
2735 __func__);
2736 }
2737
2738 done:
2739 pr_debug("%s: leave\n", __func__);
2740 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2741 return IRQ_HANDLED;
2742}
2743
2744static irqreturn_t wcd9xxx_release_handler(int irq, void *data)
2745{
2746 int ret;
2747 struct wcd9xxx_mbhc *mbhc = data;
2748
2749 pr_debug("%s: enter\n", __func__);
2750 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2751 mbhc->mbhc_state = MBHC_STATE_RELEASE;
2752
2753 wcd9xxx_codec_drive_v_to_micbias(mbhc, 10000);
2754
2755 if (mbhc->buttons_pressed & WCD9XXX_JACK_BUTTON_MASK) {
2756 ret = wcd9xxx_cancel_btn_work(mbhc);
2757 if (ret == 0) {
2758 pr_debug("%s: Reporting long button release event\n",
2759 __func__);
Joonwoo Park3699ca32013-02-08 12:06:15 -08002760 wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
Joonwoo Parka8890262012-10-15 12:04:27 -07002761 mbhc->buttons_pressed);
2762 } else {
2763 if (wcd9xxx_is_fake_press(mbhc)) {
2764 pr_debug("%s: Fake button press interrupt\n",
2765 __func__);
2766 } else {
2767 if (mbhc->in_swch_irq_handler) {
2768 pr_debug("%s: Switch irq kicked in, ignore\n",
2769 __func__);
2770 } else {
2771 pr_debug("%s: Reporting btn press\n",
2772 __func__);
Joonwoo Park3699ca32013-02-08 12:06:15 -08002773 wcd9xxx_jack_report(mbhc,
2774 &mbhc->button_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -07002775 mbhc->buttons_pressed,
2776 mbhc->buttons_pressed);
2777 pr_debug("%s: Reporting btn release\n",
2778 __func__);
Joonwoo Park3699ca32013-02-08 12:06:15 -08002779 wcd9xxx_jack_report(mbhc,
2780 &mbhc->button_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -07002781 0, mbhc->buttons_pressed);
2782 }
2783 }
2784 }
2785
2786 mbhc->buttons_pressed &= ~WCD9XXX_JACK_BUTTON_MASK;
2787 }
2788
2789 wcd9xxx_calibrate_hs_polling(mbhc);
2790
2791 msleep(SWCH_REL_DEBOUNCE_TIME_MS);
2792 wcd9xxx_start_hs_polling(mbhc);
2793
2794 pr_debug("%s: leave\n", __func__);
2795 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2796 return IRQ_HANDLED;
2797}
2798
2799static irqreturn_t wcd9xxx_hphl_ocp_irq(int irq, void *data)
2800{
2801 struct wcd9xxx_mbhc *mbhc = data;
2802 struct snd_soc_codec *codec;
2803
2804 pr_info("%s: received HPHL OCP irq\n", __func__);
2805
2806 if (mbhc) {
2807 codec = mbhc->codec;
Patrick Lai56fea882013-03-02 09:11:20 -08002808 if ((mbhc->hphlocp_cnt < OCP_ATTEMPT) &&
2809 (!mbhc->hphrocp_cnt)) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002810 pr_info("%s: retry\n", __func__);
Patrick Lai56fea882013-03-02 09:11:20 -08002811 mbhc->hphlocp_cnt++;
Joonwoo Parka8890262012-10-15 12:04:27 -07002812 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
2813 0x10, 0x00);
2814 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
2815 0x10, 0x10);
2816 } else {
2817 wcd9xxx_disable_irq(codec->control_data,
2818 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Joonwoo Parka8890262012-10-15 12:04:27 -07002819 mbhc->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Park3699ca32013-02-08 12:06:15 -08002820 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -07002821 mbhc->hph_status,
2822 WCD9XXX_JACK_MASK);
2823 }
2824 } else {
2825 pr_err("%s: Bad wcd9xxx private data\n", __func__);
2826 }
2827
2828 return IRQ_HANDLED;
2829}
2830
2831static irqreturn_t wcd9xxx_hphr_ocp_irq(int irq, void *data)
2832{
2833 struct wcd9xxx_mbhc *mbhc = data;
2834 struct snd_soc_codec *codec;
2835
2836 pr_info("%s: received HPHR OCP irq\n", __func__);
2837 codec = mbhc->codec;
Patrick Lai56fea882013-03-02 09:11:20 -08002838 if ((mbhc->hphrocp_cnt < OCP_ATTEMPT) &&
2839 (!mbhc->hphlocp_cnt)) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002840 pr_info("%s: retry\n", __func__);
Patrick Lai56fea882013-03-02 09:11:20 -08002841 mbhc->hphrocp_cnt++;
Joonwoo Parka8890262012-10-15 12:04:27 -07002842 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
2843 0x00);
2844 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
2845 0x10);
2846 } else {
2847 wcd9xxx_disable_irq(mbhc->resmgr->core,
2848 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Joonwoo Parka8890262012-10-15 12:04:27 -07002849 mbhc->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Park3699ca32013-02-08 12:06:15 -08002850 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -07002851 mbhc->hph_status, WCD9XXX_JACK_MASK);
2852 }
2853
2854 return IRQ_HANDLED;
2855}
2856
2857static int wcd9xxx_acdb_mclk_index(const int rate)
2858{
2859 if (rate == MCLK_RATE_12288KHZ)
2860 return 0;
2861 else if (rate == MCLK_RATE_9600KHZ)
2862 return 1;
2863 else {
2864 BUG_ON(1);
2865 return -EINVAL;
2866 }
2867}
2868
2869static void wcd9xxx_update_mbhc_clk_rate(struct wcd9xxx_mbhc *mbhc, u32 rate)
2870{
2871 u32 dce_wait, sta_wait;
2872 u8 ncic, nmeas, navg;
2873 void *calibration;
2874 u8 *n_cic, *n_ready;
2875 struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
2876 u8 npoll = 4, nbounce_wait = 30;
2877 struct snd_soc_codec *codec = mbhc->codec;
2878 int idx = wcd9xxx_acdb_mclk_index(rate);
2879 int idxmclk = wcd9xxx_acdb_mclk_index(mbhc->mbhc_cfg->mclk_rate);
2880
2881 pr_debug("%s: Updating clock rate dependents, rate = %u\n", __func__,
2882 rate);
2883 calibration = mbhc->mbhc_cfg->calibration;
2884
2885 /*
2886 * First compute the DCE / STA wait times depending on tunable
2887 * parameters. The value is computed in microseconds
2888 */
2889 btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration);
2890 n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_N_READY);
2891 n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_N_CIC);
2892 nmeas = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
2893 navg = WCD9XXX_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
2894
2895 /* ncic stays with the same what we had during calibration */
2896 ncic = n_cic[idxmclk];
2897 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (rate / 1000);
2898 sta_wait = (1000 * 128 * (navg + 1)) / (rate / 1000);
2899 mbhc->mbhc_data.t_dce = dce_wait;
2900 mbhc->mbhc_data.t_sta = sta_wait;
2901 mbhc->mbhc_data.t_sta_dce = ((1000 * 256) / (rate / 1000) *
2902 n_ready[idx]) + 10;
2903
2904 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B1_CTL, n_ready[idx]);
2905 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B6_CTL, ncic);
2906
2907 if (rate == MCLK_RATE_12288KHZ) {
2908 npoll = 4;
2909 nbounce_wait = 30;
2910 } else if (rate == MCLK_RATE_9600KHZ) {
2911 npoll = 3;
2912 nbounce_wait = 23;
2913 }
2914
2915 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B2_CTL, npoll);
2916 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B3_CTL, nbounce_wait);
2917 pr_debug("%s: leave\n", __func__);
2918}
2919
2920static void wcd9xxx_mbhc_cal(struct wcd9xxx_mbhc *mbhc)
2921{
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -07002922 u8 cfilt_mode;
Joonwoo Park7902f4c2013-02-20 15:21:25 -08002923 u16 reg0, reg1;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302924 int ret;
Joonwoo Parka8890262012-10-15 12:04:27 -07002925 struct snd_soc_codec *codec = mbhc->codec;
2926
2927 pr_debug("%s: enter\n", __func__);
2928 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
2929 wcd9xxx_turn_onoff_rel_detection(codec, false);
2930
2931 /* t_dce and t_sta are updated by wcd9xxx_update_mbhc_clk_rate() */
2932 WARN_ON(!mbhc->mbhc_data.t_dce);
2933 WARN_ON(!mbhc->mbhc_data.t_sta);
2934
2935 /*
2936 * LDOH and CFILT are already configured during pdata handling.
2937 * Only need to make sure CFILT and bandgap are in Fast mode.
2938 * Need to restore defaults once calculation is done.
2939 */
2940 cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302941 ret = wcd9xxx_put_cfilt_fast_mode(codec, mbhc);
2942 if (ret)
2943 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07002944 /*
2945 * Micbias, CFILT, LDOH, MBHC MUX mode settings
2946 * to perform ADC calibration
2947 */
2948 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x60,
2949 mbhc->mbhc_cfg->micbias << 5);
2950 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
2951 snd_soc_update_bits(codec, WCD9XXX_A_LDO_H_MODE_1, 0x60, 0x60);
2952 snd_soc_write(codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0x78);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302953 ret = wcd9xxx_codec_specific_cal_setup(codec, mbhc);
2954 if (ret)
2955 goto gen_err;
Joonwoo Park7902f4c2013-02-20 15:21:25 -08002956 /* Pull down micbias to ground */
2957 reg0 = snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg);
2958 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 1, 1);
2959 /* Disconnect override from micbias */
2960 reg1 = snd_soc_read(codec, WCD9XXX_A_MAD_ANA_CTRL);
2961 snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
2962 /* Connect the MUX to micbias */
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05302963 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302964 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
2965 if (ret)
2966 goto gen_err;
Joonwoo Parkaec97c72013-05-14 16:51:02 -07002967 /*
2968 * Hardware that has external cap can delay mic bias ramping down up
2969 * to 50ms.
2970 */
2971 msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
Joonwoo Park7902f4c2013-02-20 15:21:25 -08002972 /* DCE measurement for 0 voltage */
Joonwoo Parka8890262012-10-15 12:04:27 -07002973 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
Joonwoo Parka8890262012-10-15 12:04:27 -07002974 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park7902f4c2013-02-20 15:21:25 -08002975 mbhc->mbhc_data.dce_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true, false);
2976 /* STA measurement for 0 voltage */
2977 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
2978 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
2979 mbhc->mbhc_data.sta_z = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
2980 /* Restore registers */
2981 snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
2982 snd_soc_write(codec, WCD9XXX_A_MAD_ANA_CTRL, reg1);
Joonwoo Parka8890262012-10-15 12:04:27 -07002983
2984 /* DCE measurment for MB voltage */
2985 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
2986 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05302987 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302988 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
2989 if (ret)
2990 goto gen_err;
Joonwoo Parkaec97c72013-05-14 16:51:02 -07002991 /*
2992 * Hardware that has external cap can delay mic bias ramping down up
2993 * to 50ms.
2994 */
2995 msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
Joonwoo Parka8890262012-10-15 12:04:27 -07002996 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x04);
2997 usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce);
2998 mbhc->mbhc_data.dce_mb = wcd9xxx_read_dce_result(codec);
2999
Joonwoo Park7902f4c2013-02-20 15:21:25 -08003000 /* STA Measurement for MB Voltage */
Joonwoo Parka8890262012-10-15 12:04:27 -07003001 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
3002 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
3003 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05303004 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303005 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
3006 if (ret)
3007 goto gen_err;
Joonwoo Parkaec97c72013-05-14 16:51:02 -07003008 /*
3009 * Hardware that has external cap can delay mic bias ramping down up
3010 * to 50ms.
3011 */
3012 msleep(WCD9XXX_MUX_SWITCH_READY_WAIT_MS);
Joonwoo Parka8890262012-10-15 12:04:27 -07003013 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
3014 usleep_range(mbhc->mbhc_data.t_sta, mbhc->mbhc_data.t_sta);
3015 mbhc->mbhc_data.sta_mb = wcd9xxx_read_sta_result(codec);
3016
3017 /* Restore default settings. */
3018 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303019 snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05303020 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303021 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
3022 if (ret)
3023 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07003024 usleep_range(100, 100);
3025
3026 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
3027 wcd9xxx_turn_onoff_rel_detection(codec, true);
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -07003028
Joonwoo Parka8890262012-10-15 12:04:27 -07003029 pr_debug("%s: leave\n", __func__);
Simmi Pateriya387ddbc2013-04-18 01:14:20 +05303030 return;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303031
3032gen_err:
3033 pr_err("%s: Error returned, ret: %d\n", __func__, ret);
Joonwoo Parka8890262012-10-15 12:04:27 -07003034}
3035
3036static void wcd9xxx_mbhc_setup(struct wcd9xxx_mbhc *mbhc)
3037{
3038 int n;
3039 u8 *gain;
3040 struct wcd9xxx_mbhc_general_cfg *generic;
3041 struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
3042 struct snd_soc_codec *codec = mbhc->codec;
3043 const int idx = wcd9xxx_acdb_mclk_index(mbhc->mbhc_cfg->mclk_rate);
3044
3045 pr_debug("%s: enter\n", __func__);
3046 generic = WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
3047 btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
3048
3049 for (n = 0; n < 8; n++) {
3050 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_FIR_B1_CFG,
3051 0x07, n);
3052 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_FIR_B2_CFG,
3053 btn_det->c[n]);
3054 }
3055
3056 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B2_CTL, 0x07,
3057 btn_det->nc);
3058
3059 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
3060 generic->mbhc_nsa << 4);
3061
3062 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
3063 btn_det->n_meas);
3064
3065 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL,
3066 generic->mbhc_navg);
3067
3068 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
3069
3070 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
3071 btn_det->mbhc_nsc << 3);
3072
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303073 if (mbhc->resmgr->reg_addr->micb_4_mbhc)
3074 snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
3075 0x03, MBHC_MICBIAS2);
Joonwoo Parka8890262012-10-15 12:04:27 -07003076
3077 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
3078
3079 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
3080
3081 gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_GAIN);
3082 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B2_CTL, 0x78,
3083 gain[idx] << 3);
3084
3085 pr_debug("%s: leave\n", __func__);
3086}
3087
3088static int wcd9xxx_setup_jack_detect_irq(struct wcd9xxx_mbhc *mbhc)
3089{
3090 int ret = 0;
3091 void *core = mbhc->resmgr->core;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303092 int jack_irq;
Joonwoo Parka8890262012-10-15 12:04:27 -07003093
3094 if (mbhc->mbhc_cfg->gpio) {
3095 ret = request_threaded_irq(mbhc->mbhc_cfg->gpio_irq, NULL,
3096 wcd9xxx_mech_plug_detect_irq,
3097 (IRQF_TRIGGER_RISING |
3098 IRQF_TRIGGER_FALLING |
3099 IRQF_DISABLED),
3100 "headset detect", mbhc);
3101 if (ret) {
3102 pr_err("%s: Failed to request gpio irq %d\n", __func__,
3103 mbhc->mbhc_cfg->gpio_irq);
3104 } else {
3105 ret = enable_irq_wake(mbhc->mbhc_cfg->gpio_irq);
3106 if (ret)
3107 pr_err("%s: Failed to enable wake up irq %d\n",
3108 __func__, mbhc->mbhc_cfg->gpio_irq);
3109 }
3110 } else if (mbhc->mbhc_cfg->insert_detect) {
3111 /* Enable HPHL_10K_SW */
3112 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_RX_HPH_OCP_CTL,
3113 1 << 1, 1 << 1);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303114
3115 switch (mbhc->mbhc_version) {
3116 case WCD9XXX_MBHC_VERSION_TAIKO:
Joonwoo Park055ae4f2013-05-28 19:09:56 -07003117 jack_irq = WCD9320_IRQ_MBHC_JACK_SWITCH;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303118 break;
3119 case WCD9XXX_MBHC_VERSION_TAPAN:
Joonwoo Park055ae4f2013-05-28 19:09:56 -07003120 jack_irq = WCD9306_IRQ_MBHC_JACK_SWITCH;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303121 break;
3122 default:
3123 return -EINVAL;
3124 }
3125
3126 ret = wcd9xxx_request_irq(core, jack_irq,
Joonwoo Parka8890262012-10-15 12:04:27 -07003127 wcd9xxx_mech_plug_detect_irq,
3128 "Jack Detect",
3129 mbhc);
3130 if (ret)
3131 pr_err("%s: Failed to request insert detect irq %d\n",
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303132 __func__, jack_irq);
Joonwoo Parka8890262012-10-15 12:04:27 -07003133 }
3134
3135 return ret;
3136}
3137
3138static int wcd9xxx_init_and_calibrate(struct wcd9xxx_mbhc *mbhc)
3139{
3140 int ret = 0;
3141 struct snd_soc_codec *codec = mbhc->codec;
3142
3143 pr_debug("%s: enter\n", __func__);
3144
3145 /* Enable MCLK during calibration */
3146 wcd9xxx_onoff_ext_mclk(mbhc, true);
3147 wcd9xxx_mbhc_setup(mbhc);
3148 wcd9xxx_mbhc_cal(mbhc);
3149 wcd9xxx_mbhc_calc_thres(mbhc);
3150 wcd9xxx_onoff_ext_mclk(mbhc, false);
3151 wcd9xxx_calibrate_hs_polling(mbhc);
3152
3153 /* Enable Mic Bias pull down and HPH Switch to GND */
3154 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
3155 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01, 0x01);
3156 INIT_WORK(&mbhc->correct_plug_swch, wcd9xxx_correct_swch_plug);
3157
3158 if (!IS_ERR_VALUE(ret)) {
3159 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
3160 0x10);
3161 wcd9xxx_enable_irq(codec->control_data,
3162 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
3163 wcd9xxx_enable_irq(codec->control_data,
3164 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
3165
3166 /* Initialize mechanical mbhc */
3167 ret = wcd9xxx_setup_jack_detect_irq(mbhc);
3168
3169 if (!ret && mbhc->mbhc_cfg->gpio) {
3170 /* Requested with IRQF_DISABLED */
3171 enable_irq(mbhc->mbhc_cfg->gpio_irq);
3172
3173 /* Bootup time detection */
3174 wcd9xxx_swch_irq_handler(mbhc);
3175 } else if (!ret && mbhc->mbhc_cfg->insert_detect) {
3176 pr_debug("%s: Setting up codec own insert detection\n",
3177 __func__);
3178 /* Setup for insertion detection */
3179 wcd9xxx_insert_detect_setup(mbhc, true);
3180 }
3181 }
3182
3183 pr_debug("%s: leave\n", __func__);
3184
3185 return ret;
3186}
3187
3188static void wcd9xxx_mbhc_fw_read(struct work_struct *work)
3189{
3190 struct delayed_work *dwork;
3191 struct wcd9xxx_mbhc *mbhc;
3192 struct snd_soc_codec *codec;
3193 const struct firmware *fw;
3194 int ret = -1, retry = 0;
3195
3196 dwork = to_delayed_work(work);
3197 mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_firmware_dwork);
3198 codec = mbhc->codec;
3199
3200 while (retry < FW_READ_ATTEMPTS) {
3201 retry++;
3202 pr_info("%s:Attempt %d to request MBHC firmware\n",
3203 __func__, retry);
3204 ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin",
3205 codec->dev);
3206
3207 if (ret != 0) {
3208 usleep_range(FW_READ_TIMEOUT, FW_READ_TIMEOUT);
3209 } else {
3210 pr_info("%s: MBHC Firmware read succesful\n", __func__);
3211 break;
3212 }
3213 }
3214
3215 if (ret != 0) {
3216 pr_err("%s: Cannot load MBHC firmware use default cal\n",
3217 __func__);
3218 } else if (wcd9xxx_mbhc_fw_validate(fw) == false) {
3219 pr_err("%s: Invalid MBHC cal data size use default cal\n",
3220 __func__);
3221 release_firmware(fw);
3222 } else {
3223 mbhc->mbhc_cfg->calibration = (void *)fw->data;
3224 mbhc->mbhc_fw = fw;
3225 }
3226
3227 (void) wcd9xxx_init_and_calibrate(mbhc);
3228}
3229
3230#ifdef CONFIG_DEBUG_FS
3231ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
3232 size_t count, loff_t *pos)
3233{
3234 const int size = 768;
3235 char buffer[size];
3236 int n = 0;
3237 struct wcd9xxx_mbhc *mbhc = file->private_data;
3238 const struct mbhc_internal_cal_data *p = &mbhc->mbhc_data;
Joonwoo Park73375212013-05-07 12:42:44 -07003239 const s16 v_ins_hu =
3240 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
3241 const s16 v_ins_h =
3242 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
3243 const s16 v_b1_hu =
3244 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
3245 const s16 v_b1_h =
3246 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
3247 const s16 v_br_h =
3248 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
Joonwoo Parka8890262012-10-15 12:04:27 -07003249
Joonwoo Park520a0f92013-05-14 19:39:58 -07003250 n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n",
3251 p->dce_z, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
Joonwoo Parka8890262012-10-15 12:04:27 -07003252 n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
3253 p->dce_mb, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_mb));
3254 n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
3255 p->sta_z, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_z));
3256 n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
3257 p->sta_mb, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_mb));
Joonwoo Park73375212013-05-07 12:42:44 -07003258 n += scnprintf(buffer + n, size - n, "t_dce = %d\n", p->t_dce);
3259 n += scnprintf(buffer + n, size - n, "t_sta = %d\n", p->t_sta);
3260 n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n", p->micb_mv);
3261 n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)\n",
3262 v_ins_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_ins_hu));
3263 n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)\n",
3264 v_ins_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_ins_h));
Joonwoo Parka8890262012-10-15 12:04:27 -07003265 n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
Joonwoo Park73375212013-05-07 12:42:44 -07003266 v_b1_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_b1_hu));
Joonwoo Parka8890262012-10-15 12:04:27 -07003267 n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
Joonwoo Park73375212013-05-07 12:42:44 -07003268 v_b1_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_b1_h));
Joonwoo Parka8890262012-10-15 12:04:27 -07003269 n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
Joonwoo Park73375212013-05-07 12:42:44 -07003270 v_br_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_br_h));
Joonwoo Parka8890262012-10-15 12:04:27 -07003271 n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
3272 wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_brl));
3273 n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
3274 p->v_no_mic,
3275 wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_no_mic));
3276 n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
3277 p->v_inval_ins_low);
3278 n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
3279 p->v_inval_ins_high);
3280 n += scnprintf(buffer + n, size - n, "Insert detect insert = %d\n",
3281 !wcd9xxx_swch_level_remove(mbhc));
3282 buffer[n] = 0;
3283
3284 return simple_read_from_buffer(buf, count, pos, buffer, n);
3285}
3286
3287static int codec_debug_open(struct inode *inode, struct file *file)
3288{
3289 file->private_data = inode->i_private;
3290 return 0;
3291}
3292
3293static ssize_t codec_debug_write(struct file *filp,
3294 const char __user *ubuf, size_t cnt,
3295 loff_t *ppos)
3296{
3297 char lbuf[32];
3298 char *buf;
3299 int rc;
3300 struct wcd9xxx_mbhc *mbhc = filp->private_data;
3301
3302 if (cnt > sizeof(lbuf) - 1)
3303 return -EINVAL;
3304
3305 rc = copy_from_user(lbuf, ubuf, cnt);
3306 if (rc)
3307 return -EFAULT;
3308
3309 lbuf[cnt] = '\0';
3310 buf = (char *)lbuf;
3311 mbhc->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
3312 false : true;
3313 return rc;
3314}
3315
3316static const struct file_operations mbhc_trrs_debug_ops = {
3317 .open = codec_debug_open,
3318 .write = codec_debug_write,
3319};
3320
3321static const struct file_operations mbhc_debug_ops = {
3322 .open = codec_debug_open,
3323 .read = codec_mbhc_debug_read,
3324};
3325
3326static void wcd9xxx_init_debugfs(struct wcd9xxx_mbhc *mbhc)
3327{
3328 mbhc->debugfs_poke =
3329 debugfs_create_file("TRRS", S_IFREG | S_IRUGO, NULL, mbhc,
3330 &mbhc_trrs_debug_ops);
3331 mbhc->debugfs_mbhc =
3332 debugfs_create_file("wcd9xxx_mbhc", S_IFREG | S_IRUGO,
3333 NULL, mbhc, &mbhc_debug_ops);
3334}
3335
3336static void wcd9xxx_cleanup_debugfs(struct wcd9xxx_mbhc *mbhc)
3337{
3338 debugfs_remove(mbhc->debugfs_poke);
3339 debugfs_remove(mbhc->debugfs_mbhc);
3340}
3341#else
3342static void wcd9xxx_init_debugfs(struct wcd9xxx_mbhc *mbhc)
3343{
3344}
3345
3346static void wcd9xxx_cleanup_debugfs(struct wcd9xxx_mbhc *mbhc)
3347{
3348}
3349#endif
3350
3351int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
3352 struct wcd9xxx_mbhc_config *mbhc_cfg)
3353{
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303354 int rc;
Joonwoo Parka8890262012-10-15 12:04:27 -07003355 struct snd_soc_codec *codec = mbhc->codec;
3356
3357 pr_debug("%s: enter\n", __func__);
3358
3359 if (!codec) {
3360 pr_err("%s: no codec\n", __func__);
3361 return -EINVAL;
3362 }
3363
3364 if (mbhc_cfg->mclk_rate != MCLK_RATE_12288KHZ &&
3365 mbhc_cfg->mclk_rate != MCLK_RATE_9600KHZ) {
3366 pr_err("Error: unsupported clock rate %d\n",
3367 mbhc_cfg->mclk_rate);
3368 return -EINVAL;
3369 }
3370
3371 /* Save mbhc config */
3372 mbhc->mbhc_cfg = mbhc_cfg;
3373
3374 /* Get HW specific mbhc registers' address */
3375 wcd9xxx_get_mbhc_micbias_regs(mbhc, &mbhc->mbhc_bias_regs);
3376
3377 /* Put CFILT in fast mode by default */
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303378 rc = wcd9xxx_put_cfilt_fast_mode(codec, mbhc);
3379 if (rc)
3380 pr_err("%s: Error returned, ret: %d\n", __func__, rc);
3381 else if (!mbhc->mbhc_cfg->read_fw_bin)
Joonwoo Parka8890262012-10-15 12:04:27 -07003382 rc = wcd9xxx_init_and_calibrate(mbhc);
3383 else
3384 schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
3385 usecs_to_jiffies(FW_READ_TIMEOUT));
3386
3387 pr_debug("%s: leave %d\n", __func__, rc);
3388 return rc;
3389}
3390EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_start);
3391
3392static enum wcd9xxx_micbias_num
3393wcd9xxx_event_to_micbias(const enum wcd9xxx_notify_event event)
3394{
3395 enum wcd9xxx_micbias_num ret;
3396 switch (event) {
3397 case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003398 case WCD9XXX_EVENT_PRE_MICBIAS_1_OFF:
3399 case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
3400 case WCD9XXX_EVENT_POST_MICBIAS_1_OFF:
Joonwoo Parka8890262012-10-15 12:04:27 -07003401 ret = MBHC_MICBIAS1;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003402 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003403 case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003404 case WCD9XXX_EVENT_PRE_MICBIAS_2_OFF:
3405 case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
3406 case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
Joonwoo Parka8890262012-10-15 12:04:27 -07003407 ret = MBHC_MICBIAS2;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003408 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003409 case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003410 case WCD9XXX_EVENT_PRE_MICBIAS_3_OFF:
3411 case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
3412 case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
Joonwoo Parka8890262012-10-15 12:04:27 -07003413 ret = MBHC_MICBIAS3;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003414 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003415 case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003416 case WCD9XXX_EVENT_PRE_MICBIAS_4_OFF:
3417 case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
3418 case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
Joonwoo Parka8890262012-10-15 12:04:27 -07003419 ret = MBHC_MICBIAS4;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003420 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003421 default:
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003422 WARN_ONCE(1, "Cannot convert event %d to micbias\n", event);
Joonwoo Parka8890262012-10-15 12:04:27 -07003423 ret = MBHC_MICBIAS_INVALID;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003424 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003425 }
3426 return ret;
3427}
3428
3429static int wcd9xxx_event_to_cfilt(const enum wcd9xxx_notify_event event)
3430{
3431 int ret;
3432 switch (event) {
3433 case WCD9XXX_EVENT_PRE_CFILT_1_OFF:
3434 case WCD9XXX_EVENT_POST_CFILT_1_OFF:
3435 case WCD9XXX_EVENT_PRE_CFILT_1_ON:
3436 case WCD9XXX_EVENT_POST_CFILT_1_ON:
3437 ret = WCD9XXX_CFILT1_SEL;
3438 break;
3439 case WCD9XXX_EVENT_PRE_CFILT_2_OFF:
3440 case WCD9XXX_EVENT_POST_CFILT_2_OFF:
3441 case WCD9XXX_EVENT_PRE_CFILT_2_ON:
3442 case WCD9XXX_EVENT_POST_CFILT_2_ON:
3443 ret = WCD9XXX_CFILT2_SEL;
3444 break;
3445 case WCD9XXX_EVENT_PRE_CFILT_3_OFF:
3446 case WCD9XXX_EVENT_POST_CFILT_3_OFF:
3447 case WCD9XXX_EVENT_PRE_CFILT_3_ON:
3448 case WCD9XXX_EVENT_POST_CFILT_3_ON:
3449 ret = WCD9XXX_CFILT3_SEL;
3450 break;
3451 default:
3452 ret = -1;
3453 }
3454 return ret;
3455}
3456
3457static int wcd9xxx_get_mbhc_cfilt_sel(struct wcd9xxx_mbhc *mbhc)
3458{
3459 int cfilt;
3460 const struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
3461
3462 switch (mbhc->mbhc_cfg->micbias) {
3463 case MBHC_MICBIAS1:
3464 cfilt = pdata->micbias.bias1_cfilt_sel;
3465 break;
3466 case MBHC_MICBIAS2:
3467 cfilt = pdata->micbias.bias2_cfilt_sel;
3468 break;
3469 case MBHC_MICBIAS3:
3470 cfilt = pdata->micbias.bias3_cfilt_sel;
3471 break;
3472 case MBHC_MICBIAS4:
3473 cfilt = pdata->micbias.bias4_cfilt_sel;
3474 break;
3475 default:
3476 cfilt = MBHC_MICBIAS_INVALID;
3477 break;
3478 }
3479 return cfilt;
3480}
3481
3482static int wcd9xxx_event_notify(struct notifier_block *self, unsigned long val,
3483 void *data)
3484{
3485 int ret = 0;
3486 struct wcd9xxx_mbhc *mbhc = ((struct wcd9xxx_resmgr *)data)->mbhc;
3487 struct snd_soc_codec *codec = mbhc->codec;
3488 enum wcd9xxx_notify_event event = (enum wcd9xxx_notify_event)val;
3489
3490 pr_debug("%s: enter event %s(%d)\n", __func__,
3491 wcd9xxx_get_event_string(event), event);
3492
3493 switch (event) {
3494 /* MICBIAS usage change */
3495 case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
3496 case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
3497 case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
3498 case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
3499 if (mbhc->mbhc_cfg->micbias == wcd9xxx_event_to_micbias(event))
3500 wcd9xxx_switch_micbias(mbhc, 0);
3501 break;
3502 case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
3503 case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
3504 case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
3505 case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
3506 if (mbhc->mbhc_cfg->micbias ==
3507 wcd9xxx_event_to_micbias(event) &&
3508 wcd9xxx_mbhc_polling(mbhc)) {
3509 /* if polling is on, restart it */
3510 wcd9xxx_pause_hs_polling(mbhc);
3511 wcd9xxx_start_hs_polling(mbhc);
3512 }
3513 break;
3514 case WCD9XXX_EVENT_POST_MICBIAS_1_OFF:
3515 case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
3516 case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
3517 case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
3518 if (mbhc->mbhc_cfg->micbias ==
3519 wcd9xxx_event_to_micbias(event) &&
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003520 (mbhc->event_state &
3521 (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
Joonwoo Parka8890262012-10-15 12:04:27 -07003522 wcd9xxx_switch_micbias(mbhc, 1);
3523 break;
3524 /* PA usage change */
3525 case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003526 set_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -07003527 if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg) & 0x80))
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003528 /* if micbias is not enabled, switch to vddio */
Joonwoo Parka8890262012-10-15 12:04:27 -07003529 wcd9xxx_switch_micbias(mbhc, 1);
3530 break;
3531 case WCD9XXX_EVENT_PRE_HPHR_PA_ON:
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003532 set_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
Joonwoo Parka8890262012-10-15 12:04:27 -07003533 break;
3534 case WCD9XXX_EVENT_POST_HPHL_PA_OFF:
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003535 clear_bit(MBHC_EVENT_PA_HPHL, &mbhc->event_state);
Joonwoo Parka8890262012-10-15 12:04:27 -07003536 /* if HPH PAs are off, report OCP and switch back to CFILT */
3537 clear_bit(WCD9XXX_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
3538 clear_bit(WCD9XXX_HPHL_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
3539 if (mbhc->hph_status & SND_JACK_OC_HPHL)
3540 hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003541 if (!(mbhc->event_state &
3542 (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
3543 wcd9xxx_switch_micbias(mbhc, 0);
Joonwoo Parka8890262012-10-15 12:04:27 -07003544 break;
3545 case WCD9XXX_EVENT_POST_HPHR_PA_OFF:
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003546 clear_bit(MBHC_EVENT_PA_HPHR, &mbhc->event_state);
Joonwoo Parka8890262012-10-15 12:04:27 -07003547 /* if HPH PAs are off, report OCP and switch back to CFILT */
3548 clear_bit(WCD9XXX_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
3549 clear_bit(WCD9XXX_HPHR_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
3550 if (mbhc->hph_status & SND_JACK_OC_HPHR)
3551 hphrocp_off_report(mbhc, SND_JACK_OC_HPHL);
Joonwoo Park2cee50a2013-05-15 14:09:06 -07003552 if (!(mbhc->event_state &
3553 (1 << MBHC_EVENT_PA_HPHL | 1 << MBHC_EVENT_PA_HPHR)))
3554 wcd9xxx_switch_micbias(mbhc, 0);
Joonwoo Parka8890262012-10-15 12:04:27 -07003555 break;
3556 /* Clock usage change */
3557 case WCD9XXX_EVENT_PRE_MCLK_ON:
3558 break;
3559 case WCD9XXX_EVENT_POST_MCLK_ON:
3560 /* Change to lower TxAAF frequency */
3561 snd_soc_update_bits(codec, WCD9XXX_A_TX_COM_BIAS, 1 << 4,
3562 1 << 4);
3563 /* Re-calibrate clock rate dependent values */
3564 wcd9xxx_update_mbhc_clk_rate(mbhc, mbhc->mbhc_cfg->mclk_rate);
3565 /* If clock source changes, stop and restart polling */
3566 if (wcd9xxx_mbhc_polling(mbhc)) {
3567 wcd9xxx_calibrate_hs_polling(mbhc);
3568 wcd9xxx_start_hs_polling(mbhc);
3569 }
3570 break;
3571 case WCD9XXX_EVENT_PRE_MCLK_OFF:
3572 /* If clock source changes, stop and restart polling */
3573 if (wcd9xxx_mbhc_polling(mbhc))
3574 wcd9xxx_pause_hs_polling(mbhc);
3575 break;
3576 case WCD9XXX_EVENT_POST_MCLK_OFF:
3577 break;
3578 case WCD9XXX_EVENT_PRE_RCO_ON:
3579 break;
3580 case WCD9XXX_EVENT_POST_RCO_ON:
3581 /* Change to higher TxAAF frequency */
3582 snd_soc_update_bits(codec, WCD9XXX_A_TX_COM_BIAS, 1 << 4,
3583 0 << 4);
3584 /* Re-calibrate clock rate dependent values */
Phani Kumar Uppalapati43bc4152013-05-24 00:44:20 -07003585 wcd9xxx_update_mbhc_clk_rate(mbhc, mbhc->rco_clk_rate);
Joonwoo Parka8890262012-10-15 12:04:27 -07003586 /* If clock source changes, stop and restart polling */
3587 if (wcd9xxx_mbhc_polling(mbhc)) {
3588 wcd9xxx_calibrate_hs_polling(mbhc);
3589 wcd9xxx_start_hs_polling(mbhc);
3590 }
3591 break;
3592 case WCD9XXX_EVENT_PRE_RCO_OFF:
3593 /* If clock source changes, stop and restart polling */
3594 if (wcd9xxx_mbhc_polling(mbhc))
3595 wcd9xxx_pause_hs_polling(mbhc);
3596 break;
3597 case WCD9XXX_EVENT_POST_RCO_OFF:
3598 break;
3599 /* CFILT usage change */
3600 case WCD9XXX_EVENT_PRE_CFILT_1_ON:
3601 case WCD9XXX_EVENT_PRE_CFILT_2_ON:
3602 case WCD9XXX_EVENT_PRE_CFILT_3_ON:
3603 if (wcd9xxx_get_mbhc_cfilt_sel(mbhc) ==
3604 wcd9xxx_event_to_cfilt(event))
3605 /*
3606 * Switch CFILT to slow mode if MBHC CFILT is being
3607 * used.
3608 */
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303609 ret = wcd9xxx_codec_switch_cfilt_mode(mbhc, false);
Joonwoo Parka8890262012-10-15 12:04:27 -07003610 break;
3611 case WCD9XXX_EVENT_POST_CFILT_1_OFF:
3612 case WCD9XXX_EVENT_POST_CFILT_2_OFF:
3613 case WCD9XXX_EVENT_POST_CFILT_3_OFF:
3614 if (wcd9xxx_get_mbhc_cfilt_sel(mbhc) ==
3615 wcd9xxx_event_to_cfilt(event))
3616 /*
3617 * Switch CFILT to fast mode if MBHC CFILT is not
3618 * used anymore.
3619 */
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303620 ret = wcd9xxx_codec_switch_cfilt_mode(mbhc, true);
Joonwoo Parka8890262012-10-15 12:04:27 -07003621 break;
3622 /* System resume */
3623 case WCD9XXX_EVENT_POST_RESUME:
3624 mbhc->mbhc_last_resume = jiffies;
3625 break;
3626 /* BG mode chage */
3627 case WCD9XXX_EVENT_PRE_BG_OFF:
3628 case WCD9XXX_EVENT_POST_BG_OFF:
3629 case WCD9XXX_EVENT_PRE_BG_AUDIO_ON:
3630 case WCD9XXX_EVENT_POST_BG_AUDIO_ON:
3631 case WCD9XXX_EVENT_PRE_BG_MBHC_ON:
3632 case WCD9XXX_EVENT_POST_BG_MBHC_ON:
3633 /* Not used for now */
3634 break;
3635 default:
3636 WARN(1, "Unknown event %d\n", event);
3637 ret = -EINVAL;
3638 }
3639
3640 pr_debug("%s: leave\n", __func__);
3641
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303642 return ret;
Joonwoo Parka8890262012-10-15 12:04:27 -07003643}
3644
3645/*
3646 * wcd9xxx_mbhc_init : initialize MBHC internal structures.
3647 *
3648 * NOTE: mbhc->mbhc_cfg is not YET configure so shouldn't be used
3649 */
3650int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
Joonwoo Parkccccba72013-04-26 11:19:46 -07003651 struct snd_soc_codec *codec,
3652 int (*micbias_enable_cb) (struct snd_soc_codec*, bool),
Phani Kumar Uppalapati43bc4152013-05-24 00:44:20 -07003653 int version,
3654 int rco_clk_rate)
Joonwoo Parka8890262012-10-15 12:04:27 -07003655{
3656 int ret;
3657 void *core;
3658
3659 pr_debug("%s: enter\n", __func__);
3660 memset(&mbhc->mbhc_bias_regs, 0, sizeof(struct mbhc_micbias_regs));
3661 memset(&mbhc->mbhc_data, 0, sizeof(struct mbhc_internal_cal_data));
3662
3663 mbhc->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
3664 mbhc->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
3665 mbhc->mbhc_data.t_sta = DEFAULT_STA_WAIT;
3666 mbhc->mbhc_micbias_switched = false;
3667 mbhc->polling_active = false;
3668 mbhc->mbhc_state = MBHC_STATE_NONE;
3669 mbhc->in_swch_irq_handler = false;
3670 mbhc->current_plug = PLUG_TYPE_NONE;
3671 mbhc->lpi_enabled = false;
3672 mbhc->no_mic_headset_override = false;
3673 mbhc->mbhc_last_resume = 0;
3674 mbhc->codec = codec;
3675 mbhc->resmgr = resmgr;
3676 mbhc->resmgr->mbhc = mbhc;
Joonwoo Parkccccba72013-04-26 11:19:46 -07003677 mbhc->micbias_enable_cb = micbias_enable_cb;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303678 mbhc->mbhc_version = version;
Phani Kumar Uppalapati43bc4152013-05-24 00:44:20 -07003679 mbhc->rco_clk_rate = rco_clk_rate;
Joonwoo Parka8890262012-10-15 12:04:27 -07003680
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003681 if (mbhc->headset_jack.jack == NULL) {
3682 ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
3683 &mbhc->headset_jack);
3684 if (ret) {
3685 pr_err("%s: Failed to create new jack\n", __func__);
3686 return ret;
3687 }
Joonwoo Parka8890262012-10-15 12:04:27 -07003688
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003689 ret = snd_soc_jack_new(codec, "Button Jack",
3690 WCD9XXX_JACK_BUTTON_MASK,
3691 &mbhc->button_jack);
3692 if (ret) {
3693 pr_err("Failed to create new jack\n");
3694 return ret;
3695 }
Joonwoo Parka8890262012-10-15 12:04:27 -07003696
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003697 INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
3698 wcd9xxx_mbhc_fw_read);
3699 INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
3700 INIT_DELAYED_WORK(&mbhc->mbhc_insert_dwork,
3701 wcd9xxx_mbhc_insert_work);
3702 }
Joonwoo Parka8890262012-10-15 12:04:27 -07003703
3704 /* Register event notifier */
3705 mbhc->nblock.notifier_call = wcd9xxx_event_notify;
3706 ret = wcd9xxx_resmgr_register_notifier(mbhc->resmgr, &mbhc->nblock);
3707 if (ret) {
3708 pr_err("%s: Failed to register notifier %d\n", __func__, ret);
3709 return ret;
3710 }
3711
3712 wcd9xxx_init_debugfs(mbhc);
3713
3714 core = mbhc->resmgr->core;
3715 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_INSERTION,
3716 wcd9xxx_hs_insert_irq,
3717 "Headset insert detect", mbhc);
3718 if (ret) {
3719 pr_err("%s: Failed to request irq %d\n", __func__,
3720 WCD9XXX_IRQ_MBHC_INSERTION);
3721 goto err_insert_irq;
3722 }
3723 wcd9xxx_disable_irq(core, WCD9XXX_IRQ_MBHC_INSERTION);
3724
3725 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL,
3726 wcd9xxx_hs_remove_irq,
3727 "Headset remove detect", mbhc);
3728 if (ret) {
3729 pr_err("%s: Failed to request irq %d\n", __func__,
3730 WCD9XXX_IRQ_MBHC_REMOVAL);
3731 goto err_remove_irq;
3732 }
3733
3734 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL,
3735 wcd9xxx_dce_handler, "DC Estimation detect",
3736 mbhc);
3737 if (ret) {
3738 pr_err("%s: Failed to request irq %d\n", __func__,
3739 WCD9XXX_IRQ_MBHC_POTENTIAL);
3740 goto err_potential_irq;
3741 }
3742
3743 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_RELEASE,
3744 wcd9xxx_release_handler,
3745 "Button Release detect", mbhc);
3746 if (ret) {
3747 pr_err("%s: Failed to request irq %d\n", __func__,
3748 WCD9XXX_IRQ_MBHC_RELEASE);
3749 goto err_release_irq;
3750 }
3751
3752 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
3753 wcd9xxx_hphl_ocp_irq, "HPH_L OCP detect",
3754 mbhc);
3755 if (ret) {
3756 pr_err("%s: Failed to request irq %d\n", __func__,
3757 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
3758 goto err_hphl_ocp_irq;
3759 }
3760 wcd9xxx_disable_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
3761
3762 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
3763 wcd9xxx_hphr_ocp_irq, "HPH_R OCP detect",
3764 mbhc);
3765 if (ret) {
3766 pr_err("%s: Failed to request irq %d\n", __func__,
3767 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
3768 goto err_hphr_ocp_irq;
3769 }
3770 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
3771
3772 pr_debug("%s: leave ret %d\n", __func__, ret);
3773 return ret;
3774
3775err_hphr_ocp_irq:
3776 wcd9xxx_free_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
3777err_hphl_ocp_irq:
3778 wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
3779err_release_irq:
3780 wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
3781err_potential_irq:
3782 wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
3783err_remove_irq:
3784 wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
3785err_insert_irq:
3786 wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
3787
3788 pr_debug("%s: leave ret %d\n", __func__, ret);
3789 return ret;
3790}
3791EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_init);
3792
3793void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc)
3794{
3795 void *cdata = mbhc->codec->control_data;
3796
Joonwoo Parka8890262012-10-15 12:04:27 -07003797 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
3798 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
3799 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
3800 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
3801
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07003802 switch (mbhc->mbhc_version) {
3803 case WCD9XXX_MBHC_VERSION_TAIKO:
Joonwoo Park055ae4f2013-05-28 19:09:56 -07003804 wcd9xxx_free_irq(cdata, WCD9320_IRQ_MBHC_JACK_SWITCH, mbhc);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07003805 break;
3806 case WCD9XXX_MBHC_VERSION_TAPAN:
Joonwoo Park055ae4f2013-05-28 19:09:56 -07003807 wcd9xxx_free_irq(cdata, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07003808 break;
3809 default:
3810 pr_err("%s: irq free failed! Invalid MBHC version %d\n",
3811 __func__, mbhc->mbhc_version);
3812 }
3813
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003814 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
3815 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003816
Joonwoo Parka8890262012-10-15 12:04:27 -07003817 if (mbhc->mbhc_fw)
3818 release_firmware(mbhc->mbhc_fw);
3819
3820 wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
3821
3822 wcd9xxx_cleanup_debugfs(mbhc);
Joonwoo Parka8890262012-10-15 12:04:27 -07003823}
3824EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_deinit);
3825
3826MODULE_DESCRIPTION("wcd9xxx MBHC module");
3827MODULE_LICENSE("GPL v2");