blob: 9041bd7352adc1284b0173d73bea3342f2087a69 [file] [log] [blame]
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/firmware.h>
15#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/device.h>
18#include <linux/printk.h>
19#include <linux/ratelimit.h>
20#include <linux/debugfs.h>
21#include <linux/mfd/wcd9xxx/core.h>
22#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
23#include <linux/mfd/wcd9xxx/wcd9304_registers.h>
24#include <linux/mfd/wcd9xxx/pdata.h>
25#include <sound/pcm.h>
26#include <sound/pcm_params.h>
27#include <sound/jack.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>
Asish Bhattacharya1d069532012-03-07 13:25:24 -080033#include <linux/pm_runtime.h>
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070034#include <linux/kernel.h>
35#include <linux/gpio.h>
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053036#include "wcd9304.h"
37
38#define WCD9304_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
39 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
40
41#define NUM_DECIMATORS 4
42#define NUM_INTERPOLATORS 3
43#define BITS_PER_REG 8
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080044#define SITAR_CFILT_FAST_MODE 0x00
45#define SITAR_CFILT_SLOW_MODE 0x40
46#define MBHC_FW_READ_ATTEMPTS 15
47#define MBHC_FW_READ_TIMEOUT 2000000
48
49#define SITAR_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
50
51#define SITAR_I2S_MASTER_MODE_MASK 0x08
52
53#define SITAR_OCP_ATTEMPT 1
54
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053055#define AIF1_PB 1
56#define AIF1_CAP 2
57#define NUM_CODEC_DAIS 2
58
59struct sitar_codec_dai_data {
60 u32 rate;
61 u32 *ch_num;
62 u32 ch_act;
63 u32 ch_tot;
64};
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053065
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080066#define SITAR_MCLK_RATE_12288KHZ 12288000
67#define SITAR_MCLK_RATE_9600KHZ 9600000
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053068
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -080069#define SITAR_FAKE_INS_THRESHOLD_MS 2500
70#define SITAR_FAKE_REMOVAL_MIN_PERIOD_MS 50
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -070071#define SITAR_MBHC_BUTTON_MIN 0x8000
72#define SITAR_GPIO_IRQ_DEBOUNCE_TIME_US 5000
73
74#define SITAR_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
75#define SITAR_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
76
77#define MBHC_NUM_DCE_PLUG_DETECT 3
78#define SITAR_MBHC_FAKE_INSERT_LOW 10
79#define SITAR_MBHC_FAKE_INSERT_HIGH 80
80#define SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV 500
81#define SITAR_HS_DETECT_PLUG_TIME_MS (5 * 1000)
82#define SITAR_HS_DETECT_PLUG_INERVAL_MS 100
83#define NUM_ATTEMPTS_TO_REPORT 5
84#define SITAR_MBHC_STATUS_REL_DETECTION 0x0C
85#define SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
Asish Bhattacharyab86c3472012-02-15 08:31:52 +053086
87static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
88static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
89static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
90static struct snd_soc_dai_driver sitar_dai[];
91static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
92 struct snd_kcontrol *kcontrol, int event);
93static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
94 struct snd_kcontrol *kcontrol, int event);
95
96enum sitar_bandgap_type {
97 SITAR_BANDGAP_OFF = 0,
98 SITAR_BANDGAP_AUDIO_MODE,
99 SITAR_BANDGAP_MBHC_MODE,
100};
101
102struct mbhc_micbias_regs {
103 u16 cfilt_val;
104 u16 cfilt_ctl;
105 u16 mbhc_reg;
106 u16 int_rbias;
107 u16 ctl_reg;
108 u8 cfilt_sel;
109};
110
111/* Codec supports 2 IIR filters */
112enum {
113 IIR1 = 0,
114 IIR2,
115 IIR_MAX,
116};
117/* Codec supports 5 bands */
118enum {
119 BAND1 = 0,
120 BAND2,
121 BAND3,
122 BAND4,
123 BAND5,
124 BAND_MAX,
125};
126
127/* Flags to track of PA and DAC state.
128 * PA and DAC should be tracked separately as AUXPGA loopback requires
129 * only PA to be turned on without DAC being on. */
130enum sitar_priv_ack_flags {
131 SITAR_HPHL_PA_OFF_ACK = 0,
132 SITAR_HPHR_PA_OFF_ACK,
133 SITAR_HPHL_DAC_OFF_ACK,
134 SITAR_HPHR_DAC_OFF_ACK
135};
136
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800137/* Data used by MBHC */
138struct mbhc_internal_cal_data {
139 u16 dce_z;
140 u16 dce_mb;
141 u16 sta_z;
142 u16 sta_mb;
143 u32 t_sta_dce;
144 u32 t_dce;
145 u32 t_sta;
146 u32 micb_mv;
147 u16 v_ins_hu;
148 u16 v_ins_h;
149 u16 v_b1_hu;
150 u16 v_b1_h;
151 u16 v_b1_huc;
152 u16 v_brh;
153 u16 v_brl;
154 u16 v_no_mic;
155 u8 npoll;
156 u8 nbounce_wait;
157};
158
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700159enum sitar_mbhc_plug_type {
160 PLUG_TYPE_INVALID = -1,
161 PLUG_TYPE_NONE,
162 PLUG_TYPE_HEADSET,
163 PLUG_TYPE_HEADPHONE,
164 PLUG_TYPE_HIGH_HPH,
165};
166
167enum sitar_mbhc_state {
168 MBHC_STATE_NONE = -1,
169 MBHC_STATE_POTENTIAL,
170 MBHC_STATE_POTENTIAL_RECOVERY,
171 MBHC_STATE_RELEASE,
172};
173
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530174struct sitar_priv {
175 struct snd_soc_codec *codec;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800176 u32 mclk_freq;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530177 u32 adc_count;
178 u32 cfilt1_cnt;
179 u32 cfilt2_cnt;
180 u32 cfilt3_cnt;
181 u32 rx_bias_count;
182 enum sitar_bandgap_type bandgap_type;
183 bool mclk_enabled;
184 bool clock_active;
185 bool config_mode_active;
186 bool mbhc_polling_active;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800187 unsigned long mbhc_fake_ins_start;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530188 int buttons_pressed;
189
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800190 enum sitar_micbias_num micbias;
191 /* void* calibration contains:
192 * struct sitar_mbhc_general_cfg generic;
193 * struct sitar_mbhc_plug_detect_cfg plug_det;
194 * struct sitar_mbhc_plug_type_cfg plug_type;
195 * struct sitar_mbhc_btn_detect_cfg btn_det;
196 * struct sitar_mbhc_imped_detect_cfg imped_det;
197 * Note: various size depends on btn_det->num_btn
198 */
199 void *calibration;
200 struct mbhc_internal_cal_data mbhc_data;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530201
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530202 struct wcd9xxx_pdata *pdata;
203 u32 anc_slot;
204
205 bool no_mic_headset_override;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530206
207 struct mbhc_micbias_regs mbhc_bias_regs;
208 u8 cfilt_k_value;
209 bool mbhc_micbias_switched;
210
211 /* track PA/DAC state */
212 unsigned long hph_pa_dac_state;
213
214 /*track sitar interface type*/
215 u8 intf_type;
216
217 u32 hph_status; /* track headhpone status */
218 /* define separate work for left and right headphone OCP to avoid
219 * additional checking on which OCP event to report so no locking
220 * to ensure synchronization is required
221 */
222 struct work_struct hphlocp_work; /* reporting left hph ocp off */
223 struct work_struct hphrocp_work; /* reporting right hph ocp off */
224
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530225 u8 hphlocp_cnt; /* headphone left ocp retry */
226 u8 hphrocp_cnt; /* headphone right ocp retry */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800227
228 /* Callback function to enable MCLK */
229 int (*mclk_cb) (struct snd_soc_codec*, int);
230
231 /* Work to perform MBHC Firmware Read */
232 struct delayed_work mbhc_firmware_dwork;
233 const struct firmware *mbhc_fw;
234
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530235 /* num of slim ports required */
236 struct sitar_codec_dai_data dai[NUM_CODEC_DAIS];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700237
238 /* Currently, only used for mbhc purpose, to protect
239 * concurrent execution of mbhc threaded irq handlers and
240 * kill race between DAPM and MBHC.But can serve as a
241 * general lock to protect codec resource
242 */
243 struct mutex codec_resource_lock;
244
245 struct sitar_mbhc_config mbhc_cfg;
246 bool in_gpio_handler;
247 u8 current_plug;
248 bool lpi_enabled;
249 enum sitar_mbhc_state mbhc_state;
250 struct work_struct hs_correct_plug_work;
251 bool hs_detect_work_stop;
252 struct delayed_work mbhc_btn_dwork;
253 unsigned long mbhc_last_resume; /* in jiffies */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530254};
255
256#ifdef CONFIG_DEBUG_FS
257struct sitar_priv *debug_sitar_priv;
258#endif
259
260
261static int sitar_pa_gain_get(struct snd_kcontrol *kcontrol,
262 struct snd_ctl_elem_value *ucontrol)
263{
264 u8 ear_pa_gain;
265 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
266
267 ear_pa_gain = snd_soc_read(codec, SITAR_A_RX_EAR_GAIN);
268
269 ear_pa_gain = ear_pa_gain >> 5;
270
271 if (ear_pa_gain == 0x00) {
272 ucontrol->value.integer.value[0] = 0;
273 } else if (ear_pa_gain == 0x04) {
274 ucontrol->value.integer.value[0] = 1;
275 } else {
276 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
277 __func__, ear_pa_gain);
278 return -EINVAL;
279 }
280
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530281 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530282
283 return 0;
284}
285
286static int sitar_pa_gain_put(struct snd_kcontrol *kcontrol,
287 struct snd_ctl_elem_value *ucontrol)
288{
289 u8 ear_pa_gain;
290 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
291
292 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
293 ucontrol->value.integer.value[0]);
294
295 switch (ucontrol->value.integer.value[0]) {
296 case 0:
297 ear_pa_gain = 0x00;
298 break;
299 case 1:
300 ear_pa_gain = 0x80;
301 break;
302 default:
303 return -EINVAL;
304 }
305
306 snd_soc_write(codec, SITAR_A_RX_EAR_GAIN, ear_pa_gain);
307 return 0;
308}
309
310static int sitar_get_iir_enable_audio_mixer(
311 struct snd_kcontrol *kcontrol,
312 struct snd_ctl_elem_value *ucontrol)
313{
314 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
315 int iir_idx = ((struct soc_multi_mixer_control *)
316 kcontrol->private_value)->reg;
317 int band_idx = ((struct soc_multi_mixer_control *)
318 kcontrol->private_value)->shift;
319
320 ucontrol->value.integer.value[0] =
321 snd_soc_read(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx)) &
322 (1 << band_idx);
323
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530324 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530325 iir_idx, band_idx,
326 (uint32_t)ucontrol->value.integer.value[0]);
327 return 0;
328}
329
330static int sitar_put_iir_enable_audio_mixer(
331 struct snd_kcontrol *kcontrol,
332 struct snd_ctl_elem_value *ucontrol)
333{
334 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
335 int iir_idx = ((struct soc_multi_mixer_control *)
336 kcontrol->private_value)->reg;
337 int band_idx = ((struct soc_multi_mixer_control *)
338 kcontrol->private_value)->shift;
339 int value = ucontrol->value.integer.value[0];
340
341 /* Mask first 5 bits, 6-8 are reserved */
342 snd_soc_update_bits(codec, (SITAR_A_CDC_IIR1_CTL + 16 * iir_idx),
343 (1 << band_idx), (value << band_idx));
344
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530345 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530346 iir_idx, band_idx, value);
347 return 0;
348}
349static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
350 int iir_idx, int band_idx,
351 int coeff_idx)
352{
353 /* Address does not automatically update if reading */
354 snd_soc_update_bits(codec,
355 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
356 0x1F, band_idx * BAND_MAX + coeff_idx);
357
358 /* Mask bits top 2 bits since they are reserved */
359 return ((snd_soc_read(codec,
360 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
361 (snd_soc_read(codec,
362 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
363 (snd_soc_read(codec,
364 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
365 (snd_soc_read(codec,
366 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
367 0x3FFFFFFF;
368}
369
370static int sitar_get_iir_band_audio_mixer(
371 struct snd_kcontrol *kcontrol,
372 struct snd_ctl_elem_value *ucontrol)
373{
374 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
375 int iir_idx = ((struct soc_multi_mixer_control *)
376 kcontrol->private_value)->reg;
377 int band_idx = ((struct soc_multi_mixer_control *)
378 kcontrol->private_value)->shift;
379
380 ucontrol->value.integer.value[0] =
381 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
382 ucontrol->value.integer.value[1] =
383 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
384 ucontrol->value.integer.value[2] =
385 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
386 ucontrol->value.integer.value[3] =
387 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
388 ucontrol->value.integer.value[4] =
389 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
390
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530391 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530392 "%s: IIR #%d band #%d b1 = 0x%x\n"
393 "%s: IIR #%d band #%d b2 = 0x%x\n"
394 "%s: IIR #%d band #%d a1 = 0x%x\n"
395 "%s: IIR #%d band #%d a2 = 0x%x\n",
396 __func__, iir_idx, band_idx,
397 (uint32_t)ucontrol->value.integer.value[0],
398 __func__, iir_idx, band_idx,
399 (uint32_t)ucontrol->value.integer.value[1],
400 __func__, iir_idx, band_idx,
401 (uint32_t)ucontrol->value.integer.value[2],
402 __func__, iir_idx, band_idx,
403 (uint32_t)ucontrol->value.integer.value[3],
404 __func__, iir_idx, band_idx,
405 (uint32_t)ucontrol->value.integer.value[4]);
406 return 0;
407}
408
409static void set_iir_band_coeff(struct snd_soc_codec *codec,
410 int iir_idx, int band_idx,
411 int coeff_idx, uint32_t value)
412{
413 /* Mask top 3 bits, 6-8 are reserved */
414 /* Update address manually each time */
415 snd_soc_update_bits(codec,
416 (SITAR_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
417 0x1F, band_idx * BAND_MAX + coeff_idx);
418
419 /* Mask top 2 bits, 7-8 are reserved */
420 snd_soc_update_bits(codec,
421 (SITAR_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
422 0x3F, (value >> 24) & 0x3F);
423
424 /* Isolate 8bits at a time */
425 snd_soc_update_bits(codec,
426 (SITAR_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
427 0xFF, (value >> 16) & 0xFF);
428
429 snd_soc_update_bits(codec,
430 (SITAR_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
431 0xFF, (value >> 8) & 0xFF);
432
433 snd_soc_update_bits(codec,
434 (SITAR_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
435 0xFF, value & 0xFF);
436}
437
438static int sitar_put_iir_band_audio_mixer(
439 struct snd_kcontrol *kcontrol,
440 struct snd_ctl_elem_value *ucontrol)
441{
442 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
443 int iir_idx = ((struct soc_multi_mixer_control *)
444 kcontrol->private_value)->reg;
445 int band_idx = ((struct soc_multi_mixer_control *)
446 kcontrol->private_value)->shift;
447
448 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
449 ucontrol->value.integer.value[0]);
450 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
451 ucontrol->value.integer.value[1]);
452 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
453 ucontrol->value.integer.value[2]);
454 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
455 ucontrol->value.integer.value[3]);
456 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
457 ucontrol->value.integer.value[4]);
458
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530459 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530460 "%s: IIR #%d band #%d b1 = 0x%x\n"
461 "%s: IIR #%d band #%d b2 = 0x%x\n"
462 "%s: IIR #%d band #%d a1 = 0x%x\n"
463 "%s: IIR #%d band #%d a2 = 0x%x\n",
464 __func__, iir_idx, band_idx,
465 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
466 __func__, iir_idx, band_idx,
467 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
468 __func__, iir_idx, band_idx,
469 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
470 __func__, iir_idx, band_idx,
471 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
472 __func__, iir_idx, band_idx,
473 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
474 return 0;
475}
476
477static const char *sitar_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
478static const struct soc_enum sitar_ear_pa_gain_enum[] = {
479 SOC_ENUM_SINGLE_EXT(2, sitar_ear_pa_gain_text),
480};
481
482/*cut of frequency for high pass filter*/
483static const char *cf_text[] = {
484 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
485};
486
487static const struct soc_enum cf_dec1_enum =
488 SOC_ENUM_SINGLE(SITAR_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
489
490static const struct soc_enum cf_rxmix1_enum =
491 SOC_ENUM_SINGLE(SITAR_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
492
493static const struct snd_kcontrol_new sitar_snd_controls[] = {
494
495 SOC_ENUM_EXT("EAR PA Gain", sitar_ear_pa_gain_enum[0],
496 sitar_pa_gain_get, sitar_pa_gain_put),
497
498 SOC_SINGLE_TLV("LINEOUT1 Volume", SITAR_A_RX_LINE_1_GAIN, 0, 12, 1,
499 line_gain),
500 SOC_SINGLE_TLV("LINEOUT2 Volume", SITAR_A_RX_LINE_2_GAIN, 0, 12, 1,
501 line_gain),
502
503 SOC_SINGLE_TLV("HPHL Volume", SITAR_A_RX_HPH_L_GAIN, 0, 12, 1,
504 line_gain),
505 SOC_SINGLE_TLV("HPHR Volume", SITAR_A_RX_HPH_R_GAIN, 0, 12, 1,
506 line_gain),
507
508 SOC_SINGLE_S8_TLV("RX1 Digital Volume", SITAR_A_CDC_RX1_VOL_CTL_B2_CTL,
509 -84, 40, digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800510 SOC_SINGLE_S8_TLV("RX2 Digital Volume", SITAR_A_CDC_RX2_VOL_CTL_B2_CTL,
511 -84, 40, digital_gain),
512 SOC_SINGLE_S8_TLV("RX3 Digital Volume", SITAR_A_CDC_RX3_VOL_CTL_B2_CTL,
513 -84, 40, digital_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530514
515 SOC_SINGLE_S8_TLV("DEC1 Volume", SITAR_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
516 digital_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800517 SOC_SINGLE_S8_TLV("DEC2 Volume", SITAR_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
518 digital_gain),
519 SOC_SINGLE_S8_TLV("DEC3 Volume", SITAR_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
520 digital_gain),
521 SOC_SINGLE_S8_TLV("DEC4 Volume", SITAR_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
522 digital_gain),
523
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530524 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", SITAR_A_CDC_IIR1_GAIN_B1_CTL, -84,
525 40, digital_gain),
526 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", SITAR_A_CDC_IIR1_GAIN_B2_CTL, -84,
527 40, digital_gain),
528 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", SITAR_A_CDC_IIR1_GAIN_B3_CTL, -84,
529 40, digital_gain),
530 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", SITAR_A_CDC_IIR1_GAIN_B4_CTL, -84,
531 40, digital_gain),
532 SOC_SINGLE_TLV("ADC1 Volume", SITAR_A_TX_1_2_EN, 5, 3, 0, analog_gain),
533 SOC_SINGLE_TLV("ADC2 Volume", SITAR_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800534 SOC_SINGLE_TLV("ADC3 Volume", SITAR_A_TX_3_EN, 5, 3, 0, analog_gain),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530535
536 SOC_SINGLE("MICBIAS1 CAPLESS Switch", SITAR_A_MICB_1_CTL, 4, 1, 1),
537 SOC_SINGLE("MICBIAS2 CAPLESS Switch", SITAR_A_MICB_2_CTL, 4, 1, 1),
538
539 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
540
541 SOC_SINGLE("TX1 HPF Switch", SITAR_A_CDC_TX1_MUX_CTL, 3, 1, 0),
542
543 SOC_SINGLE("RX1 HPF Switch", SITAR_A_CDC_RX1_B5_CTL, 2, 1, 0),
544
545 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
546
547 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
548 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
549 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
550 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
551 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
552 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
553 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
554 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
555 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
556 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
557 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
558 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
559 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
560 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
561 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
562 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
563 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
564 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
565 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
566 sitar_get_iir_enable_audio_mixer, sitar_put_iir_enable_audio_mixer),
567
568 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
569 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
570 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
571 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
572 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
573 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
574 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
575 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
576 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
577 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
578 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
579 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
580 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
581 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
582 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
583 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
584 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
585 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
586 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
587 sitar_get_iir_band_audio_mixer, sitar_put_iir_band_audio_mixer),
588};
589
590static const char *rx_mix1_text[] = {
591 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
592 "RX5"
593};
594
595static const char *rx_dac1_text[] = {
596 "ZERO", "RX1", "RX2"
597};
598
599static const char *rx_dac2_text[] = {
600 "ZERO", "RX1",
601};
602
603static const char *rx_dac3_text[] = {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800604 "ZERO", "RX1", "INV_RX1", "RX2"
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530605};
606
607static const char *rx_dac4_text[] = {
608 "ZERO", "ON"
609};
610
611static const char *sb_tx1_mux_text[] = {
612 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
613 "DEC1"
614};
615
616static const char *sb_tx2_mux_text[] = {
617 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
618 "DEC2"
619};
620
621static const char *sb_tx3_mux_text[] = {
622 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
623 "DEC3"
624};
625
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800626static const char *sb_tx4_mux_text[] = {
627 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
628 "DEC4"
629};
630
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530631static const char *sb_tx5_mux_text[] = {
632 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
633 "DEC5"
634};
635
636static const char *dec1_mux_text[] = {
637 "ZERO", "DMIC1", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC4", "ANCFB1",
638};
639
640static const char *dec2_mux_text[] = {
641 "ZERO", "DMIC2", "ADC1", "ADC2", "ADC3", "MBADC", "DMIC3", "ANCFB2",
642};
643
644static const char *dec3_mux_text[] = {
645 "ZERO", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3", "MBADC",
646};
647
648static const char *dec4_mux_text[] = {
649 "ZERO", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "ADC1", "ADC2", "ADC3",
650};
651
652static const char *iir1_inp1_text[] = {
653 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "ZERO", "ZERO", "ZERO",
654 "ZERO", "ZERO", "ZERO", "RX1", "RX2", "RX3", "RX4", "RX5",
655};
656
657static const struct soc_enum rx_mix1_inp1_chain_enum =
658 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 0, 10, rx_mix1_text);
659
660static const struct soc_enum rx_mix1_inp2_chain_enum =
661 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX1_B1_CTL, 4, 10, rx_mix1_text);
662
663static const struct soc_enum rx2_mix1_inp1_chain_enum =
664 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 0, 10, rx_mix1_text);
665
666static const struct soc_enum rx2_mix1_inp2_chain_enum =
667 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX2_B1_CTL, 4, 10, rx_mix1_text);
668
669static const struct soc_enum rx3_mix1_inp1_chain_enum =
670 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 0, 10, rx_mix1_text);
671
672static const struct soc_enum rx3_mix1_inp2_chain_enum =
673 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_RX3_B1_CTL, 4, 10, rx_mix1_text);
674
675static const struct soc_enum rx_dac1_enum =
676 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 6, 3, rx_dac1_text);
677
678static const struct soc_enum rx_dac2_enum =
679 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 4, 2, rx_dac2_text);
680
681static const struct soc_enum rx_dac3_enum =
682 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 2, 4, rx_dac3_text);
683
684static const struct soc_enum rx_dac4_enum =
685 SOC_ENUM_SINGLE(SITAR_A_CDC_TOP_RDAC_DOUT_CTL, 0, 2, rx_dac4_text);
686
687static const struct soc_enum sb_tx5_mux_enum =
688 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
689
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800690static const struct soc_enum sb_tx4_mux_enum =
691 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
692
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530693static const struct soc_enum sb_tx3_mux_enum =
694 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
695
696static const struct soc_enum sb_tx2_mux_enum =
697 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
698
699static const struct soc_enum sb_tx1_mux_enum =
700 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
701
702static const struct soc_enum dec1_mux_enum =
703 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 0, 8, dec1_mux_text);
704
705static const struct soc_enum dec2_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800706 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B1_CTL, 3, 8, dec2_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530707
708static const struct soc_enum dec3_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800709 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 0, 8, dec3_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530710
711static const struct soc_enum dec4_mux_enum =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800712 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_TX_B2_CTL, 3, 8, dec4_mux_text);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530713
714static const struct soc_enum iir1_inp1_mux_enum =
715 SOC_ENUM_SINGLE(SITAR_A_CDC_CONN_EQ1_B1_CTL, 0, 16, iir1_inp1_text);
716
717static const struct snd_kcontrol_new rx_mix1_inp1_mux =
718 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
719
720static const struct snd_kcontrol_new rx_mix1_inp2_mux =
721 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
722
723static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
724 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
725
726static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
727 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
728
729static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
730 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
731
732static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
733 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
734
735static const struct snd_kcontrol_new rx_dac1_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800736 SOC_DAPM_ENUM("RX DAC1 Mux", rx_dac1_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530737
738static const struct snd_kcontrol_new rx_dac2_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800739 SOC_DAPM_ENUM("RX DAC2 Mux", rx_dac2_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530740
741static const struct snd_kcontrol_new rx_dac3_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800742 SOC_DAPM_ENUM("RX DAC3 Mux", rx_dac3_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530743
744static const struct snd_kcontrol_new rx_dac4_mux =
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800745 SOC_DAPM_ENUM("RX DAC4 Mux", rx_dac4_enum);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530746
747static const struct snd_kcontrol_new sb_tx5_mux =
748 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
749
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800750static const struct snd_kcontrol_new sb_tx4_mux =
751 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
752
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530753static const struct snd_kcontrol_new sb_tx3_mux =
754 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
755
756static const struct snd_kcontrol_new sb_tx2_mux =
757 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
758
759static const struct snd_kcontrol_new sb_tx1_mux =
760 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
761
762static const struct snd_kcontrol_new dec1_mux =
763 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
764
765static const struct snd_kcontrol_new dec2_mux =
766 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
767
768static const struct snd_kcontrol_new dec3_mux =
769 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
770
771static const struct snd_kcontrol_new dec4_mux =
772 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
773
774static const struct snd_kcontrol_new iir1_inp1_mux =
775 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
776
777static const struct snd_kcontrol_new dac1_switch[] = {
778 SOC_DAPM_SINGLE("Switch", SITAR_A_RX_EAR_EN, 5, 1, 0),
779};
780
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530781static void sitar_codec_enable_adc_block(struct snd_soc_codec *codec,
782 int enable)
783{
784 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
785
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530786 pr_debug("%s %d\n", __func__, enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530787
788 if (enable) {
789 sitar->adc_count++;
790 snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS, 0xE0, 0xE0);
791
792 } else {
793 sitar->adc_count--;
794 if (!sitar->adc_count) {
795 if (!sitar->mbhc_polling_active)
796 snd_soc_update_bits(codec, SITAR_A_TX_COM_BIAS,
797 0xE0, 0x0);
798 }
799 }
800}
801
802static int sitar_codec_enable_adc(struct snd_soc_dapm_widget *w,
803 struct snd_kcontrol *kcontrol, int event)
804{
805 struct snd_soc_codec *codec = w->codec;
806 u16 adc_reg;
807
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530808 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530809
810 if (w->reg == SITAR_A_TX_1_2_EN)
811 adc_reg = SITAR_A_TX_1_2_TEST_CTL;
812 else {
813 pr_err("%s: Error, invalid adc register\n", __func__);
814 return -EINVAL;
815 }
816
817 switch (event) {
818 case SND_SOC_DAPM_PRE_PMU:
819 sitar_codec_enable_adc_block(codec, 1);
820 break;
821 case SND_SOC_DAPM_POST_PMU:
822 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
823 1 << w->shift);
824 usleep_range(1000, 1000);
825 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
826 usleep_range(1000, 1000);
827 snd_soc_update_bits(codec, adc_reg, 0x08, 0x08);
828 break;
829 case SND_SOC_DAPM_POST_PMD:
830 sitar_codec_enable_adc_block(codec, 0);
831 break;
832 }
833 return 0;
834}
835
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800836static int sitar_lineout_dac_event(struct snd_soc_dapm_widget *w,
837 struct snd_kcontrol *kcontrol, int event)
838{
839 struct snd_soc_codec *codec = w->codec;
840
841 pr_debug("%s %s %d\n", __func__, w->name, event);
842
843 switch (event) {
844 case SND_SOC_DAPM_PRE_PMU:
845 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
846 break;
847
848 case SND_SOC_DAPM_POST_PMD:
849 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
850 break;
851 }
852 return 0;
853}
854
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530855static int sitar_codec_enable_lineout(struct snd_soc_dapm_widget *w,
856 struct snd_kcontrol *kcontrol, int event)
857{
858 struct snd_soc_codec *codec = w->codec;
859 u16 lineout_gain_reg;
860
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530861 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530862
863 switch (w->shift) {
864 case 0:
865 lineout_gain_reg = SITAR_A_RX_LINE_1_GAIN;
866 break;
867 case 1:
868 lineout_gain_reg = SITAR_A_RX_LINE_2_GAIN;
869 break;
870 default:
871 pr_err("%s: Error, incorrect lineout register value\n",
872 __func__);
873 return -EINVAL;
874 }
875
876 switch (event) {
877 case SND_SOC_DAPM_PRE_PMU:
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800878 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530879 break;
880 case SND_SOC_DAPM_POST_PMU:
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530881 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530882 __func__, w->name);
883 usleep_range(16000, 16000);
884 break;
885 case SND_SOC_DAPM_POST_PMD:
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800886 snd_soc_update_bits(codec, lineout_gain_reg, 0x10, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530887 break;
888 }
889 return 0;
890}
891
892static int sitar_codec_enable_dmic(struct snd_soc_dapm_widget *w,
893 struct snd_kcontrol *kcontrol, int event)
894{
895 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajare37f4ab72012-04-10 18:52:37 -0700896 u16 tx_dmic_ctl_reg, tx_mux_ctl_reg;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530897 u8 dmic_clk_sel, dmic_clk_en;
898 unsigned int dmic;
899 int ret;
900
901 ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
902 if (ret < 0) {
903 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
904 return -EINVAL;
905 }
906
907 switch (dmic) {
908 case 1:
909 case 2:
910 dmic_clk_sel = 0x02;
911 dmic_clk_en = 0x01;
912 break;
913 case 3:
914 case 4:
915 dmic_clk_sel = 0x08;
916 dmic_clk_en = 0x04;
917 break;
918
919 break;
920
921 default:
922 pr_err("%s: Invalid DMIC Selection\n", __func__);
923 return -EINVAL;
924 }
925
Bhalchandra Gajare37f4ab72012-04-10 18:52:37 -0700926 tx_mux_ctl_reg = SITAR_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530927 tx_dmic_ctl_reg = SITAR_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
928
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +0530929 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530930
931 switch (event) {
932 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajare37f4ab72012-04-10 18:52:37 -0700933 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x01);
934
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530935 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
936 dmic_clk_sel, dmic_clk_sel);
937
938 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
939
940 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
941 dmic_clk_en, dmic_clk_en);
942 break;
943 case SND_SOC_DAPM_POST_PMD:
944 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_DMIC_CTL,
945 dmic_clk_en, 0);
Bhalchandra Gajare37f4ab72012-04-10 18:52:37 -0700946
947 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x01, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530948 break;
949 }
950 return 0;
951}
952
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530953static void sitar_codec_start_hs_polling(struct snd_soc_codec *codec)
954{
955 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700956 int mbhc_state = sitar->mbhc_state;
957
958 pr_debug("%s: enter\n", __func__);
959 if (!sitar->mbhc_polling_active) {
960 pr_debug("Polling is not active, do not start polling\n");
961 return;
962 }
963 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
964
965
966 if (!sitar->no_mic_headset_override) {
967 if (mbhc_state == MBHC_STATE_POTENTIAL) {
968 pr_debug("%s recovering MBHC state macine\n", __func__);
969 sitar->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
970 /* set to max button press threshold */
971 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
972 0x7F);
973 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
974 0xFF);
975 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
976 0x7F);
977 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
978 0xFF);
979 /* set to max */
980 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
981 0x7F);
982 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
983 0xFF);
984 }
985 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530986
987 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -0800988 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
989 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
990 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +0530991}
992
993static void sitar_codec_pause_hs_polling(struct snd_soc_codec *codec)
994{
995 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
996
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -0700997 pr_debug("%s: enter\n", __func__);
998 if (!sitar->mbhc_polling_active) {
999 pr_debug("polling not active, nothing to pause\n");
1000 return;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301001 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001002
1003 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1004 pr_debug("%s: leave\n", __func__);
1005
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301006}
1007
1008static void sitar_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1009 int mode)
1010{
1011 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1012 u8 reg_mode_val, cur_mode_val;
1013 bool mbhc_was_polling = false;
1014
1015 if (mode)
1016 reg_mode_val = SITAR_CFILT_FAST_MODE;
1017 else
1018 reg_mode_val = SITAR_CFILT_SLOW_MODE;
1019
1020 cur_mode_val = snd_soc_read(codec,
1021 sitar->mbhc_bias_regs.cfilt_ctl) & 0x40;
1022
1023 if (cur_mode_val != reg_mode_val) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001024 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301025 if (sitar->mbhc_polling_active) {
1026 sitar_codec_pause_hs_polling(codec);
1027 mbhc_was_polling = true;
1028 }
1029 snd_soc_update_bits(codec,
1030 sitar->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1031 if (mbhc_was_polling)
1032 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001033 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301034 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301035 cur_mode_val, reg_mode_val);
1036 } else {
1037 pr_err("%s: CFILT Value is already %x\n",
1038 __func__, cur_mode_val);
1039 }
1040}
1041
1042static void sitar_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1043 u8 cfilt_sel, int inc)
1044{
1045 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1046 u32 *cfilt_cnt_ptr = NULL;
1047 u16 micb_cfilt_reg;
1048
1049 switch (cfilt_sel) {
1050 case SITAR_CFILT1_SEL:
1051 cfilt_cnt_ptr = &sitar->cfilt1_cnt;
1052 micb_cfilt_reg = SITAR_A_MICB_CFILT_1_CTL;
1053 break;
1054 case SITAR_CFILT2_SEL:
1055 cfilt_cnt_ptr = &sitar->cfilt2_cnt;
1056 micb_cfilt_reg = SITAR_A_MICB_CFILT_2_CTL;
1057 break;
1058 default:
1059 return; /* should not happen */
1060 }
1061
1062 if (inc) {
1063 if (!(*cfilt_cnt_ptr)++) {
1064 /* Switch CFILT to slow mode if MBHC CFILT being used */
1065 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1066 sitar_codec_switch_cfilt_mode(codec, 0);
1067
1068 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1069 }
1070 } else {
1071 /* check if count not zero, decrement
1072 * then check if zero, go ahead disable cfilter
1073 */
1074 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1075 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1076
1077 /* Switch CFILT to fast mode if MBHC CFILT being used */
1078 if (cfilt_sel == sitar->mbhc_bias_regs.cfilt_sel)
1079 sitar_codec_switch_cfilt_mode(codec, 1);
1080 }
1081 }
1082}
1083
1084static int sitar_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1085{
1086 int rc = -EINVAL;
1087 unsigned min_mv, max_mv;
1088
1089 switch (ldoh_v) {
1090 case SITAR_LDOH_1P95_V:
1091 min_mv = 160;
1092 max_mv = 1800;
1093 break;
1094 case SITAR_LDOH_2P35_V:
1095 min_mv = 200;
1096 max_mv = 2200;
1097 break;
1098 case SITAR_LDOH_2P75_V:
1099 min_mv = 240;
1100 max_mv = 2600;
1101 break;
1102 case SITAR_LDOH_2P85_V:
1103 min_mv = 250;
1104 max_mv = 2700;
1105 break;
1106 default:
1107 goto done;
1108 }
1109
1110 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1111 goto done;
1112
1113 for (rc = 4; rc <= 44; rc++) {
1114 min_mv = max_mv * (rc) / 44;
1115 if (min_mv >= cfilt_mv) {
1116 rc -= 4;
1117 break;
1118 }
1119 }
1120done:
1121 return rc;
1122}
1123
1124static bool sitar_is_hph_pa_on(struct snd_soc_codec *codec)
1125{
1126 u8 hph_reg_val = 0;
1127 hph_reg_val = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_EN);
1128
1129 return (hph_reg_val & 0x30) ? true : false;
1130}
1131
1132static bool sitar_is_hph_dac_on(struct snd_soc_codec *codec, int left)
1133{
1134 u8 hph_reg_val = 0;
1135 if (left)
1136 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001137 SITAR_A_RX_HPH_L_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301138 else
1139 hph_reg_val = snd_soc_read(codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001140 SITAR_A_RX_HPH_R_DAC_CTL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301141
1142 return (hph_reg_val & 0xC0) ? true : false;
1143}
1144
1145static void sitar_codec_switch_micbias(struct snd_soc_codec *codec,
1146 int vddio_switch)
1147{
1148 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1149 int cfilt_k_val;
1150 bool mbhc_was_polling = false;
1151
1152 switch (vddio_switch) {
1153 case 1:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001154 if (sitar->mbhc_micbias_switched == 0 &&
1155 sitar->mbhc_polling_active) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301156
1157 sitar_codec_pause_hs_polling(codec);
1158 /* Enable Mic Bias switch to VDDIO */
1159 sitar->cfilt_k_value = snd_soc_read(codec,
1160 sitar->mbhc_bias_regs.cfilt_val);
1161 cfilt_k_val = sitar_find_k_value(
1162 sitar->pdata->micbias.ldoh_v, 1800);
1163 snd_soc_update_bits(codec,
1164 sitar->mbhc_bias_regs.cfilt_val,
1165 0xFC, (cfilt_k_val << 2));
1166
1167 snd_soc_update_bits(codec,
1168 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1169 snd_soc_update_bits(codec,
1170 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1171 sitar_codec_start_hs_polling(codec);
1172
1173 sitar->mbhc_micbias_switched = true;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301174 pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301175 __func__);
1176 }
1177 break;
1178
1179 case 0:
1180 if (sitar->mbhc_micbias_switched) {
1181 if (sitar->mbhc_polling_active) {
1182 sitar_codec_pause_hs_polling(codec);
1183 mbhc_was_polling = true;
1184 }
1185 /* Disable Mic Bias switch to VDDIO */
1186 if (sitar->cfilt_k_value != 0)
1187 snd_soc_update_bits(codec,
1188 sitar->mbhc_bias_regs.cfilt_val, 0XFC,
1189 sitar->cfilt_k_value);
1190 snd_soc_update_bits(codec,
1191 sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1192 snd_soc_update_bits(codec,
1193 sitar->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1194
1195 if (mbhc_was_polling)
1196 sitar_codec_start_hs_polling(codec);
1197
1198 sitar->mbhc_micbias_switched = false;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301199 pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301200 __func__);
1201 }
1202 break;
1203 }
1204}
1205
1206static int sitar_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1207 struct snd_kcontrol *kcontrol, int event)
1208{
1209 struct snd_soc_codec *codec = w->codec;
1210 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1211 u16 micb_int_reg;
1212 int micb_line;
1213 u8 cfilt_sel_val = 0;
1214 char *internal1_text = "Internal1";
1215 char *internal2_text = "Internal2";
1216
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301217 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301218 switch (w->reg) {
1219 case SITAR_A_MICB_1_CTL:
1220 micb_int_reg = SITAR_A_MICB_1_INT_RBIAS;
1221 cfilt_sel_val = sitar->pdata->micbias.bias1_cfilt_sel;
1222 micb_line = SITAR_MICBIAS1;
1223 break;
1224 case SITAR_A_MICB_2_CTL:
1225 micb_int_reg = SITAR_A_MICB_2_INT_RBIAS;
1226 cfilt_sel_val = sitar->pdata->micbias.bias2_cfilt_sel;
1227 micb_line = SITAR_MICBIAS2;
1228 break;
1229 default:
1230 pr_err("%s: Error, invalid micbias register\n", __func__);
1231 return -EINVAL;
1232 }
1233
1234 switch (event) {
1235 case SND_SOC_DAPM_PRE_PMU:
1236 /* Decide whether to switch the micbias for MBHC */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001237 if (w->reg == sitar->mbhc_bias_regs.ctl_reg) {
1238 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301239 sitar_codec_switch_micbias(codec, 0);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001240 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
1241 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301242
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001243 snd_soc_update_bits(codec, w->reg, 0x1E, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301244 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
1245
1246 if (strnstr(w->name, internal1_text, 30))
1247 snd_soc_update_bits(codec, micb_int_reg, 0xFF, 0xA4);
1248 else if (strnstr(w->name, internal2_text, 30))
1249 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1250 break;
1251 case SND_SOC_DAPM_POST_PMU:
1252 if (sitar->mbhc_polling_active &&
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001253 sitar->micbias == micb_line) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001254 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301255 sitar_codec_pause_hs_polling(codec);
1256 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001257 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301258 }
1259 break;
1260 case SND_SOC_DAPM_POST_PMD:
1261
1262 if ((w->reg == sitar->mbhc_bias_regs.ctl_reg)
1263 && sitar_is_hph_pa_on(codec))
1264 sitar_codec_switch_micbias(codec, 1);
1265
1266 if (strnstr(w->name, internal1_text, 30))
1267 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1268 else if (strnstr(w->name, internal2_text, 30))
1269 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1270 sitar_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
1271 break;
1272 }
1273
1274 return 0;
1275}
1276
1277static int sitar_codec_enable_dec(struct snd_soc_dapm_widget *w,
1278 struct snd_kcontrol *kcontrol, int event)
1279{
1280 struct snd_soc_codec *codec = w->codec;
1281 u16 dec_reset_reg;
1282
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301283 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301284
1285 if (w->reg == SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1286 dec_reset_reg = SITAR_A_CDC_CLK_TX_RESET_B1_CTL;
1287 else {
1288 pr_err("%s: Error, incorrect dec\n", __func__);
1289 return -EINVAL;
1290 }
1291
1292 switch (event) {
1293 case SND_SOC_DAPM_PRE_PMU:
1294 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1295 1 << w->shift);
1296 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1297 break;
1298 }
1299 return 0;
1300}
1301
1302static int sitar_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
1303 struct snd_kcontrol *kcontrol, int event)
1304{
1305 struct snd_soc_codec *codec = w->codec;
1306
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301307 pr_debug("%s %d %s\n", __func__, event, w->name);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301308
1309 switch (event) {
1310 case SND_SOC_DAPM_PRE_PMU:
1311 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
1312 1 << w->shift, 1 << w->shift);
1313 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_RESET_CTL,
1314 1 << w->shift, 0x0);
1315 break;
1316 }
1317 return 0;
1318}
1319
1320static int sitar_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1321 struct snd_kcontrol *kcontrol, int event)
1322{
1323 switch (event) {
1324 case SND_SOC_DAPM_POST_PMU:
1325 case SND_SOC_DAPM_POST_PMD:
1326 usleep_range(1000, 1000);
1327 pr_debug("LDO_H\n");
1328 break;
1329 }
1330 return 0;
1331}
1332
1333static void sitar_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1334{
1335 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1336
1337 if (enable) {
1338 sitar->rx_bias_count++;
1339 if (sitar->rx_bias_count == 1)
1340 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
1341 0x80, 0x80);
1342 } else {
1343 sitar->rx_bias_count--;
1344 if (!sitar->rx_bias_count)
1345 snd_soc_update_bits(codec, SITAR_A_RX_COM_BIAS,
1346 0x80, 0x00);
1347 }
1348}
1349
1350static int sitar_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1351 struct snd_kcontrol *kcontrol, int event)
1352{
1353 struct snd_soc_codec *codec = w->codec;
1354
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301355 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301356
1357 switch (event) {
1358 case SND_SOC_DAPM_PRE_PMU:
1359 sitar_enable_rx_bias(codec, 1);
1360 break;
1361 case SND_SOC_DAPM_POST_PMD:
1362 sitar_enable_rx_bias(codec, 0);
1363 break;
1364 }
1365 return 0;
1366}
Bhalchandra Gajare66131712012-05-07 14:12:26 -07001367static int sitar_hph_dac_event(struct snd_soc_dapm_widget *w,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301368 struct snd_kcontrol *kcontrol, int event)
1369{
1370 struct snd_soc_codec *codec = w->codec;
1371
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301372 pr_debug("%s %s %d\n", __func__, w->name, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301373
1374 switch (event) {
1375 case SND_SOC_DAPM_PRE_PMU:
1376 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1377 break;
1378 case SND_SOC_DAPM_POST_PMD:
1379 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1380 break;
1381 }
1382 return 0;
1383}
1384
1385static void sitar_snd_soc_jack_report(struct sitar_priv *sitar,
1386 struct snd_soc_jack *jack, int status,
1387 int mask)
1388{
1389 /* XXX: wake_lock_timeout()? */
1390 snd_soc_jack_report(jack, status, mask);
1391}
1392
1393static void hphocp_off_report(struct sitar_priv *sitar,
1394 u32 jack_status, int irq)
1395{
1396 struct snd_soc_codec *codec;
1397
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001398 if (!sitar) {
1399 pr_err("%s: Bad sitar private data\n", __func__);
1400 return;
1401 }
1402
1403 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
1404 codec = sitar->codec;
1405 if (sitar->hph_status & jack_status) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301406 sitar->hph_status &= ~jack_status;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001407 if (sitar->mbhc_cfg.headset_jack)
1408 sitar_snd_soc_jack_report(sitar,
1409 sitar->mbhc_cfg.headset_jack,
1410 sitar->hph_status,
1411 SITAR_JACK_MASK);
1412 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x00);
1413 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301414 /* reset retry counter as PA is turned off signifying
1415 * start of new OCP detection session
1416 */
1417 if (SITAR_IRQ_HPH_PA_OCPL_FAULT)
1418 sitar->hphlocp_cnt = 0;
1419 else
1420 sitar->hphrocp_cnt = 0;
1421 wcd9xxx_enable_irq(codec->control_data, irq);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301422 }
1423}
1424
1425static void hphlocp_off_report(struct work_struct *work)
1426{
1427 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
1428 hphlocp_work);
1429 hphocp_off_report(sitar, SND_JACK_OC_HPHL, SITAR_IRQ_HPH_PA_OCPL_FAULT);
1430}
1431
1432static void hphrocp_off_report(struct work_struct *work)
1433{
1434 struct sitar_priv *sitar = container_of(work, struct sitar_priv,
1435 hphrocp_work);
1436 hphocp_off_report(sitar, SND_JACK_OC_HPHR, SITAR_IRQ_HPH_PA_OCPR_FAULT);
1437}
1438
1439static int sitar_hph_pa_event(struct snd_soc_dapm_widget *w,
1440 struct snd_kcontrol *kcontrol, int event)
1441{
1442 struct snd_soc_codec *codec = w->codec;
1443 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1444 u8 mbhc_micb_ctl_val;
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301445 pr_debug("%s: event = %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301446
1447 switch (event) {
1448 case SND_SOC_DAPM_PRE_PMU:
1449 mbhc_micb_ctl_val = snd_soc_read(codec,
1450 sitar->mbhc_bias_regs.ctl_reg);
1451
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001452 if (!(mbhc_micb_ctl_val & 0x80)) {
1453 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301454 sitar_codec_switch_micbias(codec, 1);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001455 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
1456 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301457
1458 break;
1459
1460 case SND_SOC_DAPM_POST_PMD:
1461 /* schedule work is required because at the time HPH PA DAPM
1462 * event callback is called by DAPM framework, CODEC dapm mutex
1463 * would have been locked while snd_soc_jack_report also
1464 * attempts to acquire same lock.
1465 */
1466 if (w->shift == 5) {
1467 clear_bit(SITAR_HPHL_PA_OFF_ACK,
1468 &sitar->hph_pa_dac_state);
1469 clear_bit(SITAR_HPHL_DAC_OFF_ACK,
1470 &sitar->hph_pa_dac_state);
1471 if (sitar->hph_status & SND_JACK_OC_HPHL)
1472 schedule_work(&sitar->hphlocp_work);
1473 } else if (w->shift == 4) {
1474 clear_bit(SITAR_HPHR_PA_OFF_ACK,
1475 &sitar->hph_pa_dac_state);
1476 clear_bit(SITAR_HPHR_DAC_OFF_ACK,
1477 &sitar->hph_pa_dac_state);
1478 if (sitar->hph_status & SND_JACK_OC_HPHR)
1479 schedule_work(&sitar->hphrocp_work);
1480 }
1481
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07001482 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
1483 sitar_codec_switch_micbias(codec, 0);
1484 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301485
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301486 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301487 w->name);
1488 usleep_range(10000, 10000);
1489
1490 break;
1491 }
1492 return 0;
1493}
1494
1495static void sitar_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
1496 struct mbhc_micbias_regs *micbias_regs)
1497{
1498 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301499 unsigned int cfilt;
1500
Patrick Laia5062da2012-05-11 17:55:09 -07001501 switch (sitar->mbhc_cfg.micbias) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301502 case SITAR_MICBIAS1:
1503 cfilt = sitar->pdata->micbias.bias1_cfilt_sel;
1504 micbias_regs->mbhc_reg = SITAR_A_MICB_1_MBHC;
1505 micbias_regs->int_rbias = SITAR_A_MICB_1_INT_RBIAS;
1506 micbias_regs->ctl_reg = SITAR_A_MICB_1_CTL;
1507 break;
1508 case SITAR_MICBIAS2:
1509 cfilt = sitar->pdata->micbias.bias2_cfilt_sel;
1510 micbias_regs->mbhc_reg = SITAR_A_MICB_2_MBHC;
1511 micbias_regs->int_rbias = SITAR_A_MICB_2_INT_RBIAS;
1512 micbias_regs->ctl_reg = SITAR_A_MICB_2_CTL;
1513 break;
1514 default:
1515 /* Should never reach here */
1516 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
1517 return;
1518 }
1519
1520 micbias_regs->cfilt_sel = cfilt;
1521
1522 switch (cfilt) {
1523 case SITAR_CFILT1_SEL:
1524 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_1_VAL;
1525 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_1_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001526 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt1_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301527 break;
1528 case SITAR_CFILT2_SEL:
1529 micbias_regs->cfilt_val = SITAR_A_MICB_CFILT_2_VAL;
1530 micbias_regs->cfilt_ctl = SITAR_A_MICB_CFILT_2_CTL;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001531 sitar->mbhc_data.micb_mv = sitar->pdata->micbias.cfilt2_mv;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301532 break;
1533 }
1534}
1535
1536static int sitar_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
1537 struct snd_kcontrol *kcontrol, int event)
1538{
1539 struct snd_soc_codec *codec = w->codec;
1540
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301541 pr_debug("%s %d\n", __func__, event);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301542 switch (event) {
1543 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajare2776af12012-04-27 16:59:39 -07001544 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
1545 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301546 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
1547 0x01);
1548 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x08);
1549 usleep_range(200, 200);
1550 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x00);
1551 break;
1552 case SND_SOC_DAPM_PRE_PMD:
1553 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
1554 0x10);
1555 usleep_range(20, 20);
1556 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x08);
1557 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x10, 0x10);
1558 snd_soc_update_bits(codec, SITAR_A_CDC_CLSG_CTL, 0x08, 0x00);
1559 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_OTHR_CTL, 0x01,
1560 0x00);
1561 snd_soc_update_bits(codec, SITAR_A_CP_STATIC, 0x08, 0x00);
1562 break;
1563 }
1564 return 0;
1565}
1566
1567static const struct snd_soc_dapm_widget sitar_dapm_i2s_widgets[] = {
1568 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", SITAR_A_CDC_CLK_RX_I2S_CTL,
1569 4, 0, NULL, 0),
1570 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", SITAR_A_CDC_CLK_TX_I2S_CTL, 4,
1571 0, NULL, 0),
1572};
1573
1574static const struct snd_soc_dapm_widget sitar_dapm_widgets[] = {
1575 /*RX stuff */
1576 SND_SOC_DAPM_OUTPUT("EAR"),
1577
1578 SND_SOC_DAPM_PGA("EAR PA", SITAR_A_RX_EAR_EN, 4, 0, NULL, 0),
1579 SND_SOC_DAPM_MIXER("DAC1", SITAR_A_RX_EAR_EN, 6, 0, dac1_switch,
1580 ARRAY_SIZE(dac1_switch)),
1581 SND_SOC_DAPM_SUPPLY("EAR DRIVER", SITAR_A_RX_EAR_EN, 3, 0, NULL, 0),
1582 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
1583 0, sitar_codec_enable_slimrx,
1584 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1585 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
1586 0, sitar_codec_enable_slimrx,
1587 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1588 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1589 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1590 SND_SOC_DAPM_AIF_IN("SLIM RX5", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1591
1592 /* Headphone */
1593 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
1594 SND_SOC_DAPM_PGA_E("HPHL", SITAR_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
1595 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1596 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301597
1598 SND_SOC_DAPM_PGA_E("HPHR", SITAR_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
1599 sitar_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1600 SND_SOC_DAPM_POST_PMD),
1601
Bhalchandra Gajare66131712012-05-07 14:12:26 -07001602 SND_SOC_DAPM_DAC_E("HPHL DAC", NULL, SITAR_A_RX_HPH_L_DAC_CTL, 7, 0,
1603 sitar_hph_dac_event,
1604 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301605 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, SITAR_A_RX_HPH_R_DAC_CTL, 7, 0,
Bhalchandra Gajare66131712012-05-07 14:12:26 -07001606 sitar_hph_dac_event,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301607 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1608
1609 /* Speaker */
1610 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
1611 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
1612
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001613 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, SITAR_A_RX_LINE_1_DAC_CTL, 7, 0
1614 , sitar_lineout_dac_event,
1615 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1616 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, SITAR_A_RX_LINE_2_DAC_CTL, 7, 0
1617 , sitar_lineout_dac_event,
1618 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1619
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301620 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", SITAR_A_RX_LINE_CNP_EN, 0, 0, NULL,
1621 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1622 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1623 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", SITAR_A_RX_LINE_CNP_EN, 1, 0, NULL,
1624 0, sitar_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1625 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1626
1627 SND_SOC_DAPM_MIXER_E("RX1 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
1628 0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1629 SND_SOC_DAPM_MIXER_E("RX2 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
1630 0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1631 SND_SOC_DAPM_MIXER_E("RX3 MIX1", SITAR_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
1632 0, sitar_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1633
1634 SND_SOC_DAPM_MUX("DAC1 MUX", SND_SOC_NOPM, 0, 0,
1635 &rx_dac1_mux),
1636 SND_SOC_DAPM_MUX("DAC2 MUX", SND_SOC_NOPM, 0, 0,
1637 &rx_dac2_mux),
1638 SND_SOC_DAPM_MUX("DAC3 MUX", SND_SOC_NOPM, 0, 0,
1639 &rx_dac3_mux),
1640 SND_SOC_DAPM_MUX("DAC4 MUX", SND_SOC_NOPM, 0, 0,
1641 &rx_dac4_mux),
1642
1643 SND_SOC_DAPM_MIXER("RX1 CHAIN", SITAR_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
1644 SND_SOC_DAPM_MIXER("RX2 CHAIN", SITAR_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
1645 SND_SOC_DAPM_MIXER("RX3 CHAIN", SITAR_A_CDC_RX3_B6_CTL, 5, 0, NULL, 0),
1646
1647 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1648 &rx_mix1_inp1_mux),
1649 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1650 &rx_mix1_inp2_mux),
1651 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1652 &rx2_mix1_inp1_mux),
1653 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1654 &rx2_mix1_inp2_mux),
1655 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1656 &rx3_mix1_inp1_mux),
1657 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1658 &rx3_mix1_inp2_mux),
1659
1660 SND_SOC_DAPM_SUPPLY("CP", SITAR_A_CP_EN, 0, 0,
1661 sitar_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
1662 SND_SOC_DAPM_PRE_PMD),
1663 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
1664 sitar_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
1665 SND_SOC_DAPM_POST_PMD),
1666
1667 SND_SOC_DAPM_SUPPLY("LDO_H", SITAR_A_LDO_H_MODE_1, 7, 0,
1668 sitar_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
1669 /* TX */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001670
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301671 SND_SOC_DAPM_SUPPLY("CDC_CONN", SITAR_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
1672 0),
1673 SND_SOC_DAPM_INPUT("AMIC1"),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001674 SND_SOC_DAPM_INPUT("AMIC2"),
1675 SND_SOC_DAPM_INPUT("AMIC3"),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301676 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SITAR_A_MICB_1_CTL, 7, 0,
1677 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1678 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1679 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SITAR_A_MICB_1_CTL, 7, 0,
1680 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1681 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1682
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301683 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SITAR_A_MICB_2_CTL, 7, 0,
1684 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1685 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1686 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SITAR_A_MICB_2_CTL, 7, 0,
1687 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1688 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1689 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SITAR_A_MICB_2_CTL, 7, 0,
1690 sitar_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
1691 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1692
1693 SND_SOC_DAPM_ADC_E("ADC1", NULL, SITAR_A_TX_1_2_EN, 7, 0,
1694 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1695 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1696 SND_SOC_DAPM_ADC_E("ADC2", NULL, SITAR_A_TX_1_2_EN, 3, 0,
1697 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1698 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001699 SND_SOC_DAPM_ADC_E("ADC3", NULL, SITAR_A_TX_3_EN, 7, 0,
1700 sitar_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1701 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301702
1703 SND_SOC_DAPM_MUX_E("DEC1 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
1704 &dec1_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001705 SND_SOC_DAPM_MUX_E("DEC2 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
1706 &dec2_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
1707 SND_SOC_DAPM_MUX_E("DEC3 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
1708 &dec3_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
1709 SND_SOC_DAPM_MUX_E("DEC4 MUX", SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
1710 &dec4_mux, sitar_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301711
1712 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
1713 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
1714 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001715 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301716
1717 SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
1718 0, sitar_codec_enable_slimtx,
1719 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1720
1721 SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
1722 0, sitar_codec_enable_slimtx,
1723 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1724
1725 SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
1726 0, sitar_codec_enable_slimtx,
1727 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001728 SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
1729 0, sitar_codec_enable_slimtx,
1730 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301731
1732 /* Digital Mic Inputs */
1733 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
1734 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1735 SND_SOC_DAPM_POST_PMD),
1736 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
1737 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1738 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301739 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
1740 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1741 SND_SOC_DAPM_POST_PMD),
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301742 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
1743 sitar_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
1744 SND_SOC_DAPM_POST_PMD),
1745
1746 /* Sidetone */
1747 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
1748 SND_SOC_DAPM_PGA("IIR1", SITAR_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
1749
1750};
1751
1752static const struct snd_soc_dapm_route audio_map[] = {
1753 /* Earpiece (RX MIX1) */
1754 {"EAR", NULL, "EAR PA"},
1755 {"EAR PA", "NULL", "DAC1"},
1756 {"DAC1", "Switch", "DAC1 MUX"},
1757 {"DAC1", NULL, "CP"},
1758 {"DAC1", NULL, "EAR DRIVER"},
1759
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001760 {"CP", NULL, "RX_BIAS"},
1761
1762 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
1763 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301764
1765 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001766 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
1767 {"LINEOUT2 DAC", NULL, "DAC3 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301768
1769 {"LINEOUT1", NULL, "LINEOUT1 PA"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001770 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
1771 {"LINEOUT1 DAC", NULL, "DAC2 MUX"},
1772
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301773
1774 /* Headset (RX MIX1 and RX MIX2) */
1775 {"HEADPHONE", NULL, "HPHL"},
1776 {"HEADPHONE", NULL, "HPHR"},
1777
1778 {"HPHL", NULL, "HPHL DAC"},
Bhalchandra Gajare66131712012-05-07 14:12:26 -07001779 {"HPHL DAC", "NULL", "DAC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301780 {"HPHR", NULL, "HPHR DAC"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001781 {"HPHR DAC", NULL, "RX3 MIX1"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301782
1783 {"DAC1 MUX", "RX1", "RX1 CHAIN"},
1784 {"DAC2 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001785
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301786 {"DAC3 MUX", "RX1", "RX1 CHAIN"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001787 {"DAC3 MUX", "INV_RX1", "RX1 CHAIN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301788 {"DAC3 MUX", "RX2", "RX2 MIX1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001789
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301790 {"DAC4 MUX", "ON", "RX2 MIX1"},
1791
1792 {"RX1 CHAIN", NULL, "RX1 MIX1"},
1793
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301794 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1795 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1796 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1797 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
1798 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1799 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1800
1801 /* SLIMBUS Connections */
1802
1803 /* Slimbus port 5 is non functional in Sitar 1.0 */
1804 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
1805 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
1806 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
1807 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
1808 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1809 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
1810 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
1811 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
1812 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
1813 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1814 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
1815 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
1816 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
1817 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
1818 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
1819 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
1820 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
1821 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
1822 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
1823 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
1824 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
1825 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
1826 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
1827 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
1828 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
1829 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
1830 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
1831 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
1832 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
1833 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
1834
1835
1836 /* TX */
1837 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301838 {"SLIM TX2", NULL, "SLIM TX2 MUX"},
1839 {"SLIM TX3", NULL, "SLIM TX3 MUX"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001840 {"SLIM TX4", NULL, "SLIM TX4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301841
1842 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
1843 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
1844 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001845 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301846
1847 /* Decimator Inputs */
1848 {"DEC1 MUX", "DMIC1", "DMIC1"},
1849 {"DEC1 MUX", "DMIC4", "DMIC4"},
1850 {"DEC1 MUX", "ADC1", "ADC1"},
1851 {"DEC1 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001852 {"DEC1 MUX", "ADC3", "ADC3"},
1853 {"DEC1 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301854 {"DEC2 MUX", "DMIC2", "DMIC2"},
1855 {"DEC2 MUX", "DMIC3", "DMIC3"},
1856 {"DEC2 MUX", "ADC1", "ADC1"},
1857 {"DEC2 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001858 {"DEC2 MUX", "ADC3", "ADC3"},
1859 {"DEC2 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301860 {"DEC3 MUX", "DMIC3", "DMIC3"},
1861 {"DEC3 MUX", "ADC1", "ADC1"},
1862 {"DEC3 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001863 {"DEC3 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301864 {"DEC3 MUX", "DMIC2", "DMIC2"},
1865 {"DEC3 MUX", "DMIC3", "DMIC4"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001866 {"DEC3 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301867 {"DEC4 MUX", "DMIC4", "DMIC4"},
1868 {"DEC4 MUX", "ADC1", "ADC1"},
1869 {"DEC4 MUX", "ADC2", "ADC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001870 {"DEC4 MUX", "ADC3", "ADC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301871 {"DEC4 MUX", "DMIC3", "DMIC3"},
1872 {"DEC4 MUX", "DMIC2", "DMIC2"},
1873 {"DEC4 MUX", "DMIC1", "DMIC1"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001874 {"DEC4 MUX", NULL, "CDC_CONN"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301875
1876 /* ADC Connections */
1877 {"ADC1", NULL, "AMIC1"},
1878 {"ADC2", NULL, "AMIC2"},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001879 {"ADC3", NULL, "AMIC3"},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301880
1881 /* IIR */
1882 {"IIR1", NULL, "IIR1 INP1 MUX"},
1883 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
1884 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
1885 {"MIC BIAS1 External", NULL, "LDO_H"},
1886 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
1887 {"MIC BIAS2 External", NULL, "LDO_H"},
1888};
1889
1890static int sitar_readable(struct snd_soc_codec *ssc, unsigned int reg)
1891{
1892 return sitar_reg_readable[reg];
1893}
1894
1895static int sitar_volatile(struct snd_soc_codec *ssc, unsigned int reg)
1896{
1897 /* Registers lower than 0x100 are top level registers which can be
1898 * written by the Sitar core driver.
1899 */
1900
1901 if ((reg >= SITAR_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
1902 return 1;
1903
1904 /* IIR Coeff registers are not cacheable */
1905 if ((reg >= SITAR_A_CDC_IIR1_COEF_B1_CTL) &&
1906 (reg <= SITAR_A_CDC_IIR1_COEF_B5_CTL))
1907 return 1;
1908
1909 return 0;
1910}
1911
1912#define SITAR_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
1913static int sitar_write(struct snd_soc_codec *codec, unsigned int reg,
1914 unsigned int value)
1915{
1916 int ret;
1917
1918 BUG_ON(reg > SITAR_MAX_REGISTER);
1919
1920 if (!sitar_volatile(codec, reg)) {
1921 ret = snd_soc_cache_write(codec, reg, value);
1922 if (ret != 0)
1923 dev_err(codec->dev, "Cache write to %x failed: %d\n",
1924 reg, ret);
1925 }
1926
1927 return wcd9xxx_reg_write(codec->control_data, reg, value);
1928}
1929static unsigned int sitar_read(struct snd_soc_codec *codec,
1930 unsigned int reg)
1931{
1932 unsigned int val;
1933 int ret;
1934
1935 BUG_ON(reg > SITAR_MAX_REGISTER);
1936
1937 if (!sitar_volatile(codec, reg) && sitar_readable(codec, reg) &&
1938 reg < codec->driver->reg_cache_size) {
1939 ret = snd_soc_cache_read(codec, reg, &val);
1940 if (ret >= 0) {
1941 return val;
1942 } else
1943 dev_err(codec->dev, "Cache read from %x failed: %d\n",
1944 reg, ret);
1945 }
1946
1947 val = wcd9xxx_reg_read(codec->control_data, reg);
1948 return val;
1949}
1950
1951static void sitar_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1952{
1953
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001954 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x0C, 0x04);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301955 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x80, 0x80);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08001956 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x08);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301957 usleep_range(1000, 1000);
1958 snd_soc_write(codec, SITAR_A_BIAS_REF_CTL, 0x1C);
1959 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
1960 0x80);
1961 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x04,
1962 0x04);
1963 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
1964 0x01);
1965 usleep_range(1000, 1000);
1966 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
1967 0x00);
1968}
1969
1970static void sitar_codec_enable_bandgap(struct snd_soc_codec *codec,
1971 enum sitar_bandgap_type choice)
1972{
1973 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
1974
1975 /* TODO lock resources accessed by audio streams and threaded
1976 * interrupt handlers
1977 */
1978
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05301979 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301980 sitar->bandgap_type);
1981
1982 if (sitar->bandgap_type == choice)
1983 return;
1984
1985 if ((sitar->bandgap_type == SITAR_BANDGAP_OFF) &&
1986 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
1987 sitar_codec_enable_audio_mode_bandgap(codec);
1988 } else if (choice == SITAR_BANDGAP_MBHC_MODE) {
1989 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x2,
1990 0x2);
1991 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
1992 0x80);
1993 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x4,
1994 0x4);
1995 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x01,
1996 0x1);
1997 usleep_range(1000, 1000);
1998 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x80,
1999 0x00);
2000 } else if ((sitar->bandgap_type == SITAR_BANDGAP_MBHC_MODE) &&
2001 (choice == SITAR_BANDGAP_AUDIO_MODE)) {
2002 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
2003 usleep_range(100, 100);
2004 sitar_codec_enable_audio_mode_bandgap(codec);
2005 } else if (choice == SITAR_BANDGAP_OFF) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002006 snd_soc_update_bits(codec, SITAR_A_BIAS_CURR_CTL_2, 0x0C, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302007 snd_soc_write(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x50);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002008 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0xFF, 0x65);
2009 usleep_range(1000, 1000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302010 } else {
2011 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2012 }
2013 sitar->bandgap_type = choice;
2014}
2015
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002016static int sitar_codec_enable_config_mode(struct snd_soc_codec *codec,
2017 int enable)
2018{
2019 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2020
2021 if (enable) {
2022 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x10, 0);
2023 snd_soc_write(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x17);
2024 usleep_range(5, 5);
2025 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80,
2026 0x80);
2027 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80,
2028 0x80);
2029 usleep_range(10, 10);
2030 snd_soc_update_bits(codec, SITAR_A_RC_OSC_TEST, 0x80, 0);
2031 usleep_range(20, 20);
2032 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x08);
2033 } else {
2034 snd_soc_update_bits(codec, SITAR_A_BIAS_OSC_BG_CTL, 0x1,
2035 0);
2036 snd_soc_update_bits(codec, SITAR_A_RC_OSC_FREQ, 0x80, 0);
2037 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
2038 }
2039 sitar->config_mode_active = enable ? true : false;
2040
2041 return 0;
2042}
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302043
2044static int sitar_codec_enable_clock_block(struct snd_soc_codec *codec,
2045 int config_mode)
2046{
2047 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2048
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302049 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302050
2051 if (config_mode) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002052 sitar_codec_enable_config_mode(codec, 1);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302053 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x00);
2054 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
2055 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN1, 0x0D);
2056 usleep_range(1000, 1000);
2057 } else
2058 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x08, 0x00);
2059
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002060 if (!config_mode && sitar->mbhc_polling_active) {
2061 snd_soc_write(codec, SITAR_A_CLK_BUFF_EN2, 0x02);
2062 sitar_codec_enable_config_mode(codec, 0);
2063
2064 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302065
2066 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x05);
2067 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x00);
2068 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x04);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302069 usleep_range(50, 50);
2070 sitar->clock_active = true;
2071 return 0;
2072}
2073static void sitar_codec_disable_clock_block(struct snd_soc_codec *codec)
2074{
2075 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302076 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302077 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x04, 0x00);
2078 ndelay(160);
2079 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN2, 0x02, 0x02);
2080 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x00);
2081 sitar->clock_active = false;
2082}
2083
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002084static int sitar_codec_mclk_index(const struct sitar_priv *sitar)
2085{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002086 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002087 return 0;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002088 else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002089 return 1;
2090 else {
2091 BUG_ON(1);
2092 return -EINVAL;
2093 }
2094}
2095
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302096static void sitar_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2097{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002098 u8 *n_ready, *n_cic;
2099 struct sitar_mbhc_btn_detect_cfg *btn_det;
2100 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302101
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002102 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302103
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002104 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B1_CTL,
2105 sitar->mbhc_data.v_ins_hu & 0xFF);
2106 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B2_CTL,
2107 (sitar->mbhc_data.v_ins_hu >> 8) & 0xFF);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302108
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002109 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B3_CTL,
2110 sitar->mbhc_data.v_b1_hu & 0xFF);
2111 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B4_CTL,
2112 (sitar->mbhc_data.v_b1_hu >> 8) & 0xFF);
2113
2114 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B5_CTL,
2115 sitar->mbhc_data.v_b1_h & 0xFF);
2116 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B6_CTL,
2117 (sitar->mbhc_data.v_b1_h >> 8) & 0xFF);
2118
2119 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B9_CTL,
2120 sitar->mbhc_data.v_brh & 0xFF);
2121 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B10_CTL,
2122 (sitar->mbhc_data.v_brh >> 8) & 0xFF);
2123
2124 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B11_CTL,
2125 sitar->mbhc_data.v_brl & 0xFF);
2126 snd_soc_write(codec, SITAR_A_CDC_MBHC_VOLT_B12_CTL,
2127 (sitar->mbhc_data.v_brl >> 8) & 0xFF);
2128
2129 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
2130 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B1_CTL,
2131 n_ready[sitar_codec_mclk_index(sitar)]);
2132 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B2_CTL,
2133 sitar->mbhc_data.npoll);
2134 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B3_CTL,
2135 sitar->mbhc_data.nbounce_wait);
2136 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
2137 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL,
2138 n_cic[sitar_codec_mclk_index(sitar)]);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302139}
2140
2141static int sitar_startup(struct snd_pcm_substream *substream,
2142 struct snd_soc_dai *dai)
2143{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08002144 struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
2145 if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
2146 (wcd9xxx->dev->parent != NULL))
2147 pm_runtime_get_sync(wcd9xxx->dev->parent);
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302148 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302149 substream->name, substream->stream);
2150
2151 return 0;
2152}
2153
2154static void sitar_shutdown(struct snd_pcm_substream *substream,
2155 struct snd_soc_dai *dai)
2156{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08002157 struct wcd9xxx *wcd9xxx = dev_get_drvdata(dai->codec->dev->parent);
2158 if ((wcd9xxx != NULL) && (wcd9xxx->dev != NULL) &&
2159 (wcd9xxx->dev->parent != NULL)) {
2160 pm_runtime_mark_last_busy(wcd9xxx->dev->parent);
2161 pm_runtime_put(wcd9xxx->dev->parent);
2162 }
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302163 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302164 substream->name, substream->stream);
2165}
2166
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002167int sitar_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302168{
2169 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2170
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302171 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302172
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002173 if (dapm)
2174 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302175 if (mclk_enable) {
2176 sitar->mclk_enabled = true;
2177
2178 if (sitar->mbhc_polling_active && (sitar->mclk_enabled)) {
2179 sitar_codec_pause_hs_polling(codec);
2180 sitar_codec_enable_bandgap(codec,
2181 SITAR_BANDGAP_AUDIO_MODE);
2182 sitar_codec_enable_clock_block(codec, 0);
2183 sitar_codec_calibrate_hs_polling(codec);
2184 sitar_codec_start_hs_polling(codec);
2185 } else {
2186 sitar_codec_enable_bandgap(codec,
2187 SITAR_BANDGAP_AUDIO_MODE);
2188 sitar_codec_enable_clock_block(codec, 0);
2189 }
2190 } else {
2191
2192 if (!sitar->mclk_enabled) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002193 if (dapm)
2194 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302195 pr_err("Error, MCLK already diabled\n");
2196 return -EINVAL;
2197 }
2198 sitar->mclk_enabled = false;
2199
2200 if (sitar->mbhc_polling_active) {
2201 if (!sitar->mclk_enabled) {
2202 sitar_codec_pause_hs_polling(codec);
2203 sitar_codec_enable_bandgap(codec,
2204 SITAR_BANDGAP_MBHC_MODE);
2205 sitar_enable_rx_bias(codec, 1);
2206 sitar_codec_enable_clock_block(codec, 1);
2207 sitar_codec_calibrate_hs_polling(codec);
2208 sitar_codec_start_hs_polling(codec);
2209 }
2210 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1,
2211 0x05, 0x01);
2212 } else {
2213 sitar_codec_disable_clock_block(codec);
2214 sitar_codec_enable_bandgap(codec,
2215 SITAR_BANDGAP_OFF);
2216 }
2217 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002218 if (dapm)
2219 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302220 return 0;
2221}
2222
2223static int sitar_set_dai_sysclk(struct snd_soc_dai *dai,
2224 int clk_id, unsigned int freq, int dir)
2225{
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302226 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302227 return 0;
2228}
2229
2230static int sitar_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2231{
2232 u8 val = 0;
2233 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
2234
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302235 pr_debug("%s\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302236 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2237 case SND_SOC_DAIFMT_CBS_CFS:
2238 /* CPU is master */
2239 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2240 if (dai->id == AIF1_CAP)
2241 snd_soc_update_bits(dai->codec,
2242 SITAR_A_CDC_CLK_TX_I2S_CTL,
2243 SITAR_I2S_MASTER_MODE_MASK, 0);
2244 else if (dai->id == AIF1_PB)
2245 snd_soc_update_bits(dai->codec,
2246 SITAR_A_CDC_CLK_RX_I2S_CTL,
2247 SITAR_I2S_MASTER_MODE_MASK, 0);
2248 }
2249 break;
2250 case SND_SOC_DAIFMT_CBM_CFM:
2251 /* CPU is slave */
2252 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2253 val = SITAR_I2S_MASTER_MODE_MASK;
2254 if (dai->id == AIF1_CAP)
2255 snd_soc_update_bits(dai->codec,
2256 SITAR_A_CDC_CLK_TX_I2S_CTL, val, val);
2257 else if (dai->id == AIF1_PB)
2258 snd_soc_update_bits(dai->codec,
2259 SITAR_A_CDC_CLK_RX_I2S_CTL, val, val);
2260 }
2261 break;
2262 default:
2263 return -EINVAL;
2264 }
2265 return 0;
2266}
2267static int sitar_set_channel_map(struct snd_soc_dai *dai,
2268 unsigned int tx_num, unsigned int *tx_slot,
2269 unsigned int rx_num, unsigned int *rx_slot)
2270
2271{
2272 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
2273 u32 i = 0;
2274 if (!tx_slot && !rx_slot) {
2275 pr_err("%s: Invalid\n", __func__);
2276 return -EINVAL;
2277 }
2278 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
2279
2280 if (dai->id == AIF1_PB) {
2281 for (i = 0; i < rx_num; i++) {
2282 sitar->dai[dai->id - 1].ch_num[i] = rx_slot[i];
2283 sitar->dai[dai->id - 1].ch_act = 0;
2284 sitar->dai[dai->id - 1].ch_tot = rx_num;
2285 }
2286 } else if (dai->id == AIF1_CAP) {
2287 for (i = 0; i < tx_num; i++) {
2288 sitar->dai[dai->id - 1].ch_num[i] = tx_slot[i];
2289 sitar->dai[dai->id - 1].ch_act = 0;
2290 sitar->dai[dai->id - 1].ch_tot = tx_num;
2291 }
2292 }
2293 return 0;
2294}
2295
2296static int sitar_get_channel_map(struct snd_soc_dai *dai,
2297 unsigned int *tx_num, unsigned int *tx_slot,
2298 unsigned int *rx_num, unsigned int *rx_slot)
2299
2300{
2301 struct wcd9xxx *sitar = dev_get_drvdata(dai->codec->control_data);
2302
2303 u32 cnt = 0;
2304 u32 tx_ch[SLIM_MAX_TX_PORTS];
2305 u32 rx_ch[SLIM_MAX_RX_PORTS];
2306
2307 if (!rx_slot && !tx_slot) {
2308 pr_err("%s: Invalid\n", __func__);
2309 return -EINVAL;
2310 }
2311 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
2312 /* for virtual port, codec driver needs to do
2313 * housekeeping, for now should be ok
2314 */
2315 wcd9xxx_get_channel(sitar, rx_ch, tx_ch);
2316 if (dai->id == AIF1_PB) {
2317 *rx_num = sitar_dai[dai->id - 1].playback.channels_max;
2318 while (cnt < *rx_num) {
2319 rx_slot[cnt] = rx_ch[cnt];
2320 cnt++;
2321 }
2322 } else if (dai->id == AIF1_CAP) {
2323 *tx_num = sitar_dai[dai->id - 1].capture.channels_max;
2324 while (cnt < *tx_num) {
Bhalchandra Gajare37f4ab72012-04-10 18:52:37 -07002325 tx_slot[cnt] = tx_ch[cnt];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302326 cnt++;
2327 }
2328 }
2329 return 0;
2330}
2331
2332static int sitar_hw_params(struct snd_pcm_substream *substream,
2333 struct snd_pcm_hw_params *params,
2334 struct snd_soc_dai *dai)
2335{
2336 struct snd_soc_codec *codec = dai->codec;
2337 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(dai->codec);
2338 u8 path, shift;
2339 u16 tx_fs_reg, rx_fs_reg;
2340 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
2341
Asish Bhattacharya7147f8e2012-04-30 10:34:39 +05302342 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302343
2344 switch (params_rate(params)) {
2345 case 8000:
2346 tx_fs_rate = 0x00;
2347 rx_fs_rate = 0x00;
2348 break;
2349 case 16000:
2350 tx_fs_rate = 0x01;
2351 rx_fs_rate = 0x20;
2352 break;
2353 case 32000:
2354 tx_fs_rate = 0x02;
2355 rx_fs_rate = 0x40;
2356 break;
2357 case 48000:
2358 tx_fs_rate = 0x03;
2359 rx_fs_rate = 0x60;
2360 break;
2361 default:
2362 pr_err("%s: Invalid sampling rate %d\n", __func__,
2363 params_rate(params));
2364 return -EINVAL;
2365 }
2366
2367
2368 /**
2369 * If current dai is a tx dai, set sample rate to
2370 * all the txfe paths that are currently not active
2371 */
2372 if (dai->id == AIF1_CAP) {
2373
2374 tx_state = snd_soc_read(codec,
2375 SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL);
2376
2377 for (path = 1, shift = 0;
2378 path <= NUM_DECIMATORS; path++, shift++) {
2379
2380 if (!(tx_state & (1 << shift))) {
2381 tx_fs_reg = SITAR_A_CDC_TX1_CLK_FS_CTL
2382 + (BITS_PER_REG*(path-1));
2383 snd_soc_update_bits(codec, tx_fs_reg,
2384 0x03, tx_fs_rate);
2385 }
2386 }
2387 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2388 switch (params_format(params)) {
2389 case SNDRV_PCM_FORMAT_S16_LE:
2390 snd_soc_update_bits(codec,
2391 SITAR_A_CDC_CLK_TX_I2S_CTL,
2392 0x20, 0x20);
2393 break;
2394 case SNDRV_PCM_FORMAT_S32_LE:
2395 snd_soc_update_bits(codec,
2396 SITAR_A_CDC_CLK_TX_I2S_CTL,
2397 0x20, 0x00);
2398 break;
2399 default:
2400 pr_err("invalid format\n");
2401 break;
2402 }
2403 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_TX_I2S_CTL,
2404 0x03, tx_fs_rate);
2405 }
2406 } else {
2407 sitar->dai[dai->id - 1].rate = params_rate(params);
2408 }
2409
2410 /**
2411 * TODO: Need to handle case where same RX chain takes 2 or more inputs
2412 * with varying sample rates
2413 */
2414
2415 /**
2416 * If current dai is a rx dai, set sample rate to
2417 * all the rx paths that are currently not active
2418 */
2419 if (dai->id == AIF1_PB) {
2420
2421 rx_state = snd_soc_read(codec,
2422 SITAR_A_CDC_CLK_RX_B1_CTL);
2423
2424 for (path = 1, shift = 0;
2425 path <= NUM_INTERPOLATORS; path++, shift++) {
2426
2427 if (!(rx_state & (1 << shift))) {
2428 rx_fs_reg = SITAR_A_CDC_RX1_B5_CTL
2429 + (BITS_PER_REG*(path-1));
2430 snd_soc_update_bits(codec, rx_fs_reg,
2431 0xE0, rx_fs_rate);
2432 }
2433 }
2434 if (sitar->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2435 switch (params_format(params)) {
2436 case SNDRV_PCM_FORMAT_S16_LE:
2437 snd_soc_update_bits(codec,
2438 SITAR_A_CDC_CLK_RX_I2S_CTL,
2439 0x20, 0x20);
2440 break;
2441 case SNDRV_PCM_FORMAT_S32_LE:
2442 snd_soc_update_bits(codec,
2443 SITAR_A_CDC_CLK_RX_I2S_CTL,
2444 0x20, 0x00);
2445 break;
2446 default:
2447 pr_err("invalid format\n");
2448 break;
2449 }
2450 snd_soc_update_bits(codec, SITAR_A_CDC_CLK_RX_I2S_CTL,
2451 0x03, (rx_fs_rate >> 0x05));
2452 }
2453 } else {
2454 sitar->dai[dai->id - 1].rate = params_rate(params);
2455 }
2456
2457 return 0;
2458}
2459
2460static struct snd_soc_dai_ops sitar_dai_ops = {
2461 .startup = sitar_startup,
2462 .shutdown = sitar_shutdown,
2463 .hw_params = sitar_hw_params,
2464 .set_sysclk = sitar_set_dai_sysclk,
2465 .set_fmt = sitar_set_dai_fmt,
2466 .set_channel_map = sitar_set_channel_map,
2467 .get_channel_map = sitar_get_channel_map,
2468};
2469
2470static struct snd_soc_dai_driver sitar_dai[] = {
2471 {
2472 .name = "sitar_rx1",
2473 .id = AIF1_PB,
2474 .playback = {
2475 .stream_name = "AIF1 Playback",
2476 .rates = WCD9304_RATES,
2477 .formats = SITAR_FORMATS,
2478 .rate_max = 48000,
2479 .rate_min = 8000,
2480 .channels_min = 1,
2481 .channels_max = 2,
2482 },
2483 .ops = &sitar_dai_ops,
2484 },
2485 {
2486 .name = "sitar_tx1",
2487 .id = AIF1_CAP,
2488 .capture = {
2489 .stream_name = "AIF1 Capture",
2490 .rates = WCD9304_RATES,
2491 .formats = SITAR_FORMATS,
2492 .rate_max = 48000,
2493 .rate_min = 8000,
2494 .channels_min = 1,
2495 .channels_max = 2,
2496 },
2497 .ops = &sitar_dai_ops,
2498 },
2499};
2500
2501static int sitar_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
2502 struct snd_kcontrol *kcontrol, int event)
2503{
2504 struct wcd9xxx *sitar;
2505 struct snd_soc_codec *codec = w->codec;
2506 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
2507 u32 j = 0;
2508 codec->control_data = dev_get_drvdata(codec->dev->parent);
2509 sitar = codec->control_data;
2510 /* Execute the callback only if interface type is slimbus */
2511 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
2512 return 0;
2513 switch (event) {
2514 case SND_SOC_DAPM_POST_PMU:
2515 for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
2516 if (sitar_dai[j].id == AIF1_CAP)
2517 continue;
2518 if (!strncmp(w->sname,
2519 sitar_dai[j].playback.stream_name, 13)) {
2520 ++sitar_p->dai[j].ch_act;
2521 break;
2522 }
2523 }
2524 if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
2525 wcd9xxx_cfg_slim_sch_rx(sitar,
2526 sitar_p->dai[j].ch_num,
2527 sitar_p->dai[j].ch_tot,
2528 sitar_p->dai[j].rate);
2529 break;
2530 case SND_SOC_DAPM_POST_PMD:
2531 for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
2532 if (sitar_dai[j].id == AIF1_CAP)
2533 continue;
2534 if (!strncmp(w->sname,
2535 sitar_dai[j].playback.stream_name, 13)) {
2536 --sitar_p->dai[j].ch_act;
2537 break;
2538 }
2539 }
2540 if (!sitar_p->dai[j].ch_act) {
2541 wcd9xxx_close_slim_sch_rx(sitar,
2542 sitar_p->dai[j].ch_num,
2543 sitar_p->dai[j].ch_tot);
Bhalchandra Gajare1ff24fd2012-03-30 11:24:47 -07002544 /* Wait for remove channel to complete
2545 * before derouting Rx path
2546 */
2547 usleep_range(15000, 15000);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302548 sitar_p->dai[j].rate = 0;
2549 memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
2550 sitar_p->dai[j].ch_tot));
2551 sitar_p->dai[j].ch_tot = 0;
2552 }
2553 }
2554 return 0;
2555}
2556
2557static int sitar_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
2558 struct snd_kcontrol *kcontrol, int event)
2559{
2560 struct wcd9xxx *sitar;
2561 struct snd_soc_codec *codec = w->codec;
2562 struct sitar_priv *sitar_p = snd_soc_codec_get_drvdata(codec);
2563 /* index to the DAI ID, for now hardcoding */
2564 u32 j = 0;
2565
2566 codec->control_data = dev_get_drvdata(codec->dev->parent);
2567 sitar = codec->control_data;
2568
2569 /* Execute the callback only if interface type is slimbus */
2570 if (sitar_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
2571 return 0;
2572 switch (event) {
2573 case SND_SOC_DAPM_POST_PMU:
2574 for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
2575 if (sitar_dai[j].id == AIF1_PB)
2576 continue;
2577 if (!strncmp(w->sname,
2578 sitar_dai[j].capture.stream_name, 13)) {
2579 ++sitar_p->dai[j].ch_act;
2580 break;
2581 }
2582 }
2583 if (sitar_p->dai[j].ch_act == sitar_p->dai[j].ch_tot)
2584 wcd9xxx_cfg_slim_sch_tx(sitar,
2585 sitar_p->dai[j].ch_num,
2586 sitar_p->dai[j].ch_tot,
2587 sitar_p->dai[j].rate);
2588 break;
2589 case SND_SOC_DAPM_POST_PMD:
2590 for (j = 0; j < ARRAY_SIZE(sitar_dai); j++) {
2591 if (sitar_dai[j].id == AIF1_PB)
2592 continue;
2593 if (!strncmp(w->sname,
2594 sitar_dai[j].capture.stream_name, 13)) {
2595 --sitar_p->dai[j].ch_act;
2596 break;
2597 }
2598 }
2599 if (!sitar_p->dai[j].ch_act) {
2600 wcd9xxx_close_slim_sch_tx(sitar,
2601 sitar_p->dai[j].ch_num,
2602 sitar_p->dai[j].ch_tot);
2603 sitar_p->dai[j].rate = 0;
2604 memset(sitar_p->dai[j].ch_num, 0, (sizeof(u32)*
2605 sitar_p->dai[j].ch_tot));
2606 sitar_p->dai[j].ch_tot = 0;
2607 }
2608 }
2609 return 0;
2610}
2611
2612
2613static short sitar_codec_read_sta_result(struct snd_soc_codec *codec)
2614{
2615 u8 bias_msb, bias_lsb;
2616 short bias_value;
2617
2618 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B3_STATUS);
2619 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B2_STATUS);
2620 bias_value = (bias_msb << 8) | bias_lsb;
2621 return bias_value;
2622}
2623
2624static short sitar_codec_read_dce_result(struct snd_soc_codec *codec)
2625{
2626 u8 bias_msb, bias_lsb;
2627 short bias_value;
2628
2629 bias_msb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B5_STATUS);
2630 bias_lsb = snd_soc_read(codec, SITAR_A_CDC_MBHC_B4_STATUS);
2631 bias_value = (bias_msb << 8) | bias_lsb;
2632 return bias_value;
2633}
2634
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002635static void sitar_turn_onoff_rel_detection(struct snd_soc_codec *codec,
2636 bool on)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302637{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002638 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
2639}
2640
2641static short __sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
2642 bool override_bypass, bool noreldetection)
2643{
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302644 short bias_value;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002645 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2646
2647 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
2648 if (noreldetection)
2649 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302650
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002651 /* Turn on the override */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002652 if (!override_bypass)
2653 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302654 if (dce) {
2655 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2656 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
2657 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002658 usleep_range(sitar->mbhc_data.t_sta_dce,
2659 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302660 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x4);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002661 usleep_range(sitar->mbhc_data.t_dce,
2662 sitar->mbhc_data.t_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302663 bias_value = sitar_codec_read_dce_result(codec);
2664 } else {
2665 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2666 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
2667 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002668 usleep_range(sitar->mbhc_data.t_sta_dce,
2669 sitar->mbhc_data.t_sta_dce);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302670 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x2);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002671 usleep_range(sitar->mbhc_data.t_sta,
2672 sitar->mbhc_data.t_sta);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302673 bias_value = sitar_codec_read_sta_result(codec);
2674 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2675 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x0);
2676 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002677 /* Turn off the override after measuring mic voltage */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002678 if (!override_bypass)
2679 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
2680
2681 if (noreldetection)
2682 sitar_turn_onoff_rel_detection(codec, true);
2683 wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302684
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302685 return bias_value;
2686}
2687
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002688static short sitar_codec_sta_dce(struct snd_soc_codec *codec, int dce,
2689 bool norel)
2690{
2691 return __sitar_codec_sta_dce(codec, dce, false, norel);
2692}
2693
2694static void sitar_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
2695{
2696 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2697 const struct sitar_mbhc_general_cfg *generic =
2698 SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
2699
2700 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
2701 sitar_codec_enable_config_mode(codec, 1);
2702
2703 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2704 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
2705
2706 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
2707
2708 usleep_range(generic->t_shutdown_plug_rem,
2709 generic->t_shutdown_plug_rem);
2710
2711 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
2712 if (!sitar->mclk_enabled && !sitar->mbhc_polling_active)
2713 sitar_codec_enable_config_mode(codec, 0);
2714
2715 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x00);
2716}
2717
2718static void sitar_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
2719{
2720 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
2721
2722 sitar_codec_shutdown_hs_removal_detect(codec);
2723
2724 if (!sitar->mclk_enabled) {
2725 sitar_codec_disable_clock_block(codec);
2726 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
2727 }
2728
2729 sitar->mbhc_polling_active = false;
2730 sitar->mbhc_state = MBHC_STATE_NONE;
2731}
2732
2733/* called only from interrupt which is under codec_resource_lock acquisition */
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302734static short sitar_codec_setup_hs_polling(struct snd_soc_codec *codec)
2735{
2736 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302737 short bias_value;
2738 u8 cfilt_mode;
2739
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002740 if (!sitar->mbhc_cfg.calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302741 pr_err("Error, no sitar calibration\n");
2742 return -ENODEV;
2743 }
2744
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302745 if (!sitar->mclk_enabled) {
2746 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_MBHC_MODE);
2747 sitar_enable_rx_bias(codec, 1);
2748 sitar_codec_enable_clock_block(codec, 1);
2749 }
2750
2751 snd_soc_update_bits(codec, SITAR_A_CLK_BUFF_EN1, 0x05, 0x01);
2752
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302753 /* Make sure CFILT is in fast mode, save current mode */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002754 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
2755 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
2756
2757 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302758
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302759 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2760 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
2761
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002762 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x80);
2763 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x1F, 0x1C);
2764 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x40, 0x40);
2765
2766 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN, 0x80, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302767 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2768 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
2769
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002770 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302771 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2772
2773 sitar_codec_calibrate_hs_polling(codec);
2774
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002775 /* don't flip override */
2776 bias_value = __sitar_codec_sta_dce(codec, 1, true, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002777 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
2778 cfilt_mode);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302779 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
2780
2781 return bias_value;
2782}
2783
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002784static int sitar_cancel_btn_work(struct sitar_priv *sitar)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302785{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002786 int r = 0;
2787 struct wcd9xxx *core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302788
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002789 if (cancel_delayed_work_sync(&sitar->mbhc_btn_dwork)) {
2790 /* if scheduled mbhc_btn_dwork is canceled from here,
2791 * we have to unlock from here instead btn_work */
2792 wcd9xxx_unlock_sleep(core);
2793 r = 1;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302794 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002795 return r;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302796}
2797
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002798
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002799static u16 sitar_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
2800 s16 vin_mv)
2801{
2802 short diff, zero;
2803 struct sitar_priv *sitar;
2804 u32 mb_mv, in;
2805
2806 sitar = snd_soc_codec_get_drvdata(codec);
2807 mb_mv = sitar->mbhc_data.micb_mv;
2808
2809 if (mb_mv == 0) {
2810 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
2811 return -EINVAL;
2812 }
2813
2814 if (dce) {
2815 diff = sitar->mbhc_data.dce_mb - sitar->mbhc_data.dce_z;
2816 zero = sitar->mbhc_data.dce_z;
2817 } else {
2818 diff = sitar->mbhc_data.sta_mb - sitar->mbhc_data.sta_z;
2819 zero = sitar->mbhc_data.sta_z;
2820 }
2821 in = (u32) diff * vin_mv;
2822
2823 return (u16) (in / mb_mv) + zero;
2824}
2825
2826static s32 sitar_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
2827 u16 bias_value)
2828{
2829 struct sitar_priv *sitar;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002830 s16 value, z, mb;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002831 s32 mv;
2832
2833 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002834 value = bias_value;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002835
2836 if (dce) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002837 z = (sitar->mbhc_data.dce_z);
2838 mb = (sitar->mbhc_data.dce_mb);
2839 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002840 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002841 z = (sitar->mbhc_data.sta_z);
2842 mb = (sitar->mbhc_data.sta_mb);
2843 mv = (value - z) * (s32)sitar->mbhc_data.micb_mv / (mb - z);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002844 }
2845
2846 return mv;
2847}
2848
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002849static void btn_lpress_fn(struct work_struct *work)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302850{
2851 struct delayed_work *delayed_work;
2852 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002853 short bias_value;
2854 int dce_mv, sta_mv;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002855 struct wcd9xxx *core;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302856
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002857 pr_debug("%s:\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302858
2859 delayed_work = to_delayed_work(work);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002860 sitar = container_of(delayed_work, struct sitar_priv, mbhc_btn_dwork);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002861 core = dev_get_drvdata(sitar->codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302862
2863 if (sitar) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002864 if (sitar->mbhc_cfg.button_jack) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002865 bias_value = sitar_codec_read_sta_result(sitar->codec);
2866 sta_mv = sitar_codec_sta_dce_v(sitar->codec, 0,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002867 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002868 bias_value = sitar_codec_read_dce_result(sitar->codec);
2869 dce_mv = sitar_codec_sta_dce_v(sitar->codec, 1,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002870 bias_value);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002871 pr_debug("%s: Reporting long button press event"
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002872 " STA: %d, DCE: %d\n", __func__, sta_mv, dce_mv);
2873 sitar_snd_soc_jack_report(sitar,
2874 sitar->mbhc_cfg.button_jack,
2875 sitar->buttons_pressed,
2876 sitar->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302877 }
2878 } else {
2879 pr_err("%s: Bad sitar private data\n", __func__);
2880 }
2881
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002882 pr_debug("%s: leave\n", __func__);
2883 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302884}
2885
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002886
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002887void sitar_mbhc_cal(struct snd_soc_codec *codec)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05302888{
2889 struct sitar_priv *sitar;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002890 struct sitar_mbhc_btn_detect_cfg *btn_det;
2891 u8 cfilt_mode, bg_mode;
2892 u8 ncic, nmeas, navg;
2893 u32 mclk_rate;
2894 u32 dce_wait, sta_wait;
2895 u8 *n_cic;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002896 void *calibration;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002897
2898 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002899 calibration = sitar->mbhc_cfg.calibration;
2900
2901 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
2902 sitar_turn_onoff_rel_detection(codec, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002903
2904 /* First compute the DCE / STA wait times
2905 * depending on tunable parameters.
2906 * The value is computed in microseconds
2907 */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002908 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002909 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
2910 ncic = n_cic[sitar_codec_mclk_index(sitar)];
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002911 nmeas = SITAR_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
2912 navg = SITAR_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
2913 mclk_rate = sitar->mbhc_cfg.mclk_rate;
2914 dce_wait = (1000 * 512 * 60 * (nmeas + 1)) / (mclk_rate / 1000);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002915 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
2916
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002917 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
2918 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002919
2920 /* LDOH and CFILT are already configured during pdata handling.
2921 * Only need to make sure CFILT and bandgap are in Fast mode.
2922 * Need to restore defaults once calculation is done.
2923 */
2924 cfilt_mode = snd_soc_read(codec, sitar->mbhc_bias_regs.cfilt_ctl);
2925 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
2926 bg_mode = snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02,
2927 0x02);
2928
2929 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
2930 * to perform ADC calibration
2931 */
2932 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x60,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002933 sitar->mbhc_cfg.micbias << 5);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002934 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
2935 snd_soc_update_bits(codec, SITAR_A_LDO_H_MODE_1, 0x60, 0x60);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002936 snd_soc_write(codec, SITAR_A_TX_4_MBHC_TEST_CTL, 0x78);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002937 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
2938
2939 /* DCE measurement for 0 volts */
2940 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
2941 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
2942 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
2943 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
2944 usleep_range(100, 100);
2945 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
2946 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
2947 sitar->mbhc_data.dce_z = sitar_codec_read_dce_result(codec);
2948
2949 /* DCE measurment for MB voltage */
2950 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
2951 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
2952 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
2953 usleep_range(100, 100);
2954 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x04);
2955 usleep_range(sitar->mbhc_data.t_dce, sitar->mbhc_data.t_dce);
2956 sitar->mbhc_data.dce_mb = sitar_codec_read_dce_result(codec);
2957
2958 /* Sta measuremnt for 0 volts */
2959 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x0A);
2960 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
2961 snd_soc_write(codec, SITAR_A_CDC_MBHC_CLK_CTL, 0x02);
2962 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x81);
2963 usleep_range(100, 100);
2964 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
2965 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
2966 sitar->mbhc_data.sta_z = sitar_codec_read_sta_result(codec);
2967
2968 /* STA Measurement for MB Voltage */
2969 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x82);
2970 usleep_range(100, 100);
2971 snd_soc_write(codec, SITAR_A_CDC_MBHC_EN_CTL, 0x02);
2972 usleep_range(sitar->mbhc_data.t_sta, sitar->mbhc_data.t_sta);
2973 sitar->mbhc_data.sta_mb = sitar_codec_read_sta_result(codec);
2974
2975 /* Restore default settings. */
2976 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
2977 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl, 0x40,
2978 cfilt_mode);
2979 snd_soc_update_bits(codec, SITAR_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
2980
2981 snd_soc_write(codec, SITAR_A_MBHC_SCALING_MUX_1, 0x84);
2982 usleep_range(100, 100);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07002983
2984 wcd9xxx_enable_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL);
2985 sitar_turn_onoff_rel_detection(codec, true);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08002986}
2987
2988void *sitar_mbhc_cal_btn_det_mp(const struct sitar_mbhc_btn_detect_cfg* btn_det,
2989 const enum sitar_mbhc_btn_det_mem mem)
2990{
2991 void *ret = &btn_det->_v_btn_low;
2992
2993 switch (mem) {
2994 case SITAR_BTN_DET_GAIN:
2995 ret += sizeof(btn_det->_n_cic);
2996 case SITAR_BTN_DET_N_CIC:
2997 ret += sizeof(btn_det->_n_ready);
2998 case SITAR_BTN_DET_N_READY:
2999 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
3000 case SITAR_BTN_DET_V_BTN_HIGH:
3001 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
3002 case SITAR_BTN_DET_V_BTN_LOW:
3003 /* do nothing */
3004 break;
3005 default:
3006 ret = NULL;
3007 }
3008
3009 return ret;
3010}
3011
3012static void sitar_mbhc_calc_thres(struct snd_soc_codec *codec)
3013{
3014 struct sitar_priv *sitar;
3015 s16 btn_mv = 0, btn_delta_mv;
3016 struct sitar_mbhc_btn_detect_cfg *btn_det;
3017 struct sitar_mbhc_plug_type_cfg *plug_type;
3018 u16 *btn_high;
3019 u8 *n_ready;
3020 int i;
3021
3022 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003023 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
3024 plug_type = SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003025
3026 n_ready = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_READY);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003027 if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_12288KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003028 sitar->mbhc_data.npoll = 9;
3029 sitar->mbhc_data.nbounce_wait = 30;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003030 } else if (sitar->mbhc_cfg.mclk_rate == SITAR_MCLK_RATE_9600KHZ) {
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003031 sitar->mbhc_data.npoll = 7;
3032 sitar->mbhc_data.nbounce_wait = 23;
3033 }
3034
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003035 sitar->mbhc_data.t_sta_dce = ((1000 * 256) /
3036 (sitar->mbhc_cfg.mclk_rate / 1000) *
3037 n_ready[sitar_codec_mclk_index(sitar)]) +
3038 10;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003039 sitar->mbhc_data.v_ins_hu =
3040 sitar_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
3041 sitar->mbhc_data.v_ins_h =
3042 sitar_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
3043
3044 btn_high = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_HIGH);
3045 for (i = 0; i < btn_det->num_btn; i++)
3046 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
3047
3048 sitar->mbhc_data.v_b1_h = sitar_codec_v_sta_dce(codec, DCE, btn_mv);
3049 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
3050
3051 sitar->mbhc_data.v_b1_hu =
3052 sitar_codec_v_sta_dce(codec, STA, btn_delta_mv);
3053
3054 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
3055
3056 sitar->mbhc_data.v_b1_huc =
3057 sitar_codec_v_sta_dce(codec, DCE, btn_delta_mv);
3058
3059 sitar->mbhc_data.v_brh = sitar->mbhc_data.v_b1_h;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003060 sitar->mbhc_data.v_brl = SITAR_MBHC_BUTTON_MIN;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003061
3062 sitar->mbhc_data.v_no_mic =
3063 sitar_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
3064}
3065
3066void sitar_mbhc_init(struct snd_soc_codec *codec)
3067{
3068 struct sitar_priv *sitar;
3069 struct sitar_mbhc_general_cfg *generic;
3070 struct sitar_mbhc_btn_detect_cfg *btn_det;
3071 int n;
3072 u8 *n_cic, *gain;
3073
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003074 pr_err("%s(): ENTER\n", __func__);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003075 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003076 generic = SITAR_MBHC_CAL_GENERAL_PTR(sitar->mbhc_cfg.calibration);
3077 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(sitar->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003078
3079 for (n = 0; n < 8; n++) {
3080 if (n != 7) {
3081 snd_soc_update_bits(codec,
3082 SITAR_A_CDC_MBHC_FIR_B1_CFG,
3083 0x07, n);
3084 snd_soc_write(codec, SITAR_A_CDC_MBHC_FIR_B2_CFG,
3085 btn_det->c[n]);
3086 }
3087 }
3088 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x07,
3089 btn_det->nc);
3090
3091 n_cic = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_N_CIC);
3092 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
3093 n_cic[sitar_codec_mclk_index(sitar)]);
3094
3095 gain = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_GAIN);
3096 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B2_CTL, 0x78,
3097 gain[sitar_codec_mclk_index(sitar)] << 3);
3098
3099 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
3100 generic->mbhc_nsa << 4);
3101
3102 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
3103 btn_det->n_meas);
3104
3105 snd_soc_write(codec, SITAR_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
3106
3107 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
3108
3109 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x78,
3110 btn_det->mbhc_nsc << 3);
3111
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003112 snd_soc_update_bits(codec, SITAR_A_MICB_1_MBHC, 0x03,
3113 sitar->mbhc_cfg.micbias);
3114
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003115 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003116
3117 snd_soc_update_bits(codec, SITAR_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
3118
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003119}
3120
3121static bool sitar_mbhc_fw_validate(const struct firmware *fw)
3122{
3123 u32 cfg_offset;
3124 struct sitar_mbhc_imped_detect_cfg *imped_cfg;
3125 struct sitar_mbhc_btn_detect_cfg *btn_cfg;
3126
3127 if (fw->size < SITAR_MBHC_CAL_MIN_SIZE)
3128 return false;
3129
3130 /* previous check guarantees that there is enough fw data up
3131 * to num_btn
3132 */
3133 btn_cfg = SITAR_MBHC_CAL_BTN_DET_PTR(fw->data);
3134 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
3135 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_BTN_SZ(btn_cfg)))
3136 return false;
3137
3138 /* previous check guarantees that there is enough fw data up
3139 * to start of impedance detection configuration
3140 */
3141 imped_cfg = SITAR_MBHC_CAL_IMPED_DET_PTR(fw->data);
3142 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
3143
3144 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_MIN_SZ))
3145 return false;
3146
3147 if (fw->size < (cfg_offset + SITAR_MBHC_CAL_IMPED_SZ(imped_cfg)))
3148 return false;
3149
3150 return true;
3151}
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003152
3153
3154static void sitar_turn_onoff_override(struct snd_soc_codec *codec, bool on)
3155{
3156 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
3157}
3158
3159/* called under codec_resource_lock acquisition */
3160void sitar_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
3161{
3162 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3163 u8 wg_time;
3164
3165 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
3166 wg_time += 1;
3167
3168 /* If headphone PA is on, check if userspace receives
3169 * removal event to sync-up PA's state */
3170 if (sitar_is_hph_pa_on(codec)) {
3171 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
3172 set_bit(SITAR_HPHL_PA_OFF_ACK, &sitar->hph_pa_dac_state);
3173 set_bit(SITAR_HPHR_PA_OFF_ACK, &sitar->hph_pa_dac_state);
3174 } else {
3175 pr_debug("%s PA is off\n", __func__);
3176 }
3177
3178 if (sitar_is_hph_dac_on(codec, 1))
3179 set_bit(SITAR_HPHL_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
3180 if (sitar_is_hph_dac_on(codec, 0))
3181 set_bit(SITAR_HPHR_DAC_OFF_ACK, &sitar->hph_pa_dac_state);
3182
3183 snd_soc_update_bits(codec, SITAR_A_RX_HPH_CNP_EN, 0x30, 0x00);
3184 snd_soc_update_bits(codec, SITAR_A_RX_HPH_L_DAC_CTL,
3185 0xC0, 0x00);
3186 snd_soc_update_bits(codec, SITAR_A_RX_HPH_R_DAC_CTL,
3187 0xC0, 0x00);
3188 usleep_range(wg_time * 1000, wg_time * 1000);
3189}
3190
3191static void sitar_clr_and_turnon_hph_padac(struct sitar_priv *sitar)
3192{
3193 bool pa_turned_on = false;
3194 struct snd_soc_codec *codec = sitar->codec;
3195 u8 wg_time;
3196
3197 wg_time = snd_soc_read(codec, SITAR_A_RX_HPH_CNP_WG_TIME) ;
3198 wg_time += 1;
3199
3200 if (test_and_clear_bit(SITAR_HPHR_DAC_OFF_ACK,
3201 &sitar->hph_pa_dac_state)) {
3202 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
3203 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_R_DAC_CTL,
3204 0xC0, 0xC0);
3205 }
3206 if (test_and_clear_bit(SITAR_HPHL_DAC_OFF_ACK,
3207 &sitar->hph_pa_dac_state)) {
3208 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
3209 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_L_DAC_CTL,
3210 0xC0, 0xC0);
3211 }
3212
3213 if (test_and_clear_bit(SITAR_HPHR_PA_OFF_ACK,
3214 &sitar->hph_pa_dac_state)) {
3215 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
3216 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x10,
3217 1 << 4);
3218 pa_turned_on = true;
3219 }
3220 if (test_and_clear_bit(SITAR_HPHL_PA_OFF_ACK,
3221 &sitar->hph_pa_dac_state)) {
3222 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
3223 snd_soc_update_bits(sitar->codec, SITAR_A_RX_HPH_CNP_EN, 0x20,
3224 1 << 5);
3225 pa_turned_on = true;
3226 }
3227
3228 if (pa_turned_on) {
3229 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
3230 __func__);
3231 usleep_range(wg_time * 1000, wg_time * 1000);
3232 }
3233}
3234
3235static void sitar_codec_report_plug(struct snd_soc_codec *codec, int insertion,
3236 enum snd_jack_types jack_type)
3237{
3238 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3239
3240 if (!insertion) {
3241 /* Report removal */
3242 sitar->hph_status &= ~jack_type;
3243 if (sitar->mbhc_cfg.headset_jack) {
3244 /* cancel possibly scheduled btn work and
3245 * report release if we reported button press */
3246 if (sitar_cancel_btn_work(sitar)) {
3247 pr_debug("%s: button press is canceled\n",
3248 __func__);
3249 } else if (sitar->buttons_pressed) {
3250 pr_debug("%s: Reporting release for reported "
3251 "button press %d\n", __func__,
3252 jack_type);
3253 sitar_snd_soc_jack_report(sitar,
3254 sitar->mbhc_cfg.button_jack, 0,
3255 sitar->buttons_pressed);
3256 sitar->buttons_pressed &=
3257 ~SITAR_JACK_BUTTON_MASK;
3258 }
3259 pr_debug("%s: Reporting removal %d\n", __func__,
3260 jack_type);
3261 sitar_snd_soc_jack_report(sitar,
3262 sitar->mbhc_cfg.headset_jack,
3263 sitar->hph_status,
3264 SITAR_JACK_MASK);
3265 }
3266 sitar_set_and_turnoff_hph_padac(codec);
3267 hphocp_off_report(sitar, SND_JACK_OC_HPHR,
3268 SITAR_IRQ_HPH_PA_OCPR_FAULT);
3269 hphocp_off_report(sitar, SND_JACK_OC_HPHL,
3270 SITAR_IRQ_HPH_PA_OCPL_FAULT);
3271 sitar->current_plug = PLUG_TYPE_NONE;
3272 sitar->mbhc_polling_active = false;
3273 } else {
3274 /* Report insertion */
3275 sitar->hph_status |= jack_type;
3276
3277 if (jack_type == SND_JACK_HEADPHONE)
3278 sitar->current_plug = PLUG_TYPE_HEADPHONE;
3279 else if (jack_type == SND_JACK_HEADSET) {
3280 sitar->mbhc_polling_active = true;
3281 sitar->current_plug = PLUG_TYPE_HEADSET;
3282 }
3283 if (sitar->mbhc_cfg.headset_jack) {
3284 pr_debug("%s: Reporting insertion %d\n", __func__,
3285 jack_type);
3286 sitar_snd_soc_jack_report(sitar,
3287 sitar->mbhc_cfg.headset_jack,
3288 sitar->hph_status,
3289 SITAR_JACK_MASK);
3290 }
3291 sitar_clr_and_turnon_hph_padac(sitar);
3292 }
3293}
3294
3295
3296static bool sitar_hs_gpio_level_remove(struct sitar_priv *sitar)
3297{
3298 return (gpio_get_value_cansleep(sitar->mbhc_cfg.gpio) !=
3299 sitar->mbhc_cfg.gpio_level_insert);
3300}
3301
3302static bool sitar_is_invalid_insert_delta(struct snd_soc_codec *codec,
3303 int mic_volt, int mic_volt_prev)
3304{
3305 int delta = abs(mic_volt - mic_volt_prev);
3306 if (delta > SITAR_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
3307 pr_debug("%s: volt delta %dmv\n", __func__, delta);
3308 return true;
3309 }
3310 return false;
3311}
3312
3313static bool sitar_is_invalid_insertion_range(struct snd_soc_codec *codec,
3314 s32 mic_volt)
3315{
3316 bool invalid = false;
3317
3318 if (mic_volt < SITAR_MBHC_FAKE_INSERT_HIGH
3319 && (mic_volt > SITAR_MBHC_FAKE_INSERT_LOW)) {
3320 invalid = true;
3321 }
3322
3323 return invalid;
3324}
3325
3326static bool sitar_codec_is_invalid_plug(struct snd_soc_codec *codec,
3327 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
3328 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT])
3329{
3330 int i;
3331 bool r = false;
3332 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3333 struct sitar_mbhc_plug_type_cfg *plug_type_ptr =
3334 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
3335
3336 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
3337 if (mic_mv[i] < plug_type_ptr->v_no_mic)
3338 plug_type[i] = PLUG_TYPE_HEADPHONE;
3339 else if (mic_mv[i] < plug_type_ptr->v_hs_max)
3340 plug_type[i] = PLUG_TYPE_HEADSET;
3341 else if (mic_mv[i] > plug_type_ptr->v_hs_max)
3342 plug_type[i] = PLUG_TYPE_HIGH_HPH;
3343
3344 r = sitar_is_invalid_insertion_range(codec, mic_mv[i]);
3345 if (!r && i > 0) {
3346 if (plug_type[i-1] != plug_type[i])
3347 r = true;
3348 else
3349 r = sitar_is_invalid_insert_delta(codec,
3350 mic_mv[i],
3351 mic_mv[i - 1]);
3352 }
3353 }
3354
3355 return r;
3356}
3357
3358/* called under codec_resource_lock acquisition */
3359void sitar_find_plug_and_report(struct snd_soc_codec *codec,
3360 enum sitar_mbhc_plug_type plug_type)
3361{
3362 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3363
3364 if (plug_type == PLUG_TYPE_HEADPHONE
3365 && sitar->current_plug == PLUG_TYPE_NONE) {
3366 /* Nothing was reported previously
3367 * reporte a headphone
3368 */
3369 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
3370 sitar_codec_cleanup_hs_polling(codec);
3371 } else if (plug_type == PLUG_TYPE_HEADSET) {
3372 /* If Headphone was reported previously, this will
3373 * only report the mic line
3374 */
3375 sitar_codec_report_plug(codec, 1, SND_JACK_HEADSET);
3376 msleep(100);
3377 sitar_codec_start_hs_polling(codec);
3378 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
3379 if (sitar->current_plug == PLUG_TYPE_NONE)
3380 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
3381 sitar_codec_cleanup_hs_polling(codec);
3382 pr_debug("setup mic trigger for further detection\n");
3383 sitar->lpi_enabled = true;
3384 /* TODO ::: sitar_codec_enable_hs_detect */
3385 pr_err("%s(): High impedence hph not supported\n", __func__);
3386 }
3387}
3388
3389/* should be called under interrupt context that hold suspend */
3390static void sitar_schedule_hs_detect_plug(struct sitar_priv *sitar)
3391{
3392 pr_debug("%s: scheduling sitar_hs_correct_gpio_plug\n", __func__);
3393 sitar->hs_detect_work_stop = false;
3394 wcd9xxx_lock_sleep(sitar->codec->control_data);
3395 schedule_work(&sitar->hs_correct_plug_work);
3396}
3397
3398/* called under codec_resource_lock acquisition */
3399static void sitar_cancel_hs_detect_plug(struct sitar_priv *sitar)
3400{
3401 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
3402 sitar->hs_detect_work_stop = true;
3403 wmb();
3404 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
3405 if (cancel_work_sync(&sitar->hs_correct_plug_work)) {
3406 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
3407 wcd9xxx_unlock_sleep(sitar->codec->control_data);
3408 }
3409 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
3410}
3411
3412static void sitar_hs_correct_gpio_plug(struct work_struct *work)
3413{
3414 struct sitar_priv *sitar;
3415 struct snd_soc_codec *codec;
3416 int retry = 0, i;
3417 bool correction = false;
3418 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
3419 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
3420 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
3421 unsigned long timeout;
3422
3423 sitar = container_of(work, struct sitar_priv, hs_correct_plug_work);
3424 codec = sitar->codec;
3425
3426 pr_debug("%s: enter\n", __func__);
3427 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
3428
3429 /* Keep override on during entire plug type correction work.
3430 *
3431 * This is okay under the assumption that any GPIO irqs which use
3432 * MBHC block cancel and sync this work so override is off again
3433 * prior to GPIO interrupt handler's MBHC block usage.
3434 * Also while this correction work is running, we can guarantee
3435 * DAPM doesn't use any MBHC block as this work only runs with
3436 * headphone detection.
3437 */
3438 sitar_turn_onoff_override(codec, true);
3439
3440 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
3441 while (!time_after(jiffies, timeout)) {
3442 ++retry;
3443 rmb();
3444 if (sitar->hs_detect_work_stop) {
3445 pr_debug("%s: stop requested\n", __func__);
3446 break;
3447 }
3448
3449 msleep(SITAR_HS_DETECT_PLUG_INERVAL_MS);
3450 if (sitar_hs_gpio_level_remove(sitar)) {
3451 pr_debug("%s: GPIO value is low\n", __func__);
3452 break;
3453 }
3454
3455 /* can race with removal interrupt */
3456 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
3457 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
3458 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
3459 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
3460 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
3461 __func__, retry, mic_mv[i], mb_v[i]);
3462 }
3463 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
3464
3465 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
3466 pr_debug("Invalid plug in attempt # %d\n", retry);
3467 if (retry == NUM_ATTEMPTS_TO_REPORT &&
3468 sitar->current_plug == PLUG_TYPE_NONE) {
3469 sitar_codec_report_plug(codec, 1,
3470 SND_JACK_HEADPHONE);
3471 }
3472 } else if (!sitar_codec_is_invalid_plug(codec, mic_mv,
3473 plug_type) &&
3474 plug_type[0] == PLUG_TYPE_HEADPHONE) {
3475 pr_debug("Good headphone detected, continue polling mic\n");
3476 if (sitar->current_plug == PLUG_TYPE_NONE) {
3477 sitar_codec_report_plug(codec, 1,
3478 SND_JACK_HEADPHONE);
3479 }
3480 } else {
3481 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
3482 /* Turn off override */
3483 sitar_turn_onoff_override(codec, false);
3484 sitar_find_plug_and_report(codec, plug_type[0]);
3485 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
3486 pr_debug("Attempt %d found correct plug %d\n", retry,
3487 plug_type[0]);
3488 correction = true;
3489 break;
3490 }
3491 }
3492
3493 /* Turn off override */
3494 if (!correction)
3495 sitar_turn_onoff_override(codec, false);
3496
3497 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
3498 pr_debug("%s: leave\n", __func__);
3499 /* unlock sleep */
3500 wcd9xxx_unlock_sleep(sitar->codec->control_data);
3501}
3502
3503/* called under codec_resource_lock acquisition */
3504static void sitar_codec_decide_gpio_plug(struct snd_soc_codec *codec)
3505{
3506 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3507 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
3508 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
3509 enum sitar_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
3510 int i;
3511
3512 pr_debug("%s: enter\n", __func__);
3513
3514 sitar_turn_onoff_override(codec, true);
3515 mb_v[0] = sitar_codec_setup_hs_polling(codec);
3516 mic_mv[0] = sitar_codec_sta_dce_v(codec, 1, mb_v[0]);
3517 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
3518
3519 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
3520 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
3521 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
3522 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
3523 mic_mv[i]);
3524 }
3525 sitar_turn_onoff_override(codec, false);
3526
3527 if (sitar_hs_gpio_level_remove(sitar)) {
3528 pr_debug("%s: GPIO value is low when determining plug\n",
3529 __func__);
3530 return;
3531 }
3532
3533 if (sitar_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
3534 sitar_schedule_hs_detect_plug(sitar);
3535 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
3536 sitar_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
3537 sitar_schedule_hs_detect_plug(sitar);
3538 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
3539 pr_debug("%s: Valid plug found, determine plug type\n",
3540 __func__);
3541 sitar_find_plug_and_report(codec, plug_type[0]);
3542 }
3543
3544}
3545
3546/* called under codec_resource_lock acquisition */
3547static void sitar_codec_detect_plug_type(struct snd_soc_codec *codec)
3548{
3549 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3550 const struct sitar_mbhc_plug_detect_cfg *plug_det =
3551 SITAR_MBHC_CAL_PLUG_DET_PTR(sitar->mbhc_cfg.calibration);
3552
3553 if (plug_det->t_ins_complete > 20)
3554 msleep(plug_det->t_ins_complete);
3555 else
3556 usleep_range(plug_det->t_ins_complete * 1000,
3557 plug_det->t_ins_complete * 1000);
3558
3559 if (sitar_hs_gpio_level_remove(sitar))
3560 pr_debug("%s: GPIO value is low when determining "
3561 "plug\n", __func__);
3562 else
3563 sitar_codec_decide_gpio_plug(codec);
3564
3565 return;
3566}
3567
3568static void sitar_hs_gpio_handler(struct snd_soc_codec *codec)
3569{
3570 bool insert;
3571 struct sitar_priv *priv = snd_soc_codec_get_drvdata(codec);
3572 bool is_removed = false;
3573
3574 pr_debug("%s: enter\n", __func__);
3575
3576 priv->in_gpio_handler = true;
3577 /* Wait here for debounce time */
3578 usleep_range(SITAR_GPIO_IRQ_DEBOUNCE_TIME_US,
3579 SITAR_GPIO_IRQ_DEBOUNCE_TIME_US);
3580
3581 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
3582
3583 /* cancel pending button press */
3584 if (sitar_cancel_btn_work(priv))
3585 pr_debug("%s: button press is canceled\n", __func__);
3586
3587 insert = (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
3588 priv->mbhc_cfg.gpio_level_insert);
3589 if ((priv->current_plug == PLUG_TYPE_NONE) && insert) {
3590 priv->lpi_enabled = false;
3591 wmb();
3592
3593 /* cancel detect plug */
3594 sitar_cancel_hs_detect_plug(priv);
3595
3596 /* Disable Mic Bias pull down and HPH Switch to GND */
3597 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01,
3598 0x00);
3599 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01, 0x00);
3600 sitar_codec_detect_plug_type(codec);
3601 } else if ((priv->current_plug != PLUG_TYPE_NONE) && !insert) {
3602 priv->lpi_enabled = false;
3603 wmb();
3604
3605 /* cancel detect plug */
3606 sitar_cancel_hs_detect_plug(priv);
3607
3608 if (priv->current_plug == PLUG_TYPE_HEADPHONE) {
3609 sitar_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
3610 is_removed = true;
3611 } else if (priv->current_plug == PLUG_TYPE_HEADSET) {
3612 sitar_codec_pause_hs_polling(codec);
3613 sitar_codec_cleanup_hs_polling(codec);
3614 sitar_codec_report_plug(codec, 0, SND_JACK_HEADSET);
3615 is_removed = true;
3616 }
3617
3618 if (is_removed) {
3619 /* Enable Mic Bias pull down and HPH Switch to GND */
3620 snd_soc_update_bits(codec,
3621 priv->mbhc_bias_regs.ctl_reg, 0x01,
3622 0x01);
3623 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x01,
3624 0x01);
3625 /* Make sure mic trigger is turned off */
3626 snd_soc_update_bits(codec,
3627 priv->mbhc_bias_regs.ctl_reg,
3628 0x01, 0x01);
3629 snd_soc_update_bits(codec,
3630 priv->mbhc_bias_regs.mbhc_reg,
3631 0x90, 0x00);
3632 /* Reset MBHC State Machine */
3633 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
3634 0x08, 0x08);
3635 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_CLK_CTL,
3636 0x08, 0x00);
3637 /* Turn off override */
3638 sitar_turn_onoff_override(codec, false);
3639 }
3640 }
3641
3642 priv->in_gpio_handler = false;
3643 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
3644 pr_debug("%s: leave\n", __func__);
3645}
3646
3647static irqreturn_t sitar_mechanical_plug_detect_irq(int irq, void *data)
3648{
3649 int r = IRQ_HANDLED;
3650 struct snd_soc_codec *codec = data;
3651
3652 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
3653 pr_warn("%s(): Failed to hold suspend\n", __func__);
3654 r = IRQ_NONE;
3655 } else {
3656 sitar_hs_gpio_handler(codec);
3657 wcd9xxx_unlock_sleep(codec->control_data);
3658 }
3659 return r;
3660}
3661
3662static int sitar_mbhc_init_and_calibrate(struct snd_soc_codec *codec)
3663{
3664 int rc = 0;
3665 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
3666
3667 sitar->mbhc_cfg.mclk_cb_fn(codec, 1, false);
3668 sitar_mbhc_init(codec);
3669 sitar_mbhc_cal(codec);
3670 sitar_mbhc_calc_thres(codec);
3671 sitar->mbhc_cfg.mclk_cb_fn(codec, 0, false);
3672 sitar_codec_calibrate_hs_polling(codec);
3673
3674 /* Enable Mic Bias pull down and HPH Switch to GND */
3675 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.ctl_reg,
3676 0x01, 0x01);
3677 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH,
3678 0x01, 0x01);
3679
3680 rc = request_threaded_irq(sitar->mbhc_cfg.gpio_irq,
3681 NULL,
3682 sitar_mechanical_plug_detect_irq,
3683 (IRQF_TRIGGER_RISING |
3684 IRQF_TRIGGER_FALLING),
3685 "sitar-hs-gpio", codec);
3686
3687 if (!IS_ERR_VALUE(rc)) {
3688 rc = enable_irq_wake(sitar->mbhc_cfg.gpio_irq);
3689 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
3690 0x10, 0x10);
3691 wcd9xxx_enable_irq(codec->control_data,
3692 SITAR_IRQ_HPH_PA_OCPL_FAULT);
3693 wcd9xxx_enable_irq(codec->control_data,
3694 SITAR_IRQ_HPH_PA_OCPR_FAULT);
3695 /* Bootup time detection */
3696 sitar_hs_gpio_handler(codec);
3697 }
3698
3699 return rc;
3700}
3701
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003702static void mbhc_fw_read(struct work_struct *work)
3703{
3704 struct delayed_work *dwork;
3705 struct sitar_priv *sitar;
3706 struct snd_soc_codec *codec;
3707 const struct firmware *fw;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003708 int ret = -1, retry = 0;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003709
3710 dwork = to_delayed_work(work);
3711 sitar = container_of(dwork, struct sitar_priv,
3712 mbhc_firmware_dwork);
3713 codec = sitar->codec;
3714
3715 while (retry < MBHC_FW_READ_ATTEMPTS) {
3716 retry++;
3717 pr_info("%s:Attempt %d to request MBHC firmware\n",
3718 __func__, retry);
3719 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
3720 codec->dev);
3721
3722 if (ret != 0) {
3723 usleep_range(MBHC_FW_READ_TIMEOUT,
3724 MBHC_FW_READ_TIMEOUT);
3725 } else {
3726 pr_info("%s: MBHC Firmware read succesful\n", __func__);
3727 break;
3728 }
3729 }
3730
3731 if (ret != 0) {
3732 pr_err("%s: Cannot load MBHC firmware use default cal\n",
3733 __func__);
3734 } else if (sitar_mbhc_fw_validate(fw) == false) {
3735 pr_err("%s: Invalid MBHC cal data size use default cal\n",
3736 __func__);
3737 release_firmware(fw);
3738 } else {
3739 sitar->calibration = (void *)fw->data;
3740 sitar->mbhc_fw = fw;
3741 }
3742
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003743 sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003744}
3745
3746int sitar_hs_detect(struct snd_soc_codec *codec,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003747 const struct sitar_mbhc_config *cfg)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003748{
3749 struct sitar_priv *sitar;
3750 int rc = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303751
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003752 if (!codec || !cfg->calibration) {
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303753 pr_err("Error: no codec or calibration\n");
3754 return -EINVAL;
3755 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003756
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003757 if (cfg->mclk_rate != SITAR_MCLK_RATE_12288KHZ) {
3758 if (cfg->mclk_rate == SITAR_MCLK_RATE_9600KHZ)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003759 pr_err("Error: clock rate %dHz is not yet supported\n",
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003760 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003761 else
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003762 pr_err("Error: unsupported clock rate %d\n",
3763 cfg->mclk_rate);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003764 return -EINVAL;
3765 }
3766
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303767 sitar = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003768 sitar->mbhc_cfg = *cfg;
3769 sitar->in_gpio_handler = false;
3770 sitar->current_plug = PLUG_TYPE_NONE;
3771 sitar->lpi_enabled = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303772 sitar_get_mbhc_micbias_regs(codec, &sitar->mbhc_bias_regs);
3773
3774 /* Put CFILT in fast mode by default */
3775 snd_soc_update_bits(codec, sitar->mbhc_bias_regs.cfilt_ctl,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003776 0x40, SITAR_CFILT_FAST_MODE);
3777
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003778 INIT_DELAYED_WORK(&sitar->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003779 INIT_DELAYED_WORK(&sitar->mbhc_btn_dwork, btn_lpress_fn);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303780 INIT_WORK(&sitar->hphlocp_work, hphlocp_off_report);
3781 INIT_WORK(&sitar->hphrocp_work, hphrocp_off_report);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003782 INIT_WORK(&sitar->hs_correct_plug_work,
3783 sitar_hs_correct_gpio_plug);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003784
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003785 if (!sitar->mbhc_cfg.read_fw_bin) {
3786 rc = sitar_mbhc_init_and_calibrate(codec);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003787 } else {
3788 schedule_delayed_work(&sitar->mbhc_firmware_dwork,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003789 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303790 }
3791
3792 return rc;
3793}
3794EXPORT_SYMBOL_GPL(sitar_hs_detect);
3795
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003796static int sitar_determine_button(const struct sitar_priv *priv,
3797 const s32 bias_mv)
3798{
3799 s16 *v_btn_low, *v_btn_high;
3800 struct sitar_mbhc_btn_detect_cfg *btn_det;
3801 int i, btn = -1;
3802
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003803 btn_det = SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003804 v_btn_low = sitar_mbhc_cal_btn_det_mp(btn_det, SITAR_BTN_DET_V_BTN_LOW);
3805 v_btn_high = sitar_mbhc_cal_btn_det_mp(btn_det,
3806 SITAR_BTN_DET_V_BTN_HIGH);
3807 for (i = 0; i < btn_det->num_btn; i++) {
3808 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
3809 btn = i;
3810 break;
3811 }
3812 }
3813
3814 if (btn == -1)
3815 pr_debug("%s: couldn't find button number for mic mv %d\n",
3816 __func__, bias_mv);
3817
3818 return btn;
3819}
3820
3821static int sitar_get_button_mask(const int btn)
3822{
3823 int mask = 0;
3824 switch (btn) {
3825 case 0:
3826 mask = SND_JACK_BTN_0;
3827 break;
3828 case 1:
3829 mask = SND_JACK_BTN_1;
3830 break;
3831 case 2:
3832 mask = SND_JACK_BTN_2;
3833 break;
3834 case 3:
3835 mask = SND_JACK_BTN_3;
3836 break;
3837 case 4:
3838 mask = SND_JACK_BTN_4;
3839 break;
3840 case 5:
3841 mask = SND_JACK_BTN_5;
3842 break;
3843 case 6:
3844 mask = SND_JACK_BTN_6;
3845 break;
3846 case 7:
3847 mask = SND_JACK_BTN_7;
3848 break;
3849 }
3850 return mask;
3851}
3852
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003853
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303854static irqreturn_t sitar_dce_handler(int irq, void *data)
3855{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003856 int i, mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003857 short dce, sta, bias_value_dce;
3858 s32 mv, stamv, bias_mv_dce;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003859 int btn = -1, meas = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303860 struct sitar_priv *priv = data;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003861 const struct sitar_mbhc_btn_detect_cfg *d =
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003862 SITAR_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003863 short btnmeas[d->n_btn_meas + 1];
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303864 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08003865 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003866 int n_btn_meas = d->n_btn_meas;
3867 u8 mbhc_status = snd_soc_read(codec, SITAR_A_CDC_MBHC_B1_STATUS) & 0x3E;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303868
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003869 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303870
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003871 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
3872 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
3873 pr_debug("%s: mbhc is being recovered, skip button press\n",
3874 __func__);
3875 goto done;
3876 }
3877
3878 priv->mbhc_state = MBHC_STATE_POTENTIAL;
3879
3880 if (!priv->mbhc_polling_active) {
3881 pr_warn("%s: mbhc polling is not active, skip button press\n",
3882 __func__);
3883 goto done;
3884 }
3885
3886 dce = sitar_codec_read_dce_result(codec);
3887 mv = sitar_codec_sta_dce_v(codec, 1, dce);
3888
3889 /* If GPIO interrupt already kicked in, ignore button press */
3890 if (priv->in_gpio_handler) {
3891 pr_debug("%s: GPIO State Changed, ignore button press\n",
3892 __func__);
3893 btn = -1;
3894 goto done;
3895 }
3896
3897 if (mbhc_status != SITAR_MBHC_STATUS_REL_DETECTION) {
3898 if (priv->mbhc_last_resume &&
3899 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
3900 pr_debug("%s: Button is already released shortly after "
3901 "resume\n", __func__);
3902 n_btn_meas = 0;
3903 } else {
3904 pr_debug("%s: Button is already released without "
3905 "resume", __func__);
3906 sta = sitar_codec_read_sta_result(codec);
3907 stamv = sitar_codec_sta_dce_v(codec, 0, sta);
3908 btn = sitar_determine_button(priv, mv);
3909 if (btn != sitar_determine_button(priv, stamv))
3910 btn = -1;
3911 goto done;
3912 }
3913 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303914
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003915 /* determine pressed button */
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003916 btnmeas[meas++] = sitar_determine_button(priv, mv);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003917 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003918 meas - 1, dce, mv, btnmeas[meas - 1]);
3919 if (n_btn_meas == 0)
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003920 btn = btnmeas[0];
3921 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003922 bias_value_dce = sitar_codec_sta_dce(codec, 1, false);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003923 bias_mv_dce = sitar_codec_sta_dce_v(codec, 1, bias_value_dce);
3924 btnmeas[meas] = sitar_determine_button(priv, bias_mv_dce);
3925 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
3926 __func__, meas, bias_value_dce, bias_mv_dce,
3927 btnmeas[meas]);
3928 /* if large enough measurements are collected,
3929 * start to check if last all n_btn_con measurements were
3930 * in same button low/high range */
3931 if (meas + 1 >= d->n_btn_con) {
3932 for (i = 0; i < d->n_btn_con; i++)
3933 if ((btnmeas[meas] < 0) ||
3934 (btnmeas[meas] != btnmeas[meas - i]))
3935 break;
3936 if (i == d->n_btn_con) {
3937 /* button pressed */
3938 btn = btnmeas[meas];
3939 break;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003940 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
3941 /* if left measurements are less than n_btn_con,
3942 * it's impossible to find button number */
3943 break;
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003944 }
3945 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003946 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303947
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003948 if (btn >= 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003949 if (priv->in_gpio_handler) {
3950 pr_debug("%s: GPIO already triggered, ignore button "
3951 "press\n", __func__);
3952 goto done;
3953 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003954 mask = sitar_get_button_mask(btn);
3955 priv->buttons_pressed |= mask;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003956 wcd9xxx_lock_sleep(core);
3957 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
3958 msecs_to_jiffies(400)) == 0) {
3959 WARN(1, "Button pressed twice without release"
3960 "event\n");
3961 wcd9xxx_unlock_sleep(core);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08003962 }
3963 } else {
3964 pr_debug("%s: bogus button press, too short press?\n",
3965 __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303966 }
3967
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003968 done:
3969 pr_debug("%s: leave\n", __func__);
3970 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05303971 return IRQ_HANDLED;
3972}
3973
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07003974static int sitar_is_fake_press(struct sitar_priv *priv)
3975{
3976 int i;
3977 int r = 0;
3978 struct snd_soc_codec *codec = priv->codec;
3979 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
3980 short mb_v;
3981
3982 for (i = 0; i < dces; i++) {
3983 usleep_range(10000, 10000);
3984 if (i == 0) {
3985 mb_v = sitar_codec_sta_dce(codec, 0, true);
3986 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
3987 sitar_codec_sta_dce_v(codec, 0, mb_v));
3988 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
3989 mb_v > (short)priv->mbhc_data.v_ins_hu) {
3990 r = 1;
3991 break;
3992 }
3993 } else {
3994 mb_v = sitar_codec_sta_dce(codec, 1, true);
3995 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
3996 sitar_codec_sta_dce_v(codec, 1, mb_v));
3997 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
3998 mb_v > (short)priv->mbhc_data.v_ins_h) {
3999 r = 1;
4000 break;
4001 }
4002 }
4003 }
4004
4005 return r;
4006}
4007
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304008static irqreturn_t sitar_release_handler(int irq, void *data)
4009{
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004010 int ret;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304011 struct sitar_priv *priv = data;
4012 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304013
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004014 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304015
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004016 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4017 priv->mbhc_state = MBHC_STATE_RELEASE;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304018
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004019 if (priv->buttons_pressed & SITAR_JACK_BUTTON_MASK) {
4020 ret = sitar_cancel_btn_work(priv);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304021 if (ret == 0) {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004022 pr_debug("%s: Reporting long button release event\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004023 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004024 if (priv->mbhc_cfg.button_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304025 sitar_snd_soc_jack_report(priv,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004026 priv->mbhc_cfg.button_jack, 0,
4027 priv->buttons_pressed);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304028 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004029 if (sitar_is_fake_press(priv)) {
4030 pr_debug("%s: Fake button press interrupt\n",
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004031 __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004032 } else if (priv->mbhc_cfg.button_jack) {
4033 if (priv->in_gpio_handler) {
4034 pr_debug("%s: GPIO kicked in, ignore\n",
4035 __func__);
4036 } else {
4037 pr_debug("%s: Reporting short button 0 "
4038 "press and release\n",
4039 __func__);
4040 sitar_snd_soc_jack_report(priv,
4041 priv->mbhc_cfg.button_jack,
4042 priv->buttons_pressed,
4043 priv->buttons_pressed);
4044 sitar_snd_soc_jack_report(priv,
4045 priv->mbhc_cfg.button_jack, 0,
4046 priv->buttons_pressed);
4047 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304048 }
4049 }
4050
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004051 priv->buttons_pressed &= ~SITAR_JACK_BUTTON_MASK;
4052 }
4053
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004054 sitar_codec_calibrate_hs_polling(codec);
4055
4056 if (priv->mbhc_cfg.gpio)
4057 msleep(SITAR_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
4058
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304059 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004060
4061 pr_debug("%s: leave\n", __func__);
4062 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4063
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304064 return IRQ_HANDLED;
4065}
4066
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304067static irqreturn_t sitar_hphl_ocp_irq(int irq, void *data)
4068{
4069 struct sitar_priv *sitar = data;
4070 struct snd_soc_codec *codec;
4071
4072 pr_info("%s: received HPHL OCP irq\n", __func__);
4073
4074 if (sitar) {
4075 codec = sitar->codec;
4076 if (sitar->hphlocp_cnt++ < SITAR_OCP_ATTEMPT) {
4077 pr_info("%s: retry\n", __func__);
4078 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004079 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304080 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004081 0x10);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304082 } else {
4083 wcd9xxx_disable_irq(codec->control_data,
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004084 SITAR_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304085 sitar->hphlocp_cnt = 0;
4086 sitar->hph_status |= SND_JACK_OC_HPHL;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004087 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304088 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004089 sitar->mbhc_cfg.headset_jack,
4090 sitar->hph_status,
4091 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304092 }
4093 } else {
4094 pr_err("%s: Bad sitar private data\n", __func__);
4095 }
4096
4097 return IRQ_HANDLED;
4098}
4099
4100static irqreturn_t sitar_hphr_ocp_irq(int irq, void *data)
4101{
4102 struct sitar_priv *sitar = data;
4103 struct snd_soc_codec *codec;
4104
4105 pr_info("%s: received HPHR OCP irq\n", __func__);
4106
4107 if (sitar) {
4108 codec = sitar->codec;
4109 if (sitar->hphrocp_cnt++ < SITAR_OCP_ATTEMPT) {
4110 pr_info("%s: retry\n", __func__);
4111 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
4112 0x00);
4113 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL, 0x10,
4114 0x10);
4115 } else {
4116 wcd9xxx_disable_irq(codec->control_data,
4117 SITAR_IRQ_HPH_PA_OCPR_FAULT);
4118 sitar->hphrocp_cnt = 0;
4119 sitar->hph_status |= SND_JACK_OC_HPHR;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004120 if (sitar->mbhc_cfg.headset_jack)
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304121 sitar_snd_soc_jack_report(sitar,
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004122 sitar->mbhc_cfg.headset_jack,
4123 sitar->hph_status,
4124 SITAR_JACK_MASK);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304125 }
4126 } else {
4127 pr_err("%s: Bad sitar private data\n", __func__);
4128 }
4129
4130 return IRQ_HANDLED;
4131}
4132
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304133static irqreturn_t sitar_hs_insert_irq(int irq, void *data)
4134{
4135 struct sitar_priv *priv = data;
4136 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304137
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004138 pr_debug("%s: enter\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004139 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304140 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304141
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304142 snd_soc_update_bits(codec, SITAR_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
4143
4144 /* Turn off both HPH and MIC line schmitt triggers */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004145 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304146 snd_soc_update_bits(codec, SITAR_A_MBHC_HPH, 0x13, 0x00);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004147 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304148
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004149 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304150
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004151 rmb();
4152 if (priv->lpi_enabled)
4153 msleep(100);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304154
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004155 rmb();
4156 if (!priv->lpi_enabled) {
4157 pr_debug("%s: lpi is disabled\n", __func__);
4158 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
4159 priv->mbhc_cfg.gpio_level_insert) {
4160 pr_debug("%s: Valid insertion, "
4161 "detect plug type\n", __func__);
4162 sitar_codec_decide_gpio_plug(codec);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304163 } else {
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004164 pr_debug("%s: Invalid insertion, "
4165 "stop plug detection\n", __func__);
4166 }
4167 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
4168 return IRQ_HANDLED;
4169}
4170
4171static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
4172{
4173 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4174 struct sitar_mbhc_plug_type_cfg *plug_type =
4175 SITAR_MBHC_CAL_PLUG_TYPE_PTR(sitar->mbhc_cfg.calibration);
4176
4177 return (!(mic_mv > SITAR_MBHC_FAKE_INSERT_LOW
4178 && mic_mv < SITAR_MBHC_FAKE_INSERT_HIGH)
4179 && (mic_mv > plug_type->v_no_mic)
4180 && (mic_mv < plug_type->v_hs_max)) ? true : false;
4181}
4182
4183/* called under codec_resource_lock acquisition
4184 * returns true if mic voltage range is back to normal insertion
4185 * returns false either if timedout or removed */
4186static bool sitar_hs_remove_settle(struct snd_soc_codec *codec)
4187{
4188 int i;
4189 bool timedout, settled = false;
4190 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
4191 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
4192 unsigned long retry = 0, timeout;
4193 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4194
4195 timeout = jiffies + msecs_to_jiffies(SITAR_HS_DETECT_PLUG_TIME_MS);
4196 while (!(timedout = time_after(jiffies, timeout))) {
4197 retry++;
4198 if (sitar_hs_gpio_level_remove(sitar)) {
4199 pr_debug("%s: GPIO indicates removal\n", __func__);
4200 break;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304201 }
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004202
4203 if (retry > 1)
4204 msleep(250);
4205 else
4206 msleep(50);
4207
4208 if (sitar_hs_gpio_level_remove(sitar)) {
4209 pr_debug("%s: GPIO indicates removal\n", __func__);
4210 break;
4211 }
4212
4213 sitar_turn_onoff_override(codec, true);
4214 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
4215 mb_v[i] = __sitar_codec_sta_dce(codec, 1, true, true);
4216 mic_mv[i] = sitar_codec_sta_dce_v(codec, 1 , mb_v[i]);
4217 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
4218 __func__, retry, mic_mv[i], mb_v[i]);
4219 }
4220 sitar_turn_onoff_override(codec, false);
4221
4222 if (sitar_hs_gpio_level_remove(sitar)) {
4223 pr_debug("%s: GPIO indicates removal\n", __func__);
4224 break;
4225 }
4226
4227 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
4228 if (!is_valid_mic_voltage(codec, mic_mv[i]))
4229 break;
4230
4231 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
4232 pr_debug("%s: MIC voltage settled\n", __func__);
4233 settled = true;
4234 msleep(200);
4235 break;
4236 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304237 }
4238
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004239 if (timedout)
4240 pr_debug("%s: Microphone did not settle in %d seconds\n",
4241 __func__, SITAR_HS_DETECT_PLUG_TIME_MS);
4242 return settled;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304243}
4244
4245static irqreturn_t sitar_hs_remove_irq(int irq, void *data)
4246{
4247 struct sitar_priv *priv = data;
4248 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304249
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004250 pr_debug("%s: enter, removal interrupt\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304251
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004252 SITAR_ACQUIRE_LOCK(priv->codec_resource_lock);
4253 if (sitar_hs_remove_settle(codec))
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304254 sitar_codec_start_hs_polling(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004255 pr_debug("%s: remove settle done\n", __func__);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304256
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004257 SITAR_RELEASE_LOCK(priv->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304258 return IRQ_HANDLED;
4259}
4260
4261
4262static unsigned long slimbus_value;
4263
4264static irqreturn_t sitar_slimbus_irq(int irq, void *data)
4265{
4266 struct sitar_priv *priv = data;
4267 struct snd_soc_codec *codec = priv->codec;
4268 int i, j;
4269 u8 val;
4270
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304271
4272 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
4273 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
4274 SITAR_SLIM_PGD_PORT_INT_STATUS0 + i);
4275 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
4276 val = wcd9xxx_interface_reg_read(codec->control_data,
4277 SITAR_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
4278 if (val & 0x1)
4279 pr_err_ratelimited("overflow error on port %x,"
4280 " value %x\n", i*8 + j, val);
4281 if (val & 0x2)
4282 pr_err_ratelimited("underflow error on port %x,"
4283 " value %x\n", i*8 + j, val);
4284 }
4285 wcd9xxx_interface_reg_write(codec->control_data,
4286 SITAR_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
4287 }
4288
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304289 return IRQ_HANDLED;
4290}
4291
4292
4293static int sitar_handle_pdata(struct sitar_priv *sitar)
4294{
4295 struct snd_soc_codec *codec = sitar->codec;
4296 struct wcd9xxx_pdata *pdata = sitar->pdata;
4297 int k1, k2, rc = 0;
4298 u8 leg_mode = pdata->amic_settings.legacy_mode;
4299 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4300 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4301 u8 flag = pdata->amic_settings.use_pdata;
4302 u8 i = 0, j = 0;
4303 u8 val_txfe = 0, value = 0;
4304
4305 if (!pdata) {
4306 rc = -ENODEV;
4307 goto done;
4308 }
4309
4310 /* Make sure settings are correct */
4311 if ((pdata->micbias.ldoh_v > SITAR_LDOH_2P85_V) ||
4312 (pdata->micbias.bias1_cfilt_sel > SITAR_CFILT2_SEL) ||
4313 (pdata->micbias.bias2_cfilt_sel > SITAR_CFILT2_SEL)) {
4314 rc = -EINVAL;
4315 goto done;
4316 }
4317
4318 /* figure out k value */
4319 k1 = sitar_find_k_value(pdata->micbias.ldoh_v,
4320 pdata->micbias.cfilt1_mv);
4321 k2 = sitar_find_k_value(pdata->micbias.ldoh_v,
4322 pdata->micbias.cfilt2_mv);
4323
4324 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2)) {
4325 rc = -EINVAL;
4326 goto done;
4327 }
4328
4329 /* Set voltage level and always use LDO */
4330
4331 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_1_VAL, 0xFC,
4332 (k1 << 2));
4333 snd_soc_update_bits(codec, SITAR_A_MICB_CFILT_2_VAL, 0xFC,
4334 (k2 << 2));
4335
4336 snd_soc_update_bits(codec, SITAR_A_MICB_1_CTL, 0x60,
4337 (pdata->micbias.bias1_cfilt_sel << 5));
4338 snd_soc_update_bits(codec, SITAR_A_MICB_2_CTL, 0x60,
4339 (pdata->micbias.bias2_cfilt_sel << 5));
4340
4341 for (i = 0; i < 6; j++, i += 2) {
4342 if (flag & (0x01 << i)) {
4343 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
4344 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4345 val_txfe = val_txfe |
4346 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4347 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
4348 0x10, value);
4349 snd_soc_update_bits(codec,
4350 SITAR_A_TX_1_2_TEST_EN + j * 10,
4351 0x30, val_txfe);
4352 }
4353 if (flag & (0x01 << (i + 1))) {
4354 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
4355 val_txfe = (txfe_bypass &
4356 (0x01 << (i + 1))) ? 0x02 : 0x00;
4357 val_txfe |= (txfe_buff &
4358 (0x01 << (i + 1))) ? 0x01 : 0x00;
4359 snd_soc_update_bits(codec, SITAR_A_TX_1_2_EN + j * 10,
4360 0x01, value);
4361 snd_soc_update_bits(codec,
4362 SITAR_A_TX_1_2_TEST_EN + j * 10,
4363 0x03, val_txfe);
4364 }
4365 }
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004366 if (flag & 0x40) {
4367 value = (leg_mode & 0x40) ? 0x10 : 0x00;
4368 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
4369 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
4370 snd_soc_update_bits(codec, SITAR_A_TX_4_MBHC_EN,
4371 0x13, value);
4372 }
4373
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304374
4375 if (pdata->ocp.use_pdata) {
4376 /* not defined in CODEC specification */
4377 if (pdata->ocp.hph_ocp_limit == 1 ||
4378 pdata->ocp.hph_ocp_limit == 5) {
4379 rc = -EINVAL;
4380 goto done;
4381 }
4382 snd_soc_update_bits(codec, SITAR_A_RX_COM_OCP_CTL,
4383 0x0F, pdata->ocp.num_attempts);
4384 snd_soc_write(codec, SITAR_A_RX_COM_OCP_COUNT,
4385 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4386 snd_soc_update_bits(codec, SITAR_A_RX_HPH_OCP_CTL,
4387 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4388 }
4389done:
4390 return rc;
4391}
4392
4393static const struct sitar_reg_mask_val sitar_1_1_reg_defaults[] = {
4394
4395 /* Sitar 1.1 MICBIAS changes */
4396 SITAR_REG_VAL(SITAR_A_MICB_1_INT_RBIAS, 0x24),
4397 SITAR_REG_VAL(SITAR_A_MICB_2_INT_RBIAS, 0x24),
4398
4399 /* Sitar 1.1 HPH changes */
4400 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_PA, 0x57),
4401 SITAR_REG_VAL(SITAR_A_RX_HPH_BIAS_LDO, 0x56),
4402
4403 /* Sitar 1.1 EAR PA changes */
4404 SITAR_REG_VAL(SITAR_A_RX_EAR_BIAS_PA, 0xA6),
4405 SITAR_REG_VAL(SITAR_A_RX_EAR_GAIN, 0x02),
4406 SITAR_REG_VAL(SITAR_A_RX_EAR_VCM, 0x03),
4407
4408 /* Sitar 1.1 RX Changes */
4409 SITAR_REG_VAL(SITAR_A_CDC_RX1_B5_CTL, 0x78),
4410
4411 /* Sitar 1.1 RX1 and RX2 Changes */
4412 SITAR_REG_VAL(SITAR_A_CDC_RX1_B6_CTL, 0x80),
4413
4414 SITAR_REG_VAL(SITAR_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
4415
4416};
4417
4418static void sitar_update_reg_defaults(struct snd_soc_codec *codec)
4419{
4420 u32 i;
4421 for (i = 0; i < ARRAY_SIZE(sitar_1_1_reg_defaults); i++)
4422 snd_soc_write(codec, sitar_1_1_reg_defaults[i].reg,
4423 sitar_1_1_reg_defaults[i].val);
4424
4425}
4426static const struct sitar_reg_mask_val sitar_codec_reg_init_val[] = {
4427 /* Initialize current threshold to 350MA
4428 * number of wait and run cycles to 4096
4429 */
4430 {SITAR_A_RX_HPH_OCP_CTL, 0xF8, 0x60},
4431 {SITAR_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
4432
4433 {SITAR_A_QFUSE_CTL, 0xFF, 0x03},
4434
4435 /* Initialize gain registers to use register gain */
4436 {SITAR_A_RX_HPH_L_GAIN, 0x10, 0x10},
4437 {SITAR_A_RX_HPH_R_GAIN, 0x10, 0x10},
4438 {SITAR_A_RX_LINE_1_GAIN, 0x10, 0x10},
4439 {SITAR_A_RX_LINE_2_GAIN, 0x10, 0x10},
4440
4441 /* Initialize mic biases to differential mode */
4442 {SITAR_A_MICB_1_INT_RBIAS, 0x24, 0x24},
4443 {SITAR_A_MICB_2_INT_RBIAS, 0x24, 0x24},
4444
4445 {SITAR_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
4446
4447 /* Use 16 bit sample size for TX1 to TX6 */
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004448 {SITAR_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304449 {SITAR_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4450 {SITAR_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4451 {SITAR_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4452 {SITAR_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004453 {SITAR_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0x1, 0x1},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304454
4455 /* Use 16 bit sample size for RX */
4456 {SITAR_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4457 {SITAR_A_CDC_CONN_RX_SB_B2_CTL, 0x02, 0x02},
4458
4459 /*enable HPF filter for TX paths */
4460 {SITAR_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004461 {SITAR_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
Bhalchandra Gajare2776af12012-04-27 16:59:39 -07004462
4463 /*enable External clock select*/
4464 {SITAR_A_CDC_CLK_MCLK_CTL, 0x01, 0x01},
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304465};
4466
4467static void sitar_codec_init_reg(struct snd_soc_codec *codec)
4468{
4469 u32 i;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304470 for (i = 0; i < ARRAY_SIZE(sitar_codec_reg_init_val); i++)
4471 snd_soc_update_bits(codec, sitar_codec_reg_init_val[i].reg,
4472 sitar_codec_reg_init_val[i].mask,
4473 sitar_codec_reg_init_val[i].val);
4474}
4475
4476static int sitar_codec_probe(struct snd_soc_codec *codec)
4477{
4478 struct sitar *control;
4479 struct sitar_priv *sitar;
4480 struct snd_soc_dapm_context *dapm = &codec->dapm;
4481 int ret = 0;
4482 int i;
4483 u8 sitar_version;
4484 int ch_cnt;
4485
4486 codec->control_data = dev_get_drvdata(codec->dev->parent);
4487 control = codec->control_data;
4488
4489 sitar = kzalloc(sizeof(struct sitar_priv), GFP_KERNEL);
4490 if (!sitar) {
4491 dev_err(codec->dev, "Failed to allocate private data\n");
4492 return -ENOMEM;
4493 }
4494
4495 /* Make sure mbhc micbias register addresses are zeroed out */
4496 memset(&sitar->mbhc_bias_regs, 0,
4497 sizeof(struct mbhc_micbias_regs));
4498 sitar->cfilt_k_value = 0;
4499 sitar->mbhc_micbias_switched = false;
4500
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004501 /* Make sure mbhc intenal calibration data is zeroed out */
4502 memset(&sitar->mbhc_data, 0,
4503 sizeof(struct mbhc_internal_cal_data));
4504 sitar->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
4505 sitar->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
4506 sitar->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304507 snd_soc_codec_set_drvdata(codec, sitar);
4508
4509 sitar->mclk_enabled = false;
4510 sitar->bandgap_type = SITAR_BANDGAP_OFF;
4511 sitar->clock_active = false;
4512 sitar->config_mode_active = false;
4513 sitar->mbhc_polling_active = false;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304514 sitar->no_mic_headset_override = false;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004515 mutex_init(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304516 sitar->codec = codec;
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004517 sitar->mbhc_state = MBHC_STATE_NONE;
4518 sitar->mbhc_last_resume = 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304519 sitar->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304520 sitar_update_reg_defaults(codec);
4521 sitar_codec_init_reg(codec);
4522
4523 ret = sitar_handle_pdata(sitar);
4524 if (IS_ERR_VALUE(ret)) {
4525 pr_err("%s: bad pdata\n", __func__);
4526 goto err_pdata;
4527 }
4528
4529 snd_soc_add_controls(codec, sitar_snd_controls,
4530 ARRAY_SIZE(sitar_snd_controls));
4531 snd_soc_dapm_new_controls(dapm, sitar_dapm_widgets,
4532 ARRAY_SIZE(sitar_dapm_widgets));
4533 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
4534
4535 sitar_version = snd_soc_read(codec, WCD9XXX_A_CHIP_VERSION);
4536 pr_info("%s : Sitar version reg 0x%2x\n", __func__, (u32)sitar_version);
4537
4538 sitar_version &= 0x1F;
4539 pr_info("%s : Sitar version %u\n", __func__, (u32)sitar_version);
4540
4541 snd_soc_dapm_sync(dapm);
4542
4543
4544 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION,
4545 sitar_hs_insert_irq, "Headset insert detect", sitar);
4546 if (ret) {
4547 pr_err("%s: Failed to request irq %d\n", __func__,
4548 SITAR_IRQ_MBHC_INSERTION);
4549 goto err_insert_irq;
4550 }
4551 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION);
4552
4553 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL,
4554 sitar_hs_remove_irq, "Headset remove detect", sitar);
4555 if (ret) {
4556 pr_err("%s: Failed to request irq %d\n", __func__,
4557 SITAR_IRQ_MBHC_REMOVAL);
4558 goto err_remove_irq;
4559 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304560
4561 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL,
4562 sitar_dce_handler, "DC Estimation detect", sitar);
4563 if (ret) {
4564 pr_err("%s: Failed to request irq %d\n", __func__,
4565 SITAR_IRQ_MBHC_POTENTIAL);
4566 goto err_potential_irq;
4567 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304568
4569 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE,
4570 sitar_release_handler, "Button Release detect", sitar);
4571 if (ret) {
4572 pr_err("%s: Failed to request irq %d\n", __func__,
4573 SITAR_IRQ_MBHC_RELEASE);
4574 goto err_release_irq;
4575 }
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304576
4577 ret = wcd9xxx_request_irq(codec->control_data, SITAR_IRQ_SLIMBUS,
4578 sitar_slimbus_irq, "SLIMBUS Slave", sitar);
4579 if (ret) {
4580 pr_err("%s: Failed to request irq %d\n", __func__,
4581 SITAR_IRQ_SLIMBUS);
4582 goto err_slimbus_irq;
4583 }
4584
4585 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
4586 wcd9xxx_interface_reg_write(codec->control_data,
4587 SITAR_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
4588
4589
4590 ret = wcd9xxx_request_irq(codec->control_data,
4591 SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar_hphl_ocp_irq,
4592 "HPH_L OCP detect", sitar);
4593 if (ret) {
4594 pr_err("%s: Failed to request irq %d\n", __func__,
4595 SITAR_IRQ_HPH_PA_OCPL_FAULT);
4596 goto err_hphl_ocp_irq;
4597 }
4598 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPL_FAULT);
4599
4600 ret = wcd9xxx_request_irq(codec->control_data,
4601 SITAR_IRQ_HPH_PA_OCPR_FAULT, sitar_hphr_ocp_irq,
4602 "HPH_R OCP detect", sitar);
4603 if (ret) {
4604 pr_err("%s: Failed to request irq %d\n", __func__,
4605 SITAR_IRQ_HPH_PA_OCPR_FAULT);
4606 goto err_hphr_ocp_irq;
4607 }
4608 wcd9xxx_disable_irq(codec->control_data, SITAR_IRQ_HPH_PA_OCPR_FAULT);
4609
4610 for (i = 0; i < ARRAY_SIZE(sitar_dai); i++) {
4611 switch (sitar_dai[i].id) {
4612 case AIF1_PB:
4613 ch_cnt = sitar_dai[i].playback.channels_max;
4614 break;
4615 case AIF1_CAP:
4616 ch_cnt = sitar_dai[i].capture.channels_max;
4617 break;
4618 default:
4619 continue;
4620 }
4621 sitar->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
4622 ch_cnt), GFP_KERNEL);
4623 }
4624
4625#ifdef CONFIG_DEBUG_FS
4626 debug_sitar_priv = sitar;
4627#endif
4628
4629 return ret;
4630
4631err_hphr_ocp_irq:
4632 wcd9xxx_free_irq(codec->control_data,
4633 SITAR_IRQ_HPH_PA_OCPL_FAULT, sitar);
4634err_hphl_ocp_irq:
4635 wcd9xxx_free_irq(codec->control_data,
4636 SITAR_IRQ_SLIMBUS, sitar);
4637err_slimbus_irq:
4638 wcd9xxx_free_irq(codec->control_data,
4639 SITAR_IRQ_MBHC_RELEASE, sitar);
4640err_release_irq:
4641 wcd9xxx_free_irq(codec->control_data,
4642 SITAR_IRQ_MBHC_POTENTIAL, sitar);
4643err_potential_irq:
4644 wcd9xxx_free_irq(codec->control_data,
4645 SITAR_IRQ_MBHC_REMOVAL, sitar);
4646err_remove_irq:
4647 wcd9xxx_free_irq(codec->control_data,
4648 SITAR_IRQ_MBHC_INSERTION, sitar);
4649err_insert_irq:
4650err_pdata:
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004651 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304652 kfree(sitar);
4653 return ret;
4654}
4655static int sitar_codec_remove(struct snd_soc_codec *codec)
4656{
4657 int i;
4658 struct sitar_priv *sitar = snd_soc_codec_get_drvdata(codec);
4659 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_SLIMBUS, sitar);
4660 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_RELEASE, sitar);
4661 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_POTENTIAL, sitar);
4662 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_REMOVAL, sitar);
4663 wcd9xxx_free_irq(codec->control_data, SITAR_IRQ_MBHC_INSERTION, sitar);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004664 SITAR_ACQUIRE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304665 sitar_codec_disable_clock_block(codec);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004666 SITAR_RELEASE_LOCK(sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304667 sitar_codec_enable_bandgap(codec, SITAR_BANDGAP_OFF);
Asish Bhattacharyaf868a1f2012-03-05 10:07:44 -08004668 if (sitar->mbhc_fw)
4669 release_firmware(sitar->mbhc_fw);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304670 for (i = 0; i < ARRAY_SIZE(sitar_dai); i++)
4671 kfree(sitar->dai[i].ch_num);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004672 mutex_destroy(&sitar->codec_resource_lock);
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304673 kfree(sitar);
4674 return 0;
4675}
4676static struct snd_soc_codec_driver soc_codec_dev_sitar = {
4677 .probe = sitar_codec_probe,
4678 .remove = sitar_codec_remove,
4679 .read = sitar_read,
4680 .write = sitar_write,
4681
4682 .readable_register = sitar_readable,
4683 .volatile_register = sitar_volatile,
4684
4685 .reg_cache_size = SITAR_CACHE_SIZE,
4686 .reg_cache_default = sitar_reg_defaults,
4687 .reg_word_size = 1,
4688};
4689
4690#ifdef CONFIG_DEBUG_FS
4691static struct dentry *debugfs_poke;
4692
4693static int codec_debug_open(struct inode *inode, struct file *file)
4694{
4695 file->private_data = inode->i_private;
4696 return 0;
4697}
4698
4699static ssize_t codec_debug_write(struct file *filp,
4700 const char __user *ubuf, size_t cnt, loff_t *ppos)
4701{
4702 char lbuf[32];
4703 char *buf;
4704 int rc;
4705
4706 if (cnt > sizeof(lbuf) - 1)
4707 return -EINVAL;
4708
4709 rc = copy_from_user(lbuf, ubuf, cnt);
4710 if (rc)
4711 return -EFAULT;
4712
4713 lbuf[cnt] = '\0';
4714 buf = (char *)lbuf;
4715 debug_sitar_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
4716 ? false : true;
4717
4718 return rc;
4719}
4720
4721static const struct file_operations codec_debug_ops = {
4722 .open = codec_debug_open,
4723 .write = codec_debug_write,
4724};
4725#endif
4726
4727#ifdef CONFIG_PM
4728static int sitar_suspend(struct device *dev)
4729{
Asish Bhattacharya1d069532012-03-07 13:25:24 -08004730 dev_dbg(dev, "%s: system suspend\n", __func__);
4731 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304732}
4733
4734static int sitar_resume(struct device *dev)
4735{
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004736 struct platform_device *pdev = to_platform_device(dev);
4737 struct sitar_priv *sitar = platform_get_drvdata(pdev);
Asish Bhattacharya1d069532012-03-07 13:25:24 -08004738 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajare466aafe2012-05-02 17:55:26 -07004739 sitar->mbhc_last_resume = jiffies;
Asish Bhattacharya1d069532012-03-07 13:25:24 -08004740 return 0;
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05304741}
4742
4743static const struct dev_pm_ops sitar_pm_ops = {
4744 .suspend = sitar_suspend,
4745 .resume = sitar_resume,
4746};
4747#endif
4748
4749static int __devinit sitar_probe(struct platform_device *pdev)
4750{
4751 int ret = 0;
4752 pr_err("%s\n", __func__);
4753#ifdef CONFIG_DEBUG_FS
4754 debugfs_poke = debugfs_create_file("TRRS",
4755 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
4756
4757#endif
4758 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_sitar,
4759 sitar_dai, ARRAY_SIZE(sitar_dai));
4760 return ret;
4761}
4762static int __devexit sitar_remove(struct platform_device *pdev)
4763{
4764 snd_soc_unregister_codec(&pdev->dev);
4765
4766#ifdef CONFIG_DEBUG_FS
4767 debugfs_remove(debugfs_poke);
4768#endif
4769 return 0;
4770}
4771static struct platform_driver sitar_codec_driver = {
4772 .probe = sitar_probe,
4773 .remove = sitar_remove,
4774 .driver = {
4775 .name = "sitar_codec",
4776 .owner = THIS_MODULE,
4777#ifdef CONFIG_PM
4778 .pm = &sitar_pm_ops,
4779#endif
4780 },
4781};
4782
4783static int __init sitar_codec_init(void)
4784{
4785 return platform_driver_register(&sitar_codec_driver);
4786}
4787
4788static void __exit sitar_codec_exit(void)
4789{
4790 platform_driver_unregister(&sitar_codec_driver);
4791}
4792
4793module_init(sitar_codec_init);
4794module_exit(sitar_codec_exit);
4795
4796MODULE_DESCRIPTION("Sitar codec driver");
4797MODULE_VERSION("1.0");
4798MODULE_LICENSE("GPL v2");