blob: 0ecb265a7aba77342cbfa4877e27156477cf3b4b [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
Patrick Laic7cae882011-11-18 11:52:49 -080049#define TABLA_OCP_ATTEMPT 1
50
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
52static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
53static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
54
55enum tabla_bandgap_type {
56 TABLA_BANDGAP_OFF = 0,
57 TABLA_BANDGAP_AUDIO_MODE,
58 TABLA_BANDGAP_MBHC_MODE,
59};
60
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070061struct mbhc_micbias_regs {
62 u16 cfilt_val;
63 u16 cfilt_ctl;
64 u16 mbhc_reg;
65 u16 int_rbias;
66 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080067 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070068};
69
Ben Romberger1f045a72011-11-04 10:14:57 -070070/* Codec supports 2 IIR filters */
71enum {
72 IIR1 = 0,
73 IIR2,
74 IIR_MAX,
75};
76/* Codec supports 5 bands */
77enum {
78 BAND1 = 0,
79 BAND2,
80 BAND3,
81 BAND4,
82 BAND5,
83 BAND_MAX,
84};
85
Joonwoo Parka9444452011-12-08 18:48:27 -080086/* Flags to track of PA and DAC state.
87 * PA and DAC should be tracked separately as AUXPGA loopback requires
88 * only PA to be turned on without DAC being on. */
89enum tabla_priv_ack_flags {
90 TABLA_HPHL_PA_OFF_ACK = 0,
91 TABLA_HPHR_PA_OFF_ACK,
92 TABLA_HPHL_DAC_OFF_ACK,
93 TABLA_HPHR_DAC_OFF_ACK
94};
95
Bradley Rubin229c6a52011-07-12 16:18:48 -070096struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070097 struct snd_soc_codec *codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -070099 u32 cfilt1_cnt;
100 u32 cfilt2_cnt;
101 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700102 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700104 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700105 bool clock_active;
106 bool config_mode_active;
107 bool mbhc_polling_active;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -0800108 bool fake_insert_context;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700109 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700110
111 struct tabla_mbhc_calibration *calibration;
112
Bradley Rubincb1e2732011-06-23 16:49:20 -0700113 struct snd_soc_jack *headset_jack;
114 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700115
Patrick Lai3043fba2011-08-01 14:15:57 -0700116 struct tabla_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700117 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700118
119 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700120 /* Delayed work to report long button press */
121 struct delayed_work btn0_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700122
123 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700124 u8 cfilt_k_value;
125 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700126
Joonwoo Parka9444452011-12-08 18:48:27 -0800127 /* track PA/DAC state */
128 unsigned long hph_pa_dac_state;
129
Santosh Mardie15e2302011-11-15 10:39:23 +0530130 /*track tabla interface type*/
131 u8 intf_type;
132
Patrick Lai49efeac2011-11-03 11:01:12 -0700133 u32 hph_status; /* track headhpone status */
134 /* define separate work for left and right headphone OCP to avoid
135 * additional checking on which OCP event to report so no locking
136 * to ensure synchronization is required
137 */
138 struct work_struct hphlocp_work; /* reporting left hph ocp off */
139 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800140
141 /* pm_cnt holds number of sleep lock holders + 1
142 * so if pm_cnt is 1 system is sleep-able. */
143 atomic_t pm_cnt;
144 wait_queue_head_t pm_wq;
Patrick Laic7cae882011-11-18 11:52:49 -0800145
146 u8 hphlocp_cnt; /* headphone left ocp retry */
147 u8 hphrocp_cnt; /* headphone right ocp retry */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148};
149
Bradley Rubincb3950a2011-08-18 13:07:26 -0700150#ifdef CONFIG_DEBUG_FS
151struct tabla_priv *debug_tabla_priv;
152#endif
153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700154static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
155 struct snd_kcontrol *kcontrol, int event)
156{
157 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158
159 pr_debug("%s %d\n", __func__, event);
160 switch (event) {
161 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
163 0x01);
164 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
165 usleep_range(200, 200);
166 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
167 break;
168 case SND_SOC_DAPM_PRE_PMD:
169 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
170 0x10);
171 usleep_range(20, 20);
172 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
173 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
174 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
175 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
176 0x00);
177 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178 break;
179 }
180 return 0;
181}
182
Bradley Rubina7096d02011-08-03 18:29:02 -0700183static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
184 struct snd_ctl_elem_value *ucontrol)
185{
186 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
187 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
188 ucontrol->value.integer.value[0] = tabla->anc_slot;
189 return 0;
190}
191
192static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
193 struct snd_ctl_elem_value *ucontrol)
194{
195 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
196 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
197 tabla->anc_slot = ucontrol->value.integer.value[0];
198 return 0;
199}
200
Kiran Kandid2d86b52011-09-09 17:44:28 -0700201static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
202 struct snd_ctl_elem_value *ucontrol)
203{
204 u8 ear_pa_gain;
205 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
206
207 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
208
209 ear_pa_gain = ear_pa_gain >> 5;
210
211 if (ear_pa_gain == 0x00) {
212 ucontrol->value.integer.value[0] = 0;
213 } else if (ear_pa_gain == 0x04) {
214 ucontrol->value.integer.value[0] = 1;
215 } else {
216 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
217 __func__, ear_pa_gain);
218 return -EINVAL;
219 }
220
221 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
222
223 return 0;
224}
225
226static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
227 struct snd_ctl_elem_value *ucontrol)
228{
229 u8 ear_pa_gain;
230 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
231
232 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
233 ucontrol->value.integer.value[0]);
234
235 switch (ucontrol->value.integer.value[0]) {
236 case 0:
237 ear_pa_gain = 0x00;
238 break;
239 case 1:
240 ear_pa_gain = 0x80;
241 break;
242 default:
243 return -EINVAL;
244 }
245
246 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
247 return 0;
248}
249
Ben Romberger1f045a72011-11-04 10:14:57 -0700250static int tabla_get_iir_enable_audio_mixer(
251 struct snd_kcontrol *kcontrol,
252 struct snd_ctl_elem_value *ucontrol)
253{
254 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
255 int iir_idx = ((struct soc_multi_mixer_control *)
256 kcontrol->private_value)->reg;
257 int band_idx = ((struct soc_multi_mixer_control *)
258 kcontrol->private_value)->shift;
259
260 ucontrol->value.integer.value[0] =
261 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
262 (1 << band_idx);
263
264 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
265 iir_idx, band_idx,
266 (uint32_t)ucontrol->value.integer.value[0]);
267 return 0;
268}
269
270static int tabla_put_iir_enable_audio_mixer(
271 struct snd_kcontrol *kcontrol,
272 struct snd_ctl_elem_value *ucontrol)
273{
274 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
275 int iir_idx = ((struct soc_multi_mixer_control *)
276 kcontrol->private_value)->reg;
277 int band_idx = ((struct soc_multi_mixer_control *)
278 kcontrol->private_value)->shift;
279 int value = ucontrol->value.integer.value[0];
280
281 /* Mask first 5 bits, 6-8 are reserved */
282 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
283 (1 << band_idx), (value << band_idx));
284
285 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
286 iir_idx, band_idx, value);
287 return 0;
288}
289static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
290 int iir_idx, int band_idx,
291 int coeff_idx)
292{
293 /* Address does not automatically update if reading */
294 snd_soc_update_bits(codec,
295 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
296 0x1F, band_idx * BAND_MAX + coeff_idx);
297
298 /* Mask bits top 2 bits since they are reserved */
299 return ((snd_soc_read(codec,
300 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
301 (snd_soc_read(codec,
302 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
303 (snd_soc_read(codec,
304 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
305 (snd_soc_read(codec,
306 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
307 0x3FFFFFFF;
308}
309
310static int tabla_get_iir_band_audio_mixer(
311 struct snd_kcontrol *kcontrol,
312 struct snd_ctl_elem_value *ucontrol)
313{
314 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
315 int iir_idx = ((struct soc_multi_mixer_control *)
316 kcontrol->private_value)->reg;
317 int band_idx = ((struct soc_multi_mixer_control *)
318 kcontrol->private_value)->shift;
319
320 ucontrol->value.integer.value[0] =
321 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
322 ucontrol->value.integer.value[1] =
323 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
324 ucontrol->value.integer.value[2] =
325 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
326 ucontrol->value.integer.value[3] =
327 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
328 ucontrol->value.integer.value[4] =
329 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
330
331 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
332 "%s: IIR #%d band #%d b1 = 0x%x\n"
333 "%s: IIR #%d band #%d b2 = 0x%x\n"
334 "%s: IIR #%d band #%d a1 = 0x%x\n"
335 "%s: IIR #%d band #%d a2 = 0x%x\n",
336 __func__, iir_idx, band_idx,
337 (uint32_t)ucontrol->value.integer.value[0],
338 __func__, iir_idx, band_idx,
339 (uint32_t)ucontrol->value.integer.value[1],
340 __func__, iir_idx, band_idx,
341 (uint32_t)ucontrol->value.integer.value[2],
342 __func__, iir_idx, band_idx,
343 (uint32_t)ucontrol->value.integer.value[3],
344 __func__, iir_idx, band_idx,
345 (uint32_t)ucontrol->value.integer.value[4]);
346 return 0;
347}
348
349static void set_iir_band_coeff(struct snd_soc_codec *codec,
350 int iir_idx, int band_idx,
351 int coeff_idx, uint32_t value)
352{
353 /* Mask top 3 bits, 6-8 are reserved */
354 /* Update address manually each time */
355 snd_soc_update_bits(codec,
356 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
357 0x1F, band_idx * BAND_MAX + coeff_idx);
358
359 /* Mask top 2 bits, 7-8 are reserved */
360 snd_soc_update_bits(codec,
361 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
362 0x3F, (value >> 24) & 0x3F);
363
364 /* Isolate 8bits at a time */
365 snd_soc_update_bits(codec,
366 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
367 0xFF, (value >> 16) & 0xFF);
368
369 snd_soc_update_bits(codec,
370 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
371 0xFF, (value >> 8) & 0xFF);
372
373 snd_soc_update_bits(codec,
374 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
375 0xFF, value & 0xFF);
376}
377
378static int tabla_put_iir_band_audio_mixer(
379 struct snd_kcontrol *kcontrol,
380 struct snd_ctl_elem_value *ucontrol)
381{
382 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
383 int iir_idx = ((struct soc_multi_mixer_control *)
384 kcontrol->private_value)->reg;
385 int band_idx = ((struct soc_multi_mixer_control *)
386 kcontrol->private_value)->shift;
387
388 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
389 ucontrol->value.integer.value[0]);
390 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
391 ucontrol->value.integer.value[1]);
392 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
393 ucontrol->value.integer.value[2]);
394 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
395 ucontrol->value.integer.value[3]);
396 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
397 ucontrol->value.integer.value[4]);
398
399 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
400 "%s: IIR #%d band #%d b1 = 0x%x\n"
401 "%s: IIR #%d band #%d b2 = 0x%x\n"
402 "%s: IIR #%d band #%d a1 = 0x%x\n"
403 "%s: IIR #%d band #%d a2 = 0x%x\n",
404 __func__, iir_idx, band_idx,
405 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
406 __func__, iir_idx, band_idx,
407 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
408 __func__, iir_idx, band_idx,
409 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
410 __func__, iir_idx, band_idx,
411 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
412 __func__, iir_idx, band_idx,
413 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
414 return 0;
415}
416
Kiran Kandid2d86b52011-09-09 17:44:28 -0700417static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
418static const struct soc_enum tabla_ear_pa_gain_enum[] = {
419 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
420};
421
Santosh Mardi024010f2011-10-18 06:27:21 +0530422/*cut of frequency for high pass filter*/
423static const char *cf_text[] = {
424 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
425};
426
427static const struct soc_enum cf_dec1_enum =
428 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
429
430static const struct soc_enum cf_dec2_enum =
431 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
432
433static const struct soc_enum cf_dec3_enum =
434 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
435
436static const struct soc_enum cf_dec4_enum =
437 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
438
439static const struct soc_enum cf_dec5_enum =
440 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
441
442static const struct soc_enum cf_dec6_enum =
443 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
444
445static const struct soc_enum cf_dec7_enum =
446 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
447
448static const struct soc_enum cf_dec8_enum =
449 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
450
451static const struct soc_enum cf_dec9_enum =
452 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
453
454static const struct soc_enum cf_dec10_enum =
455 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
456
457static const struct soc_enum cf_rxmix1_enum =
458 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
459
460static const struct soc_enum cf_rxmix2_enum =
461 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
462
463static const struct soc_enum cf_rxmix3_enum =
464 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
465
466static const struct soc_enum cf_rxmix4_enum =
467 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
468
469static const struct soc_enum cf_rxmix5_enum =
470 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
471;
472static const struct soc_enum cf_rxmix6_enum =
473 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
474
475static const struct soc_enum cf_rxmix7_enum =
476 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700479
480 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
481 tabla_pa_gain_get, tabla_pa_gain_put),
482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700483 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
484 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700485 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
486 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700487 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
488 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700489 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
490 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700491 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
492 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
495 line_gain),
496 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
497 line_gain),
498
Bradley Rubin410383f2011-07-22 13:44:23 -0700499 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
500 -84, 40, digital_gain),
501 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
502 -84, 40, digital_gain),
503 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
504 -84, 40, digital_gain),
505 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
506 -84, 40, digital_gain),
507 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
508 -84, 40, digital_gain),
509 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
510 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700511
Bradley Rubin410383f2011-07-22 13:44:23 -0700512 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700513 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700514 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700515 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700516 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
517 digital_gain),
518 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
519 digital_gain),
520 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
521 digital_gain),
522 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
523 digital_gain),
524 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
525 digital_gain),
526 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
527 digital_gain),
528 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
529 digital_gain),
530 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
531 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700532 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
533 40, digital_gain),
534 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
535 40, digital_gain),
536 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
537 40, digital_gain),
538 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
539 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700540 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
541 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700542 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
543 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700544 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
545 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546
547 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800548 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700549 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
550 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700551
552 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
553 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530554 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
555 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
556 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
557 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
558 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
559 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
560 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
561 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
562 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
563 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
564
565 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
566 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
567 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
568 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
569 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
570 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
571 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
572 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
573 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
574 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
575
576 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
577 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
578 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
579 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
580 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
581 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
582 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
583
584 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
585 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
586 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
587 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
588 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
589 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
590 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700591
592 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
593 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
594 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
595 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
596 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
597 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
598 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
599 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
600 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
601 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
602 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
603 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
604 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
605 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
606 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
607 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
608 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
609 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
610 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
611 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
612
613 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
614 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
615 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
616 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
617 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
618 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
619 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
620 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
621 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
622 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
623 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
624 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
625 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
626 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
627 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
628 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
629 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
630 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
631 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
632 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700633};
634
635static const char *rx_mix1_text[] = {
636 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
637 "RX5", "RX6", "RX7"
638};
639
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700640static const char *rx_dsm_text[] = {
641 "CIC_OUT", "DSM_INV"
642};
643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700644static const char *sb_tx1_mux_text[] = {
645 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
646 "DEC1"
647};
648
649static const char *sb_tx5_mux_text[] = {
650 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
651 "DEC5"
652};
653
654static const char *sb_tx6_mux_text[] = {
655 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
656 "DEC6"
657};
658
659static const char const *sb_tx7_to_tx10_mux_text[] = {
660 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
661 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
662 "DEC9", "DEC10"
663};
664
665static const char *dec1_mux_text[] = {
666 "ZERO", "DMIC1", "ADC6",
667};
668
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700669static const char *dec2_mux_text[] = {
670 "ZERO", "DMIC2", "ADC5",
671};
672
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700673static const char *dec3_mux_text[] = {
674 "ZERO", "DMIC3", "ADC4",
675};
676
677static const char *dec4_mux_text[] = {
678 "ZERO", "DMIC4", "ADC3",
679};
680
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681static const char *dec5_mux_text[] = {
682 "ZERO", "DMIC5", "ADC2",
683};
684
685static const char *dec6_mux_text[] = {
686 "ZERO", "DMIC6", "ADC1",
687};
688
689static const char const *dec7_mux_text[] = {
690 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
691};
692
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700693static const char *dec8_mux_text[] = {
694 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
695};
696
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700697static const char *dec9_mux_text[] = {
698 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
699};
700
701static const char *dec10_mux_text[] = {
702 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
703};
704
Bradley Rubin229c6a52011-07-12 16:18:48 -0700705static const char const *anc_mux_text[] = {
706 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
707 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
708};
709
710static const char const *anc1_fb_mux_text[] = {
711 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
712};
713
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700714static const char *iir1_inp1_text[] = {
715 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
716 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
717};
718
719static const struct soc_enum rx_mix1_inp1_chain_enum =
720 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
721
Bradley Rubin229c6a52011-07-12 16:18:48 -0700722static const struct soc_enum rx_mix1_inp2_chain_enum =
723 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700725static const struct soc_enum rx2_mix1_inp1_chain_enum =
726 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
727
Bradley Rubin229c6a52011-07-12 16:18:48 -0700728static const struct soc_enum rx2_mix1_inp2_chain_enum =
729 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
730
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700731static const struct soc_enum rx3_mix1_inp1_chain_enum =
732 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
733
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700734static const struct soc_enum rx3_mix1_inp2_chain_enum =
735 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
736
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700737static const struct soc_enum rx4_mix1_inp1_chain_enum =
738 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
739
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700740static const struct soc_enum rx4_mix1_inp2_chain_enum =
741 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
742
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700743static const struct soc_enum rx5_mix1_inp1_chain_enum =
744 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
745
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700746static const struct soc_enum rx5_mix1_inp2_chain_enum =
747 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
748
749static const struct soc_enum rx6_mix1_inp1_chain_enum =
750 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
751
752static const struct soc_enum rx6_mix1_inp2_chain_enum =
753 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
754
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700755static const struct soc_enum rx7_mix1_inp1_chain_enum =
756 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
757
758static const struct soc_enum rx7_mix1_inp2_chain_enum =
759 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
760
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700761static const struct soc_enum rx4_dsm_enum =
762 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
763
764static const struct soc_enum rx6_dsm_enum =
765 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700767static const struct soc_enum sb_tx5_mux_enum =
768 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
769
770static const struct soc_enum sb_tx6_mux_enum =
771 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
772
773static const struct soc_enum sb_tx7_mux_enum =
774 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
775 sb_tx7_to_tx10_mux_text);
776
777static const struct soc_enum sb_tx8_mux_enum =
778 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
779 sb_tx7_to_tx10_mux_text);
780
781static const struct soc_enum sb_tx1_mux_enum =
782 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
783
784static const struct soc_enum dec1_mux_enum =
785 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
786
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700787static const struct soc_enum dec2_mux_enum =
788 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
789
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700790static const struct soc_enum dec3_mux_enum =
791 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
792
793static const struct soc_enum dec4_mux_enum =
794 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
795
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700796static const struct soc_enum dec5_mux_enum =
797 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
798
799static const struct soc_enum dec6_mux_enum =
800 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
801
802static const struct soc_enum dec7_mux_enum =
803 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
804
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700805static const struct soc_enum dec8_mux_enum =
806 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
807
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700808static const struct soc_enum dec9_mux_enum =
809 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
810
811static const struct soc_enum dec10_mux_enum =
812 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
813
Bradley Rubin229c6a52011-07-12 16:18:48 -0700814static const struct soc_enum anc1_mux_enum =
815 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
816
817static const struct soc_enum anc2_mux_enum =
818 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
819
820static const struct soc_enum anc1_fb_mux_enum =
821 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823static const struct soc_enum iir1_inp1_mux_enum =
824 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
825
826static const struct snd_kcontrol_new rx_mix1_inp1_mux =
827 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
828
Bradley Rubin229c6a52011-07-12 16:18:48 -0700829static const struct snd_kcontrol_new rx_mix1_inp2_mux =
830 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
831
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
833 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
834
Bradley Rubin229c6a52011-07-12 16:18:48 -0700835static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
836 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
837
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700838static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
839 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
840
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700841static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
842 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
843
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
845 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
846
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700847static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
848 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
851 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
852
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700853static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
854 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
855
856static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
857 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
858
859static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
860 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
861
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700862static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
863 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
864
865static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
866 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
867
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700868static const struct snd_kcontrol_new rx4_dsm_mux =
869 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
870
871static const struct snd_kcontrol_new rx6_dsm_mux =
872 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
873
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700874static const struct snd_kcontrol_new sb_tx5_mux =
875 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
876
877static const struct snd_kcontrol_new sb_tx6_mux =
878 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
879
880static const struct snd_kcontrol_new sb_tx7_mux =
881 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
882
883static const struct snd_kcontrol_new sb_tx8_mux =
884 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
885
886static const struct snd_kcontrol_new sb_tx1_mux =
887 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
888
889static const struct snd_kcontrol_new dec1_mux =
890 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
891
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700892static const struct snd_kcontrol_new dec2_mux =
893 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
894
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700895static const struct snd_kcontrol_new dec3_mux =
896 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
897
898static const struct snd_kcontrol_new dec4_mux =
899 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901static const struct snd_kcontrol_new dec5_mux =
902 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
903
904static const struct snd_kcontrol_new dec6_mux =
905 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
906
907static const struct snd_kcontrol_new dec7_mux =
908 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
909
Bradley Rubin229c6a52011-07-12 16:18:48 -0700910static const struct snd_kcontrol_new anc1_mux =
911 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700912static const struct snd_kcontrol_new dec8_mux =
913 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
914
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700915static const struct snd_kcontrol_new dec9_mux =
916 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
917
918static const struct snd_kcontrol_new dec10_mux =
919 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921static const struct snd_kcontrol_new iir1_inp1_mux =
922 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
923
Bradley Rubin229c6a52011-07-12 16:18:48 -0700924static const struct snd_kcontrol_new anc2_mux =
925 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700926
Bradley Rubin229c6a52011-07-12 16:18:48 -0700927static const struct snd_kcontrol_new anc1_fb_mux =
928 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929
Bradley Rubin229c6a52011-07-12 16:18:48 -0700930static const struct snd_kcontrol_new dac1_switch[] = {
931 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
932};
933static const struct snd_kcontrol_new hphl_switch[] = {
934 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
935};
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700936
937static const struct snd_kcontrol_new lineout3_ground_switch =
938 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
939
940static const struct snd_kcontrol_new lineout4_ground_switch =
941 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
944 int enable)
945{
946 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
947
948 pr_debug("%s %d\n", __func__, enable);
949
950 if (enable) {
951 tabla->adc_count++;
952 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
953 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
954 } else {
955 tabla->adc_count--;
956 if (!tabla->adc_count) {
957 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
958 0x2, 0x0);
959 if (!tabla->mbhc_polling_active)
960 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
961 0xE0, 0x0);
962 }
963 }
964}
965
966static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
967 struct snd_kcontrol *kcontrol, int event)
968{
969 struct snd_soc_codec *codec = w->codec;
970 u16 adc_reg;
971
972 pr_debug("%s %d\n", __func__, event);
973
974 if (w->reg == TABLA_A_TX_1_2_EN)
975 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
976 else if (w->reg == TABLA_A_TX_3_4_EN)
977 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
978 else if (w->reg == TABLA_A_TX_5_6_EN)
979 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
980 else {
981 pr_err("%s: Error, invalid adc register\n", __func__);
982 return -EINVAL;
983 }
984
985 switch (event) {
986 case SND_SOC_DAPM_PRE_PMU:
987 tabla_codec_enable_adc_block(codec, 1);
988 break;
989 case SND_SOC_DAPM_POST_PMU:
990 snd_soc_update_bits(codec, adc_reg, 1 << w->shift,
991 1 << w->shift);
992 usleep_range(1000, 1000);
993 snd_soc_update_bits(codec, adc_reg, 1 << w->shift, 0x00);
994 usleep_range(1000, 1000);
995 break;
996 case SND_SOC_DAPM_POST_PMD:
997 tabla_codec_enable_adc_block(codec, 0);
998 break;
999 }
1000 return 0;
1001}
1002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1004 struct snd_kcontrol *kcontrol, int event)
1005{
1006 struct snd_soc_codec *codec = w->codec;
1007 u16 lineout_gain_reg;
1008
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001009 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010
1011 switch (w->shift) {
1012 case 0:
1013 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1014 break;
1015 case 1:
1016 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1017 break;
1018 case 2:
1019 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1020 break;
1021 case 3:
1022 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1023 break;
1024 case 4:
1025 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1026 break;
1027 default:
1028 pr_err("%s: Error, incorrect lineout register value\n",
1029 __func__);
1030 return -EINVAL;
1031 }
1032
1033 switch (event) {
1034 case SND_SOC_DAPM_PRE_PMU:
1035 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1036 break;
1037 case SND_SOC_DAPM_POST_PMU:
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001038 pr_debug("%s: sleeping 40 ms after %s PA turn on\n",
1039 __func__, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 usleep_range(40000, 40000);
1041 break;
1042 case SND_SOC_DAPM_POST_PMD:
1043 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1044 break;
1045 }
1046 return 0;
1047}
1048
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001049
1050static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 struct snd_kcontrol *kcontrol, int event)
1052{
1053 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001054 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1055 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001056 unsigned int dmic;
1057 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001058
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001059 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1060 if (ret < 0) {
1061 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001062 return -EINVAL;
1063 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001065 switch (dmic) {
1066 case 1:
1067 case 2:
1068 dmic_clk_sel = 0x02;
1069 dmic_clk_en = 0x01;
1070 break;
1071
1072 case 3:
1073 case 4:
1074 dmic_clk_sel = 0x08;
1075 dmic_clk_en = 0x04;
1076 break;
1077
1078 case 5:
1079 case 6:
1080 dmic_clk_sel = 0x20;
1081 dmic_clk_en = 0x10;
1082 break;
1083
1084 default:
1085 pr_err("%s: Invalid DMIC Selection\n", __func__);
1086 return -EINVAL;
1087 }
1088
1089 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1090 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 switch (event) {
1095 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001096 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1097
1098 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1099 dmic_clk_sel, dmic_clk_sel);
1100
1101 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1102
1103 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1104 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 break;
1106 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001107 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1108 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001109 break;
1110 }
1111 return 0;
1112}
1113
Bradley Rubin229c6a52011-07-12 16:18:48 -07001114static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1115 struct snd_kcontrol *kcontrol, int event)
1116{
1117 struct snd_soc_codec *codec = w->codec;
1118 const char *filename;
1119 const struct firmware *fw;
1120 int i;
1121 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001122 int num_anc_slots;
1123 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001124 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001125 u32 anc_writes_size = 0;
1126 int anc_size_remaining;
1127 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001128 u16 reg;
1129 u8 mask, val, old_val;
1130
1131 pr_debug("%s %d\n", __func__, event);
1132 switch (event) {
1133 case SND_SOC_DAPM_PRE_PMU:
1134
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001135 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001136
1137 ret = request_firmware(&fw, filename, codec->dev);
1138 if (ret != 0) {
1139 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1140 ret);
1141 return -ENODEV;
1142 }
1143
Bradley Rubina7096d02011-08-03 18:29:02 -07001144 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001145 dev_err(codec->dev, "Not enough data\n");
1146 release_firmware(fw);
1147 return -ENOMEM;
1148 }
1149
1150 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001151 anc_head = (struct anc_header *)(fw->data);
1152 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1153 anc_size_remaining = fw->size - sizeof(struct anc_header);
1154 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001155
Bradley Rubina7096d02011-08-03 18:29:02 -07001156 if (tabla->anc_slot >= num_anc_slots) {
1157 dev_err(codec->dev, "Invalid ANC slot selected\n");
1158 release_firmware(fw);
1159 return -EINVAL;
1160 }
1161
1162 for (i = 0; i < num_anc_slots; i++) {
1163
1164 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1165 dev_err(codec->dev, "Invalid register format\n");
1166 release_firmware(fw);
1167 return -EINVAL;
1168 }
1169 anc_writes_size = (u32)(*anc_ptr);
1170 anc_size_remaining -= sizeof(u32);
1171 anc_ptr += 1;
1172
1173 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1174 > anc_size_remaining) {
1175 dev_err(codec->dev, "Invalid register format\n");
1176 release_firmware(fw);
1177 return -ENOMEM;
1178 }
1179
1180 if (tabla->anc_slot == i)
1181 break;
1182
1183 anc_size_remaining -= (anc_writes_size *
1184 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001185 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001186 }
1187 if (i == num_anc_slots) {
1188 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001189 release_firmware(fw);
1190 return -ENOMEM;
1191 }
1192
Bradley Rubina7096d02011-08-03 18:29:02 -07001193 for (i = 0; i < anc_writes_size; i++) {
1194 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001195 mask, val);
1196 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001197 snd_soc_write(codec, reg, (old_val & ~mask) |
1198 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001199 }
1200 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001201
1202 break;
1203 case SND_SOC_DAPM_POST_PMD:
1204 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1205 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1206 break;
1207 }
1208 return 0;
1209}
1210
1211
Bradley Rubincb3950a2011-08-18 13:07:26 -07001212static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
1213{
1214 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
1215 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
1216}
1217
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001218static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1219{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001220 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1221
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001222 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001223 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001224 if (!tabla->no_mic_headset_override) {
1225 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1226 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1227 } else {
1228 tabla_codec_disable_button_presses(codec);
1229 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001230 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1231 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1232 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1233}
1234
1235static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1236{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001237 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1238
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001239 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1240 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001241 if (!tabla->no_mic_headset_override) {
1242 tabla_disable_irq(codec->control_data,
1243 TABLA_IRQ_MBHC_POTENTIAL);
1244 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1245 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001246}
1247
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001248static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1249 int mode)
1250{
1251 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1252 u8 reg_mode_val, cur_mode_val;
1253 bool mbhc_was_polling = false;
1254
1255 if (mode)
1256 reg_mode_val = TABLA_CFILT_FAST_MODE;
1257 else
1258 reg_mode_val = TABLA_CFILT_SLOW_MODE;
1259
1260 cur_mode_val = snd_soc_read(codec,
1261 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
1262
1263 if (cur_mode_val != reg_mode_val) {
1264 if (tabla->mbhc_polling_active) {
1265 tabla_codec_pause_hs_polling(codec);
1266 mbhc_was_polling = true;
1267 }
1268 snd_soc_update_bits(codec,
1269 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1270 if (mbhc_was_polling)
1271 tabla_codec_start_hs_polling(codec);
1272 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
1273 cur_mode_val, reg_mode_val);
1274 } else {
1275 pr_debug("%s: CFILT Value is already %x\n",
1276 __func__, cur_mode_val);
1277 }
1278}
1279
1280static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1281 u8 cfilt_sel, int inc)
1282{
1283 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1284 u32 *cfilt_cnt_ptr = NULL;
1285 u16 micb_cfilt_reg;
1286
1287 switch (cfilt_sel) {
1288 case TABLA_CFILT1_SEL:
1289 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
1290 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
1291 break;
1292 case TABLA_CFILT2_SEL:
1293 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
1294 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
1295 break;
1296 case TABLA_CFILT3_SEL:
1297 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
1298 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
1299 break;
1300 default:
1301 return; /* should not happen */
1302 }
1303
1304 if (inc) {
1305 if (!(*cfilt_cnt_ptr)++) {
1306 /* Switch CFILT to slow mode if MBHC CFILT being used */
1307 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1308 tabla_codec_switch_cfilt_mode(codec, 0);
1309
1310 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1311 }
1312 } else {
1313 /* check if count not zero, decrement
1314 * then check if zero, go ahead disable cfilter
1315 */
1316 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1317 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1318
1319 /* Switch CFILT to fast mode if MBHC CFILT being used */
1320 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1321 tabla_codec_switch_cfilt_mode(codec, 1);
1322 }
1323 }
1324}
1325
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001326static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1327{
1328 int rc = -EINVAL;
1329 unsigned min_mv, max_mv;
1330
1331 switch (ldoh_v) {
1332 case TABLA_LDOH_1P95_V:
1333 min_mv = 160;
1334 max_mv = 1800;
1335 break;
1336 case TABLA_LDOH_2P35_V:
1337 min_mv = 200;
1338 max_mv = 2200;
1339 break;
1340 case TABLA_LDOH_2P75_V:
1341 min_mv = 240;
1342 max_mv = 2600;
1343 break;
1344 case TABLA_LDOH_2P85_V:
1345 min_mv = 250;
1346 max_mv = 2700;
1347 break;
1348 default:
1349 goto done;
1350 }
1351
1352 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1353 goto done;
1354
1355 for (rc = 4; rc <= 44; rc++) {
1356 min_mv = max_mv * (rc) / 44;
1357 if (min_mv >= cfilt_mv) {
1358 rc -= 4;
1359 break;
1360 }
1361 }
1362done:
1363 return rc;
1364}
1365
1366static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
1367{
1368 u8 hph_reg_val = 0;
1369 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
1370
1371 return (hph_reg_val & 0x30) ? true : false;
1372}
1373
Joonwoo Parka9444452011-12-08 18:48:27 -08001374static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
1375{
1376 u8 hph_reg_val = 0;
1377 if (left)
1378 hph_reg_val = snd_soc_read(codec,
1379 TABLA_A_RX_HPH_L_DAC_CTL);
1380 else
1381 hph_reg_val = snd_soc_read(codec,
1382 TABLA_A_RX_HPH_R_DAC_CTL);
1383
1384 return (hph_reg_val & 0xC0) ? true : false;
1385}
1386
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001387static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
1388 int vddio_switch)
1389{
1390 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1391 int cfilt_k_val;
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001392 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001393
1394 switch (vddio_switch) {
1395 case 1:
1396 if (tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001397
1398 tabla_codec_pause_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001399 /* Enable Mic Bias switch to VDDIO */
1400 tabla->cfilt_k_value = snd_soc_read(codec,
1401 tabla->mbhc_bias_regs.cfilt_val);
1402 cfilt_k_val = tabla_find_k_value(
1403 tabla->pdata->micbias.ldoh_v, 1800);
1404 snd_soc_update_bits(codec,
1405 tabla->mbhc_bias_regs.cfilt_val,
1406 0xFC, (cfilt_k_val << 2));
1407
1408 snd_soc_update_bits(codec,
1409 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1410 snd_soc_update_bits(codec,
1411 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001412 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001413
1414 tabla->mbhc_micbias_switched = true;
1415 pr_debug("%s: Enabled MBHC Mic bias to VDDIO Switch\n",
1416 __func__);
1417 }
1418 break;
1419
1420 case 0:
1421 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001422 if (tabla->mbhc_polling_active) {
1423 tabla_codec_pause_hs_polling(codec);
1424 mbhc_was_polling = true;
1425 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001426 /* Disable Mic Bias switch to VDDIO */
1427 if (tabla->cfilt_k_value != 0)
1428 snd_soc_update_bits(codec,
1429 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
1430 tabla->cfilt_k_value);
1431 snd_soc_update_bits(codec,
1432 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1433 snd_soc_update_bits(codec,
1434 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1435
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001436 if (mbhc_was_polling)
1437 tabla_codec_start_hs_polling(codec);
1438
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001439 tabla->mbhc_micbias_switched = false;
1440 pr_debug("%s: Disabled MBHC Mic bias to VDDIO Switch\n",
1441 __func__);
1442 }
1443 break;
1444 }
1445}
1446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1448 struct snd_kcontrol *kcontrol, int event)
1449{
1450 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07001451 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1452 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001453 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001454 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001455 char *internal1_text = "Internal1";
1456 char *internal2_text = "Internal2";
1457 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458
1459 pr_debug("%s %d\n", __func__, event);
1460 switch (w->reg) {
1461 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001463 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001464 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 break;
1466 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001468 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001469 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 break;
1471 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001472 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001473 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001474 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001475 break;
1476 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001477 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001478 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001479 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001480 break;
1481 default:
1482 pr_err("%s: Error, invalid micbias register\n", __func__);
1483 return -EINVAL;
1484 }
1485
1486 switch (event) {
1487 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001488 /* Decide whether to switch the micbias for MBHC */
1489 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1490 && tabla->mbhc_micbias_switched)
1491 tabla_codec_switch_micbias(codec, 0);
1492
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001493 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07001494 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001495
1496 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001498 else if (strnstr(w->name, internal2_text, 30))
1499 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1500 else if (strnstr(w->name, internal3_text, 30))
1501 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
1502
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001504 case SND_SOC_DAPM_POST_PMU:
1505 if (tabla->mbhc_polling_active &&
1506 (tabla->calibration->bias == micb_line)) {
1507 tabla_codec_pause_hs_polling(codec);
1508 tabla_codec_start_hs_polling(codec);
1509 }
1510 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001513
1514 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1515 && tabla_is_hph_pa_on(codec))
1516 tabla_codec_switch_micbias(codec, 1);
1517
Bradley Rubin229c6a52011-07-12 16:18:48 -07001518 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001520 else if (strnstr(w->name, internal2_text, 30))
1521 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1522 else if (strnstr(w->name, internal3_text, 30))
1523 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1524
Patrick Lai3043fba2011-08-01 14:15:57 -07001525 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526 break;
1527 }
1528
1529 return 0;
1530}
1531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001532static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
1533 struct snd_kcontrol *kcontrol, int event)
1534{
1535 struct snd_soc_codec *codec = w->codec;
1536 u16 dec_reset_reg;
1537
1538 pr_debug("%s %d\n", __func__, event);
1539
1540 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1541 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
1542 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
1543 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
1544 else {
1545 pr_err("%s: Error, incorrect dec\n", __func__);
1546 return -EINVAL;
1547 }
1548
1549 switch (event) {
1550 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1552 1 << w->shift);
1553 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1554 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555 }
1556 return 0;
1557}
1558
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001559static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 struct snd_kcontrol *kcontrol, int event)
1561{
1562 struct snd_soc_codec *codec = w->codec;
1563
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001564 pr_debug("%s %d %s\n", __func__, event, w->name);
1565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 switch (event) {
1567 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001568 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1569 1 << w->shift, 1 << w->shift);
1570 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1571 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001572 break;
1573 }
1574 return 0;
1575}
1576
Bradley Rubin229c6a52011-07-12 16:18:48 -07001577static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1578 struct snd_kcontrol *kcontrol, int event)
1579{
1580 switch (event) {
1581 case SND_SOC_DAPM_POST_PMU:
1582 case SND_SOC_DAPM_POST_PMD:
1583 usleep_range(1000, 1000);
1584 break;
1585 }
1586 return 0;
1587}
1588
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001589
1590static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1591{
1592 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1593
1594 if (enable) {
1595 tabla->rx_bias_count++;
1596 if (tabla->rx_bias_count == 1)
1597 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1598 0x80, 0x80);
1599 } else {
1600 tabla->rx_bias_count--;
1601 if (!tabla->rx_bias_count)
1602 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1603 0x80, 0x00);
1604 }
1605}
1606
1607static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1608 struct snd_kcontrol *kcontrol, int event)
1609{
1610 struct snd_soc_codec *codec = w->codec;
1611
1612 pr_debug("%s %d\n", __func__, event);
1613
1614 switch (event) {
1615 case SND_SOC_DAPM_PRE_PMU:
1616 tabla_enable_rx_bias(codec, 1);
1617 break;
1618 case SND_SOC_DAPM_POST_PMD:
1619 tabla_enable_rx_bias(codec, 0);
1620 break;
1621 }
1622 return 0;
1623}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001624static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
1625 struct snd_kcontrol *kcontrol, int event)
1626{
1627 struct snd_soc_codec *codec = w->codec;
1628
1629 pr_debug("%s %s %d\n", __func__, w->name, event);
1630
1631 switch (event) {
1632 case SND_SOC_DAPM_PRE_PMU:
1633 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1634 break;
1635 case SND_SOC_DAPM_POST_PMD:
1636 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1637 break;
1638 }
1639 return 0;
1640}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001641
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001642static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
1643 struct snd_soc_jack *jack, int status,
1644 int mask)
1645{
1646 /* XXX: wake_lock_timeout()? */
1647 snd_soc_jack_report(jack, status, mask);
1648}
1649
Patrick Lai49efeac2011-11-03 11:01:12 -07001650static void hphocp_off_report(struct tabla_priv *tabla,
1651 u32 jack_status, int irq)
1652{
1653 struct snd_soc_codec *codec;
1654
1655 if (tabla) {
1656 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
1657 codec = tabla->codec;
1658 tabla->hph_status &= ~jack_status;
1659 if (tabla->headset_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001660 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
1661 tabla->hph_status,
1662 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07001663 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
1664 0x00);
1665 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
1666 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08001667 /* reset retry counter as PA is turned off signifying
1668 * start of new OCP detection session
1669 */
1670 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
1671 tabla->hphlocp_cnt = 0;
1672 else
1673 tabla->hphrocp_cnt = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07001674 tabla_enable_irq(codec->control_data, irq);
1675 } else {
1676 pr_err("%s: Bad tabla private data\n", __func__);
1677 }
1678}
1679
1680static void hphlocp_off_report(struct work_struct *work)
1681{
1682 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1683 hphlocp_work);
1684 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
1685}
1686
1687static void hphrocp_off_report(struct work_struct *work)
1688{
1689 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1690 hphrocp_work);
1691 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
1692}
1693
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001694static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
1695 struct snd_kcontrol *kcontrol, int event)
1696{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001697 struct snd_soc_codec *codec = w->codec;
1698 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1699 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001700 pr_debug("%s: event = %d\n", __func__, event);
1701
1702 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001703 case SND_SOC_DAPM_PRE_PMU:
1704 mbhc_micb_ctl_val = snd_soc_read(codec,
1705 tabla->mbhc_bias_regs.ctl_reg);
1706
1707 if (!(mbhc_micb_ctl_val & 0x80)
1708 && !tabla->mbhc_micbias_switched)
1709 tabla_codec_switch_micbias(codec, 1);
1710
1711 break;
1712
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001713 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07001714 /* schedule work is required because at the time HPH PA DAPM
1715 * event callback is called by DAPM framework, CODEC dapm mutex
1716 * would have been locked while snd_soc_jack_report also
1717 * attempts to acquire same lock.
1718 */
Joonwoo Parka9444452011-12-08 18:48:27 -08001719 if (w->shift == 5) {
1720 clear_bit(TABLA_HPHL_PA_OFF_ACK,
1721 &tabla->hph_pa_dac_state);
1722 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
1723 &tabla->hph_pa_dac_state);
1724 if (tabla->hph_status & SND_JACK_OC_HPHL)
1725 schedule_work(&tabla->hphlocp_work);
1726 } else if (w->shift == 4) {
1727 clear_bit(TABLA_HPHR_PA_OFF_ACK,
1728 &tabla->hph_pa_dac_state);
1729 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
1730 &tabla->hph_pa_dac_state);
1731 if (tabla->hph_status & SND_JACK_OC_HPHR)
1732 schedule_work(&tabla->hphrocp_work);
1733 }
1734
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001735 if (tabla->mbhc_micbias_switched)
1736 tabla_codec_switch_micbias(codec, 0);
1737
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001738 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
1739 w->name);
1740 usleep_range(10000, 10000);
1741
1742 break;
1743 }
1744 return 0;
1745}
1746
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001747static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
1748 struct mbhc_micbias_regs *micbias_regs)
1749{
1750 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1751 struct tabla_mbhc_calibration *calibration = tabla->calibration;
1752 unsigned int cfilt;
1753
1754 switch (calibration->bias) {
1755 case TABLA_MICBIAS1:
1756 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
1757 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
1758 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
1759 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
1760 break;
1761 case TABLA_MICBIAS2:
1762 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
1763 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
1764 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
1765 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
1766 break;
1767 case TABLA_MICBIAS3:
1768 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
1769 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
1770 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
1771 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
1772 break;
1773 case TABLA_MICBIAS4:
1774 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
1775 micbias_regs->mbhc_reg = TABLA_A_MICB_4_MBHC;
1776 micbias_regs->int_rbias = TABLA_A_MICB_4_INT_RBIAS;
1777 micbias_regs->ctl_reg = TABLA_A_MICB_4_CTL;
1778 break;
1779 default:
1780 /* Should never reach here */
1781 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07001782 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001783 }
1784
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001785 micbias_regs->cfilt_sel = cfilt;
1786
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001787 switch (cfilt) {
1788 case TABLA_CFILT1_SEL:
1789 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
1790 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
1791 break;
1792 case TABLA_CFILT2_SEL:
1793 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
1794 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
1795 break;
1796 case TABLA_CFILT3_SEL:
1797 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
1798 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
1799 break;
1800 }
1801}
Santosh Mardie15e2302011-11-15 10:39:23 +05301802static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
1803 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
1804 4, 0, NULL, 0),
1805 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
1806 0, NULL, 0),
1807};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001808
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001809static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
1810 struct snd_kcontrol *kcontrol, int event)
1811{
1812 struct snd_soc_codec *codec = w->codec;
1813
1814 pr_debug("%s %s %d\n", __func__, w->name, event);
1815
1816 switch (event) {
1817 case SND_SOC_DAPM_PRE_PMU:
1818 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1819 break;
1820
1821 case SND_SOC_DAPM_POST_PMD:
1822 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1823 break;
1824 }
1825 return 0;
1826}
1827
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001828static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
1829 /*RX stuff */
1830 SND_SOC_DAPM_OUTPUT("EAR"),
1831
Kiran Kandid2d86b52011-09-09 17:44:28 -07001832 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001833
Bradley Rubin229c6a52011-07-12 16:18:48 -07001834 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
1835 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001836
Bradley Rubin229c6a52011-07-12 16:18:48 -07001837 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1838 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Santosh Mardie15e2302011-11-15 10:39:23 +05301839 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1840 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001841
1842 /* Headphone */
1843 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001844 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001845 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1846 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001847 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
1848 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001850 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001851 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1852 SND_SOC_DAPM_POST_PMD),
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001853
1854 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
1855 tabla_hphr_dac_event,
1856 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857
1858 /* Speaker */
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001859 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
1860 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
1861 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
1862 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
1863 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001864
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001865 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
1866 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1867 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1868 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
1869 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1870 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1871 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
1872 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1873 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1874 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
1875 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1876 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1877 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001878 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1879 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001880
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001881 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
1882 , tabla_lineout_dac_event,
1883 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1884 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
1885 , tabla_lineout_dac_event,
1886 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1887 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
1888 , tabla_lineout_dac_event,
1889 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1890 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
1891 &lineout3_ground_switch),
1892 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
1893 , tabla_lineout_dac_event,
1894 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1895 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
1896 &lineout4_ground_switch),
1897 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
1898 , tabla_lineout_dac_event,
1899 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001900
Bradley Rubin229c6a52011-07-12 16:18:48 -07001901 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
1902 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1903 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
1904 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1905 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
1906 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1907 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
1908 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1909 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
1910 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1911 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
1912 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001913 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
1914 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001915
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001916
1917 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
1918 &rx4_dsm_mux, tabla_codec_reset_interpolator,
1919 SND_SOC_DAPM_PRE_PMU),
1920
1921 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
1922 &rx6_dsm_mux, tabla_codec_reset_interpolator,
1923 SND_SOC_DAPM_PRE_PMU),
1924
Bradley Rubin229c6a52011-07-12 16:18:48 -07001925 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
1926 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
1927
1928 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1929 &rx_mix1_inp1_mux),
1930 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1931 &rx_mix1_inp2_mux),
1932 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1933 &rx2_mix1_inp1_mux),
1934 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1935 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001936 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1937 &rx3_mix1_inp1_mux),
1938 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1939 &rx3_mix1_inp2_mux),
1940 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1941 &rx4_mix1_inp1_mux),
1942 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1943 &rx4_mix1_inp2_mux),
1944 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1945 &rx5_mix1_inp1_mux),
1946 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1947 &rx5_mix1_inp2_mux),
1948 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1949 &rx6_mix1_inp1_mux),
1950 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1951 &rx6_mix1_inp2_mux),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001952 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1953 &rx7_mix1_inp1_mux),
1954 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1955 &rx7_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001956
Bradley Rubin229c6a52011-07-12 16:18:48 -07001957 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
1958 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
1959 SND_SOC_DAPM_PRE_PMD),
1960
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001961 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
1962 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
1963 SND_SOC_DAPM_POST_PMD),
1964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001965 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -07001966
Bradley Rubine1d08622011-07-20 18:01:35 -07001967 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
1968 0),
1969
Bradley Rubin229c6a52011-07-12 16:18:48 -07001970 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
1971 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
1972
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001973 SND_SOC_DAPM_INPUT("AMIC1"),
1974 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
1975 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001976 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001977 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
1978 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001979 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001980 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001981 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001982 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
1984 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1985 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1986
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001987 SND_SOC_DAPM_INPUT("AMIC3"),
1988 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
1989 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1990 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1991
1992 SND_SOC_DAPM_INPUT("AMIC4"),
1993 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
1994 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
1995 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1996
1997 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
1998 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001999 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002000
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002001 SND_SOC_DAPM_INPUT("AMIC5"),
2002 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
2003 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
2004
2005 SND_SOC_DAPM_INPUT("AMIC6"),
2006 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
2007 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
2008
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002009 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 -07002010 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002011
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002012 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 -07002013 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002014
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002015 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 -07002016 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002017
2018 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 -07002019 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002020
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 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 -07002022 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023
2024 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 -07002025 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002026
2027 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 -07002028 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002029
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002030 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 -07002031 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002032
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002033 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 -07002034 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002035
2036 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 -07002037 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002038
Bradley Rubin229c6a52011-07-12 16:18:48 -07002039 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
2040 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
2041
2042 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
2043 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
2044 SND_SOC_DAPM_POST_PMD),
2045
2046 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
2047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002048 SND_SOC_DAPM_INPUT("AMIC2"),
2049 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
2050 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002051 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002052 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
2053 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002054 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002055 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
2056 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002057 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002058 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002059 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002060 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002061 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
2062 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002063 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002064 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
2065 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002066 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002067 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002069 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002070 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
2071 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2072 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2073
2074 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
2075 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
2076 0, 0),
2077
2078 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
2079 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
2080 4, 0),
2081
2082 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
2083 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
2084 5, 0),
2085
2086 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
2087 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
2088 0, 0),
2089
2090 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
2091 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
2092 0, 0),
2093
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002094 /* Digital Mic Inputs */
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002095 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2096 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2097 SND_SOC_DAPM_POST_PMD),
2098
2099 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2100 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2101 SND_SOC_DAPM_POST_PMD),
2102
2103 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
2104 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2105 SND_SOC_DAPM_POST_PMD),
2106
2107 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
2108 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2109 SND_SOC_DAPM_POST_PMD),
2110
2111 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
2112 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2113 SND_SOC_DAPM_POST_PMD),
2114
2115 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
2116 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2117 SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118
2119 /* Sidetone */
2120 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2121 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2122};
2123
Santosh Mardie15e2302011-11-15 10:39:23 +05302124static const struct snd_soc_dapm_route audio_i2s_map[] = {
2125 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2126 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2127 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2128 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2129 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2130
2131 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2132 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2133 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2134 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2135};
2136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137static const struct snd_soc_dapm_route audio_map[] = {
2138 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002139
2140 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2141 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2142
2143 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2144 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2145
2146 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2147 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2148
2149 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2150 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002151 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002152 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2153 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2155 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002156 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2157 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002158 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2159 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002160
2161 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002162 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2163 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2164 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002165 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002166 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2167 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2168
2169 /* Earpiece (RX MIX1) */
2170 {"EAR", NULL, "EAR PA"},
Kiran Kandiac034ac2011-07-29 16:39:08 -07002171 {"EAR PA", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002172 {"DAC1", NULL, "CP"},
2173
2174 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2175 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2176 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002177
2178 /* Headset (RX MIX1 and RX MIX2) */
2179 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002180 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002181
2182 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002183 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002184
2185 {"HPHL DAC", NULL, "CP"},
2186 {"HPHR DAC", NULL, "CP"},
2187
2188 {"ANC", NULL, "ANC1 MUX"},
2189 {"ANC", NULL, "ANC2 MUX"},
2190 {"ANC1 MUX", "ADC1", "ADC1"},
2191 {"ANC1 MUX", "ADC2", "ADC2"},
2192 {"ANC1 MUX", "ADC3", "ADC3"},
2193 {"ANC1 MUX", "ADC4", "ADC4"},
2194 {"ANC2 MUX", "ADC1", "ADC1"},
2195 {"ANC2 MUX", "ADC2", "ADC2"},
2196 {"ANC2 MUX", "ADC3", "ADC3"},
2197 {"ANC2 MUX", "ADC4", "ADC4"},
2198
Bradley Rubine1d08622011-07-20 18:01:35 -07002199 {"ANC", NULL, "CDC_CONN"},
2200
Bradley Rubin229c6a52011-07-12 16:18:48 -07002201 {"DAC1", "Switch", "RX1 CHAIN"},
2202 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002203 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002204
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002205 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2206 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2207 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2208 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2209 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002210
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002211 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2212 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2213 {"LINEOUT3 PA", NULL, "LINEOUT3 DAC"},
2214 {"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
2215 {"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002216
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002217 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2218 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2219
Bradley Rubin229c6a52011-07-12 16:18:48 -07002220 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2221 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2222 {"RX1 CHAIN", NULL, "ANC"},
2223 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002224
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002225 {"CP", NULL, "RX_BIAS"},
2226 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2227 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2228 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2229 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002230 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002231
Bradley Rubin229c6a52011-07-12 16:18:48 -07002232 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2233 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2234 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2235 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002236 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2237 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2238 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2239 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2240 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2241 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2242 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2243 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002244 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2245 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002246
Bradley Rubin229c6a52011-07-12 16:18:48 -07002247 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2248 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302249 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2250 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002251 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2252 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2253 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302254 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2255 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002256 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2257 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2258 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302259 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2260 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002261 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002262 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2263 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302264 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2265 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002266 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002267 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2268 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302269 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2270 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002271 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002272 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2273 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302274 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2275 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002276 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002277 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2278 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302279 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2280 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002281 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002282 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2283 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302284 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2285 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002286 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002287 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2288 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302289 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2290 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002291 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002292 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2293 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302294 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2295 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002296 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002297 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2298 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302299 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2300 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002301 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002302 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2303 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302304 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2305 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002306 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002307 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2308 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302309 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2310 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002311 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002312 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2313 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302314 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2315 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002316 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002318 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002319 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002320 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002321 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002322 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002323 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002324 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002325 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002326 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002327 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002328 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002329 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002330 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002331 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002332 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002333 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002334 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002335 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002336 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002337 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002338 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002339 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002340 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002341 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002342 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002343 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002344 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002345 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002346
2347 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002348 {"ADC1", NULL, "AMIC1"},
2349 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002350 {"ADC3", NULL, "AMIC3"},
2351 {"ADC4", NULL, "AMIC4"},
2352 {"ADC5", NULL, "AMIC5"},
2353 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002354
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002356 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2357 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2358 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2359 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2360 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002361 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002362 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
2363 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
2364 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
2365 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002366
2367 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2368 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2369 {"MIC BIAS1 External", NULL, "LDO_H"},
2370 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2371 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2372 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2373 {"MIC BIAS2 External", NULL, "LDO_H"},
2374 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2375 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2376 {"MIC BIAS3 External", NULL, "LDO_H"},
2377 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002378};
2379
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002380static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
2381
2382 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2383 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2384
2385 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
2386
2387 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
2388 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
2389 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
2390
2391 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2392 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2393
2394 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2395 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
2396 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
2397};
2398
Kiran Kandi7a9fd902011-11-14 13:51:45 -08002399
2400static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
2401
2402 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2403 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2404
2405 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
2406
2407 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
2408
2409 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2410 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2411
2412 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2413};
2414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002415static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
2416{
2417 return tabla_reg_readable[reg];
2418}
2419
2420static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2421{
2422 /* Registers lower than 0x100 are top level registers which can be
2423 * written by the Tabla core driver.
2424 */
2425
2426 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2427 return 1;
2428
Ben Romberger1f045a72011-11-04 10:14:57 -07002429 /* IIR Coeff registers are not cacheable */
2430 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
2431 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
2432 return 1;
2433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002434 return 0;
2435}
2436
2437#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2438static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
2439 unsigned int value)
2440{
2441 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002442
2443 BUG_ON(reg > TABLA_MAX_REGISTER);
2444
2445 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002446 ret = snd_soc_cache_write(codec, reg, value);
2447 if (ret != 0)
2448 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2449 reg, ret);
2450 }
2451
2452 return tabla_reg_write(codec->control_data, reg, value);
2453}
2454static unsigned int tabla_read(struct snd_soc_codec *codec,
2455 unsigned int reg)
2456{
2457 unsigned int val;
2458 int ret;
2459
2460 BUG_ON(reg > TABLA_MAX_REGISTER);
2461
2462 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
2463 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002464 ret = snd_soc_cache_read(codec, reg, &val);
2465 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 return val;
2467 } else
2468 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2469 reg, ret);
2470 }
2471
2472 val = tabla_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473 return val;
2474}
2475
2476static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2477{
2478 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
2479 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2480 0x80);
2481 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
2482 0x04);
2483 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2484 0x01);
2485 usleep_range(1000, 1000);
2486 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2487 0x00);
2488}
2489
2490static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
2491 enum tabla_bandgap_type choice)
2492{
2493 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2494
2495 /* TODO lock resources accessed by audio streams and threaded
2496 * interrupt handlers
2497 */
2498
2499 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
2500 tabla->bandgap_type);
2501
2502 if (tabla->bandgap_type == choice)
2503 return;
2504
2505 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
2506 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2507 tabla_codec_enable_audio_mode_bandgap(codec);
2508 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
2509 (choice == TABLA_BANDGAP_MBHC_MODE)) {
2510 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
2511 0x2);
2512 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2513 0x80);
2514 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
2515 0x4);
2516 usleep_range(1000, 1000);
2517 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2518 0x00);
2519 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
2520 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2521 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2522 usleep_range(100, 100);
2523 tabla_codec_enable_audio_mode_bandgap(codec);
2524 } else if (choice == TABLA_BANDGAP_OFF) {
2525 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2526 } else {
2527 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2528 }
2529 tabla->bandgap_type = choice;
2530}
2531
2532static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
2533 int enable)
2534{
2535 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2536
2537 if (enable) {
2538 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
2539 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
2540 usleep_range(5, 5);
2541 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
2542 0x80);
2543 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
2544 0x80);
2545 usleep_range(10, 10);
2546 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
2547 usleep_range(20, 20);
2548 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
2549 } else {
2550 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
2551 0);
2552 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
2553 }
2554 tabla->config_mode_active = enable ? true : false;
2555
2556 return 0;
2557}
2558
2559static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
2560 int config_mode)
2561{
2562 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2563
2564 pr_debug("%s\n", __func__);
2565
2566 if (config_mode) {
2567 tabla_codec_enable_config_mode(codec, 1);
2568 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
2569 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2570 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
2571 usleep_range(1000, 1000);
2572 } else
2573 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
2574
2575 if (!config_mode && tabla->mbhc_polling_active) {
2576 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2577 tabla_codec_enable_config_mode(codec, 0);
2578
2579 }
2580
2581 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
2582 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
2583 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
2584 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
2585 usleep_range(50, 50);
2586 tabla->clock_active = true;
2587 return 0;
2588}
2589static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
2590{
2591 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2592 pr_debug("%s\n", __func__);
2593 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
2594 ndelay(160);
2595 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
2596 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
2597 tabla->clock_active = false;
2598}
2599
Bradley Rubincb1e2732011-06-23 16:49:20 -07002600static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2601{
2602 /* TODO store register values in calibration */
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07002603 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL, 0x20);
2604 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL, 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002605
2606 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL, 0xFF);
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07002607 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL, 0x20);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002608
Bhalchandra Gajarefabb8772011-11-10 19:52:01 -08002609 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0xF8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002610 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xEE);
2611 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0xFC);
2612 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xCE);
2613
2614 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 3);
2615 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL, 9);
2616 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL, 30);
2617 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 120);
2618 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL, 0x78, 0x58);
2619 snd_soc_write(codec, TABLA_A_CDC_MBHC_B2_CTL, 11);
2620}
2621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622static int tabla_startup(struct snd_pcm_substream *substream,
2623 struct snd_soc_dai *dai)
2624{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002625 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2626 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002627
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002628 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002629}
2630
2631static void tabla_shutdown(struct snd_pcm_substream *substream,
2632 struct snd_soc_dai *dai)
2633{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002634 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2635 substream->name, substream->stream);
2636}
2637
2638int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
2639{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002640 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2641
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002642 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002643
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002644 if (mclk_enable) {
2645 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002646
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002647 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07002648 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002649 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002650 TABLA_BANDGAP_AUDIO_MODE);
2651 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002652 tabla_codec_calibrate_hs_polling(codec);
2653 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002655 } else {
2656
2657 if (!tabla->mclk_enabled) {
2658 pr_err("Error, MCLK already diabled\n");
2659 return -EINVAL;
2660 }
2661 tabla->mclk_enabled = false;
2662
2663 if (tabla->mbhc_polling_active) {
2664 if (!tabla->mclk_enabled) {
2665 tabla_codec_pause_hs_polling(codec);
2666 tabla_codec_enable_bandgap(codec,
2667 TABLA_BANDGAP_MBHC_MODE);
2668 tabla_enable_rx_bias(codec, 1);
2669 tabla_codec_enable_clock_block(codec, 1);
2670 tabla_codec_calibrate_hs_polling(codec);
2671 tabla_codec_start_hs_polling(codec);
2672 }
2673 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
2674 0x05, 0x01);
2675 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002676 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002677 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678}
2679
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002680static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
2681 int clk_id, unsigned int freq, int dir)
2682{
2683 pr_debug("%s\n", __func__);
2684 return 0;
2685}
2686
2687static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2688{
Santosh Mardie15e2302011-11-15 10:39:23 +05302689 u8 val = 0;
2690 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
2691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002692 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05302693 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2694 case SND_SOC_DAIFMT_CBS_CFS:
2695 /* CPU is master */
2696 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2697 if (dai->id == TABLA_TX_DAI_ID)
2698 snd_soc_update_bits(dai->codec,
2699 TABLA_A_CDC_CLK_TX_I2S_CTL,
2700 TABLA_I2S_MASTER_MODE_MASK, 0);
2701 else if (dai->id == TABLA_RX_DAI_ID)
2702 snd_soc_update_bits(dai->codec,
2703 TABLA_A_CDC_CLK_RX_I2S_CTL,
2704 TABLA_I2S_MASTER_MODE_MASK, 0);
2705 }
2706 break;
2707 case SND_SOC_DAIFMT_CBM_CFM:
2708 /* CPU is slave */
2709 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2710 val = TABLA_I2S_MASTER_MODE_MASK;
2711 if (dai->id == TABLA_TX_DAI_ID)
2712 snd_soc_update_bits(dai->codec,
2713 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
2714 else if (dai->id == TABLA_RX_DAI_ID)
2715 snd_soc_update_bits(dai->codec,
2716 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
2717 }
2718 break;
2719 default:
2720 return -EINVAL;
2721 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722 return 0;
2723}
2724
2725static int tabla_hw_params(struct snd_pcm_substream *substream,
2726 struct snd_pcm_hw_params *params,
2727 struct snd_soc_dai *dai)
2728{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002729 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05302730 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07002731 u8 path, shift;
2732 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002733 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
2734
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002735 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002736
2737 switch (params_rate(params)) {
2738 case 8000:
2739 tx_fs_rate = 0x00;
2740 rx_fs_rate = 0x00;
2741 break;
2742 case 16000:
2743 tx_fs_rate = 0x01;
2744 rx_fs_rate = 0x20;
2745 break;
2746 case 32000:
2747 tx_fs_rate = 0x02;
2748 rx_fs_rate = 0x40;
2749 break;
2750 case 48000:
2751 tx_fs_rate = 0x03;
2752 rx_fs_rate = 0x60;
2753 break;
2754 default:
2755 pr_err("%s: Invalid sampling rate %d\n", __func__,
2756 params_rate(params));
2757 return -EINVAL;
2758 }
2759
2760
2761 /**
2762 * If current dai is a tx dai, set sample rate to
2763 * all the txfe paths that are currently not active
2764 */
2765 if (dai->id == TABLA_TX_DAI_ID) {
2766
2767 tx_state = snd_soc_read(codec,
2768 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
2769
2770 for (path = 1, shift = 0;
2771 path <= NUM_DECIMATORS; path++, shift++) {
2772
2773 if (path == BITS_PER_REG + 1) {
2774 shift = 0;
2775 tx_state = snd_soc_read(codec,
2776 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
2777 }
2778
2779 if (!(tx_state & (1 << shift))) {
2780 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
2781 + (BITS_PER_REG*(path-1));
2782 snd_soc_update_bits(codec, tx_fs_reg,
2783 0x03, tx_fs_rate);
2784 }
2785 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302786 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2787 switch (params_format(params)) {
2788 case SNDRV_PCM_FORMAT_S16_LE:
2789 snd_soc_update_bits(codec,
2790 TABLA_A_CDC_CLK_TX_I2S_CTL,
2791 0x20, 0x20);
2792 break;
2793 case SNDRV_PCM_FORMAT_S32_LE:
2794 snd_soc_update_bits(codec,
2795 TABLA_A_CDC_CLK_TX_I2S_CTL,
2796 0x20, 0x00);
2797 break;
2798 default:
2799 pr_err("invalid format\n");
2800 break;
2801 }
2802 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
2803 0x03, tx_fs_rate);
2804 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002805 }
2806
2807 /**
2808 * TODO: Need to handle case where same RX chain takes 2 or more inputs
2809 * with varying sample rates
2810 */
2811
2812 /**
2813 * If current dai is a rx dai, set sample rate to
2814 * all the rx paths that are currently not active
2815 */
2816 if (dai->id == TABLA_RX_DAI_ID) {
2817
2818 rx_state = snd_soc_read(codec,
2819 TABLA_A_CDC_CLK_RX_B1_CTL);
2820
2821 for (path = 1, shift = 0;
2822 path <= NUM_INTERPOLATORS; path++, shift++) {
2823
2824 if (!(rx_state & (1 << shift))) {
2825 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
2826 + (BITS_PER_REG*(path-1));
2827 snd_soc_update_bits(codec, rx_fs_reg,
2828 0xE0, rx_fs_rate);
2829 }
2830 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302831 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2832 switch (params_format(params)) {
2833 case SNDRV_PCM_FORMAT_S16_LE:
2834 snd_soc_update_bits(codec,
2835 TABLA_A_CDC_CLK_RX_I2S_CTL,
2836 0x20, 0x20);
2837 break;
2838 case SNDRV_PCM_FORMAT_S32_LE:
2839 snd_soc_update_bits(codec,
2840 TABLA_A_CDC_CLK_RX_I2S_CTL,
2841 0x20, 0x00);
2842 break;
2843 default:
2844 pr_err("invalid format\n");
2845 break;
2846 }
2847 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
2848 0x03, (rx_fs_rate >> 0x05));
2849 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002850 }
2851
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002852 return 0;
2853}
2854
2855static struct snd_soc_dai_ops tabla_dai_ops = {
2856 .startup = tabla_startup,
2857 .shutdown = tabla_shutdown,
2858 .hw_params = tabla_hw_params,
2859 .set_sysclk = tabla_set_dai_sysclk,
2860 .set_fmt = tabla_set_dai_fmt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002861};
2862
2863static struct snd_soc_dai_driver tabla_dai[] = {
2864 {
2865 .name = "tabla_rx1",
2866 .id = 1,
2867 .playback = {
2868 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002869 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002870 .formats = TABLA_FORMATS,
2871 .rate_max = 48000,
2872 .rate_min = 8000,
2873 .channels_min = 1,
2874 .channels_max = 2,
2875 },
2876 .ops = &tabla_dai_ops,
2877 },
2878 {
2879 .name = "tabla_tx1",
2880 .id = 2,
2881 .capture = {
2882 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002883 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002884 .formats = TABLA_FORMATS,
2885 .rate_max = 48000,
2886 .rate_min = 8000,
2887 .channels_min = 1,
2888 .channels_max = 2,
2889 },
2890 .ops = &tabla_dai_ops,
2891 },
2892};
Santosh Mardie15e2302011-11-15 10:39:23 +05302893
2894static struct snd_soc_dai_driver tabla_i2s_dai[] = {
2895 {
2896 .name = "tabla_i2s_rx1",
2897 .id = 1,
2898 .playback = {
2899 .stream_name = "AIF1 Playback",
2900 .rates = WCD9310_RATES,
2901 .formats = TABLA_FORMATS,
2902 .rate_max = 48000,
2903 .rate_min = 8000,
2904 .channels_min = 1,
2905 .channels_max = 4,
2906 },
2907 .ops = &tabla_dai_ops,
2908 },
2909 {
2910 .name = "tabla_i2s_tx1",
2911 .id = 2,
2912 .capture = {
2913 .stream_name = "AIF1 Capture",
2914 .rates = WCD9310_RATES,
2915 .formats = TABLA_FORMATS,
2916 .rate_max = 48000,
2917 .rate_min = 8000,
2918 .channels_min = 1,
2919 .channels_max = 4,
2920 },
2921 .ops = &tabla_dai_ops,
2922 },
2923};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002924static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07002925{
2926 u8 bias_msb, bias_lsb;
2927 short bias_value;
2928
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002929 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
2930 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
2931 bias_value = (bias_msb << 8) | bias_lsb;
2932 return bias_value;
2933}
2934
2935static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
2936{
2937 u8 bias_msb, bias_lsb;
2938 short bias_value;
2939
2940 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
2941 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
2942 bias_value = (bias_msb << 8) | bias_lsb;
2943 return bias_value;
2944}
2945
2946static short tabla_codec_measure_micbias_voltage(struct snd_soc_codec *codec,
2947 int dce)
2948{
2949 short bias_value;
2950
Bradley Rubincb1e2732011-06-23 16:49:20 -07002951 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002952 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2953 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
2954 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2955 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
2956 usleep_range(60000, 60000);
2957 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002958 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002959 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002960 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
2961 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002962 usleep_range(5000, 5000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002963 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002964 usleep_range(50, 50);
2965 bias_value = tabla_codec_read_sta_result(codec);
2966 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
2967 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002968 }
2969
Bradley Rubincb1e2732011-06-23 16:49:20 -07002970 pr_debug("read microphone bias value %x\n", bias_value);
2971 return bias_value;
2972}
2973
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07002974static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002975{
2976 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2977 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07002978 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002979 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002980
2981 if (!calibration) {
2982 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07002983 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002984 }
2985
2986 tabla->mbhc_polling_active = true;
2987
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002988 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002989 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002990 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002991 tabla_codec_enable_clock_block(codec, 1);
2992 }
2993
2994 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
2995
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002996 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
2997
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002998 /* Make sure CFILT is in fast mode, save current mode */
2999 cfilt_mode = snd_soc_read(codec,
3000 tabla->mbhc_bias_regs.cfilt_ctl);
3001 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
3002 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07003003
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003004 snd_soc_update_bits(codec,
3005 tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003006
3007 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003008 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003009
3010 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
3011 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
3012 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
3013
3014 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003015 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3016 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003017
Bradley Rubincb1e2732011-06-23 16:49:20 -07003018 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003019 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3020
Bradley Rubincb1e2732011-06-23 16:49:20 -07003021 tabla_codec_calibrate_hs_polling(codec);
3022
3023 bias_value = tabla_codec_measure_micbias_voltage(codec, 0);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003024 snd_soc_update_bits(codec,
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003025 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003026 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003027
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003028 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003029}
3030
3031static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
3032 int insertion)
3033{
3034 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3035 struct tabla_mbhc_calibration *calibration = tabla->calibration;
3036 int central_bias_enabled = 0;
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003037 u8 wg_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003038
3039 if (!calibration) {
3040 pr_err("Error, no tabla calibration\n");
3041 return -EINVAL;
3042 }
3043
3044 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
3045
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003046 if (insertion) {
3047 /* Make sure mic bias and Mic line schmitt trigger
3048 * are turned OFF
3049 */
3050 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
3051 0x81, 0x01);
3052 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3053 0x90, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003054 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
3055 wg_time += 1;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003056
3057 /* Enable HPH Schmitt Trigger */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003058 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003059 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
3060 calibration->hph_current << 2);
3061
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003062 /* Turn off HPH PAs and DAC's during insertion detection to
3063 * avoid false insertion interrupts
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003064 */
3065 if (tabla->mbhc_micbias_switched)
3066 tabla_codec_switch_micbias(codec, 0);
3067 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003068 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
3069 0xC0, 0x00);
3070 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
3071 0xC0, 0x00);
3072 usleep_range(wg_time * 1000, wg_time * 1000);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003073
3074 /* setup for insetion detection */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003075 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003076 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003077 } else {
3078 /* Make sure the HPH schmitt trigger is OFF */
3079 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3080
3081 /* enable the mic line schmitt trigger */
3082 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
3083 calibration->mic_current << 5);
3084 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3085 0x80, 0x80);
3086 usleep_range(calibration->mic_pid, calibration->mic_pid);
3087 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3088 0x10, 0x10);
3089
3090 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003091 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003092 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003093
3094 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
3095 if (!(tabla->clock_active)) {
3096 tabla_codec_enable_config_mode(codec, 1);
3097 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003098 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003099 usleep_range(calibration->shutdown_plug_removal,
3100 calibration->shutdown_plug_removal);
3101 tabla_codec_enable_config_mode(codec, 0);
3102 } else
3103 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003104 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003105 }
3106
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003107 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108
3109 /* If central bandgap disabled */
3110 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
3111 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
3112 usleep_range(calibration->bg_fast_settle,
3113 calibration->bg_fast_settle);
3114 central_bias_enabled = 1;
3115 }
3116
3117 /* If LDO_H disabled */
3118 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
3119 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
3120 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
3121 usleep_range(calibration->tldoh, calibration->tldoh);
3122 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
3123
3124 if (central_bias_enabled)
3125 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
3126 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003127
3128 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, calibration->bias);
3129
3130 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3131 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3132 return 0;
3133}
3134
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003135static void tabla_lock_sleep(struct tabla_priv *tabla)
3136{
3137 int ret;
3138 while (!(ret = wait_event_timeout(tabla->pm_wq,
3139 atomic_inc_not_zero(&tabla->pm_cnt),
3140 2 * HZ))) {
3141 pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
3142 __func__, ret, atomic_read(&tabla->pm_cnt));
3143 WARN_ON_ONCE(1);
3144 }
3145}
3146
3147static void tabla_unlock_sleep(struct tabla_priv *tabla)
3148{
3149 atomic_dec(&tabla->pm_cnt);
3150 wake_up(&tabla->pm_wq);
3151}
3152
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003153static void btn0_lpress_fn(struct work_struct *work)
3154{
3155 struct delayed_work *delayed_work;
3156 struct tabla_priv *tabla;
3157
3158 pr_debug("%s:\n", __func__);
3159
3160 delayed_work = to_delayed_work(work);
3161 tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
3162
3163 if (tabla) {
3164 if (tabla->button_jack) {
3165 pr_debug("%s: Reporting long button press event\n",
3166 __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003167 tabla_snd_soc_jack_report(tabla, tabla->button_jack,
3168 SND_JACK_BTN_0,
3169 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003170 }
3171 } else {
3172 pr_err("%s: Bad tabla private data\n", __func__);
3173 }
3174
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003175 tabla_unlock_sleep(tabla);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003176}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003177
Bradley Rubincb1e2732011-06-23 16:49:20 -07003178int tabla_hs_detect(struct snd_soc_codec *codec,
3179 struct snd_soc_jack *headset_jack, struct snd_soc_jack *button_jack,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003180 struct tabla_mbhc_calibration *calibration)
3181{
3182 struct tabla_priv *tabla;
Patrick Lai49efeac2011-11-03 11:01:12 -07003183 int rc;
3184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003185 if (!codec || !calibration) {
3186 pr_err("Error: no codec or calibration\n");
3187 return -EINVAL;
3188 }
3189 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003190 tabla->headset_jack = headset_jack;
3191 tabla->button_jack = button_jack;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003192 tabla->calibration = calibration;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003193 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003194
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003195 /* Put CFILT in fast mode by default */
3196 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
3197 0x40, TABLA_CFILT_FAST_MODE);
3198
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003199 INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
Patrick Lai49efeac2011-11-03 11:01:12 -07003200 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
3201 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
3202 rc = tabla_codec_enable_hs_detect(codec, 1);
3203
3204 if (!IS_ERR_VALUE(rc)) {
3205 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3206 0x10);
3207 tabla_enable_irq(codec->control_data,
3208 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3209 tabla_enable_irq(codec->control_data,
3210 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3211 }
3212
3213 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214}
3215EXPORT_SYMBOL_GPL(tabla_hs_detect);
3216
Bradley Rubincb1e2732011-06-23 16:49:20 -07003217static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218{
3219 struct tabla_priv *priv = data;
3220 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003221 short bias_value;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003222
3223 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3224 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003225 tabla_lock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003226
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003227 bias_value = tabla_codec_read_dce_result(codec);
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003228 pr_debug("%s: button press interrupt, bias value(DCE Read)=%d\n",
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003229 __func__, bias_value);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003230
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003231 bias_value = tabla_codec_read_sta_result(codec);
3232 pr_debug("%s: button press interrupt, bias value(STA Read)=%d\n",
3233 __func__, bias_value);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003234 /*
3235 * TODO: If button pressed is not button 0,
3236 * report the button press event immediately.
3237 */
3238 priv->buttons_pressed |= SND_JACK_BTN_0;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003239
Bradley Rubin688c66a2011-08-16 12:25:13 -07003240 msleep(100);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003241
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003242 if (schedule_delayed_work(&priv->btn0_dwork,
3243 msecs_to_jiffies(400)) == 0) {
3244 WARN(1, "Button pressed twice without release event\n");
3245 tabla_unlock_sleep(priv);
3246 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003247
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003248 return IRQ_HANDLED;
3249}
3250
Bradley Rubincb1e2732011-06-23 16:49:20 -07003251static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003252{
3253 struct tabla_priv *priv = data;
3254 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003255 int ret, mic_voltage;
3256
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003257 pr_debug("%s\n", __func__);
3258 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003259 tabla_lock_sleep(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003260
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003261 mic_voltage = tabla_codec_read_dce_result(codec);
3262 pr_debug("%s: Microphone Voltage on release(DCE Read) = %d\n",
3263 __func__, mic_voltage);
3264
Bradley Rubincb1e2732011-06-23 16:49:20 -07003265 if (priv->buttons_pressed & SND_JACK_BTN_0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003266 ret = cancel_delayed_work(&priv->btn0_dwork);
3267
3268 if (ret == 0) {
3269
3270 pr_debug("%s: Reporting long button release event\n",
3271 __func__);
3272 if (priv->button_jack) {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003273 tabla_snd_soc_jack_report(priv,
3274 priv->button_jack, 0,
3275 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003276 }
3277
3278 } else {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003279 /* if scheduled btn0_dwork is canceled from here,
3280 * we have to unlock from here instead btn0_work */
3281 tabla_unlock_sleep(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003282 mic_voltage =
3283 tabla_codec_measure_micbias_voltage(codec, 0);
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003284 pr_debug("%s: Mic Voltage on release(new STA) = %d\n",
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003285 __func__, mic_voltage);
3286
3287 if (mic_voltage < -2000 || mic_voltage > -670) {
3288 pr_debug("%s: Fake buttton press interrupt\n",
3289 __func__);
3290 } else {
3291
3292 if (priv->button_jack) {
3293 pr_debug("%s:reporting short button press and release\n",
3294 __func__);
3295
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003296 tabla_snd_soc_jack_report(priv,
3297 priv->button_jack,
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003298 SND_JACK_BTN_0, SND_JACK_BTN_0);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003299 tabla_snd_soc_jack_report(priv,
3300 priv->button_jack,
3301 0, SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003302 }
3303 }
3304 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003305
Bradley Rubincb1e2732011-06-23 16:49:20 -07003306 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003307 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003308
Bradley Rubin688c66a2011-08-16 12:25:13 -07003309 tabla_codec_start_hs_polling(codec);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003310 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003311 return IRQ_HANDLED;
3312}
3313
Bradley Rubincb1e2732011-06-23 16:49:20 -07003314static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
3315{
3316 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3317 struct tabla_mbhc_calibration *calibration = tabla->calibration;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003318
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003319 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003320 tabla_codec_enable_config_mode(codec, 1);
3321
3322 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3323 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003324
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003325 snd_soc_update_bits(codec,
3326 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003327 usleep_range(calibration->shutdown_plug_removal,
3328 calibration->shutdown_plug_removal);
3329
3330 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003331 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003332 tabla_codec_enable_config_mode(codec, 0);
3333
3334 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
3335}
3336
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003337static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
3338{
3339 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003340
3341 tabla_codec_shutdown_hs_removal_detect(codec);
3342
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003343 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003344 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
3345 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
3346 tabla_codec_enable_clock_block(codec, 0);
3347 }
3348
3349 tabla->mbhc_polling_active = false;
3350}
3351
Patrick Lai49efeac2011-11-03 11:01:12 -07003352static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
3353{
3354 struct tabla_priv *tabla = data;
3355 struct snd_soc_codec *codec;
3356
3357 pr_info("%s: received HPHL OCP irq\n", __func__);
3358
3359 if (tabla) {
3360 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08003361 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
3362 pr_info("%s: retry\n", __func__);
3363 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3364 0x00);
3365 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3366 0x10);
3367 } else {
3368 tabla_disable_irq(codec->control_data,
3369 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3370 tabla->hphlocp_cnt = 0;
3371 tabla->hph_status |= SND_JACK_OC_HPHL;
3372 if (tabla->headset_jack)
3373 tabla_snd_soc_jack_report(tabla,
3374 tabla->headset_jack,
3375 tabla->hph_status,
3376 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07003377 }
3378 } else {
3379 pr_err("%s: Bad tabla private data\n", __func__);
3380 }
3381
3382 return IRQ_HANDLED;
3383}
3384
3385static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
3386{
3387 struct tabla_priv *tabla = data;
3388 struct snd_soc_codec *codec;
3389
3390 pr_info("%s: received HPHR OCP irq\n", __func__);
3391
3392 if (tabla) {
3393 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08003394 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
3395 pr_info("%s: retry\n", __func__);
3396 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3397 0x00);
3398 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3399 0x10);
3400 } else {
3401 tabla_disable_irq(codec->control_data,
3402 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3403 tabla->hphrocp_cnt = 0;
3404 tabla->hph_status |= SND_JACK_OC_HPHR;
3405 if (tabla->headset_jack)
3406 tabla_snd_soc_jack_report(tabla,
3407 tabla->headset_jack,
3408 tabla->hph_status,
3409 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07003410 }
3411 } else {
3412 pr_err("%s: Bad tabla private data\n", __func__);
3413 }
3414
3415 return IRQ_HANDLED;
3416}
3417
Joonwoo Parka9444452011-12-08 18:48:27 -08003418static void tabla_sync_hph_state(struct tabla_priv *tabla)
3419{
3420 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
3421 &tabla->hph_pa_dac_state)) {
3422 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
3423 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
3424 1 << 4);
3425 }
3426 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
3427 &tabla->hph_pa_dac_state)) {
3428 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
3429 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
3430 1 << 5);
3431 }
3432
3433 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
3434 &tabla->hph_pa_dac_state)) {
3435 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
3436 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
3437 0xC0, 0xC0);
3438 }
3439 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
3440 &tabla->hph_pa_dac_state)) {
3441 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
3442 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
3443 0xC0, 0xC0);
3444 }
3445}
3446
Bradley Rubincb1e2732011-06-23 16:49:20 -07003447static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
3448{
3449 struct tabla_priv *priv = data;
3450 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin355611a2011-08-24 14:01:18 -07003451 int ldo_h_on, micb_cfilt_on;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003452 short mic_voltage;
3453 short threshold_no_mic = 0xF7F6;
3454 short threshold_fake_insert = 0xFD30;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003455 u8 is_removal;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003456
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003457 pr_debug("%s\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003458 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003459 tabla_lock_sleep(priv);
3460
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003461 is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
3462 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
3463
3464 /* Turn off both HPH and MIC line schmitt triggers */
3465 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
3466 0x90, 0x00);
3467 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003468
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003469 if (priv->fake_insert_context) {
3470 pr_debug("%s: fake context interrupt, reset insertion\n",
3471 __func__);
3472 priv->fake_insert_context = false;
3473 tabla_codec_shutdown_hs_polling(codec);
3474 tabla_codec_enable_hs_detect(codec, 1);
3475 return IRQ_HANDLED;
3476 }
3477
3478
Bradley Rubin355611a2011-08-24 14:01:18 -07003479 ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003480 micb_cfilt_on = snd_soc_read(codec,
3481 priv->mbhc_bias_regs.cfilt_ctl) & 0x80;
Bradley Rubin355611a2011-08-24 14:01:18 -07003482
3483 if (!ldo_h_on)
3484 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
3485 if (!micb_cfilt_on)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003486 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
3487 0x80, 0x80);
Bradley Rubin355611a2011-08-24 14:01:18 -07003488
Bradley Rubincb1e2732011-06-23 16:49:20 -07003489 usleep_range(priv->calibration->setup_plug_removal_delay,
3490 priv->calibration->setup_plug_removal_delay);
3491
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003492 if (!ldo_h_on)
3493 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
3494 if (!micb_cfilt_on)
3495 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
3496 0x80, 0x0);
3497
3498 if (is_removal) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003499 /*
3500 * If headphone is removed while playback is in progress,
3501 * it is possible that micbias will be switched to VDDIO.
3502 */
3503 if (priv->mbhc_micbias_switched)
3504 tabla_codec_switch_micbias(codec, 0);
Patrick Lai72aa4da2011-12-08 12:38:18 -08003505 priv->hph_status &= ~SND_JACK_HEADPHONE;
Joonwoo Parka9444452011-12-08 18:48:27 -08003506
3507 /* If headphone PA is on, check if userspace receives
3508 * removal event to sync-up PA's state */
3509 if (tabla_is_hph_pa_on(codec)) {
3510 set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
3511 set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
3512 }
3513
3514 if (tabla_is_hph_dac_on(codec, 1))
3515 set_bit(TABLA_HPHL_DAC_OFF_ACK,
3516 &priv->hph_pa_dac_state);
3517 if (tabla_is_hph_dac_on(codec, 0))
3518 set_bit(TABLA_HPHR_DAC_OFF_ACK,
3519 &priv->hph_pa_dac_state);
3520
Bradley Rubincb1e2732011-06-23 16:49:20 -07003521 if (priv->headset_jack) {
3522 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003523 tabla_snd_soc_jack_report(priv, priv->headset_jack,
3524 priv->hph_status,
3525 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003526 }
3527 tabla_codec_shutdown_hs_removal_detect(codec);
3528 tabla_codec_enable_hs_detect(codec, 1);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003529 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003530 return IRQ_HANDLED;
3531 }
3532
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003533 mic_voltage = tabla_codec_setup_hs_polling(codec);
Bradley Rubin355611a2011-08-24 14:01:18 -07003534
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003535 if (mic_voltage > threshold_fake_insert) {
3536 pr_debug("%s: Fake insertion interrupt, mic_voltage = %x\n",
3537 __func__, mic_voltage);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003538
3539 /* Disable HPH trigger and enable MIC line trigger */
3540 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3541
3542 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
3543 priv->calibration->mic_current << 5);
3544 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
3545 0x80, 0x80);
3546 usleep_range(priv->calibration->mic_pid,
3547 priv->calibration->mic_pid);
3548 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
3549 0x10, 0x10);
3550
3551 /* Setup for insertion detection */
3552 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
3553 priv->fake_insert_context = true;
3554 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3555 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3556
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003557 } else if (mic_voltage < threshold_no_mic) {
3558 pr_debug("%s: Headphone Detected, mic_voltage = %x\n",
3559 __func__, mic_voltage);
Patrick Lai49efeac2011-11-03 11:01:12 -07003560 priv->hph_status |= SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003561 if (priv->headset_jack) {
3562 pr_debug("%s: Reporting insertion %d\n", __func__,
3563 SND_JACK_HEADPHONE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003564 tabla_snd_soc_jack_report(priv, priv->headset_jack,
3565 priv->hph_status,
3566 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003567 }
3568 tabla_codec_shutdown_hs_polling(codec);
3569 tabla_codec_enable_hs_detect(codec, 0);
Joonwoo Parka9444452011-12-08 18:48:27 -08003570 tabla_sync_hph_state(priv);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003571 } else {
3572 pr_debug("%s: Headset detected, mic_voltage = %x\n",
3573 __func__, mic_voltage);
Patrick Lai49efeac2011-11-03 11:01:12 -07003574 priv->hph_status |= SND_JACK_HEADSET;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003575 if (priv->headset_jack) {
3576 pr_debug("%s: Reporting insertion %d\n", __func__,
3577 SND_JACK_HEADSET);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003578 tabla_snd_soc_jack_report(priv, priv->headset_jack,
3579 priv->hph_status,
3580 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003581 }
3582 tabla_codec_start_hs_polling(codec);
Joonwoo Parka9444452011-12-08 18:48:27 -08003583 tabla_sync_hph_state(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003584 }
3585
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003586 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003587 return IRQ_HANDLED;
3588}
3589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003590static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
3591{
3592 struct tabla_priv *priv = data;
3593 struct snd_soc_codec *codec = priv->codec;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003594 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003595
3596 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3597 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003598 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003599 tabla_lock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600
3601 usleep_range(priv->calibration->shutdown_plug_removal,
3602 priv->calibration->shutdown_plug_removal);
3603
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003604 bias_value = tabla_codec_measure_micbias_voltage(codec, 1);
3605 pr_debug("removal interrupt, bias value is %d\n", bias_value);
3606
3607 if (bias_value < -90) {
3608 pr_debug("False alarm, headset not actually removed\n");
3609 tabla_codec_start_hs_polling(codec);
3610 } else {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003611 /*
3612 * If this removal is not false, first check the micbias
3613 * switch status and switch it to LDOH if it is already
3614 * switched to VDDIO.
3615 */
3616 if (priv->mbhc_micbias_switched)
3617 tabla_codec_switch_micbias(codec, 0);
Patrick Lai49efeac2011-11-03 11:01:12 -07003618 priv->hph_status &= ~SND_JACK_HEADSET;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003619 if (priv->headset_jack) {
3620 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003621 tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
3622 TABLA_JACK_MASK);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003623 }
3624 tabla_codec_shutdown_hs_polling(codec);
3625
3626 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003627 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003628
3629 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003630 return IRQ_HANDLED;
3631}
3632
3633static unsigned long slimbus_value;
3634
3635static irqreturn_t tabla_slimbus_irq(int irq, void *data)
3636{
3637 struct tabla_priv *priv = data;
3638 struct snd_soc_codec *codec = priv->codec;
3639 int i, j;
3640 u8 val;
3641
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003642 tabla_lock_sleep(priv);
3643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003644 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
3645 slimbus_value = tabla_interface_reg_read(codec->control_data,
3646 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
3647 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
3648 val = tabla_interface_reg_read(codec->control_data,
3649 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
3650 if (val & 0x1)
3651 pr_err_ratelimited("overflow error on port %x,"
3652 " value %x\n", i*8 + j, val);
3653 if (val & 0x2)
3654 pr_err_ratelimited("underflow error on port %x,"
3655 " value %x\n", i*8 + j, val);
3656 }
3657 tabla_interface_reg_write(codec->control_data,
3658 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
3659 }
3660
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003661 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003662 return IRQ_HANDLED;
3663}
3664
Patrick Lai3043fba2011-08-01 14:15:57 -07003665
3666static int tabla_handle_pdata(struct tabla_priv *tabla)
3667{
3668 struct snd_soc_codec *codec = tabla->codec;
3669 struct tabla_pdata *pdata = tabla->pdata;
3670 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05303671 u8 leg_mode = pdata->amic_settings.legacy_mode;
3672 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
3673 u8 txfe_buff = pdata->amic_settings.txfe_buff;
3674 u8 flag = pdata->amic_settings.use_pdata;
3675 u8 i = 0, j = 0;
3676 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07003677
3678 if (!pdata) {
3679 rc = -ENODEV;
3680 goto done;
3681 }
3682
3683 /* Make sure settings are correct */
3684 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
3685 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
3686 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
3687 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
3688 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
3689 rc = -EINVAL;
3690 goto done;
3691 }
3692
3693 /* figure out k value */
3694 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
3695 pdata->micbias.cfilt1_mv);
3696 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
3697 pdata->micbias.cfilt2_mv);
3698 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
3699 pdata->micbias.cfilt3_mv);
3700
3701 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
3702 rc = -EINVAL;
3703 goto done;
3704 }
3705
3706 /* Set voltage level and always use LDO */
3707 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
3708 (pdata->micbias.ldoh_v << 2));
3709
3710 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
3711 (k1 << 2));
3712 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
3713 (k2 << 2));
3714 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
3715 (k3 << 2));
3716
3717 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
3718 (pdata->micbias.bias1_cfilt_sel << 5));
3719 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
3720 (pdata->micbias.bias2_cfilt_sel << 5));
3721 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
3722 (pdata->micbias.bias3_cfilt_sel << 5));
3723 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
3724 (pdata->micbias.bias4_cfilt_sel << 5));
3725
Santosh Mardi22920282011-10-26 02:38:40 +05303726 for (i = 0; i < 6; j++, i += 2) {
3727 if (flag & (0x01 << i)) {
3728 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
3729 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
3730 val_txfe = val_txfe |
3731 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
3732 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
3733 0x10, value);
3734 snd_soc_update_bits(codec,
3735 TABLA_A_TX_1_2_TEST_EN + j * 10,
3736 0x30, val_txfe);
3737 }
3738 if (flag & (0x01 << (i + 1))) {
3739 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
3740 val_txfe = (txfe_bypass &
3741 (0x01 << (i + 1))) ? 0x02 : 0x00;
3742 val_txfe |= (txfe_buff &
3743 (0x01 << (i + 1))) ? 0x01 : 0x00;
3744 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
3745 0x01, value);
3746 snd_soc_update_bits(codec,
3747 TABLA_A_TX_1_2_TEST_EN + j * 10,
3748 0x03, val_txfe);
3749 }
3750 }
3751 if (flag & 0x40) {
3752 value = (leg_mode & 0x40) ? 0x10 : 0x00;
3753 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
3754 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
3755 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
3756 0x13, value);
3757 }
Patrick Lai49efeac2011-11-03 11:01:12 -07003758
3759 if (pdata->ocp.use_pdata) {
3760 /* not defined in CODEC specification */
3761 if (pdata->ocp.hph_ocp_limit == 1 ||
3762 pdata->ocp.hph_ocp_limit == 5) {
3763 rc = -EINVAL;
3764 goto done;
3765 }
3766 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
3767 0x0F, pdata->ocp.num_attempts);
3768 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
3769 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
3770 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
3771 0xE0, (pdata->ocp.hph_ocp_limit << 5));
3772 }
Patrick Lai3043fba2011-08-01 14:15:57 -07003773done:
3774 return rc;
3775}
3776
Kiran Kandi1f6fd722011-08-11 10:36:11 -07003777static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
3778
3779 /* Tabla 1.1 MICBIAS changes */
3780 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
3781 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
3782 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
3783 TABLA_REG_VAL(TABLA_A_MICB_4_INT_RBIAS, 0x24),
3784
3785 /* Tabla 1.1 HPH changes */
3786 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
3787 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
3788
3789 /* Tabla 1.1 EAR PA changes */
3790 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
3791 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
3792 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
3793
3794 /* Tabla 1.1 Lineout_5 Changes */
3795 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
3796
3797 /* Tabla 1.1 RX Changes */
3798 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
3799 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
3800 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
3801 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
3802 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
3803 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
3804 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
3805
3806 /* Tabla 1.1 RX1 and RX2 Changes */
3807 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
3808 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
3809
3810 /* Tabla 1.1 RX3 to RX7 Changes */
3811 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
3812 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
3813 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
3814 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
3815 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
3816
3817 /* Tabla 1.1 CLASSG Changes */
3818 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
3819};
3820
3821static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
3822
3823 /* Tabla 2.0 MICBIAS changes */
3824 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
3825};
3826
3827static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
3828{
3829 u32 i;
3830
3831 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
3832 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
3833 tabla_1_1_reg_defaults[i].val);
3834
3835 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
3836 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
3837 tabla_2_0_reg_defaults[i].val);
3838}
3839
3840static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08003841 /* Initialize current threshold to 350MA
3842 * number of wait and run cycles to 4096
3843 */
Patrick Lai49efeac2011-11-03 11:01:12 -07003844 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08003845 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07003846
Santosh Mardi32171012011-10-28 23:32:06 +05303847 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
3848
Kiran Kandi1f6fd722011-08-11 10:36:11 -07003849 /* Initialize gain registers to use register gain */
3850 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
3851 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
3852 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
3853 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
3854 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
3855 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
3856
3857 /* Initialize mic biases to differential mode */
3858 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
3859 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
3860 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
3861 {TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24},
3862
3863 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
3864
3865 /* Use 16 bit sample size for TX1 to TX6 */
3866 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
3867 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
3868 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
3869 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
3870 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
3871 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
3872
3873 /* Use 16 bit sample size for TX7 to TX10 */
3874 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
3875 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
3876 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
3877 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
3878
3879 /* Use 16 bit sample size for RX */
3880 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
3881 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
3882
3883 /*enable HPF filter for TX paths */
3884 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
3885 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
3886 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
3887 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
3888 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
3889 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
3890 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
3891 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
3892 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
3893 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
3894};
3895
3896static void tabla_codec_init_reg(struct snd_soc_codec *codec)
3897{
3898 u32 i;
3899
3900 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
3901 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
3902 tabla_codec_reg_init_val[i].mask,
3903 tabla_codec_reg_init_val[i].val);
3904}
3905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003906static int tabla_codec_probe(struct snd_soc_codec *codec)
3907{
3908 struct tabla *control;
3909 struct tabla_priv *tabla;
3910 struct snd_soc_dapm_context *dapm = &codec->dapm;
3911 int ret = 0;
3912 int i;
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003913 u8 tabla_version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003914
3915 codec->control_data = dev_get_drvdata(codec->dev->parent);
3916 control = codec->control_data;
3917
3918 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
3919 if (!tabla) {
3920 dev_err(codec->dev, "Failed to allocate private data\n");
3921 return -ENOMEM;
3922 }
3923
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003924 /* Make sure mbhc micbias register addresses are zeroed out */
3925 memset(&tabla->mbhc_bias_regs, 0,
3926 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003927 tabla->cfilt_k_value = 0;
3928 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003929
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003930 snd_soc_codec_set_drvdata(codec, tabla);
3931
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003932 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003933 tabla->bandgap_type = TABLA_BANDGAP_OFF;
3934 tabla->clock_active = false;
3935 tabla->config_mode_active = false;
3936 tabla->mbhc_polling_active = false;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003937 tabla->fake_insert_context = false;
Bradley Rubincb3950a2011-08-18 13:07:26 -07003938 tabla->no_mic_headset_override = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003939 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07003940 tabla->pdata = dev_get_platdata(codec->dev->parent);
Santosh Mardie15e2302011-11-15 10:39:23 +05303941 tabla->intf_type = tabla_get_intf_type();
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003942 atomic_set(&tabla->pm_cnt, 1);
3943 init_waitqueue_head(&tabla->pm_wq);
Patrick Lai3043fba2011-08-01 14:15:57 -07003944
Santosh Mardi22920282011-10-26 02:38:40 +05303945 tabla_update_reg_defaults(codec);
3946 tabla_codec_init_reg(codec);
Patrick Lai3043fba2011-08-01 14:15:57 -07003947
Santosh Mardi22920282011-10-26 02:38:40 +05303948 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07003949 if (IS_ERR_VALUE(ret)) {
3950 pr_err("%s: bad pdata\n", __func__);
3951 goto err_pdata;
3952 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003953
3954 /* TODO only enable bandgap when necessary in order to save power */
3955 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
3956 tabla_codec_enable_clock_block(codec, 0);
3957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003958 snd_soc_add_controls(codec, tabla_snd_controls,
3959 ARRAY_SIZE(tabla_snd_controls));
3960 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
3961 ARRAY_SIZE(tabla_dapm_widgets));
Santosh Mardie15e2302011-11-15 10:39:23 +05303962 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
3963 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
3964 ARRAY_SIZE(tabla_dapm_i2s_widgets));
3965 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
3966 ARRAY_SIZE(audio_i2s_map));
3967 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003968 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003969
3970 tabla_version = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
3971 pr_info("%s : Tabla version reg 0x%2x\n", __func__, (u32)tabla_version);
3972
3973 tabla_version &= 0x1F;
3974 pr_info("%s : Tabla version %u\n", __func__, (u32)tabla_version);
3975
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003976 if ((tabla_version == TABLA_VERSION_1_0) ||
3977 (tabla_version == TABLA_VERSION_1_1)) {
3978 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003979 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
3980
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003981 } else if (tabla_version == TABLA_VERSION_2_0) {
3982 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
3983 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
3984 } else {
3985 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
3986 __func__, (u32)tabla_version);
3987 goto err_pdata;
3988 }
3989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003990 snd_soc_dapm_sync(dapm);
3991
3992 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
3993 tabla_hs_insert_irq, "Headset insert detect", tabla);
3994 if (ret) {
3995 pr_err("%s: Failed to request irq %d\n", __func__,
3996 TABLA_IRQ_MBHC_INSERTION);
3997 goto err_insert_irq;
3998 }
3999 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4000
4001 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
4002 tabla_hs_remove_irq, "Headset remove detect", tabla);
4003 if (ret) {
4004 pr_err("%s: Failed to request irq %d\n", __func__,
4005 TABLA_IRQ_MBHC_REMOVAL);
4006 goto err_remove_irq;
4007 }
4008 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4009
4010 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004011 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004012 if (ret) {
4013 pr_err("%s: Failed to request irq %d\n", __func__,
4014 TABLA_IRQ_MBHC_POTENTIAL);
4015 goto err_potential_irq;
4016 }
4017 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4018
Bradley Rubincb1e2732011-06-23 16:49:20 -07004019 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
4020 tabla_release_handler, "Button Release detect", tabla);
4021 if (ret) {
4022 pr_err("%s: Failed to request irq %d\n", __func__,
4023 TABLA_IRQ_MBHC_RELEASE);
4024 goto err_release_irq;
4025 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004026 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004027
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004028 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
4029 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
4030 if (ret) {
4031 pr_err("%s: Failed to request irq %d\n", __func__,
4032 TABLA_IRQ_SLIMBUS);
4033 goto err_slimbus_irq;
4034 }
4035
4036 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
4037 tabla_interface_reg_write(codec->control_data,
4038 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
4039
Patrick Lai49efeac2011-11-03 11:01:12 -07004040 ret = tabla_request_irq(codec->control_data,
4041 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
4042 "HPH_L OCP detect", tabla);
4043 if (ret) {
4044 pr_err("%s: Failed to request irq %d\n", __func__,
4045 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4046 goto err_hphl_ocp_irq;
4047 }
Patrick Lai92032be2011-12-19 14:14:25 -08004048 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004049
4050 ret = tabla_request_irq(codec->control_data,
4051 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
4052 "HPH_R OCP detect", tabla);
4053 if (ret) {
4054 pr_err("%s: Failed to request irq %d\n", __func__,
4055 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4056 goto err_hphr_ocp_irq;
4057 }
Patrick Lai92032be2011-12-19 14:14:25 -08004058 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004059
Bradley Rubincb3950a2011-08-18 13:07:26 -07004060#ifdef CONFIG_DEBUG_FS
4061 debug_tabla_priv = tabla;
4062#endif
4063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004064 return ret;
4065
Patrick Lai49efeac2011-11-03 11:01:12 -07004066err_hphr_ocp_irq:
4067 tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
4068err_hphl_ocp_irq:
4069 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004070err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07004071 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
4072err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4074err_potential_irq:
4075 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4076err_remove_irq:
4077 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4078err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07004079err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004080 kfree(tabla);
4081 return ret;
4082}
4083static int tabla_codec_remove(struct snd_soc_codec *codec)
4084{
4085 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4086 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004087 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004088 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4089 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4090 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4091 tabla_codec_disable_clock_block(codec);
4092 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
4093 kfree(tabla);
4094 return 0;
4095}
4096static struct snd_soc_codec_driver soc_codec_dev_tabla = {
4097 .probe = tabla_codec_probe,
4098 .remove = tabla_codec_remove,
4099 .read = tabla_read,
4100 .write = tabla_write,
4101
4102 .readable_register = tabla_readable,
4103 .volatile_register = tabla_volatile,
4104
4105 .reg_cache_size = TABLA_CACHE_SIZE,
4106 .reg_cache_default = tabla_reg_defaults,
4107 .reg_word_size = 1,
4108};
Bradley Rubincb3950a2011-08-18 13:07:26 -07004109
4110#ifdef CONFIG_DEBUG_FS
4111static struct dentry *debugfs_poke;
4112
4113static int codec_debug_open(struct inode *inode, struct file *file)
4114{
4115 file->private_data = inode->i_private;
4116 return 0;
4117}
4118
4119static ssize_t codec_debug_write(struct file *filp,
4120 const char __user *ubuf, size_t cnt, loff_t *ppos)
4121{
4122 char lbuf[32];
4123 char *buf;
4124 int rc;
4125
4126 if (cnt > sizeof(lbuf) - 1)
4127 return -EINVAL;
4128
4129 rc = copy_from_user(lbuf, ubuf, cnt);
4130 if (rc)
4131 return -EFAULT;
4132
4133 lbuf[cnt] = '\0';
4134 buf = (char *)lbuf;
4135 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
4136 ? false : true;
4137
4138 return rc;
4139}
4140
4141static const struct file_operations codec_debug_ops = {
4142 .open = codec_debug_open,
4143 .write = codec_debug_write,
4144};
4145#endif
4146
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004147#ifdef CONFIG_PM
4148static int tabla_suspend(struct device *dev)
4149{
4150 int ret = 0, cnt;
4151 struct platform_device *pdev = to_platform_device(dev);
4152 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4153
4154 cnt = atomic_read(&tabla->pm_cnt);
4155 if (cnt > 0) {
4156 if (wait_event_timeout(tabla->pm_wq,
4157 (atomic_cmpxchg(&tabla->pm_cnt, 1, 0)
4158 == 1), 5 * HZ)) {
4159 dev_dbg(dev, "system suspend pm_cnt %d\n",
4160 atomic_read(&tabla->pm_cnt));
4161 } else {
4162 dev_err(dev, "%s timed out pm_cnt = %d\n",
4163 __func__, atomic_read(&tabla->pm_cnt));
4164 WARN_ON_ONCE(1);
4165 ret = -EBUSY;
4166 }
4167 } else if (cnt == 0)
4168 dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
4169 atomic_read(&tabla->pm_cnt));
4170 else {
4171 WARN(1, "unexpected pm_cnt %d\n", cnt);
4172 ret = -EFAULT;
4173 }
4174
4175 return ret;
4176}
4177
4178static int tabla_resume(struct device *dev)
4179{
4180 int ret = 0, cnt;
4181 struct platform_device *pdev = to_platform_device(dev);
4182 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4183
4184 cnt = atomic_cmpxchg(&tabla->pm_cnt, 0, 1);
4185 if (cnt == 0) {
4186 dev_dbg(dev, "system resume, pm_cnt %d\n",
4187 atomic_read(&tabla->pm_cnt));
4188 wake_up_all(&tabla->pm_wq);
4189 } else if (cnt > 0)
4190 dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
4191 else {
4192 WARN(1, "unexpected pm_cnt %d\n", cnt);
4193 ret = -EFAULT;
4194 }
4195
4196 return ret;
4197}
4198
4199static const struct dev_pm_ops tabla_pm_ops = {
4200 .suspend = tabla_suspend,
4201 .resume = tabla_resume,
4202};
4203#endif
4204
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004205static int __devinit tabla_probe(struct platform_device *pdev)
4206{
Santosh Mardie15e2302011-11-15 10:39:23 +05304207 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004208#ifdef CONFIG_DEBUG_FS
4209 debugfs_poke = debugfs_create_file("TRRS",
4210 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
4211
4212#endif
Santosh Mardie15e2302011-11-15 10:39:23 +05304213 if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
4214 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4215 tabla_dai, ARRAY_SIZE(tabla_dai));
4216 else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
4217 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4218 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
4219 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004220}
4221static int __devexit tabla_remove(struct platform_device *pdev)
4222{
4223 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07004224
4225#ifdef CONFIG_DEBUG_FS
4226 debugfs_remove(debugfs_poke);
4227#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004228 return 0;
4229}
4230static struct platform_driver tabla_codec_driver = {
4231 .probe = tabla_probe,
4232 .remove = tabla_remove,
4233 .driver = {
4234 .name = "tabla_codec",
4235 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004236#ifdef CONFIG_PM
4237 .pm = &tabla_pm_ops,
4238#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004239 },
4240};
4241
4242static int __init tabla_codec_init(void)
4243{
4244 return platform_driver_register(&tabla_codec_driver);
4245}
4246
4247static void __exit tabla_codec_exit(void)
4248{
4249 platform_driver_unregister(&tabla_codec_driver);
4250}
4251
4252module_init(tabla_codec_init);
4253module_exit(tabla_codec_exit);
4254
4255MODULE_DESCRIPTION("Tabla codec driver");
4256MODULE_VERSION("1.0");
4257MODULE_LICENSE("GPL v2");