blob: 758647029ace1e4c17c15f8e2dfee4aea886e8c8 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2011, 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>
Bradley Rubin229c6a52011-07-12 16:18:48 -070014#include <linux/firmware.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070015#include <linux/slab.h>
16#include <linux/platform_device.h>
Santosh Mardie15e2302011-11-15 10:39:23 +053017#include <linux/device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070018#include <linux/printk.h>
19#include <linux/ratelimit.h>
Bradley Rubincb3950a2011-08-18 13:07:26 -070020#include <linux/debugfs.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070021#include <linux/mfd/wcd9310/core.h>
22#include <linux/mfd/wcd9310/registers.h>
Patrick Lai3043fba2011-08-01 14:15:57 -070023#include <linux/mfd/wcd9310/pdata.h>
Santosh Mardie15e2302011-11-15 10:39:23 +053024#include <sound/pcm.h>
25#include <sound/pcm_params.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070026#include <sound/jack.h>
27#include <sound/soc.h>
28#include <sound/soc-dapm.h>
29#include <sound/tlv.h>
30#include <linux/bitops.h>
31#include <linux/delay.h>
32#include "wcd9310.h"
33
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070034#define WCD9310_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
35 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
36
37#define NUM_DECIMATORS 10
38#define NUM_INTERPOLATORS 7
39#define BITS_PER_REG 8
40#define TABLA_RX_DAI_ID 1
41#define TABLA_TX_DAI_ID 2
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080042#define TABLA_CFILT_FAST_MODE 0x00
43#define TABLA_CFILT_SLOW_MODE 0x40
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070044
Patrick Lai49efeac2011-11-03 11:01:12 -070045#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
46
Santosh Mardie15e2302011-11-15 10:39:23 +053047#define TABLA_I2S_MASTER_MODE_MASK 0x08
48
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
50static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
51static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
52
53enum tabla_bandgap_type {
54 TABLA_BANDGAP_OFF = 0,
55 TABLA_BANDGAP_AUDIO_MODE,
56 TABLA_BANDGAP_MBHC_MODE,
57};
58
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070059struct mbhc_micbias_regs {
60 u16 cfilt_val;
61 u16 cfilt_ctl;
62 u16 mbhc_reg;
63 u16 int_rbias;
64 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080065 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070066};
67
Ben Romberger1f045a72011-11-04 10:14:57 -070068/* Codec supports 2 IIR filters */
69enum {
70 IIR1 = 0,
71 IIR2,
72 IIR_MAX,
73};
74/* Codec supports 5 bands */
75enum {
76 BAND1 = 0,
77 BAND2,
78 BAND3,
79 BAND4,
80 BAND5,
81 BAND_MAX,
82};
83
Bradley Rubin229c6a52011-07-12 16:18:48 -070084struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070085 struct snd_soc_codec *codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070086 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -070087 u32 cfilt1_cnt;
88 u32 cfilt2_cnt;
89 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -070090 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -070092 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093 bool clock_active;
94 bool config_mode_active;
95 bool mbhc_polling_active;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -080096 bool fake_insert_context;
Bradley Rubincb1e2732011-06-23 16:49:20 -070097 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098
99 struct tabla_mbhc_calibration *calibration;
100
Bradley Rubincb1e2732011-06-23 16:49:20 -0700101 struct snd_soc_jack *headset_jack;
102 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700103
Patrick Lai3043fba2011-08-01 14:15:57 -0700104 struct tabla_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700105 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700106
107 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700108 /* Delayed work to report long button press */
109 struct delayed_work btn0_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700110
111 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700112 u8 cfilt_k_value;
113 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700114
Santosh Mardie15e2302011-11-15 10:39:23 +0530115 /*track tabla interface type*/
116 u8 intf_type;
117
Patrick Lai49efeac2011-11-03 11:01:12 -0700118 u32 hph_status; /* track headhpone status */
119 /* define separate work for left and right headphone OCP to avoid
120 * additional checking on which OCP event to report so no locking
121 * to ensure synchronization is required
122 */
123 struct work_struct hphlocp_work; /* reporting left hph ocp off */
124 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800125
126 /* pm_cnt holds number of sleep lock holders + 1
127 * so if pm_cnt is 1 system is sleep-able. */
128 atomic_t pm_cnt;
129 wait_queue_head_t pm_wq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130};
131
Bradley Rubincb3950a2011-08-18 13:07:26 -0700132#ifdef CONFIG_DEBUG_FS
133struct tabla_priv *debug_tabla_priv;
134#endif
135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
137 struct snd_kcontrol *kcontrol, int event)
138{
139 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140
141 pr_debug("%s %d\n", __func__, event);
142 switch (event) {
143 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
145 0x01);
146 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
147 usleep_range(200, 200);
148 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
149 break;
150 case SND_SOC_DAPM_PRE_PMD:
151 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
152 0x10);
153 usleep_range(20, 20);
154 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
155 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
156 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
157 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
158 0x00);
159 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160 break;
161 }
162 return 0;
163}
164
Bradley Rubina7096d02011-08-03 18:29:02 -0700165static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
166 struct snd_ctl_elem_value *ucontrol)
167{
168 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
169 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
170 ucontrol->value.integer.value[0] = tabla->anc_slot;
171 return 0;
172}
173
174static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
175 struct snd_ctl_elem_value *ucontrol)
176{
177 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
178 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
179 tabla->anc_slot = ucontrol->value.integer.value[0];
180 return 0;
181}
182
Kiran Kandid2d86b52011-09-09 17:44:28 -0700183static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
184 struct snd_ctl_elem_value *ucontrol)
185{
186 u8 ear_pa_gain;
187 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
188
189 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
190
191 ear_pa_gain = ear_pa_gain >> 5;
192
193 if (ear_pa_gain == 0x00) {
194 ucontrol->value.integer.value[0] = 0;
195 } else if (ear_pa_gain == 0x04) {
196 ucontrol->value.integer.value[0] = 1;
197 } else {
198 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
199 __func__, ear_pa_gain);
200 return -EINVAL;
201 }
202
203 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
204
205 return 0;
206}
207
208static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
209 struct snd_ctl_elem_value *ucontrol)
210{
211 u8 ear_pa_gain;
212 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
213
214 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
215 ucontrol->value.integer.value[0]);
216
217 switch (ucontrol->value.integer.value[0]) {
218 case 0:
219 ear_pa_gain = 0x00;
220 break;
221 case 1:
222 ear_pa_gain = 0x80;
223 break;
224 default:
225 return -EINVAL;
226 }
227
228 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
229 return 0;
230}
231
Ben Romberger1f045a72011-11-04 10:14:57 -0700232static int tabla_get_iir_enable_audio_mixer(
233 struct snd_kcontrol *kcontrol,
234 struct snd_ctl_elem_value *ucontrol)
235{
236 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
237 int iir_idx = ((struct soc_multi_mixer_control *)
238 kcontrol->private_value)->reg;
239 int band_idx = ((struct soc_multi_mixer_control *)
240 kcontrol->private_value)->shift;
241
242 ucontrol->value.integer.value[0] =
243 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
244 (1 << band_idx);
245
246 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
247 iir_idx, band_idx,
248 (uint32_t)ucontrol->value.integer.value[0]);
249 return 0;
250}
251
252static int tabla_put_iir_enable_audio_mixer(
253 struct snd_kcontrol *kcontrol,
254 struct snd_ctl_elem_value *ucontrol)
255{
256 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
257 int iir_idx = ((struct soc_multi_mixer_control *)
258 kcontrol->private_value)->reg;
259 int band_idx = ((struct soc_multi_mixer_control *)
260 kcontrol->private_value)->shift;
261 int value = ucontrol->value.integer.value[0];
262
263 /* Mask first 5 bits, 6-8 are reserved */
264 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
265 (1 << band_idx), (value << band_idx));
266
267 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
268 iir_idx, band_idx, value);
269 return 0;
270}
271static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
272 int iir_idx, int band_idx,
273 int coeff_idx)
274{
275 /* Address does not automatically update if reading */
276 snd_soc_update_bits(codec,
277 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
278 0x1F, band_idx * BAND_MAX + coeff_idx);
279
280 /* Mask bits top 2 bits since they are reserved */
281 return ((snd_soc_read(codec,
282 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
283 (snd_soc_read(codec,
284 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
285 (snd_soc_read(codec,
286 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
287 (snd_soc_read(codec,
288 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
289 0x3FFFFFFF;
290}
291
292static int tabla_get_iir_band_audio_mixer(
293 struct snd_kcontrol *kcontrol,
294 struct snd_ctl_elem_value *ucontrol)
295{
296 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
297 int iir_idx = ((struct soc_multi_mixer_control *)
298 kcontrol->private_value)->reg;
299 int band_idx = ((struct soc_multi_mixer_control *)
300 kcontrol->private_value)->shift;
301
302 ucontrol->value.integer.value[0] =
303 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
304 ucontrol->value.integer.value[1] =
305 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
306 ucontrol->value.integer.value[2] =
307 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
308 ucontrol->value.integer.value[3] =
309 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
310 ucontrol->value.integer.value[4] =
311 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
312
313 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
314 "%s: IIR #%d band #%d b1 = 0x%x\n"
315 "%s: IIR #%d band #%d b2 = 0x%x\n"
316 "%s: IIR #%d band #%d a1 = 0x%x\n"
317 "%s: IIR #%d band #%d a2 = 0x%x\n",
318 __func__, iir_idx, band_idx,
319 (uint32_t)ucontrol->value.integer.value[0],
320 __func__, iir_idx, band_idx,
321 (uint32_t)ucontrol->value.integer.value[1],
322 __func__, iir_idx, band_idx,
323 (uint32_t)ucontrol->value.integer.value[2],
324 __func__, iir_idx, band_idx,
325 (uint32_t)ucontrol->value.integer.value[3],
326 __func__, iir_idx, band_idx,
327 (uint32_t)ucontrol->value.integer.value[4]);
328 return 0;
329}
330
331static void set_iir_band_coeff(struct snd_soc_codec *codec,
332 int iir_idx, int band_idx,
333 int coeff_idx, uint32_t value)
334{
335 /* Mask top 3 bits, 6-8 are reserved */
336 /* Update address manually each time */
337 snd_soc_update_bits(codec,
338 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
339 0x1F, band_idx * BAND_MAX + coeff_idx);
340
341 /* Mask top 2 bits, 7-8 are reserved */
342 snd_soc_update_bits(codec,
343 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
344 0x3F, (value >> 24) & 0x3F);
345
346 /* Isolate 8bits at a time */
347 snd_soc_update_bits(codec,
348 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
349 0xFF, (value >> 16) & 0xFF);
350
351 snd_soc_update_bits(codec,
352 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
353 0xFF, (value >> 8) & 0xFF);
354
355 snd_soc_update_bits(codec,
356 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
357 0xFF, value & 0xFF);
358}
359
360static int tabla_put_iir_band_audio_mixer(
361 struct snd_kcontrol *kcontrol,
362 struct snd_ctl_elem_value *ucontrol)
363{
364 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
365 int iir_idx = ((struct soc_multi_mixer_control *)
366 kcontrol->private_value)->reg;
367 int band_idx = ((struct soc_multi_mixer_control *)
368 kcontrol->private_value)->shift;
369
370 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
371 ucontrol->value.integer.value[0]);
372 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
373 ucontrol->value.integer.value[1]);
374 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
375 ucontrol->value.integer.value[2]);
376 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
377 ucontrol->value.integer.value[3]);
378 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
379 ucontrol->value.integer.value[4]);
380
381 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
382 "%s: IIR #%d band #%d b1 = 0x%x\n"
383 "%s: IIR #%d band #%d b2 = 0x%x\n"
384 "%s: IIR #%d band #%d a1 = 0x%x\n"
385 "%s: IIR #%d band #%d a2 = 0x%x\n",
386 __func__, iir_idx, band_idx,
387 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
388 __func__, iir_idx, band_idx,
389 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
390 __func__, iir_idx, band_idx,
391 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
392 __func__, iir_idx, band_idx,
393 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
394 __func__, iir_idx, band_idx,
395 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
396 return 0;
397}
398
Kiran Kandid2d86b52011-09-09 17:44:28 -0700399static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
400static const struct soc_enum tabla_ear_pa_gain_enum[] = {
401 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
402};
403
Santosh Mardi024010f2011-10-18 06:27:21 +0530404/*cut of frequency for high pass filter*/
405static const char *cf_text[] = {
406 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
407};
408
409static const struct soc_enum cf_dec1_enum =
410 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
411
412static const struct soc_enum cf_dec2_enum =
413 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
414
415static const struct soc_enum cf_dec3_enum =
416 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
417
418static const struct soc_enum cf_dec4_enum =
419 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
420
421static const struct soc_enum cf_dec5_enum =
422 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
423
424static const struct soc_enum cf_dec6_enum =
425 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
426
427static const struct soc_enum cf_dec7_enum =
428 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
429
430static const struct soc_enum cf_dec8_enum =
431 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
432
433static const struct soc_enum cf_dec9_enum =
434 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
435
436static const struct soc_enum cf_dec10_enum =
437 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
438
439static const struct soc_enum cf_rxmix1_enum =
440 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
441
442static const struct soc_enum cf_rxmix2_enum =
443 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
444
445static const struct soc_enum cf_rxmix3_enum =
446 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
447
448static const struct soc_enum cf_rxmix4_enum =
449 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
450
451static const struct soc_enum cf_rxmix5_enum =
452 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
453;
454static const struct soc_enum cf_rxmix6_enum =
455 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
456
457static const struct soc_enum cf_rxmix7_enum =
458 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700461
462 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
463 tabla_pa_gain_get, tabla_pa_gain_put),
464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
466 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700467 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
468 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
470 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700471 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
472 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700473 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
474 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700476 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
477 line_gain),
478 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
479 line_gain),
480
Bradley Rubin410383f2011-07-22 13:44:23 -0700481 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
482 -84, 40, digital_gain),
483 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
484 -84, 40, digital_gain),
485 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
486 -84, 40, digital_gain),
487 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
488 -84, 40, digital_gain),
489 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
490 -84, 40, digital_gain),
491 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
492 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700493
Bradley Rubin410383f2011-07-22 13:44:23 -0700494 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700495 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700496 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700498 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
499 digital_gain),
500 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
501 digital_gain),
502 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
503 digital_gain),
504 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
505 digital_gain),
506 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
507 digital_gain),
508 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
509 digital_gain),
510 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
511 digital_gain),
512 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
513 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700514 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
515 40, digital_gain),
516 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
517 40, digital_gain),
518 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
519 40, digital_gain),
520 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
521 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700522 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
523 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700524 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
525 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700526 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
527 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528
529 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800530 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700531 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
532 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700533
534 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
535 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530536 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
537 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
538 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
539 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
540 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
541 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
542 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
543 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
544 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
545 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
546
547 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
548 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
549 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
550 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
551 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
552 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
553 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
554 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
555 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
556 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
557
558 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
559 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
560 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
561 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
562 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
563 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
564 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
565
566 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
567 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
568 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
569 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
570 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
571 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
572 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700573
574 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
575 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
576 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
577 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
578 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
579 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
580 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
581 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
582 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
583 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
584 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
585 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
586 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
587 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
588 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
589 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
590 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
591 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
592 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
593 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
594
595 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
596 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
597 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
598 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
599 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
600 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
601 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
602 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
603 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
604 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
605 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
606 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
607 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
608 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
609 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
610 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
611 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
612 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
613 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
614 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615};
616
617static const char *rx_mix1_text[] = {
618 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
619 "RX5", "RX6", "RX7"
620};
621
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700622static const char *rx_dsm_text[] = {
623 "CIC_OUT", "DSM_INV"
624};
625
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626static const char *sb_tx1_mux_text[] = {
627 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
628 "DEC1"
629};
630
631static const char *sb_tx5_mux_text[] = {
632 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
633 "DEC5"
634};
635
636static const char *sb_tx6_mux_text[] = {
637 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
638 "DEC6"
639};
640
641static const char const *sb_tx7_to_tx10_mux_text[] = {
642 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
643 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
644 "DEC9", "DEC10"
645};
646
647static const char *dec1_mux_text[] = {
648 "ZERO", "DMIC1", "ADC6",
649};
650
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700651static const char *dec2_mux_text[] = {
652 "ZERO", "DMIC2", "ADC5",
653};
654
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700655static const char *dec3_mux_text[] = {
656 "ZERO", "DMIC3", "ADC4",
657};
658
659static const char *dec4_mux_text[] = {
660 "ZERO", "DMIC4", "ADC3",
661};
662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663static const char *dec5_mux_text[] = {
664 "ZERO", "DMIC5", "ADC2",
665};
666
667static const char *dec6_mux_text[] = {
668 "ZERO", "DMIC6", "ADC1",
669};
670
671static const char const *dec7_mux_text[] = {
672 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
673};
674
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700675static const char *dec8_mux_text[] = {
676 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
677};
678
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700679static const char *dec9_mux_text[] = {
680 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
681};
682
683static const char *dec10_mux_text[] = {
684 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
685};
686
Bradley Rubin229c6a52011-07-12 16:18:48 -0700687static const char const *anc_mux_text[] = {
688 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
689 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
690};
691
692static const char const *anc1_fb_mux_text[] = {
693 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
694};
695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696static const char *iir1_inp1_text[] = {
697 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
698 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
699};
700
701static const struct soc_enum rx_mix1_inp1_chain_enum =
702 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
703
Bradley Rubin229c6a52011-07-12 16:18:48 -0700704static const struct soc_enum rx_mix1_inp2_chain_enum =
705 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707static const struct soc_enum rx2_mix1_inp1_chain_enum =
708 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
709
Bradley Rubin229c6a52011-07-12 16:18:48 -0700710static const struct soc_enum rx2_mix1_inp2_chain_enum =
711 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713static const struct soc_enum rx3_mix1_inp1_chain_enum =
714 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
715
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700716static const struct soc_enum rx3_mix1_inp2_chain_enum =
717 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719static const struct soc_enum rx4_mix1_inp1_chain_enum =
720 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
721
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700722static const struct soc_enum rx4_mix1_inp2_chain_enum =
723 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725static const struct soc_enum rx5_mix1_inp1_chain_enum =
726 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
727
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700728static const struct soc_enum rx5_mix1_inp2_chain_enum =
729 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
730
731static const struct soc_enum rx6_mix1_inp1_chain_enum =
732 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
733
734static const struct soc_enum rx6_mix1_inp2_chain_enum =
735 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
736
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700737static const struct soc_enum rx7_mix1_inp1_chain_enum =
738 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
739
740static const struct soc_enum rx7_mix1_inp2_chain_enum =
741 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
742
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700743static const struct soc_enum rx4_dsm_enum =
744 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
745
746static const struct soc_enum rx6_dsm_enum =
747 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
748
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749static const struct soc_enum sb_tx5_mux_enum =
750 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
751
752static const struct soc_enum sb_tx6_mux_enum =
753 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
754
755static const struct soc_enum sb_tx7_mux_enum =
756 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
757 sb_tx7_to_tx10_mux_text);
758
759static const struct soc_enum sb_tx8_mux_enum =
760 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
761 sb_tx7_to_tx10_mux_text);
762
763static const struct soc_enum sb_tx1_mux_enum =
764 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
765
766static const struct soc_enum dec1_mux_enum =
767 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
768
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700769static const struct soc_enum dec2_mux_enum =
770 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
771
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700772static const struct soc_enum dec3_mux_enum =
773 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
774
775static const struct soc_enum dec4_mux_enum =
776 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778static const struct soc_enum dec5_mux_enum =
779 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
780
781static const struct soc_enum dec6_mux_enum =
782 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
783
784static const struct soc_enum dec7_mux_enum =
785 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
786
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700787static const struct soc_enum dec8_mux_enum =
788 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
789
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700790static const struct soc_enum dec9_mux_enum =
791 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
792
793static const struct soc_enum dec10_mux_enum =
794 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
795
Bradley Rubin229c6a52011-07-12 16:18:48 -0700796static const struct soc_enum anc1_mux_enum =
797 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
798
799static const struct soc_enum anc2_mux_enum =
800 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
801
802static const struct soc_enum anc1_fb_mux_enum =
803 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700805static const struct soc_enum iir1_inp1_mux_enum =
806 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
807
808static const struct snd_kcontrol_new rx_mix1_inp1_mux =
809 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
810
Bradley Rubin229c6a52011-07-12 16:18:48 -0700811static const struct snd_kcontrol_new rx_mix1_inp2_mux =
812 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
813
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
815 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
816
Bradley Rubin229c6a52011-07-12 16:18:48 -0700817static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
818 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
819
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700820static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
821 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
822
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700823static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
824 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
827 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
828
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700829static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
830 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
833 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
834
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700835static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
836 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
837
838static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
839 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
840
841static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
842 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
843
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700844static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
845 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
846
847static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
848 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
849
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700850static const struct snd_kcontrol_new rx4_dsm_mux =
851 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
852
853static const struct snd_kcontrol_new rx6_dsm_mux =
854 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
855
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856static const struct snd_kcontrol_new sb_tx5_mux =
857 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
858
859static const struct snd_kcontrol_new sb_tx6_mux =
860 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
861
862static const struct snd_kcontrol_new sb_tx7_mux =
863 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
864
865static const struct snd_kcontrol_new sb_tx8_mux =
866 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
867
868static const struct snd_kcontrol_new sb_tx1_mux =
869 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
870
871static const struct snd_kcontrol_new dec1_mux =
872 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
873
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700874static const struct snd_kcontrol_new dec2_mux =
875 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
876
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700877static const struct snd_kcontrol_new dec3_mux =
878 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
879
880static const struct snd_kcontrol_new dec4_mux =
881 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883static const struct snd_kcontrol_new dec5_mux =
884 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
885
886static const struct snd_kcontrol_new dec6_mux =
887 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
888
889static const struct snd_kcontrol_new dec7_mux =
890 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
891
Bradley Rubin229c6a52011-07-12 16:18:48 -0700892static const struct snd_kcontrol_new anc1_mux =
893 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700894static const struct snd_kcontrol_new dec8_mux =
895 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
896
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700897static const struct snd_kcontrol_new dec9_mux =
898 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
899
900static const struct snd_kcontrol_new dec10_mux =
901 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903static const struct snd_kcontrol_new iir1_inp1_mux =
904 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
905
Bradley Rubin229c6a52011-07-12 16:18:48 -0700906static const struct snd_kcontrol_new anc2_mux =
907 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908
Bradley Rubin229c6a52011-07-12 16:18:48 -0700909static const struct snd_kcontrol_new anc1_fb_mux =
910 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911
Bradley Rubin229c6a52011-07-12 16:18:48 -0700912static const struct snd_kcontrol_new dac1_switch[] = {
913 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
914};
915static const struct snd_kcontrol_new hphl_switch[] = {
916 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
917};
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700918
919static const struct snd_kcontrol_new lineout3_ground_switch =
920 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
921
922static const struct snd_kcontrol_new lineout4_ground_switch =
923 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
926 int enable)
927{
928 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
929
930 pr_debug("%s %d\n", __func__, enable);
931
932 if (enable) {
933 tabla->adc_count++;
934 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
935 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
936 } else {
937 tabla->adc_count--;
938 if (!tabla->adc_count) {
939 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
940 0x2, 0x0);
941 if (!tabla->mbhc_polling_active)
942 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
943 0xE0, 0x0);
944 }
945 }
946}
947
948static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
949 struct snd_kcontrol *kcontrol, int event)
950{
951 struct snd_soc_codec *codec = w->codec;
952 u16 adc_reg;
953
954 pr_debug("%s %d\n", __func__, event);
955
956 if (w->reg == TABLA_A_TX_1_2_EN)
957 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
958 else if (w->reg == TABLA_A_TX_3_4_EN)
959 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
960 else if (w->reg == TABLA_A_TX_5_6_EN)
961 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
962 else {
963 pr_err("%s: Error, invalid adc register\n", __func__);
964 return -EINVAL;
965 }
966
967 switch (event) {
968 case SND_SOC_DAPM_PRE_PMU:
969 tabla_codec_enable_adc_block(codec, 1);
970 break;
971 case SND_SOC_DAPM_POST_PMU:
972 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
973 1 << w->shift);
974 usleep_range(1000, 1000);
975 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
976 usleep_range(1000, 1000);
977 break;
978 case SND_SOC_DAPM_POST_PMD:
979 tabla_codec_enable_adc_block(codec, 0);
980 break;
981 }
982 return 0;
983}
984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
986 struct snd_kcontrol *kcontrol, int event)
987{
988 struct snd_soc_codec *codec = w->codec;
989 u16 lineout_gain_reg;
990
Kiran Kandidb0a4b02011-08-23 09:32:09 -0700991 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992
993 switch (w->shift) {
994 case 0:
995 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
996 break;
997 case 1:
998 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
999 break;
1000 case 2:
1001 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1002 break;
1003 case 3:
1004 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1005 break;
1006 case 4:
1007 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1008 break;
1009 default:
1010 pr_err("%s: Error, incorrect lineout register value\n",
1011 __func__);
1012 return -EINVAL;
1013 }
1014
1015 switch (event) {
1016 case SND_SOC_DAPM_PRE_PMU:
1017 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1018 break;
1019 case SND_SOC_DAPM_POST_PMU:
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001020 pr_debug("%s: sleeping 40 ms after %s PA turn on\n",
1021 __func__, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 usleep_range(40000, 40000);
1023 break;
1024 case SND_SOC_DAPM_POST_PMD:
1025 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1026 break;
1027 }
1028 return 0;
1029}
1030
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001031
1032static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 struct snd_kcontrol *kcontrol, int event)
1034{
1035 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001036 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1037 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001038 unsigned int dmic;
1039 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001040
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001041 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1042 if (ret < 0) {
1043 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001044 return -EINVAL;
1045 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001047 switch (dmic) {
1048 case 1:
1049 case 2:
1050 dmic_clk_sel = 0x02;
1051 dmic_clk_en = 0x01;
1052 break;
1053
1054 case 3:
1055 case 4:
1056 dmic_clk_sel = 0x08;
1057 dmic_clk_en = 0x04;
1058 break;
1059
1060 case 5:
1061 case 6:
1062 dmic_clk_sel = 0x20;
1063 dmic_clk_en = 0x10;
1064 break;
1065
1066 default:
1067 pr_err("%s: Invalid DMIC Selection\n", __func__);
1068 return -EINVAL;
1069 }
1070
1071 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1072 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1073
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001074 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 switch (event) {
1077 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001078 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1079
1080 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1081 dmic_clk_sel, dmic_clk_sel);
1082
1083 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1084
1085 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1086 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087 break;
1088 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001089 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1090 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 break;
1092 }
1093 return 0;
1094}
1095
Bradley Rubin229c6a52011-07-12 16:18:48 -07001096static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1097 struct snd_kcontrol *kcontrol, int event)
1098{
1099 struct snd_soc_codec *codec = w->codec;
1100 const char *filename;
1101 const struct firmware *fw;
1102 int i;
1103 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001104 int num_anc_slots;
1105 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001106 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001107 u32 anc_writes_size = 0;
1108 int anc_size_remaining;
1109 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001110 u16 reg;
1111 u8 mask, val, old_val;
1112
1113 pr_debug("%s %d\n", __func__, event);
1114 switch (event) {
1115 case SND_SOC_DAPM_PRE_PMU:
1116
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001117 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001118
1119 ret = request_firmware(&fw, filename, codec->dev);
1120 if (ret != 0) {
1121 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1122 ret);
1123 return -ENODEV;
1124 }
1125
Bradley Rubina7096d02011-08-03 18:29:02 -07001126 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001127 dev_err(codec->dev, "Not enough data\n");
1128 release_firmware(fw);
1129 return -ENOMEM;
1130 }
1131
1132 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001133 anc_head = (struct anc_header *)(fw->data);
1134 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1135 anc_size_remaining = fw->size - sizeof(struct anc_header);
1136 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001137
Bradley Rubina7096d02011-08-03 18:29:02 -07001138 if (tabla->anc_slot >= num_anc_slots) {
1139 dev_err(codec->dev, "Invalid ANC slot selected\n");
1140 release_firmware(fw);
1141 return -EINVAL;
1142 }
1143
1144 for (i = 0; i < num_anc_slots; i++) {
1145
1146 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1147 dev_err(codec->dev, "Invalid register format\n");
1148 release_firmware(fw);
1149 return -EINVAL;
1150 }
1151 anc_writes_size = (u32)(*anc_ptr);
1152 anc_size_remaining -= sizeof(u32);
1153 anc_ptr += 1;
1154
1155 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1156 > anc_size_remaining) {
1157 dev_err(codec->dev, "Invalid register format\n");
1158 release_firmware(fw);
1159 return -ENOMEM;
1160 }
1161
1162 if (tabla->anc_slot == i)
1163 break;
1164
1165 anc_size_remaining -= (anc_writes_size *
1166 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001167 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001168 }
1169 if (i == num_anc_slots) {
1170 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001171 release_firmware(fw);
1172 return -ENOMEM;
1173 }
1174
Bradley Rubina7096d02011-08-03 18:29:02 -07001175 for (i = 0; i < anc_writes_size; i++) {
1176 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001177 mask, val);
1178 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001179 snd_soc_write(codec, reg, (old_val & ~mask) |
1180 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001181 }
1182 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001183
1184 break;
1185 case SND_SOC_DAPM_POST_PMD:
1186 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1187 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1188 break;
1189 }
1190 return 0;
1191}
1192
1193
Bradley Rubincb3950a2011-08-18 13:07:26 -07001194static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
1195{
1196 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
1197 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
1198}
1199
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001200static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1201{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001202 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1203
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001204 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001205 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001206 if (!tabla->no_mic_headset_override) {
1207 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1208 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1209 } else {
1210 tabla_codec_disable_button_presses(codec);
1211 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001212 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1213 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1214 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1215}
1216
1217static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1218{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001219 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1220
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001221 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1222 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001223 if (!tabla->no_mic_headset_override) {
1224 tabla_disable_irq(codec->control_data,
1225 TABLA_IRQ_MBHC_POTENTIAL);
1226 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1227 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001228}
1229
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001230static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1231 int mode)
1232{
1233 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1234 u8 reg_mode_val, cur_mode_val;
1235 bool mbhc_was_polling = false;
1236
1237 if (mode)
1238 reg_mode_val = TABLA_CFILT_FAST_MODE;
1239 else
1240 reg_mode_val = TABLA_CFILT_SLOW_MODE;
1241
1242 cur_mode_val = snd_soc_read(codec,
1243 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
1244
1245 if (cur_mode_val != reg_mode_val) {
1246 if (tabla->mbhc_polling_active) {
1247 tabla_codec_pause_hs_polling(codec);
1248 mbhc_was_polling = true;
1249 }
1250 snd_soc_update_bits(codec,
1251 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1252 if (mbhc_was_polling)
1253 tabla_codec_start_hs_polling(codec);
1254 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
1255 cur_mode_val, reg_mode_val);
1256 } else {
1257 pr_debug("%s: CFILT Value is already %x\n",
1258 __func__, cur_mode_val);
1259 }
1260}
1261
1262static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1263 u8 cfilt_sel, int inc)
1264{
1265 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1266 u32 *cfilt_cnt_ptr = NULL;
1267 u16 micb_cfilt_reg;
1268
1269 switch (cfilt_sel) {
1270 case TABLA_CFILT1_SEL:
1271 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
1272 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
1273 break;
1274 case TABLA_CFILT2_SEL:
1275 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
1276 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
1277 break;
1278 case TABLA_CFILT3_SEL:
1279 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
1280 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
1281 break;
1282 default:
1283 return; /* should not happen */
1284 }
1285
1286 if (inc) {
1287 if (!(*cfilt_cnt_ptr)++) {
1288 /* Switch CFILT to slow mode if MBHC CFILT being used */
1289 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1290 tabla_codec_switch_cfilt_mode(codec, 0);
1291
1292 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1293 }
1294 } else {
1295 /* check if count not zero, decrement
1296 * then check if zero, go ahead disable cfilter
1297 */
1298 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1299 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1300
1301 /* Switch CFILT to fast mode if MBHC CFILT being used */
1302 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1303 tabla_codec_switch_cfilt_mode(codec, 1);
1304 }
1305 }
1306}
1307
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001308static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1309{
1310 int rc = -EINVAL;
1311 unsigned min_mv, max_mv;
1312
1313 switch (ldoh_v) {
1314 case TABLA_LDOH_1P95_V:
1315 min_mv = 160;
1316 max_mv = 1800;
1317 break;
1318 case TABLA_LDOH_2P35_V:
1319 min_mv = 200;
1320 max_mv = 2200;
1321 break;
1322 case TABLA_LDOH_2P75_V:
1323 min_mv = 240;
1324 max_mv = 2600;
1325 break;
1326 case TABLA_LDOH_2P85_V:
1327 min_mv = 250;
1328 max_mv = 2700;
1329 break;
1330 default:
1331 goto done;
1332 }
1333
1334 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1335 goto done;
1336
1337 for (rc = 4; rc <= 44; rc++) {
1338 min_mv = max_mv * (rc) / 44;
1339 if (min_mv >= cfilt_mv) {
1340 rc -= 4;
1341 break;
1342 }
1343 }
1344done:
1345 return rc;
1346}
1347
1348static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
1349{
1350 u8 hph_reg_val = 0;
1351 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
1352
1353 return (hph_reg_val & 0x30) ? true : false;
1354}
1355
1356static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
1357 int vddio_switch)
1358{
1359 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1360 int cfilt_k_val;
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001361 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001362
1363 switch (vddio_switch) {
1364 case 1:
1365 if (tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001366
1367 tabla_codec_pause_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001368 /* Enable Mic Bias switch to VDDIO */
1369 tabla->cfilt_k_value = snd_soc_read(codec,
1370 tabla->mbhc_bias_regs.cfilt_val);
1371 cfilt_k_val = tabla_find_k_value(
1372 tabla->pdata->micbias.ldoh_v, 1800);
1373 snd_soc_update_bits(codec,
1374 tabla->mbhc_bias_regs.cfilt_val,
1375 0xFC, (cfilt_k_val << 2));
1376
1377 snd_soc_update_bits(codec,
1378 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1379 snd_soc_update_bits(codec,
1380 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001381 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001382
1383 tabla->mbhc_micbias_switched = true;
1384 pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
1385 __func__);
1386 }
1387 break;
1388
1389 case 0:
1390 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001391 if (tabla->mbhc_polling_active) {
1392 tabla_codec_pause_hs_polling(codec);
1393 mbhc_was_polling = true;
1394 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001395 /* Disable Mic Bias switch to VDDIO */
1396 if (tabla->cfilt_k_value != 0)
1397 snd_soc_update_bits(codec,
1398 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
1399 tabla->cfilt_k_value);
1400 snd_soc_update_bits(codec,
1401 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1402 snd_soc_update_bits(codec,
1403 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1404
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001405 if (mbhc_was_polling)
1406 tabla_codec_start_hs_polling(codec);
1407
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001408 tabla->mbhc_micbias_switched = false;
1409 pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
1410 __func__);
1411 }
1412 break;
1413 }
1414}
1415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1417 struct snd_kcontrol *kcontrol, int event)
1418{
1419 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07001420 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1421 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001422 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001423 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001424 char *internal1_text = "Internal1";
1425 char *internal2_text = "Internal2";
1426 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427
1428 pr_debug("%s %d\n", __func__, event);
1429 switch (w->reg) {
1430 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001432 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001433 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 break;
1435 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001437 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001438 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 break;
1440 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001442 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001443 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001444 break;
1445 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001446 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001447 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001448 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 break;
1450 default:
1451 pr_err("%s: Error, invalid micbias register\n", __func__);
1452 return -EINVAL;
1453 }
1454
1455 switch (event) {
1456 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001457 /* Decide whether to switch the micbias for MBHC */
1458 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1459 && tabla->mbhc_micbias_switched)
1460 tabla_codec_switch_micbias(codec, 0);
1461
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001462 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07001463 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001464
1465 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001467 else if (strnstr(w->name, internal2_text, 30))
1468 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1469 else if (strnstr(w->name, internal3_text, 30))
1470 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
1471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001472 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001473 case SND_SOC_DAPM_POST_PMU:
1474 if (tabla->mbhc_polling_active &&
1475 (tabla->calibration->bias == micb_line)) {
1476 tabla_codec_pause_hs_polling(codec);
1477 tabla_codec_start_hs_polling(codec);
1478 }
1479 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001480
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001482
1483 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1484 && tabla_is_hph_pa_on(codec))
1485 tabla_codec_switch_micbias(codec, 1);
1486
Bradley Rubin229c6a52011-07-12 16:18:48 -07001487 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001488 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001489 else if (strnstr(w->name, internal2_text, 30))
1490 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1491 else if (strnstr(w->name, internal3_text, 30))
1492 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1493
Patrick Lai3043fba2011-08-01 14:15:57 -07001494 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001495 break;
1496 }
1497
1498 return 0;
1499}
1500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001501static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
1502 struct snd_kcontrol *kcontrol, int event)
1503{
1504 struct snd_soc_codec *codec = w->codec;
1505 u16 dec_reset_reg;
1506
1507 pr_debug("%s %d\n", __func__, event);
1508
1509 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1510 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
1511 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
1512 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
1513 else {
1514 pr_err("%s: Error, incorrect dec\n", __func__);
1515 return -EINVAL;
1516 }
1517
1518 switch (event) {
1519 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1521 1 << w->shift);
1522 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1523 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001524 }
1525 return 0;
1526}
1527
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001528static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 struct snd_kcontrol *kcontrol, int event)
1530{
1531 struct snd_soc_codec *codec = w->codec;
1532
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001533 pr_debug("%s %d %s\n", __func__, event, w->name);
1534
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535 switch (event) {
1536 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001537 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1538 1 << w->shift, 1 << w->shift);
1539 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1540 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541 break;
1542 }
1543 return 0;
1544}
1545
Bradley Rubin229c6a52011-07-12 16:18:48 -07001546static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1547 struct snd_kcontrol *kcontrol, int event)
1548{
1549 switch (event) {
1550 case SND_SOC_DAPM_POST_PMU:
1551 case SND_SOC_DAPM_POST_PMD:
1552 usleep_range(1000, 1000);
1553 break;
1554 }
1555 return 0;
1556}
1557
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001558
1559static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1560{
1561 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1562
1563 if (enable) {
1564 tabla->rx_bias_count++;
1565 if (tabla->rx_bias_count == 1)
1566 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1567 0x80, 0x80);
1568 } else {
1569 tabla->rx_bias_count--;
1570 if (!tabla->rx_bias_count)
1571 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1572 0x80, 0x00);
1573 }
1574}
1575
1576static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1577 struct snd_kcontrol *kcontrol, int event)
1578{
1579 struct snd_soc_codec *codec = w->codec;
1580
1581 pr_debug("%s %d\n", __func__, event);
1582
1583 switch (event) {
1584 case SND_SOC_DAPM_PRE_PMU:
1585 tabla_enable_rx_bias(codec, 1);
1586 break;
1587 case SND_SOC_DAPM_POST_PMD:
1588 tabla_enable_rx_bias(codec, 0);
1589 break;
1590 }
1591 return 0;
1592}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001593static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
1594 struct snd_kcontrol *kcontrol, int event)
1595{
1596 struct snd_soc_codec *codec = w->codec;
1597
1598 pr_debug("%s %s %d\n", __func__, w->name, event);
1599
1600 switch (event) {
1601 case SND_SOC_DAPM_PRE_PMU:
1602 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1603 break;
1604 case SND_SOC_DAPM_POST_PMD:
1605 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1606 break;
1607 }
1608 return 0;
1609}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001610
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001611static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
1612 struct snd_soc_jack *jack, int status,
1613 int mask)
1614{
1615 /* XXX: wake_lock_timeout()? */
1616 snd_soc_jack_report(jack, status, mask);
1617}
1618
Patrick Lai49efeac2011-11-03 11:01:12 -07001619static void hphocp_off_report(struct tabla_priv *tabla,
1620 u32 jack_status, int irq)
1621{
1622 struct snd_soc_codec *codec;
1623
1624 if (tabla) {
1625 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
1626 codec = tabla->codec;
1627 tabla->hph_status &= ~jack_status;
1628 if (tabla->headset_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001629 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
1630 tabla->hph_status,
1631 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07001632 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
1633 0x00);
1634 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
1635 0x10);
1636 tabla_enable_irq(codec->control_data, irq);
1637 } else {
1638 pr_err("%s: Bad tabla private data\n", __func__);
1639 }
1640}
1641
1642static void hphlocp_off_report(struct work_struct *work)
1643{
1644 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1645 hphlocp_work);
1646 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
1647}
1648
1649static void hphrocp_off_report(struct work_struct *work)
1650{
1651 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1652 hphrocp_work);
1653 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
1654}
1655
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001656static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
1657 struct snd_kcontrol *kcontrol, int event)
1658{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001659 struct snd_soc_codec *codec = w->codec;
1660 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1661 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001662 pr_debug("%s: event = %d\n", __func__, event);
1663
1664 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001665 case SND_SOC_DAPM_PRE_PMU:
1666 mbhc_micb_ctl_val = snd_soc_read(codec,
1667 tabla->mbhc_bias_regs.ctl_reg);
1668
1669 if (!(mbhc_micb_ctl_val & 0x80)
1670 && !tabla->mbhc_micbias_switched)
1671 tabla_codec_switch_micbias(codec, 1);
1672
1673 break;
1674
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001675 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07001676 /* schedule work is required because at the time HPH PA DAPM
1677 * event callback is called by DAPM framework, CODEC dapm mutex
1678 * would have been locked while snd_soc_jack_report also
1679 * attempts to acquire same lock.
1680 */
1681 if ((tabla->hph_status & SND_JACK_OC_HPHL) &&
1682 strnstr(w->name, "HPHL", 4))
1683 schedule_work(&tabla->hphlocp_work);
1684 else if ((tabla->hph_status & SND_JACK_OC_HPHR) &&
1685 strnstr(w->name, "HPHR", 4))
1686 schedule_work(&tabla->hphrocp_work);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001687 if (tabla->mbhc_micbias_switched)
1688 tabla_codec_switch_micbias(codec, 0);
1689
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001690 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
1691 w->name);
1692 usleep_range(10000, 10000);
1693
1694 break;
1695 }
1696 return 0;
1697}
1698
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001699static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
1700 struct mbhc_micbias_regs *micbias_regs)
1701{
1702 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1703 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1704 unsigned int cfilt;
1705
1706 switch (calibration->bias) {
1707 case TABLA_MICBIAS1:
1708 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
1709 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
1710 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
1711 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
1712 break;
1713 case TABLA_MICBIAS2:
1714 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
1715 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
1716 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
1717 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
1718 break;
1719 case TABLA_MICBIAS3:
1720 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
1721 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
1722 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
1723 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
1724 break;
1725 case TABLA_MICBIAS4:
1726 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
1727 micbias_regs->mbhc_reg = TABLA_A_MICB_4_MBHC;
1728 micbias_regs->int_rbias = TABLA_A_MICB_4_INT_RBIAS;
1729 micbias_regs->ctl_reg = TABLA_A_MICB_4_CTL;
1730 break;
1731 default:
1732 /* Should never reach here */
1733 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07001734 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001735 }
1736
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001737 micbias_regs->cfilt_sel = cfilt;
1738
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001739 switch (cfilt) {
1740 case TABLA_CFILT1_SEL:
1741 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
1742 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
1743 break;
1744 case TABLA_CFILT2_SEL:
1745 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
1746 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
1747 break;
1748 case TABLA_CFILT3_SEL:
1749 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
1750 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
1751 break;
1752 }
1753}
Santosh Mardie15e2302011-11-15 10:39:23 +05301754static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
1755 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
1756 4, 0, NULL, 0),
1757 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
1758 0, NULL, 0),
1759};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001760
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001761static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
1762 struct snd_kcontrol *kcontrol, int event)
1763{
1764 struct snd_soc_codec *codec = w->codec;
1765
1766 pr_debug("%s %s %d\n", __func__, w->name, event);
1767
1768 switch (event) {
1769 case SND_SOC_DAPM_PRE_PMU:
1770 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1771 break;
1772
1773 case SND_SOC_DAPM_POST_PMD:
1774 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1775 break;
1776 }
1777 return 0;
1778}
1779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
1781 /*RX stuff */
1782 SND_SOC_DAPM_OUTPUT("EAR"),
1783
Kiran Kandid2d86b52011-09-09 17:44:28 -07001784 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785
Bradley Rubin229c6a52011-07-12 16:18:48 -07001786 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
1787 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788
Bradley Rubin229c6a52011-07-12 16:18:48 -07001789 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1790 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Santosh Mardie15e2302011-11-15 10:39:23 +05301791 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1792 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001793
1794 /* Headphone */
1795 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001796 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001797 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1798 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001799 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
1800 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001801
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001802 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001803 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1804 SND_SOC_DAPM_POST_PMD),
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001805
1806 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
1807 tabla_hphr_dac_event,
1808 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809
1810 /* Speaker */
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001811 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
1812 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
1813 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
1814 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
1815 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001816
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001817 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
1818 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1819 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1820 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
1821 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1822 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1823 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
1824 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1825 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1826 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
1827 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1828 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1829 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001830 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1831 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001832
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001833 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
1834 , tabla_lineout_dac_event,
1835 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1836 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
1837 , tabla_lineout_dac_event,
1838 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1839 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
1840 , tabla_lineout_dac_event,
1841 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1842 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
1843 &lineout3_ground_switch),
1844 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
1845 , tabla_lineout_dac_event,
1846 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1847 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
1848 &lineout4_ground_switch),
1849 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
1850 , tabla_lineout_dac_event,
1851 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001852
Bradley Rubin229c6a52011-07-12 16:18:48 -07001853 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
1854 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1855 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
1856 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1857 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
1858 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1859 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
1860 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1861 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
1862 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1863 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
1864 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001865 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
1866 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001867
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001868
1869 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
1870 &rx4_dsm_mux, tabla_codec_reset_interpolator,
1871 SND_SOC_DAPM_PRE_PMU),
1872
1873 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
1874 &rx6_dsm_mux, tabla_codec_reset_interpolator,
1875 SND_SOC_DAPM_PRE_PMU),
1876
Bradley Rubin229c6a52011-07-12 16:18:48 -07001877 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
1878 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
1879
1880 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1881 &rx_mix1_inp1_mux),
1882 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1883 &rx_mix1_inp2_mux),
1884 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1885 &rx2_mix1_inp1_mux),
1886 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1887 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001888 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1889 &rx3_mix1_inp1_mux),
1890 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1891 &rx3_mix1_inp2_mux),
1892 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1893 &rx4_mix1_inp1_mux),
1894 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1895 &rx4_mix1_inp2_mux),
1896 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1897 &rx5_mix1_inp1_mux),
1898 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1899 &rx5_mix1_inp2_mux),
1900 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1901 &rx6_mix1_inp1_mux),
1902 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1903 &rx6_mix1_inp2_mux),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001904 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1905 &rx7_mix1_inp1_mux),
1906 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1907 &rx7_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908
Bradley Rubin229c6a52011-07-12 16:18:48 -07001909 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
1910 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
1911 SND_SOC_DAPM_PRE_PMD),
1912
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001913 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
1914 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
1915 SND_SOC_DAPM_POST_PMD),
1916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001917 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001918
Bradley Rubine1d08622011-07-20 18:01:35 -07001919 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
1920 0),
1921
Bradley Rubin229c6a52011-07-12 16:18:48 -07001922 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
1923 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
1924
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001925 SND_SOC_DAPM_INPUT("AMIC1"),
1926 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
1927 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001928 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001929 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
1930 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001931 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001932 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001933 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001934 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
1936 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1937 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1938
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001939 SND_SOC_DAPM_INPUT("AMIC3"),
1940 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
1941 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1942 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1943
1944 SND_SOC_DAPM_INPUT("AMIC4"),
1945 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
1946 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1947 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1948
1949 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
1950 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001951 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001952
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001953 SND_SOC_DAPM_INPUT("AMIC5"),
1954 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
1955 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1956
1957 SND_SOC_DAPM_INPUT("AMIC6"),
1958 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
1959 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
1960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001962 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001963
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001964 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001965 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001966
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001967 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001968 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001969
1970 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001971 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001972
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001973 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001974 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001975
1976 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001977 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001978
1979 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001980 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001981
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001982 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001983 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001984
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001985 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001986 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001987
1988 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
Bradley Rubine1d08622011-07-20 18:01:35 -07001989 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001990
Bradley Rubin229c6a52011-07-12 16:18:48 -07001991 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
1992 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
1993
1994 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
1995 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
1996 SND_SOC_DAPM_POST_PMD),
1997
1998 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
1999
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002000 SND_SOC_DAPM_INPUT("AMIC2"),
2001 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
2002 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002003 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002004 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
2005 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002006 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002007 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
2008 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002009 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002010 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002012 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002013 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
2014 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002015 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002016 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
2017 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002018 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002019 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002020 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002021 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002022 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
2023 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2024 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2025
2026 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
2027 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
2028 0, 0),
2029
2030 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
2031 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
2032 4, 0),
2033
2034 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
2035 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
2036 5, 0),
2037
2038 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
2039 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
2040 0, 0),
2041
2042 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
2043 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
2044 0, 0),
2045
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002046 /* Digital Mic Inputs */
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002047 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2048 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2049 SND_SOC_DAPM_POST_PMD),
2050
2051 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2052 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2053 SND_SOC_DAPM_POST_PMD),
2054
2055 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
2056 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2057 SND_SOC_DAPM_POST_PMD),
2058
2059 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
2060 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2061 SND_SOC_DAPM_POST_PMD),
2062
2063 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
2064 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2065 SND_SOC_DAPM_POST_PMD),
2066
2067 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
2068 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2069 SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002070
2071 /* Sidetone */
2072 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2073 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2074};
2075
Santosh Mardie15e2302011-11-15 10:39:23 +05302076static const struct snd_soc_dapm_route audio_i2s_map[] = {
2077 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2078 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2079 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2080 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2081 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2082
2083 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2084 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2085 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2086 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2087};
2088
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089static const struct snd_soc_dapm_route audio_map[] = {
2090 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002091
2092 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2093 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2094
2095 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2096 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2097
2098 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2099 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2100
2101 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2102 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002103 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002104 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2105 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002106 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2107 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002108 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2109 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002110 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2111 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002112
2113 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002114 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2115 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2116 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002117 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2119 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2120
2121 /* Earpiece (RX MIX1) */
2122 {"EAR", NULL, "EAR PA"},
Kiran Kandiac034ac2011-07-29 16:39:08 -07002123 {"EAR PA", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002124 {"DAC1", NULL, "CP"},
2125
2126 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2127 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2128 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002129
2130 /* Headset (RX MIX1 and RX MIX2) */
2131 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002132 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002133
2134 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002135 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002136
2137 {"HPHL DAC", NULL, "CP"},
2138 {"HPHR DAC", NULL, "CP"},
2139
2140 {"ANC", NULL, "ANC1 MUX"},
2141 {"ANC", NULL, "ANC2 MUX"},
2142 {"ANC1 MUX", "ADC1", "ADC1"},
2143 {"ANC1 MUX", "ADC2", "ADC2"},
2144 {"ANC1 MUX", "ADC3", "ADC3"},
2145 {"ANC1 MUX", "ADC4", "ADC4"},
2146 {"ANC2 MUX", "ADC1", "ADC1"},
2147 {"ANC2 MUX", "ADC2", "ADC2"},
2148 {"ANC2 MUX", "ADC3", "ADC3"},
2149 {"ANC2 MUX", "ADC4", "ADC4"},
2150
Bradley Rubine1d08622011-07-20 18:01:35 -07002151 {"ANC", NULL, "CDC_CONN"},
2152
Bradley Rubin229c6a52011-07-12 16:18:48 -07002153 {"DAC1", "Switch", "RX1 CHAIN"},
2154 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002155 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002156
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002157 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2158 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2159 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2160 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2161 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002162
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002163 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2164 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2165 {"LINEOUT3 PA", NULL, "LINEOUT3 DAC"},
2166 {"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
2167 {"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002168
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002169 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2170 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2171
Bradley Rubin229c6a52011-07-12 16:18:48 -07002172 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2173 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2174 {"RX1 CHAIN", NULL, "ANC"},
2175 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002176
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002177 {"CP", NULL, "RX_BIAS"},
2178 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2179 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2180 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2181 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002182 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002183
Bradley Rubin229c6a52011-07-12 16:18:48 -07002184 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2185 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2186 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2187 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002188 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2189 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2190 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2191 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2192 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2193 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2194 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2195 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002196 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2197 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002198
Bradley Rubin229c6a52011-07-12 16:18:48 -07002199 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2200 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302201 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2202 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002203 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2204 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2205 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302206 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2207 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002208 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2209 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2210 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302211 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2212 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002213 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002214 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2215 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302216 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2217 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002218 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002219 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2220 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302221 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2222 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002223 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002224 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2225 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302226 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2227 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002228 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002229 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2230 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302231 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2232 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002233 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002234 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2235 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302236 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2237 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002238 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002239 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2240 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302241 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2242 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002243 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002244 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2245 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302246 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2247 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002248 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002249 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2250 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302251 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2252 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002253 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002254 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2255 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302256 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2257 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002258 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002259 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2260 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302261 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2262 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002263 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002264 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2265 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302266 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2267 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002268 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002270 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002271 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002272 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002273 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002274 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002275 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002276 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002277 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002278 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002279 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002280 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002281 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002282 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002283 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002284 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002285 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002286 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002287 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002288 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002289 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002290 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002291 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002292 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002293 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002294 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002295 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002296 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002297 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002298
2299 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300 {"ADC1", NULL, "AMIC1"},
2301 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002302 {"ADC3", NULL, "AMIC3"},
2303 {"ADC4", NULL, "AMIC4"},
2304 {"ADC5", NULL, "AMIC5"},
2305 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002307 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002308 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2309 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2310 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2311 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2312 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002314 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
2315 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
2316 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
2317 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002318
2319 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2320 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2321 {"MIC BIAS1 External", NULL, "LDO_H"},
2322 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2323 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2324 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2325 {"MIC BIAS2 External", NULL, "LDO_H"},
2326 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2327 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2328 {"MIC BIAS3 External", NULL, "LDO_H"},
2329 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330};
2331
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002332static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
2333
2334 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2335 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2336
2337 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
2338
2339 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
2340 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
2341 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
2342
2343 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2344 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2345
2346 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2347 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
2348 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
2349};
2350
Kiran Kandi7a9fd902011-11-14 13:51:45 -08002351
2352static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
2353
2354 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2355 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2356
2357 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
2358
2359 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
2360
2361 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2362 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2363
2364 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2365};
2366
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
2368{
2369 return tabla_reg_readable[reg];
2370}
2371
2372static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2373{
2374 /* Registers lower than 0x100 are top level registers which can be
2375 * written by the Tabla core driver.
2376 */
2377
2378 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2379 return 1;
2380
Ben Romberger1f045a72011-11-04 10:14:57 -07002381 /* IIR Coeff registers are not cacheable */
2382 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
2383 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
2384 return 1;
2385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002386 return 0;
2387}
2388
2389#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2390static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
2391 unsigned int value)
2392{
2393 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394
2395 BUG_ON(reg > TABLA_MAX_REGISTER);
2396
2397 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398 ret = snd_soc_cache_write(codec, reg, value);
2399 if (ret != 0)
2400 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2401 reg, ret);
2402 }
2403
2404 return tabla_reg_write(codec->control_data, reg, value);
2405}
2406static unsigned int tabla_read(struct snd_soc_codec *codec,
2407 unsigned int reg)
2408{
2409 unsigned int val;
2410 int ret;
2411
2412 BUG_ON(reg > TABLA_MAX_REGISTER);
2413
2414 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
2415 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002416 ret = snd_soc_cache_read(codec, reg, &val);
2417 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418 return val;
2419 } else
2420 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2421 reg, ret);
2422 }
2423
2424 val = tabla_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425 return val;
2426}
2427
2428static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2429{
2430 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
2431 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2432 0x80);
2433 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
2434 0x04);
2435 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2436 0x01);
2437 usleep_range(1000, 1000);
2438 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2439 0x00);
2440}
2441
2442static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
2443 enum tabla_bandgap_type choice)
2444{
2445 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2446
2447 /* TODO lock resources accessed by audio streams and threaded
2448 * interrupt handlers
2449 */
2450
2451 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
2452 tabla->bandgap_type);
2453
2454 if (tabla->bandgap_type == choice)
2455 return;
2456
2457 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
2458 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2459 tabla_codec_enable_audio_mode_bandgap(codec);
2460 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
2461 (choice == TABLA_BANDGAP_MBHC_MODE)) {
2462 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
2463 0x2);
2464 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2465 0x80);
2466 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
2467 0x4);
2468 usleep_range(1000, 1000);
2469 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2470 0x00);
2471 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
2472 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2473 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2474 usleep_range(100, 100);
2475 tabla_codec_enable_audio_mode_bandgap(codec);
2476 } else if (choice == TABLA_BANDGAP_OFF) {
2477 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2478 } else {
2479 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2480 }
2481 tabla->bandgap_type = choice;
2482}
2483
2484static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
2485 int enable)
2486{
2487 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2488
2489 if (enable) {
2490 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
2491 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
2492 usleep_range(5, 5);
2493 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
2494 0x80);
2495 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
2496 0x80);
2497 usleep_range(10, 10);
2498 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
2499 usleep_range(20, 20);
2500 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
2501 } else {
2502 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
2503 0);
2504 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
2505 }
2506 tabla->config_mode_active = enable ? true : false;
2507
2508 return 0;
2509}
2510
2511static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
2512 int config_mode)
2513{
2514 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2515
2516 pr_debug("%s\n", __func__);
2517
2518 if (config_mode) {
2519 tabla_codec_enable_config_mode(codec, 1);
2520 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
2521 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2522 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
2523 usleep_range(1000, 1000);
2524 } else
2525 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
2526
2527 if (!config_mode && tabla->mbhc_polling_active) {
2528 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2529 tabla_codec_enable_config_mode(codec, 0);
2530
2531 }
2532
2533 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
2534 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
2535 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
2536 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
2537 usleep_range(50, 50);
2538 tabla->clock_active = true;
2539 return 0;
2540}
2541static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
2542{
2543 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2544 pr_debug("%s\n", __func__);
2545 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
2546 ndelay(160);
2547 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
2548 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
2549 tabla->clock_active = false;
2550}
2551
Bradley Rubincb1e2732011-06-23 16:49:20 -07002552static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2553{
2554 /* TODO store register values in calibration */
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07002555 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL, 0x20);
2556 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL, 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002557
2558 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07002559 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x20);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002560
Bhalchandra Gajarefabb8772011-11-10 19:52:01 -08002561 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0xF8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002562 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
2563 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
2564 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
2565
2566 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
2567 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
2568 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
2569 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
2570 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
2571 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
2572}
2573
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002574static int tabla_startup(struct snd_pcm_substream *substream,
2575 struct snd_soc_dai *dai)
2576{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002577 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2578 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002580 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002581}
2582
2583static void tabla_shutdown(struct snd_pcm_substream *substream,
2584 struct snd_soc_dai *dai)
2585{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002586 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2587 substream->name, substream->stream);
2588}
2589
2590int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
2591{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002592 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2593
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002594 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002595
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002596 if (mclk_enable) {
2597 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002598
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002599 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07002600 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002601 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002602 TABLA_BANDGAP_AUDIO_MODE);
2603 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002604 tabla_codec_calibrate_hs_polling(codec);
2605 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002606 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002607 } else {
2608
2609 if (!tabla->mclk_enabled) {
2610 pr_err("Error, MCLK already diabled\n");
2611 return -EINVAL;
2612 }
2613 tabla->mclk_enabled = false;
2614
2615 if (tabla->mbhc_polling_active) {
2616 if (!tabla->mclk_enabled) {
2617 tabla_codec_pause_hs_polling(codec);
2618 tabla_codec_enable_bandgap(codec,
2619 TABLA_BANDGAP_MBHC_MODE);
2620 tabla_enable_rx_bias(codec, 1);
2621 tabla_codec_enable_clock_block(codec, 1);
2622 tabla_codec_calibrate_hs_polling(codec);
2623 tabla_codec_start_hs_polling(codec);
2624 }
2625 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
2626 0x05, 0x01);
2627 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002628 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002629 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630}
2631
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002632static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
2633 int clk_id, unsigned int freq, int dir)
2634{
2635 pr_debug("%s\n", __func__);
2636 return 0;
2637}
2638
2639static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2640{
Santosh Mardie15e2302011-11-15 10:39:23 +05302641 u8 val = 0;
2642 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
2643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05302645 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2646 case SND_SOC_DAIFMT_CBS_CFS:
2647 /* CPU is master */
2648 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2649 if (dai->id == TABLA_TX_DAI_ID)
2650 snd_soc_update_bits(dai->codec,
2651 TABLA_A_CDC_CLK_TX_I2S_CTL,
2652 TABLA_I2S_MASTER_MODE_MASK, 0);
2653 else if (dai->id == TABLA_RX_DAI_ID)
2654 snd_soc_update_bits(dai->codec,
2655 TABLA_A_CDC_CLK_RX_I2S_CTL,
2656 TABLA_I2S_MASTER_MODE_MASK, 0);
2657 }
2658 break;
2659 case SND_SOC_DAIFMT_CBM_CFM:
2660 /* CPU is slave */
2661 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2662 val = TABLA_I2S_MASTER_MODE_MASK;
2663 if (dai->id == TABLA_TX_DAI_ID)
2664 snd_soc_update_bits(dai->codec,
2665 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
2666 else if (dai->id == TABLA_RX_DAI_ID)
2667 snd_soc_update_bits(dai->codec,
2668 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
2669 }
2670 break;
2671 default:
2672 return -EINVAL;
2673 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002674 return 0;
2675}
2676
2677static int tabla_hw_params(struct snd_pcm_substream *substream,
2678 struct snd_pcm_hw_params *params,
2679 struct snd_soc_dai *dai)
2680{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002681 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05302682 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07002683 u8 path, shift;
2684 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002685 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
2686
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002688
2689 switch (params_rate(params)) {
2690 case 8000:
2691 tx_fs_rate = 0x00;
2692 rx_fs_rate = 0x00;
2693 break;
2694 case 16000:
2695 tx_fs_rate = 0x01;
2696 rx_fs_rate = 0x20;
2697 break;
2698 case 32000:
2699 tx_fs_rate = 0x02;
2700 rx_fs_rate = 0x40;
2701 break;
2702 case 48000:
2703 tx_fs_rate = 0x03;
2704 rx_fs_rate = 0x60;
2705 break;
2706 default:
2707 pr_err("%s: Invalid sampling rate %d\n", __func__,
2708 params_rate(params));
2709 return -EINVAL;
2710 }
2711
2712
2713 /**
2714 * If current dai is a tx dai, set sample rate to
2715 * all the txfe paths that are currently not active
2716 */
2717 if (dai->id == TABLA_TX_DAI_ID) {
2718
2719 tx_state = snd_soc_read(codec,
2720 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
2721
2722 for (path = 1, shift = 0;
2723 path <= NUM_DECIMATORS; path++, shift++) {
2724
2725 if (path == BITS_PER_REG + 1) {
2726 shift = 0;
2727 tx_state = snd_soc_read(codec,
2728 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
2729 }
2730
2731 if (!(tx_state & (1 << shift))) {
2732 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
2733 + (BITS_PER_REG*(path-1));
2734 snd_soc_update_bits(codec, tx_fs_reg,
2735 0x03, tx_fs_rate);
2736 }
2737 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302738 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2739 switch (params_format(params)) {
2740 case SNDRV_PCM_FORMAT_S16_LE:
2741 snd_soc_update_bits(codec,
2742 TABLA_A_CDC_CLK_TX_I2S_CTL,
2743 0x20, 0x20);
2744 break;
2745 case SNDRV_PCM_FORMAT_S32_LE:
2746 snd_soc_update_bits(codec,
2747 TABLA_A_CDC_CLK_TX_I2S_CTL,
2748 0x20, 0x00);
2749 break;
2750 default:
2751 pr_err("invalid format\n");
2752 break;
2753 }
2754 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
2755 0x03, tx_fs_rate);
2756 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002757 }
2758
2759 /**
2760 * TODO: Need to handle case where same RX chain takes 2 or more inputs
2761 * with varying sample rates
2762 */
2763
2764 /**
2765 * If current dai is a rx dai, set sample rate to
2766 * all the rx paths that are currently not active
2767 */
2768 if (dai->id == TABLA_RX_DAI_ID) {
2769
2770 rx_state = snd_soc_read(codec,
2771 TABLA_A_CDC_CLK_RX_B1_CTL);
2772
2773 for (path = 1, shift = 0;
2774 path <= NUM_INTERPOLATORS; path++, shift++) {
2775
2776 if (!(rx_state & (1 << shift))) {
2777 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
2778 + (BITS_PER_REG*(path-1));
2779 snd_soc_update_bits(codec, rx_fs_reg,
2780 0xE0, rx_fs_rate);
2781 }
2782 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302783 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2784 switch (params_format(params)) {
2785 case SNDRV_PCM_FORMAT_S16_LE:
2786 snd_soc_update_bits(codec,
2787 TABLA_A_CDC_CLK_RX_I2S_CTL,
2788 0x20, 0x20);
2789 break;
2790 case SNDRV_PCM_FORMAT_S32_LE:
2791 snd_soc_update_bits(codec,
2792 TABLA_A_CDC_CLK_RX_I2S_CTL,
2793 0x20, 0x00);
2794 break;
2795 default:
2796 pr_err("invalid format\n");
2797 break;
2798 }
2799 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
2800 0x03, (rx_fs_rate >> 0x05));
2801 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002802 }
2803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002804 return 0;
2805}
2806
2807static struct snd_soc_dai_ops tabla_dai_ops = {
2808 .startup = tabla_startup,
2809 .shutdown = tabla_shutdown,
2810 .hw_params = tabla_hw_params,
2811 .set_sysclk = tabla_set_dai_sysclk,
2812 .set_fmt = tabla_set_dai_fmt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002813};
2814
2815static struct snd_soc_dai_driver tabla_dai[] = {
2816 {
2817 .name = "tabla_rx1",
2818 .id = 1,
2819 .playback = {
2820 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002821 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002822 .formats = TABLA_FORMATS,
2823 .rate_max = 48000,
2824 .rate_min = 8000,
2825 .channels_min = 1,
2826 .channels_max = 2,
2827 },
2828 .ops = &tabla_dai_ops,
2829 },
2830 {
2831 .name = "tabla_tx1",
2832 .id = 2,
2833 .capture = {
2834 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002835 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002836 .formats = TABLA_FORMATS,
2837 .rate_max = 48000,
2838 .rate_min = 8000,
2839 .channels_min = 1,
2840 .channels_max = 2,
2841 },
2842 .ops = &tabla_dai_ops,
2843 },
2844};
Santosh Mardie15e2302011-11-15 10:39:23 +05302845
2846static struct snd_soc_dai_driver tabla_i2s_dai[] = {
2847 {
2848 .name = "tabla_i2s_rx1",
2849 .id = 1,
2850 .playback = {
2851 .stream_name = "AIF1 Playback",
2852 .rates = WCD9310_RATES,
2853 .formats = TABLA_FORMATS,
2854 .rate_max = 48000,
2855 .rate_min = 8000,
2856 .channels_min = 1,
2857 .channels_max = 4,
2858 },
2859 .ops = &tabla_dai_ops,
2860 },
2861 {
2862 .name = "tabla_i2s_tx1",
2863 .id = 2,
2864 .capture = {
2865 .stream_name = "AIF1 Capture",
2866 .rates = WCD9310_RATES,
2867 .formats = TABLA_FORMATS,
2868 .rate_max = 48000,
2869 .rate_min = 8000,
2870 .channels_min = 1,
2871 .channels_max = 4,
2872 },
2873 .ops = &tabla_dai_ops,
2874 },
2875};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002876static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07002877{
2878 u8 bias_msb, bias_lsb;
2879 short bias_value;
2880
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002881 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
2882 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
2883 bias_value = (bias_msb << 8) | bias_lsb;
2884 return bias_value;
2885}
2886
2887static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
2888{
2889 u8 bias_msb, bias_lsb;
2890 short bias_value;
2891
2892 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
2893 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
2894 bias_value = (bias_msb << 8) | bias_lsb;
2895 return bias_value;
2896}
2897
2898static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
2899 int dce)
2900{
2901 short bias_value;
2902
Bradley Rubincb1e2732011-06-23 16:49:20 -07002903 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002904 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2905 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
2906 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2907 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
2908 usleep_range(60000, 60000);
2909 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002910 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002911 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002912 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
2913 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002914 usleep_range(5000, 5000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002915 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002916 usleep_range(50, 50);
2917 bias_value = tabla_codec_read_sta_result(codec);
2918 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2919 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002920 }
2921
Bradley Rubincb1e2732011-06-23 16:49:20 -07002922 pr_debug("read microphone bias value %x\n", bias_value);
2923 return bias_value;
2924}
2925
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07002926static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002927{
2928 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2929 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07002930 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002931 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002932
2933 if (!calibration) {
2934 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07002935 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002936 }
2937
2938 tabla->mbhc_polling_active = true;
2939
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002940 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002941 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002942 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002943 tabla_codec_enable_clock_block(codec, 1);
2944 }
2945
2946 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
2947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002948 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
2949
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002950 /* Make sure CFILT is in fast mode, save current mode */
2951 cfilt_mode = snd_soc_read(codec,
2952 tabla->mbhc_bias_regs.cfilt_ctl);
2953 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
2954 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07002955
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002956 snd_soc_update_bits(codec,
2957 tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002958
2959 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002960 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002961
2962 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
2963 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
2964 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
2965
2966 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002967 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2968 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002969
Bradley Rubincb1e2732011-06-23 16:49:20 -07002970 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002971 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2972
Bradley Rubincb1e2732011-06-23 16:49:20 -07002973 tabla_codec_calibrate_hs_polling(codec);
2974
2975 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002976 snd_soc_update_bits(codec,
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002977 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002978 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002979
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07002980 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002981}
2982
2983static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
2984 int insertion)
2985{
2986 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2987 struct tabla_mbhc_calibration *calibration = tabla->calibration;
2988 int central_bias_enabled = 0;
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08002989 u8 wg_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002990
2991 if (!calibration) {
2992 pr_err("Error, no tabla calibration\n");
2993 return -EINVAL;
2994 }
2995
2996 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
2997
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07002998 if (insertion) {
2999 /* Make sure mic bias and Mic line schmitt trigger
3000 * are turned OFF
3001 */
3002 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
3003 0x81, 0x01);
3004 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3005 0x90, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003006 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
3007 wg_time += 1;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003008
3009 /* Enable HPH Schmitt Trigger */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003010 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003011 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
3012 calibration->hph_current << 2);
3013
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003014 /* Turn off HPH PAs and DAC's during insertion detection to
3015 * avoid false insertion interrupts
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003016 */
3017 if (tabla->mbhc_micbias_switched)
3018 tabla_codec_switch_micbias(codec, 0);
3019 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003020 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
3021 0xC0, 0x00);
3022 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
3023 0xC0, 0x00);
3024 usleep_range(wg_time * 1000, wg_time * 1000);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003025
3026 /* setup for insetion detection */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003027 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003028 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003029 } else {
3030 /* Make sure the HPH schmitt trigger is OFF */
3031 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3032
3033 /* enable the mic line schmitt trigger */
3034 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
3035 calibration->mic_current << 5);
3036 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3037 0x80, 0x80);
3038 usleep_range(calibration->mic_pid, calibration->mic_pid);
3039 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3040 0x10, 0x10);
3041
3042 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003043 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003044 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003045
3046 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
3047 if (!(tabla->clock_active)) {
3048 tabla_codec_enable_config_mode(codec, 1);
3049 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003050 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003051 usleep_range(calibration->shutdown_plug_removal,
3052 calibration->shutdown_plug_removal);
3053 tabla_codec_enable_config_mode(codec, 0);
3054 } else
3055 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003056 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003057 }
3058
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003059 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060
3061 /* If central bandgap disabled */
3062 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
3063 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
3064 usleep_range(calibration->bg_fast_settle,
3065 calibration->bg_fast_settle);
3066 central_bias_enabled = 1;
3067 }
3068
3069 /* If LDO_H disabled */
3070 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
3071 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
3072 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
3073 usleep_range(calibration->tldoh, calibration->tldoh);
3074 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
3075
3076 if (central_bias_enabled)
3077 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
3078 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079
3080 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
3081
3082 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3083 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3084 return 0;
3085}
3086
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003087static void tabla_lock_sleep(struct tabla_priv *tabla)
3088{
3089 int ret;
3090 while (!(ret = wait_event_timeout(tabla->pm_wq,
3091 atomic_inc_not_zero(&tabla->pm_cnt),
3092 2 * HZ))) {
3093 pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
3094 __func__, ret, atomic_read(&tabla->pm_cnt));
3095 WARN_ON_ONCE(1);
3096 }
3097}
3098
3099static void tabla_unlock_sleep(struct tabla_priv *tabla)
3100{
3101 atomic_dec(&tabla->pm_cnt);
3102 wake_up(&tabla->pm_wq);
3103}
3104
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003105static void btn0_lpress_fn(struct work_struct *work)
3106{
3107 struct delayed_work *delayed_work;
3108 struct tabla_priv *tabla;
3109
3110 pr_debug("%s:\n", __func__);
3111
3112 delayed_work = to_delayed_work(work);
3113 tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
3114
3115 if (tabla) {
3116 if (tabla->button_jack) {
3117 pr_debug("%s: Reporting long button press event\n",
3118 __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003119 tabla_snd_soc_jack_report(tabla, tabla->button_jack,
3120 SND_JACK_BTN_0,
3121 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003122 }
3123 } else {
3124 pr_err("%s: Bad tabla private data\n", __func__);
3125 }
3126
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003127 tabla_unlock_sleep(tabla);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003128}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003129
Bradley Rubincb1e2732011-06-23 16:49:20 -07003130int tabla_hs_detect(struct snd_soc_codec *codec,
3131 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003132 struct tabla_mbhc_calibration *calibration)
3133{
3134 struct tabla_priv *tabla;
Patrick Lai49efeac2011-11-03 11:01:12 -07003135 int rc;
3136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137 if (!codec || !calibration) {
3138 pr_err("Error: no codec or calibration\n");
3139 return -EINVAL;
3140 }
3141 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003142 tabla->headset_jack = headset_jack;
3143 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003144 tabla->calibration = calibration;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003145 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003146
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003147 /* Put CFILT in fast mode by default */
3148 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
3149 0x40, TABLA_CFILT_FAST_MODE);
3150
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003151 INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
Patrick Lai49efeac2011-11-03 11:01:12 -07003152 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
3153 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
3154 rc = tabla_codec_enable_hs_detect(codec, 1);
3155
3156 if (!IS_ERR_VALUE(rc)) {
3157 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3158 0x10);
3159 tabla_enable_irq(codec->control_data,
3160 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3161 tabla_enable_irq(codec->control_data,
3162 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3163 }
3164
3165 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003166}
3167EXPORT_SYMBOL_GPL(tabla_hs_detect);
3168
Bradley Rubincb1e2732011-06-23 16:49:20 -07003169static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003170{
3171 struct tabla_priv *priv = data;
3172 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003173 short bias_value;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003174
3175 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3176 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003177 tabla_lock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003178
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003179 bias_value = tabla_codec_read_dce_result(codec);
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003180 pr_debug("%s: button press interrupt, bias value(DCE Read)=%d\n",
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003181 __func__, bias_value);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003182
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003183 bias_value = tabla_codec_read_sta_result(codec);
3184 pr_debug("%s: button press interrupt, bias value(STA Read)=%d\n",
3185 __func__, bias_value);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003186 /*
3187 * TODO: If button pressed is not button 0,
3188 * report the button press event immediately.
3189 */
3190 priv->buttons_pressed |= SND_JACK_BTN_0;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003191
Bradley Rubin688c66a2011-08-16 12:25:13 -07003192 msleep(100);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003193
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003194 if (schedule_delayed_work(&priv->btn0_dwork,
3195 msecs_to_jiffies(400)) == 0) {
3196 WARN(1, "Button pressed twice without release event\n");
3197 tabla_unlock_sleep(priv);
3198 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200 return IRQ_HANDLED;
3201}
3202
Bradley Rubincb1e2732011-06-23 16:49:20 -07003203static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003204{
3205 struct tabla_priv *priv = data;
3206 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003207 int ret, mic_voltage;
3208
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003209 pr_debug("%s\n", __func__);
3210 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003211 tabla_lock_sleep(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003212
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003213 mic_voltage = tabla_codec_read_dce_result(codec);
3214 pr_debug("%s: Microphone Voltage on release(DCE Read) = %d\n",
3215 __func__, mic_voltage);
3216
Bradley Rubincb1e2732011-06-23 16:49:20 -07003217 if (priv->buttons_pressed & SND_JACK_BTN_0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003218 ret = cancel_delayed_work(&priv->btn0_dwork);
3219
3220 if (ret == 0) {
3221
3222 pr_debug("%s: Reporting long button release event\n",
3223 __func__);
3224 if (priv->button_jack) {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003225 tabla_snd_soc_jack_report(priv,
3226 priv->button_jack, 0,
3227 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003228 }
3229
3230 } else {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003231 /* if scheduled btn0_dwork is canceled from here,
3232 * we have to unlock from here instead btn0_work */
3233 tabla_unlock_sleep(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003234 mic_voltage =
3235 tabla_codec_measure_micbias_voltage(codec, 0);
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003236 pr_debug("%s: Mic Voltage on release(new STA) = %d\n",
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003237 __func__, mic_voltage);
3238
3239 if (mic_voltage < -2000 || mic_voltage > -670) {
3240 pr_debug("%s: Fake buttton press interrupt\n",
3241 __func__);
3242 } else {
3243
3244 if (priv->button_jack) {
3245 pr_debug("%s:reporting short button press and release\n",
3246 __func__);
3247
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003248 tabla_snd_soc_jack_report(priv,
3249 priv->button_jack,
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003250 SND_JACK_BTN_0, SND_JACK_BTN_0);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003251 tabla_snd_soc_jack_report(priv,
3252 priv->button_jack,
3253 0, SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003254 }
3255 }
3256 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003257
Bradley Rubincb1e2732011-06-23 16:49:20 -07003258 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003260
Bradley Rubin688c66a2011-08-16 12:25:13 -07003261 tabla_codec_start_hs_polling(codec);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003262 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263 return IRQ_HANDLED;
3264}
3265
Bradley Rubincb1e2732011-06-23 16:49:20 -07003266static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
3267{
3268 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3269 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003270
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003271 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003272 tabla_codec_enable_config_mode(codec, 1);
3273
3274 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3275 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003276
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003277 snd_soc_update_bits(codec,
3278 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003279 usleep_range(calibration->shutdown_plug_removal,
3280 calibration->shutdown_plug_removal);
3281
3282 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003283 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003284 tabla_codec_enable_config_mode(codec, 0);
3285
3286 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
3287}
3288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
3290{
3291 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003292
3293 tabla_codec_shutdown_hs_removal_detect(codec);
3294
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003295 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003296 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
3297 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
3298 tabla_codec_enable_clock_block(codec, 0);
3299 }
3300
3301 tabla->mbhc_polling_active = false;
3302}
3303
Patrick Lai49efeac2011-11-03 11:01:12 -07003304static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
3305{
3306 struct tabla_priv *tabla = data;
3307 struct snd_soc_codec *codec;
3308
3309 pr_info("%s: received HPHL OCP irq\n", __func__);
3310
3311 if (tabla) {
3312 codec = tabla->codec;
3313 tabla_disable_irq(codec->control_data,
3314 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3315 tabla->hph_status |= SND_JACK_OC_HPHL;
3316 if (tabla->headset_jack) {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003317 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
3318 tabla->hph_status,
3319 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07003320 }
3321 } else {
3322 pr_err("%s: Bad tabla private data\n", __func__);
3323 }
3324
3325 return IRQ_HANDLED;
3326}
3327
3328static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
3329{
3330 struct tabla_priv *tabla = data;
3331 struct snd_soc_codec *codec;
3332
3333 pr_info("%s: received HPHR OCP irq\n", __func__);
3334
3335 if (tabla) {
3336 codec = tabla->codec;
3337 tabla_disable_irq(codec->control_data,
3338 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3339 tabla->hph_status |= SND_JACK_OC_HPHR;
3340 if (tabla->headset_jack) {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003341 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
3342 tabla->hph_status,
3343 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07003344 }
3345 } else {
3346 pr_err("%s: Bad tabla private data\n", __func__);
3347 }
3348
3349 return IRQ_HANDLED;
3350}
3351
Bradley Rubincb1e2732011-06-23 16:49:20 -07003352static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
3353{
3354 struct tabla_priv *priv = data;
3355 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin355611a2011-08-24 14:01:18 -07003356 int ldo_h_on, micb_cfilt_on;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003357 short mic_voltage;
3358 short threshold_no_mic = 0xF7F6;
3359 short threshold_fake_insert = 0xFD30;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003360 u8 is_removal;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003361
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003362 pr_debug("%s\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003363 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003364 tabla_lock_sleep(priv);
3365
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003366 is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
3367 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
3368
3369 /* Turn off both HPH and MIC line schmitt triggers */
3370 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
3371 0x90, 0x00);
3372 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003373
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003374 if (priv->fake_insert_context) {
3375 pr_debug("%s: fake context interrupt, reset insertion\n",
3376 __func__);
3377 priv->fake_insert_context = false;
3378 tabla_codec_shutdown_hs_polling(codec);
3379 tabla_codec_enable_hs_detect(codec, 1);
3380 return IRQ_HANDLED;
3381 }
3382
3383
Bradley Rubin355611a2011-08-24 14:01:18 -07003384 ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003385 micb_cfilt_on = snd_soc_read(codec,
3386 priv->mbhc_bias_regs.cfilt_ctl) & 0x80;
Bradley Rubin355611a2011-08-24 14:01:18 -07003387
3388 if (!ldo_h_on)
3389 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
3390 if (!micb_cfilt_on)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003391 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
3392 0x80, 0x80);
Bradley Rubin355611a2011-08-24 14:01:18 -07003393
Bradley Rubincb1e2732011-06-23 16:49:20 -07003394 usleep_range(priv->calibration->setup_plug_removal_delay,
3395 priv->calibration->setup_plug_removal_delay);
3396
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003397 if (!ldo_h_on)
3398 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
3399 if (!micb_cfilt_on)
3400 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
3401 0x80, 0x0);
3402
3403 if (is_removal) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003404 /*
3405 * If headphone is removed while playback is in progress,
3406 * it is possible that micbias will be switched to VDDIO.
3407 */
3408 if (priv->mbhc_micbias_switched)
3409 tabla_codec_switch_micbias(codec, 0);
Patrick Lai72aa4da2011-12-08 12:38:18 -08003410 priv->hph_status &= ~SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003411 if (priv->headset_jack) {
3412 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003413 tabla_snd_soc_jack_report(priv, priv->headset_jack,
3414 priv->hph_status,
3415 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003416 }
3417 tabla_codec_shutdown_hs_removal_detect(codec);
3418 tabla_codec_enable_hs_detect(codec, 1);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003419 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003420 return IRQ_HANDLED;
3421 }
3422
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003423 mic_voltage = tabla_codec_setup_hs_polling(codec);
Bradley Rubin355611a2011-08-24 14:01:18 -07003424
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003425 if (mic_voltage > threshold_fake_insert) {
3426 pr_debug("%s: Fake insertion interrupt, mic_voltage = %x\n",
3427 __func__, mic_voltage);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003428
3429 /* Disable HPH trigger and enable MIC line trigger */
3430 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3431
3432 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
3433 priv->calibration->mic_current << 5);
3434 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
3435 0x80, 0x80);
3436 usleep_range(priv->calibration->mic_pid,
3437 priv->calibration->mic_pid);
3438 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
3439 0x10, 0x10);
3440
3441 /* Setup for insertion detection */
3442 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
3443 priv->fake_insert_context = true;
3444 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3445 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3446
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003447 } else if (mic_voltage < threshold_no_mic) {
3448 pr_debug("%s: Headphone Detected, mic_voltage = %x\n",
3449 __func__, mic_voltage);
Patrick Lai49efeac2011-11-03 11:01:12 -07003450 priv->hph_status |= SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003451 if (priv->headset_jack) {
3452 pr_debug("%s: Reporting insertion %d\n", __func__,
3453 SND_JACK_HEADPHONE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003454 tabla_snd_soc_jack_report(priv, priv->headset_jack,
3455 priv->hph_status,
3456 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003457 }
3458 tabla_codec_shutdown_hs_polling(codec);
3459 tabla_codec_enable_hs_detect(codec, 0);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003460
3461 } else {
3462 pr_debug("%s: Headset detected, mic_voltage = %x\n",
3463 __func__, mic_voltage);
Patrick Lai49efeac2011-11-03 11:01:12 -07003464 priv->hph_status |= SND_JACK_HEADSET;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003465 if (priv->headset_jack) {
3466 pr_debug("%s: Reporting insertion %d\n", __func__,
3467 SND_JACK_HEADSET);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003468 tabla_snd_soc_jack_report(priv, priv->headset_jack,
3469 priv->hph_status,
3470 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003471 }
3472 tabla_codec_start_hs_polling(codec);
3473 }
3474
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003475 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003476 return IRQ_HANDLED;
3477}
3478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003479static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
3480{
3481 struct tabla_priv *priv = data;
3482 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003483 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003484
3485 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3486 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003487 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003488 tabla_lock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489
3490 usleep_range(priv->calibration->shutdown_plug_removal,
3491 priv->calibration->shutdown_plug_removal);
3492
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003493 bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
3494 pr_debug("removal interrupt, bias value is %d\n", bias_value);
3495
3496 if (bias_value < -90) {
3497 pr_debug("False alarm, headset not actually removed\n");
3498 tabla_codec_start_hs_polling(codec);
3499 } else {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003500 /*
3501 * If this removal is not false, first check the micbias
3502 * switch status and switch it to LDOH if it is already
3503 * switched to VDDIO.
3504 */
3505 if (priv->mbhc_micbias_switched)
3506 tabla_codec_switch_micbias(codec, 0);
Patrick Lai49efeac2011-11-03 11:01:12 -07003507 priv->hph_status &= ~SND_JACK_HEADSET;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003508 if (priv->headset_jack) {
3509 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003510 tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
3511 TABLA_JACK_MASK);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003512 }
3513 tabla_codec_shutdown_hs_polling(codec);
3514
3515 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003516 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003517
3518 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003519 return IRQ_HANDLED;
3520}
3521
3522static unsigned long slimbus_value;
3523
3524static irqreturn_t tabla_slimbus_irq(int irq, void *data)
3525{
3526 struct tabla_priv *priv = data;
3527 struct snd_soc_codec *codec = priv->codec;
3528 int i, j;
3529 u8 val;
3530
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003531 tabla_lock_sleep(priv);
3532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003533 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
3534 slimbus_value = tabla_interface_reg_read(codec->control_data,
3535 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
3536 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
3537 val = tabla_interface_reg_read(codec->control_data,
3538 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
3539 if (val & 0x1)
3540 pr_err_ratelimited("overflow error on port %x,"
3541 " value %x\n", i*8 + j, val);
3542 if (val & 0x2)
3543 pr_err_ratelimited("underflow error on port %x,"
3544 " value %x\n", i*8 + j, val);
3545 }
3546 tabla_interface_reg_write(codec->control_data,
3547 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
3548 }
3549
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003550 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003551 return IRQ_HANDLED;
3552}
3553
Patrick Lai3043fba2011-08-01 14:15:57 -07003554
3555static int tabla_handle_pdata(struct tabla_priv *tabla)
3556{
3557 struct snd_soc_codec *codec = tabla->codec;
3558 struct tabla_pdata *pdata = tabla->pdata;
3559 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05303560 u8 leg_mode = pdata->amic_settings.legacy_mode;
3561 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
3562 u8 txfe_buff = pdata->amic_settings.txfe_buff;
3563 u8 flag = pdata->amic_settings.use_pdata;
3564 u8 i = 0, j = 0;
3565 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07003566
3567 if (!pdata) {
3568 rc = -ENODEV;
3569 goto done;
3570 }
3571
3572 /* Make sure settings are correct */
3573 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
3574 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
3575 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
3576 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
3577 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
3578 rc = -EINVAL;
3579 goto done;
3580 }
3581
3582 /* figure out k value */
3583 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
3584 pdata->micbias.cfilt1_mv);
3585 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
3586 pdata->micbias.cfilt2_mv);
3587 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
3588 pdata->micbias.cfilt3_mv);
3589
3590 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
3591 rc = -EINVAL;
3592 goto done;
3593 }
3594
3595 /* Set voltage level and always use LDO */
3596 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
3597 (pdata->micbias.ldoh_v << 2));
3598
3599 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
3600 (k1 << 2));
3601 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
3602 (k2 << 2));
3603 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
3604 (k3 << 2));
3605
3606 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
3607 (pdata->micbias.bias1_cfilt_sel << 5));
3608 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
3609 (pdata->micbias.bias2_cfilt_sel << 5));
3610 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
3611 (pdata->micbias.bias3_cfilt_sel << 5));
3612 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
3613 (pdata->micbias.bias4_cfilt_sel << 5));
3614
Santosh Mardi22920282011-10-26 02:38:40 +05303615 for (i = 0; i < 6; j++, i += 2) {
3616 if (flag & (0x01 << i)) {
3617 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
3618 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
3619 val_txfe = val_txfe |
3620 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
3621 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
3622 0x10, value);
3623 snd_soc_update_bits(codec,
3624 TABLA_A_TX_1_2_TEST_EN + j * 10,
3625 0x30, val_txfe);
3626 }
3627 if (flag & (0x01 << (i + 1))) {
3628 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
3629 val_txfe = (txfe_bypass &
3630 (0x01 << (i + 1))) ? 0x02 : 0x00;
3631 val_txfe |= (txfe_buff &
3632 (0x01 << (i + 1))) ? 0x01 : 0x00;
3633 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
3634 0x01, value);
3635 snd_soc_update_bits(codec,
3636 TABLA_A_TX_1_2_TEST_EN + j * 10,
3637 0x03, val_txfe);
3638 }
3639 }
3640 if (flag & 0x40) {
3641 value = (leg_mode & 0x40) ? 0x10 : 0x00;
3642 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
3643 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
3644 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
3645 0x13, value);
3646 }
Patrick Lai49efeac2011-11-03 11:01:12 -07003647
3648 if (pdata->ocp.use_pdata) {
3649 /* not defined in CODEC specification */
3650 if (pdata->ocp.hph_ocp_limit == 1 ||
3651 pdata->ocp.hph_ocp_limit == 5) {
3652 rc = -EINVAL;
3653 goto done;
3654 }
3655 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
3656 0x0F, pdata->ocp.num_attempts);
3657 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
3658 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
3659 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
3660 0xE0, (pdata->ocp.hph_ocp_limit << 5));
3661 }
Patrick Lai3043fba2011-08-01 14:15:57 -07003662done:
3663 return rc;
3664}
3665
Kiran Kandi1f6fd722011-08-11 10:36:11 -07003666static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
3667
3668 /* Tabla 1.1 MICBIAS changes */
3669 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
3670 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
3671 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
3672 TABLA_REG_VAL(TABLA_A_MICB_4_INT_RBIAS, 0x24),
3673
3674 /* Tabla 1.1 HPH changes */
3675 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
3676 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
3677
3678 /* Tabla 1.1 EAR PA changes */
3679 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
3680 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
3681 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
3682
3683 /* Tabla 1.1 Lineout_5 Changes */
3684 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
3685
3686 /* Tabla 1.1 RX Changes */
3687 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
3688 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
3689 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
3690 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
3691 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
3692 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
3693 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
3694
3695 /* Tabla 1.1 RX1 and RX2 Changes */
3696 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
3697 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
3698
3699 /* Tabla 1.1 RX3 to RX7 Changes */
3700 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
3701 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
3702 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
3703 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
3704 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
3705
3706 /* Tabla 1.1 CLASSG Changes */
3707 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
3708};
3709
3710static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
3711
3712 /* Tabla 2.0 MICBIAS changes */
3713 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
3714};
3715
3716static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
3717{
3718 u32 i;
3719
3720 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
3721 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
3722 tabla_1_1_reg_defaults[i].val);
3723
3724 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
3725 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
3726 tabla_2_0_reg_defaults[i].val);
3727}
3728
3729static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Lai49efeac2011-11-03 11:01:12 -07003730 /* Initialize current threshold to 350MA */
3731 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07003732
Santosh Mardi32171012011-10-28 23:32:06 +05303733 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
3734
Kiran Kandi1f6fd722011-08-11 10:36:11 -07003735 /* Initialize gain registers to use register gain */
3736 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
3737 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
3738 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
3739 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
3740 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
3741 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
3742
3743 /* Initialize mic biases to differential mode */
3744 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
3745 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
3746 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
3747 {TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24},
3748
3749 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
3750
3751 /* Use 16 bit sample size for TX1 to TX6 */
3752 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
3753 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
3754 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
3755 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
3756 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
3757 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
3758
3759 /* Use 16 bit sample size for TX7 to TX10 */
3760 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
3761 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
3762 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
3763 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
3764
3765 /* Use 16 bit sample size for RX */
3766 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
3767 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
3768
3769 /*enable HPF filter for TX paths */
3770 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
3771 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
3772 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
3773 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
3774 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
3775 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
3776 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
3777 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
3778 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
3779 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
3780};
3781
3782static void tabla_codec_init_reg(struct snd_soc_codec *codec)
3783{
3784 u32 i;
3785
3786 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
3787 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
3788 tabla_codec_reg_init_val[i].mask,
3789 tabla_codec_reg_init_val[i].val);
3790}
3791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003792static int tabla_codec_probe(struct snd_soc_codec *codec)
3793{
3794 struct tabla *control;
3795 struct tabla_priv *tabla;
3796 struct snd_soc_dapm_context *dapm = &codec->dapm;
3797 int ret = 0;
3798 int i;
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003799 u8 tabla_version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003800
3801 codec->control_data = dev_get_drvdata(codec->dev->parent);
3802 control = codec->control_data;
3803
3804 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
3805 if (!tabla) {
3806 dev_err(codec->dev, "Failed to allocate private data\n");
3807 return -ENOMEM;
3808 }
3809
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003810 /* Make sure mbhc micbias register addresses are zeroed out */
3811 memset(&tabla->mbhc_bias_regs, 0,
3812 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003813 tabla->cfilt_k_value = 0;
3814 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816 snd_soc_codec_set_drvdata(codec, tabla);
3817
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003818 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003819 tabla->bandgap_type = TABLA_BANDGAP_OFF;
3820 tabla->clock_active = false;
3821 tabla->config_mode_active = false;
3822 tabla->mbhc_polling_active = false;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003823 tabla->fake_insert_context = false;
Bradley Rubincb3950a2011-08-18 13:07:26 -07003824 tabla->no_mic_headset_override = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003825 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07003826 tabla->pdata = dev_get_platdata(codec->dev->parent);
Santosh Mardie15e2302011-11-15 10:39:23 +05303827 tabla->intf_type = tabla_get_intf_type();
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003828 atomic_set(&tabla->pm_cnt, 1);
3829 init_waitqueue_head(&tabla->pm_wq);
Patrick Lai3043fba2011-08-01 14:15:57 -07003830
Santosh Mardi22920282011-10-26 02:38:40 +05303831 tabla_update_reg_defaults(codec);
3832 tabla_codec_init_reg(codec);
Patrick Lai3043fba2011-08-01 14:15:57 -07003833
Santosh Mardi22920282011-10-26 02:38:40 +05303834 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07003835 if (IS_ERR_VALUE(ret)) {
3836 pr_err("%s: bad pdata\n", __func__);
3837 goto err_pdata;
3838 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003839
3840 /* TODO only enable bandgap when necessary in order to save power */
3841 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
3842 tabla_codec_enable_clock_block(codec, 0);
3843
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003844 snd_soc_add_controls(codec, tabla_snd_controls,
3845 ARRAY_SIZE(tabla_snd_controls));
3846 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
3847 ARRAY_SIZE(tabla_dapm_widgets));
Santosh Mardie15e2302011-11-15 10:39:23 +05303848 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
3849 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
3850 ARRAY_SIZE(tabla_dapm_i2s_widgets));
3851 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
3852 ARRAY_SIZE(audio_i2s_map));
3853 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003854 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003855
3856 tabla_version = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
3857 pr_info("%s : Tabla version reg 0x%2x\n", __func__, (u32)tabla_version);
3858
3859 tabla_version &= 0x1F;
3860 pr_info("%s : Tabla version %u\n", __func__, (u32)tabla_version);
3861
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003862 if ((tabla_version == TABLA_VERSION_1_0) ||
3863 (tabla_version == TABLA_VERSION_1_1)) {
3864 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003865 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
3866
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003867 } else if (tabla_version == TABLA_VERSION_2_0) {
3868 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
3869 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
3870 } else {
3871 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
3872 __func__, (u32)tabla_version);
3873 goto err_pdata;
3874 }
3875
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003876 snd_soc_dapm_sync(dapm);
3877
3878 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
3879 tabla_hs_insert_irq, "Headset insert detect", tabla);
3880 if (ret) {
3881 pr_err("%s: Failed to request irq %d\n", __func__,
3882 TABLA_IRQ_MBHC_INSERTION);
3883 goto err_insert_irq;
3884 }
3885 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3886
3887 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
3888 tabla_hs_remove_irq, "Headset remove detect", tabla);
3889 if (ret) {
3890 pr_err("%s: Failed to request irq %d\n", __func__,
3891 TABLA_IRQ_MBHC_REMOVAL);
3892 goto err_remove_irq;
3893 }
3894 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3895
3896 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003897 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003898 if (ret) {
3899 pr_err("%s: Failed to request irq %d\n", __func__,
3900 TABLA_IRQ_MBHC_POTENTIAL);
3901 goto err_potential_irq;
3902 }
3903 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
3904
Bradley Rubincb1e2732011-06-23 16:49:20 -07003905 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
3906 tabla_release_handler, "Button Release detect", tabla);
3907 if (ret) {
3908 pr_err("%s: Failed to request irq %d\n", __func__,
3909 TABLA_IRQ_MBHC_RELEASE);
3910 goto err_release_irq;
3911 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003912 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003913
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003914 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
3915 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
3916 if (ret) {
3917 pr_err("%s: Failed to request irq %d\n", __func__,
3918 TABLA_IRQ_SLIMBUS);
3919 goto err_slimbus_irq;
3920 }
3921
3922 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
3923 tabla_interface_reg_write(codec->control_data,
3924 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
3925
Patrick Lai49efeac2011-11-03 11:01:12 -07003926 ret = tabla_request_irq(codec->control_data,
3927 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
3928 "HPH_L OCP detect", tabla);
3929 if (ret) {
3930 pr_err("%s: Failed to request irq %d\n", __func__,
3931 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3932 goto err_hphl_ocp_irq;
3933 }
Patrick Lai92032be2011-12-19 14:14:25 -08003934 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07003935
3936 ret = tabla_request_irq(codec->control_data,
3937 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
3938 "HPH_R OCP detect", tabla);
3939 if (ret) {
3940 pr_err("%s: Failed to request irq %d\n", __func__,
3941 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3942 goto err_hphr_ocp_irq;
3943 }
Patrick Lai92032be2011-12-19 14:14:25 -08003944 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07003945
Bradley Rubincb3950a2011-08-18 13:07:26 -07003946#ifdef CONFIG_DEBUG_FS
3947 debug_tabla_priv = tabla;
3948#endif
3949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003950 return ret;
3951
Patrick Lai49efeac2011-11-03 11:01:12 -07003952err_hphr_ocp_irq:
3953 tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
3954err_hphl_ocp_irq:
3955 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003956err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07003957 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
3958err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003959 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
3960err_potential_irq:
3961 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
3962err_remove_irq:
3963 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
3964err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07003965err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003966 kfree(tabla);
3967 return ret;
3968}
3969static int tabla_codec_remove(struct snd_soc_codec *codec)
3970{
3971 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3972 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003973 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003974 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
3975 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
3976 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
3977 tabla_codec_disable_clock_block(codec);
3978 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
3979 kfree(tabla);
3980 return 0;
3981}
3982static struct snd_soc_codec_driver soc_codec_dev_tabla = {
3983 .probe = tabla_codec_probe,
3984 .remove = tabla_codec_remove,
3985 .read = tabla_read,
3986 .write = tabla_write,
3987
3988 .readable_register = tabla_readable,
3989 .volatile_register = tabla_volatile,
3990
3991 .reg_cache_size = TABLA_CACHE_SIZE,
3992 .reg_cache_default = tabla_reg_defaults,
3993 .reg_word_size = 1,
3994};
Bradley Rubincb3950a2011-08-18 13:07:26 -07003995
3996#ifdef CONFIG_DEBUG_FS
3997static struct dentry *debugfs_poke;
3998
3999static int codec_debug_open(struct inode *inode, struct file *file)
4000{
4001 file->private_data = inode->i_private;
4002 return 0;
4003}
4004
4005static ssize_t codec_debug_write(struct file *filp,
4006 const char __user *ubuf, size_t cnt, loff_t *ppos)
4007{
4008 char lbuf[32];
4009 char *buf;
4010 int rc;
4011
4012 if (cnt > sizeof(lbuf) - 1)
4013 return -EINVAL;
4014
4015 rc = copy_from_user(lbuf, ubuf, cnt);
4016 if (rc)
4017 return -EFAULT;
4018
4019 lbuf[cnt] = '\0';
4020 buf = (char *)lbuf;
4021 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
4022 ? false : true;
4023
4024 return rc;
4025}
4026
4027static const struct file_operations codec_debug_ops = {
4028 .open = codec_debug_open,
4029 .write = codec_debug_write,
4030};
4031#endif
4032
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004033#ifdef CONFIG_PM
4034static int tabla_suspend(struct device *dev)
4035{
4036 int ret = 0, cnt;
4037 struct platform_device *pdev = to_platform_device(dev);
4038 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4039
4040 cnt = atomic_read(&tabla->pm_cnt);
4041 if (cnt > 0) {
4042 if (wait_event_timeout(tabla->pm_wq,
4043 (atomic_cmpxchg(&tabla->pm_cnt, 1, 0)
4044 == 1), 5 * HZ)) {
4045 dev_dbg(dev, "system suspend pm_cnt %d\n",
4046 atomic_read(&tabla->pm_cnt));
4047 } else {
4048 dev_err(dev, "%s timed out pm_cnt = %d\n",
4049 __func__, atomic_read(&tabla->pm_cnt));
4050 WARN_ON_ONCE(1);
4051 ret = -EBUSY;
4052 }
4053 } else if (cnt == 0)
4054 dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
4055 atomic_read(&tabla->pm_cnt));
4056 else {
4057 WARN(1, "unexpected pm_cnt %d\n", cnt);
4058 ret = -EFAULT;
4059 }
4060
4061 return ret;
4062}
4063
4064static int tabla_resume(struct device *dev)
4065{
4066 int ret = 0, cnt;
4067 struct platform_device *pdev = to_platform_device(dev);
4068 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4069
4070 cnt = atomic_cmpxchg(&tabla->pm_cnt, 0, 1);
4071 if (cnt == 0) {
4072 dev_dbg(dev, "system resume, pm_cnt %d\n",
4073 atomic_read(&tabla->pm_cnt));
4074 wake_up_all(&tabla->pm_wq);
4075 } else if (cnt > 0)
4076 dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
4077 else {
4078 WARN(1, "unexpected pm_cnt %d\n", cnt);
4079 ret = -EFAULT;
4080 }
4081
4082 return ret;
4083}
4084
4085static const struct dev_pm_ops tabla_pm_ops = {
4086 .suspend = tabla_suspend,
4087 .resume = tabla_resume,
4088};
4089#endif
4090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004091static int __devinit tabla_probe(struct platform_device *pdev)
4092{
Santosh Mardie15e2302011-11-15 10:39:23 +05304093 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004094#ifdef CONFIG_DEBUG_FS
4095 debugfs_poke = debugfs_create_file("TRRS",
4096 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
4097
4098#endif
Santosh Mardie15e2302011-11-15 10:39:23 +05304099 if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
4100 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4101 tabla_dai, ARRAY_SIZE(tabla_dai));
4102 else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
4103 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4104 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
4105 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004106}
4107static int __devexit tabla_remove(struct platform_device *pdev)
4108{
4109 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07004110
4111#ifdef CONFIG_DEBUG_FS
4112 debugfs_remove(debugfs_poke);
4113#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004114 return 0;
4115}
4116static struct platform_driver tabla_codec_driver = {
4117 .probe = tabla_probe,
4118 .remove = tabla_remove,
4119 .driver = {
4120 .name = "tabla_codec",
4121 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004122#ifdef CONFIG_PM
4123 .pm = &tabla_pm_ops,
4124#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125 },
4126};
4127
4128static int __init tabla_codec_init(void)
4129{
4130 return platform_driver_register(&tabla_codec_driver);
4131}
4132
4133static void __exit tabla_codec_exit(void)
4134{
4135 platform_driver_unregister(&tabla_codec_driver);
4136}
4137
4138module_init(tabla_codec_init);
4139module_exit(tabla_codec_exit);
4140
4141MODULE_DESCRIPTION("Tabla codec driver");
4142MODULE_VERSION("1.0");
4143MODULE_LICENSE("GPL v2");