blob: cc22fd4e9b39f7acf29f7b638c6f00e859437a91 [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 */
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -070012
Joonwoo Parka8890262012-10-15 12:04:27 -070013#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/firmware.h>
16#include <linux/slab.h>
17#include <linux/platform_device.h>
18#include <linux/device.h>
19#include <linux/printk.h>
20#include <linux/ratelimit.h>
21#include <linux/debugfs.h>
22#include <linux/mfd/wcd9xxx/core.h>
23#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
24#include <linux/mfd/wcd9xxx/wcd9320_registers.h>
25#include <linux/mfd/wcd9xxx/pdata.h>
26#include <sound/pcm.h>
27#include <sound/pcm_params.h>
28#include <sound/soc.h>
29#include <sound/soc-dapm.h>
30#include <sound/tlv.h>
31#include <linux/bitops.h>
32#include <linux/delay.h>
33#include <linux/pm_runtime.h>
34#include <linux/kernel.h>
35#include <linux/gpio.h>
36#include "wcd9320.h"
Simmi Pateriya0a44d842013-04-03 01:12:42 +053037#include "wcd9306.h"
Joonwoo Parka8890262012-10-15 12:04:27 -070038#include "wcd9xxx-mbhc.h"
39#include "wcd9xxx-resmgr.h"
40
41#define WCD9XXX_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
Joonwoo Park80a01172012-10-15 16:05:23 -070042 SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
43 SND_JACK_UNSUPPORTED)
Joonwoo Parka8890262012-10-15 12:04:27 -070044#define WCD9XXX_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
45 SND_JACK_BTN_2 | SND_JACK_BTN_3 | \
46 SND_JACK_BTN_4 | SND_JACK_BTN_5 | \
47 SND_JACK_BTN_6 | SND_JACK_BTN_7)
48
49#define NUM_DCE_PLUG_DETECT 3
Joonwoo Park20bc9da2013-01-16 12:58:06 -080050#define NUM_DCE_PLUG_INS_DETECT 4
Joonwoo Parka8890262012-10-15 12:04:27 -070051#define NUM_ATTEMPTS_INSERT_DETECT 25
52#define NUM_ATTEMPTS_TO_REPORT 5
53
54#define FAKE_INS_LOW 10
55#define FAKE_INS_HIGH 80
56#define FAKE_INS_HIGH_NO_SWCH 150
57#define FAKE_REMOVAL_MIN_PERIOD_MS 50
58#define FAKE_INS_DELTA_SCALED_MV 300
59
60#define BUTTON_MIN 0x8000
61#define STATUS_REL_DETECTION 0x0C
62
63#define HS_DETECT_PLUG_TIME_MS (5 * 1000)
64#define HS_DETECT_PLUG_INERVAL_MS 100
65#define SWCH_REL_DEBOUNCE_TIME_MS 50
66#define SWCH_IRQ_DEBOUNCE_TIME_US 5000
67
68#define GND_MIC_SWAP_THRESHOLD 2
69#define OCP_ATTEMPT 1
70
71#define FW_READ_ATTEMPTS 15
72#define FW_READ_TIMEOUT 2000000
73
Joonwoo Park2e6bd1e2012-10-18 13:48:55 -070074#define BUTTON_POLLING_SUPPORTED true
Joonwoo Parka8890262012-10-15 12:04:27 -070075
76#define MCLK_RATE_12288KHZ 12288000
77#define MCLK_RATE_9600KHZ 9600000
78#define WCD9XXX_RCO_CLK_RATE MCLK_RATE_12288KHZ
79
80#define DEFAULT_DCE_STA_WAIT 55
81#define DEFAULT_DCE_WAIT 60000
82#define DEFAULT_STA_WAIT 5000
83
84#define VDDIO_MICBIAS_MV 1800
85
Joonwoo Park20bc9da2013-01-16 12:58:06 -080086#define WCD9XXX_HPHL_STATUS_READY_WAIT_US 1000
Joonwoo Park7902f4c2013-02-20 15:21:25 -080087#define WCD9XXX_MUX_SWITCH_READY_WAIT_US 100
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 Park20bc9da2013-01-16 12:58:06 -080093
94#define WCD9XXX_USLEEP_RANGE_MARGIN_US 1000
95
Simmi Pateriya0a44d842013-04-03 01:12:42 +053096#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAIKO 28
97#define WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAPAN 21
98
Joonwoo Park20bc9da2013-01-16 12:58:06 -080099static bool detect_use_vddio_switch;
100
101struct wcd9xxx_mbhc_detect {
102 u16 dce;
103 u16 sta;
104 u16 hphl_status;
105 bool swap_gnd;
106 bool vddio;
107 bool hwvalue;
108 /* internal purpose from here */
109 bool _above_no_mic;
110 bool _below_v_hs_max;
111 s16 _vdces;
112 enum wcd9xxx_mbhc_plug_type _type;
113};
114
Joonwoo Parka8890262012-10-15 12:04:27 -0700115enum meas_type {
116 STA = 0,
117 DCE,
118};
119
120enum {
121 MBHC_USE_HPHL_TRIGGER = 1,
122 MBHC_USE_MB_TRIGGER = 2
123};
124
125/*
126 * Flags to track of PA and DAC state.
127 * PA and DAC should be tracked separately as AUXPGA loopback requires
128 * only PA to be turned on without DAC being on.
129 */
130enum pa_dac_ack_flags {
131 WCD9XXX_HPHL_PA_OFF_ACK = 0,
132 WCD9XXX_HPHR_PA_OFF_ACK,
133 WCD9XXX_HPHL_DAC_OFF_ACK,
134 WCD9XXX_HPHR_DAC_OFF_ACK
135};
136
Joonwoo Park73375212013-05-07 12:42:44 -0700137enum wcd9xxx_current_v_idx {
138 WCD9XXX_CURRENT_V_INS_H,
139 WCD9XXX_CURRENT_V_INS_HU,
140 WCD9XXX_CURRENT_V_B1_H,
141 WCD9XXX_CURRENT_V_B1_HU,
142 WCD9XXX_CURRENT_V_BR_H,
143};
144
Joonwoo Parka8890262012-10-15 12:04:27 -0700145static bool wcd9xxx_mbhc_polling(struct wcd9xxx_mbhc *mbhc)
146{
147 return mbhc->polling_active;
148}
149
150static void wcd9xxx_turn_onoff_override(struct snd_soc_codec *codec, bool on)
151{
152 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
153}
154
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530155static int wcd9xxx_enable_mux_bias_block(struct snd_soc_codec *codec,
156 struct wcd9xxx_mbhc *mbhc)
157{
158 switch (mbhc->mbhc_version) {
159 case WCD9XXX_MBHC_VERSION_TAIKO:
160 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
161 0x80, 0x80);
162 break;
163 case WCD9XXX_MBHC_VERSION_TAPAN:
164 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
165 0x80, 0x00);
166 break;
167 default:
168 return -EINVAL;
169 }
170 return 0;
171}
172
173static int wcd9xxx_put_cfilt_fast_mode(struct snd_soc_codec *codec,
174 struct wcd9xxx_mbhc *mbhc)
175{
176 switch (mbhc->mbhc_version) {
177 case WCD9XXX_MBHC_VERSION_TAIKO:
178 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
179 0x70, 0x00);
180 break;
181 case WCD9XXX_MBHC_VERSION_TAPAN:
182 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
183 0x70, 0x70);
184 break;
185 default:
186 return -EINVAL;
187 }
188 return 0;
189}
190
191static int wcd9xxx_codec_specific_cal_setup(struct snd_soc_codec *codec,
192 struct wcd9xxx_mbhc *mbhc)
193{
194 switch (mbhc->mbhc_version) {
195 case WCD9XXX_MBHC_VERSION_TAIKO:
196 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
197 0x04, 0x04);
198 break;
199 case WCD9XXX_MBHC_VERSION_TAPAN:
200 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
201 0x0C, 0x04);
202 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
203 /* Make sure the calibration is ON */
204 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_val,
205 0x02, 0x02);
206 break;
207 default:
208 return -EINVAL;
209 }
210 return 0;
211}
212
Joonwoo Parka8890262012-10-15 12:04:27 -0700213/* called under codec_resource_lock acquisition */
214static void wcd9xxx_pause_hs_polling(struct wcd9xxx_mbhc *mbhc)
215{
216 struct snd_soc_codec *codec = mbhc->codec;
217
218 pr_debug("%s: enter\n", __func__);
219 if (!mbhc->polling_active) {
220 pr_debug("polling not active, nothing to pause\n");
221 return;
222 }
223
224 /* Soft reset MBHC block */
225 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
226 pr_debug("%s: leave\n", __func__);
227}
228
229/* called under codec_resource_lock acquisition */
230static void wcd9xxx_start_hs_polling(struct wcd9xxx_mbhc *mbhc)
231{
232 struct snd_soc_codec *codec = mbhc->codec;
233 int mbhc_state = mbhc->mbhc_state;
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530234 int ret;
Joonwoo Parka8890262012-10-15 12:04:27 -0700235
236 pr_debug("%s: enter\n", __func__);
237 if (!mbhc->polling_active) {
238 pr_debug("Polling is not active, do not start polling\n");
239 return;
240 }
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +0530241
242 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530243 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
244 if (ret) {
245 pr_err("%s: Error returned, ret: %d\n", __func__, ret);
246 return;
247 }
248
Joonwoo Parka8890262012-10-15 12:04:27 -0700249 if (!mbhc->no_mic_headset_override &&
250 mbhc_state == MBHC_STATE_POTENTIAL) {
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530251 pr_debug("%s recovering MBHC state machine\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -0700252 mbhc->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
253 /* set to max button press threshold */
254 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL, 0x7F);
255 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, 0xFF);
256 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL, 0x7F);
257 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, 0xFF);
258 /* set to max */
259 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
260 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
261 }
262
263 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
264 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
265 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x1);
266 pr_debug("%s: leave\n", __func__);
267}
268
269/* called under codec_resource_lock acquisition */
270static void __wcd9xxx_switch_micbias(struct wcd9xxx_mbhc *mbhc,
271 int vddio_switch, bool restartpolling,
272 bool checkpolling)
273{
274 int cfilt_k_val;
275 bool override;
276 struct snd_soc_codec *codec;
Joonwoo Park73375212013-05-07 12:42:44 -0700277 struct mbhc_internal_cal_data *d = &mbhc->mbhc_data;
Joonwoo Parka8890262012-10-15 12:04:27 -0700278
279 codec = mbhc->codec;
280
281 if (vddio_switch && !mbhc->mbhc_micbias_switched &&
282 (!checkpolling || mbhc->polling_active)) {
283 if (restartpolling)
284 wcd9xxx_pause_hs_polling(mbhc);
285 override = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) &
286 0x04;
287 if (!override)
288 wcd9xxx_turn_onoff_override(codec, true);
289 /* Adjust threshold if Mic Bias voltage changes */
Joonwoo Park73375212013-05-07 12:42:44 -0700290 if (d->micb_mv != VDDIO_MICBIAS_MV) {
Joonwoo Parka8890262012-10-15 12:04:27 -0700291 cfilt_k_val = wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
292 VDDIO_MICBIAS_MV);
293 usleep_range(10000, 10000);
294 snd_soc_update_bits(codec,
295 mbhc->mbhc_bias_regs.cfilt_val,
296 0xFC, (cfilt_k_val << 2));
297 usleep_range(10000, 10000);
Joonwoo Park73375212013-05-07 12:42:44 -0700298 /* Threshods for insertion/removal */
Joonwoo Parka8890262012-10-15 12:04:27 -0700299 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700300 d->v_ins_hu[MBHC_V_IDX_VDDIO] & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700301 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700302 (d->v_ins_hu[MBHC_V_IDX_VDDIO] >> 8) &
Joonwoo Parka8890262012-10-15 12:04:27 -0700303 0xFF);
Joonwoo Park73375212013-05-07 12:42:44 -0700304 /* Threshods for button press */
305 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
306 d->v_b1_hu[MBHC_V_IDX_VDDIO] & 0xFF);
307 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
308 (d->v_b1_hu[MBHC_V_IDX_VDDIO] >> 8) &
309 0xFF);
310 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
311 d->v_b1_h[MBHC_V_IDX_VDDIO] & 0xFF);
312 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
313 (d->v_b1_h[MBHC_V_IDX_VDDIO] >> 8) &
314 0xFF);
315 /* Threshods for button release */
316 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
317 d->v_brh[MBHC_V_IDX_VDDIO] & 0xFF);
318 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
319 (d->v_brh[MBHC_V_IDX_VDDIO] >> 8) & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700320 pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
321 __func__);
322 }
323
324 /* Enable MIC BIAS Switch to VDDIO */
325 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
326 0x80, 0x80);
327 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
328 0x10, 0x00);
329 if (!override)
330 wcd9xxx_turn_onoff_override(codec, false);
331 if (restartpolling)
332 wcd9xxx_start_hs_polling(mbhc);
333
334 mbhc->mbhc_micbias_switched = true;
335 pr_debug("%s: VDDIO switch enabled\n", __func__);
336 } else if (!vddio_switch && mbhc->mbhc_micbias_switched) {
337 if ((!checkpolling || mbhc->polling_active) &&
338 restartpolling)
339 wcd9xxx_pause_hs_polling(mbhc);
340 /* Reprogram thresholds */
Joonwoo Park73375212013-05-07 12:42:44 -0700341 if (d->micb_mv != VDDIO_MICBIAS_MV) {
Joonwoo Parka8890262012-10-15 12:04:27 -0700342 cfilt_k_val =
343 wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
Joonwoo Park73375212013-05-07 12:42:44 -0700344 d->micb_mv);
Joonwoo Parka8890262012-10-15 12:04:27 -0700345 snd_soc_update_bits(codec,
346 mbhc->mbhc_bias_regs.cfilt_val,
347 0xFC, (cfilt_k_val << 2));
348 usleep_range(10000, 10000);
Joonwoo Park73375212013-05-07 12:42:44 -0700349 /* Revert threshods for insertion/removal */
Joonwoo Parka8890262012-10-15 12:04:27 -0700350 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700351 d->v_ins_hu[MBHC_V_IDX_CFILT] & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700352 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700353 (d->v_ins_hu[MBHC_V_IDX_CFILT] >> 8) &
354 0xFF);
355 /* Revert threshods for button press */
356 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL,
357 d->v_b1_hu[MBHC_V_IDX_CFILT] & 0xFF);
358 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
359 (d->v_b1_hu[MBHC_V_IDX_CFILT] >> 8) &
360 0xFF);
361 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL,
362 d->v_b1_h[MBHC_V_IDX_CFILT] & 0xFF);
363 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
364 (d->v_b1_h[MBHC_V_IDX_CFILT] >> 8) &
365 0xFF);
366 /* Revert threshods for button release */
367 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL,
368 d->v_brh[MBHC_V_IDX_CFILT] & 0xFF);
369 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
370 (d->v_brh[MBHC_V_IDX_CFILT] >> 8) & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700371 pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
372 __func__);
373 }
374
375 /* Disable MIC BIAS Switch to VDDIO */
376 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x80,
377 0x00);
378 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x10,
379 0x00);
380
381 if ((!checkpolling || mbhc->polling_active) && restartpolling)
382 wcd9xxx_start_hs_polling(mbhc);
383
384 mbhc->mbhc_micbias_switched = false;
385 pr_debug("%s: VDDIO switch disabled\n", __func__);
386 }
387}
388
389static void wcd9xxx_switch_micbias(struct wcd9xxx_mbhc *mbhc, int vddio_switch)
390{
391 return __wcd9xxx_switch_micbias(mbhc, vddio_switch, true, true);
392}
393
Joonwoo Park73375212013-05-07 12:42:44 -0700394static s16 wcd9xxx_get_current_v(struct wcd9xxx_mbhc *mbhc,
395 const enum wcd9xxx_current_v_idx idx)
Joonwoo Parka8890262012-10-15 12:04:27 -0700396{
Joonwoo Park73375212013-05-07 12:42:44 -0700397 enum mbhc_v_index vidx;
398 s16 ret = -EINVAL;
399
Joonwoo Parka8890262012-10-15 12:04:27 -0700400 if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
401 mbhc->mbhc_micbias_switched)
Joonwoo Park73375212013-05-07 12:42:44 -0700402 vidx = MBHC_V_IDX_VDDIO;
Joonwoo Parka8890262012-10-15 12:04:27 -0700403 else
Joonwoo Park73375212013-05-07 12:42:44 -0700404 vidx = MBHC_V_IDX_CFILT;
405
406 switch (idx) {
407 case WCD9XXX_CURRENT_V_INS_H:
408 ret = (s16)mbhc->mbhc_data.v_ins_h[vidx];
409 break;
410 case WCD9XXX_CURRENT_V_INS_HU:
411 ret = (s16)mbhc->mbhc_data.v_ins_hu[vidx];
412 break;
413 case WCD9XXX_CURRENT_V_B1_H:
414 ret = (s16)mbhc->mbhc_data.v_b1_h[vidx];
415 break;
416 case WCD9XXX_CURRENT_V_B1_HU:
417 ret = (s16)mbhc->mbhc_data.v_b1_hu[vidx];
418 break;
419 case WCD9XXX_CURRENT_V_BR_H:
420 ret = (s16)mbhc->mbhc_data.v_brh[vidx];
421 break;
422 }
423
424 return ret;
Joonwoo Parka8890262012-10-15 12:04:27 -0700425}
426
427void *wcd9xxx_mbhc_cal_btn_det_mp(
428 const struct wcd9xxx_mbhc_btn_detect_cfg *btn_det,
429 const enum wcd9xxx_mbhc_btn_det_mem mem)
430{
431 void *ret = &btn_det->_v_btn_low;
432
433 switch (mem) {
434 case MBHC_BTN_DET_GAIN:
435 ret += sizeof(btn_det->_n_cic);
436 case MBHC_BTN_DET_N_CIC:
437 ret += sizeof(btn_det->_n_ready);
438 case MBHC_BTN_DET_N_READY:
439 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
440 case MBHC_BTN_DET_V_BTN_HIGH:
441 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
442 case MBHC_BTN_DET_V_BTN_LOW:
443 /* do nothing */
444 break;
445 default:
446 ret = NULL;
447 }
448
449 return ret;
450}
451EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_cal_btn_det_mp);
452
453static void wcd9xxx_calibrate_hs_polling(struct wcd9xxx_mbhc *mbhc)
454{
455 struct snd_soc_codec *codec = mbhc->codec;
Joonwoo Park73375212013-05-07 12:42:44 -0700456 const s16 v_ins_hu = wcd9xxx_get_current_v(mbhc,
457 WCD9XXX_CURRENT_V_INS_HU);
458 const s16 v_b1_hu = wcd9xxx_get_current_v(mbhc,
459 WCD9XXX_CURRENT_V_B1_HU);
460 const s16 v_b1_h = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
461 const s16 v_brh = wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
Joonwoo Parka8890262012-10-15 12:04:27 -0700462
463 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B1_CTL, v_ins_hu & 0xFF);
464 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B2_CTL,
465 (v_ins_hu >> 8) & 0xFF);
Joonwoo Park73375212013-05-07 12:42:44 -0700466 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B3_CTL, v_b1_hu & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700467 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B4_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700468 (v_b1_hu >> 8) & 0xFF);
469 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B5_CTL, v_b1_h & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700470 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B6_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700471 (v_b1_h >> 8) & 0xFF);
472 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B9_CTL, v_brh & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700473 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B10_CTL,
Joonwoo Park73375212013-05-07 12:42:44 -0700474 (v_brh >> 8) & 0xFF);
Joonwoo Parka8890262012-10-15 12:04:27 -0700475 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B11_CTL,
476 mbhc->mbhc_data.v_brl & 0xFF);
477 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_VOLT_B12_CTL,
478 (mbhc->mbhc_data.v_brl >> 8) & 0xFF);
479}
480
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530481static int wcd9xxx_codec_switch_cfilt_mode(struct wcd9xxx_mbhc *mbhc,
Joonwoo Parka8890262012-10-15 12:04:27 -0700482 bool fast)
483{
484 struct snd_soc_codec *codec = mbhc->codec;
485 u8 reg_mode_val, cur_mode_val;
486
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530487 switch (mbhc->mbhc_version) {
488 case WCD9XXX_MBHC_VERSION_TAIKO:
489 if (fast)
490 reg_mode_val = WCD9XXX_CFILT_FAST_MODE;
491 else
492 reg_mode_val = WCD9XXX_CFILT_SLOW_MODE;
Joonwoo Parka8890262012-10-15 12:04:27 -0700493
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530494 cur_mode_val =
495 snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x40;
Joonwoo Parka8890262012-10-15 12:04:27 -0700496
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530497 if (cur_mode_val != reg_mode_val) {
498 if (mbhc->polling_active)
499 wcd9xxx_pause_hs_polling(mbhc);
500 snd_soc_update_bits(codec,
501 mbhc->mbhc_bias_regs.cfilt_ctl,
502 0x40, reg_mode_val);
503 if (mbhc->polling_active)
504 wcd9xxx_start_hs_polling(mbhc);
505 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
506 cur_mode_val, reg_mode_val);
507 } else {
508 pr_debug("%s: CFILT Value is already %x\n",
509 __func__, cur_mode_val);
510 }
511 break;
512 case WCD9XXX_MBHC_VERSION_TAPAN:
513 if (fast)
514 reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
515 else
516 reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
517
518 cur_mode_val =
519 snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x70;
520
521 if (cur_mode_val != reg_mode_val) {
522 if (mbhc->polling_active)
523 wcd9xxx_pause_hs_polling(mbhc);
524 snd_soc_update_bits(codec,
525 mbhc->mbhc_bias_regs.cfilt_ctl,
526 0x70, reg_mode_val);
527 if (mbhc->polling_active)
528 wcd9xxx_start_hs_polling(mbhc);
529 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
530 cur_mode_val, reg_mode_val);
531 } else {
532 pr_debug("%s: CFILT Value is already %x\n",
533 __func__, cur_mode_val);
534 }
535 break;
536 default:
537 return -EINVAL;
Joonwoo Parka8890262012-10-15 12:04:27 -0700538 }
Simmi Pateriya0a44d842013-04-03 01:12:42 +0530539 return 0;
Joonwoo Parka8890262012-10-15 12:04:27 -0700540}
541
Joonwoo Park3699ca32013-02-08 12:06:15 -0800542static void wcd9xxx_jack_report(struct wcd9xxx_mbhc *mbhc,
543 struct snd_soc_jack *jack, int status, int mask)
Joonwoo Parka8890262012-10-15 12:04:27 -0700544{
Joonwoo Parkaf21f032013-03-05 18:07:40 -0800545 if (jack == &mbhc->headset_jack) {
Joonwoo Park3699ca32013-02-08 12:06:15 -0800546 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
547 WCD9XXX_COND_HPH_MIC,
548 status & SND_JACK_MICROPHONE);
Joonwoo Parkaf21f032013-03-05 18:07:40 -0800549 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
550 WCD9XXX_COND_HPH,
551 status & SND_JACK_HEADPHONE);
552 }
Joonwoo Park3699ca32013-02-08 12:06:15 -0800553
Joonwoo Parka8890262012-10-15 12:04:27 -0700554 snd_soc_jack_report_no_dapm(jack, status, mask);
555}
556
557static void __hphocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status,
558 int irq)
559{
560 struct snd_soc_codec *codec;
561
562 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
563 codec = mbhc->codec;
564 if (mbhc->hph_status & jack_status) {
565 mbhc->hph_status &= ~jack_status;
Joonwoo Park3699ca32013-02-08 12:06:15 -0800566 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -0700567 mbhc->hph_status, WCD9XXX_JACK_MASK);
568 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
569 0x00);
570 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
571 0x10);
572 /*
573 * reset retry counter as PA is turned off signifying
574 * start of new OCP detection session
575 */
576 if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
577 mbhc->hphlocp_cnt = 0;
578 else
579 mbhc->hphrocp_cnt = 0;
580 wcd9xxx_enable_irq(codec->control_data, irq);
581 }
582}
583
584static void hphrocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status)
585{
586 __hphocp_off_report(mbhc, SND_JACK_OC_HPHR,
587 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
588}
589
590static void hphlocp_off_report(struct wcd9xxx_mbhc *mbhc, u32 jack_status)
591{
592 __hphocp_off_report(mbhc, SND_JACK_OC_HPHL,
593 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
594}
595
596static void wcd9xxx_get_mbhc_micbias_regs(struct wcd9xxx_mbhc *mbhc,
597 struct mbhc_micbias_regs *micbias_regs)
598{
599 unsigned int cfilt;
600 struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
601
602 switch (mbhc->mbhc_cfg->micbias) {
603 case MBHC_MICBIAS1:
604 cfilt = pdata->micbias.bias1_cfilt_sel;
605 micbias_regs->mbhc_reg = WCD9XXX_A_MICB_1_MBHC;
606 micbias_regs->int_rbias = WCD9XXX_A_MICB_1_INT_RBIAS;
607 micbias_regs->ctl_reg = WCD9XXX_A_MICB_1_CTL;
608 break;
609 case MBHC_MICBIAS2:
610 cfilt = pdata->micbias.bias2_cfilt_sel;
611 micbias_regs->mbhc_reg = WCD9XXX_A_MICB_2_MBHC;
612 micbias_regs->int_rbias = WCD9XXX_A_MICB_2_INT_RBIAS;
613 micbias_regs->ctl_reg = WCD9XXX_A_MICB_2_CTL;
614 break;
615 case MBHC_MICBIAS3:
616 cfilt = pdata->micbias.bias3_cfilt_sel;
617 micbias_regs->mbhc_reg = WCD9XXX_A_MICB_3_MBHC;
618 micbias_regs->int_rbias = WCD9XXX_A_MICB_3_INT_RBIAS;
619 micbias_regs->ctl_reg = WCD9XXX_A_MICB_3_CTL;
620 break;
621 case MBHC_MICBIAS4:
622 cfilt = pdata->micbias.bias4_cfilt_sel;
623 micbias_regs->mbhc_reg = mbhc->resmgr->reg_addr->micb_4_mbhc;
624 micbias_regs->int_rbias =
625 mbhc->resmgr->reg_addr->micb_4_int_rbias;
626 micbias_regs->ctl_reg = mbhc->resmgr->reg_addr->micb_4_ctl;
627 break;
628 default:
629 /* Should never reach here */
630 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
631 return;
632 }
633
634 micbias_regs->cfilt_sel = cfilt;
635
636 switch (cfilt) {
637 case WCD9XXX_CFILT1_SEL:
638 micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_1_VAL;
639 micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_1_CTL;
640 mbhc->mbhc_data.micb_mv =
641 mbhc->resmgr->pdata->micbias.cfilt1_mv;
642 break;
643 case WCD9XXX_CFILT2_SEL:
644 micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_2_VAL;
645 micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_2_CTL;
646 mbhc->mbhc_data.micb_mv =
647 mbhc->resmgr->pdata->micbias.cfilt2_mv;
648 break;
649 case WCD9XXX_CFILT3_SEL:
650 micbias_regs->cfilt_val = WCD9XXX_A_MICB_CFILT_3_VAL;
651 micbias_regs->cfilt_ctl = WCD9XXX_A_MICB_CFILT_3_CTL;
652 mbhc->mbhc_data.micb_mv =
653 mbhc->resmgr->pdata->micbias.cfilt3_mv;
654 break;
655 }
656}
657
658static void wcd9xxx_clr_and_turnon_hph_padac(struct wcd9xxx_mbhc *mbhc)
659{
660 bool pa_turned_on = false;
661 struct snd_soc_codec *codec = mbhc->codec;
662 u8 wg_time;
663
664 wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) ;
665 wg_time += 1;
666
667 if (test_and_clear_bit(WCD9XXX_HPHR_DAC_OFF_ACK,
668 &mbhc->hph_pa_dac_state)) {
669 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
670 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_DAC_CTL,
671 0xC0, 0xC0);
672 }
673 if (test_and_clear_bit(WCD9XXX_HPHL_DAC_OFF_ACK,
674 &mbhc->hph_pa_dac_state)) {
675 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
676 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL,
677 0xC0, 0xC0);
678 }
679
680 if (test_and_clear_bit(WCD9XXX_HPHR_PA_OFF_ACK,
681 &mbhc->hph_pa_dac_state)) {
682 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
683 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x10,
684 1 << 4);
685 pa_turned_on = true;
686 }
687 if (test_and_clear_bit(WCD9XXX_HPHL_PA_OFF_ACK,
688 &mbhc->hph_pa_dac_state)) {
689 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
690 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x20, 1
691 << 5);
692 pa_turned_on = true;
693 }
694
695 if (pa_turned_on) {
696 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
697 __func__);
698 usleep_range(wg_time * 1000, wg_time * 1000);
699 }
700}
701
702static int wcd9xxx_cancel_btn_work(struct wcd9xxx_mbhc *mbhc)
703{
704 int r;
705 r = cancel_delayed_work_sync(&mbhc->mbhc_btn_dwork);
706 if (r)
707 /* if scheduled mbhc.mbhc_btn_dwork is canceled from here,
708 * we have to unlock from here instead btn_work */
709 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
710 return r;
711}
712
713static bool wcd9xxx_is_hph_dac_on(struct snd_soc_codec *codec, int left)
714{
715 u8 hph_reg_val = 0;
716 if (left)
717 hph_reg_val = snd_soc_read(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL);
718 else
719 hph_reg_val = snd_soc_read(codec, WCD9XXX_A_RX_HPH_R_DAC_CTL);
720
721 return (hph_reg_val & 0xC0) ? true : false;
722}
723
724static bool wcd9xxx_is_hph_pa_on(struct snd_soc_codec *codec)
725{
726 u8 hph_reg_val = 0;
727 hph_reg_val = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_EN);
728
729 return (hph_reg_val & 0x30) ? true : false;
730}
731
732/* called under codec_resource_lock acquisition */
733static void wcd9xxx_set_and_turnoff_hph_padac(struct wcd9xxx_mbhc *mbhc)
734{
735 u8 wg_time;
736 struct snd_soc_codec *codec = mbhc->codec;
737
738 wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME);
739 wg_time += 1;
740
741 /* If headphone PA is on, check if userspace receives
742 * removal event to sync-up PA's state */
743 if (wcd9xxx_is_hph_pa_on(codec)) {
744 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
745 set_bit(WCD9XXX_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
746 set_bit(WCD9XXX_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
747 } else {
748 pr_debug("%s PA is off\n", __func__);
749 }
750
751 if (wcd9xxx_is_hph_dac_on(codec, 1))
752 set_bit(WCD9XXX_HPHL_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
753 if (wcd9xxx_is_hph_dac_on(codec, 0))
754 set_bit(WCD9XXX_HPHR_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
755
756 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_CNP_EN, 0x30, 0x00);
Joonwoo Park67c0dbf2013-01-25 10:47:38 -0800757 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_DAC_CTL, 0x80, 0x00);
Joonwoo Parka8890262012-10-15 12:04:27 -0700758 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_DAC_CTL, 0xC0, 0x00);
759 usleep_range(wg_time * 1000, wg_time * 1000);
760}
761
762static void wcd9xxx_insert_detect_setup(struct wcd9xxx_mbhc *mbhc, bool ins)
763{
764 if (!mbhc->mbhc_cfg->insert_detect)
765 return;
766 pr_debug("%s: Setting up %s detection\n", __func__,
767 ins ? "insert" : "removal");
Joonwoo Park2e6bd1e2012-10-18 13:48:55 -0700768 /* Disable detection to avoid glitch */
769 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 0);
Simmi Pateriya2397f5c2013-03-25 12:21:55 +0530770 if (mbhc->mbhc_cfg->gpio_level_insert)
771 snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
772 (0x68 | (ins ? (1 << 1) : 0)));
773 else
774 snd_soc_write(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT,
775 (0x6C | (ins ? (1 << 1) : 0)));
Joonwoo Park2e6bd1e2012-10-18 13:48:55 -0700776 /* Re-enable detection */
777 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MBHC_INSERT_DETECT, 1, 1);
Joonwoo Parka8890262012-10-15 12:04:27 -0700778}
779
780/* called under codec_resource_lock acquisition */
781static void wcd9xxx_report_plug(struct wcd9xxx_mbhc *mbhc, int insertion,
782 enum snd_jack_types jack_type)
783{
784 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
785
Joonwoo Park80a01172012-10-15 16:05:23 -0700786 pr_debug("%s: enter insertion %d hph_status %x\n",
787 __func__, insertion, mbhc->hph_status);
Joonwoo Parka8890262012-10-15 12:04:27 -0700788 if (!insertion) {
789 /* Report removal */
790 mbhc->hph_status &= ~jack_type;
791 /*
792 * cancel possibly scheduled btn work and
793 * report release if we reported button press
794 */
795 if (wcd9xxx_cancel_btn_work(mbhc))
796 pr_debug("%s: button press is canceled\n", __func__);
797 else if (mbhc->buttons_pressed) {
798 pr_debug("%s: release of button press%d\n",
799 __func__, jack_type);
Joonwoo Park3699ca32013-02-08 12:06:15 -0800800 wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
Joonwoo Parka8890262012-10-15 12:04:27 -0700801 mbhc->buttons_pressed);
802 mbhc->buttons_pressed &=
803 ~WCD9XXX_JACK_BUTTON_MASK;
804 }
805 pr_debug("%s: Reporting removal %d(%x)\n", __func__,
806 jack_type, mbhc->hph_status);
Joonwoo Park3699ca32013-02-08 12:06:15 -0800807 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack, mbhc->hph_status,
Joonwoo Parka8890262012-10-15 12:04:27 -0700808 WCD9XXX_JACK_MASK);
809 wcd9xxx_set_and_turnoff_hph_padac(mbhc);
810 hphrocp_off_report(mbhc, SND_JACK_OC_HPHR);
811 hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
812 mbhc->current_plug = PLUG_TYPE_NONE;
813 mbhc->polling_active = false;
814 } else {
Joonwoo Park80a01172012-10-15 16:05:23 -0700815 if (mbhc->mbhc_cfg->detect_extn_cable) {
816 /* Report removal of current jack type */
Joonwoo Park20bc9da2013-01-16 12:58:06 -0800817 if (mbhc->hph_status && mbhc->hph_status != jack_type) {
Joonwoo Park80a01172012-10-15 16:05:23 -0700818 pr_debug("%s: Reporting removal (%x)\n",
819 __func__, mbhc->hph_status);
Joonwoo Park3699ca32013-02-08 12:06:15 -0800820 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Park80a01172012-10-15 16:05:23 -0700821 0, WCD9XXX_JACK_MASK);
822 mbhc->hph_status = 0;
823 }
824 }
Joonwoo Parka8890262012-10-15 12:04:27 -0700825 /* Report insertion */
826 mbhc->hph_status |= jack_type;
827
828 if (jack_type == SND_JACK_HEADPHONE) {
829 mbhc->current_plug = PLUG_TYPE_HEADPHONE;
830 } else if (jack_type == SND_JACK_UNSUPPORTED) {
831 mbhc->current_plug = PLUG_TYPE_GND_MIC_SWAP;
832 } else if (jack_type == SND_JACK_HEADSET) {
833 mbhc->polling_active = BUTTON_POLLING_SUPPORTED;
834 mbhc->current_plug = PLUG_TYPE_HEADSET;
Joonwoo Park80a01172012-10-15 16:05:23 -0700835 } else if (jack_type == SND_JACK_LINEOUT) {
836 mbhc->current_plug = PLUG_TYPE_HIGH_HPH;
Joonwoo Parka8890262012-10-15 12:04:27 -0700837 }
838 pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
839 jack_type, mbhc->hph_status);
Joonwoo Park3699ca32013-02-08 12:06:15 -0800840 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -0700841 mbhc->hph_status, WCD9XXX_JACK_MASK);
842 wcd9xxx_clr_and_turnon_hph_padac(mbhc);
843 }
844 /* Setup insert detect */
845 wcd9xxx_insert_detect_setup(mbhc, !insertion);
Joonwoo Park80a01172012-10-15 16:05:23 -0700846
847 pr_debug("%s: leave hph_status %x\n", __func__, mbhc->hph_status);
Joonwoo Parka8890262012-10-15 12:04:27 -0700848}
849
850/* should be called under interrupt context that hold suspend */
851static void wcd9xxx_schedule_hs_detect_plug(struct wcd9xxx_mbhc *mbhc,
852 struct work_struct *work)
853{
854 pr_debug("%s: scheduling wcd9xxx_correct_swch_plug\n", __func__);
855 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
856 mbhc->hs_detect_work_stop = false;
857 wcd9xxx_lock_sleep(mbhc->resmgr->core);
858 schedule_work(work);
859}
860
861/* called under codec_resource_lock acquisition */
862static void wcd9xxx_cancel_hs_detect_plug(struct wcd9xxx_mbhc *mbhc,
863 struct work_struct *work)
864{
865 pr_debug("%s: Canceling correct_plug_swch\n", __func__);
866 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
867 mbhc->hs_detect_work_stop = true;
868 wmb();
869 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
870 if (cancel_work_sync(work)) {
871 pr_debug("%s: correct_plug_swch is canceled\n",
872 __func__);
873 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
874 }
875 WCD9XXX_BCL_LOCK(mbhc->resmgr);
876}
877
Joonwoo Park73375212013-05-07 12:42:44 -0700878static s16 scale_v_micb_vddio(struct wcd9xxx_mbhc *mbhc, int v, bool tovddio)
879{
880 int r;
881 int vddio_k, mb_k;
882 vddio_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, VDDIO_MICBIAS_MV);
883 mb_k = wcd9xxx_resmgr_get_k_val(mbhc->resmgr, mbhc->mbhc_data.micb_mv);
884 if (tovddio)
885 r = v * vddio_k / mb_k;
886 else
887 r = v * mb_k / vddio_k;
888 return r;
889}
890
Joonwoo Parka8890262012-10-15 12:04:27 -0700891static s16 wcd9xxx_get_current_v_hs_max(struct wcd9xxx_mbhc *mbhc)
892{
893 s16 v_hs_max;
894 struct wcd9xxx_mbhc_plug_type_cfg *plug_type;
895
896 plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
897 if ((mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
898 mbhc->mbhc_micbias_switched)
Joonwoo Park73375212013-05-07 12:42:44 -0700899 v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max, true);
Joonwoo Parka8890262012-10-15 12:04:27 -0700900 else
901 v_hs_max = plug_type->v_hs_max;
902 return v_hs_max;
903}
904
Joonwoo Parka8890262012-10-15 12:04:27 -0700905static short wcd9xxx_read_sta_result(struct snd_soc_codec *codec)
906{
907 u8 bias_msb, bias_lsb;
908 short bias_value;
909
910 bias_msb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B3_STATUS);
911 bias_lsb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B2_STATUS);
912 bias_value = (bias_msb << 8) | bias_lsb;
913 return bias_value;
914}
915
916static short wcd9xxx_read_dce_result(struct snd_soc_codec *codec)
917{
918 u8 bias_msb, bias_lsb;
919 short bias_value;
920
921 bias_msb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B5_STATUS);
922 bias_lsb = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B4_STATUS);
923 bias_value = (bias_msb << 8) | bias_lsb;
924 return bias_value;
925}
926
927static void wcd9xxx_turn_onoff_rel_detection(struct snd_soc_codec *codec,
928 bool on)
929{
930 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
931}
932
933static short __wcd9xxx_codec_sta_dce(struct wcd9xxx_mbhc *mbhc, int dce,
934 bool override_bypass, bool noreldetection)
935{
936 short bias_value;
937 struct snd_soc_codec *codec = mbhc->codec;
938
939 wcd9xxx_disable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
940 if (noreldetection)
941 wcd9xxx_turn_onoff_rel_detection(codec, false);
942
943 /* Turn on the override */
944 if (!override_bypass)
945 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
946 if (dce) {
947 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
948 0x8);
949 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
950 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
951 0x0);
952 usleep_range(mbhc->mbhc_data.t_sta_dce,
953 mbhc->mbhc_data.t_sta_dce);
954 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x4);
955 usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce);
956 bias_value = wcd9xxx_read_dce_result(codec);
957 } else {
958 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
959 0x8);
960 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
961 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
962 0x0);
963 usleep_range(mbhc->mbhc_data.t_sta_dce,
964 mbhc->mbhc_data.t_sta_dce);
965 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
966 usleep_range(mbhc->mbhc_data.t_sta,
967 mbhc->mbhc_data.t_sta);
968 bias_value = wcd9xxx_read_sta_result(codec);
969 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8,
970 0x8);
971 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x0);
972 }
973 /* Turn off the override after measuring mic voltage */
974 if (!override_bypass)
975 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04,
976 0x00);
977
978 if (noreldetection)
979 wcd9xxx_turn_onoff_rel_detection(codec, true);
980 wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_POTENTIAL);
981
982 return bias_value;
983}
984
985static short wcd9xxx_codec_sta_dce(struct wcd9xxx_mbhc *mbhc, int dce,
986 bool norel)
987{
988 return __wcd9xxx_codec_sta_dce(mbhc, dce, false, norel);
989}
990
991static s32 wcd9xxx_codec_sta_dce_v(struct wcd9xxx_mbhc *mbhc, s8 dce,
992 u16 bias_value)
993{
994 s16 value, z, mb;
995 s32 mv;
996
997 value = bias_value;
998 if (dce) {
999 z = (mbhc->mbhc_data.dce_z);
1000 mb = (mbhc->mbhc_data.dce_mb);
1001 mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
1002 } else {
1003 z = (mbhc->mbhc_data.sta_z);
1004 mb = (mbhc->mbhc_data.sta_mb);
1005 mv = (value - z) * (s32)mbhc->mbhc_data.micb_mv / (mb - z);
1006 }
1007
1008 return mv;
1009}
1010
1011/* called only from interrupt which is under codec_resource_lock acquisition */
1012static short wcd9xxx_mbhc_setup_hs_polling(struct wcd9xxx_mbhc *mbhc)
1013{
1014 struct snd_soc_codec *codec = mbhc->codec;
1015 short bias_value;
1016 u8 cfilt_mode;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301017 int ret;
Joonwoo Parka8890262012-10-15 12:04:27 -07001018
1019 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1020
1021 pr_debug("%s: enter\n", __func__);
1022 if (!mbhc->mbhc_cfg->calibration) {
1023 pr_err("%s: Error, no calibration exists\n", __func__);
1024 return -ENODEV;
1025 }
1026
1027 /*
1028 * Request BG and clock.
1029 * These will be released by wcd9xxx_cleanup_hs_polling
1030 */
1031 wcd9xxx_resmgr_get_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
1032 wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
1033
1034 snd_soc_update_bits(codec, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x01);
1035
1036 /* Make sure CFILT is in fast mode, save current mode */
1037 cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301038 ret = wcd9xxx_put_cfilt_fast_mode(codec, mbhc);
1039 if (ret)
1040 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07001041 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05301042 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301043 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
1044 if (ret)
1045 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07001046
1047 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x80, 0x80);
1048 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x1F, 0x1C);
1049 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
1050
1051 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0x80, 0x00);
1052 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1053 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
1054
1055 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
1056 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1057
1058 wcd9xxx_calibrate_hs_polling(mbhc);
1059
1060 /* don't flip override */
1061 bias_value = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301062 snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
Joonwoo Parka8890262012-10-15 12:04:27 -07001063 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
1064
1065 return bias_value;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301066
1067gen_err:
1068 pr_err("%s: Error returned, ret: %d\n", __func__, ret);
1069 return ret;
Joonwoo Parka8890262012-10-15 12:04:27 -07001070}
1071
1072static void wcd9xxx_shutdown_hs_removal_detect(struct wcd9xxx_mbhc *mbhc)
1073{
1074 struct snd_soc_codec *codec = mbhc->codec;
1075 const struct wcd9xxx_mbhc_general_cfg *generic =
1076 WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
1077
1078 /* Need MBHC clock */
1079 wcd9xxx_resmgr_get_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
1080
1081 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
1082 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
1083 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1084
1085 usleep_range(generic->t_shutdown_plug_rem,
1086 generic->t_shutdown_plug_rem);
1087
1088 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
1089
1090 /* Put requested CLK back */
1091 wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
1092
1093 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x00);
1094}
1095
1096static void wcd9xxx_cleanup_hs_polling(struct wcd9xxx_mbhc *mbhc)
1097{
1098 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1099
1100 wcd9xxx_shutdown_hs_removal_detect(mbhc);
1101
1102 /* Release clock and BG requested by wcd9xxx_mbhc_setup_hs_polling */
1103 wcd9xxx_resmgr_put_clk_block(mbhc->resmgr, WCD9XXX_CLK_RCO);
1104 wcd9xxx_resmgr_put_bandgap(mbhc->resmgr, WCD9XXX_BANDGAP_MBHC_MODE);
1105
1106 mbhc->polling_active = false;
1107 mbhc->mbhc_state = MBHC_STATE_NONE;
1108}
1109
Joonwoo Parka8890262012-10-15 12:04:27 -07001110/* called under codec_resource_lock acquisition */
1111static void wcd9xxx_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
1112{
1113 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01, on);
1114 if (on)
1115 usleep_range(5000, 5000);
1116}
1117
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -07001118static void wcd9xxx_onoff_vddio_switch(struct wcd9xxx_mbhc *mbhc, bool on)
1119{
1120 if (on) {
1121 snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
1122 1 << 7, 1 << 7);
1123 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
1124 1 << 4, 0);
1125 } else {
1126 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_MAD_ANA_CTRL,
1127 1 << 4, 1 << 4);
1128 snd_soc_update_bits(mbhc->codec, mbhc->mbhc_bias_regs.mbhc_reg,
1129 1 << 7, 0);
1130 }
1131 if (on)
1132 usleep_range(10000, 10000);
1133}
1134
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001135static int wcd9xxx_hphl_status(struct wcd9xxx_mbhc *mbhc)
1136{
1137 u16 hph, status;
1138 struct snd_soc_codec *codec = mbhc->codec;
1139
1140 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1141 hph = snd_soc_read(codec, WCD9XXX_A_MBHC_HPH);
1142 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x12, 0x02);
1143 usleep_range(WCD9XXX_HPHL_STATUS_READY_WAIT_US,
1144 WCD9XXX_HPHL_STATUS_READY_WAIT_US +
1145 WCD9XXX_USLEEP_RANGE_MARGIN_US);
1146 status = snd_soc_read(codec, WCD9XXX_A_RX_HPH_L_STATUS);
1147 snd_soc_write(codec, WCD9XXX_A_MBHC_HPH, hph);
1148 return status;
1149}
1150
1151/*
1152 * wcd9xxx_find_plug_type : Find out and return the best plug type with given
1153 * list of wcd9xxx_mbhc_detect structure.
1154 */
1155static enum wcd9xxx_mbhc_plug_type
1156wcd9xxx_find_plug_type(struct wcd9xxx_mbhc *mbhc,
1157 struct wcd9xxx_mbhc_detect *dt, const int size)
1158{
1159 int i;
1160 int ch;
1161 enum wcd9xxx_mbhc_plug_type type;
1162 int vdce;
1163 struct wcd9xxx_mbhc_detect *d, *dprev, *dgnd = NULL;
1164 int maxv = 0, minv = 0;
1165 const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
1166 WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
1167 const s16 hs_max = plug_type->v_hs_max;
1168 const s16 no_mic = plug_type->v_no_mic;
1169
1170 for (i = 0, d = dt, ch = 0; i < size; i++, d++) {
1171 vdce = wcd9xxx_codec_sta_dce_v(mbhc, true, d->dce);
1172 if (d->vddio)
1173 d->_vdces = scale_v_micb_vddio(mbhc, vdce, false);
1174 else
1175 d->_vdces = vdce;
1176
1177 if (d->_vdces >= no_mic && d->_vdces < hs_max)
1178 d->_type = PLUG_TYPE_HEADSET;
1179 else if (d->_vdces < no_mic)
1180 d->_type = PLUG_TYPE_HEADPHONE;
1181 else
1182 d->_type = PLUG_TYPE_HIGH_HPH;
1183
1184 ch += d->hphl_status & 0x01;
1185 if (!d->swap_gnd && !d->hwvalue) {
1186 if (maxv < d->_vdces)
1187 maxv = d->_vdces;
1188 if (!minv || minv > d->_vdces)
1189 minv = d->_vdces;
1190 }
1191
1192 pr_debug("%s: DCE #%d, %04x, V %04d(%04d), GND %d, VDDIO %d, HPHL %d TYPE %d\n",
1193 __func__, i, d->dce, vdce, d->_vdces,
1194 d->swap_gnd, d->vddio, d->hphl_status & 0x01,
1195 d->_type);
Joonwoo Park141d6182013-03-05 12:25:46 -08001196
1197
1198 /*
1199 * If GND and MIC prongs are aligned to HPHR and GND of
1200 * headphone, codec measures the voltage based on
1201 * impedance between HPHR and GND which results in ~80mv.
1202 * Avoid this.
1203 */
1204 if (d->_vdces >= WCD9XXX_MEAS_INVALD_RANGE_LOW_MV &&
1205 d->_vdces <= WCD9XXX_MEAS_INVALD_RANGE_HIGH_MV) {
1206 pr_debug("%s: within invalid range\n", __func__);
1207 type = PLUG_TYPE_INVALID;
1208 goto exit;
1209 }
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001210 }
1211 if (ch != size && ch > 0) {
1212 pr_debug("%s: Invalid, inconsistent HPHL\n", __func__);
1213 type = PLUG_TYPE_INVALID;
1214 goto exit;
1215 }
1216
Phani Kumar Uppalapatiec818fe2013-03-13 15:39:03 -07001217 for (i = 0, d = dt; i < size; i++, d++) {
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001218 if ((i > 0) && (d->_type != dprev->_type)) {
1219 pr_debug("%s: Invalid, inconsistent types\n", __func__);
1220 type = PLUG_TYPE_INVALID;
1221 goto exit;
1222 }
1223
1224 if (!d->swap_gnd && !d->hwvalue &&
1225 (abs(minv - d->_vdces) > WCD9XXX_MEAS_DELTA_MAX_MV ||
1226 abs(maxv - d->_vdces) > WCD9XXX_MEAS_DELTA_MAX_MV)) {
1227 pr_debug("%s: Invalid, delta %dmv, %dmv and %dmv\n",
1228 __func__, d->_vdces, minv, maxv);
1229 type = PLUG_TYPE_INVALID;
1230 goto exit;
1231 } else if (d->swap_gnd) {
1232 dgnd = d;
1233 }
1234 dprev = d;
1235 }
1236
1237 WARN_ON(i != size);
1238 type = dt->_type;
1239 if (type == PLUG_TYPE_HEADSET && dgnd) {
1240 if ((dgnd->_vdces + WCD9XXX_GM_SWAP_THRES_MIN_MV <
1241 minv) &&
1242 (dgnd->_vdces + WCD9XXX_GM_SWAP_THRES_MAX_MV >
1243 maxv))
1244 type = PLUG_TYPE_GND_MIC_SWAP;
1245 }
Phani Kumar Uppalapatiec818fe2013-03-13 15:39:03 -07001246 if (((type == PLUG_TYPE_HEADSET || type == PLUG_TYPE_HEADPHONE) &&
1247 ch != size) || (type == PLUG_TYPE_GND_MIC_SWAP && ch)) {
1248 pr_debug("%s: Invalid, not fully inserted, TYPE %d\n",
1249 __func__, type);
1250 type = PLUG_TYPE_INVALID;
1251 }
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001252exit:
1253 pr_debug("%s: Plug type %d detected\n", __func__, type);
1254 return type;
1255}
1256
Joonwoo Parka8890262012-10-15 12:04:27 -07001257static enum wcd9xxx_mbhc_plug_type
1258wcd9xxx_codec_get_plug_type(struct wcd9xxx_mbhc *mbhc, bool highhph)
1259{
1260 int i;
Joonwoo Parka8890262012-10-15 12:04:27 -07001261 struct wcd9xxx_mbhc_plug_type_cfg *plug_type_ptr;
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001262 struct wcd9xxx_mbhc_detect rt[NUM_DCE_PLUG_INS_DETECT];
1263 enum wcd9xxx_mbhc_plug_type type = PLUG_TYPE_INVALID;
Joonwoo Parka8890262012-10-15 12:04:27 -07001264 struct snd_soc_codec *codec = mbhc->codec;
Joonwoo Parka8890262012-10-15 12:04:27 -07001265
Joonwoo Park80a01172012-10-15 16:05:23 -07001266 pr_debug("%s: enter\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001267 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1268
1269 /* make sure override is on */
1270 WARN_ON(!(snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x04));
1271
1272 /* GND and MIC swap detection requires at least 2 rounds of DCE */
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001273 BUG_ON(NUM_DCE_PLUG_INS_DETECT < 2);
Joonwoo Parka8890262012-10-15 12:04:27 -07001274
1275 plug_type_ptr =
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001276 WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
Joonwoo Parka8890262012-10-15 12:04:27 -07001277
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001278 rt[0].hphl_status = wcd9xxx_hphl_status(mbhc);
1279 rt[0].dce = wcd9xxx_mbhc_setup_hs_polling(mbhc);
1280 rt[0].swap_gnd = false;
1281 rt[0].vddio = false;
1282 rt[0].hwvalue = true;
1283 for (i = 1; i < NUM_DCE_PLUG_INS_DETECT; i++) {
1284 rt[i].swap_gnd = (i == NUM_DCE_PLUG_INS_DETECT - 2);
1285 if (detect_use_vddio_switch)
1286 rt[i].vddio = (i == NUM_DCE_PLUG_INS_DETECT - 1);
1287 else
1288 rt[i].vddio = false;
1289 rt[i].hphl_status = wcd9xxx_hphl_status(mbhc);
1290 rt[i].hwvalue = false;
1291 if (rt[i].swap_gnd)
1292 wcd9xxx_codec_hphr_gnd_switch(codec, true);
1293 if (rt[i].vddio)
1294 wcd9xxx_onoff_vddio_switch(mbhc, true);
1295 rt[i].dce = __wcd9xxx_codec_sta_dce(mbhc, 1, true, true);
1296 if (rt[i].vddio)
1297 wcd9xxx_onoff_vddio_switch(mbhc, false);
1298 if (rt[i].swap_gnd)
1299 wcd9xxx_codec_hphr_gnd_switch(codec, false);
Joonwoo Parka8890262012-10-15 12:04:27 -07001300 }
1301
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001302 type = wcd9xxx_find_plug_type(mbhc, rt, ARRAY_SIZE(rt));
Joonwoo Parka8890262012-10-15 12:04:27 -07001303
Joonwoo Park80a01172012-10-15 16:05:23 -07001304 pr_debug("%s: leave\n", __func__);
Joonwoo Park20bc9da2013-01-16 12:58:06 -08001305 return type;
Joonwoo Parka8890262012-10-15 12:04:27 -07001306}
1307
1308static bool wcd9xxx_swch_level_remove(struct wcd9xxx_mbhc *mbhc)
1309{
1310 if (mbhc->mbhc_cfg->gpio)
1311 return (gpio_get_value_cansleep(mbhc->mbhc_cfg->gpio) !=
1312 mbhc->mbhc_cfg->gpio_level_insert);
1313 else if (mbhc->mbhc_cfg->insert_detect)
1314 return snd_soc_read(mbhc->codec,
1315 WCD9XXX_A_MBHC_INSERT_DET_STATUS) &
1316 (1 << 2);
1317 else
1318 WARN(1, "Invalid jack detection configuration\n");
1319
1320 return true;
1321}
1322
1323static bool is_clk_active(struct snd_soc_codec *codec)
1324{
1325 return !!(snd_soc_read(codec, WCD9XXX_A_CDC_CLK_MCLK_CTL) & 0x05);
1326}
1327
1328static int wcd9xxx_enable_hs_detect(struct wcd9xxx_mbhc *mbhc,
1329 int insertion, int trigger, bool padac_off)
1330{
1331 struct snd_soc_codec *codec = mbhc->codec;
1332 int central_bias_enabled = 0;
1333 const struct wcd9xxx_mbhc_general_cfg *generic =
1334 WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
1335 const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
1336 WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
1337
Joonwoo Park80a01172012-10-15 16:05:23 -07001338 pr_debug("%s: enter insertion(%d) trigger(0x%x)\n",
1339 __func__, insertion, trigger);
1340
Joonwoo Parka8890262012-10-15 12:04:27 -07001341 if (!mbhc->mbhc_cfg->calibration) {
1342 pr_err("Error, no wcd9xxx calibration\n");
1343 return -EINVAL;
1344 }
1345
1346 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0);
1347
1348 /*
1349 * Make sure mic bias and Mic line schmitt trigger
1350 * are turned OFF
1351 */
1352 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
1353 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
1354
1355 if (insertion) {
1356 wcd9xxx_switch_micbias(mbhc, 0);
1357
1358 /* DAPM can manipulate PA/DAC bits concurrently */
1359 if (padac_off == true)
1360 wcd9xxx_set_and_turnoff_hph_padac(mbhc);
1361
1362 if (trigger & MBHC_USE_HPHL_TRIGGER) {
1363 /* Enable HPH Schmitt Trigger */
1364 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x11,
1365 0x11);
1366 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x0C,
1367 plug_det->hph_current << 2);
1368 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x02,
1369 0x02);
1370 }
1371 if (trigger & MBHC_USE_MB_TRIGGER) {
1372 /* enable the mic line schmitt trigger */
1373 snd_soc_update_bits(codec,
1374 mbhc->mbhc_bias_regs.mbhc_reg,
1375 0x60, plug_det->mic_current << 5);
1376 snd_soc_update_bits(codec,
1377 mbhc->mbhc_bias_regs.mbhc_reg,
1378 0x80, 0x80);
1379 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
1380 snd_soc_update_bits(codec,
1381 mbhc->mbhc_bias_regs.ctl_reg, 0x01,
1382 0x00);
1383 snd_soc_update_bits(codec,
1384 mbhc->mbhc_bias_regs.mbhc_reg,
1385 0x10, 0x10);
1386 }
1387
1388 /* setup for insetion detection */
1389 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x2, 0);
1390 } else {
1391 pr_debug("setup for removal detection\n");
1392 /* Make sure the HPH schmitt trigger is OFF */
1393 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x12, 0x00);
1394
1395 /* enable the mic line schmitt trigger */
1396 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg,
1397 0x01, 0x00);
1398 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x60,
1399 plug_det->mic_current << 5);
1400 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
1401 0x80, 0x80);
1402 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
1403 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg,
1404 0x10, 0x10);
1405
1406 /* Setup for low power removal detection */
1407 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x2,
1408 0x2);
1409 }
1410
1411 if (snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_CTL) & 0x4) {
1412 /* called by interrupt */
1413 if (!is_clk_active(codec)) {
1414 wcd9xxx_resmgr_enable_config_mode(codec, 1);
1415 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
1416 0x06, 0);
1417 usleep_range(generic->t_shutdown_plug_rem,
1418 generic->t_shutdown_plug_rem);
1419 wcd9xxx_resmgr_enable_config_mode(codec, 0);
1420 } else
1421 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
1422 0x06, 0);
1423 }
1424
1425 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.int_rbias, 0x80, 0);
1426
1427 /* If central bandgap disabled */
1428 if (!(snd_soc_read(codec, WCD9XXX_A_PIN_CTL_OE1) & 1)) {
1429 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE1, 0x3, 0x3);
1430 usleep_range(generic->t_bg_fast_settle,
1431 generic->t_bg_fast_settle);
1432 central_bias_enabled = 1;
1433 }
1434
1435 /* If LDO_H disabled */
1436 if (snd_soc_read(codec, WCD9XXX_A_PIN_CTL_OE0) & 0x80) {
1437 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE0, 0x10, 0);
1438 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE0, 0x80, 0x80);
1439 usleep_range(generic->t_ldoh, generic->t_ldoh);
1440 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE0, 0x80, 0);
1441
1442 if (central_bias_enabled)
1443 snd_soc_update_bits(codec, WCD9XXX_A_PIN_CTL_OE1, 0x1,
1444 0);
1445 }
1446
Simmi Pateriya0a44d842013-04-03 01:12:42 +05301447 if (mbhc->resmgr->reg_addr->micb_4_mbhc)
1448 snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
1449 0x3, mbhc->mbhc_cfg->micbias);
Joonwoo Parka8890262012-10-15 12:04:27 -07001450
1451 wcd9xxx_enable_irq(mbhc->resmgr->core, WCD9XXX_IRQ_MBHC_INSERTION);
1452 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
Joonwoo Park80a01172012-10-15 16:05:23 -07001453 pr_debug("%s: leave\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001454
1455 return 0;
1456}
1457
1458/* called under codec_resource_lock acquisition */
1459static void wcd9xxx_find_plug_and_report(struct wcd9xxx_mbhc *mbhc,
1460 enum wcd9xxx_mbhc_plug_type plug_type)
1461{
Joonwoo Park80a01172012-10-15 16:05:23 -07001462 pr_debug("%s: enter current_plug(%d) new_plug(%d)\n",
1463 __func__, mbhc->current_plug, plug_type);
1464
Joonwoo Parka8890262012-10-15 12:04:27 -07001465 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1466
1467 if (plug_type == PLUG_TYPE_HEADPHONE &&
1468 mbhc->current_plug == PLUG_TYPE_NONE) {
1469 /*
1470 * Nothing was reported previously
1471 * report a headphone or unsupported
1472 */
1473 wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
1474 wcd9xxx_cleanup_hs_polling(mbhc);
1475 } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
Joonwoo Park80a01172012-10-15 16:05:23 -07001476 if (!mbhc->mbhc_cfg->detect_extn_cable) {
1477 if (mbhc->current_plug == PLUG_TYPE_HEADSET)
1478 wcd9xxx_report_plug(mbhc, 0,
1479 SND_JACK_HEADSET);
1480 else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE)
1481 wcd9xxx_report_plug(mbhc, 0,
1482 SND_JACK_HEADPHONE);
1483 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001484 wcd9xxx_report_plug(mbhc, 1, SND_JACK_UNSUPPORTED);
1485 wcd9xxx_cleanup_hs_polling(mbhc);
1486 } else if (plug_type == PLUG_TYPE_HEADSET) {
1487 /*
1488 * If Headphone was reported previously, this will
1489 * only report the mic line
1490 */
1491 wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADSET);
1492 msleep(100);
1493 wcd9xxx_start_hs_polling(mbhc);
1494 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
Joonwoo Park80a01172012-10-15 16:05:23 -07001495 if (mbhc->mbhc_cfg->detect_extn_cable) {
1496 /* High impedance device found. Report as LINEOUT*/
1497 wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
1498 wcd9xxx_cleanup_hs_polling(mbhc);
1499 pr_debug("%s: setup mic trigger for further detection\n",
1500 __func__);
1501 mbhc->lpi_enabled = true;
1502 /*
1503 * Do not enable HPHL trigger. If playback is active,
1504 * it might lead to continuous false HPHL triggers
1505 */
1506 wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER,
1507 false);
1508 } else {
1509 if (mbhc->current_plug == PLUG_TYPE_NONE)
1510 wcd9xxx_report_plug(mbhc, 1,
1511 SND_JACK_HEADPHONE);
1512 wcd9xxx_cleanup_hs_polling(mbhc);
1513 pr_debug("setup mic trigger for further detection\n");
1514 mbhc->lpi_enabled = true;
1515 wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER |
1516 MBHC_USE_HPHL_TRIGGER,
1517 false);
1518 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001519 } else {
1520 WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
1521 mbhc->current_plug, plug_type);
1522 }
Joonwoo Park80a01172012-10-15 16:05:23 -07001523 pr_debug("%s: leave\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001524}
1525
1526/* called under codec_resource_lock acquisition */
1527static void wcd9xxx_mbhc_decide_swch_plug(struct wcd9xxx_mbhc *mbhc)
1528{
1529 enum wcd9xxx_mbhc_plug_type plug_type;
1530 struct snd_soc_codec *codec = mbhc->codec;
1531
1532 pr_debug("%s: enter\n", __func__);
1533
1534 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1535
1536 wcd9xxx_turn_onoff_override(codec, true);
1537 plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
1538 wcd9xxx_turn_onoff_override(codec, false);
1539
1540 if (wcd9xxx_swch_level_remove(mbhc)) {
1541 pr_debug("%s: Switch level is low when determining plug\n",
1542 __func__);
1543 return;
1544 }
1545
1546 if (plug_type == PLUG_TYPE_INVALID ||
1547 plug_type == PLUG_TYPE_GND_MIC_SWAP) {
1548 wcd9xxx_schedule_hs_detect_plug(mbhc,
1549 &mbhc->correct_plug_swch);
1550 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
1551 wcd9xxx_report_plug(mbhc, 1, SND_JACK_HEADPHONE);
1552 wcd9xxx_schedule_hs_detect_plug(mbhc,
1553 &mbhc->correct_plug_swch);
1554 } else {
1555 pr_debug("%s: Valid plug found, determine plug type %d\n",
1556 __func__, plug_type);
1557 wcd9xxx_find_plug_and_report(mbhc, plug_type);
1558 }
Joonwoo Park80a01172012-10-15 16:05:23 -07001559 pr_debug("%s: leave\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001560}
1561
1562/* called under codec_resource_lock acquisition */
1563static void wcd9xxx_mbhc_detect_plug_type(struct wcd9xxx_mbhc *mbhc)
1564{
1565 struct snd_soc_codec *codec = mbhc->codec;
1566 const struct wcd9xxx_mbhc_plug_detect_cfg *plug_det =
1567 WCD9XXX_MBHC_CAL_PLUG_DET_PTR(mbhc->mbhc_cfg->calibration);
1568
Joonwoo Park80a01172012-10-15 16:05:23 -07001569 pr_debug("%s: enter\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001570 WCD9XXX_BCL_ASSERT_LOCKED(mbhc->resmgr);
1571
1572 /*
1573 * Turn on the override,
1574 * wcd9xxx_mbhc_setup_hs_polling requires override on
1575 */
1576 wcd9xxx_turn_onoff_override(codec, true);
1577 if (plug_det->t_ins_complete > 20)
1578 msleep(plug_det->t_ins_complete);
1579 else
1580 usleep_range(plug_det->t_ins_complete * 1000,
1581 plug_det->t_ins_complete * 1000);
1582 /* Turn off the override */
1583 wcd9xxx_turn_onoff_override(codec, false);
1584
1585 if (wcd9xxx_swch_level_remove(mbhc))
1586 pr_debug("%s: Switch level low when determining plug\n",
1587 __func__);
1588 else
1589 wcd9xxx_mbhc_decide_swch_plug(mbhc);
Joonwoo Park80a01172012-10-15 16:05:23 -07001590 pr_debug("%s: leave\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001591}
1592
1593/* called only from interrupt which is under codec_resource_lock acquisition */
1594static void wcd9xxx_hs_insert_irq_swch(struct wcd9xxx_mbhc *mbhc,
1595 bool is_removal)
1596{
1597 if (!is_removal) {
1598 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
1599
1600 rmb();
1601 if (mbhc->lpi_enabled)
1602 msleep(100);
1603
1604 rmb();
1605 if (!mbhc->lpi_enabled) {
1606 pr_debug("%s: lpi is disabled\n", __func__);
1607 } else if (!wcd9xxx_swch_level_remove(mbhc)) {
1608 pr_debug("%s: Valid insertion, detect plug type\n",
1609 __func__);
1610 wcd9xxx_mbhc_decide_swch_plug(mbhc);
1611 } else {
1612 pr_debug("%s: Invalid insertion stop plug detection\n",
1613 __func__);
1614 }
Joonwoo Park80a01172012-10-15 16:05:23 -07001615 } else if (mbhc->mbhc_cfg->detect_extn_cable) {
1616 pr_debug("%s: Removal\n", __func__);
1617 if (!wcd9xxx_swch_level_remove(mbhc)) {
1618 /*
1619 * Switch indicates, something is still inserted.
1620 * This could be extension cable i.e. headset is
1621 * removed from extension cable.
1622 */
1623 /* cancel detect plug */
1624 wcd9xxx_cancel_hs_detect_plug(mbhc,
1625 &mbhc->correct_plug_swch);
1626 wcd9xxx_mbhc_decide_swch_plug(mbhc);
1627 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001628 } else {
1629 pr_err("%s: Switch IRQ used, invalid MBHC Removal\n", __func__);
1630 }
1631}
1632
1633static bool is_valid_mic_voltage(struct wcd9xxx_mbhc *mbhc, s32 mic_mv)
1634{
1635 const struct wcd9xxx_mbhc_plug_type_cfg *plug_type =
1636 WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
1637 const s16 v_hs_max = wcd9xxx_get_current_v_hs_max(mbhc);
1638
1639 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
1640 && (mic_mv < v_hs_max)) ? true : false;
1641}
1642
1643/*
1644 * called under codec_resource_lock acquisition
1645 * returns true if mic voltage range is back to normal insertion
1646 * returns false either if timedout or removed
1647 */
1648static bool wcd9xxx_hs_remove_settle(struct wcd9xxx_mbhc *mbhc)
1649{
1650 int i;
1651 bool timedout, settled = false;
1652 s32 mic_mv[NUM_DCE_PLUG_DETECT];
1653 short mb_v[NUM_DCE_PLUG_DETECT];
1654 unsigned long retry = 0, timeout;
1655
1656 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
1657 while (!(timedout = time_after(jiffies, timeout))) {
1658 retry++;
1659 if (wcd9xxx_swch_level_remove(mbhc)) {
1660 pr_debug("%s: Switch indicates removal\n", __func__);
1661 break;
1662 }
1663
1664 if (retry > 1)
1665 msleep(250);
1666 else
1667 msleep(50);
1668
1669 if (wcd9xxx_swch_level_remove(mbhc)) {
1670 pr_debug("%s: Switch indicates removal\n", __func__);
1671 break;
1672 }
1673
1674 for (i = 0; i < NUM_DCE_PLUG_DETECT; i++) {
1675 mb_v[i] = wcd9xxx_codec_sta_dce(mbhc, 1, true);
1676 mic_mv[i] = wcd9xxx_codec_sta_dce_v(mbhc, 1 , mb_v[i]);
1677 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
1678 __func__, retry, mic_mv[i], mb_v[i]);
1679 }
1680
1681 if (wcd9xxx_swch_level_remove(mbhc)) {
1682 pr_debug("%s: Switcn indicates removal\n", __func__);
1683 break;
1684 }
1685
1686 if (mbhc->current_plug == PLUG_TYPE_NONE) {
1687 pr_debug("%s : headset/headphone is removed\n",
1688 __func__);
1689 break;
1690 }
1691
1692 for (i = 0; i < NUM_DCE_PLUG_DETECT; i++)
1693 if (!is_valid_mic_voltage(mbhc, mic_mv[i]))
1694 break;
1695
1696 if (i == NUM_DCE_PLUG_DETECT) {
1697 pr_debug("%s: MIC voltage settled\n", __func__);
1698 settled = true;
1699 msleep(200);
1700 break;
1701 }
1702 }
1703
1704 if (timedout)
1705 pr_debug("%s: Microphone did not settle in %d seconds\n",
1706 __func__, HS_DETECT_PLUG_TIME_MS);
1707 return settled;
1708}
1709
1710/* called only from interrupt which is under codec_resource_lock acquisition */
1711static void wcd9xxx_hs_remove_irq_swch(struct wcd9xxx_mbhc *mbhc)
1712{
Joonwoo Park80a01172012-10-15 16:05:23 -07001713 pr_debug("%s: enter\n", __func__);
Joonwoo Parka8890262012-10-15 12:04:27 -07001714 if (wcd9xxx_hs_remove_settle(mbhc))
1715 wcd9xxx_start_hs_polling(mbhc);
Joonwoo Park80a01172012-10-15 16:05:23 -07001716 pr_debug("%s: leave\n", __func__);
1717}
1718
1719/* called only from interrupt which is under codec_resource_lock acquisition */
1720static void wcd9xxx_hs_remove_irq_noswch(struct wcd9xxx_mbhc *mbhc)
1721{
1722 short bias_value;
1723 bool removed = true;
1724 struct snd_soc_codec *codec = mbhc->codec;
1725 const struct wcd9xxx_mbhc_general_cfg *generic =
1726 WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
1727 int min_us = FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
1728
1729 pr_debug("%s: enter\n", __func__);
1730 if (mbhc->current_plug != PLUG_TYPE_HEADSET) {
1731 pr_debug("%s(): Headset is not inserted, ignore removal\n",
1732 __func__);
1733 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
1734 0x08, 0x08);
1735 return;
1736 }
1737
1738 usleep_range(generic->t_shutdown_plug_rem,
1739 generic->t_shutdown_plug_rem);
1740
1741 do {
1742 bias_value = wcd9xxx_codec_sta_dce(mbhc, 1, true);
1743 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
1744 wcd9xxx_codec_sta_dce_v(mbhc, 1, bias_value), min_us);
Joonwoo Park73375212013-05-07 12:42:44 -07001745 if (bias_value <
1746 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H)) {
Joonwoo Park80a01172012-10-15 16:05:23 -07001747 pr_debug("%s: checking false removal\n", __func__);
1748 msleep(500);
1749 removed = !wcd9xxx_hs_remove_settle(mbhc);
1750 pr_debug("%s: headset %sactually removed\n", __func__,
1751 removed ? "" : "not ");
1752 break;
1753 }
1754 min_us -= mbhc->mbhc_data.t_dce;
1755 } while (min_us > 0);
1756
1757 if (removed) {
1758 if (mbhc->mbhc_cfg->detect_extn_cable) {
1759 if (!wcd9xxx_swch_level_remove(mbhc)) {
1760 /*
1761 * extension cable is still plugged in
1762 * report it as LINEOUT device
1763 */
1764 wcd9xxx_report_plug(mbhc, 1, SND_JACK_LINEOUT);
1765 wcd9xxx_cleanup_hs_polling(mbhc);
1766 wcd9xxx_enable_hs_detect(mbhc, 1,
1767 MBHC_USE_MB_TRIGGER,
1768 false);
1769 }
1770 } else {
1771 /* Cancel possibly running hs_detect_work */
1772 wcd9xxx_cancel_hs_detect_plug(mbhc,
1773 &mbhc->correct_plug_noswch);
1774 /*
1775 * If this removal is not false, first check the micbias
1776 * switch status and switch it to LDOH if it is already
1777 * switched to VDDIO.
1778 */
1779 wcd9xxx_switch_micbias(mbhc, 0);
1780
1781 wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
1782 wcd9xxx_cleanup_hs_polling(mbhc);
1783 wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_MB_TRIGGER |
1784 MBHC_USE_HPHL_TRIGGER,
1785 true);
1786 }
1787 } else {
1788 wcd9xxx_start_hs_polling(mbhc);
1789 }
1790 pr_debug("%s: leave\n", __func__);
1791}
1792
1793/* called only from interrupt which is under codec_resource_lock acquisition */
1794static void wcd9xxx_hs_insert_irq_extn(struct wcd9xxx_mbhc *mbhc,
1795 bool is_mb_trigger)
1796{
1797 /* Cancel possibly running hs_detect_work */
1798 wcd9xxx_cancel_hs_detect_plug(mbhc, &mbhc->correct_plug_swch);
1799
1800 if (is_mb_trigger) {
1801 pr_debug("%s: Waiting for Headphone left trigger\n", __func__);
1802 wcd9xxx_enable_hs_detect(mbhc, 1, MBHC_USE_HPHL_TRIGGER, false);
1803 } else {
1804 pr_debug("%s: HPHL trigger received, detecting plug type\n",
1805 __func__);
1806 wcd9xxx_mbhc_detect_plug_type(mbhc);
1807 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001808}
1809
1810static irqreturn_t wcd9xxx_hs_remove_irq(int irq, void *data)
1811{
1812 bool vddio;
1813 struct wcd9xxx_mbhc *mbhc = data;
1814
1815 pr_debug("%s: enter, removal interrupt\n", __func__);
1816 WCD9XXX_BCL_LOCK(mbhc->resmgr);
Joonwoo Park3699ca32013-02-08 12:06:15 -08001817 /*
1818 * While we don't know whether MIC is there or not, let the resmgr know
1819 * so micbias can be disabled temporarily
1820 */
Joonwoo Parkaf21f032013-03-05 18:07:40 -08001821 if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
Joonwoo Park3699ca32013-02-08 12:06:15 -08001822 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1823 WCD9XXX_COND_HPH_MIC, false);
Joonwoo Parkaf21f032013-03-05 18:07:40 -08001824 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1825 WCD9XXX_COND_HPH, false);
1826 } else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
1827 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1828 WCD9XXX_COND_HPH, false);
1829 }
Joonwoo Park3699ca32013-02-08 12:06:15 -08001830
Joonwoo Parka8890262012-10-15 12:04:27 -07001831 vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
1832 mbhc->mbhc_micbias_switched);
1833 if (vddio)
Joonwoo Park91226742013-01-22 15:26:27 -08001834 __wcd9xxx_switch_micbias(mbhc, 0, false, true);
Joonwoo Parka8890262012-10-15 12:04:27 -07001835
Joonwoo Park80a01172012-10-15 16:05:23 -07001836 if (mbhc->mbhc_cfg->detect_extn_cable &&
1837 !wcd9xxx_swch_level_remove(mbhc))
1838 wcd9xxx_hs_remove_irq_noswch(mbhc);
1839 else
1840 wcd9xxx_hs_remove_irq_swch(mbhc);
Joonwoo Parka8890262012-10-15 12:04:27 -07001841
1842 /*
1843 * if driver turned off vddio switch and headset is not removed,
1844 * turn on the vddio switch back, if headset is removed then vddio
1845 * switch is off by time now and shouldn't be turn on again from here
1846 */
Joonwoo Park91226742013-01-22 15:26:27 -08001847 if (vddio && (mbhc->current_plug == PLUG_TYPE_HEADSET))
1848 __wcd9xxx_switch_micbias(mbhc, 1, true, true);
Joonwoo Park3699ca32013-02-08 12:06:15 -08001849
Joonwoo Parkaf21f032013-03-05 18:07:40 -08001850 if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
1851 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1852 WCD9XXX_COND_HPH, true);
Joonwoo Park3699ca32013-02-08 12:06:15 -08001853 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1854 WCD9XXX_COND_HPH_MIC, true);
Joonwoo Parkaf21f032013-03-05 18:07:40 -08001855 } else if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
1856 wcd9xxx_resmgr_cond_update_cond(mbhc->resmgr,
1857 WCD9XXX_COND_HPH, true);
1858 }
Joonwoo Parka8890262012-10-15 12:04:27 -07001859 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
1860
1861 return IRQ_HANDLED;
1862}
1863
1864static irqreturn_t wcd9xxx_hs_insert_irq(int irq, void *data)
1865{
1866 bool is_mb_trigger, is_removal;
1867 struct wcd9xxx_mbhc *mbhc = data;
1868 struct snd_soc_codec *codec = mbhc->codec;
1869
1870 pr_debug("%s: enter\n", __func__);
1871 WCD9XXX_BCL_LOCK(mbhc->resmgr);
1872 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
1873
1874 is_mb_trigger = !!(snd_soc_read(codec, mbhc->mbhc_bias_regs.mbhc_reg) &
1875 0x10);
1876 is_removal = !!(snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_INT_CTL) & 0x02);
1877 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
1878
1879 /* Turn off both HPH and MIC line schmitt triggers */
1880 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
1881 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
1882 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
1883
Joonwoo Park80a01172012-10-15 16:05:23 -07001884 if (mbhc->mbhc_cfg->detect_extn_cable &&
1885 mbhc->current_plug == PLUG_TYPE_HIGH_HPH)
1886 wcd9xxx_hs_insert_irq_extn(mbhc, is_mb_trigger);
1887 else
1888 wcd9xxx_hs_insert_irq_swch(mbhc, is_removal);
Joonwoo Parka8890262012-10-15 12:04:27 -07001889
1890 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
1891 return IRQ_HANDLED;
1892}
1893
1894static void wcd9xxx_btn_lpress_fn(struct work_struct *work)
1895{
1896 struct delayed_work *dwork;
1897 short bias_value;
1898 int dce_mv, sta_mv;
1899 struct wcd9xxx_mbhc *mbhc;
1900
1901 pr_debug("%s:\n", __func__);
1902
1903 dwork = to_delayed_work(work);
1904 mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_btn_dwork);
1905
1906 bias_value = wcd9xxx_read_sta_result(mbhc->codec);
1907 sta_mv = wcd9xxx_codec_sta_dce_v(mbhc, 0, bias_value);
1908
1909 bias_value = wcd9xxx_read_dce_result(mbhc->codec);
1910 dce_mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, bias_value);
1911 pr_debug("%s: STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
1912
1913 pr_debug("%s: Reporting long button press event\n", __func__);
Joonwoo Park3699ca32013-02-08 12:06:15 -08001914 wcd9xxx_jack_report(mbhc, &mbhc->button_jack, mbhc->buttons_pressed,
Joonwoo Parka8890262012-10-15 12:04:27 -07001915 mbhc->buttons_pressed);
1916
1917 pr_debug("%s: leave\n", __func__);
1918 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
1919}
1920
1921static void wcd9xxx_mbhc_insert_work(struct work_struct *work)
1922{
1923 struct delayed_work *dwork;
1924 struct wcd9xxx_mbhc *mbhc;
1925 struct snd_soc_codec *codec;
1926 struct wcd9xxx *core;
1927
1928 dwork = to_delayed_work(work);
1929 mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_insert_dwork);
1930 codec = mbhc->codec;
1931 core = mbhc->resmgr->core;
1932
1933 pr_debug("%s:\n", __func__);
1934
1935 /* Turn off both HPH and MIC line schmitt triggers */
1936 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
1937 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x13, 0x00);
1938 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
1939 wcd9xxx_disable_irq_sync(core, WCD9XXX_IRQ_MBHC_INSERTION);
1940 wcd9xxx_mbhc_detect_plug_type(mbhc);
1941 wcd9xxx_unlock_sleep(core);
1942}
1943
1944static bool wcd9xxx_mbhc_fw_validate(const struct firmware *fw)
1945{
1946 u32 cfg_offset;
1947 struct wcd9xxx_mbhc_imped_detect_cfg *imped_cfg;
1948 struct wcd9xxx_mbhc_btn_detect_cfg *btn_cfg;
1949
1950 if (fw->size < WCD9XXX_MBHC_CAL_MIN_SIZE)
1951 return false;
1952
1953 /*
1954 * Previous check guarantees that there is enough fw data up
1955 * to num_btn
1956 */
1957 btn_cfg = WCD9XXX_MBHC_CAL_BTN_DET_PTR(fw->data);
1958 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
1959 if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_BTN_SZ(btn_cfg)))
1960 return false;
1961
1962 /*
1963 * Previous check guarantees that there is enough fw data up
1964 * to start of impedance detection configuration
1965 */
1966 imped_cfg = WCD9XXX_MBHC_CAL_IMPED_DET_PTR(fw->data);
1967 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
1968
1969 if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_MIN_SZ))
1970 return false;
1971
1972 if (fw->size < (cfg_offset + WCD9XXX_MBHC_CAL_IMPED_SZ(imped_cfg)))
1973 return false;
1974
1975 return true;
1976}
1977
1978static u16 wcd9xxx_codec_v_sta_dce(struct wcd9xxx_mbhc *mbhc,
1979 enum meas_type dce, s16 vin_mv)
1980{
1981 s16 diff, zero;
1982 u32 mb_mv, in;
1983 u16 value;
1984
1985 mb_mv = mbhc->mbhc_data.micb_mv;
1986
1987 if (mb_mv == 0) {
1988 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
1989 return -EINVAL;
1990 }
1991
1992 if (dce) {
1993 diff = (mbhc->mbhc_data.dce_mb) - (mbhc->mbhc_data.dce_z);
1994 zero = (mbhc->mbhc_data.dce_z);
1995 } else {
1996 diff = (mbhc->mbhc_data.sta_mb) - (mbhc->mbhc_data.sta_z);
1997 zero = (mbhc->mbhc_data.sta_z);
1998 }
1999 in = (u32) diff * vin_mv;
2000
2001 value = (u16) (in / mb_mv) + zero;
2002 return value;
2003}
2004
2005static void wcd9xxx_mbhc_calc_thres(struct wcd9xxx_mbhc *mbhc)
2006{
2007 struct snd_soc_codec *codec;
Joonwoo Park73375212013-05-07 12:42:44 -07002008 s16 adj_v_hs_max;
2009 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 -07002010 struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
2011 struct wcd9xxx_mbhc_plug_type_cfg *plug_type;
2012 u16 *btn_high;
2013 int i;
2014
2015 pr_debug("%s: enter\n", __func__);
2016 codec = mbhc->codec;
2017 btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
2018 plug_type = WCD9XXX_MBHC_CAL_PLUG_TYPE_PTR(mbhc->mbhc_cfg->calibration);
2019
Joonwoo Park73375212013-05-07 12:42:44 -07002020 mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_CFILT] =
Joonwoo Parka8890262012-10-15 12:04:27 -07002021 wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_hs_max);
Joonwoo Park73375212013-05-07 12:42:44 -07002022 mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_CFILT] =
Joonwoo Parka8890262012-10-15 12:04:27 -07002023 wcd9xxx_codec_v_sta_dce(mbhc, DCE, plug_type->v_hs_max);
2024
2025 mbhc->mbhc_data.v_inval_ins_low = FAKE_INS_LOW;
2026 mbhc->mbhc_data.v_inval_ins_high = FAKE_INS_HIGH;
2027
2028 if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
Joonwoo Park73375212013-05-07 12:42:44 -07002029 adj_v_hs_max = scale_v_micb_vddio(mbhc, plug_type->v_hs_max,
2030 true);
2031 mbhc->mbhc_data.v_ins_hu[MBHC_V_IDX_VDDIO] =
2032 wcd9xxx_codec_v_sta_dce(mbhc, STA, adj_v_hs_max);
2033 mbhc->mbhc_data.v_ins_h[MBHC_V_IDX_VDDIO] =
2034 wcd9xxx_codec_v_sta_dce(mbhc, DCE, adj_v_hs_max);
Joonwoo Parka8890262012-10-15 12:04:27 -07002035 mbhc->mbhc_data.v_inval_ins_low =
2036 scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_low,
2037 false);
2038 mbhc->mbhc_data.v_inval_ins_high =
2039 scale_v_micb_vddio(mbhc, mbhc->mbhc_data.v_inval_ins_high,
2040 false);
2041 }
2042
2043 btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
2044 MBHC_BTN_DET_V_BTN_HIGH);
2045 for (i = 0; i < btn_det->num_btn; i++)
2046 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
2047
Joonwoo Park73375212013-05-07 12:42:44 -07002048 btn_mv_sta[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_sta;
2049 btn_mv_dce[MBHC_V_IDX_CFILT] = btn_mv + btn_det->v_btn_press_delta_cic;
2050 btn_mv_sta[MBHC_V_IDX_VDDIO] =
2051 scale_v_micb_vddio(mbhc, btn_mv_sta[MBHC_V_IDX_CFILT], true);
2052 btn_mv_dce[MBHC_V_IDX_VDDIO] =
2053 scale_v_micb_vddio(mbhc, btn_mv_dce[MBHC_V_IDX_CFILT], true);
Joonwoo Parka8890262012-10-15 12:04:27 -07002054
Joonwoo Park73375212013-05-07 12:42:44 -07002055 mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_CFILT] =
2056 wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_CFILT]);
2057 mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT] =
2058 wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_CFILT]);
2059 mbhc->mbhc_data.v_b1_hu[MBHC_V_IDX_VDDIO] =
2060 wcd9xxx_codec_v_sta_dce(mbhc, STA, btn_mv_sta[MBHC_V_IDX_VDDIO]);
2061 mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO] =
2062 wcd9xxx_codec_v_sta_dce(mbhc, DCE, btn_mv_dce[MBHC_V_IDX_VDDIO]);
Joonwoo Parka8890262012-10-15 12:04:27 -07002063
Joonwoo Park73375212013-05-07 12:42:44 -07002064 mbhc->mbhc_data.v_brh[MBHC_V_IDX_CFILT] =
2065 mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_CFILT];
2066 mbhc->mbhc_data.v_brh[MBHC_V_IDX_VDDIO] =
2067 mbhc->mbhc_data.v_b1_h[MBHC_V_IDX_VDDIO];
Joonwoo Parka8890262012-10-15 12:04:27 -07002068
Joonwoo Parka8890262012-10-15 12:04:27 -07002069 mbhc->mbhc_data.v_brl = BUTTON_MIN;
2070
2071 mbhc->mbhc_data.v_no_mic =
2072 wcd9xxx_codec_v_sta_dce(mbhc, STA, plug_type->v_no_mic);
2073 pr_debug("%s: leave\n", __func__);
2074}
2075
2076static void wcd9xxx_onoff_ext_mclk(struct wcd9xxx_mbhc *mbhc, bool on)
2077{
2078 /*
2079 * XXX: {codec}_mclk_enable holds WCD9XXX_BCL_LOCK,
2080 * therefore wcd9xxx_onoff_ext_mclk caller SHOULDN'T hold
2081 * WCD9XXX_BCL_LOCK when it calls wcd9xxx_onoff_ext_mclk()
2082 */
2083 mbhc->mbhc_cfg->mclk_cb_fn(mbhc->codec, on, false);
2084}
2085
2086static void wcd9xxx_correct_swch_plug(struct work_struct *work)
2087{
2088 struct wcd9xxx_mbhc *mbhc;
2089 struct snd_soc_codec *codec;
Joonwoo Park80a01172012-10-15 16:05:23 -07002090 enum wcd9xxx_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
Joonwoo Parka8890262012-10-15 12:04:27 -07002091 unsigned long timeout;
2092 int retry = 0, pt_gnd_mic_swap_cnt = 0;
2093 bool correction = false;
2094
2095 pr_debug("%s: enter\n", __func__);
2096
2097 mbhc = container_of(work, struct wcd9xxx_mbhc, correct_plug_swch);
2098 codec = mbhc->codec;
2099
2100 wcd9xxx_onoff_ext_mclk(mbhc, true);
2101
2102 /*
2103 * Keep override on during entire plug type correction work.
2104 *
2105 * This is okay under the assumption that any switch irqs which use
2106 * MBHC block cancel and sync this work so override is off again
2107 * prior to switch interrupt handler's MBHC block usage.
2108 * Also while this correction work is running, we can guarantee
2109 * DAPM doesn't use any MBHC block as this work only runs with
2110 * headphone detection.
2111 */
2112 wcd9xxx_turn_onoff_override(codec, true);
2113
2114 timeout = jiffies + msecs_to_jiffies(HS_DETECT_PLUG_TIME_MS);
2115 while (!time_after(jiffies, timeout)) {
2116 ++retry;
2117 rmb();
2118 if (mbhc->hs_detect_work_stop) {
2119 pr_debug("%s: stop requested\n", __func__);
2120 break;
2121 }
2122
2123 msleep(HS_DETECT_PLUG_INERVAL_MS);
2124 if (wcd9xxx_swch_level_remove(mbhc)) {
2125 pr_debug("%s: Switch level is low\n", __func__);
2126 break;
2127 }
2128
2129 /* can race with removal interrupt */
2130 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2131 plug_type = wcd9xxx_codec_get_plug_type(mbhc, true);
2132 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2133
Joonwoo Park80a01172012-10-15 16:05:23 -07002134 pr_debug("%s: attempt(%d) current_plug(%d) new_plug(%d)\n",
2135 __func__, retry, mbhc->current_plug, plug_type);
Joonwoo Parka8890262012-10-15 12:04:27 -07002136 if (plug_type == PLUG_TYPE_INVALID) {
2137 pr_debug("Invalid plug in attempt # %d\n", retry);
Joonwoo Park80a01172012-10-15 16:05:23 -07002138 if (!mbhc->mbhc_cfg->detect_extn_cable &&
2139 retry == NUM_ATTEMPTS_TO_REPORT &&
Joonwoo Parka8890262012-10-15 12:04:27 -07002140 mbhc->current_plug == PLUG_TYPE_NONE) {
2141 wcd9xxx_report_plug(mbhc, 1,
2142 SND_JACK_HEADPHONE);
2143 }
2144 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
2145 pr_debug("Good headphone detected, continue polling\n");
Joonwoo Park80a01172012-10-15 16:05:23 -07002146 if (mbhc->mbhc_cfg->detect_extn_cable) {
2147 if (mbhc->current_plug != plug_type)
2148 wcd9xxx_report_plug(mbhc, 1,
2149 SND_JACK_HEADPHONE);
2150 } else if (mbhc->current_plug == PLUG_TYPE_NONE) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002151 wcd9xxx_report_plug(mbhc, 1,
2152 SND_JACK_HEADPHONE);
Joonwoo Park80a01172012-10-15 16:05:23 -07002153 }
Joonwoo Parka8890262012-10-15 12:04:27 -07002154 } else {
2155 if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
2156 pt_gnd_mic_swap_cnt++;
2157 if (pt_gnd_mic_swap_cnt <
2158 GND_MIC_SWAP_THRESHOLD)
2159 continue;
2160 else if (pt_gnd_mic_swap_cnt >
2161 GND_MIC_SWAP_THRESHOLD) {
2162 /*
2163 * This is due to GND/MIC switch didn't
2164 * work, Report unsupported plug
2165 */
2166 } else if (mbhc->mbhc_cfg->swap_gnd_mic) {
2167 /*
2168 * if switch is toggled, check again,
2169 * otherwise report unsupported plug
2170 */
2171 if (mbhc->mbhc_cfg->swap_gnd_mic(codec))
2172 continue;
2173 }
2174 } else
2175 pt_gnd_mic_swap_cnt = 0;
2176
2177 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2178 /* Turn off override */
2179 wcd9xxx_turn_onoff_override(codec, false);
2180 /*
2181 * The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
2182 */
2183 wcd9xxx_find_plug_and_report(mbhc, plug_type);
2184 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2185 pr_debug("Attempt %d found correct plug %d\n", retry,
2186 plug_type);
2187 correction = true;
2188 break;
2189 }
2190 }
2191
2192 /* Turn off override */
2193 if (!correction)
2194 wcd9xxx_turn_onoff_override(codec, false);
2195
2196 wcd9xxx_onoff_ext_mclk(mbhc, false);
Joonwoo Park80a01172012-10-15 16:05:23 -07002197
2198 if (mbhc->mbhc_cfg->detect_extn_cable) {
2199 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2200 if (mbhc->current_plug == PLUG_TYPE_HEADPHONE ||
2201 mbhc->current_plug == PLUG_TYPE_GND_MIC_SWAP ||
2202 mbhc->current_plug == PLUG_TYPE_INVALID ||
2203 plug_type == PLUG_TYPE_INVALID) {
2204 /* Enable removal detection */
2205 wcd9xxx_cleanup_hs_polling(mbhc);
2206 wcd9xxx_enable_hs_detect(mbhc, 0, 0, false);
2207 }
2208 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2209 }
2210 pr_debug("%s: leave current_plug(%d)\n", __func__, mbhc->current_plug);
Joonwoo Parka8890262012-10-15 12:04:27 -07002211 /* unlock sleep */
2212 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
2213}
2214
2215static void wcd9xxx_swch_irq_handler(struct wcd9xxx_mbhc *mbhc)
2216{
2217 bool insert;
2218 bool is_removed = false;
2219 struct snd_soc_codec *codec = mbhc->codec;
2220
2221 pr_debug("%s: enter\n", __func__);
2222
2223 mbhc->in_swch_irq_handler = true;
2224 /* Wait here for debounce time */
2225 usleep_range(SWCH_IRQ_DEBOUNCE_TIME_US, SWCH_IRQ_DEBOUNCE_TIME_US);
2226
2227 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2228
2229 /* cancel pending button press */
2230 if (wcd9xxx_cancel_btn_work(mbhc))
2231 pr_debug("%s: button press is canceled\n", __func__);
2232
2233 insert = !wcd9xxx_swch_level_remove(mbhc);
2234 pr_debug("%s: Current plug type %d, insert %d\n", __func__,
2235 mbhc->current_plug, insert);
2236 if ((mbhc->current_plug == PLUG_TYPE_NONE) && insert) {
2237 mbhc->lpi_enabled = false;
2238 wmb();
2239
2240 /* cancel detect plug */
2241 wcd9xxx_cancel_hs_detect_plug(mbhc,
2242 &mbhc->correct_plug_swch);
2243
2244 /* Disable Mic Bias pull down and HPH Switch to GND */
2245 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01,
2246 0x00);
2247 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01, 0x00);
2248 wcd9xxx_mbhc_detect_plug_type(mbhc);
2249 } else if ((mbhc->current_plug != PLUG_TYPE_NONE) && !insert) {
2250 mbhc->lpi_enabled = false;
2251 wmb();
2252
2253 /* cancel detect plug */
2254 wcd9xxx_cancel_hs_detect_plug(mbhc,
2255 &mbhc->correct_plug_swch);
2256
2257 if (mbhc->current_plug == PLUG_TYPE_HEADPHONE) {
2258 wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADPHONE);
2259 is_removed = true;
2260 } else if (mbhc->current_plug == PLUG_TYPE_GND_MIC_SWAP) {
2261 wcd9xxx_report_plug(mbhc, 0, SND_JACK_UNSUPPORTED);
2262 is_removed = true;
2263 } else if (mbhc->current_plug == PLUG_TYPE_HEADSET) {
2264 wcd9xxx_pause_hs_polling(mbhc);
2265 wcd9xxx_cleanup_hs_polling(mbhc);
2266 wcd9xxx_report_plug(mbhc, 0, SND_JACK_HEADSET);
2267 is_removed = true;
Joonwoo Park80a01172012-10-15 16:05:23 -07002268 } else if (mbhc->current_plug == PLUG_TYPE_HIGH_HPH) {
2269 wcd9xxx_report_plug(mbhc, 0, SND_JACK_LINEOUT);
2270 is_removed = true;
Joonwoo Parka8890262012-10-15 12:04:27 -07002271 }
2272
2273 if (is_removed) {
2274 /* Enable Mic Bias pull down and HPH Switch to GND */
2275 snd_soc_update_bits(codec,
2276 mbhc->mbhc_bias_regs.ctl_reg, 0x01,
2277 0x01);
2278 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01,
2279 0x01);
2280 /* Make sure mic trigger is turned off */
2281 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg,
2282 0x01, 0x01);
2283 snd_soc_update_bits(codec,
2284 mbhc->mbhc_bias_regs.mbhc_reg,
2285 0x90, 0x00);
2286 /* Reset MBHC State Machine */
2287 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
2288 0x08, 0x08);
2289 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
2290 0x08, 0x00);
2291 /* Turn off override */
2292 wcd9xxx_turn_onoff_override(codec, false);
2293 }
2294 }
2295
2296 mbhc->in_swch_irq_handler = false;
2297 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2298 pr_debug("%s: leave\n", __func__);
2299}
2300
2301static irqreturn_t wcd9xxx_mech_plug_detect_irq(int irq, void *data)
2302{
2303 int r = IRQ_HANDLED;
2304 struct wcd9xxx_mbhc *mbhc = data;
2305
2306 pr_debug("%s: enter\n", __func__);
2307 if (unlikely(wcd9xxx_lock_sleep(mbhc->resmgr->core) == false)) {
2308 pr_warn("%s: failed to hold suspend\n", __func__);
2309 r = IRQ_NONE;
2310 } else {
2311 /* Call handler */
2312 wcd9xxx_swch_irq_handler(mbhc);
2313 wcd9xxx_unlock_sleep(mbhc->resmgr->core);
2314 }
2315
2316 pr_debug("%s: leave %d\n", __func__, r);
2317 return r;
2318}
2319
2320/* called under codec_resource_lock acquisition */
2321static void wcd9xxx_codec_drive_v_to_micbias(struct wcd9xxx_mbhc *mbhc,
2322 int usec)
2323{
2324 int cfilt_k_val;
2325 bool set = true;
2326
2327 if (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2328 mbhc->mbhc_micbias_switched) {
2329 pr_debug("%s: set mic V to micbias V\n", __func__);
2330 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_CDC_MBHC_CLK_CTL,
2331 0x2, 0x2);
2332 wcd9xxx_turn_onoff_override(mbhc->codec, true);
2333 while (1) {
2334 cfilt_k_val =
2335 wcd9xxx_resmgr_get_k_val(mbhc->resmgr,
2336 set ? mbhc->mbhc_data.micb_mv :
2337 VDDIO_MICBIAS_MV);
2338 snd_soc_update_bits(mbhc->codec,
2339 mbhc->mbhc_bias_regs.cfilt_val,
2340 0xFC, (cfilt_k_val << 2));
2341 if (!set)
2342 break;
2343 usleep_range(usec, usec);
2344 set = false;
2345 }
2346 wcd9xxx_turn_onoff_override(mbhc->codec, false);
2347 }
2348}
2349
2350static int wcd9xxx_is_fake_press(struct wcd9xxx_mbhc *mbhc)
2351{
2352 int i;
Joonwoo Park73375212013-05-07 12:42:44 -07002353 s16 mb_v;
Joonwoo Parka8890262012-10-15 12:04:27 -07002354 int r = 0;
2355 const int dces = NUM_DCE_PLUG_DETECT;
Joonwoo Park73375212013-05-07 12:42:44 -07002356 const s16 v_ins_hu =
2357 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
2358 const s16 v_ins_h =
2359 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
2360 const s16 v_b1_hu =
2361 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
2362 const s16 v_b1_h =
2363 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
Joonwoo Parka8890262012-10-15 12:04:27 -07002364
2365 for (i = 0; i < dces; i++) {
2366 usleep_range(10000, 10000);
2367 if (i == 0) {
2368 mb_v = wcd9xxx_codec_sta_dce(mbhc, 0, true);
2369 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
2370 wcd9xxx_codec_sta_dce_v(mbhc, 0, mb_v));
Joonwoo Park73375212013-05-07 12:42:44 -07002371 if (mb_v < v_b1_hu || mb_v > v_ins_hu) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002372 r = 1;
2373 break;
2374 }
2375 } else {
2376 mb_v = wcd9xxx_codec_sta_dce(mbhc, 1, true);
2377 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
2378 wcd9xxx_codec_sta_dce_v(mbhc, 1, mb_v));
Joonwoo Park73375212013-05-07 12:42:44 -07002379 if (mb_v < v_b1_h || mb_v > v_ins_h) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002380 r = 1;
2381 break;
2382 }
2383 }
2384 }
2385
2386 return r;
2387}
2388
2389/* called under codec_resource_lock acquisition */
2390static int wcd9xxx_determine_button(const struct wcd9xxx_mbhc *mbhc,
2391 const s32 micmv)
2392{
2393 s16 *v_btn_low, *v_btn_high;
2394 struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
2395 int i, btn = -1;
2396
2397 btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
2398 v_btn_low = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
2399 MBHC_BTN_DET_V_BTN_LOW);
2400 v_btn_high = wcd9xxx_mbhc_cal_btn_det_mp(btn_det,
2401 MBHC_BTN_DET_V_BTN_HIGH);
2402
2403 for (i = 0; i < btn_det->num_btn; i++) {
2404 if ((v_btn_low[i] <= micmv) && (v_btn_high[i] >= micmv)) {
2405 btn = i;
2406 break;
2407 }
2408 }
2409
2410 if (btn == -1)
2411 pr_debug("%s: couldn't find button number for mic mv %d\n",
2412 __func__, micmv);
2413
2414 return btn;
2415}
2416
2417static int wcd9xxx_get_button_mask(const int btn)
2418{
2419 int mask = 0;
2420 switch (btn) {
2421 case 0:
2422 mask = SND_JACK_BTN_0;
2423 break;
2424 case 1:
2425 mask = SND_JACK_BTN_1;
2426 break;
2427 case 2:
2428 mask = SND_JACK_BTN_2;
2429 break;
2430 case 3:
2431 mask = SND_JACK_BTN_3;
2432 break;
2433 case 4:
2434 mask = SND_JACK_BTN_4;
2435 break;
2436 case 5:
2437 mask = SND_JACK_BTN_5;
2438 break;
2439 case 6:
2440 mask = SND_JACK_BTN_6;
2441 break;
2442 case 7:
2443 mask = SND_JACK_BTN_7;
2444 break;
2445 }
2446 return mask;
2447}
2448
2449irqreturn_t wcd9xxx_dce_handler(int irq, void *data)
2450{
2451 int i, mask;
2452 short dce, sta;
2453 s32 mv, mv_s, stamv_s;
2454 bool vddio;
2455 u8 mbhc_status;
2456 int btn = -1, meas = 0;
2457 struct wcd9xxx_mbhc *mbhc = data;
2458 const struct wcd9xxx_mbhc_btn_detect_cfg *d =
2459 WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
2460 short btnmeas[d->n_btn_meas + 1];
2461 struct snd_soc_codec *codec = mbhc->codec;
2462 struct wcd9xxx *core = mbhc->resmgr->core;
2463 int n_btn_meas = d->n_btn_meas;
2464
2465 pr_debug("%s: enter\n", __func__);
2466
2467 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2468 mbhc_status = snd_soc_read(codec, WCD9XXX_A_CDC_MBHC_B1_STATUS) & 0x3E;
2469
2470 if (mbhc->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
2471 pr_debug("%s: mbhc is being recovered, skip button press\n",
2472 __func__);
2473 goto done;
2474 }
2475
2476 mbhc->mbhc_state = MBHC_STATE_POTENTIAL;
2477
2478 if (!mbhc->polling_active) {
2479 pr_warn("%s: mbhc polling is not active, skip button press\n",
2480 __func__);
2481 goto done;
2482 }
2483
2484 dce = wcd9xxx_read_dce_result(codec);
2485 mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, dce);
2486
2487 /* If switch nterrupt already kicked in, ignore button press */
2488 if (mbhc->in_swch_irq_handler) {
2489 pr_debug("%s: Swtich level changed, ignore button press\n",
2490 __func__);
2491 btn = -1;
2492 goto done;
2493 }
2494
2495 /* Measure scaled HW DCE */
2496 vddio = (mbhc->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2497 mbhc->mbhc_micbias_switched);
2498 mv_s = vddio ? scale_v_micb_vddio(mbhc, mv, false) : mv;
2499
2500 /* Measure scaled HW STA */
2501 sta = wcd9xxx_read_sta_result(codec);
2502 stamv_s = wcd9xxx_codec_sta_dce_v(mbhc, 0, sta);
2503 if (vddio)
2504 stamv_s = scale_v_micb_vddio(mbhc, stamv_s, false);
2505 if (mbhc_status != STATUS_REL_DETECTION) {
2506 if (mbhc->mbhc_last_resume &&
2507 !time_after(jiffies, mbhc->mbhc_last_resume + HZ)) {
2508 pr_debug("%s: Button is released after resume\n",
2509 __func__);
2510 n_btn_meas = 0;
2511 } else {
2512 pr_debug("%s: Button is released without resume",
2513 __func__);
2514 btn = wcd9xxx_determine_button(mbhc, mv_s);
2515 if (btn != wcd9xxx_determine_button(mbhc, stamv_s))
2516 btn = -1;
2517 goto done;
2518 }
2519 }
2520
2521 pr_debug("%s: Meas HW - STA 0x%x,%d,%d\n", __func__,
2522 sta & 0xFFFF, wcd9xxx_codec_sta_dce_v(mbhc, 0, sta), stamv_s);
2523
2524 /* determine pressed button */
2525 btnmeas[meas++] = wcd9xxx_determine_button(mbhc, mv_s);
2526 pr_debug("%s: Meas HW - DCE 0x%x,%d,%d button %d\n", __func__,
2527 dce & 0xFFFF, mv, mv_s, btnmeas[meas - 1]);
2528 if (n_btn_meas == 0)
2529 btn = btnmeas[0];
2530 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
2531 dce = wcd9xxx_codec_sta_dce(mbhc, 1, false);
2532 mv = wcd9xxx_codec_sta_dce_v(mbhc, 1, dce);
2533 mv_s = vddio ? scale_v_micb_vddio(mbhc, mv, false) : mv;
2534
2535 btnmeas[meas] = wcd9xxx_determine_button(mbhc, mv_s);
2536 pr_debug("%s: Meas %d - DCE 0x%x,%d,%d button %d\n",
2537 __func__, meas, dce & 0xFFFF, mv, mv_s, btnmeas[meas]);
2538 /*
2539 * if large enough measurements are collected,
2540 * start to check if last all n_btn_con measurements were
2541 * in same button low/high range
2542 */
2543 if (meas + 1 >= d->n_btn_con) {
2544 for (i = 0; i < d->n_btn_con; i++)
2545 if ((btnmeas[meas] < 0) ||
2546 (btnmeas[meas] != btnmeas[meas - i]))
2547 break;
2548 if (i == d->n_btn_con) {
2549 /* button pressed */
2550 btn = btnmeas[meas];
2551 break;
2552 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
2553 /*
2554 * if left measurements are less than n_btn_con,
2555 * it's impossible to find button number
2556 */
2557 break;
2558 }
2559 }
2560 }
2561
2562 if (btn >= 0) {
2563 if (mbhc->in_swch_irq_handler) {
2564 pr_debug(
2565 "%s: Switch irq triggered, ignore button press\n",
2566 __func__);
2567 goto done;
2568 }
2569 mask = wcd9xxx_get_button_mask(btn);
2570 mbhc->buttons_pressed |= mask;
2571 wcd9xxx_lock_sleep(core);
2572 if (schedule_delayed_work(&mbhc->mbhc_btn_dwork,
2573 msecs_to_jiffies(400)) == 0) {
2574 WARN(1, "Button pressed twice without release event\n");
2575 wcd9xxx_unlock_sleep(core);
2576 }
2577 } else {
2578 pr_debug("%s: bogus button press, too short press?\n",
2579 __func__);
2580 }
2581
2582 done:
2583 pr_debug("%s: leave\n", __func__);
2584 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2585 return IRQ_HANDLED;
2586}
2587
2588static irqreturn_t wcd9xxx_release_handler(int irq, void *data)
2589{
2590 int ret;
2591 struct wcd9xxx_mbhc *mbhc = data;
2592
2593 pr_debug("%s: enter\n", __func__);
2594 WCD9XXX_BCL_LOCK(mbhc->resmgr);
2595 mbhc->mbhc_state = MBHC_STATE_RELEASE;
2596
2597 wcd9xxx_codec_drive_v_to_micbias(mbhc, 10000);
2598
2599 if (mbhc->buttons_pressed & WCD9XXX_JACK_BUTTON_MASK) {
2600 ret = wcd9xxx_cancel_btn_work(mbhc);
2601 if (ret == 0) {
2602 pr_debug("%s: Reporting long button release event\n",
2603 __func__);
Joonwoo Park3699ca32013-02-08 12:06:15 -08002604 wcd9xxx_jack_report(mbhc, &mbhc->button_jack, 0,
Joonwoo Parka8890262012-10-15 12:04:27 -07002605 mbhc->buttons_pressed);
2606 } else {
2607 if (wcd9xxx_is_fake_press(mbhc)) {
2608 pr_debug("%s: Fake button press interrupt\n",
2609 __func__);
2610 } else {
2611 if (mbhc->in_swch_irq_handler) {
2612 pr_debug("%s: Switch irq kicked in, ignore\n",
2613 __func__);
2614 } else {
2615 pr_debug("%s: Reporting btn press\n",
2616 __func__);
Joonwoo Park3699ca32013-02-08 12:06:15 -08002617 wcd9xxx_jack_report(mbhc,
2618 &mbhc->button_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -07002619 mbhc->buttons_pressed,
2620 mbhc->buttons_pressed);
2621 pr_debug("%s: Reporting btn release\n",
2622 __func__);
Joonwoo Park3699ca32013-02-08 12:06:15 -08002623 wcd9xxx_jack_report(mbhc,
2624 &mbhc->button_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -07002625 0, mbhc->buttons_pressed);
2626 }
2627 }
2628 }
2629
2630 mbhc->buttons_pressed &= ~WCD9XXX_JACK_BUTTON_MASK;
2631 }
2632
2633 wcd9xxx_calibrate_hs_polling(mbhc);
2634
2635 msleep(SWCH_REL_DEBOUNCE_TIME_MS);
2636 wcd9xxx_start_hs_polling(mbhc);
2637
2638 pr_debug("%s: leave\n", __func__);
2639 WCD9XXX_BCL_UNLOCK(mbhc->resmgr);
2640 return IRQ_HANDLED;
2641}
2642
2643static irqreturn_t wcd9xxx_hphl_ocp_irq(int irq, void *data)
2644{
2645 struct wcd9xxx_mbhc *mbhc = data;
2646 struct snd_soc_codec *codec;
2647
2648 pr_info("%s: received HPHL OCP irq\n", __func__);
2649
2650 if (mbhc) {
2651 codec = mbhc->codec;
Patrick Lai56fea882013-03-02 09:11:20 -08002652 if ((mbhc->hphlocp_cnt < OCP_ATTEMPT) &&
2653 (!mbhc->hphrocp_cnt)) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002654 pr_info("%s: retry\n", __func__);
Patrick Lai56fea882013-03-02 09:11:20 -08002655 mbhc->hphlocp_cnt++;
Joonwoo Parka8890262012-10-15 12:04:27 -07002656 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
2657 0x10, 0x00);
2658 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL,
2659 0x10, 0x10);
2660 } else {
2661 wcd9xxx_disable_irq(codec->control_data,
2662 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Joonwoo Parka8890262012-10-15 12:04:27 -07002663 mbhc->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Park3699ca32013-02-08 12:06:15 -08002664 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -07002665 mbhc->hph_status,
2666 WCD9XXX_JACK_MASK);
2667 }
2668 } else {
2669 pr_err("%s: Bad wcd9xxx private data\n", __func__);
2670 }
2671
2672 return IRQ_HANDLED;
2673}
2674
2675static irqreturn_t wcd9xxx_hphr_ocp_irq(int irq, void *data)
2676{
2677 struct wcd9xxx_mbhc *mbhc = data;
2678 struct snd_soc_codec *codec;
2679
2680 pr_info("%s: received HPHR OCP irq\n", __func__);
2681 codec = mbhc->codec;
Patrick Lai56fea882013-03-02 09:11:20 -08002682 if ((mbhc->hphrocp_cnt < OCP_ATTEMPT) &&
2683 (!mbhc->hphlocp_cnt)) {
Joonwoo Parka8890262012-10-15 12:04:27 -07002684 pr_info("%s: retry\n", __func__);
Patrick Lai56fea882013-03-02 09:11:20 -08002685 mbhc->hphrocp_cnt++;
Joonwoo Parka8890262012-10-15 12:04:27 -07002686 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
2687 0x00);
2688 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
2689 0x10);
2690 } else {
2691 wcd9xxx_disable_irq(mbhc->resmgr->core,
2692 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Joonwoo Parka8890262012-10-15 12:04:27 -07002693 mbhc->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Park3699ca32013-02-08 12:06:15 -08002694 wcd9xxx_jack_report(mbhc, &mbhc->headset_jack,
Joonwoo Parka8890262012-10-15 12:04:27 -07002695 mbhc->hph_status, WCD9XXX_JACK_MASK);
2696 }
2697
2698 return IRQ_HANDLED;
2699}
2700
2701static int wcd9xxx_acdb_mclk_index(const int rate)
2702{
2703 if (rate == MCLK_RATE_12288KHZ)
2704 return 0;
2705 else if (rate == MCLK_RATE_9600KHZ)
2706 return 1;
2707 else {
2708 BUG_ON(1);
2709 return -EINVAL;
2710 }
2711}
2712
2713static void wcd9xxx_update_mbhc_clk_rate(struct wcd9xxx_mbhc *mbhc, u32 rate)
2714{
2715 u32 dce_wait, sta_wait;
2716 u8 ncic, nmeas, navg;
2717 void *calibration;
2718 u8 *n_cic, *n_ready;
2719 struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
2720 u8 npoll = 4, nbounce_wait = 30;
2721 struct snd_soc_codec *codec = mbhc->codec;
2722 int idx = wcd9xxx_acdb_mclk_index(rate);
2723 int idxmclk = wcd9xxx_acdb_mclk_index(mbhc->mbhc_cfg->mclk_rate);
2724
2725 pr_debug("%s: Updating clock rate dependents, rate = %u\n", __func__,
2726 rate);
2727 calibration = mbhc->mbhc_cfg->calibration;
2728
2729 /*
2730 * First compute the DCE / STA wait times depending on tunable
2731 * parameters. The value is computed in microseconds
2732 */
2733 btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration);
2734 n_ready = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_N_READY);
2735 n_cic = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_N_CIC);
2736 nmeas = WCD9XXX_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
2737 navg = WCD9XXX_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
2738
2739 /* ncic stays with the same what we had during calibration */
2740 ncic = n_cic[idxmclk];
2741 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (rate / 1000);
2742 sta_wait = (1000 * 128 * (navg + 1)) / (rate / 1000);
2743 mbhc->mbhc_data.t_dce = dce_wait;
2744 mbhc->mbhc_data.t_sta = sta_wait;
2745 mbhc->mbhc_data.t_sta_dce = ((1000 * 256) / (rate / 1000) *
2746 n_ready[idx]) + 10;
2747
2748 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B1_CTL, n_ready[idx]);
2749 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B6_CTL, ncic);
2750
2751 if (rate == MCLK_RATE_12288KHZ) {
2752 npoll = 4;
2753 nbounce_wait = 30;
2754 } else if (rate == MCLK_RATE_9600KHZ) {
2755 npoll = 3;
2756 nbounce_wait = 23;
2757 }
2758
2759 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B2_CTL, npoll);
2760 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B3_CTL, nbounce_wait);
2761 pr_debug("%s: leave\n", __func__);
2762}
2763
2764static void wcd9xxx_mbhc_cal(struct wcd9xxx_mbhc *mbhc)
2765{
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -07002766 u8 cfilt_mode;
Joonwoo Park7902f4c2013-02-20 15:21:25 -08002767 u16 reg0, reg1;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302768 int ret;
Joonwoo Parka8890262012-10-15 12:04:27 -07002769 struct snd_soc_codec *codec = mbhc->codec;
2770
2771 pr_debug("%s: enter\n", __func__);
2772 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
2773 wcd9xxx_turn_onoff_rel_detection(codec, false);
2774
2775 /* t_dce and t_sta are updated by wcd9xxx_update_mbhc_clk_rate() */
2776 WARN_ON(!mbhc->mbhc_data.t_dce);
2777 WARN_ON(!mbhc->mbhc_data.t_sta);
2778
2779 /*
2780 * LDOH and CFILT are already configured during pdata handling.
2781 * Only need to make sure CFILT and bandgap are in Fast mode.
2782 * Need to restore defaults once calculation is done.
2783 */
2784 cfilt_mode = snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302785 ret = wcd9xxx_put_cfilt_fast_mode(codec, mbhc);
2786 if (ret)
2787 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07002788 /*
2789 * Micbias, CFILT, LDOH, MBHC MUX mode settings
2790 * to perform ADC calibration
2791 */
2792 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x60,
2793 mbhc->mbhc_cfg->micbias << 5);
2794 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
2795 snd_soc_update_bits(codec, WCD9XXX_A_LDO_H_MODE_1, 0x60, 0x60);
2796 snd_soc_write(codec, WCD9XXX_A_TX_7_MBHC_TEST_CTL, 0x78);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302797 ret = wcd9xxx_codec_specific_cal_setup(codec, mbhc);
2798 if (ret)
2799 goto gen_err;
Joonwoo Park7902f4c2013-02-20 15:21:25 -08002800 /* Pull down micbias to ground */
2801 reg0 = snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg);
2802 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 1, 1);
2803 /* Disconnect override from micbias */
2804 reg1 = snd_soc_read(codec, WCD9XXX_A_MAD_ANA_CTRL);
2805 snd_soc_update_bits(codec, WCD9XXX_A_MAD_ANA_CTRL, 1 << 4, 1 << 0);
2806 /* Connect the MUX to micbias */
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05302807 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302808 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
2809 if (ret)
2810 goto gen_err;
Joonwoo Park7902f4c2013-02-20 15:21:25 -08002811 usleep_range(WCD9XXX_MUX_SWITCH_READY_WAIT_US,
2812 WCD9XXX_MUX_SWITCH_READY_WAIT_US +
2813 WCD9XXX_USLEEP_RANGE_MARGIN_US);
2814 /* DCE measurement for 0 voltage */
Joonwoo Parka8890262012-10-15 12:04:27 -07002815 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
Joonwoo Parka8890262012-10-15 12:04:27 -07002816 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park7902f4c2013-02-20 15:21:25 -08002817 mbhc->mbhc_data.dce_z = __wcd9xxx_codec_sta_dce(mbhc, 1, true, false);
2818 /* STA measurement for 0 voltage */
2819 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
2820 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
2821 mbhc->mbhc_data.sta_z = __wcd9xxx_codec_sta_dce(mbhc, 0, true, false);
2822 /* Restore registers */
2823 snd_soc_write(codec, mbhc->mbhc_bias_regs.ctl_reg, reg0);
2824 snd_soc_write(codec, WCD9XXX_A_MAD_ANA_CTRL, reg1);
Joonwoo Parka8890262012-10-15 12:04:27 -07002825
2826 /* DCE measurment for MB voltage */
2827 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
2828 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05302829 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302830 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
2831 if (ret)
2832 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07002833 usleep_range(100, 100);
2834 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x04);
2835 usleep_range(mbhc->mbhc_data.t_dce, mbhc->mbhc_data.t_dce);
2836 mbhc->mbhc_data.dce_mb = wcd9xxx_read_dce_result(codec);
2837
Joonwoo Park7902f4c2013-02-20 15:21:25 -08002838 /* STA Measurement for MB Voltage */
Joonwoo Parka8890262012-10-15 12:04:27 -07002839 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x0A);
2840 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
2841 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_CLK_CTL, 0x02);
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05302842 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x02);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302843 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
2844 if (ret)
2845 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07002846 usleep_range(100, 100);
2847 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x02);
2848 usleep_range(mbhc->mbhc_data.t_sta, mbhc->mbhc_data.t_sta);
2849 mbhc->mbhc_data.sta_mb = wcd9xxx_read_sta_result(codec);
2850
2851 /* Restore default settings. */
2852 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302853 snd_soc_write(codec, mbhc->mbhc_bias_regs.cfilt_ctl, cfilt_mode);
Simmi Pateriya4b9c24b2013-04-10 06:10:53 +05302854 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_1, 0x04);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302855 ret = wcd9xxx_enable_mux_bias_block(codec, mbhc);
2856 if (ret)
2857 goto gen_err;
Joonwoo Parka8890262012-10-15 12:04:27 -07002858 usleep_range(100, 100);
2859
2860 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
2861 wcd9xxx_turn_onoff_rel_detection(codec, true);
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -07002862
Joonwoo Parka8890262012-10-15 12:04:27 -07002863 pr_debug("%s: leave\n", __func__);
Simmi Pateriya387ddbc2013-04-18 01:14:20 +05302864 return;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302865
2866gen_err:
2867 pr_err("%s: Error returned, ret: %d\n", __func__, ret);
Joonwoo Parka8890262012-10-15 12:04:27 -07002868}
2869
2870static void wcd9xxx_mbhc_setup(struct wcd9xxx_mbhc *mbhc)
2871{
2872 int n;
2873 u8 *gain;
2874 struct wcd9xxx_mbhc_general_cfg *generic;
2875 struct wcd9xxx_mbhc_btn_detect_cfg *btn_det;
2876 struct snd_soc_codec *codec = mbhc->codec;
2877 const int idx = wcd9xxx_acdb_mclk_index(mbhc->mbhc_cfg->mclk_rate);
2878
2879 pr_debug("%s: enter\n", __func__);
2880 generic = WCD9XXX_MBHC_CAL_GENERAL_PTR(mbhc->mbhc_cfg->calibration);
2881 btn_det = WCD9XXX_MBHC_CAL_BTN_DET_PTR(mbhc->mbhc_cfg->calibration);
2882
2883 for (n = 0; n < 8; n++) {
2884 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_FIR_B1_CFG,
2885 0x07, n);
2886 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_FIR_B2_CFG,
2887 btn_det->c[n]);
2888 }
2889
2890 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B2_CTL, 0x07,
2891 btn_det->nc);
2892
2893 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
2894 generic->mbhc_nsa << 4);
2895
2896 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
2897 btn_det->n_meas);
2898
2899 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL,
2900 generic->mbhc_navg);
2901
2902 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
2903
2904 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x78,
2905 btn_det->mbhc_nsc << 3);
2906
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302907 if (mbhc->resmgr->reg_addr->micb_4_mbhc)
2908 snd_soc_update_bits(codec, mbhc->resmgr->reg_addr->micb_4_mbhc,
2909 0x03, MBHC_MICBIAS2);
Joonwoo Parka8890262012-10-15 12:04:27 -07002910
2911 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
2912
2913 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
2914
2915 gain = wcd9xxx_mbhc_cal_btn_det_mp(btn_det, MBHC_BTN_DET_GAIN);
2916 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B2_CTL, 0x78,
2917 gain[idx] << 3);
2918
2919 pr_debug("%s: leave\n", __func__);
2920}
2921
2922static int wcd9xxx_setup_jack_detect_irq(struct wcd9xxx_mbhc *mbhc)
2923{
2924 int ret = 0;
2925 void *core = mbhc->resmgr->core;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302926 int jack_irq;
Joonwoo Parka8890262012-10-15 12:04:27 -07002927
2928 if (mbhc->mbhc_cfg->gpio) {
2929 ret = request_threaded_irq(mbhc->mbhc_cfg->gpio_irq, NULL,
2930 wcd9xxx_mech_plug_detect_irq,
2931 (IRQF_TRIGGER_RISING |
2932 IRQF_TRIGGER_FALLING |
2933 IRQF_DISABLED),
2934 "headset detect", mbhc);
2935 if (ret) {
2936 pr_err("%s: Failed to request gpio irq %d\n", __func__,
2937 mbhc->mbhc_cfg->gpio_irq);
2938 } else {
2939 ret = enable_irq_wake(mbhc->mbhc_cfg->gpio_irq);
2940 if (ret)
2941 pr_err("%s: Failed to enable wake up irq %d\n",
2942 __func__, mbhc->mbhc_cfg->gpio_irq);
2943 }
2944 } else if (mbhc->mbhc_cfg->insert_detect) {
2945 /* Enable HPHL_10K_SW */
2946 snd_soc_update_bits(mbhc->codec, WCD9XXX_A_RX_HPH_OCP_CTL,
2947 1 << 1, 1 << 1);
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302948
2949 switch (mbhc->mbhc_version) {
2950 case WCD9XXX_MBHC_VERSION_TAIKO:
2951 jack_irq = WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAIKO;
2952 break;
2953 case WCD9XXX_MBHC_VERSION_TAPAN:
2954 jack_irq = WCD9XXX_IRQ_MBHC_JACK_SWITCH_TAPAN;
2955 break;
2956 default:
2957 return -EINVAL;
2958 }
2959
2960 ret = wcd9xxx_request_irq(core, jack_irq,
Joonwoo Parka8890262012-10-15 12:04:27 -07002961 wcd9xxx_mech_plug_detect_irq,
2962 "Jack Detect",
2963 mbhc);
2964 if (ret)
2965 pr_err("%s: Failed to request insert detect irq %d\n",
Simmi Pateriya0a44d842013-04-03 01:12:42 +05302966 __func__, jack_irq);
Joonwoo Parka8890262012-10-15 12:04:27 -07002967 }
2968
2969 return ret;
2970}
2971
2972static int wcd9xxx_init_and_calibrate(struct wcd9xxx_mbhc *mbhc)
2973{
2974 int ret = 0;
2975 struct snd_soc_codec *codec = mbhc->codec;
2976
2977 pr_debug("%s: enter\n", __func__);
2978
2979 /* Enable MCLK during calibration */
2980 wcd9xxx_onoff_ext_mclk(mbhc, true);
2981 wcd9xxx_mbhc_setup(mbhc);
2982 wcd9xxx_mbhc_cal(mbhc);
2983 wcd9xxx_mbhc_calc_thres(mbhc);
2984 wcd9xxx_onoff_ext_mclk(mbhc, false);
2985 wcd9xxx_calibrate_hs_polling(mbhc);
2986
2987 /* Enable Mic Bias pull down and HPH Switch to GND */
2988 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
2989 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_HPH, 0x01, 0x01);
2990 INIT_WORK(&mbhc->correct_plug_swch, wcd9xxx_correct_swch_plug);
2991
2992 if (!IS_ERR_VALUE(ret)) {
2993 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x10,
2994 0x10);
2995 wcd9xxx_enable_irq(codec->control_data,
2996 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
2997 wcd9xxx_enable_irq(codec->control_data,
2998 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
2999
3000 /* Initialize mechanical mbhc */
3001 ret = wcd9xxx_setup_jack_detect_irq(mbhc);
3002
3003 if (!ret && mbhc->mbhc_cfg->gpio) {
3004 /* Requested with IRQF_DISABLED */
3005 enable_irq(mbhc->mbhc_cfg->gpio_irq);
3006
3007 /* Bootup time detection */
3008 wcd9xxx_swch_irq_handler(mbhc);
3009 } else if (!ret && mbhc->mbhc_cfg->insert_detect) {
3010 pr_debug("%s: Setting up codec own insert detection\n",
3011 __func__);
3012 /* Setup for insertion detection */
3013 wcd9xxx_insert_detect_setup(mbhc, true);
3014 }
3015 }
3016
3017 pr_debug("%s: leave\n", __func__);
3018
3019 return ret;
3020}
3021
3022static void wcd9xxx_mbhc_fw_read(struct work_struct *work)
3023{
3024 struct delayed_work *dwork;
3025 struct wcd9xxx_mbhc *mbhc;
3026 struct snd_soc_codec *codec;
3027 const struct firmware *fw;
3028 int ret = -1, retry = 0;
3029
3030 dwork = to_delayed_work(work);
3031 mbhc = container_of(dwork, struct wcd9xxx_mbhc, mbhc_firmware_dwork);
3032 codec = mbhc->codec;
3033
3034 while (retry < FW_READ_ATTEMPTS) {
3035 retry++;
3036 pr_info("%s:Attempt %d to request MBHC firmware\n",
3037 __func__, retry);
3038 ret = request_firmware(&fw, "wcd9320/wcd9320_mbhc.bin",
3039 codec->dev);
3040
3041 if (ret != 0) {
3042 usleep_range(FW_READ_TIMEOUT, FW_READ_TIMEOUT);
3043 } else {
3044 pr_info("%s: MBHC Firmware read succesful\n", __func__);
3045 break;
3046 }
3047 }
3048
3049 if (ret != 0) {
3050 pr_err("%s: Cannot load MBHC firmware use default cal\n",
3051 __func__);
3052 } else if (wcd9xxx_mbhc_fw_validate(fw) == false) {
3053 pr_err("%s: Invalid MBHC cal data size use default cal\n",
3054 __func__);
3055 release_firmware(fw);
3056 } else {
3057 mbhc->mbhc_cfg->calibration = (void *)fw->data;
3058 mbhc->mbhc_fw = fw;
3059 }
3060
3061 (void) wcd9xxx_init_and_calibrate(mbhc);
3062}
3063
3064#ifdef CONFIG_DEBUG_FS
3065ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
3066 size_t count, loff_t *pos)
3067{
3068 const int size = 768;
3069 char buffer[size];
3070 int n = 0;
3071 struct wcd9xxx_mbhc *mbhc = file->private_data;
3072 const struct mbhc_internal_cal_data *p = &mbhc->mbhc_data;
Joonwoo Park73375212013-05-07 12:42:44 -07003073 const s16 v_ins_hu =
3074 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_HU);
3075 const s16 v_ins_h =
3076 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_INS_H);
3077 const s16 v_b1_hu =
3078 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_HU);
3079 const s16 v_b1_h =
3080 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_B1_H);
3081 const s16 v_br_h =
3082 wcd9xxx_get_current_v(mbhc, WCD9XXX_CURRENT_V_BR_H);
Joonwoo Parka8890262012-10-15 12:04:27 -07003083
3084 n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
3085 wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_z));
3086 n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
3087 p->dce_mb, wcd9xxx_codec_sta_dce_v(mbhc, 1, p->dce_mb));
3088 n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
3089 p->sta_z, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_z));
3090 n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
3091 p->sta_mb, wcd9xxx_codec_sta_dce_v(mbhc, 0, p->sta_mb));
Joonwoo Park73375212013-05-07 12:42:44 -07003092 n += scnprintf(buffer + n, size - n, "t_dce = %d\n", p->t_dce);
3093 n += scnprintf(buffer + n, size - n, "t_sta = %d\n", p->t_sta);
3094 n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n", p->micb_mv);
3095 n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)\n",
3096 v_ins_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_ins_hu));
3097 n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)\n",
3098 v_ins_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_ins_h));
Joonwoo Parka8890262012-10-15 12:04:27 -07003099 n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
Joonwoo Park73375212013-05-07 12:42:44 -07003100 v_b1_hu, wcd9xxx_codec_sta_dce_v(mbhc, 0, v_b1_hu));
Joonwoo Parka8890262012-10-15 12:04:27 -07003101 n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
Joonwoo Park73375212013-05-07 12:42:44 -07003102 v_b1_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_b1_h));
Joonwoo Parka8890262012-10-15 12:04:27 -07003103 n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
Joonwoo Park73375212013-05-07 12:42:44 -07003104 v_br_h, wcd9xxx_codec_sta_dce_v(mbhc, 1, v_br_h));
Joonwoo Parka8890262012-10-15 12:04:27 -07003105 n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
3106 wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_brl));
3107 n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
3108 p->v_no_mic,
3109 wcd9xxx_codec_sta_dce_v(mbhc, 0, p->v_no_mic));
3110 n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
3111 p->v_inval_ins_low);
3112 n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
3113 p->v_inval_ins_high);
3114 n += scnprintf(buffer + n, size - n, "Insert detect insert = %d\n",
3115 !wcd9xxx_swch_level_remove(mbhc));
3116 buffer[n] = 0;
3117
3118 return simple_read_from_buffer(buf, count, pos, buffer, n);
3119}
3120
3121static int codec_debug_open(struct inode *inode, struct file *file)
3122{
3123 file->private_data = inode->i_private;
3124 return 0;
3125}
3126
3127static ssize_t codec_debug_write(struct file *filp,
3128 const char __user *ubuf, size_t cnt,
3129 loff_t *ppos)
3130{
3131 char lbuf[32];
3132 char *buf;
3133 int rc;
3134 struct wcd9xxx_mbhc *mbhc = filp->private_data;
3135
3136 if (cnt > sizeof(lbuf) - 1)
3137 return -EINVAL;
3138
3139 rc = copy_from_user(lbuf, ubuf, cnt);
3140 if (rc)
3141 return -EFAULT;
3142
3143 lbuf[cnt] = '\0';
3144 buf = (char *)lbuf;
3145 mbhc->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
3146 false : true;
3147 return rc;
3148}
3149
3150static const struct file_operations mbhc_trrs_debug_ops = {
3151 .open = codec_debug_open,
3152 .write = codec_debug_write,
3153};
3154
3155static const struct file_operations mbhc_debug_ops = {
3156 .open = codec_debug_open,
3157 .read = codec_mbhc_debug_read,
3158};
3159
3160static void wcd9xxx_init_debugfs(struct wcd9xxx_mbhc *mbhc)
3161{
3162 mbhc->debugfs_poke =
3163 debugfs_create_file("TRRS", S_IFREG | S_IRUGO, NULL, mbhc,
3164 &mbhc_trrs_debug_ops);
3165 mbhc->debugfs_mbhc =
3166 debugfs_create_file("wcd9xxx_mbhc", S_IFREG | S_IRUGO,
3167 NULL, mbhc, &mbhc_debug_ops);
3168}
3169
3170static void wcd9xxx_cleanup_debugfs(struct wcd9xxx_mbhc *mbhc)
3171{
3172 debugfs_remove(mbhc->debugfs_poke);
3173 debugfs_remove(mbhc->debugfs_mbhc);
3174}
3175#else
3176static void wcd9xxx_init_debugfs(struct wcd9xxx_mbhc *mbhc)
3177{
3178}
3179
3180static void wcd9xxx_cleanup_debugfs(struct wcd9xxx_mbhc *mbhc)
3181{
3182}
3183#endif
3184
3185int wcd9xxx_mbhc_start(struct wcd9xxx_mbhc *mbhc,
3186 struct wcd9xxx_mbhc_config *mbhc_cfg)
3187{
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303188 int rc;
Joonwoo Parka8890262012-10-15 12:04:27 -07003189 struct snd_soc_codec *codec = mbhc->codec;
3190
3191 pr_debug("%s: enter\n", __func__);
3192
3193 if (!codec) {
3194 pr_err("%s: no codec\n", __func__);
3195 return -EINVAL;
3196 }
3197
3198 if (mbhc_cfg->mclk_rate != MCLK_RATE_12288KHZ &&
3199 mbhc_cfg->mclk_rate != MCLK_RATE_9600KHZ) {
3200 pr_err("Error: unsupported clock rate %d\n",
3201 mbhc_cfg->mclk_rate);
3202 return -EINVAL;
3203 }
3204
3205 /* Save mbhc config */
3206 mbhc->mbhc_cfg = mbhc_cfg;
3207
3208 /* Get HW specific mbhc registers' address */
3209 wcd9xxx_get_mbhc_micbias_regs(mbhc, &mbhc->mbhc_bias_regs);
3210
3211 /* Put CFILT in fast mode by default */
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303212 rc = wcd9xxx_put_cfilt_fast_mode(codec, mbhc);
3213 if (rc)
3214 pr_err("%s: Error returned, ret: %d\n", __func__, rc);
3215 else if (!mbhc->mbhc_cfg->read_fw_bin)
Joonwoo Parka8890262012-10-15 12:04:27 -07003216 rc = wcd9xxx_init_and_calibrate(mbhc);
3217 else
3218 schedule_delayed_work(&mbhc->mbhc_firmware_dwork,
3219 usecs_to_jiffies(FW_READ_TIMEOUT));
3220
3221 pr_debug("%s: leave %d\n", __func__, rc);
3222 return rc;
3223}
3224EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_start);
3225
3226static enum wcd9xxx_micbias_num
3227wcd9xxx_event_to_micbias(const enum wcd9xxx_notify_event event)
3228{
3229 enum wcd9xxx_micbias_num ret;
3230 switch (event) {
3231 case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
3232 ret = MBHC_MICBIAS1;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003233 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003234 case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
3235 ret = MBHC_MICBIAS2;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003236 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003237 case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
3238 ret = MBHC_MICBIAS3;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003239 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003240 case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
3241 ret = MBHC_MICBIAS4;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003242 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003243 default:
3244 ret = MBHC_MICBIAS_INVALID;
Joonwoo Parkbac18db2013-03-21 15:51:33 -07003245 break;
Joonwoo Parka8890262012-10-15 12:04:27 -07003246 }
3247 return ret;
3248}
3249
3250static int wcd9xxx_event_to_cfilt(const enum wcd9xxx_notify_event event)
3251{
3252 int ret;
3253 switch (event) {
3254 case WCD9XXX_EVENT_PRE_CFILT_1_OFF:
3255 case WCD9XXX_EVENT_POST_CFILT_1_OFF:
3256 case WCD9XXX_EVENT_PRE_CFILT_1_ON:
3257 case WCD9XXX_EVENT_POST_CFILT_1_ON:
3258 ret = WCD9XXX_CFILT1_SEL;
3259 break;
3260 case WCD9XXX_EVENT_PRE_CFILT_2_OFF:
3261 case WCD9XXX_EVENT_POST_CFILT_2_OFF:
3262 case WCD9XXX_EVENT_PRE_CFILT_2_ON:
3263 case WCD9XXX_EVENT_POST_CFILT_2_ON:
3264 ret = WCD9XXX_CFILT2_SEL;
3265 break;
3266 case WCD9XXX_EVENT_PRE_CFILT_3_OFF:
3267 case WCD9XXX_EVENT_POST_CFILT_3_OFF:
3268 case WCD9XXX_EVENT_PRE_CFILT_3_ON:
3269 case WCD9XXX_EVENT_POST_CFILT_3_ON:
3270 ret = WCD9XXX_CFILT3_SEL;
3271 break;
3272 default:
3273 ret = -1;
3274 }
3275 return ret;
3276}
3277
3278static int wcd9xxx_get_mbhc_cfilt_sel(struct wcd9xxx_mbhc *mbhc)
3279{
3280 int cfilt;
3281 const struct wcd9xxx_pdata *pdata = mbhc->resmgr->pdata;
3282
3283 switch (mbhc->mbhc_cfg->micbias) {
3284 case MBHC_MICBIAS1:
3285 cfilt = pdata->micbias.bias1_cfilt_sel;
3286 break;
3287 case MBHC_MICBIAS2:
3288 cfilt = pdata->micbias.bias2_cfilt_sel;
3289 break;
3290 case MBHC_MICBIAS3:
3291 cfilt = pdata->micbias.bias3_cfilt_sel;
3292 break;
3293 case MBHC_MICBIAS4:
3294 cfilt = pdata->micbias.bias4_cfilt_sel;
3295 break;
3296 default:
3297 cfilt = MBHC_MICBIAS_INVALID;
3298 break;
3299 }
3300 return cfilt;
3301}
3302
3303static int wcd9xxx_event_notify(struct notifier_block *self, unsigned long val,
3304 void *data)
3305{
3306 int ret = 0;
3307 struct wcd9xxx_mbhc *mbhc = ((struct wcd9xxx_resmgr *)data)->mbhc;
3308 struct snd_soc_codec *codec = mbhc->codec;
3309 enum wcd9xxx_notify_event event = (enum wcd9xxx_notify_event)val;
3310
3311 pr_debug("%s: enter event %s(%d)\n", __func__,
3312 wcd9xxx_get_event_string(event), event);
3313
3314 switch (event) {
3315 /* MICBIAS usage change */
3316 case WCD9XXX_EVENT_PRE_MICBIAS_1_ON:
3317 case WCD9XXX_EVENT_PRE_MICBIAS_2_ON:
3318 case WCD9XXX_EVENT_PRE_MICBIAS_3_ON:
3319 case WCD9XXX_EVENT_PRE_MICBIAS_4_ON:
3320 if (mbhc->mbhc_cfg->micbias == wcd9xxx_event_to_micbias(event))
3321 wcd9xxx_switch_micbias(mbhc, 0);
3322 break;
3323 case WCD9XXX_EVENT_POST_MICBIAS_1_ON:
3324 case WCD9XXX_EVENT_POST_MICBIAS_2_ON:
3325 case WCD9XXX_EVENT_POST_MICBIAS_3_ON:
3326 case WCD9XXX_EVENT_POST_MICBIAS_4_ON:
3327 if (mbhc->mbhc_cfg->micbias ==
3328 wcd9xxx_event_to_micbias(event) &&
3329 wcd9xxx_mbhc_polling(mbhc)) {
3330 /* if polling is on, restart it */
3331 wcd9xxx_pause_hs_polling(mbhc);
3332 wcd9xxx_start_hs_polling(mbhc);
3333 }
3334 break;
3335 case WCD9XXX_EVENT_POST_MICBIAS_1_OFF:
3336 case WCD9XXX_EVENT_POST_MICBIAS_2_OFF:
3337 case WCD9XXX_EVENT_POST_MICBIAS_3_OFF:
3338 case WCD9XXX_EVENT_POST_MICBIAS_4_OFF:
3339 if (mbhc->mbhc_cfg->micbias ==
3340 wcd9xxx_event_to_micbias(event) &&
3341 wcd9xxx_is_hph_pa_on(codec))
3342 wcd9xxx_switch_micbias(mbhc, 1);
3343 break;
3344 /* PA usage change */
3345 case WCD9XXX_EVENT_PRE_HPHL_PA_ON:
Joonwoo Parkd87ec4c2012-10-30 15:44:18 -07003346 if (!(snd_soc_read(codec, mbhc->mbhc_bias_regs.ctl_reg) & 0x80))
Joonwoo Parka8890262012-10-15 12:04:27 -07003347 /* if micbias is enabled, switch to vddio */
3348 wcd9xxx_switch_micbias(mbhc, 1);
3349 break;
3350 case WCD9XXX_EVENT_PRE_HPHR_PA_ON:
3351 /* Not used now */
3352 break;
3353 case WCD9XXX_EVENT_POST_HPHL_PA_OFF:
3354 /* if HPH PAs are off, report OCP and switch back to CFILT */
3355 clear_bit(WCD9XXX_HPHL_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
3356 clear_bit(WCD9XXX_HPHL_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
3357 if (mbhc->hph_status & SND_JACK_OC_HPHL)
3358 hphlocp_off_report(mbhc, SND_JACK_OC_HPHL);
3359 wcd9xxx_switch_micbias(mbhc, 0);
3360 break;
3361 case WCD9XXX_EVENT_POST_HPHR_PA_OFF:
3362 /* if HPH PAs are off, report OCP and switch back to CFILT */
3363 clear_bit(WCD9XXX_HPHR_PA_OFF_ACK, &mbhc->hph_pa_dac_state);
3364 clear_bit(WCD9XXX_HPHR_DAC_OFF_ACK, &mbhc->hph_pa_dac_state);
3365 if (mbhc->hph_status & SND_JACK_OC_HPHR)
3366 hphrocp_off_report(mbhc, SND_JACK_OC_HPHL);
3367 wcd9xxx_switch_micbias(mbhc, 0);
3368 break;
3369 /* Clock usage change */
3370 case WCD9XXX_EVENT_PRE_MCLK_ON:
3371 break;
3372 case WCD9XXX_EVENT_POST_MCLK_ON:
3373 /* Change to lower TxAAF frequency */
3374 snd_soc_update_bits(codec, WCD9XXX_A_TX_COM_BIAS, 1 << 4,
3375 1 << 4);
3376 /* Re-calibrate clock rate dependent values */
3377 wcd9xxx_update_mbhc_clk_rate(mbhc, mbhc->mbhc_cfg->mclk_rate);
3378 /* If clock source changes, stop and restart polling */
3379 if (wcd9xxx_mbhc_polling(mbhc)) {
3380 wcd9xxx_calibrate_hs_polling(mbhc);
3381 wcd9xxx_start_hs_polling(mbhc);
3382 }
3383 break;
3384 case WCD9XXX_EVENT_PRE_MCLK_OFF:
3385 /* If clock source changes, stop and restart polling */
3386 if (wcd9xxx_mbhc_polling(mbhc))
3387 wcd9xxx_pause_hs_polling(mbhc);
3388 break;
3389 case WCD9XXX_EVENT_POST_MCLK_OFF:
3390 break;
3391 case WCD9XXX_EVENT_PRE_RCO_ON:
3392 break;
3393 case WCD9XXX_EVENT_POST_RCO_ON:
3394 /* Change to higher TxAAF frequency */
3395 snd_soc_update_bits(codec, WCD9XXX_A_TX_COM_BIAS, 1 << 4,
3396 0 << 4);
3397 /* Re-calibrate clock rate dependent values */
3398 wcd9xxx_update_mbhc_clk_rate(mbhc, WCD9XXX_RCO_CLK_RATE);
3399 /* If clock source changes, stop and restart polling */
3400 if (wcd9xxx_mbhc_polling(mbhc)) {
3401 wcd9xxx_calibrate_hs_polling(mbhc);
3402 wcd9xxx_start_hs_polling(mbhc);
3403 }
3404 break;
3405 case WCD9XXX_EVENT_PRE_RCO_OFF:
3406 /* If clock source changes, stop and restart polling */
3407 if (wcd9xxx_mbhc_polling(mbhc))
3408 wcd9xxx_pause_hs_polling(mbhc);
3409 break;
3410 case WCD9XXX_EVENT_POST_RCO_OFF:
3411 break;
3412 /* CFILT usage change */
3413 case WCD9XXX_EVENT_PRE_CFILT_1_ON:
3414 case WCD9XXX_EVENT_PRE_CFILT_2_ON:
3415 case WCD9XXX_EVENT_PRE_CFILT_3_ON:
3416 if (wcd9xxx_get_mbhc_cfilt_sel(mbhc) ==
3417 wcd9xxx_event_to_cfilt(event))
3418 /*
3419 * Switch CFILT to slow mode if MBHC CFILT is being
3420 * used.
3421 */
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303422 ret = wcd9xxx_codec_switch_cfilt_mode(mbhc, false);
Joonwoo Parka8890262012-10-15 12:04:27 -07003423 break;
3424 case WCD9XXX_EVENT_POST_CFILT_1_OFF:
3425 case WCD9XXX_EVENT_POST_CFILT_2_OFF:
3426 case WCD9XXX_EVENT_POST_CFILT_3_OFF:
3427 if (wcd9xxx_get_mbhc_cfilt_sel(mbhc) ==
3428 wcd9xxx_event_to_cfilt(event))
3429 /*
3430 * Switch CFILT to fast mode if MBHC CFILT is not
3431 * used anymore.
3432 */
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303433 ret = wcd9xxx_codec_switch_cfilt_mode(mbhc, true);
Joonwoo Parka8890262012-10-15 12:04:27 -07003434 break;
3435 /* System resume */
3436 case WCD9XXX_EVENT_POST_RESUME:
3437 mbhc->mbhc_last_resume = jiffies;
3438 break;
3439 /* BG mode chage */
3440 case WCD9XXX_EVENT_PRE_BG_OFF:
3441 case WCD9XXX_EVENT_POST_BG_OFF:
3442 case WCD9XXX_EVENT_PRE_BG_AUDIO_ON:
3443 case WCD9XXX_EVENT_POST_BG_AUDIO_ON:
3444 case WCD9XXX_EVENT_PRE_BG_MBHC_ON:
3445 case WCD9XXX_EVENT_POST_BG_MBHC_ON:
3446 /* Not used for now */
3447 break;
3448 default:
3449 WARN(1, "Unknown event %d\n", event);
3450 ret = -EINVAL;
3451 }
3452
3453 pr_debug("%s: leave\n", __func__);
3454
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303455 return ret;
Joonwoo Parka8890262012-10-15 12:04:27 -07003456}
3457
3458/*
3459 * wcd9xxx_mbhc_init : initialize MBHC internal structures.
3460 *
3461 * NOTE: mbhc->mbhc_cfg is not YET configure so shouldn't be used
3462 */
3463int wcd9xxx_mbhc_init(struct wcd9xxx_mbhc *mbhc, struct wcd9xxx_resmgr *resmgr,
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303464 struct snd_soc_codec *codec, int version)
Joonwoo Parka8890262012-10-15 12:04:27 -07003465{
3466 int ret;
3467 void *core;
3468
3469 pr_debug("%s: enter\n", __func__);
3470 memset(&mbhc->mbhc_bias_regs, 0, sizeof(struct mbhc_micbias_regs));
3471 memset(&mbhc->mbhc_data, 0, sizeof(struct mbhc_internal_cal_data));
3472
3473 mbhc->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
3474 mbhc->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
3475 mbhc->mbhc_data.t_sta = DEFAULT_STA_WAIT;
3476 mbhc->mbhc_micbias_switched = false;
3477 mbhc->polling_active = false;
3478 mbhc->mbhc_state = MBHC_STATE_NONE;
3479 mbhc->in_swch_irq_handler = false;
3480 mbhc->current_plug = PLUG_TYPE_NONE;
3481 mbhc->lpi_enabled = false;
3482 mbhc->no_mic_headset_override = false;
3483 mbhc->mbhc_last_resume = 0;
3484 mbhc->codec = codec;
3485 mbhc->resmgr = resmgr;
3486 mbhc->resmgr->mbhc = mbhc;
Simmi Pateriya0a44d842013-04-03 01:12:42 +05303487 mbhc->mbhc_version = version;
Joonwoo Parka8890262012-10-15 12:04:27 -07003488
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003489 if (mbhc->headset_jack.jack == NULL) {
3490 ret = snd_soc_jack_new(codec, "Headset Jack", WCD9XXX_JACK_MASK,
3491 &mbhc->headset_jack);
3492 if (ret) {
3493 pr_err("%s: Failed to create new jack\n", __func__);
3494 return ret;
3495 }
Joonwoo Parka8890262012-10-15 12:04:27 -07003496
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003497 ret = snd_soc_jack_new(codec, "Button Jack",
3498 WCD9XXX_JACK_BUTTON_MASK,
3499 &mbhc->button_jack);
3500 if (ret) {
3501 pr_err("Failed to create new jack\n");
3502 return ret;
3503 }
Joonwoo Parka8890262012-10-15 12:04:27 -07003504
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003505 INIT_DELAYED_WORK(&mbhc->mbhc_firmware_dwork,
3506 wcd9xxx_mbhc_fw_read);
3507 INIT_DELAYED_WORK(&mbhc->mbhc_btn_dwork, wcd9xxx_btn_lpress_fn);
3508 INIT_DELAYED_WORK(&mbhc->mbhc_insert_dwork,
3509 wcd9xxx_mbhc_insert_work);
3510 }
Joonwoo Parka8890262012-10-15 12:04:27 -07003511
3512 /* Register event notifier */
3513 mbhc->nblock.notifier_call = wcd9xxx_event_notify;
3514 ret = wcd9xxx_resmgr_register_notifier(mbhc->resmgr, &mbhc->nblock);
3515 if (ret) {
3516 pr_err("%s: Failed to register notifier %d\n", __func__, ret);
3517 return ret;
3518 }
3519
3520 wcd9xxx_init_debugfs(mbhc);
3521
3522 core = mbhc->resmgr->core;
3523 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_INSERTION,
3524 wcd9xxx_hs_insert_irq,
3525 "Headset insert detect", mbhc);
3526 if (ret) {
3527 pr_err("%s: Failed to request irq %d\n", __func__,
3528 WCD9XXX_IRQ_MBHC_INSERTION);
3529 goto err_insert_irq;
3530 }
3531 wcd9xxx_disable_irq(core, WCD9XXX_IRQ_MBHC_INSERTION);
3532
3533 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL,
3534 wcd9xxx_hs_remove_irq,
3535 "Headset remove detect", mbhc);
3536 if (ret) {
3537 pr_err("%s: Failed to request irq %d\n", __func__,
3538 WCD9XXX_IRQ_MBHC_REMOVAL);
3539 goto err_remove_irq;
3540 }
3541
3542 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL,
3543 wcd9xxx_dce_handler, "DC Estimation detect",
3544 mbhc);
3545 if (ret) {
3546 pr_err("%s: Failed to request irq %d\n", __func__,
3547 WCD9XXX_IRQ_MBHC_POTENTIAL);
3548 goto err_potential_irq;
3549 }
3550
3551 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_MBHC_RELEASE,
3552 wcd9xxx_release_handler,
3553 "Button Release detect", mbhc);
3554 if (ret) {
3555 pr_err("%s: Failed to request irq %d\n", __func__,
3556 WCD9XXX_IRQ_MBHC_RELEASE);
3557 goto err_release_irq;
3558 }
3559
3560 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
3561 wcd9xxx_hphl_ocp_irq, "HPH_L OCP detect",
3562 mbhc);
3563 if (ret) {
3564 pr_err("%s: Failed to request irq %d\n", __func__,
3565 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
3566 goto err_hphl_ocp_irq;
3567 }
3568 wcd9xxx_disable_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
3569
3570 ret = wcd9xxx_request_irq(core, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
3571 wcd9xxx_hphr_ocp_irq, "HPH_R OCP detect",
3572 mbhc);
3573 if (ret) {
3574 pr_err("%s: Failed to request irq %d\n", __func__,
3575 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
3576 goto err_hphr_ocp_irq;
3577 }
3578 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
3579
3580 pr_debug("%s: leave ret %d\n", __func__, ret);
3581 return ret;
3582
3583err_hphr_ocp_irq:
3584 wcd9xxx_free_irq(core, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
3585err_hphl_ocp_irq:
3586 wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
3587err_release_irq:
3588 wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
3589err_potential_irq:
3590 wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
3591err_remove_irq:
3592 wcd9xxx_free_irq(core, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
3593err_insert_irq:
3594 wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
3595
3596 pr_debug("%s: leave ret %d\n", __func__, ret);
3597 return ret;
3598}
3599EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_init);
3600
3601void wcd9xxx_mbhc_deinit(struct wcd9xxx_mbhc *mbhc)
3602{
3603 void *cdata = mbhc->codec->control_data;
3604
Joonwoo Parka8890262012-10-15 12:04:27 -07003605 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_RELEASE, mbhc);
3606 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_POTENTIAL, mbhc);
3607 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_REMOVAL, mbhc);
3608 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_INSERTION, mbhc);
3609
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003610 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_MBHC_JACK_SWITCH, mbhc);
3611 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, mbhc);
3612 wcd9xxx_free_irq(cdata, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT, mbhc);
Ravishankar Sarawadi2293efe2013-01-11 16:37:23 -08003613
Joonwoo Parka8890262012-10-15 12:04:27 -07003614 if (mbhc->mbhc_fw)
3615 release_firmware(mbhc->mbhc_fw);
3616
3617 wcd9xxx_resmgr_unregister_notifier(mbhc->resmgr, &mbhc->nblock);
3618
3619 wcd9xxx_cleanup_debugfs(mbhc);
Joonwoo Parka8890262012-10-15 12:04:27 -07003620}
3621EXPORT_SYMBOL_GPL(wcd9xxx_mbhc_deinit);
3622
3623MODULE_DESCRIPTION("wcd9xxx MBHC module");
3624MODULE_LICENSE("GPL v2");