blob: 0370b17186118a29c2a64caa561e6ae5346ba8cf [file] [log] [blame]
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/init.h>
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
Joonwoo Park0976d012011-12-22 11:48:18 -080051#define TABLA_MCLK_RATE_12288KHZ 12288000
52#define TABLA_MCLK_RATE_9600KHZ 9600000
53
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070054static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
55static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
56static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
57
58enum tabla_bandgap_type {
59 TABLA_BANDGAP_OFF = 0,
60 TABLA_BANDGAP_AUDIO_MODE,
61 TABLA_BANDGAP_MBHC_MODE,
62};
63
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070064struct mbhc_micbias_regs {
65 u16 cfilt_val;
66 u16 cfilt_ctl;
67 u16 mbhc_reg;
68 u16 int_rbias;
69 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080070 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070071};
72
Ben Romberger1f045a72011-11-04 10:14:57 -070073/* Codec supports 2 IIR filters */
74enum {
75 IIR1 = 0,
76 IIR2,
77 IIR_MAX,
78};
79/* Codec supports 5 bands */
80enum {
81 BAND1 = 0,
82 BAND2,
83 BAND3,
84 BAND4,
85 BAND5,
86 BAND_MAX,
87};
88
Joonwoo Parka9444452011-12-08 18:48:27 -080089/* Flags to track of PA and DAC state.
90 * PA and DAC should be tracked separately as AUXPGA loopback requires
91 * only PA to be turned on without DAC being on. */
92enum tabla_priv_ack_flags {
93 TABLA_HPHL_PA_OFF_ACK = 0,
94 TABLA_HPHR_PA_OFF_ACK,
95 TABLA_HPHL_DAC_OFF_ACK,
96 TABLA_HPHR_DAC_OFF_ACK
97};
98
Joonwoo Park0976d012011-12-22 11:48:18 -080099/* Data used by MBHC */
100struct mbhc_internal_cal_data {
101 u16 dce_z;
102 u16 dce_mb;
103 u16 sta_z;
104 u16 sta_mb;
105 u32 t_dce;
106 u32 t_sta;
107 u32 micb_mv;
108 u16 v_ins_hu;
109 u16 v_ins_h;
110 u16 v_b1_hu;
111 u16 v_b1_h;
112 u16 v_b1_huc;
113 u16 v_brh;
114 u16 v_brl;
115 u16 v_no_mic;
116 u8 nready;
117 u8 npoll;
118 u8 nbounce_wait;
119};
120
Bradley Rubin229c6a52011-07-12 16:18:48 -0700121struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 struct snd_soc_codec *codec;
Joonwoo Park0976d012011-12-22 11:48:18 -0800123 u32 mclk_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700124 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700125 u32 cfilt1_cnt;
126 u32 cfilt2_cnt;
127 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700128 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700130 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 bool clock_active;
132 bool config_mode_active;
133 bool mbhc_polling_active;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -0800134 bool fake_insert_context;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700135 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136
Joonwoo Park0976d012011-12-22 11:48:18 -0800137 enum tabla_micbias_num micbias;
138 /* void* calibration contains:
139 * struct tabla_mbhc_general_cfg generic;
140 * struct tabla_mbhc_plug_detect_cfg plug_det;
141 * struct tabla_mbhc_plug_type_cfg plug_type;
142 * struct tabla_mbhc_btn_detect_cfg btn_det;
143 * struct tabla_mbhc_imped_detect_cfg imped_det;
144 * Note: various size depends on btn_det->num_btn
145 */
146 void *calibration;
147 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700148
Bradley Rubincb1e2732011-06-23 16:49:20 -0700149 struct snd_soc_jack *headset_jack;
150 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700151
Patrick Lai3043fba2011-08-01 14:15:57 -0700152 struct tabla_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700153 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700154
155 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700156 /* Delayed work to report long button press */
157 struct delayed_work btn0_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700158
159 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700160 u8 cfilt_k_value;
161 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700162
Joonwoo Parka9444452011-12-08 18:48:27 -0800163 /* track PA/DAC state */
164 unsigned long hph_pa_dac_state;
165
Santosh Mardie15e2302011-11-15 10:39:23 +0530166 /*track tabla interface type*/
167 u8 intf_type;
168
Patrick Lai49efeac2011-11-03 11:01:12 -0700169 u32 hph_status; /* track headhpone status */
170 /* define separate work for left and right headphone OCP to avoid
171 * additional checking on which OCP event to report so no locking
172 * to ensure synchronization is required
173 */
174 struct work_struct hphlocp_work; /* reporting left hph ocp off */
175 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800176
177 /* pm_cnt holds number of sleep lock holders + 1
178 * so if pm_cnt is 1 system is sleep-able. */
179 atomic_t pm_cnt;
180 wait_queue_head_t pm_wq;
Patrick Laic7cae882011-11-18 11:52:49 -0800181
182 u8 hphlocp_cnt; /* headphone left ocp retry */
183 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800184
185 /* Callback function to enable MCLK */
186 int (*mclk_cb) (struct snd_soc_codec*, int);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187};
188
Bradley Rubincb3950a2011-08-18 13:07:26 -0700189#ifdef CONFIG_DEBUG_FS
190struct tabla_priv *debug_tabla_priv;
191#endif
192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
194 struct snd_kcontrol *kcontrol, int event)
195{
196 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700197
198 pr_debug("%s %d\n", __func__, event);
199 switch (event) {
200 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
202 0x01);
203 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
204 usleep_range(200, 200);
205 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
206 break;
207 case SND_SOC_DAPM_PRE_PMD:
208 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
209 0x10);
210 usleep_range(20, 20);
211 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
212 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
213 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
214 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
215 0x00);
216 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700217 break;
218 }
219 return 0;
220}
221
Bradley Rubina7096d02011-08-03 18:29:02 -0700222static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
223 struct snd_ctl_elem_value *ucontrol)
224{
225 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
226 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
227 ucontrol->value.integer.value[0] = tabla->anc_slot;
228 return 0;
229}
230
231static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
232 struct snd_ctl_elem_value *ucontrol)
233{
234 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
235 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
236 tabla->anc_slot = ucontrol->value.integer.value[0];
237 return 0;
238}
239
Kiran Kandid2d86b52011-09-09 17:44:28 -0700240static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
241 struct snd_ctl_elem_value *ucontrol)
242{
243 u8 ear_pa_gain;
244 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
245
246 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
247
248 ear_pa_gain = ear_pa_gain >> 5;
249
250 if (ear_pa_gain == 0x00) {
251 ucontrol->value.integer.value[0] = 0;
252 } else if (ear_pa_gain == 0x04) {
253 ucontrol->value.integer.value[0] = 1;
254 } else {
255 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
256 __func__, ear_pa_gain);
257 return -EINVAL;
258 }
259
260 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
261
262 return 0;
263}
264
265static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
266 struct snd_ctl_elem_value *ucontrol)
267{
268 u8 ear_pa_gain;
269 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
270
271 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
272 ucontrol->value.integer.value[0]);
273
274 switch (ucontrol->value.integer.value[0]) {
275 case 0:
276 ear_pa_gain = 0x00;
277 break;
278 case 1:
279 ear_pa_gain = 0x80;
280 break;
281 default:
282 return -EINVAL;
283 }
284
285 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
286 return 0;
287}
288
Ben Romberger1f045a72011-11-04 10:14:57 -0700289static int tabla_get_iir_enable_audio_mixer(
290 struct snd_kcontrol *kcontrol,
291 struct snd_ctl_elem_value *ucontrol)
292{
293 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
294 int iir_idx = ((struct soc_multi_mixer_control *)
295 kcontrol->private_value)->reg;
296 int band_idx = ((struct soc_multi_mixer_control *)
297 kcontrol->private_value)->shift;
298
299 ucontrol->value.integer.value[0] =
300 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
301 (1 << band_idx);
302
303 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
304 iir_idx, band_idx,
305 (uint32_t)ucontrol->value.integer.value[0]);
306 return 0;
307}
308
309static int tabla_put_iir_enable_audio_mixer(
310 struct snd_kcontrol *kcontrol,
311 struct snd_ctl_elem_value *ucontrol)
312{
313 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
314 int iir_idx = ((struct soc_multi_mixer_control *)
315 kcontrol->private_value)->reg;
316 int band_idx = ((struct soc_multi_mixer_control *)
317 kcontrol->private_value)->shift;
318 int value = ucontrol->value.integer.value[0];
319
320 /* Mask first 5 bits, 6-8 are reserved */
321 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
322 (1 << band_idx), (value << band_idx));
323
324 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
325 iir_idx, band_idx, value);
326 return 0;
327}
328static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
329 int iir_idx, int band_idx,
330 int coeff_idx)
331{
332 /* Address does not automatically update if reading */
333 snd_soc_update_bits(codec,
334 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
335 0x1F, band_idx * BAND_MAX + coeff_idx);
336
337 /* Mask bits top 2 bits since they are reserved */
338 return ((snd_soc_read(codec,
339 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
340 (snd_soc_read(codec,
341 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
342 (snd_soc_read(codec,
343 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
344 (snd_soc_read(codec,
345 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
346 0x3FFFFFFF;
347}
348
349static int tabla_get_iir_band_audio_mixer(
350 struct snd_kcontrol *kcontrol,
351 struct snd_ctl_elem_value *ucontrol)
352{
353 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
354 int iir_idx = ((struct soc_multi_mixer_control *)
355 kcontrol->private_value)->reg;
356 int band_idx = ((struct soc_multi_mixer_control *)
357 kcontrol->private_value)->shift;
358
359 ucontrol->value.integer.value[0] =
360 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
361 ucontrol->value.integer.value[1] =
362 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
363 ucontrol->value.integer.value[2] =
364 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
365 ucontrol->value.integer.value[3] =
366 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
367 ucontrol->value.integer.value[4] =
368 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
369
370 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
371 "%s: IIR #%d band #%d b1 = 0x%x\n"
372 "%s: IIR #%d band #%d b2 = 0x%x\n"
373 "%s: IIR #%d band #%d a1 = 0x%x\n"
374 "%s: IIR #%d band #%d a2 = 0x%x\n",
375 __func__, iir_idx, band_idx,
376 (uint32_t)ucontrol->value.integer.value[0],
377 __func__, iir_idx, band_idx,
378 (uint32_t)ucontrol->value.integer.value[1],
379 __func__, iir_idx, band_idx,
380 (uint32_t)ucontrol->value.integer.value[2],
381 __func__, iir_idx, band_idx,
382 (uint32_t)ucontrol->value.integer.value[3],
383 __func__, iir_idx, band_idx,
384 (uint32_t)ucontrol->value.integer.value[4]);
385 return 0;
386}
387
388static void set_iir_band_coeff(struct snd_soc_codec *codec,
389 int iir_idx, int band_idx,
390 int coeff_idx, uint32_t value)
391{
392 /* Mask top 3 bits, 6-8 are reserved */
393 /* Update address manually each time */
394 snd_soc_update_bits(codec,
395 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
396 0x1F, band_idx * BAND_MAX + coeff_idx);
397
398 /* Mask top 2 bits, 7-8 are reserved */
399 snd_soc_update_bits(codec,
400 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
401 0x3F, (value >> 24) & 0x3F);
402
403 /* Isolate 8bits at a time */
404 snd_soc_update_bits(codec,
405 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
406 0xFF, (value >> 16) & 0xFF);
407
408 snd_soc_update_bits(codec,
409 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
410 0xFF, (value >> 8) & 0xFF);
411
412 snd_soc_update_bits(codec,
413 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
414 0xFF, value & 0xFF);
415}
416
417static int tabla_put_iir_band_audio_mixer(
418 struct snd_kcontrol *kcontrol,
419 struct snd_ctl_elem_value *ucontrol)
420{
421 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
422 int iir_idx = ((struct soc_multi_mixer_control *)
423 kcontrol->private_value)->reg;
424 int band_idx = ((struct soc_multi_mixer_control *)
425 kcontrol->private_value)->shift;
426
427 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
428 ucontrol->value.integer.value[0]);
429 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
430 ucontrol->value.integer.value[1]);
431 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
432 ucontrol->value.integer.value[2]);
433 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
434 ucontrol->value.integer.value[3]);
435 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
436 ucontrol->value.integer.value[4]);
437
438 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
439 "%s: IIR #%d band #%d b1 = 0x%x\n"
440 "%s: IIR #%d band #%d b2 = 0x%x\n"
441 "%s: IIR #%d band #%d a1 = 0x%x\n"
442 "%s: IIR #%d band #%d a2 = 0x%x\n",
443 __func__, iir_idx, band_idx,
444 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
445 __func__, iir_idx, band_idx,
446 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
447 __func__, iir_idx, band_idx,
448 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
449 __func__, iir_idx, band_idx,
450 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
451 __func__, iir_idx, band_idx,
452 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
453 return 0;
454}
455
Kiran Kandid2d86b52011-09-09 17:44:28 -0700456static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
457static const struct soc_enum tabla_ear_pa_gain_enum[] = {
458 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
459};
460
Santosh Mardi024010f2011-10-18 06:27:21 +0530461/*cut of frequency for high pass filter*/
462static const char *cf_text[] = {
463 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
464};
465
466static const struct soc_enum cf_dec1_enum =
467 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
468
469static const struct soc_enum cf_dec2_enum =
470 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
471
472static const struct soc_enum cf_dec3_enum =
473 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
474
475static const struct soc_enum cf_dec4_enum =
476 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
477
478static const struct soc_enum cf_dec5_enum =
479 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
480
481static const struct soc_enum cf_dec6_enum =
482 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
483
484static const struct soc_enum cf_dec7_enum =
485 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
486
487static const struct soc_enum cf_dec8_enum =
488 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
489
490static const struct soc_enum cf_dec9_enum =
491 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
492
493static const struct soc_enum cf_dec10_enum =
494 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
495
496static const struct soc_enum cf_rxmix1_enum =
497 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
498
499static const struct soc_enum cf_rxmix2_enum =
500 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
501
502static const struct soc_enum cf_rxmix3_enum =
503 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
504
505static const struct soc_enum cf_rxmix4_enum =
506 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
507
508static const struct soc_enum cf_rxmix5_enum =
509 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
510;
511static const struct soc_enum cf_rxmix6_enum =
512 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
513
514static const struct soc_enum cf_rxmix7_enum =
515 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
516
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700517static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700518
519 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
520 tabla_pa_gain_get, tabla_pa_gain_put),
521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
523 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700524 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
525 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
527 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700528 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
529 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700530 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
531 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700533 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
534 line_gain),
535 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
536 line_gain),
537
Bradley Rubin410383f2011-07-22 13:44:23 -0700538 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
539 -84, 40, digital_gain),
540 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
541 -84, 40, digital_gain),
542 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
543 -84, 40, digital_gain),
544 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
545 -84, 40, digital_gain),
546 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
547 -84, 40, digital_gain),
548 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
549 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700550
Bradley Rubin410383f2011-07-22 13:44:23 -0700551 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700553 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700554 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700555 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
556 digital_gain),
557 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
558 digital_gain),
559 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
560 digital_gain),
561 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
562 digital_gain),
563 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
564 digital_gain),
565 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
566 digital_gain),
567 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
568 digital_gain),
569 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
570 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700571 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
572 40, digital_gain),
573 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
574 40, digital_gain),
575 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
576 40, digital_gain),
577 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
578 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700579 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
580 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700581 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
582 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700583 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
584 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585
586 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800587 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700588 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
589 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700590
591 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
592 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530593 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
594 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
595 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
596 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
597 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
598 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
599 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
600 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
601 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
602 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
603
604 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
605 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
606 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
607 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
608 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
609 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
610 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
611 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
612 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
613 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
614
615 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
616 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
617 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
618 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
619 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
620 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
621 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
622
623 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
624 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
625 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
626 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
627 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
628 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
629 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700630
631 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
632 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
633 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
634 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
635 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
636 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
637 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
638 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
639 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
640 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
641 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
642 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
643 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
644 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
645 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
646 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
647 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
648 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
649 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
650 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
651
652 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
653 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
654 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
655 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
656 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
657 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
658 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
659 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
660 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
661 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
662 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
663 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
664 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
665 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
666 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
667 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
668 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
669 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
670 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
671 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672};
673
674static const char *rx_mix1_text[] = {
675 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
676 "RX5", "RX6", "RX7"
677};
678
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700679static const char *rx_dsm_text[] = {
680 "CIC_OUT", "DSM_INV"
681};
682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700683static const char *sb_tx1_mux_text[] = {
684 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
685 "DEC1"
686};
687
688static const char *sb_tx5_mux_text[] = {
689 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
690 "DEC5"
691};
692
693static const char *sb_tx6_mux_text[] = {
694 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
695 "DEC6"
696};
697
698static const char const *sb_tx7_to_tx10_mux_text[] = {
699 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
700 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
701 "DEC9", "DEC10"
702};
703
704static const char *dec1_mux_text[] = {
705 "ZERO", "DMIC1", "ADC6",
706};
707
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700708static const char *dec2_mux_text[] = {
709 "ZERO", "DMIC2", "ADC5",
710};
711
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700712static const char *dec3_mux_text[] = {
713 "ZERO", "DMIC3", "ADC4",
714};
715
716static const char *dec4_mux_text[] = {
717 "ZERO", "DMIC4", "ADC3",
718};
719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700720static const char *dec5_mux_text[] = {
721 "ZERO", "DMIC5", "ADC2",
722};
723
724static const char *dec6_mux_text[] = {
725 "ZERO", "DMIC6", "ADC1",
726};
727
728static const char const *dec7_mux_text[] = {
729 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
730};
731
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700732static const char *dec8_mux_text[] = {
733 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
734};
735
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700736static const char *dec9_mux_text[] = {
737 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
738};
739
740static const char *dec10_mux_text[] = {
741 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
742};
743
Bradley Rubin229c6a52011-07-12 16:18:48 -0700744static const char const *anc_mux_text[] = {
745 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
746 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
747};
748
749static const char const *anc1_fb_mux_text[] = {
750 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
751};
752
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700753static const char *iir1_inp1_text[] = {
754 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
755 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
756};
757
758static const struct soc_enum rx_mix1_inp1_chain_enum =
759 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
760
Bradley Rubin229c6a52011-07-12 16:18:48 -0700761static const struct soc_enum rx_mix1_inp2_chain_enum =
762 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700764static const struct soc_enum rx2_mix1_inp1_chain_enum =
765 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
766
Bradley Rubin229c6a52011-07-12 16:18:48 -0700767static const struct soc_enum rx2_mix1_inp2_chain_enum =
768 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
769
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700770static const struct soc_enum rx3_mix1_inp1_chain_enum =
771 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
772
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700773static const struct soc_enum rx3_mix1_inp2_chain_enum =
774 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700776static const struct soc_enum rx4_mix1_inp1_chain_enum =
777 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
778
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700779static const struct soc_enum rx4_mix1_inp2_chain_enum =
780 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
781
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700782static const struct soc_enum rx5_mix1_inp1_chain_enum =
783 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
784
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700785static const struct soc_enum rx5_mix1_inp2_chain_enum =
786 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
787
788static const struct soc_enum rx6_mix1_inp1_chain_enum =
789 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
790
791static const struct soc_enum rx6_mix1_inp2_chain_enum =
792 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
793
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700794static const struct soc_enum rx7_mix1_inp1_chain_enum =
795 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
796
797static const struct soc_enum rx7_mix1_inp2_chain_enum =
798 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
799
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700800static const struct soc_enum rx4_dsm_enum =
801 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
802
803static const struct soc_enum rx6_dsm_enum =
804 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806static const struct soc_enum sb_tx5_mux_enum =
807 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
808
809static const struct soc_enum sb_tx6_mux_enum =
810 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
811
812static const struct soc_enum sb_tx7_mux_enum =
813 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
814 sb_tx7_to_tx10_mux_text);
815
816static const struct soc_enum sb_tx8_mux_enum =
817 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
818 sb_tx7_to_tx10_mux_text);
819
820static const struct soc_enum sb_tx1_mux_enum =
821 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
822
823static const struct soc_enum dec1_mux_enum =
824 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
825
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700826static const struct soc_enum dec2_mux_enum =
827 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
828
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700829static const struct soc_enum dec3_mux_enum =
830 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
831
832static const struct soc_enum dec4_mux_enum =
833 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
834
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835static const struct soc_enum dec5_mux_enum =
836 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
837
838static const struct soc_enum dec6_mux_enum =
839 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
840
841static const struct soc_enum dec7_mux_enum =
842 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
843
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700844static const struct soc_enum dec8_mux_enum =
845 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
846
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700847static const struct soc_enum dec9_mux_enum =
848 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
849
850static const struct soc_enum dec10_mux_enum =
851 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
852
Bradley Rubin229c6a52011-07-12 16:18:48 -0700853static const struct soc_enum anc1_mux_enum =
854 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
855
856static const struct soc_enum anc2_mux_enum =
857 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
858
859static const struct soc_enum anc1_fb_mux_enum =
860 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862static const struct soc_enum iir1_inp1_mux_enum =
863 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
864
865static const struct snd_kcontrol_new rx_mix1_inp1_mux =
866 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
867
Bradley Rubin229c6a52011-07-12 16:18:48 -0700868static const struct snd_kcontrol_new rx_mix1_inp2_mux =
869 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
872 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
873
Bradley Rubin229c6a52011-07-12 16:18:48 -0700874static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
875 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
876
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700877static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
878 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
879
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700880static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
881 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
884 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
885
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700886static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
887 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
888
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700889static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
890 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
891
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700892static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
893 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
894
895static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
896 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
897
898static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
899 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
900
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700901static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
902 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
903
904static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
905 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
906
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700907static const struct snd_kcontrol_new rx4_dsm_mux =
908 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
909
910static const struct snd_kcontrol_new rx6_dsm_mux =
911 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
912
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913static const struct snd_kcontrol_new sb_tx5_mux =
914 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
915
916static const struct snd_kcontrol_new sb_tx6_mux =
917 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
918
919static const struct snd_kcontrol_new sb_tx7_mux =
920 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
921
922static const struct snd_kcontrol_new sb_tx8_mux =
923 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
924
925static const struct snd_kcontrol_new sb_tx1_mux =
926 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
927
928static const struct snd_kcontrol_new dec1_mux =
929 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
930
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700931static const struct snd_kcontrol_new dec2_mux =
932 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
933
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700934static const struct snd_kcontrol_new dec3_mux =
935 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
936
937static const struct snd_kcontrol_new dec4_mux =
938 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
939
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940static const struct snd_kcontrol_new dec5_mux =
941 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
942
943static const struct snd_kcontrol_new dec6_mux =
944 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
945
946static const struct snd_kcontrol_new dec7_mux =
947 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
948
Bradley Rubin229c6a52011-07-12 16:18:48 -0700949static const struct snd_kcontrol_new anc1_mux =
950 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700951static const struct snd_kcontrol_new dec8_mux =
952 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
953
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700954static const struct snd_kcontrol_new dec9_mux =
955 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
956
957static const struct snd_kcontrol_new dec10_mux =
958 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960static const struct snd_kcontrol_new iir1_inp1_mux =
961 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
962
Bradley Rubin229c6a52011-07-12 16:18:48 -0700963static const struct snd_kcontrol_new anc2_mux =
964 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700965
Bradley Rubin229c6a52011-07-12 16:18:48 -0700966static const struct snd_kcontrol_new anc1_fb_mux =
967 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700968
Bradley Rubin229c6a52011-07-12 16:18:48 -0700969static const struct snd_kcontrol_new dac1_switch[] = {
970 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
971};
972static const struct snd_kcontrol_new hphl_switch[] = {
973 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
974};
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700975
976static const struct snd_kcontrol_new lineout3_ground_switch =
977 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
978
979static const struct snd_kcontrol_new lineout4_ground_switch =
980 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
983 int enable)
984{
985 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
986
987 pr_debug("%s %d\n", __func__, enable);
988
989 if (enable) {
990 tabla->adc_count++;
991 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
992 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
993 } else {
994 tabla->adc_count--;
995 if (!tabla->adc_count) {
996 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
997 0x2, 0x0);
998 if (!tabla->mbhc_polling_active)
999 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
1000 0xE0, 0x0);
1001 }
1002 }
1003}
1004
1005static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1006 struct snd_kcontrol *kcontrol, int event)
1007{
1008 struct snd_soc_codec *codec = w->codec;
1009 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001010 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001011
1012 pr_debug("%s %d\n", __func__, event);
1013
1014 if (w->reg == TABLA_A_TX_1_2_EN)
1015 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1016 else if (w->reg == TABLA_A_TX_3_4_EN)
1017 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1018 else if (w->reg == TABLA_A_TX_5_6_EN)
1019 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1020 else {
1021 pr_err("%s: Error, invalid adc register\n", __func__);
1022 return -EINVAL;
1023 }
1024
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001025 if (w->shift == 3)
1026 init_bit_shift = 6;
1027 else if (w->shift == 7)
1028 init_bit_shift = 7;
1029 else {
1030 pr_err("%s: Error, invalid init bit postion adc register\n",
1031 __func__);
1032 return -EINVAL;
1033 }
1034
1035
1036
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001037 switch (event) {
1038 case SND_SOC_DAPM_PRE_PMU:
1039 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001040 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1041 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 break;
1043 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001044
1045 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1046
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 break;
1048 case SND_SOC_DAPM_POST_PMD:
1049 tabla_codec_enable_adc_block(codec, 0);
1050 break;
1051 }
1052 return 0;
1053}
1054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1056 struct snd_kcontrol *kcontrol, int event)
1057{
1058 struct snd_soc_codec *codec = w->codec;
1059 u16 lineout_gain_reg;
1060
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001061 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001062
1063 switch (w->shift) {
1064 case 0:
1065 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1066 break;
1067 case 1:
1068 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1069 break;
1070 case 2:
1071 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1072 break;
1073 case 3:
1074 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1075 break;
1076 case 4:
1077 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1078 break;
1079 default:
1080 pr_err("%s: Error, incorrect lineout register value\n",
1081 __func__);
1082 return -EINVAL;
1083 }
1084
1085 switch (event) {
1086 case SND_SOC_DAPM_PRE_PMU:
1087 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1088 break;
1089 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001090 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001091 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001092 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093 break;
1094 case SND_SOC_DAPM_POST_PMD:
1095 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1096 break;
1097 }
1098 return 0;
1099}
1100
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001101
1102static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 struct snd_kcontrol *kcontrol, int event)
1104{
1105 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001106 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1107 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001108 unsigned int dmic;
1109 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001110
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001111 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1112 if (ret < 0) {
1113 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001114 return -EINVAL;
1115 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001117 switch (dmic) {
1118 case 1:
1119 case 2:
1120 dmic_clk_sel = 0x02;
1121 dmic_clk_en = 0x01;
1122 break;
1123
1124 case 3:
1125 case 4:
1126 dmic_clk_sel = 0x08;
1127 dmic_clk_en = 0x04;
1128 break;
1129
1130 case 5:
1131 case 6:
1132 dmic_clk_sel = 0x20;
1133 dmic_clk_en = 0x10;
1134 break;
1135
1136 default:
1137 pr_err("%s: Invalid DMIC Selection\n", __func__);
1138 return -EINVAL;
1139 }
1140
1141 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1142 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 switch (event) {
1147 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001148 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1149
1150 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1151 dmic_clk_sel, dmic_clk_sel);
1152
1153 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1154
1155 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1156 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001157 break;
1158 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001159 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1160 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 break;
1162 }
1163 return 0;
1164}
1165
Bradley Rubin229c6a52011-07-12 16:18:48 -07001166static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1167 struct snd_kcontrol *kcontrol, int event)
1168{
1169 struct snd_soc_codec *codec = w->codec;
1170 const char *filename;
1171 const struct firmware *fw;
1172 int i;
1173 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001174 int num_anc_slots;
1175 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001176 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001177 u32 anc_writes_size = 0;
1178 int anc_size_remaining;
1179 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001180 u16 reg;
1181 u8 mask, val, old_val;
1182
1183 pr_debug("%s %d\n", __func__, event);
1184 switch (event) {
1185 case SND_SOC_DAPM_PRE_PMU:
1186
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001187 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001188
1189 ret = request_firmware(&fw, filename, codec->dev);
1190 if (ret != 0) {
1191 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1192 ret);
1193 return -ENODEV;
1194 }
1195
Bradley Rubina7096d02011-08-03 18:29:02 -07001196 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001197 dev_err(codec->dev, "Not enough data\n");
1198 release_firmware(fw);
1199 return -ENOMEM;
1200 }
1201
1202 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001203 anc_head = (struct anc_header *)(fw->data);
1204 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1205 anc_size_remaining = fw->size - sizeof(struct anc_header);
1206 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001207
Bradley Rubina7096d02011-08-03 18:29:02 -07001208 if (tabla->anc_slot >= num_anc_slots) {
1209 dev_err(codec->dev, "Invalid ANC slot selected\n");
1210 release_firmware(fw);
1211 return -EINVAL;
1212 }
1213
1214 for (i = 0; i < num_anc_slots; i++) {
1215
1216 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1217 dev_err(codec->dev, "Invalid register format\n");
1218 release_firmware(fw);
1219 return -EINVAL;
1220 }
1221 anc_writes_size = (u32)(*anc_ptr);
1222 anc_size_remaining -= sizeof(u32);
1223 anc_ptr += 1;
1224
1225 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1226 > anc_size_remaining) {
1227 dev_err(codec->dev, "Invalid register format\n");
1228 release_firmware(fw);
1229 return -ENOMEM;
1230 }
1231
1232 if (tabla->anc_slot == i)
1233 break;
1234
1235 anc_size_remaining -= (anc_writes_size *
1236 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001237 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001238 }
1239 if (i == num_anc_slots) {
1240 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001241 release_firmware(fw);
1242 return -ENOMEM;
1243 }
1244
Bradley Rubina7096d02011-08-03 18:29:02 -07001245 for (i = 0; i < anc_writes_size; i++) {
1246 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001247 mask, val);
1248 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001249 snd_soc_write(codec, reg, (old_val & ~mask) |
1250 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001251 }
1252 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001253
1254 break;
1255 case SND_SOC_DAPM_POST_PMD:
1256 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1257 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1258 break;
1259 }
1260 return 0;
1261}
1262
1263
Bradley Rubincb3950a2011-08-18 13:07:26 -07001264static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
1265{
1266 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
1267 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
1268}
1269
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001270static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1271{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001272 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1273
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001274 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001275 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001276 if (!tabla->no_mic_headset_override) {
1277 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1278 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1279 } else {
1280 tabla_codec_disable_button_presses(codec);
1281 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001282 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1283 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1284 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1285}
1286
1287static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1288{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001289 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1290
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001291 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1292 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001293 if (!tabla->no_mic_headset_override) {
1294 tabla_disable_irq(codec->control_data,
1295 TABLA_IRQ_MBHC_POTENTIAL);
1296 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1297 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001298}
1299
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001300static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1301 int mode)
1302{
1303 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1304 u8 reg_mode_val, cur_mode_val;
1305 bool mbhc_was_polling = false;
1306
1307 if (mode)
1308 reg_mode_val = TABLA_CFILT_FAST_MODE;
1309 else
1310 reg_mode_val = TABLA_CFILT_SLOW_MODE;
1311
1312 cur_mode_val = snd_soc_read(codec,
1313 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
1314
1315 if (cur_mode_val != reg_mode_val) {
1316 if (tabla->mbhc_polling_active) {
1317 tabla_codec_pause_hs_polling(codec);
1318 mbhc_was_polling = true;
1319 }
1320 snd_soc_update_bits(codec,
1321 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1322 if (mbhc_was_polling)
1323 tabla_codec_start_hs_polling(codec);
1324 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
1325 cur_mode_val, reg_mode_val);
1326 } else {
1327 pr_debug("%s: CFILT Value is already %x\n",
1328 __func__, cur_mode_val);
1329 }
1330}
1331
1332static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1333 u8 cfilt_sel, int inc)
1334{
1335 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1336 u32 *cfilt_cnt_ptr = NULL;
1337 u16 micb_cfilt_reg;
1338
1339 switch (cfilt_sel) {
1340 case TABLA_CFILT1_SEL:
1341 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
1342 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
1343 break;
1344 case TABLA_CFILT2_SEL:
1345 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
1346 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
1347 break;
1348 case TABLA_CFILT3_SEL:
1349 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
1350 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
1351 break;
1352 default:
1353 return; /* should not happen */
1354 }
1355
1356 if (inc) {
1357 if (!(*cfilt_cnt_ptr)++) {
1358 /* Switch CFILT to slow mode if MBHC CFILT being used */
1359 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1360 tabla_codec_switch_cfilt_mode(codec, 0);
1361
1362 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1363 }
1364 } else {
1365 /* check if count not zero, decrement
1366 * then check if zero, go ahead disable cfilter
1367 */
1368 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1369 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1370
1371 /* Switch CFILT to fast mode if MBHC CFILT being used */
1372 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1373 tabla_codec_switch_cfilt_mode(codec, 1);
1374 }
1375 }
1376}
1377
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001378static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1379{
1380 int rc = -EINVAL;
1381 unsigned min_mv, max_mv;
1382
1383 switch (ldoh_v) {
1384 case TABLA_LDOH_1P95_V:
1385 min_mv = 160;
1386 max_mv = 1800;
1387 break;
1388 case TABLA_LDOH_2P35_V:
1389 min_mv = 200;
1390 max_mv = 2200;
1391 break;
1392 case TABLA_LDOH_2P75_V:
1393 min_mv = 240;
1394 max_mv = 2600;
1395 break;
1396 case TABLA_LDOH_2P85_V:
1397 min_mv = 250;
1398 max_mv = 2700;
1399 break;
1400 default:
1401 goto done;
1402 }
1403
1404 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1405 goto done;
1406
1407 for (rc = 4; rc <= 44; rc++) {
1408 min_mv = max_mv * (rc) / 44;
1409 if (min_mv >= cfilt_mv) {
1410 rc -= 4;
1411 break;
1412 }
1413 }
1414done:
1415 return rc;
1416}
1417
1418static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
1419{
1420 u8 hph_reg_val = 0;
1421 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
1422
1423 return (hph_reg_val & 0x30) ? true : false;
1424}
1425
Joonwoo Parka9444452011-12-08 18:48:27 -08001426static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
1427{
1428 u8 hph_reg_val = 0;
1429 if (left)
1430 hph_reg_val = snd_soc_read(codec,
1431 TABLA_A_RX_HPH_L_DAC_CTL);
1432 else
1433 hph_reg_val = snd_soc_read(codec,
1434 TABLA_A_RX_HPH_R_DAC_CTL);
1435
1436 return (hph_reg_val & 0xC0) ? true : false;
1437}
1438
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001439static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
1440 int vddio_switch)
1441{
1442 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1443 int cfilt_k_val;
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001444 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001445
1446 switch (vddio_switch) {
1447 case 1:
1448 if (tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001449
1450 tabla_codec_pause_hs_polling(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08001451 /* VDDIO switch enabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001452 tabla->cfilt_k_value = snd_soc_read(codec,
1453 tabla->mbhc_bias_regs.cfilt_val);
1454 cfilt_k_val = tabla_find_k_value(
1455 tabla->pdata->micbias.ldoh_v, 1800);
1456 snd_soc_update_bits(codec,
1457 tabla->mbhc_bias_regs.cfilt_val,
1458 0xFC, (cfilt_k_val << 2));
1459
1460 snd_soc_update_bits(codec,
1461 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1462 snd_soc_update_bits(codec,
1463 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001464 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001465
1466 tabla->mbhc_micbias_switched = true;
Joonwoo Park0976d012011-12-22 11:48:18 -08001467 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001468 }
1469 break;
1470
1471 case 0:
1472 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001473 if (tabla->mbhc_polling_active) {
1474 tabla_codec_pause_hs_polling(codec);
1475 mbhc_was_polling = true;
1476 }
Joonwoo Park0976d012011-12-22 11:48:18 -08001477 /* VDDIO switch disabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001478 if (tabla->cfilt_k_value != 0)
1479 snd_soc_update_bits(codec,
1480 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
1481 tabla->cfilt_k_value);
1482 snd_soc_update_bits(codec,
1483 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1484 snd_soc_update_bits(codec,
1485 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1486
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001487 if (mbhc_was_polling)
1488 tabla_codec_start_hs_polling(codec);
1489
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001490 tabla->mbhc_micbias_switched = false;
Joonwoo Park0976d012011-12-22 11:48:18 -08001491 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001492 }
1493 break;
1494 }
1495}
1496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001497static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1498 struct snd_kcontrol *kcontrol, int event)
1499{
1500 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07001501 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1502 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001503 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001504 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001505 char *internal1_text = "Internal1";
1506 char *internal2_text = "Internal2";
1507 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001508
1509 pr_debug("%s %d\n", __func__, event);
1510 switch (w->reg) {
1511 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001513 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001514 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001515 break;
1516 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001517 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001518 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001519 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001520 break;
1521 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001523 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001524 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001525 break;
1526 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001527 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001528 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001529 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530 break;
1531 default:
1532 pr_err("%s: Error, invalid micbias register\n", __func__);
1533 return -EINVAL;
1534 }
1535
1536 switch (event) {
1537 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001538 /* Decide whether to switch the micbias for MBHC */
1539 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1540 && tabla->mbhc_micbias_switched)
1541 tabla_codec_switch_micbias(codec, 0);
1542
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001543 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07001544 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001545
1546 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001548 else if (strnstr(w->name, internal2_text, 30))
1549 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1550 else if (strnstr(w->name, internal3_text, 30))
1551 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
1552
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001554 case SND_SOC_DAPM_POST_PMU:
1555 if (tabla->mbhc_polling_active &&
Joonwoo Park0976d012011-12-22 11:48:18 -08001556 tabla->micbias == micb_line) {
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001557 tabla_codec_pause_hs_polling(codec);
1558 tabla_codec_start_hs_polling(codec);
1559 }
1560 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001563
1564 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1565 && tabla_is_hph_pa_on(codec))
1566 tabla_codec_switch_micbias(codec, 1);
1567
Bradley Rubin229c6a52011-07-12 16:18:48 -07001568 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001570 else if (strnstr(w->name, internal2_text, 30))
1571 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1572 else if (strnstr(w->name, internal3_text, 30))
1573 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1574
Patrick Lai3043fba2011-08-01 14:15:57 -07001575 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 break;
1577 }
1578
1579 return 0;
1580}
1581
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001582static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
1583 struct snd_kcontrol *kcontrol, int event)
1584{
1585 struct snd_soc_codec *codec = w->codec;
1586 u16 dec_reset_reg;
1587
1588 pr_debug("%s %d\n", __func__, event);
1589
1590 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1591 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
1592 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
1593 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
1594 else {
1595 pr_err("%s: Error, incorrect dec\n", __func__);
1596 return -EINVAL;
1597 }
1598
1599 switch (event) {
1600 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1602 1 << w->shift);
1603 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1604 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 }
1606 return 0;
1607}
1608
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001609static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001610 struct snd_kcontrol *kcontrol, int event)
1611{
1612 struct snd_soc_codec *codec = w->codec;
1613
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001614 pr_debug("%s %d %s\n", __func__, event, w->name);
1615
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 switch (event) {
1617 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001618 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1619 1 << w->shift, 1 << w->shift);
1620 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1621 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 break;
1623 }
1624 return 0;
1625}
1626
Bradley Rubin229c6a52011-07-12 16:18:48 -07001627static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1628 struct snd_kcontrol *kcontrol, int event)
1629{
1630 switch (event) {
1631 case SND_SOC_DAPM_POST_PMU:
1632 case SND_SOC_DAPM_POST_PMD:
1633 usleep_range(1000, 1000);
1634 break;
1635 }
1636 return 0;
1637}
1638
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001639
1640static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1641{
1642 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1643
1644 if (enable) {
1645 tabla->rx_bias_count++;
1646 if (tabla->rx_bias_count == 1)
1647 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1648 0x80, 0x80);
1649 } else {
1650 tabla->rx_bias_count--;
1651 if (!tabla->rx_bias_count)
1652 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1653 0x80, 0x00);
1654 }
1655}
1656
1657static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1658 struct snd_kcontrol *kcontrol, int event)
1659{
1660 struct snd_soc_codec *codec = w->codec;
1661
1662 pr_debug("%s %d\n", __func__, event);
1663
1664 switch (event) {
1665 case SND_SOC_DAPM_PRE_PMU:
1666 tabla_enable_rx_bias(codec, 1);
1667 break;
1668 case SND_SOC_DAPM_POST_PMD:
1669 tabla_enable_rx_bias(codec, 0);
1670 break;
1671 }
1672 return 0;
1673}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001674static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
1675 struct snd_kcontrol *kcontrol, int event)
1676{
1677 struct snd_soc_codec *codec = w->codec;
1678
1679 pr_debug("%s %s %d\n", __func__, w->name, event);
1680
1681 switch (event) {
1682 case SND_SOC_DAPM_PRE_PMU:
1683 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1684 break;
1685 case SND_SOC_DAPM_POST_PMD:
1686 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1687 break;
1688 }
1689 return 0;
1690}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001691
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001692static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
1693 struct snd_soc_jack *jack, int status,
1694 int mask)
1695{
1696 /* XXX: wake_lock_timeout()? */
1697 snd_soc_jack_report(jack, status, mask);
1698}
1699
Patrick Lai49efeac2011-11-03 11:01:12 -07001700static void hphocp_off_report(struct tabla_priv *tabla,
1701 u32 jack_status, int irq)
1702{
1703 struct snd_soc_codec *codec;
1704
1705 if (tabla) {
1706 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
1707 codec = tabla->codec;
1708 tabla->hph_status &= ~jack_status;
1709 if (tabla->headset_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001710 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
1711 tabla->hph_status,
1712 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08001713 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
1714 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08001715 /* reset retry counter as PA is turned off signifying
1716 * start of new OCP detection session
1717 */
1718 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
1719 tabla->hphlocp_cnt = 0;
1720 else
1721 tabla->hphrocp_cnt = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07001722 tabla_enable_irq(codec->control_data, irq);
1723 } else {
1724 pr_err("%s: Bad tabla private data\n", __func__);
1725 }
1726}
1727
1728static void hphlocp_off_report(struct work_struct *work)
1729{
1730 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1731 hphlocp_work);
1732 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
1733}
1734
1735static void hphrocp_off_report(struct work_struct *work)
1736{
1737 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1738 hphrocp_work);
1739 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
1740}
1741
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001742static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
1743 struct snd_kcontrol *kcontrol, int event)
1744{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001745 struct snd_soc_codec *codec = w->codec;
1746 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1747 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001748 pr_debug("%s: event = %d\n", __func__, event);
1749
1750 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001751 case SND_SOC_DAPM_PRE_PMU:
1752 mbhc_micb_ctl_val = snd_soc_read(codec,
1753 tabla->mbhc_bias_regs.ctl_reg);
1754
1755 if (!(mbhc_micb_ctl_val & 0x80)
1756 && !tabla->mbhc_micbias_switched)
1757 tabla_codec_switch_micbias(codec, 1);
1758
1759 break;
1760
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001761 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07001762 /* schedule work is required because at the time HPH PA DAPM
1763 * event callback is called by DAPM framework, CODEC dapm mutex
1764 * would have been locked while snd_soc_jack_report also
1765 * attempts to acquire same lock.
1766 */
Joonwoo Parka9444452011-12-08 18:48:27 -08001767 if (w->shift == 5) {
1768 clear_bit(TABLA_HPHL_PA_OFF_ACK,
1769 &tabla->hph_pa_dac_state);
1770 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
1771 &tabla->hph_pa_dac_state);
1772 if (tabla->hph_status & SND_JACK_OC_HPHL)
1773 schedule_work(&tabla->hphlocp_work);
1774 } else if (w->shift == 4) {
1775 clear_bit(TABLA_HPHR_PA_OFF_ACK,
1776 &tabla->hph_pa_dac_state);
1777 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
1778 &tabla->hph_pa_dac_state);
1779 if (tabla->hph_status & SND_JACK_OC_HPHR)
1780 schedule_work(&tabla->hphrocp_work);
1781 }
1782
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001783 if (tabla->mbhc_micbias_switched)
1784 tabla_codec_switch_micbias(codec, 0);
1785
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001786 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
1787 w->name);
1788 usleep_range(10000, 10000);
1789
1790 break;
1791 }
1792 return 0;
1793}
1794
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001795static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
1796 struct mbhc_micbias_regs *micbias_regs)
1797{
1798 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001799 unsigned int cfilt;
1800
Joonwoo Park0976d012011-12-22 11:48:18 -08001801 switch (tabla->micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001802 case TABLA_MICBIAS1:
1803 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
1804 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
1805 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
1806 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
1807 break;
1808 case TABLA_MICBIAS2:
1809 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
1810 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
1811 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
1812 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
1813 break;
1814 case TABLA_MICBIAS3:
1815 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
1816 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
1817 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
1818 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
1819 break;
1820 case TABLA_MICBIAS4:
1821 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
1822 micbias_regs->mbhc_reg = TABLA_A_MICB_4_MBHC;
1823 micbias_regs->int_rbias = TABLA_A_MICB_4_INT_RBIAS;
1824 micbias_regs->ctl_reg = TABLA_A_MICB_4_CTL;
1825 break;
1826 default:
1827 /* Should never reach here */
1828 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07001829 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001830 }
1831
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001832 micbias_regs->cfilt_sel = cfilt;
1833
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001834 switch (cfilt) {
1835 case TABLA_CFILT1_SEL:
1836 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
1837 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001838 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001839 break;
1840 case TABLA_CFILT2_SEL:
1841 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
1842 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001843 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001844 break;
1845 case TABLA_CFILT3_SEL:
1846 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
1847 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001848 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001849 break;
1850 }
1851}
Santosh Mardie15e2302011-11-15 10:39:23 +05301852static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
1853 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
1854 4, 0, NULL, 0),
1855 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
1856 0, NULL, 0),
1857};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001858
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001859static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
1860 struct snd_kcontrol *kcontrol, int event)
1861{
1862 struct snd_soc_codec *codec = w->codec;
1863
1864 pr_debug("%s %s %d\n", __func__, w->name, event);
1865
1866 switch (event) {
1867 case SND_SOC_DAPM_PRE_PMU:
1868 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1869 break;
1870
1871 case SND_SOC_DAPM_POST_PMD:
1872 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1873 break;
1874 }
1875 return 0;
1876}
1877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001878static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
1879 /*RX stuff */
1880 SND_SOC_DAPM_OUTPUT("EAR"),
1881
Kiran Kandid2d86b52011-09-09 17:44:28 -07001882 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001883
Bradley Rubin229c6a52011-07-12 16:18:48 -07001884 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
1885 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886
Bradley Rubin229c6a52011-07-12 16:18:48 -07001887 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1888 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Santosh Mardie15e2302011-11-15 10:39:23 +05301889 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1890 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001891
1892 /* Headphone */
1893 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001894 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001895 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1896 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001897 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
1898 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001899
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001900 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001901 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1902 SND_SOC_DAPM_POST_PMD),
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001903
1904 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
1905 tabla_hphr_dac_event,
1906 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001907
1908 /* Speaker */
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001909 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
1910 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
1911 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
1912 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
1913 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001914
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001915 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
1916 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1917 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1918 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
1919 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1920 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1921 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
1922 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1923 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1924 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
1925 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1926 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1927 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001928 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1929 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001930
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001931 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
1932 , tabla_lineout_dac_event,
1933 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1934 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
1935 , tabla_lineout_dac_event,
1936 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1937 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
1938 , tabla_lineout_dac_event,
1939 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1940 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
1941 &lineout3_ground_switch),
1942 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
1943 , tabla_lineout_dac_event,
1944 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1945 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
1946 &lineout4_ground_switch),
1947 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
1948 , tabla_lineout_dac_event,
1949 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001950
Bradley Rubin229c6a52011-07-12 16:18:48 -07001951 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
1952 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1953 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
1954 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1955 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
1956 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1957 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
1958 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1959 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
1960 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1961 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
1962 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001963 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
1964 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001965
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001966
1967 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
1968 &rx4_dsm_mux, tabla_codec_reset_interpolator,
1969 SND_SOC_DAPM_PRE_PMU),
1970
1971 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
1972 &rx6_dsm_mux, tabla_codec_reset_interpolator,
1973 SND_SOC_DAPM_PRE_PMU),
1974
Bradley Rubin229c6a52011-07-12 16:18:48 -07001975 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
1976 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
1977
1978 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1979 &rx_mix1_inp1_mux),
1980 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1981 &rx_mix1_inp2_mux),
1982 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1983 &rx2_mix1_inp1_mux),
1984 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1985 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001986 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1987 &rx3_mix1_inp1_mux),
1988 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1989 &rx3_mix1_inp2_mux),
1990 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1991 &rx4_mix1_inp1_mux),
1992 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1993 &rx4_mix1_inp2_mux),
1994 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1995 &rx5_mix1_inp1_mux),
1996 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
1997 &rx5_mix1_inp2_mux),
1998 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
1999 &rx6_mix1_inp1_mux),
2000 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2001 &rx6_mix1_inp2_mux),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002002 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2003 &rx7_mix1_inp1_mux),
2004 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2005 &rx7_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002006
Bradley Rubin229c6a52011-07-12 16:18:48 -07002007 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
2008 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2009 SND_SOC_DAPM_PRE_PMD),
2010
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002011 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2012 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2013 SND_SOC_DAPM_POST_PMD),
2014
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002015 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -07002016
Bradley Rubine1d08622011-07-20 18:01:35 -07002017 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
2018 0),
2019
Bradley Rubin229c6a52011-07-12 16:18:48 -07002020 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
2021 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
2022
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023 SND_SOC_DAPM_INPUT("AMIC1"),
2024 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
2025 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002026 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002027 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
2028 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002029 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002030 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002032 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002033 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
2034 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2035 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2036
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002037 SND_SOC_DAPM_INPUT("AMIC3"),
2038 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
2039 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2040 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2041
2042 SND_SOC_DAPM_INPUT("AMIC4"),
2043 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
2044 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2045 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2046
2047 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
2048 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002049 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002050
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002051 SND_SOC_DAPM_INPUT("AMIC5"),
2052 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
2053 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
2054
2055 SND_SOC_DAPM_INPUT("AMIC6"),
2056 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
2057 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
2058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002059 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 -07002060 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002061
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002062 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 -07002063 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002064
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002065 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 -07002066 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002067
2068 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 -07002069 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002071 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 -07002072 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002073
2074 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 -07002075 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002076
2077 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 -07002078 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002079
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002080 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 -07002081 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002082
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002083 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 -07002084 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002085
2086 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 -07002087 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002088
Bradley Rubin229c6a52011-07-12 16:18:48 -07002089 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
2090 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
2091
2092 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
2093 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
2094 SND_SOC_DAPM_POST_PMD),
2095
2096 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
2097
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098 SND_SOC_DAPM_INPUT("AMIC2"),
2099 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
2100 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002101 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002102 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
2103 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002104 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002105 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
2106 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002107 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002108 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002109 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002110 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
2112 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002113 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002114 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
2115 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002116 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002117 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002119 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002120 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
2121 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2122 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2123
2124 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
2125 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
2126 0, 0),
2127
2128 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
2129 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
2130 4, 0),
2131
2132 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
2133 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
2134 5, 0),
2135
2136 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
2137 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
2138 0, 0),
2139
2140 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
2141 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
2142 0, 0),
2143
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002144 /* Digital Mic Inputs */
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002145 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2146 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2147 SND_SOC_DAPM_POST_PMD),
2148
2149 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2150 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2151 SND_SOC_DAPM_POST_PMD),
2152
2153 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
2154 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2155 SND_SOC_DAPM_POST_PMD),
2156
2157 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
2158 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2159 SND_SOC_DAPM_POST_PMD),
2160
2161 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
2162 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2163 SND_SOC_DAPM_POST_PMD),
2164
2165 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
2166 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2167 SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002168
2169 /* Sidetone */
2170 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2171 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2172};
2173
Santosh Mardie15e2302011-11-15 10:39:23 +05302174static const struct snd_soc_dapm_route audio_i2s_map[] = {
2175 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2176 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2177 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2178 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2179 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2180
2181 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2182 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2183 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2184 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2185};
2186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002187static const struct snd_soc_dapm_route audio_map[] = {
2188 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002189
2190 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2191 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2192
2193 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2194 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2195
2196 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2197 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2198
2199 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2200 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002201 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002202 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2203 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002204 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2205 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002206 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2207 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002208 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2209 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002210
2211 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002212 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2213 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2214 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002215 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002216 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2217 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2218
2219 /* Earpiece (RX MIX1) */
2220 {"EAR", NULL, "EAR PA"},
Kiran Kandiac034ac2011-07-29 16:39:08 -07002221 {"EAR PA", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002222 {"DAC1", NULL, "CP"},
2223
2224 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2225 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2226 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002227
2228 /* Headset (RX MIX1 and RX MIX2) */
2229 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002231
2232 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002234
2235 {"HPHL DAC", NULL, "CP"},
2236 {"HPHR DAC", NULL, "CP"},
2237
2238 {"ANC", NULL, "ANC1 MUX"},
2239 {"ANC", NULL, "ANC2 MUX"},
2240 {"ANC1 MUX", "ADC1", "ADC1"},
2241 {"ANC1 MUX", "ADC2", "ADC2"},
2242 {"ANC1 MUX", "ADC3", "ADC3"},
2243 {"ANC1 MUX", "ADC4", "ADC4"},
2244 {"ANC2 MUX", "ADC1", "ADC1"},
2245 {"ANC2 MUX", "ADC2", "ADC2"},
2246 {"ANC2 MUX", "ADC3", "ADC3"},
2247 {"ANC2 MUX", "ADC4", "ADC4"},
2248
Bradley Rubine1d08622011-07-20 18:01:35 -07002249 {"ANC", NULL, "CDC_CONN"},
2250
Bradley Rubin229c6a52011-07-12 16:18:48 -07002251 {"DAC1", "Switch", "RX1 CHAIN"},
2252 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002253 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002255 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2256 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2257 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2258 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2259 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002260
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002261 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2262 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2263 {"LINEOUT3 PA", NULL, "LINEOUT3 DAC"},
2264 {"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
2265 {"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002266
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002267 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2268 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2269
Bradley Rubin229c6a52011-07-12 16:18:48 -07002270 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2271 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2272 {"RX1 CHAIN", NULL, "ANC"},
2273 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002274
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002275 {"CP", NULL, "RX_BIAS"},
2276 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2277 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2278 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2279 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002280 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002281
Bradley Rubin229c6a52011-07-12 16:18:48 -07002282 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2283 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2284 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2285 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002286 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2287 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2288 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2289 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2290 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2291 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2292 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2293 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002294 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2295 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002296
Bradley Rubin229c6a52011-07-12 16:18:48 -07002297 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2298 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302299 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2300 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002301 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2302 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2303 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302304 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2305 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002306 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2307 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2308 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302309 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2310 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002311 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002312 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2313 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302314 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2315 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002316 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002317 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2318 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302319 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2320 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002321 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002322 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2323 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302324 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2325 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002326 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002327 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2328 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302329 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2330 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002331 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002332 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2333 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302334 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2335 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002336 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002337 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2338 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302339 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2340 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002341 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002342 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2343 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302344 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2345 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002346 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002347 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2348 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302349 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2350 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002351 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002352 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2353 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302354 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2355 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002356 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002357 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2358 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302359 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2360 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002361 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002362 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2363 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302364 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2365 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002366 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002367
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002368 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002369 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002370 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002371 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002372 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002373 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002374 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002375 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002376 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002377 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002378 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002379 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002380 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002381 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002383 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002384 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002385 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002386 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002387 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002388 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002389 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002390 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002391 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002392 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002393 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002394 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002395 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002396
2397 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002398 {"ADC1", NULL, "AMIC1"},
2399 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002400 {"ADC3", NULL, "AMIC3"},
2401 {"ADC4", NULL, "AMIC4"},
2402 {"ADC5", NULL, "AMIC5"},
2403 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002406 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2407 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2408 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2409 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2410 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002411 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002412 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
2413 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
2414 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
2415 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002416
2417 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2418 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2419 {"MIC BIAS1 External", NULL, "LDO_H"},
2420 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2421 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2422 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2423 {"MIC BIAS2 External", NULL, "LDO_H"},
2424 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2425 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2426 {"MIC BIAS3 External", NULL, "LDO_H"},
2427 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002428};
2429
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002430static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
2431
2432 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2433 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2434
2435 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
2436
2437 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
2438 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
2439 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
2440
2441 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2442 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2443
2444 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2445 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
2446 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
2447};
2448
Kiran Kandi7a9fd902011-11-14 13:51:45 -08002449
2450static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
2451
2452 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2453 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2454
2455 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
2456
2457 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
2458
2459 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2460 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2461
2462 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2463};
2464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
2466{
2467 return tabla_reg_readable[reg];
2468}
2469
2470static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2471{
2472 /* Registers lower than 0x100 are top level registers which can be
2473 * written by the Tabla core driver.
2474 */
2475
2476 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2477 return 1;
2478
Ben Romberger1f045a72011-11-04 10:14:57 -07002479 /* IIR Coeff registers are not cacheable */
2480 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
2481 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
2482 return 1;
2483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484 return 0;
2485}
2486
2487#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2488static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
2489 unsigned int value)
2490{
2491 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492
2493 BUG_ON(reg > TABLA_MAX_REGISTER);
2494
2495 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002496 ret = snd_soc_cache_write(codec, reg, value);
2497 if (ret != 0)
2498 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2499 reg, ret);
2500 }
2501
2502 return tabla_reg_write(codec->control_data, reg, value);
2503}
2504static unsigned int tabla_read(struct snd_soc_codec *codec,
2505 unsigned int reg)
2506{
2507 unsigned int val;
2508 int ret;
2509
2510 BUG_ON(reg > TABLA_MAX_REGISTER);
2511
2512 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
2513 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002514 ret = snd_soc_cache_read(codec, reg, &val);
2515 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002516 return val;
2517 } else
2518 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2519 reg, ret);
2520 }
2521
2522 val = tabla_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002523 return val;
2524}
2525
2526static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2527{
2528 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
2529 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2530 0x80);
2531 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
2532 0x04);
2533 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2534 0x01);
2535 usleep_range(1000, 1000);
2536 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2537 0x00);
2538}
2539
2540static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
2541 enum tabla_bandgap_type choice)
2542{
2543 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2544
2545 /* TODO lock resources accessed by audio streams and threaded
2546 * interrupt handlers
2547 */
2548
2549 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
2550 tabla->bandgap_type);
2551
2552 if (tabla->bandgap_type == choice)
2553 return;
2554
2555 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
2556 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2557 tabla_codec_enable_audio_mode_bandgap(codec);
2558 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
2559 (choice == TABLA_BANDGAP_MBHC_MODE)) {
2560 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
2561 0x2);
2562 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2563 0x80);
2564 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
2565 0x4);
2566 usleep_range(1000, 1000);
2567 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2568 0x00);
2569 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
2570 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2571 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2572 usleep_range(100, 100);
2573 tabla_codec_enable_audio_mode_bandgap(codec);
2574 } else if (choice == TABLA_BANDGAP_OFF) {
2575 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2576 } else {
2577 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2578 }
2579 tabla->bandgap_type = choice;
2580}
2581
2582static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
2583 int enable)
2584{
2585 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2586
2587 if (enable) {
2588 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
2589 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
2590 usleep_range(5, 5);
2591 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
2592 0x80);
2593 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
2594 0x80);
2595 usleep_range(10, 10);
2596 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
2597 usleep_range(20, 20);
2598 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
2599 } else {
2600 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
2601 0);
2602 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
2603 }
2604 tabla->config_mode_active = enable ? true : false;
2605
2606 return 0;
2607}
2608
2609static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
2610 int config_mode)
2611{
2612 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2613
2614 pr_debug("%s\n", __func__);
2615
2616 if (config_mode) {
2617 tabla_codec_enable_config_mode(codec, 1);
2618 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
2619 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2620 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
2621 usleep_range(1000, 1000);
2622 } else
2623 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
2624
2625 if (!config_mode && tabla->mbhc_polling_active) {
2626 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2627 tabla_codec_enable_config_mode(codec, 0);
2628
2629 }
2630
2631 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
2632 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
2633 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
2634 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
2635 usleep_range(50, 50);
2636 tabla->clock_active = true;
2637 return 0;
2638}
2639static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
2640{
2641 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2642 pr_debug("%s\n", __func__);
2643 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
2644 ndelay(160);
2645 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
2646 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
2647 tabla->clock_active = false;
2648}
2649
Bradley Rubincb1e2732011-06-23 16:49:20 -07002650static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2651{
Joonwoo Park0976d012011-12-22 11:48:18 -08002652 u8 *n_cic;
2653 struct tabla_mbhc_btn_detect_cfg *btn_det;
2654 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002655
Joonwoo Park0976d012011-12-22 11:48:18 -08002656 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002657
Joonwoo Park0976d012011-12-22 11:48:18 -08002658 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2659 tabla->mbhc_data.v_ins_hu & 0xFF);
2660 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2661 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002662
Joonwoo Park0976d012011-12-22 11:48:18 -08002663 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2664 tabla->mbhc_data.v_b1_hu & 0xFF);
2665 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2666 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
2667
2668 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2669 tabla->mbhc_data.v_b1_h & 0xFF);
2670 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2671 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
2672
2673 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
2674 tabla->mbhc_data.v_brh & 0xFF);
2675 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
2676 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
2677
2678 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
2679 tabla->mbhc_data.v_brl & 0xFF);
2680 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
2681 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
2682
2683 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
2684 tabla->mbhc_data.nready);
2685 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
2686 tabla->mbhc_data.npoll);
2687 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
2688 tabla->mbhc_data.nbounce_wait);
2689
2690 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
2691 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, n_cic[0]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002692}
2693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694static int tabla_startup(struct snd_pcm_substream *substream,
2695 struct snd_soc_dai *dai)
2696{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002697 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2698 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002699
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002700 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701}
2702
2703static void tabla_shutdown(struct snd_pcm_substream *substream,
2704 struct snd_soc_dai *dai)
2705{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002706 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2707 substream->name, substream->stream);
2708}
2709
2710int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
2711{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2713
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002714 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002715
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002716 if (mclk_enable) {
2717 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002718
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002719 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07002720 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002721 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002722 TABLA_BANDGAP_AUDIO_MODE);
2723 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002724 tabla_codec_calibrate_hs_polling(codec);
2725 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002726 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002727 } else {
2728
2729 if (!tabla->mclk_enabled) {
2730 pr_err("Error, MCLK already diabled\n");
2731 return -EINVAL;
2732 }
2733 tabla->mclk_enabled = false;
2734
2735 if (tabla->mbhc_polling_active) {
2736 if (!tabla->mclk_enabled) {
2737 tabla_codec_pause_hs_polling(codec);
2738 tabla_codec_enable_bandgap(codec,
2739 TABLA_BANDGAP_MBHC_MODE);
2740 tabla_enable_rx_bias(codec, 1);
2741 tabla_codec_enable_clock_block(codec, 1);
2742 tabla_codec_calibrate_hs_polling(codec);
2743 tabla_codec_start_hs_polling(codec);
2744 }
2745 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
2746 0x05, 0x01);
2747 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002748 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002749 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002750}
2751
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002752static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
2753 int clk_id, unsigned int freq, int dir)
2754{
2755 pr_debug("%s\n", __func__);
2756 return 0;
2757}
2758
2759static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2760{
Santosh Mardie15e2302011-11-15 10:39:23 +05302761 u8 val = 0;
2762 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
2763
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05302765 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2766 case SND_SOC_DAIFMT_CBS_CFS:
2767 /* CPU is master */
2768 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2769 if (dai->id == TABLA_TX_DAI_ID)
2770 snd_soc_update_bits(dai->codec,
2771 TABLA_A_CDC_CLK_TX_I2S_CTL,
2772 TABLA_I2S_MASTER_MODE_MASK, 0);
2773 else if (dai->id == TABLA_RX_DAI_ID)
2774 snd_soc_update_bits(dai->codec,
2775 TABLA_A_CDC_CLK_RX_I2S_CTL,
2776 TABLA_I2S_MASTER_MODE_MASK, 0);
2777 }
2778 break;
2779 case SND_SOC_DAIFMT_CBM_CFM:
2780 /* CPU is slave */
2781 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2782 val = TABLA_I2S_MASTER_MODE_MASK;
2783 if (dai->id == TABLA_TX_DAI_ID)
2784 snd_soc_update_bits(dai->codec,
2785 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
2786 else if (dai->id == TABLA_RX_DAI_ID)
2787 snd_soc_update_bits(dai->codec,
2788 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
2789 }
2790 break;
2791 default:
2792 return -EINVAL;
2793 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002794 return 0;
2795}
2796
2797static int tabla_hw_params(struct snd_pcm_substream *substream,
2798 struct snd_pcm_hw_params *params,
2799 struct snd_soc_dai *dai)
2800{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002801 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05302802 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07002803 u8 path, shift;
2804 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002805 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
2806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002807 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002808
2809 switch (params_rate(params)) {
2810 case 8000:
2811 tx_fs_rate = 0x00;
2812 rx_fs_rate = 0x00;
2813 break;
2814 case 16000:
2815 tx_fs_rate = 0x01;
2816 rx_fs_rate = 0x20;
2817 break;
2818 case 32000:
2819 tx_fs_rate = 0x02;
2820 rx_fs_rate = 0x40;
2821 break;
2822 case 48000:
2823 tx_fs_rate = 0x03;
2824 rx_fs_rate = 0x60;
2825 break;
2826 default:
2827 pr_err("%s: Invalid sampling rate %d\n", __func__,
2828 params_rate(params));
2829 return -EINVAL;
2830 }
2831
2832
2833 /**
2834 * If current dai is a tx dai, set sample rate to
2835 * all the txfe paths that are currently not active
2836 */
2837 if (dai->id == TABLA_TX_DAI_ID) {
2838
2839 tx_state = snd_soc_read(codec,
2840 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
2841
2842 for (path = 1, shift = 0;
2843 path <= NUM_DECIMATORS; path++, shift++) {
2844
2845 if (path == BITS_PER_REG + 1) {
2846 shift = 0;
2847 tx_state = snd_soc_read(codec,
2848 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
2849 }
2850
2851 if (!(tx_state & (1 << shift))) {
2852 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
2853 + (BITS_PER_REG*(path-1));
2854 snd_soc_update_bits(codec, tx_fs_reg,
2855 0x03, tx_fs_rate);
2856 }
2857 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302858 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2859 switch (params_format(params)) {
2860 case SNDRV_PCM_FORMAT_S16_LE:
2861 snd_soc_update_bits(codec,
2862 TABLA_A_CDC_CLK_TX_I2S_CTL,
2863 0x20, 0x20);
2864 break;
2865 case SNDRV_PCM_FORMAT_S32_LE:
2866 snd_soc_update_bits(codec,
2867 TABLA_A_CDC_CLK_TX_I2S_CTL,
2868 0x20, 0x00);
2869 break;
2870 default:
2871 pr_err("invalid format\n");
2872 break;
2873 }
2874 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
2875 0x03, tx_fs_rate);
2876 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002877 }
2878
2879 /**
2880 * TODO: Need to handle case where same RX chain takes 2 or more inputs
2881 * with varying sample rates
2882 */
2883
2884 /**
2885 * If current dai is a rx dai, set sample rate to
2886 * all the rx paths that are currently not active
2887 */
2888 if (dai->id == TABLA_RX_DAI_ID) {
2889
2890 rx_state = snd_soc_read(codec,
2891 TABLA_A_CDC_CLK_RX_B1_CTL);
2892
2893 for (path = 1, shift = 0;
2894 path <= NUM_INTERPOLATORS; path++, shift++) {
2895
2896 if (!(rx_state & (1 << shift))) {
2897 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
2898 + (BITS_PER_REG*(path-1));
2899 snd_soc_update_bits(codec, rx_fs_reg,
2900 0xE0, rx_fs_rate);
2901 }
2902 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302903 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2904 switch (params_format(params)) {
2905 case SNDRV_PCM_FORMAT_S16_LE:
2906 snd_soc_update_bits(codec,
2907 TABLA_A_CDC_CLK_RX_I2S_CTL,
2908 0x20, 0x20);
2909 break;
2910 case SNDRV_PCM_FORMAT_S32_LE:
2911 snd_soc_update_bits(codec,
2912 TABLA_A_CDC_CLK_RX_I2S_CTL,
2913 0x20, 0x00);
2914 break;
2915 default:
2916 pr_err("invalid format\n");
2917 break;
2918 }
2919 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
2920 0x03, (rx_fs_rate >> 0x05));
2921 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002922 }
2923
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002924 return 0;
2925}
2926
2927static struct snd_soc_dai_ops tabla_dai_ops = {
2928 .startup = tabla_startup,
2929 .shutdown = tabla_shutdown,
2930 .hw_params = tabla_hw_params,
2931 .set_sysclk = tabla_set_dai_sysclk,
2932 .set_fmt = tabla_set_dai_fmt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002933};
2934
2935static struct snd_soc_dai_driver tabla_dai[] = {
2936 {
2937 .name = "tabla_rx1",
2938 .id = 1,
2939 .playback = {
2940 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002941 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002942 .formats = TABLA_FORMATS,
2943 .rate_max = 48000,
2944 .rate_min = 8000,
2945 .channels_min = 1,
2946 .channels_max = 2,
2947 },
2948 .ops = &tabla_dai_ops,
2949 },
2950 {
2951 .name = "tabla_tx1",
2952 .id = 2,
2953 .capture = {
2954 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002955 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002956 .formats = TABLA_FORMATS,
2957 .rate_max = 48000,
2958 .rate_min = 8000,
2959 .channels_min = 1,
2960 .channels_max = 2,
2961 },
2962 .ops = &tabla_dai_ops,
2963 },
2964};
Santosh Mardie15e2302011-11-15 10:39:23 +05302965
2966static struct snd_soc_dai_driver tabla_i2s_dai[] = {
2967 {
2968 .name = "tabla_i2s_rx1",
2969 .id = 1,
2970 .playback = {
2971 .stream_name = "AIF1 Playback",
2972 .rates = WCD9310_RATES,
2973 .formats = TABLA_FORMATS,
2974 .rate_max = 48000,
2975 .rate_min = 8000,
2976 .channels_min = 1,
2977 .channels_max = 4,
2978 },
2979 .ops = &tabla_dai_ops,
2980 },
2981 {
2982 .name = "tabla_i2s_tx1",
2983 .id = 2,
2984 .capture = {
2985 .stream_name = "AIF1 Capture",
2986 .rates = WCD9310_RATES,
2987 .formats = TABLA_FORMATS,
2988 .rate_max = 48000,
2989 .rate_min = 8000,
2990 .channels_min = 1,
2991 .channels_max = 4,
2992 },
2993 .ops = &tabla_dai_ops,
2994 },
2995};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07002996static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07002997{
2998 u8 bias_msb, bias_lsb;
2999 short bias_value;
3000
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003001 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
3002 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
3003 bias_value = (bias_msb << 8) | bias_lsb;
3004 return bias_value;
3005}
3006
3007static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
3008{
3009 u8 bias_msb, bias_lsb;
3010 short bias_value;
3011
3012 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
3013 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
3014 bias_value = (bias_msb << 8) | bias_lsb;
3015 return bias_value;
3016}
3017
Joonwoo Park0976d012011-12-22 11:48:18 -08003018static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003019{
Joonwoo Park0976d012011-12-22 11:48:18 -08003020 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003021 short bias_value;
3022
Bradley Rubincb1e2732011-06-23 16:49:20 -07003023 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003024 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3025 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
3026 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
3027 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08003028 usleep_range(tabla->mbhc_data.t_dce,
3029 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003030 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003031 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003032 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003033 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3034 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003035 usleep_range(50, 50);
Joonwoo Park0976d012011-12-22 11:48:18 -08003036 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3037 usleep_range(tabla->mbhc_data.t_sta,
3038 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003039 bias_value = tabla_codec_read_sta_result(codec);
3040 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3041 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003042 }
3043
Joonwoo Park0976d012011-12-22 11:48:18 -08003044 pr_debug("read microphone bias value %04x\n", bias_value);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003045 return bias_value;
3046}
3047
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003048static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003049{
3050 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003051 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003052 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003053
Joonwoo Park0976d012011-12-22 11:48:18 -08003054 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003055 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07003056 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003057 }
3058
3059 tabla->mbhc_polling_active = true;
3060
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003061 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003062 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003063 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003064 tabla_codec_enable_clock_block(codec, 1);
3065 }
3066
3067 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
3068
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003069 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
3070
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003071 /* Make sure CFILT is in fast mode, save current mode */
3072 cfilt_mode = snd_soc_read(codec,
3073 tabla->mbhc_bias_regs.cfilt_ctl);
3074 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
3075 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07003076
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003077 snd_soc_update_bits(codec,
3078 tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079
3080 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003081 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003082
3083 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
3084 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
3085 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
3086
3087 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003088 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3089 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003090
Bradley Rubincb1e2732011-06-23 16:49:20 -07003091 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x6);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003092 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3093
Bradley Rubincb1e2732011-06-23 16:49:20 -07003094 tabla_codec_calibrate_hs_polling(codec);
3095
Joonwoo Park0976d012011-12-22 11:48:18 -08003096 bias_value = tabla_codec_sta_dce(codec, 0);
3097 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3098 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003099 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003100
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003101 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003102}
3103
3104static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
3105 int insertion)
3106{
3107 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08003109 const struct tabla_mbhc_general_cfg *generic =
3110 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3111 const struct tabla_mbhc_plug_detect_cfg *plug_det =
3112 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003113 u8 wg_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003114
Joonwoo Park0976d012011-12-22 11:48:18 -08003115 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116 pr_err("Error, no tabla calibration\n");
3117 return -EINVAL;
3118 }
3119
3120 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
3121
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003122 if (insertion) {
3123 /* Make sure mic bias and Mic line schmitt trigger
3124 * are turned OFF
3125 */
3126 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
3127 0x81, 0x01);
3128 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3129 0x90, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003130 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
3131 wg_time += 1;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003132
3133 /* Enable HPH Schmitt Trigger */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003134 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003135 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
Joonwoo Park0976d012011-12-22 11:48:18 -08003136 plug_det->hph_current << 2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003137
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003138 /* Turn off HPH PAs and DAC's during insertion detection to
3139 * avoid false insertion interrupts
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003140 */
3141 if (tabla->mbhc_micbias_switched)
3142 tabla_codec_switch_micbias(codec, 0);
3143 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003144 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003145 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003146 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003147 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003148 usleep_range(wg_time * 1000, wg_time * 1000);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003149
3150 /* setup for insetion detection */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003151 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003152 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003153 } else {
3154 /* Make sure the HPH schmitt trigger is OFF */
3155 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3156
3157 /* enable the mic line schmitt trigger */
3158 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08003159 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003160 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3161 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003162 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003163 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3164 0x10, 0x10);
3165
3166 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003167 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003168 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003169
3170 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
3171 if (!(tabla->clock_active)) {
3172 tabla_codec_enable_config_mode(codec, 1);
3173 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003174 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08003175 usleep_range(generic->t_shutdown_plug_rem,
3176 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177 tabla_codec_enable_config_mode(codec, 0);
3178 } else
3179 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003180 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181 }
3182
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003183 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003184
3185 /* If central bandgap disabled */
3186 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
3187 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08003188 usleep_range(generic->t_bg_fast_settle,
3189 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003190 central_bias_enabled = 1;
3191 }
3192
3193 /* If LDO_H disabled */
3194 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
3195 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
3196 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003197 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003198 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
3199
3200 if (central_bias_enabled)
3201 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
3202 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003203
Joonwoo Park0976d012011-12-22 11:48:18 -08003204 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, tabla->micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003205
3206 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3207 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3208 return 0;
3209}
3210
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003211static void tabla_lock_sleep(struct tabla_priv *tabla)
3212{
3213 int ret;
3214 while (!(ret = wait_event_timeout(tabla->pm_wq,
3215 atomic_inc_not_zero(&tabla->pm_cnt),
3216 2 * HZ))) {
3217 pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
3218 __func__, ret, atomic_read(&tabla->pm_cnt));
3219 WARN_ON_ONCE(1);
3220 }
3221}
3222
3223static void tabla_unlock_sleep(struct tabla_priv *tabla)
3224{
3225 atomic_dec(&tabla->pm_cnt);
3226 wake_up(&tabla->pm_wq);
3227}
3228
Joonwoo Park0976d012011-12-22 11:48:18 -08003229static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
3230 s16 vin_mv)
3231{
3232 short diff, zero;
3233 struct tabla_priv *tabla;
3234 u32 mb_mv, in;
3235
3236 tabla = snd_soc_codec_get_drvdata(codec);
3237 mb_mv = tabla->mbhc_data.micb_mv;
3238
3239 if (mb_mv == 0) {
3240 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
3241 return -EINVAL;
3242 }
3243
3244 if (dce) {
3245 diff = tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z;
3246 zero = tabla->mbhc_data.dce_z;
3247 } else {
3248 diff = tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z;
3249 zero = tabla->mbhc_data.sta_z;
3250 }
3251 in = (u32) diff * vin_mv;
3252
3253 return (u16) (in / mb_mv) + zero;
3254}
3255
3256static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
3257 u16 bias_value)
3258{
3259 struct tabla_priv *tabla;
3260 s32 mv;
3261
3262 tabla = snd_soc_codec_get_drvdata(codec);
3263
3264 if (dce) {
3265 mv = ((s32)bias_value - (s32)tabla->mbhc_data.dce_z) *
3266 (s32)tabla->mbhc_data.micb_mv /
3267 (s32)(tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z);
3268 } else {
3269 mv = ((s32)bias_value - (s32)tabla->mbhc_data.sta_z) *
3270 (s32)tabla->mbhc_data.micb_mv /
3271 (s32)(tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z);
3272 }
3273
3274 return mv;
3275}
3276
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003277static void btn0_lpress_fn(struct work_struct *work)
3278{
3279 struct delayed_work *delayed_work;
3280 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08003281 short bias_value;
3282 int dce_mv, sta_mv;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003283
3284 pr_debug("%s:\n", __func__);
3285
3286 delayed_work = to_delayed_work(work);
3287 tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
3288
3289 if (tabla) {
3290 if (tabla->button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003291 bias_value = tabla_codec_read_sta_result(tabla->codec);
3292 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
3293 bias_value);
3294 bias_value = tabla_codec_read_dce_result(tabla->codec);
3295 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
3296 bias_value);
3297 pr_debug("%s: Reporting long button press event"
3298 " STA: %d, DCE: %d\n", __func__,
3299 sta_mv, dce_mv);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003300 tabla_snd_soc_jack_report(tabla, tabla->button_jack,
3301 SND_JACK_BTN_0,
3302 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003303 }
3304 } else {
3305 pr_err("%s: Bad tabla private data\n", __func__);
3306 }
3307
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003308 tabla_unlock_sleep(tabla);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003309}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003310
Joonwoo Park0976d012011-12-22 11:48:18 -08003311void tabla_mbhc_cal(struct snd_soc_codec *codec)
3312{
3313 struct tabla_priv *tabla;
3314 struct tabla_mbhc_btn_detect_cfg *btn_det;
3315 u8 cfilt_mode, bg_mode;
3316 u8 ncic, nmeas, navg;
3317 u32 mclk_rate;
3318 u32 dce_wait, sta_wait;
3319 u8 *n_cic;
3320
3321 tabla = snd_soc_codec_get_drvdata(codec);
3322
3323 /* First compute the DCE / STA wait times
3324 * depending on tunable parameters.
3325 * The value is computed in microseconds
3326 */
3327 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3328 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
3329 ncic = n_cic[0];
3330 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
3331 navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
3332 mclk_rate = tabla->mclk_freq;
3333 dce_wait = (1000 * 512 * ncic * nmeas) / (mclk_rate / 1000);
3334 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
3335 dce_wait = dce_wait + 10000;
3336 else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
3337 dce_wait = dce_wait + 9810;
3338 else
3339 WARN(1, "Unsupported mclk freq %d\n", tabla->mclk_freq);
3340
3341 sta_wait = (1000 * 128 * navg) / (mclk_rate / 1000);
3342
3343 /* Add 10 microseconds to handle error margin */
3344 dce_wait = dce_wait + 10;
3345 sta_wait = sta_wait + 10;
3346
3347 tabla->mbhc_data.t_dce = dce_wait;
3348 tabla->mbhc_data.t_sta = sta_wait;
3349
3350 /* LDOH and CFILT are already configured during pdata handling.
3351 * Only need to make sure CFILT and bandgap are in Fast mode.
3352 * Need to restore defaults once calculation is done.
3353 */
3354 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
3355 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
3356 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
3357 0x02);
3358
3359 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
3360 * to perform ADC calibration
3361 */
3362 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
3363 tabla->micbias << 5);
3364 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
3365 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
3366 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
3367 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
3368
3369 /* DCE measurement for 0 volts */
3370 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3371 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3372 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3373 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3374 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
3375 usleep_range(100, 100);
3376 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3377 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3378 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
3379
3380 /* DCE measurment for MB voltage */
3381 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3382 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3383 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3384 usleep_range(100, 100);
3385 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3386 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3387 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
3388
3389 /* Sta measuremnt for 0 volts */
3390 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3391 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3392 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3393 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3394 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
3395 usleep_range(100, 100);
3396 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3397 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
3398 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
3399
3400 /* STA Measurement for MB Voltage */
3401 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3402 usleep_range(100, 100);
3403 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3404 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
3405 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
3406
3407 /* Restore default settings. */
3408 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3409 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3410 cfilt_mode);
3411 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
3412
3413 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
3414 usleep_range(100, 100);
3415}
3416
3417void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
3418 const enum tabla_mbhc_btn_det_mem mem)
3419{
3420 void *ret = &btn_det->_v_btn_low;
3421
3422 switch (mem) {
3423 case TABLA_BTN_DET_GAIN:
3424 ret += sizeof(btn_det->_n_cic);
3425 case TABLA_BTN_DET_N_CIC:
3426 ret += sizeof(btn_det->_n_ready);
3427 case TABLA_BTN_DET_V_N_READY:
3428 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
3429 case TABLA_BTN_DET_V_BTN_HIGH:
3430 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
3431 case TABLA_BTN_DET_V_BTN_LOW:
3432 /* do nothing */
3433 break;
3434 default:
3435 ret = NULL;
3436 }
3437
3438 return ret;
3439}
3440
3441static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
3442{
3443 struct tabla_priv *tabla;
3444 s16 btn_mv = 0, btn_delta_mv;
3445 struct tabla_mbhc_btn_detect_cfg *btn_det;
3446 struct tabla_mbhc_plug_type_cfg *plug_type;
3447 u16 *btn_high;
3448 int i;
3449
3450 tabla = snd_soc_codec_get_drvdata(codec);
3451 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3452 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
3453
3454 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
3455 tabla->mbhc_data.nready = 3;
3456 tabla->mbhc_data.npoll = 9;
3457 tabla->mbhc_data.nbounce_wait = 30;
3458 } else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
3459 tabla->mbhc_data.nready = 2;
3460 tabla->mbhc_data.npoll = 7;
3461 tabla->mbhc_data.nbounce_wait = 23;
3462 }
3463
3464 tabla->mbhc_data.v_ins_hu =
3465 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
3466 tabla->mbhc_data.v_ins_h =
3467 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
3468
3469 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
3470 for (i = 0; i < btn_det->num_btn; i++)
3471 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
3472
3473 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
3474 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
3475
3476 tabla->mbhc_data.v_b1_hu =
3477 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
3478
3479 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
3480
3481 tabla->mbhc_data.v_b1_huc =
3482 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
3483
3484 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
3485 tabla->mbhc_data.v_brl = 0xFA55;
3486
3487 tabla->mbhc_data.v_no_mic =
3488 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
3489}
3490
3491void tabla_mbhc_init(struct snd_soc_codec *codec)
3492{
3493 struct tabla_priv *tabla;
3494 struct tabla_mbhc_general_cfg *generic;
3495 struct tabla_mbhc_btn_detect_cfg *btn_det;
3496 int n;
3497 u8 tabla_ver;
3498 u8 *n_cic, *gain;
3499
3500 tabla = snd_soc_codec_get_drvdata(codec);
3501 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3502 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3503
3504 tabla_ver = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
3505 tabla_ver &= 0x1F;
3506
3507 for (n = 0; n < 8; n++) {
3508 if ((tabla_ver != TABLA_VERSION_1_0 &&
3509 tabla_ver != TABLA_VERSION_1_1) || n != 7) {
3510 snd_soc_update_bits(codec,
3511 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
3512 0x07, n);
3513 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
3514 btn_det->c[n]);
3515 }
3516 }
3517 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
3518 btn_det->nc);
3519
3520 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
3521 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
3522 n_cic[0]);
3523
3524 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
3525 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78, gain[0] << 3);
3526
3527 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
3528 generic->mbhc_nsa << 4);
3529
3530 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
3531 btn_det->n_meas);
3532
3533 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
3534
3535 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
3536
3537 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
3538 btn_det->mbhc_nsc << 3);
3539
3540 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x03, TABLA_MICBIAS2);
3541
3542 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
3543}
3544
Bradley Rubincb1e2732011-06-23 16:49:20 -07003545int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park0976d012011-12-22 11:48:18 -08003546 struct snd_soc_jack *headset_jack,
3547 struct snd_soc_jack *button_jack,
3548 void *calibration, enum tabla_micbias_num micbias,
3549 int (*mclk_cb_fn) (struct snd_soc_codec*, int),
3550 int read_fw_bin, u32 mclk_rate)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003551{
3552 struct tabla_priv *tabla;
Patrick Lai49efeac2011-11-03 11:01:12 -07003553 int rc;
3554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003555 if (!codec || !calibration) {
3556 pr_err("Error: no codec or calibration\n");
3557 return -EINVAL;
3558 }
3559 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003560 tabla->headset_jack = headset_jack;
3561 tabla->button_jack = button_jack;
Joonwoo Park0976d012011-12-22 11:48:18 -08003562 tabla->micbias = micbias;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003563 tabla->calibration = calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08003564 tabla->mclk_cb = mclk_cb_fn;
3565 tabla->mclk_freq = mclk_rate;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003566 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003567
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003568 /* Put CFILT in fast mode by default */
3569 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
3570 0x40, TABLA_CFILT_FAST_MODE);
3571
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003572 INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
Patrick Lai49efeac2011-11-03 11:01:12 -07003573 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
3574 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
Joonwoo Park0976d012011-12-22 11:48:18 -08003575
3576 if (!read_fw_bin) {
3577 tabla->mclk_cb(codec, 1);
3578 tabla_mbhc_init(codec);
3579 tabla_mbhc_cal(codec);
3580 tabla_mbhc_calc_thres(codec);
3581 tabla->mclk_cb(codec, 0);
3582 tabla_codec_calibrate_hs_polling(codec);
3583 rc = tabla_codec_enable_hs_detect(codec, 1);
3584 } else {
3585 pr_err("%s: MBHC firmware read not supported\n", __func__);
3586 rc = -EINVAL;
3587 }
Patrick Lai49efeac2011-11-03 11:01:12 -07003588
3589 if (!IS_ERR_VALUE(rc)) {
3590 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3591 0x10);
3592 tabla_enable_irq(codec->control_data,
3593 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3594 tabla_enable_irq(codec->control_data,
3595 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3596 }
3597
3598 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003599}
3600EXPORT_SYMBOL_GPL(tabla_hs_detect);
3601
Bradley Rubincb1e2732011-06-23 16:49:20 -07003602static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003603{
3604 struct tabla_priv *priv = data;
3605 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003606 short bias_value;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003607
3608 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3609 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003610 tabla_lock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003611
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003612 bias_value = tabla_codec_read_dce_result(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08003613 pr_debug("%s: button press interrupt, DCE: %d,%d\n",
3614 __func__, bias_value,
3615 tabla_codec_sta_dce_v(codec, 1, bias_value));
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003616
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003617 bias_value = tabla_codec_read_sta_result(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08003618 pr_debug("%s: button press interrupt, STA: %d,%d\n",
3619 __func__, bias_value,
3620 tabla_codec_sta_dce_v(codec, 0, bias_value));
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003621 /*
3622 * TODO: If button pressed is not button 0,
3623 * report the button press event immediately.
3624 */
3625 priv->buttons_pressed |= SND_JACK_BTN_0;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003626
Bradley Rubin688c66a2011-08-16 12:25:13 -07003627 msleep(100);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003628
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003629 if (schedule_delayed_work(&priv->btn0_dwork,
3630 msecs_to_jiffies(400)) == 0) {
3631 WARN(1, "Button pressed twice without release event\n");
3632 tabla_unlock_sleep(priv);
3633 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003634
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003635 return IRQ_HANDLED;
3636}
3637
Bradley Rubincb1e2732011-06-23 16:49:20 -07003638static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003639{
3640 struct tabla_priv *priv = data;
3641 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08003642 int ret, mb_v;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003643
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003644 pr_debug("%s\n", __func__);
3645 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003646 tabla_lock_sleep(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003647
Bradley Rubincb1e2732011-06-23 16:49:20 -07003648 if (priv->buttons_pressed & SND_JACK_BTN_0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003649 ret = cancel_delayed_work(&priv->btn0_dwork);
3650
3651 if (ret == 0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003652 pr_debug("%s: Reporting long button release event\n",
3653 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08003654 if (priv->button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003655 tabla_snd_soc_jack_report(priv,
3656 priv->button_jack, 0,
3657 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003658 } else {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003659 /* if scheduled btn0_dwork is canceled from here,
3660 * we have to unlock from here instead btn0_work */
3661 tabla_unlock_sleep(priv);
Joonwoo Park0976d012011-12-22 11:48:18 -08003662 mb_v = tabla_codec_sta_dce(codec, 0);
3663 pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
3664 __func__, mb_v,
3665 tabla_codec_sta_dce_v(codec, 0, mb_v));
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003666
Joonwoo Park0976d012011-12-22 11:48:18 -08003667 if (mb_v < -2000 || mb_v > -670)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003668 pr_debug("%s: Fake buttton press interrupt\n",
3669 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08003670 else if (priv->button_jack) {
3671 pr_debug("%s:reporting short button "
3672 "press and release\n", __func__);
3673 tabla_snd_soc_jack_report(priv,
3674 priv->button_jack,
3675 SND_JACK_BTN_0,
3676 SND_JACK_BTN_0);
3677 tabla_snd_soc_jack_report(priv,
3678 priv->button_jack,
3679 0, SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003680 }
3681 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003682
Bradley Rubincb1e2732011-06-23 16:49:20 -07003683 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003684 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003685
Bradley Rubin688c66a2011-08-16 12:25:13 -07003686 tabla_codec_start_hs_polling(codec);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003687 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003688 return IRQ_HANDLED;
3689}
3690
Bradley Rubincb1e2732011-06-23 16:49:20 -07003691static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
3692{
3693 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08003694 const struct tabla_mbhc_general_cfg *generic =
3695 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003696
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003697 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003698 tabla_codec_enable_config_mode(codec, 1);
3699
3700 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3701 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003702
Joonwoo Park0976d012011-12-22 11:48:18 -08003703 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
3704
3705 usleep_range(generic->t_shutdown_plug_rem,
3706 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003707
3708 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003709 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003710 tabla_codec_enable_config_mode(codec, 0);
3711
3712 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
3713}
3714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003715static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
3716{
3717 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003718
3719 tabla_codec_shutdown_hs_removal_detect(codec);
3720
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003721 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003722 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
3723 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
3724 tabla_codec_enable_clock_block(codec, 0);
3725 }
3726
3727 tabla->mbhc_polling_active = false;
3728}
3729
Patrick Lai49efeac2011-11-03 11:01:12 -07003730static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
3731{
3732 struct tabla_priv *tabla = data;
3733 struct snd_soc_codec *codec;
3734
3735 pr_info("%s: received HPHL OCP irq\n", __func__);
3736
3737 if (tabla) {
3738 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08003739 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
3740 pr_info("%s: retry\n", __func__);
3741 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3742 0x00);
3743 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3744 0x10);
3745 } else {
3746 tabla_disable_irq(codec->control_data,
3747 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3748 tabla->hphlocp_cnt = 0;
3749 tabla->hph_status |= SND_JACK_OC_HPHL;
3750 if (tabla->headset_jack)
3751 tabla_snd_soc_jack_report(tabla,
3752 tabla->headset_jack,
3753 tabla->hph_status,
3754 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07003755 }
3756 } else {
3757 pr_err("%s: Bad tabla private data\n", __func__);
3758 }
3759
3760 return IRQ_HANDLED;
3761}
3762
3763static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
3764{
3765 struct tabla_priv *tabla = data;
3766 struct snd_soc_codec *codec;
3767
3768 pr_info("%s: received HPHR OCP irq\n", __func__);
3769
3770 if (tabla) {
3771 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08003772 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
3773 pr_info("%s: retry\n", __func__);
3774 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3775 0x00);
3776 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3777 0x10);
3778 } else {
3779 tabla_disable_irq(codec->control_data,
3780 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3781 tabla->hphrocp_cnt = 0;
3782 tabla->hph_status |= SND_JACK_OC_HPHR;
3783 if (tabla->headset_jack)
3784 tabla_snd_soc_jack_report(tabla,
3785 tabla->headset_jack,
3786 tabla->hph_status,
3787 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07003788 }
3789 } else {
3790 pr_err("%s: Bad tabla private data\n", __func__);
3791 }
3792
3793 return IRQ_HANDLED;
3794}
3795
Joonwoo Parka9444452011-12-08 18:48:27 -08003796static void tabla_sync_hph_state(struct tabla_priv *tabla)
3797{
3798 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
3799 &tabla->hph_pa_dac_state)) {
3800 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
3801 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
3802 1 << 4);
3803 }
3804 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
3805 &tabla->hph_pa_dac_state)) {
3806 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
3807 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
3808 1 << 5);
3809 }
3810
3811 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
3812 &tabla->hph_pa_dac_state)) {
3813 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
3814 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
3815 0xC0, 0xC0);
3816 }
3817 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
3818 &tabla->hph_pa_dac_state)) {
3819 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
3820 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
3821 0xC0, 0xC0);
3822 }
3823}
3824
Bradley Rubincb1e2732011-06-23 16:49:20 -07003825static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
3826{
3827 struct tabla_priv *priv = data;
3828 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08003829 const struct tabla_mbhc_plug_detect_cfg *plug_det =
3830 TABLA_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
Bradley Rubin355611a2011-08-24 14:01:18 -07003831 int ldo_h_on, micb_cfilt_on;
Joonwoo Park0976d012011-12-22 11:48:18 -08003832 short mb_v;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003833 u8 is_removal;
Joonwoo Park0976d012011-12-22 11:48:18 -08003834 int mic_mv;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003835
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003836 pr_debug("%s\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003837 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003838 tabla_lock_sleep(priv);
3839
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003840 is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
3841 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
3842
3843 /* Turn off both HPH and MIC line schmitt triggers */
Joonwoo Park0976d012011-12-22 11:48:18 -08003844 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003845 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003846
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003847 if (priv->fake_insert_context) {
3848 pr_debug("%s: fake context interrupt, reset insertion\n",
3849 __func__);
3850 priv->fake_insert_context = false;
3851 tabla_codec_shutdown_hs_polling(codec);
3852 tabla_codec_enable_hs_detect(codec, 1);
3853 return IRQ_HANDLED;
3854 }
3855
Bradley Rubin355611a2011-08-24 14:01:18 -07003856 ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
Joonwoo Park0976d012011-12-22 11:48:18 -08003857 micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
3858 & 0x80;
Bradley Rubin355611a2011-08-24 14:01:18 -07003859
3860 if (!ldo_h_on)
3861 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
3862 if (!micb_cfilt_on)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003863 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08003864 0x80, 0x80);
3865 if (plug_det->t_ins_complete > 20)
3866 msleep(plug_det->t_ins_complete);
3867 else
3868 usleep_range(plug_det->t_ins_complete * 1000,
3869 plug_det->t_ins_complete * 1000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003870
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003871 if (!ldo_h_on)
3872 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
3873 if (!micb_cfilt_on)
3874 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08003875 0x80, 0x0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003876
3877 if (is_removal) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003878 /*
3879 * If headphone is removed while playback is in progress,
3880 * it is possible that micbias will be switched to VDDIO.
3881 */
3882 if (priv->mbhc_micbias_switched)
3883 tabla_codec_switch_micbias(codec, 0);
Patrick Lai72aa4da2011-12-08 12:38:18 -08003884 priv->hph_status &= ~SND_JACK_HEADPHONE;
Joonwoo Parka9444452011-12-08 18:48:27 -08003885
3886 /* If headphone PA is on, check if userspace receives
3887 * removal event to sync-up PA's state */
3888 if (tabla_is_hph_pa_on(codec)) {
3889 set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
3890 set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
3891 }
3892
3893 if (tabla_is_hph_dac_on(codec, 1))
3894 set_bit(TABLA_HPHL_DAC_OFF_ACK,
3895 &priv->hph_pa_dac_state);
3896 if (tabla_is_hph_dac_on(codec, 0))
3897 set_bit(TABLA_HPHR_DAC_OFF_ACK,
3898 &priv->hph_pa_dac_state);
3899
Bradley Rubincb1e2732011-06-23 16:49:20 -07003900 if (priv->headset_jack) {
3901 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003902 tabla_snd_soc_jack_report(priv, priv->headset_jack,
3903 priv->hph_status,
3904 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003905 }
3906 tabla_codec_shutdown_hs_removal_detect(codec);
3907 tabla_codec_enable_hs_detect(codec, 1);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003908 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003909 return IRQ_HANDLED;
3910 }
3911
Joonwoo Park0976d012011-12-22 11:48:18 -08003912 mb_v = tabla_codec_setup_hs_polling(codec);
3913 mic_mv = tabla_codec_sta_dce_v(codec, 0, mb_v);
Bradley Rubin355611a2011-08-24 14:01:18 -07003914
Joonwoo Park0976d012011-12-22 11:48:18 -08003915 if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
3916 pr_debug("%s: Fake insertion interrupt, STA: %d,%d\n",
3917 __func__, mb_v, mic_mv);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003918
3919 /* Disable HPH trigger and enable MIC line trigger */
3920 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3921
3922 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08003923 plug_det->mic_current << 5);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003924 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
Joonwoo Park0976d012011-12-22 11:48:18 -08003925 0x80, 0x80);
3926 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003927 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg,
Joonwoo Park0976d012011-12-22 11:48:18 -08003928 0x10, 0x10);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08003929
3930 /* Setup for insertion detection */
3931 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
3932 priv->fake_insert_context = true;
3933 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3934 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3935
Joonwoo Park0976d012011-12-22 11:48:18 -08003936 } else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
3937 pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
3938 __func__, mb_v, mic_mv);
Patrick Lai49efeac2011-11-03 11:01:12 -07003939 priv->hph_status |= SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003940 if (priv->headset_jack) {
3941 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08003942 SND_JACK_HEADPHONE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003943 tabla_snd_soc_jack_report(priv, priv->headset_jack,
3944 priv->hph_status,
3945 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003946 }
3947 tabla_codec_shutdown_hs_polling(codec);
3948 tabla_codec_enable_hs_detect(codec, 0);
Joonwoo Parka9444452011-12-08 18:48:27 -08003949 tabla_sync_hph_state(priv);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003950 } else {
Joonwoo Park0976d012011-12-22 11:48:18 -08003951 pr_debug("%s: Headset detected, mb_v: %d,%d\n",
3952 __func__, mb_v, mic_mv);
Patrick Lai49efeac2011-11-03 11:01:12 -07003953 priv->hph_status |= SND_JACK_HEADSET;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003954 if (priv->headset_jack) {
3955 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08003956 SND_JACK_HEADSET);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003957 tabla_snd_soc_jack_report(priv, priv->headset_jack,
3958 priv->hph_status,
3959 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003960 }
3961 tabla_codec_start_hs_polling(codec);
Joonwoo Parka9444452011-12-08 18:48:27 -08003962 tabla_sync_hph_state(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003963 }
3964
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003965 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003966 return IRQ_HANDLED;
3967}
3968
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003969static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
3970{
3971 struct tabla_priv *priv = data;
3972 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08003973 const struct tabla_mbhc_general_cfg *generic =
3974 TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003975 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003976
3977 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3978 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003979 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003980 tabla_lock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003981
Joonwoo Park0976d012011-12-22 11:48:18 -08003982 usleep_range(generic->t_shutdown_plug_rem,
3983 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003984
Joonwoo Park0976d012011-12-22 11:48:18 -08003985 bias_value = tabla_codec_sta_dce(codec, 1);
3986 pr_debug("removal interrupt, DCE: %d,%d\n",
3987 bias_value, tabla_codec_sta_dce_v(codec, 1, bias_value));
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003988
Joonwoo Park0976d012011-12-22 11:48:18 -08003989 if (bias_value < (short) priv->mbhc_data.v_ins_h) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003990 pr_debug("False alarm, headset not actually removed\n");
3991 tabla_codec_start_hs_polling(codec);
3992 } else {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003993 /*
3994 * If this removal is not false, first check the micbias
3995 * switch status and switch it to LDOH if it is already
3996 * switched to VDDIO.
3997 */
3998 if (priv->mbhc_micbias_switched)
3999 tabla_codec_switch_micbias(codec, 0);
Patrick Lai49efeac2011-11-03 11:01:12 -07004000 priv->hph_status &= ~SND_JACK_HEADSET;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004001 if (priv->headset_jack) {
4002 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004003 tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
4004 TABLA_JACK_MASK);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004005 }
4006 tabla_codec_shutdown_hs_polling(codec);
4007
4008 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004009 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004010
4011 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004012 return IRQ_HANDLED;
4013}
4014
4015static unsigned long slimbus_value;
4016
4017static irqreturn_t tabla_slimbus_irq(int irq, void *data)
4018{
4019 struct tabla_priv *priv = data;
4020 struct snd_soc_codec *codec = priv->codec;
4021 int i, j;
4022 u8 val;
4023
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004024 tabla_lock_sleep(priv);
4025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004026 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
4027 slimbus_value = tabla_interface_reg_read(codec->control_data,
4028 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
4029 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
4030 val = tabla_interface_reg_read(codec->control_data,
4031 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
4032 if (val & 0x1)
4033 pr_err_ratelimited("overflow error on port %x,"
4034 " value %x\n", i*8 + j, val);
4035 if (val & 0x2)
4036 pr_err_ratelimited("underflow error on port %x,"
4037 " value %x\n", i*8 + j, val);
4038 }
4039 tabla_interface_reg_write(codec->control_data,
4040 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
4041 }
4042
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004043 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004044 return IRQ_HANDLED;
4045}
4046
Patrick Lai3043fba2011-08-01 14:15:57 -07004047
4048static int tabla_handle_pdata(struct tabla_priv *tabla)
4049{
4050 struct snd_soc_codec *codec = tabla->codec;
4051 struct tabla_pdata *pdata = tabla->pdata;
4052 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05304053 u8 leg_mode = pdata->amic_settings.legacy_mode;
4054 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4055 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4056 u8 flag = pdata->amic_settings.use_pdata;
4057 u8 i = 0, j = 0;
4058 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07004059
4060 if (!pdata) {
4061 rc = -ENODEV;
4062 goto done;
4063 }
4064
4065 /* Make sure settings are correct */
4066 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
4067 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
4068 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
4069 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
4070 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
4071 rc = -EINVAL;
4072 goto done;
4073 }
4074
4075 /* figure out k value */
4076 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
4077 pdata->micbias.cfilt1_mv);
4078 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
4079 pdata->micbias.cfilt2_mv);
4080 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
4081 pdata->micbias.cfilt3_mv);
4082
4083 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
4084 rc = -EINVAL;
4085 goto done;
4086 }
4087
4088 /* Set voltage level and always use LDO */
4089 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
4090 (pdata->micbias.ldoh_v << 2));
4091
4092 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
4093 (k1 << 2));
4094 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
4095 (k2 << 2));
4096 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
4097 (k3 << 2));
4098
4099 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
4100 (pdata->micbias.bias1_cfilt_sel << 5));
4101 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
4102 (pdata->micbias.bias2_cfilt_sel << 5));
4103 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
4104 (pdata->micbias.bias3_cfilt_sel << 5));
4105 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
4106 (pdata->micbias.bias4_cfilt_sel << 5));
4107
Santosh Mardi22920282011-10-26 02:38:40 +05304108 for (i = 0; i < 6; j++, i += 2) {
4109 if (flag & (0x01 << i)) {
4110 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
4111 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4112 val_txfe = val_txfe |
4113 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4114 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4115 0x10, value);
4116 snd_soc_update_bits(codec,
4117 TABLA_A_TX_1_2_TEST_EN + j * 10,
4118 0x30, val_txfe);
4119 }
4120 if (flag & (0x01 << (i + 1))) {
4121 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
4122 val_txfe = (txfe_bypass &
4123 (0x01 << (i + 1))) ? 0x02 : 0x00;
4124 val_txfe |= (txfe_buff &
4125 (0x01 << (i + 1))) ? 0x01 : 0x00;
4126 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4127 0x01, value);
4128 snd_soc_update_bits(codec,
4129 TABLA_A_TX_1_2_TEST_EN + j * 10,
4130 0x03, val_txfe);
4131 }
4132 }
4133 if (flag & 0x40) {
4134 value = (leg_mode & 0x40) ? 0x10 : 0x00;
4135 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
4136 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
4137 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
4138 0x13, value);
4139 }
Patrick Lai49efeac2011-11-03 11:01:12 -07004140
4141 if (pdata->ocp.use_pdata) {
4142 /* not defined in CODEC specification */
4143 if (pdata->ocp.hph_ocp_limit == 1 ||
4144 pdata->ocp.hph_ocp_limit == 5) {
4145 rc = -EINVAL;
4146 goto done;
4147 }
4148 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
4149 0x0F, pdata->ocp.num_attempts);
4150 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
4151 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4152 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
4153 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4154 }
Patrick Lai3043fba2011-08-01 14:15:57 -07004155done:
4156 return rc;
4157}
4158
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004159static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
4160
4161 /* Tabla 1.1 MICBIAS changes */
4162 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
4163 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
4164 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
4165 TABLA_REG_VAL(TABLA_A_MICB_4_INT_RBIAS, 0x24),
4166
4167 /* Tabla 1.1 HPH changes */
4168 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
4169 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
4170
4171 /* Tabla 1.1 EAR PA changes */
4172 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
4173 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
4174 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
4175
4176 /* Tabla 1.1 Lineout_5 Changes */
4177 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
4178
4179 /* Tabla 1.1 RX Changes */
4180 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
4181 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
4182 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
4183 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
4184 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
4185 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
4186 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
4187
4188 /* Tabla 1.1 RX1 and RX2 Changes */
4189 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
4190 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
4191
4192 /* Tabla 1.1 RX3 to RX7 Changes */
4193 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
4194 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
4195 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
4196 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
4197 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
4198
4199 /* Tabla 1.1 CLASSG Changes */
4200 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
4201};
4202
4203static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
4204
4205 /* Tabla 2.0 MICBIAS changes */
4206 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
4207};
4208
4209static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
4210{
4211 u32 i;
4212
4213 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
4214 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
4215 tabla_1_1_reg_defaults[i].val);
4216
4217 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
4218 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
4219 tabla_2_0_reg_defaults[i].val);
4220}
4221
4222static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08004223 /* Initialize current threshold to 350MA
4224 * number of wait and run cycles to 4096
4225 */
Patrick Lai49efeac2011-11-03 11:01:12 -07004226 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08004227 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004228
Santosh Mardi32171012011-10-28 23:32:06 +05304229 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
4230
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004231 /* Initialize gain registers to use register gain */
4232 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
4233 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
4234 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
4235 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
4236 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
4237 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
4238
4239 /* Initialize mic biases to differential mode */
4240 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
4241 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
4242 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
4243 {TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24},
4244
4245 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
4246
4247 /* Use 16 bit sample size for TX1 to TX6 */
4248 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
4249 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4250 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4251 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4252 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
4253 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
4254
4255 /* Use 16 bit sample size for TX7 to TX10 */
4256 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
4257 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
4258 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
4259 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
4260
4261 /* Use 16 bit sample size for RX */
4262 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4263 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
4264
4265 /*enable HPF filter for TX paths */
4266 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
4267 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
4268 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
4269 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
4270 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
4271 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
4272 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
4273 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
4274 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
4275 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
4276};
4277
4278static void tabla_codec_init_reg(struct snd_soc_codec *codec)
4279{
4280 u32 i;
4281
4282 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
4283 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
4284 tabla_codec_reg_init_val[i].mask,
4285 tabla_codec_reg_init_val[i].val);
4286}
4287
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004288static int tabla_codec_probe(struct snd_soc_codec *codec)
4289{
4290 struct tabla *control;
4291 struct tabla_priv *tabla;
4292 struct snd_soc_dapm_context *dapm = &codec->dapm;
4293 int ret = 0;
4294 int i;
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004295 u8 tabla_version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004296
4297 codec->control_data = dev_get_drvdata(codec->dev->parent);
4298 control = codec->control_data;
4299
4300 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
4301 if (!tabla) {
4302 dev_err(codec->dev, "Failed to allocate private data\n");
4303 return -ENOMEM;
4304 }
4305
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004306 /* Make sure mbhc micbias register addresses are zeroed out */
4307 memset(&tabla->mbhc_bias_regs, 0,
4308 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004309 tabla->cfilt_k_value = 0;
4310 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004311
Joonwoo Park0976d012011-12-22 11:48:18 -08004312 /* Make sure mbhc intenal calibration data is zeroed out */
4313 memset(&tabla->mbhc_data, 0,
4314 sizeof(struct mbhc_internal_cal_data));
4315 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
4316 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004317 snd_soc_codec_set_drvdata(codec, tabla);
4318
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004319 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004320 tabla->bandgap_type = TABLA_BANDGAP_OFF;
4321 tabla->clock_active = false;
4322 tabla->config_mode_active = false;
4323 tabla->mbhc_polling_active = false;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004324 tabla->fake_insert_context = false;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004325 tabla->no_mic_headset_override = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004326 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07004327 tabla->pdata = dev_get_platdata(codec->dev->parent);
Santosh Mardie15e2302011-11-15 10:39:23 +05304328 tabla->intf_type = tabla_get_intf_type();
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004329 atomic_set(&tabla->pm_cnt, 1);
4330 init_waitqueue_head(&tabla->pm_wq);
Patrick Lai3043fba2011-08-01 14:15:57 -07004331
Santosh Mardi22920282011-10-26 02:38:40 +05304332 tabla_update_reg_defaults(codec);
4333 tabla_codec_init_reg(codec);
Patrick Lai3043fba2011-08-01 14:15:57 -07004334
Santosh Mardi22920282011-10-26 02:38:40 +05304335 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07004336 if (IS_ERR_VALUE(ret)) {
4337 pr_err("%s: bad pdata\n", __func__);
4338 goto err_pdata;
4339 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004340
4341 /* TODO only enable bandgap when necessary in order to save power */
4342 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
4343 tabla_codec_enable_clock_block(codec, 0);
4344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004345 snd_soc_add_controls(codec, tabla_snd_controls,
4346 ARRAY_SIZE(tabla_snd_controls));
4347 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
4348 ARRAY_SIZE(tabla_dapm_widgets));
Santosh Mardie15e2302011-11-15 10:39:23 +05304349 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
4350 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
4351 ARRAY_SIZE(tabla_dapm_i2s_widgets));
4352 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
4353 ARRAY_SIZE(audio_i2s_map));
4354 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004355 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004356
4357 tabla_version = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
Joonwoo Park0976d012011-12-22 11:48:18 -08004358 pr_info("%s : Tabla version reg 0x%2x\n", __func__,
4359 (u32)tabla_version);
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004360
4361 tabla_version &= 0x1F;
4362 pr_info("%s : Tabla version %u\n", __func__, (u32)tabla_version);
4363
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004364 if ((tabla_version == TABLA_VERSION_1_0) ||
4365 (tabla_version == TABLA_VERSION_1_1)) {
4366 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004367 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
4368
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004369 } else if (tabla_version == TABLA_VERSION_2_0) {
4370 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
4371 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
4372 } else {
4373 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
4374 __func__, (u32)tabla_version);
4375 goto err_pdata;
4376 }
4377
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004378 snd_soc_dapm_sync(dapm);
4379
4380 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
4381 tabla_hs_insert_irq, "Headset insert detect", tabla);
4382 if (ret) {
4383 pr_err("%s: Failed to request irq %d\n", __func__,
4384 TABLA_IRQ_MBHC_INSERTION);
4385 goto err_insert_irq;
4386 }
4387 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4388
4389 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
4390 tabla_hs_remove_irq, "Headset remove detect", tabla);
4391 if (ret) {
4392 pr_err("%s: Failed to request irq %d\n", __func__,
4393 TABLA_IRQ_MBHC_REMOVAL);
4394 goto err_remove_irq;
4395 }
4396 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4397
4398 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004399 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004400 if (ret) {
4401 pr_err("%s: Failed to request irq %d\n", __func__,
4402 TABLA_IRQ_MBHC_POTENTIAL);
4403 goto err_potential_irq;
4404 }
4405 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4406
Bradley Rubincb1e2732011-06-23 16:49:20 -07004407 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
4408 tabla_release_handler, "Button Release detect", tabla);
4409 if (ret) {
4410 pr_err("%s: Failed to request irq %d\n", __func__,
4411 TABLA_IRQ_MBHC_RELEASE);
4412 goto err_release_irq;
4413 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004414 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004416 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
4417 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
4418 if (ret) {
4419 pr_err("%s: Failed to request irq %d\n", __func__,
4420 TABLA_IRQ_SLIMBUS);
4421 goto err_slimbus_irq;
4422 }
4423
4424 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
4425 tabla_interface_reg_write(codec->control_data,
4426 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
4427
Patrick Lai49efeac2011-11-03 11:01:12 -07004428 ret = tabla_request_irq(codec->control_data,
4429 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
4430 "HPH_L OCP detect", tabla);
4431 if (ret) {
4432 pr_err("%s: Failed to request irq %d\n", __func__,
4433 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4434 goto err_hphl_ocp_irq;
4435 }
Patrick Lai92032be2011-12-19 14:14:25 -08004436 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004437
4438 ret = tabla_request_irq(codec->control_data,
4439 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
4440 "HPH_R OCP detect", tabla);
4441 if (ret) {
4442 pr_err("%s: Failed to request irq %d\n", __func__,
4443 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4444 goto err_hphr_ocp_irq;
4445 }
Patrick Lai92032be2011-12-19 14:14:25 -08004446 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004447
Bradley Rubincb3950a2011-08-18 13:07:26 -07004448#ifdef CONFIG_DEBUG_FS
4449 debug_tabla_priv = tabla;
4450#endif
4451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004452 return ret;
4453
Patrick Lai49efeac2011-11-03 11:01:12 -07004454err_hphr_ocp_irq:
4455 tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
4456err_hphl_ocp_irq:
4457 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004458err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07004459 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
4460err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004461 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4462err_potential_irq:
4463 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4464err_remove_irq:
4465 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4466err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07004467err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004468 kfree(tabla);
4469 return ret;
4470}
4471static int tabla_codec_remove(struct snd_soc_codec *codec)
4472{
4473 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4474 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004475 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004476 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4477 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4478 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4479 tabla_codec_disable_clock_block(codec);
4480 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
4481 kfree(tabla);
4482 return 0;
4483}
4484static struct snd_soc_codec_driver soc_codec_dev_tabla = {
4485 .probe = tabla_codec_probe,
4486 .remove = tabla_codec_remove,
4487 .read = tabla_read,
4488 .write = tabla_write,
4489
4490 .readable_register = tabla_readable,
4491 .volatile_register = tabla_volatile,
4492
4493 .reg_cache_size = TABLA_CACHE_SIZE,
4494 .reg_cache_default = tabla_reg_defaults,
4495 .reg_word_size = 1,
4496};
Bradley Rubincb3950a2011-08-18 13:07:26 -07004497
4498#ifdef CONFIG_DEBUG_FS
4499static struct dentry *debugfs_poke;
4500
4501static int codec_debug_open(struct inode *inode, struct file *file)
4502{
4503 file->private_data = inode->i_private;
4504 return 0;
4505}
4506
4507static ssize_t codec_debug_write(struct file *filp,
4508 const char __user *ubuf, size_t cnt, loff_t *ppos)
4509{
4510 char lbuf[32];
4511 char *buf;
4512 int rc;
4513
4514 if (cnt > sizeof(lbuf) - 1)
4515 return -EINVAL;
4516
4517 rc = copy_from_user(lbuf, ubuf, cnt);
4518 if (rc)
4519 return -EFAULT;
4520
4521 lbuf[cnt] = '\0';
4522 buf = (char *)lbuf;
4523 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
4524 ? false : true;
4525
4526 return rc;
4527}
4528
4529static const struct file_operations codec_debug_ops = {
4530 .open = codec_debug_open,
4531 .write = codec_debug_write,
4532};
4533#endif
4534
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004535#ifdef CONFIG_PM
4536static int tabla_suspend(struct device *dev)
4537{
4538 int ret = 0, cnt;
4539 struct platform_device *pdev = to_platform_device(dev);
4540 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4541
4542 cnt = atomic_read(&tabla->pm_cnt);
4543 if (cnt > 0) {
4544 if (wait_event_timeout(tabla->pm_wq,
4545 (atomic_cmpxchg(&tabla->pm_cnt, 1, 0)
4546 == 1), 5 * HZ)) {
4547 dev_dbg(dev, "system suspend pm_cnt %d\n",
4548 atomic_read(&tabla->pm_cnt));
4549 } else {
4550 dev_err(dev, "%s timed out pm_cnt = %d\n",
4551 __func__, atomic_read(&tabla->pm_cnt));
4552 WARN_ON_ONCE(1);
4553 ret = -EBUSY;
4554 }
4555 } else if (cnt == 0)
4556 dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
4557 atomic_read(&tabla->pm_cnt));
4558 else {
4559 WARN(1, "unexpected pm_cnt %d\n", cnt);
4560 ret = -EFAULT;
4561 }
4562
4563 return ret;
4564}
4565
4566static int tabla_resume(struct device *dev)
4567{
4568 int ret = 0, cnt;
4569 struct platform_device *pdev = to_platform_device(dev);
4570 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4571
4572 cnt = atomic_cmpxchg(&tabla->pm_cnt, 0, 1);
4573 if (cnt == 0) {
4574 dev_dbg(dev, "system resume, pm_cnt %d\n",
4575 atomic_read(&tabla->pm_cnt));
4576 wake_up_all(&tabla->pm_wq);
4577 } else if (cnt > 0)
4578 dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
4579 else {
4580 WARN(1, "unexpected pm_cnt %d\n", cnt);
4581 ret = -EFAULT;
4582 }
4583
4584 return ret;
4585}
4586
4587static const struct dev_pm_ops tabla_pm_ops = {
4588 .suspend = tabla_suspend,
4589 .resume = tabla_resume,
4590};
4591#endif
4592
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004593static int __devinit tabla_probe(struct platform_device *pdev)
4594{
Santosh Mardie15e2302011-11-15 10:39:23 +05304595 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004596#ifdef CONFIG_DEBUG_FS
4597 debugfs_poke = debugfs_create_file("TRRS",
4598 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
4599
4600#endif
Santosh Mardie15e2302011-11-15 10:39:23 +05304601 if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
4602 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4603 tabla_dai, ARRAY_SIZE(tabla_dai));
4604 else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
4605 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4606 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
4607 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004608}
4609static int __devexit tabla_remove(struct platform_device *pdev)
4610{
4611 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07004612
4613#ifdef CONFIG_DEBUG_FS
4614 debugfs_remove(debugfs_poke);
4615#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004616 return 0;
4617}
4618static struct platform_driver tabla_codec_driver = {
4619 .probe = tabla_probe,
4620 .remove = tabla_remove,
4621 .driver = {
4622 .name = "tabla_codec",
4623 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004624#ifdef CONFIG_PM
4625 .pm = &tabla_pm_ops,
4626#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004627 },
4628};
4629
4630static int __init tabla_codec_init(void)
4631{
4632 return platform_driver_register(&tabla_codec_driver);
4633}
4634
4635static void __exit tabla_codec_exit(void)
4636{
4637 platform_driver_unregister(&tabla_codec_driver);
4638}
4639
4640module_init(tabla_codec_init);
4641module_exit(tabla_codec_exit);
4642
4643MODULE_DESCRIPTION("Tabla codec driver");
4644MODULE_VERSION("1.0");
4645MODULE_LICENSE("GPL v2");