blob: 2bdb9170c7da246b5df7cab387697ce38f5fb933 [file] [log] [blame]
Kiran Kandi3426e512011-09-13 22:50:10 -07001/* Copyright (c) 2011-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
Patrick Lai64b43262011-12-06 17:29:15 -080044#define MBHC_FW_READ_ATTEMPTS 15
45#define MBHC_FW_READ_TIMEOUT 2000000
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070046
Patrick Lai49efeac2011-11-03 11:01:12 -070047#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
48
Santosh Mardie15e2302011-11-15 10:39:23 +053049#define TABLA_I2S_MASTER_MODE_MASK 0x08
50
Patrick Laic7cae882011-11-18 11:52:49 -080051#define TABLA_OCP_ATTEMPT 1
52
Joonwoo Park0976d012011-12-22 11:48:18 -080053#define TABLA_MCLK_RATE_12288KHZ 12288000
54#define TABLA_MCLK_RATE_9600KHZ 9600000
55
Joonwoo Parkf4267c22012-01-10 13:25:24 -080056#define TABLA_FAKE_INS_THRESHOLD_MS 2500
57
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
59static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
60static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
61
62enum tabla_bandgap_type {
63 TABLA_BANDGAP_OFF = 0,
64 TABLA_BANDGAP_AUDIO_MODE,
65 TABLA_BANDGAP_MBHC_MODE,
66};
67
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070068struct mbhc_micbias_regs {
69 u16 cfilt_val;
70 u16 cfilt_ctl;
71 u16 mbhc_reg;
72 u16 int_rbias;
73 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080074 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070075};
76
Ben Romberger1f045a72011-11-04 10:14:57 -070077/* Codec supports 2 IIR filters */
78enum {
79 IIR1 = 0,
80 IIR2,
81 IIR_MAX,
82};
83/* Codec supports 5 bands */
84enum {
85 BAND1 = 0,
86 BAND2,
87 BAND3,
88 BAND4,
89 BAND5,
90 BAND_MAX,
91};
92
Joonwoo Parka9444452011-12-08 18:48:27 -080093/* Flags to track of PA and DAC state.
94 * PA and DAC should be tracked separately as AUXPGA loopback requires
95 * only PA to be turned on without DAC being on. */
96enum tabla_priv_ack_flags {
97 TABLA_HPHL_PA_OFF_ACK = 0,
98 TABLA_HPHR_PA_OFF_ACK,
99 TABLA_HPHL_DAC_OFF_ACK,
100 TABLA_HPHR_DAC_OFF_ACK
101};
102
Joonwoo Park0976d012011-12-22 11:48:18 -0800103/* Data used by MBHC */
104struct mbhc_internal_cal_data {
105 u16 dce_z;
106 u16 dce_mb;
107 u16 sta_z;
108 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800109 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800110 u32 t_dce;
111 u32 t_sta;
112 u32 micb_mv;
113 u16 v_ins_hu;
114 u16 v_ins_h;
115 u16 v_b1_hu;
116 u16 v_b1_h;
117 u16 v_b1_huc;
118 u16 v_brh;
119 u16 v_brl;
120 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800121 u8 npoll;
122 u8 nbounce_wait;
123};
124
Bradley Rubin229c6a52011-07-12 16:18:48 -0700125struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126 struct snd_soc_codec *codec;
Joonwoo Park0976d012011-12-22 11:48:18 -0800127 u32 mclk_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700128 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700129 u32 cfilt1_cnt;
130 u32 cfilt2_cnt;
131 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700132 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700133 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700134 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 bool clock_active;
136 bool config_mode_active;
137 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800138 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700139 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140
Joonwoo Park0976d012011-12-22 11:48:18 -0800141 enum tabla_micbias_num micbias;
142 /* void* calibration contains:
143 * struct tabla_mbhc_general_cfg generic;
144 * struct tabla_mbhc_plug_detect_cfg plug_det;
145 * struct tabla_mbhc_plug_type_cfg plug_type;
146 * struct tabla_mbhc_btn_detect_cfg btn_det;
147 * struct tabla_mbhc_imped_detect_cfg imped_det;
148 * Note: various size depends on btn_det->num_btn
149 */
150 void *calibration;
151 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152
Bradley Rubincb1e2732011-06-23 16:49:20 -0700153 struct snd_soc_jack *headset_jack;
154 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700155
Patrick Lai3043fba2011-08-01 14:15:57 -0700156 struct tabla_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700157 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700158
159 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700160 /* Delayed work to report long button press */
161 struct delayed_work btn0_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700162
163 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700164 u8 cfilt_k_value;
165 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700166
Joonwoo Parka9444452011-12-08 18:48:27 -0800167 /* track PA/DAC state */
168 unsigned long hph_pa_dac_state;
169
Santosh Mardie15e2302011-11-15 10:39:23 +0530170 /*track tabla interface type*/
171 u8 intf_type;
172
Patrick Lai49efeac2011-11-03 11:01:12 -0700173 u32 hph_status; /* track headhpone status */
174 /* define separate work for left and right headphone OCP to avoid
175 * additional checking on which OCP event to report so no locking
176 * to ensure synchronization is required
177 */
178 struct work_struct hphlocp_work; /* reporting left hph ocp off */
179 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800180
181 /* pm_cnt holds number of sleep lock holders + 1
182 * so if pm_cnt is 1 system is sleep-able. */
183 atomic_t pm_cnt;
184 wait_queue_head_t pm_wq;
Patrick Laic7cae882011-11-18 11:52:49 -0800185
186 u8 hphlocp_cnt; /* headphone left ocp retry */
187 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800188
189 /* Callback function to enable MCLK */
190 int (*mclk_cb) (struct snd_soc_codec*, int);
Patrick Lai64b43262011-12-06 17:29:15 -0800191
192 /* Work to perform MBHC Firmware Read */
193 struct delayed_work mbhc_firmware_dwork;
194 const struct firmware *mbhc_fw;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195};
196
Bradley Rubincb3950a2011-08-18 13:07:26 -0700197#ifdef CONFIG_DEBUG_FS
198struct tabla_priv *debug_tabla_priv;
199#endif
200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
202 struct snd_kcontrol *kcontrol, int event)
203{
204 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700205
206 pr_debug("%s %d\n", __func__, event);
207 switch (event) {
208 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700209 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
210 0x01);
211 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
212 usleep_range(200, 200);
213 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
214 break;
215 case SND_SOC_DAPM_PRE_PMD:
216 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
217 0x10);
218 usleep_range(20, 20);
219 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
220 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
221 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
222 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
223 0x00);
224 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225 break;
226 }
227 return 0;
228}
229
Bradley Rubina7096d02011-08-03 18:29:02 -0700230static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
231 struct snd_ctl_elem_value *ucontrol)
232{
233 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
234 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
235 ucontrol->value.integer.value[0] = tabla->anc_slot;
236 return 0;
237}
238
239static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
240 struct snd_ctl_elem_value *ucontrol)
241{
242 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
243 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
244 tabla->anc_slot = ucontrol->value.integer.value[0];
245 return 0;
246}
247
Kiran Kandid2d86b52011-09-09 17:44:28 -0700248static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
249 struct snd_ctl_elem_value *ucontrol)
250{
251 u8 ear_pa_gain;
252 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
253
254 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
255
256 ear_pa_gain = ear_pa_gain >> 5;
257
258 if (ear_pa_gain == 0x00) {
259 ucontrol->value.integer.value[0] = 0;
260 } else if (ear_pa_gain == 0x04) {
261 ucontrol->value.integer.value[0] = 1;
262 } else {
263 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
264 __func__, ear_pa_gain);
265 return -EINVAL;
266 }
267
268 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
269
270 return 0;
271}
272
273static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
274 struct snd_ctl_elem_value *ucontrol)
275{
276 u8 ear_pa_gain;
277 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
278
279 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
280 ucontrol->value.integer.value[0]);
281
282 switch (ucontrol->value.integer.value[0]) {
283 case 0:
284 ear_pa_gain = 0x00;
285 break;
286 case 1:
287 ear_pa_gain = 0x80;
288 break;
289 default:
290 return -EINVAL;
291 }
292
293 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
294 return 0;
295}
296
Ben Romberger1f045a72011-11-04 10:14:57 -0700297static int tabla_get_iir_enable_audio_mixer(
298 struct snd_kcontrol *kcontrol,
299 struct snd_ctl_elem_value *ucontrol)
300{
301 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
302 int iir_idx = ((struct soc_multi_mixer_control *)
303 kcontrol->private_value)->reg;
304 int band_idx = ((struct soc_multi_mixer_control *)
305 kcontrol->private_value)->shift;
306
307 ucontrol->value.integer.value[0] =
308 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
309 (1 << band_idx);
310
311 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
312 iir_idx, band_idx,
313 (uint32_t)ucontrol->value.integer.value[0]);
314 return 0;
315}
316
317static int tabla_put_iir_enable_audio_mixer(
318 struct snd_kcontrol *kcontrol,
319 struct snd_ctl_elem_value *ucontrol)
320{
321 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
322 int iir_idx = ((struct soc_multi_mixer_control *)
323 kcontrol->private_value)->reg;
324 int band_idx = ((struct soc_multi_mixer_control *)
325 kcontrol->private_value)->shift;
326 int value = ucontrol->value.integer.value[0];
327
328 /* Mask first 5 bits, 6-8 are reserved */
329 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
330 (1 << band_idx), (value << band_idx));
331
332 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
333 iir_idx, band_idx, value);
334 return 0;
335}
336static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
337 int iir_idx, int band_idx,
338 int coeff_idx)
339{
340 /* Address does not automatically update if reading */
341 snd_soc_update_bits(codec,
342 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
343 0x1F, band_idx * BAND_MAX + coeff_idx);
344
345 /* Mask bits top 2 bits since they are reserved */
346 return ((snd_soc_read(codec,
347 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
348 (snd_soc_read(codec,
349 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
350 (snd_soc_read(codec,
351 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
352 (snd_soc_read(codec,
353 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
354 0x3FFFFFFF;
355}
356
357static int tabla_get_iir_band_audio_mixer(
358 struct snd_kcontrol *kcontrol,
359 struct snd_ctl_elem_value *ucontrol)
360{
361 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
362 int iir_idx = ((struct soc_multi_mixer_control *)
363 kcontrol->private_value)->reg;
364 int band_idx = ((struct soc_multi_mixer_control *)
365 kcontrol->private_value)->shift;
366
367 ucontrol->value.integer.value[0] =
368 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
369 ucontrol->value.integer.value[1] =
370 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
371 ucontrol->value.integer.value[2] =
372 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
373 ucontrol->value.integer.value[3] =
374 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
375 ucontrol->value.integer.value[4] =
376 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
377
378 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
379 "%s: IIR #%d band #%d b1 = 0x%x\n"
380 "%s: IIR #%d band #%d b2 = 0x%x\n"
381 "%s: IIR #%d band #%d a1 = 0x%x\n"
382 "%s: IIR #%d band #%d a2 = 0x%x\n",
383 __func__, iir_idx, band_idx,
384 (uint32_t)ucontrol->value.integer.value[0],
385 __func__, iir_idx, band_idx,
386 (uint32_t)ucontrol->value.integer.value[1],
387 __func__, iir_idx, band_idx,
388 (uint32_t)ucontrol->value.integer.value[2],
389 __func__, iir_idx, band_idx,
390 (uint32_t)ucontrol->value.integer.value[3],
391 __func__, iir_idx, band_idx,
392 (uint32_t)ucontrol->value.integer.value[4]);
393 return 0;
394}
395
396static void set_iir_band_coeff(struct snd_soc_codec *codec,
397 int iir_idx, int band_idx,
398 int coeff_idx, uint32_t value)
399{
400 /* Mask top 3 bits, 6-8 are reserved */
401 /* Update address manually each time */
402 snd_soc_update_bits(codec,
403 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
404 0x1F, band_idx * BAND_MAX + coeff_idx);
405
406 /* Mask top 2 bits, 7-8 are reserved */
407 snd_soc_update_bits(codec,
408 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
409 0x3F, (value >> 24) & 0x3F);
410
411 /* Isolate 8bits at a time */
412 snd_soc_update_bits(codec,
413 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
414 0xFF, (value >> 16) & 0xFF);
415
416 snd_soc_update_bits(codec,
417 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
418 0xFF, (value >> 8) & 0xFF);
419
420 snd_soc_update_bits(codec,
421 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
422 0xFF, value & 0xFF);
423}
424
425static int tabla_put_iir_band_audio_mixer(
426 struct snd_kcontrol *kcontrol,
427 struct snd_ctl_elem_value *ucontrol)
428{
429 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
430 int iir_idx = ((struct soc_multi_mixer_control *)
431 kcontrol->private_value)->reg;
432 int band_idx = ((struct soc_multi_mixer_control *)
433 kcontrol->private_value)->shift;
434
435 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
436 ucontrol->value.integer.value[0]);
437 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
438 ucontrol->value.integer.value[1]);
439 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
440 ucontrol->value.integer.value[2]);
441 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
442 ucontrol->value.integer.value[3]);
443 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
444 ucontrol->value.integer.value[4]);
445
446 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
447 "%s: IIR #%d band #%d b1 = 0x%x\n"
448 "%s: IIR #%d band #%d b2 = 0x%x\n"
449 "%s: IIR #%d band #%d a1 = 0x%x\n"
450 "%s: IIR #%d band #%d a2 = 0x%x\n",
451 __func__, iir_idx, band_idx,
452 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
453 __func__, iir_idx, band_idx,
454 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
455 __func__, iir_idx, band_idx,
456 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
457 __func__, iir_idx, band_idx,
458 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
459 __func__, iir_idx, band_idx,
460 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
461 return 0;
462}
463
Kiran Kandid2d86b52011-09-09 17:44:28 -0700464static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
465static const struct soc_enum tabla_ear_pa_gain_enum[] = {
466 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
467};
468
Santosh Mardi024010f2011-10-18 06:27:21 +0530469/*cut of frequency for high pass filter*/
470static const char *cf_text[] = {
471 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
472};
473
474static const struct soc_enum cf_dec1_enum =
475 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
476
477static const struct soc_enum cf_dec2_enum =
478 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
479
480static const struct soc_enum cf_dec3_enum =
481 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
482
483static const struct soc_enum cf_dec4_enum =
484 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
485
486static const struct soc_enum cf_dec5_enum =
487 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
488
489static const struct soc_enum cf_dec6_enum =
490 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
491
492static const struct soc_enum cf_dec7_enum =
493 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
494
495static const struct soc_enum cf_dec8_enum =
496 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
497
498static const struct soc_enum cf_dec9_enum =
499 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
500
501static const struct soc_enum cf_dec10_enum =
502 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
503
504static const struct soc_enum cf_rxmix1_enum =
505 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
506
507static const struct soc_enum cf_rxmix2_enum =
508 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
509
510static const struct soc_enum cf_rxmix3_enum =
511 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
512
513static const struct soc_enum cf_rxmix4_enum =
514 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
515
516static const struct soc_enum cf_rxmix5_enum =
517 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
518;
519static const struct soc_enum cf_rxmix6_enum =
520 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
521
522static const struct soc_enum cf_rxmix7_enum =
523 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700525static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700526
527 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
528 tabla_pa_gain_get, tabla_pa_gain_put),
529
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700530 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
531 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700532 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
533 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
535 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700536 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
537 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700538 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
539 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
542 line_gain),
543 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
544 line_gain),
545
Bradley Rubin410383f2011-07-22 13:44:23 -0700546 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
547 -84, 40, digital_gain),
548 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
549 -84, 40, digital_gain),
550 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
551 -84, 40, digital_gain),
552 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
553 -84, 40, digital_gain),
554 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
555 -84, 40, digital_gain),
556 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
557 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558
Bradley Rubin410383f2011-07-22 13:44:23 -0700559 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700561 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700563 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
564 digital_gain),
565 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
566 digital_gain),
567 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
568 digital_gain),
569 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
570 digital_gain),
571 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
572 digital_gain),
573 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
574 digital_gain),
575 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
576 digital_gain),
577 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
578 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700579 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
580 40, digital_gain),
581 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
582 40, digital_gain),
583 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
584 40, digital_gain),
585 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
586 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700587 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
588 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700589 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
590 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700591 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
592 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700593
594 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800595 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700596 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
597 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_A_MICB_4_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700598
599 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
600 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530601 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
602 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
603 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
604 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
605 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
606 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
607 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
608 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
609 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
610 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
611
612 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
613 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
614 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
615 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
616 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
617 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
618 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
619 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
620 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
621 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
622
623 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
624 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
625 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
626 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
627 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
628 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
629 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
630
631 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
632 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
633 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
634 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
635 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
636 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
637 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700638
639 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
640 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
641 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
642 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
643 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
644 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
645 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
646 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
647 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
648 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
649 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
650 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
651 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
652 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
653 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
654 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
655 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
656 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
657 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
658 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
659
660 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
661 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
662 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
663 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
664 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
665 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
666 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
667 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
668 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
669 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
670 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
671 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
672 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
673 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
674 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
675 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
676 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
677 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
678 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
679 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700680};
681
682static const char *rx_mix1_text[] = {
683 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
684 "RX5", "RX6", "RX7"
685};
686
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700687static const char *rx_dsm_text[] = {
688 "CIC_OUT", "DSM_INV"
689};
690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691static const char *sb_tx1_mux_text[] = {
692 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
693 "DEC1"
694};
695
696static const char *sb_tx5_mux_text[] = {
697 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
698 "DEC5"
699};
700
701static const char *sb_tx6_mux_text[] = {
702 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
703 "DEC6"
704};
705
706static const char const *sb_tx7_to_tx10_mux_text[] = {
707 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
708 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
709 "DEC9", "DEC10"
710};
711
712static const char *dec1_mux_text[] = {
713 "ZERO", "DMIC1", "ADC6",
714};
715
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700716static const char *dec2_mux_text[] = {
717 "ZERO", "DMIC2", "ADC5",
718};
719
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700720static const char *dec3_mux_text[] = {
721 "ZERO", "DMIC3", "ADC4",
722};
723
724static const char *dec4_mux_text[] = {
725 "ZERO", "DMIC4", "ADC3",
726};
727
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728static const char *dec5_mux_text[] = {
729 "ZERO", "DMIC5", "ADC2",
730};
731
732static const char *dec6_mux_text[] = {
733 "ZERO", "DMIC6", "ADC1",
734};
735
736static const char const *dec7_mux_text[] = {
737 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
738};
739
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700740static const char *dec8_mux_text[] = {
741 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
742};
743
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700744static const char *dec9_mux_text[] = {
745 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
746};
747
748static const char *dec10_mux_text[] = {
749 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
750};
751
Bradley Rubin229c6a52011-07-12 16:18:48 -0700752static const char const *anc_mux_text[] = {
753 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
754 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
755};
756
757static const char const *anc1_fb_mux_text[] = {
758 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
759};
760
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700761static const char *iir1_inp1_text[] = {
762 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
763 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
764};
765
766static const struct soc_enum rx_mix1_inp1_chain_enum =
767 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
768
Bradley Rubin229c6a52011-07-12 16:18:48 -0700769static const struct soc_enum rx_mix1_inp2_chain_enum =
770 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
771
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700772static const struct soc_enum rx2_mix1_inp1_chain_enum =
773 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
774
Bradley Rubin229c6a52011-07-12 16:18:48 -0700775static const struct soc_enum rx2_mix1_inp2_chain_enum =
776 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
777
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700778static const struct soc_enum rx3_mix1_inp1_chain_enum =
779 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
780
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700781static const struct soc_enum rx3_mix1_inp2_chain_enum =
782 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
783
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700784static const struct soc_enum rx4_mix1_inp1_chain_enum =
785 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
786
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700787static const struct soc_enum rx4_mix1_inp2_chain_enum =
788 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
789
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790static const struct soc_enum rx5_mix1_inp1_chain_enum =
791 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
792
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700793static const struct soc_enum rx5_mix1_inp2_chain_enum =
794 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
795
796static const struct soc_enum rx6_mix1_inp1_chain_enum =
797 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
798
799static const struct soc_enum rx6_mix1_inp2_chain_enum =
800 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
801
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700802static const struct soc_enum rx7_mix1_inp1_chain_enum =
803 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
804
805static const struct soc_enum rx7_mix1_inp2_chain_enum =
806 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
807
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700808static const struct soc_enum rx4_dsm_enum =
809 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
810
811static const struct soc_enum rx6_dsm_enum =
812 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
813
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814static const struct soc_enum sb_tx5_mux_enum =
815 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
816
817static const struct soc_enum sb_tx6_mux_enum =
818 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
819
820static const struct soc_enum sb_tx7_mux_enum =
821 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
822 sb_tx7_to_tx10_mux_text);
823
824static const struct soc_enum sb_tx8_mux_enum =
825 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
826 sb_tx7_to_tx10_mux_text);
827
Kiran Kandi3426e512011-09-13 22:50:10 -0700828static const struct soc_enum sb_tx9_mux_enum =
829 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
830 sb_tx7_to_tx10_mux_text);
831
832static const struct soc_enum sb_tx10_mux_enum =
833 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
834 sb_tx7_to_tx10_mux_text);
835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836static const struct soc_enum sb_tx1_mux_enum =
837 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
838
839static const struct soc_enum dec1_mux_enum =
840 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
841
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700842static const struct soc_enum dec2_mux_enum =
843 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
844
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700845static const struct soc_enum dec3_mux_enum =
846 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
847
848static const struct soc_enum dec4_mux_enum =
849 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851static const struct soc_enum dec5_mux_enum =
852 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
853
854static const struct soc_enum dec6_mux_enum =
855 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
856
857static const struct soc_enum dec7_mux_enum =
858 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
859
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700860static const struct soc_enum dec8_mux_enum =
861 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
862
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700863static const struct soc_enum dec9_mux_enum =
864 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
865
866static const struct soc_enum dec10_mux_enum =
867 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
868
Bradley Rubin229c6a52011-07-12 16:18:48 -0700869static const struct soc_enum anc1_mux_enum =
870 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
871
872static const struct soc_enum anc2_mux_enum =
873 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
874
875static const struct soc_enum anc1_fb_mux_enum =
876 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878static const struct soc_enum iir1_inp1_mux_enum =
879 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
880
881static const struct snd_kcontrol_new rx_mix1_inp1_mux =
882 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
883
Bradley Rubin229c6a52011-07-12 16:18:48 -0700884static const struct snd_kcontrol_new rx_mix1_inp2_mux =
885 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
886
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
888 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
889
Bradley Rubin229c6a52011-07-12 16:18:48 -0700890static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
891 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
892
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700893static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
894 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
895
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700896static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
897 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
898
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
900 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
901
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700902static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
903 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
904
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700905static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
906 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
907
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700908static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
909 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
910
911static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
912 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
913
914static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
915 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
916
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700917static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
918 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
919
920static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
921 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
922
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700923static const struct snd_kcontrol_new rx4_dsm_mux =
924 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
925
926static const struct snd_kcontrol_new rx6_dsm_mux =
927 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
928
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929static const struct snd_kcontrol_new sb_tx5_mux =
930 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
931
932static const struct snd_kcontrol_new sb_tx6_mux =
933 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
934
935static const struct snd_kcontrol_new sb_tx7_mux =
936 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
937
938static const struct snd_kcontrol_new sb_tx8_mux =
939 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
940
Kiran Kandi3426e512011-09-13 22:50:10 -0700941static const struct snd_kcontrol_new sb_tx9_mux =
942 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
943
944static const struct snd_kcontrol_new sb_tx10_mux =
945 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
946
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947static const struct snd_kcontrol_new sb_tx1_mux =
948 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
949
950static const struct snd_kcontrol_new dec1_mux =
951 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
952
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700953static const struct snd_kcontrol_new dec2_mux =
954 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
955
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700956static const struct snd_kcontrol_new dec3_mux =
957 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
958
959static const struct snd_kcontrol_new dec4_mux =
960 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
961
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700962static const struct snd_kcontrol_new dec5_mux =
963 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
964
965static const struct snd_kcontrol_new dec6_mux =
966 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
967
968static const struct snd_kcontrol_new dec7_mux =
969 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
970
Bradley Rubin229c6a52011-07-12 16:18:48 -0700971static const struct snd_kcontrol_new anc1_mux =
972 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700973static const struct snd_kcontrol_new dec8_mux =
974 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
975
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700976static const struct snd_kcontrol_new dec9_mux =
977 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
978
979static const struct snd_kcontrol_new dec10_mux =
980 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
981
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982static const struct snd_kcontrol_new iir1_inp1_mux =
983 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
984
Bradley Rubin229c6a52011-07-12 16:18:48 -0700985static const struct snd_kcontrol_new anc2_mux =
986 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987
Bradley Rubin229c6a52011-07-12 16:18:48 -0700988static const struct snd_kcontrol_new anc1_fb_mux =
989 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990
Bradley Rubin229c6a52011-07-12 16:18:48 -0700991static const struct snd_kcontrol_new dac1_switch[] = {
992 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
993};
994static const struct snd_kcontrol_new hphl_switch[] = {
995 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
996};
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700997
998static const struct snd_kcontrol_new lineout3_ground_switch =
999 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1000
1001static const struct snd_kcontrol_new lineout4_ground_switch =
1002 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
1005 int enable)
1006{
1007 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1008
1009 pr_debug("%s %d\n", __func__, enable);
1010
1011 if (enable) {
1012 tabla->adc_count++;
1013 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1014 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1015 } else {
1016 tabla->adc_count--;
1017 if (!tabla->adc_count) {
1018 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
1019 0x2, 0x0);
1020 if (!tabla->mbhc_polling_active)
1021 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
1022 0xE0, 0x0);
1023 }
1024 }
1025}
1026
1027static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1028 struct snd_kcontrol *kcontrol, int event)
1029{
1030 struct snd_soc_codec *codec = w->codec;
1031 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001032 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033
1034 pr_debug("%s %d\n", __func__, event);
1035
1036 if (w->reg == TABLA_A_TX_1_2_EN)
1037 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1038 else if (w->reg == TABLA_A_TX_3_4_EN)
1039 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1040 else if (w->reg == TABLA_A_TX_5_6_EN)
1041 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1042 else {
1043 pr_err("%s: Error, invalid adc register\n", __func__);
1044 return -EINVAL;
1045 }
1046
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001047 if (w->shift == 3)
1048 init_bit_shift = 6;
1049 else if (w->shift == 7)
1050 init_bit_shift = 7;
1051 else {
1052 pr_err("%s: Error, invalid init bit postion adc register\n",
1053 __func__);
1054 return -EINVAL;
1055 }
1056
1057
1058
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001059 switch (event) {
1060 case SND_SOC_DAPM_PRE_PMU:
1061 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001062 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1063 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064 break;
1065 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001066
1067 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1068
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069 break;
1070 case SND_SOC_DAPM_POST_PMD:
1071 tabla_codec_enable_adc_block(codec, 0);
1072 break;
1073 }
1074 return 0;
1075}
1076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001077static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1078 struct snd_kcontrol *kcontrol, int event)
1079{
1080 struct snd_soc_codec *codec = w->codec;
1081 u16 lineout_gain_reg;
1082
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001083 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084
1085 switch (w->shift) {
1086 case 0:
1087 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1088 break;
1089 case 1:
1090 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1091 break;
1092 case 2:
1093 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1094 break;
1095 case 3:
1096 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1097 break;
1098 case 4:
1099 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1100 break;
1101 default:
1102 pr_err("%s: Error, incorrect lineout register value\n",
1103 __func__);
1104 return -EINVAL;
1105 }
1106
1107 switch (event) {
1108 case SND_SOC_DAPM_PRE_PMU:
1109 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1110 break;
1111 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001112 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001113 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001114 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 break;
1116 case SND_SOC_DAPM_POST_PMD:
1117 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1118 break;
1119 }
1120 return 0;
1121}
1122
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001123
1124static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 struct snd_kcontrol *kcontrol, int event)
1126{
1127 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001128 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1129 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001130 unsigned int dmic;
1131 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001132
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001133 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1134 if (ret < 0) {
1135 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001136 return -EINVAL;
1137 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001139 switch (dmic) {
1140 case 1:
1141 case 2:
1142 dmic_clk_sel = 0x02;
1143 dmic_clk_en = 0x01;
1144 break;
1145
1146 case 3:
1147 case 4:
1148 dmic_clk_sel = 0x08;
1149 dmic_clk_en = 0x04;
1150 break;
1151
1152 case 5:
1153 case 6:
1154 dmic_clk_sel = 0x20;
1155 dmic_clk_en = 0x10;
1156 break;
1157
1158 default:
1159 pr_err("%s: Invalid DMIC Selection\n", __func__);
1160 return -EINVAL;
1161 }
1162
1163 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1164 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1165
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 switch (event) {
1169 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001170 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1171
1172 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1173 dmic_clk_sel, dmic_clk_sel);
1174
1175 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1176
1177 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1178 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 break;
1180 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001181 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1182 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001183 break;
1184 }
1185 return 0;
1186}
1187
Bradley Rubin229c6a52011-07-12 16:18:48 -07001188static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1189 struct snd_kcontrol *kcontrol, int event)
1190{
1191 struct snd_soc_codec *codec = w->codec;
1192 const char *filename;
1193 const struct firmware *fw;
1194 int i;
1195 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001196 int num_anc_slots;
1197 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001198 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001199 u32 anc_writes_size = 0;
1200 int anc_size_remaining;
1201 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001202 u16 reg;
1203 u8 mask, val, old_val;
1204
1205 pr_debug("%s %d\n", __func__, event);
1206 switch (event) {
1207 case SND_SOC_DAPM_PRE_PMU:
1208
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001209 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001210
1211 ret = request_firmware(&fw, filename, codec->dev);
1212 if (ret != 0) {
1213 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1214 ret);
1215 return -ENODEV;
1216 }
1217
Bradley Rubina7096d02011-08-03 18:29:02 -07001218 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001219 dev_err(codec->dev, "Not enough data\n");
1220 release_firmware(fw);
1221 return -ENOMEM;
1222 }
1223
1224 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001225 anc_head = (struct anc_header *)(fw->data);
1226 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1227 anc_size_remaining = fw->size - sizeof(struct anc_header);
1228 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001229
Bradley Rubina7096d02011-08-03 18:29:02 -07001230 if (tabla->anc_slot >= num_anc_slots) {
1231 dev_err(codec->dev, "Invalid ANC slot selected\n");
1232 release_firmware(fw);
1233 return -EINVAL;
1234 }
1235
1236 for (i = 0; i < num_anc_slots; i++) {
1237
1238 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1239 dev_err(codec->dev, "Invalid register format\n");
1240 release_firmware(fw);
1241 return -EINVAL;
1242 }
1243 anc_writes_size = (u32)(*anc_ptr);
1244 anc_size_remaining -= sizeof(u32);
1245 anc_ptr += 1;
1246
1247 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1248 > anc_size_remaining) {
1249 dev_err(codec->dev, "Invalid register format\n");
1250 release_firmware(fw);
1251 return -ENOMEM;
1252 }
1253
1254 if (tabla->anc_slot == i)
1255 break;
1256
1257 anc_size_remaining -= (anc_writes_size *
1258 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001259 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001260 }
1261 if (i == num_anc_slots) {
1262 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001263 release_firmware(fw);
1264 return -ENOMEM;
1265 }
1266
Bradley Rubina7096d02011-08-03 18:29:02 -07001267 for (i = 0; i < anc_writes_size; i++) {
1268 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001269 mask, val);
1270 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001271 snd_soc_write(codec, reg, (old_val & ~mask) |
1272 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001273 }
1274 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001275
1276 break;
1277 case SND_SOC_DAPM_POST_PMD:
1278 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1279 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1280 break;
1281 }
1282 return 0;
1283}
1284
1285
Bradley Rubincb3950a2011-08-18 13:07:26 -07001286static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
1287{
1288 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
1289 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
1290}
1291
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001292static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1293{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001294 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1295
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001296 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001297 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001298 if (!tabla->no_mic_headset_override) {
1299 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1300 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1301 } else {
1302 tabla_codec_disable_button_presses(codec);
1303 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001304 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1305 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1306 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1307}
1308
1309static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1310{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001311 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1312
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001313 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1314 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001315 if (!tabla->no_mic_headset_override) {
1316 tabla_disable_irq(codec->control_data,
1317 TABLA_IRQ_MBHC_POTENTIAL);
1318 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1319 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001320}
1321
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001322static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1323 int mode)
1324{
1325 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1326 u8 reg_mode_val, cur_mode_val;
1327 bool mbhc_was_polling = false;
1328
1329 if (mode)
1330 reg_mode_val = TABLA_CFILT_FAST_MODE;
1331 else
1332 reg_mode_val = TABLA_CFILT_SLOW_MODE;
1333
1334 cur_mode_val = snd_soc_read(codec,
1335 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
1336
1337 if (cur_mode_val != reg_mode_val) {
1338 if (tabla->mbhc_polling_active) {
1339 tabla_codec_pause_hs_polling(codec);
1340 mbhc_was_polling = true;
1341 }
1342 snd_soc_update_bits(codec,
1343 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1344 if (mbhc_was_polling)
1345 tabla_codec_start_hs_polling(codec);
1346 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
1347 cur_mode_val, reg_mode_val);
1348 } else {
1349 pr_debug("%s: CFILT Value is already %x\n",
1350 __func__, cur_mode_val);
1351 }
1352}
1353
1354static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1355 u8 cfilt_sel, int inc)
1356{
1357 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1358 u32 *cfilt_cnt_ptr = NULL;
1359 u16 micb_cfilt_reg;
1360
1361 switch (cfilt_sel) {
1362 case TABLA_CFILT1_SEL:
1363 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
1364 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
1365 break;
1366 case TABLA_CFILT2_SEL:
1367 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
1368 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
1369 break;
1370 case TABLA_CFILT3_SEL:
1371 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
1372 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
1373 break;
1374 default:
1375 return; /* should not happen */
1376 }
1377
1378 if (inc) {
1379 if (!(*cfilt_cnt_ptr)++) {
1380 /* Switch CFILT to slow mode if MBHC CFILT being used */
1381 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1382 tabla_codec_switch_cfilt_mode(codec, 0);
1383
1384 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1385 }
1386 } else {
1387 /* check if count not zero, decrement
1388 * then check if zero, go ahead disable cfilter
1389 */
1390 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1391 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1392
1393 /* Switch CFILT to fast mode if MBHC CFILT being used */
1394 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1395 tabla_codec_switch_cfilt_mode(codec, 1);
1396 }
1397 }
1398}
1399
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001400static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1401{
1402 int rc = -EINVAL;
1403 unsigned min_mv, max_mv;
1404
1405 switch (ldoh_v) {
1406 case TABLA_LDOH_1P95_V:
1407 min_mv = 160;
1408 max_mv = 1800;
1409 break;
1410 case TABLA_LDOH_2P35_V:
1411 min_mv = 200;
1412 max_mv = 2200;
1413 break;
1414 case TABLA_LDOH_2P75_V:
1415 min_mv = 240;
1416 max_mv = 2600;
1417 break;
1418 case TABLA_LDOH_2P85_V:
1419 min_mv = 250;
1420 max_mv = 2700;
1421 break;
1422 default:
1423 goto done;
1424 }
1425
1426 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1427 goto done;
1428
1429 for (rc = 4; rc <= 44; rc++) {
1430 min_mv = max_mv * (rc) / 44;
1431 if (min_mv >= cfilt_mv) {
1432 rc -= 4;
1433 break;
1434 }
1435 }
1436done:
1437 return rc;
1438}
1439
1440static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
1441{
1442 u8 hph_reg_val = 0;
1443 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
1444
1445 return (hph_reg_val & 0x30) ? true : false;
1446}
1447
Joonwoo Parka9444452011-12-08 18:48:27 -08001448static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
1449{
1450 u8 hph_reg_val = 0;
1451 if (left)
1452 hph_reg_val = snd_soc_read(codec,
1453 TABLA_A_RX_HPH_L_DAC_CTL);
1454 else
1455 hph_reg_val = snd_soc_read(codec,
1456 TABLA_A_RX_HPH_R_DAC_CTL);
1457
1458 return (hph_reg_val & 0xC0) ? true : false;
1459}
1460
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001461static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
1462 int vddio_switch)
1463{
1464 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1465 int cfilt_k_val;
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001466 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001467
1468 switch (vddio_switch) {
1469 case 1:
1470 if (tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001471
1472 tabla_codec_pause_hs_polling(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08001473 /* VDDIO switch enabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001474 tabla->cfilt_k_value = snd_soc_read(codec,
1475 tabla->mbhc_bias_regs.cfilt_val);
1476 cfilt_k_val = tabla_find_k_value(
1477 tabla->pdata->micbias.ldoh_v, 1800);
1478 snd_soc_update_bits(codec,
1479 tabla->mbhc_bias_regs.cfilt_val,
1480 0xFC, (cfilt_k_val << 2));
1481
1482 snd_soc_update_bits(codec,
1483 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1484 snd_soc_update_bits(codec,
1485 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001486 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001487
1488 tabla->mbhc_micbias_switched = true;
Joonwoo Park0976d012011-12-22 11:48:18 -08001489 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001490 }
1491 break;
1492
1493 case 0:
1494 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001495 if (tabla->mbhc_polling_active) {
1496 tabla_codec_pause_hs_polling(codec);
1497 mbhc_was_polling = true;
1498 }
Joonwoo Park0976d012011-12-22 11:48:18 -08001499 /* VDDIO switch disabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001500 if (tabla->cfilt_k_value != 0)
1501 snd_soc_update_bits(codec,
1502 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
1503 tabla->cfilt_k_value);
1504 snd_soc_update_bits(codec,
1505 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1506 snd_soc_update_bits(codec,
1507 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1508
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001509 if (mbhc_was_polling)
1510 tabla_codec_start_hs_polling(codec);
1511
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001512 tabla->mbhc_micbias_switched = false;
Joonwoo Park0976d012011-12-22 11:48:18 -08001513 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001514 }
1515 break;
1516 }
1517}
1518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1520 struct snd_kcontrol *kcontrol, int event)
1521{
1522 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07001523 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1524 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001525 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001526 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001527 char *internal1_text = "Internal1";
1528 char *internal2_text = "Internal2";
1529 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530
1531 pr_debug("%s %d\n", __func__, event);
1532 switch (w->reg) {
1533 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001534 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001535 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001536 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537 break;
1538 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001540 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001541 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001542 break;
1543 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001545 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001546 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001547 break;
1548 case TABLA_A_MICB_4_CTL:
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001549 micb_int_reg = TABLA_A_MICB_4_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001550 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001551 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552 break;
1553 default:
1554 pr_err("%s: Error, invalid micbias register\n", __func__);
1555 return -EINVAL;
1556 }
1557
1558 switch (event) {
1559 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001560 /* Decide whether to switch the micbias for MBHC */
1561 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1562 && tabla->mbhc_micbias_switched)
1563 tabla_codec_switch_micbias(codec, 0);
1564
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001565 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07001566 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001567
1568 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
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, 0x1C, 0x1C);
1572 else if (strnstr(w->name, internal3_text, 30))
1573 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
1574
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001576 case SND_SOC_DAPM_POST_PMU:
1577 if (tabla->mbhc_polling_active &&
Joonwoo Park0976d012011-12-22 11:48:18 -08001578 tabla->micbias == micb_line) {
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001579 tabla_codec_pause_hs_polling(codec);
1580 tabla_codec_start_hs_polling(codec);
1581 }
1582 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001585
1586 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1587 && tabla_is_hph_pa_on(codec))
1588 tabla_codec_switch_micbias(codec, 1);
1589
Bradley Rubin229c6a52011-07-12 16:18:48 -07001590 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001592 else if (strnstr(w->name, internal2_text, 30))
1593 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1594 else if (strnstr(w->name, internal3_text, 30))
1595 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1596
Patrick Lai3043fba2011-08-01 14:15:57 -07001597 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 break;
1599 }
1600
1601 return 0;
1602}
1603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
1605 struct snd_kcontrol *kcontrol, int event)
1606{
1607 struct snd_soc_codec *codec = w->codec;
1608 u16 dec_reset_reg;
1609
1610 pr_debug("%s %d\n", __func__, event);
1611
1612 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1613 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
1614 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
1615 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
1616 else {
1617 pr_err("%s: Error, incorrect dec\n", __func__);
1618 return -EINVAL;
1619 }
1620
1621 switch (event) {
1622 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001623 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1624 1 << w->shift);
1625 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1626 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001627 }
1628 return 0;
1629}
1630
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001631static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 struct snd_kcontrol *kcontrol, int event)
1633{
1634 struct snd_soc_codec *codec = w->codec;
1635
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001636 pr_debug("%s %d %s\n", __func__, event, w->name);
1637
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 switch (event) {
1639 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001640 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1641 1 << w->shift, 1 << w->shift);
1642 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1643 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001644 break;
1645 }
1646 return 0;
1647}
1648
Bradley Rubin229c6a52011-07-12 16:18:48 -07001649static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1650 struct snd_kcontrol *kcontrol, int event)
1651{
1652 switch (event) {
1653 case SND_SOC_DAPM_POST_PMU:
1654 case SND_SOC_DAPM_POST_PMD:
1655 usleep_range(1000, 1000);
1656 break;
1657 }
1658 return 0;
1659}
1660
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001661
1662static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1663{
1664 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1665
1666 if (enable) {
1667 tabla->rx_bias_count++;
1668 if (tabla->rx_bias_count == 1)
1669 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1670 0x80, 0x80);
1671 } else {
1672 tabla->rx_bias_count--;
1673 if (!tabla->rx_bias_count)
1674 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1675 0x80, 0x00);
1676 }
1677}
1678
1679static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1680 struct snd_kcontrol *kcontrol, int event)
1681{
1682 struct snd_soc_codec *codec = w->codec;
1683
1684 pr_debug("%s %d\n", __func__, event);
1685
1686 switch (event) {
1687 case SND_SOC_DAPM_PRE_PMU:
1688 tabla_enable_rx_bias(codec, 1);
1689 break;
1690 case SND_SOC_DAPM_POST_PMD:
1691 tabla_enable_rx_bias(codec, 0);
1692 break;
1693 }
1694 return 0;
1695}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001696static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
1697 struct snd_kcontrol *kcontrol, int event)
1698{
1699 struct snd_soc_codec *codec = w->codec;
1700
1701 pr_debug("%s %s %d\n", __func__, w->name, event);
1702
1703 switch (event) {
1704 case SND_SOC_DAPM_PRE_PMU:
1705 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1706 break;
1707 case SND_SOC_DAPM_POST_PMD:
1708 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1709 break;
1710 }
1711 return 0;
1712}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001713
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001714static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
1715 struct snd_soc_jack *jack, int status,
1716 int mask)
1717{
1718 /* XXX: wake_lock_timeout()? */
1719 snd_soc_jack_report(jack, status, mask);
1720}
1721
Patrick Lai49efeac2011-11-03 11:01:12 -07001722static void hphocp_off_report(struct tabla_priv *tabla,
1723 u32 jack_status, int irq)
1724{
1725 struct snd_soc_codec *codec;
1726
1727 if (tabla) {
1728 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
1729 codec = tabla->codec;
1730 tabla->hph_status &= ~jack_status;
1731 if (tabla->headset_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001732 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
1733 tabla->hph_status,
1734 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08001735 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
1736 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08001737 /* reset retry counter as PA is turned off signifying
1738 * start of new OCP detection session
1739 */
1740 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
1741 tabla->hphlocp_cnt = 0;
1742 else
1743 tabla->hphrocp_cnt = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07001744 tabla_enable_irq(codec->control_data, irq);
1745 } else {
1746 pr_err("%s: Bad tabla private data\n", __func__);
1747 }
1748}
1749
1750static void hphlocp_off_report(struct work_struct *work)
1751{
1752 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1753 hphlocp_work);
1754 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
1755}
1756
1757static void hphrocp_off_report(struct work_struct *work)
1758{
1759 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1760 hphrocp_work);
1761 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
1762}
1763
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001764static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
1765 struct snd_kcontrol *kcontrol, int event)
1766{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001767 struct snd_soc_codec *codec = w->codec;
1768 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1769 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001770 pr_debug("%s: event = %d\n", __func__, event);
1771
1772 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001773 case SND_SOC_DAPM_PRE_PMU:
1774 mbhc_micb_ctl_val = snd_soc_read(codec,
1775 tabla->mbhc_bias_regs.ctl_reg);
1776
1777 if (!(mbhc_micb_ctl_val & 0x80)
1778 && !tabla->mbhc_micbias_switched)
1779 tabla_codec_switch_micbias(codec, 1);
1780
1781 break;
1782
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001783 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07001784 /* schedule work is required because at the time HPH PA DAPM
1785 * event callback is called by DAPM framework, CODEC dapm mutex
1786 * would have been locked while snd_soc_jack_report also
1787 * attempts to acquire same lock.
1788 */
Joonwoo Parka9444452011-12-08 18:48:27 -08001789 if (w->shift == 5) {
1790 clear_bit(TABLA_HPHL_PA_OFF_ACK,
1791 &tabla->hph_pa_dac_state);
1792 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
1793 &tabla->hph_pa_dac_state);
1794 if (tabla->hph_status & SND_JACK_OC_HPHL)
1795 schedule_work(&tabla->hphlocp_work);
1796 } else if (w->shift == 4) {
1797 clear_bit(TABLA_HPHR_PA_OFF_ACK,
1798 &tabla->hph_pa_dac_state);
1799 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
1800 &tabla->hph_pa_dac_state);
1801 if (tabla->hph_status & SND_JACK_OC_HPHR)
1802 schedule_work(&tabla->hphrocp_work);
1803 }
1804
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001805 if (tabla->mbhc_micbias_switched)
1806 tabla_codec_switch_micbias(codec, 0);
1807
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001808 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
1809 w->name);
1810 usleep_range(10000, 10000);
1811
1812 break;
1813 }
1814 return 0;
1815}
1816
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001817static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
1818 struct mbhc_micbias_regs *micbias_regs)
1819{
1820 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001821 unsigned int cfilt;
1822
Joonwoo Park0976d012011-12-22 11:48:18 -08001823 switch (tabla->micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001824 case TABLA_MICBIAS1:
1825 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
1826 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
1827 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
1828 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
1829 break;
1830 case TABLA_MICBIAS2:
1831 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
1832 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
1833 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
1834 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
1835 break;
1836 case TABLA_MICBIAS3:
1837 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
1838 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
1839 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
1840 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
1841 break;
1842 case TABLA_MICBIAS4:
1843 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
1844 micbias_regs->mbhc_reg = TABLA_A_MICB_4_MBHC;
1845 micbias_regs->int_rbias = TABLA_A_MICB_4_INT_RBIAS;
1846 micbias_regs->ctl_reg = TABLA_A_MICB_4_CTL;
1847 break;
1848 default:
1849 /* Should never reach here */
1850 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07001851 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001852 }
1853
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001854 micbias_regs->cfilt_sel = cfilt;
1855
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001856 switch (cfilt) {
1857 case TABLA_CFILT1_SEL:
1858 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
1859 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001860 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001861 break;
1862 case TABLA_CFILT2_SEL:
1863 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
1864 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001865 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001866 break;
1867 case TABLA_CFILT3_SEL:
1868 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
1869 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001870 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001871 break;
1872 }
1873}
Santosh Mardie15e2302011-11-15 10:39:23 +05301874static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
1875 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
1876 4, 0, NULL, 0),
1877 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
1878 0, NULL, 0),
1879};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001880
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001881static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
1882 struct snd_kcontrol *kcontrol, int event)
1883{
1884 struct snd_soc_codec *codec = w->codec;
1885
1886 pr_debug("%s %s %d\n", __func__, w->name, event);
1887
1888 switch (event) {
1889 case SND_SOC_DAPM_PRE_PMU:
1890 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1891 break;
1892
1893 case SND_SOC_DAPM_POST_PMD:
1894 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1895 break;
1896 }
1897 return 0;
1898}
1899
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001900static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
1901 /*RX stuff */
1902 SND_SOC_DAPM_OUTPUT("EAR"),
1903
Kiran Kandid2d86b52011-09-09 17:44:28 -07001904 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001905
Bradley Rubin229c6a52011-07-12 16:18:48 -07001906 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
1907 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001908
Bradley Rubin229c6a52011-07-12 16:18:48 -07001909 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1910 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Santosh Mardie15e2302011-11-15 10:39:23 +05301911 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1912 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001913
1914 /* Headphone */
1915 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001916 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001917 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1918 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001919 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
1920 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001921
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001922 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001923 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1924 SND_SOC_DAPM_POST_PMD),
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001925
1926 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
1927 tabla_hphr_dac_event,
1928 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001929
1930 /* Speaker */
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001931 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
1932 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
1933 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
1934 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
1935 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001936
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001937 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
1938 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1939 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1940 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
1941 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1942 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1943 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
1944 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1945 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1946 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
1947 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1948 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1949 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001950 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1951 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001952
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001953 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
1954 , tabla_lineout_dac_event,
1955 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1956 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
1957 , tabla_lineout_dac_event,
1958 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1959 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
1960 , tabla_lineout_dac_event,
1961 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1962 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
1963 &lineout3_ground_switch),
1964 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
1965 , tabla_lineout_dac_event,
1966 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1967 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
1968 &lineout4_ground_switch),
1969 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
1970 , tabla_lineout_dac_event,
1971 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001972
Bradley Rubin229c6a52011-07-12 16:18:48 -07001973 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
1974 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1975 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
1976 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1977 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
1978 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1979 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
1980 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1981 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
1982 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1983 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
1984 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001985 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
1986 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001987
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001988
1989 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
1990 &rx4_dsm_mux, tabla_codec_reset_interpolator,
1991 SND_SOC_DAPM_PRE_PMU),
1992
1993 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
1994 &rx6_dsm_mux, tabla_codec_reset_interpolator,
1995 SND_SOC_DAPM_PRE_PMU),
1996
Bradley Rubin229c6a52011-07-12 16:18:48 -07001997 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
1998 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
1999
2000 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2001 &rx_mix1_inp1_mux),
2002 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2003 &rx_mix1_inp2_mux),
2004 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2005 &rx2_mix1_inp1_mux),
2006 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2007 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002008 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2009 &rx3_mix1_inp1_mux),
2010 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2011 &rx3_mix1_inp2_mux),
2012 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2013 &rx4_mix1_inp1_mux),
2014 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2015 &rx4_mix1_inp2_mux),
2016 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2017 &rx5_mix1_inp1_mux),
2018 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2019 &rx5_mix1_inp2_mux),
2020 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2021 &rx6_mix1_inp1_mux),
2022 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2023 &rx6_mix1_inp2_mux),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002024 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2025 &rx7_mix1_inp1_mux),
2026 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2027 &rx7_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028
Bradley Rubin229c6a52011-07-12 16:18:48 -07002029 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
2030 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2031 SND_SOC_DAPM_PRE_PMD),
2032
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002033 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2034 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2035 SND_SOC_DAPM_POST_PMD),
2036
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002037 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -07002038
Bradley Rubine1d08622011-07-20 18:01:35 -07002039 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
2040 0),
2041
Bradley Rubin229c6a52011-07-12 16:18:48 -07002042 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
2043 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
2044
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002045 SND_SOC_DAPM_INPUT("AMIC1"),
2046 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
2047 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002048 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002049 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
2050 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002051 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002052 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002053 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002054 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002055 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
2056 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2057 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2058
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002059 SND_SOC_DAPM_INPUT("AMIC3"),
2060 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
2061 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2062 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2063
2064 SND_SOC_DAPM_INPUT("AMIC4"),
2065 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
2066 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2067 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2068
2069 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_A_MICB_4_CTL, 7, 0,
2070 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002071 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002072
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002073 SND_SOC_DAPM_INPUT("AMIC5"),
2074 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
2075 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
2076
2077 SND_SOC_DAPM_INPUT("AMIC6"),
2078 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
2079 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
2080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 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 -07002082 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002083
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002084 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 -07002085 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002086
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002087 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 -07002088 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002089
2090 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 -07002091 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002093 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 -07002094 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002095
2096 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 -07002097 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002098
2099 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 -07002100 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002101
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002102 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 -07002103 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002104
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002105 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 -07002106 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002107
2108 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 -07002109 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002110
Bradley Rubin229c6a52011-07-12 16:18:48 -07002111 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
2112 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
2113
2114 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
2115 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
2116 SND_SOC_DAPM_POST_PMD),
2117
2118 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
2119
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002120 SND_SOC_DAPM_INPUT("AMIC2"),
2121 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
2122 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002123 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002124 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
2125 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002126 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002127 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
2128 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002129 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002130 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002132 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002133 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
2134 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002135 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002136 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
2137 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002138 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002139 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002140 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002141 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
2143 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2144 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2145
2146 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
2147 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
2148 0, 0),
2149
2150 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
2151 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
2152 4, 0),
2153
2154 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
2155 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
2156 5, 0),
2157
2158 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
2159 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
2160 0, 0),
2161
2162 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
2163 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
2164 0, 0),
2165
Kiran Kandi3426e512011-09-13 22:50:10 -07002166 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
2167 SND_SOC_DAPM_AIF_OUT("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
2168 0, 0),
2169
2170 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
2171 SND_SOC_DAPM_AIF_OUT("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
2172 0, 0),
2173
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002174 /* Digital Mic Inputs */
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002175 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2176 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2177 SND_SOC_DAPM_POST_PMD),
2178
2179 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2180 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2181 SND_SOC_DAPM_POST_PMD),
2182
2183 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
2184 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2185 SND_SOC_DAPM_POST_PMD),
2186
2187 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
2188 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2189 SND_SOC_DAPM_POST_PMD),
2190
2191 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
2192 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2193 SND_SOC_DAPM_POST_PMD),
2194
2195 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
2196 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2197 SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002198
2199 /* Sidetone */
2200 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2201 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2202};
2203
Santosh Mardie15e2302011-11-15 10:39:23 +05302204static const struct snd_soc_dapm_route audio_i2s_map[] = {
2205 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2206 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2207 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2208 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2209 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2210
2211 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2212 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2213 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2214 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2215};
2216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217static const struct snd_soc_dapm_route audio_map[] = {
2218 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002219
2220 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2221 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2222
2223 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2224 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2225
2226 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2227 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2228
2229 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2230 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002231 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002232 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2233 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002234 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2235 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002236 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2237 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002238 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2239 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002240
2241 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002242 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2243 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2244 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002245 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002246 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2247 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2248
Kiran Kandi3426e512011-09-13 22:50:10 -07002249 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
2250 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
2251 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
2252 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
2253 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
2254 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
2255 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
2256 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
2257 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
2258 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
2259 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
2260
2261 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
2262 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
2263 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
2264 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
2265 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
2266 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
2267 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
2268 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
2269 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
2270 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
2271 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
2272
2273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274 /* Earpiece (RX MIX1) */
2275 {"EAR", NULL, "EAR PA"},
Kiran Kandiac034ac2011-07-29 16:39:08 -07002276 {"EAR PA", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002277 {"DAC1", NULL, "CP"},
2278
2279 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2280 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2281 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282
2283 /* Headset (RX MIX1 and RX MIX2) */
2284 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002285 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002286
2287 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002288 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002289
2290 {"HPHL DAC", NULL, "CP"},
2291 {"HPHR DAC", NULL, "CP"},
2292
2293 {"ANC", NULL, "ANC1 MUX"},
2294 {"ANC", NULL, "ANC2 MUX"},
2295 {"ANC1 MUX", "ADC1", "ADC1"},
2296 {"ANC1 MUX", "ADC2", "ADC2"},
2297 {"ANC1 MUX", "ADC3", "ADC3"},
2298 {"ANC1 MUX", "ADC4", "ADC4"},
2299 {"ANC2 MUX", "ADC1", "ADC1"},
2300 {"ANC2 MUX", "ADC2", "ADC2"},
2301 {"ANC2 MUX", "ADC3", "ADC3"},
2302 {"ANC2 MUX", "ADC4", "ADC4"},
2303
Bradley Rubine1d08622011-07-20 18:01:35 -07002304 {"ANC", NULL, "CDC_CONN"},
2305
Bradley Rubin229c6a52011-07-12 16:18:48 -07002306 {"DAC1", "Switch", "RX1 CHAIN"},
2307 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002308 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002309
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002310 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2311 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2312 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2313 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2314 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002315
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002316 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2317 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2318 {"LINEOUT3 PA", NULL, "LINEOUT3 DAC"},
2319 {"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
2320 {"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002321
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002322 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2323 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2324
Bradley Rubin229c6a52011-07-12 16:18:48 -07002325 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2326 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2327 {"RX1 CHAIN", NULL, "ANC"},
2328 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002329
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002330 {"CP", NULL, "RX_BIAS"},
2331 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2332 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2333 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2334 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002335 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002336
Bradley Rubin229c6a52011-07-12 16:18:48 -07002337 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2338 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2339 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2340 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002341 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2342 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2343 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2344 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2345 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2346 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2347 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2348 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002349 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2350 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002351
Bradley Rubin229c6a52011-07-12 16:18:48 -07002352 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2353 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302354 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2355 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002356 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2357 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2358 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302359 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2360 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002361 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2362 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2363 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302364 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2365 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002366 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002367 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2368 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302369 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2370 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002371 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002372 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2373 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302374 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2375 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002376 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002377 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2378 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302379 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2380 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002381 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002382 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2383 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302384 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2385 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002386 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002387 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2388 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302389 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2390 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002391 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002392 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2393 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302394 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2395 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002396 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002397 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2398 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302399 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2400 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002401 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002402 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2403 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302404 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2405 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002406 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002407 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2408 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302409 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2410 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002411 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002412 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2413 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302414 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2415 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002416 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002417 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2418 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302419 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2420 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002421 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002422
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002423 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002424 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002425 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002426 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002427 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002428 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002429 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002430 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002431 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002432 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002433 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002434 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002435 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002436 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002437 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002438 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002439 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002440 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002441 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002442 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002443 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002444 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002445 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002446 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002447 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002448 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002449 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002450 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002451
2452 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002453 {"ADC1", NULL, "AMIC1"},
2454 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002455 {"ADC3", NULL, "AMIC3"},
2456 {"ADC4", NULL, "AMIC4"},
2457 {"ADC5", NULL, "AMIC5"},
2458 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002460 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002461 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2462 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2463 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2464 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2465 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002467 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
2468 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
2469 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
2470 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002471
2472 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2473 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2474 {"MIC BIAS1 External", NULL, "LDO_H"},
2475 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2476 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2477 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2478 {"MIC BIAS2 External", NULL, "LDO_H"},
2479 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2480 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2481 {"MIC BIAS3 External", NULL, "LDO_H"},
2482 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002483};
2484
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002485static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
2486
2487 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2488 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2489
2490 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
2491
2492 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
2493 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
2494 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
2495
2496 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2497 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2498
2499 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2500 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
2501 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
2502};
2503
Kiran Kandi7a9fd902011-11-14 13:51:45 -08002504
2505static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
2506
2507 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2508 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2509
2510 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
2511
2512 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
2513
2514 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2515 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2516
2517 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2518};
2519
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002520static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
2521{
2522 return tabla_reg_readable[reg];
2523}
2524
2525static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2526{
2527 /* Registers lower than 0x100 are top level registers which can be
2528 * written by the Tabla core driver.
2529 */
2530
2531 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2532 return 1;
2533
Ben Romberger1f045a72011-11-04 10:14:57 -07002534 /* IIR Coeff registers are not cacheable */
2535 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
2536 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
2537 return 1;
2538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 return 0;
2540}
2541
2542#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2543static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
2544 unsigned int value)
2545{
2546 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547
2548 BUG_ON(reg > TABLA_MAX_REGISTER);
2549
2550 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551 ret = snd_soc_cache_write(codec, reg, value);
2552 if (ret != 0)
2553 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2554 reg, ret);
2555 }
2556
2557 return tabla_reg_write(codec->control_data, reg, value);
2558}
2559static unsigned int tabla_read(struct snd_soc_codec *codec,
2560 unsigned int reg)
2561{
2562 unsigned int val;
2563 int ret;
2564
2565 BUG_ON(reg > TABLA_MAX_REGISTER);
2566
2567 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
2568 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002569 ret = snd_soc_cache_read(codec, reg, &val);
2570 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571 return val;
2572 } else
2573 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2574 reg, ret);
2575 }
2576
2577 val = tabla_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002578 return val;
2579}
2580
2581static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2582{
2583 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
2584 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2585 0x80);
2586 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
2587 0x04);
2588 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2589 0x01);
2590 usleep_range(1000, 1000);
2591 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2592 0x00);
2593}
2594
2595static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
2596 enum tabla_bandgap_type choice)
2597{
2598 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2599
2600 /* TODO lock resources accessed by audio streams and threaded
2601 * interrupt handlers
2602 */
2603
2604 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
2605 tabla->bandgap_type);
2606
2607 if (tabla->bandgap_type == choice)
2608 return;
2609
2610 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
2611 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2612 tabla_codec_enable_audio_mode_bandgap(codec);
2613 } else if ((tabla->bandgap_type == TABLA_BANDGAP_AUDIO_MODE) &&
2614 (choice == TABLA_BANDGAP_MBHC_MODE)) {
2615 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
2616 0x2);
2617 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2618 0x80);
2619 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
2620 0x4);
2621 usleep_range(1000, 1000);
2622 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2623 0x00);
2624 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
2625 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2626 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2627 usleep_range(100, 100);
2628 tabla_codec_enable_audio_mode_bandgap(codec);
2629 } else if (choice == TABLA_BANDGAP_OFF) {
2630 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2631 } else {
2632 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2633 }
2634 tabla->bandgap_type = choice;
2635}
2636
2637static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
2638 int enable)
2639{
2640 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2641
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002642 pr_debug("%s: enable = %d\n", __func__, enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002643 if (enable) {
2644 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
2645 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
2646 usleep_range(5, 5);
2647 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
2648 0x80);
2649 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
2650 0x80);
2651 usleep_range(10, 10);
2652 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
2653 usleep_range(20, 20);
2654 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
2655 } else {
2656 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
2657 0);
2658 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002659 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002660 }
2661 tabla->config_mode_active = enable ? true : false;
2662
2663 return 0;
2664}
2665
2666static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
2667 int config_mode)
2668{
2669 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2670
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002671 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002672
2673 if (config_mode) {
2674 tabla_codec_enable_config_mode(codec, 1);
2675 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
2676 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2677 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
2678 usleep_range(1000, 1000);
2679 } else
2680 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
2681
2682 if (!config_mode && tabla->mbhc_polling_active) {
2683 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2684 tabla_codec_enable_config_mode(codec, 0);
2685
2686 }
2687
2688 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
2689 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
2690 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
2691 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
2692 usleep_range(50, 50);
2693 tabla->clock_active = true;
2694 return 0;
2695}
2696static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
2697{
2698 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2699 pr_debug("%s\n", __func__);
2700 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
2701 ndelay(160);
2702 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
2703 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
2704 tabla->clock_active = false;
2705}
2706
Joonwoo Park107edf02012-01-11 11:42:24 -08002707static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
2708{
2709 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
2710 return 0;
2711 else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
2712 return 1;
2713 else {
2714 BUG_ON(1);
2715 return -EINVAL;
2716 }
2717}
2718
Bradley Rubincb1e2732011-06-23 16:49:20 -07002719static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2720{
Joonwoo Parkc0672392012-01-11 11:03:14 -08002721 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08002722 struct tabla_mbhc_btn_detect_cfg *btn_det;
2723 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002724
Joonwoo Park0976d012011-12-22 11:48:18 -08002725 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002726
Joonwoo Park0976d012011-12-22 11:48:18 -08002727 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2728 tabla->mbhc_data.v_ins_hu & 0xFF);
2729 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2730 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002731
Joonwoo Park0976d012011-12-22 11:48:18 -08002732 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2733 tabla->mbhc_data.v_b1_hu & 0xFF);
2734 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2735 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
2736
2737 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2738 tabla->mbhc_data.v_b1_h & 0xFF);
2739 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2740 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
2741
2742 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
2743 tabla->mbhc_data.v_brh & 0xFF);
2744 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
2745 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
2746
2747 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
2748 tabla->mbhc_data.v_brl & 0xFF);
2749 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
2750 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
2751
Joonwoo Parkc0672392012-01-11 11:03:14 -08002752 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08002753 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08002754 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08002755 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
2756 tabla->mbhc_data.npoll);
2757 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
2758 tabla->mbhc_data.nbounce_wait);
2759
2760 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08002761 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
2762 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002763}
2764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002765static int tabla_startup(struct snd_pcm_substream *substream,
2766 struct snd_soc_dai *dai)
2767{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002768 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2769 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002770
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002771 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002772}
2773
2774static void tabla_shutdown(struct snd_pcm_substream *substream,
2775 struct snd_soc_dai *dai)
2776{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002777 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2778 substream->name, substream->stream);
2779}
2780
2781int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
2782{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002783 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2784
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002785 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002786
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002787 if (mclk_enable) {
2788 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002789
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002790 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07002791 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002792 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002793 TABLA_BANDGAP_AUDIO_MODE);
2794 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002795 tabla_codec_calibrate_hs_polling(codec);
2796 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002798 } else {
2799
2800 if (!tabla->mclk_enabled) {
2801 pr_err("Error, MCLK already diabled\n");
2802 return -EINVAL;
2803 }
2804 tabla->mclk_enabled = false;
2805
2806 if (tabla->mbhc_polling_active) {
2807 if (!tabla->mclk_enabled) {
2808 tabla_codec_pause_hs_polling(codec);
2809 tabla_codec_enable_bandgap(codec,
2810 TABLA_BANDGAP_MBHC_MODE);
2811 tabla_enable_rx_bias(codec, 1);
2812 tabla_codec_enable_clock_block(codec, 1);
2813 tabla_codec_calibrate_hs_polling(codec);
2814 tabla_codec_start_hs_polling(codec);
2815 }
2816 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
2817 0x05, 0x01);
2818 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002819 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002820 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002821}
2822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002823static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
2824 int clk_id, unsigned int freq, int dir)
2825{
2826 pr_debug("%s\n", __func__);
2827 return 0;
2828}
2829
2830static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2831{
Santosh Mardie15e2302011-11-15 10:39:23 +05302832 u8 val = 0;
2833 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
2834
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002835 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05302836 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2837 case SND_SOC_DAIFMT_CBS_CFS:
2838 /* CPU is master */
2839 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2840 if (dai->id == TABLA_TX_DAI_ID)
2841 snd_soc_update_bits(dai->codec,
2842 TABLA_A_CDC_CLK_TX_I2S_CTL,
2843 TABLA_I2S_MASTER_MODE_MASK, 0);
2844 else if (dai->id == TABLA_RX_DAI_ID)
2845 snd_soc_update_bits(dai->codec,
2846 TABLA_A_CDC_CLK_RX_I2S_CTL,
2847 TABLA_I2S_MASTER_MODE_MASK, 0);
2848 }
2849 break;
2850 case SND_SOC_DAIFMT_CBM_CFM:
2851 /* CPU is slave */
2852 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2853 val = TABLA_I2S_MASTER_MODE_MASK;
2854 if (dai->id == TABLA_TX_DAI_ID)
2855 snd_soc_update_bits(dai->codec,
2856 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
2857 else if (dai->id == TABLA_RX_DAI_ID)
2858 snd_soc_update_bits(dai->codec,
2859 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
2860 }
2861 break;
2862 default:
2863 return -EINVAL;
2864 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002865 return 0;
2866}
2867
2868static int tabla_hw_params(struct snd_pcm_substream *substream,
2869 struct snd_pcm_hw_params *params,
2870 struct snd_soc_dai *dai)
2871{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002872 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05302873 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07002874 u8 path, shift;
2875 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002876 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
2877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002878 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002879
2880 switch (params_rate(params)) {
2881 case 8000:
2882 tx_fs_rate = 0x00;
2883 rx_fs_rate = 0x00;
2884 break;
2885 case 16000:
2886 tx_fs_rate = 0x01;
2887 rx_fs_rate = 0x20;
2888 break;
2889 case 32000:
2890 tx_fs_rate = 0x02;
2891 rx_fs_rate = 0x40;
2892 break;
2893 case 48000:
2894 tx_fs_rate = 0x03;
2895 rx_fs_rate = 0x60;
2896 break;
2897 default:
2898 pr_err("%s: Invalid sampling rate %d\n", __func__,
2899 params_rate(params));
2900 return -EINVAL;
2901 }
2902
2903
2904 /**
2905 * If current dai is a tx dai, set sample rate to
2906 * all the txfe paths that are currently not active
2907 */
2908 if (dai->id == TABLA_TX_DAI_ID) {
2909
2910 tx_state = snd_soc_read(codec,
2911 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
2912
2913 for (path = 1, shift = 0;
2914 path <= NUM_DECIMATORS; path++, shift++) {
2915
2916 if (path == BITS_PER_REG + 1) {
2917 shift = 0;
2918 tx_state = snd_soc_read(codec,
2919 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
2920 }
2921
2922 if (!(tx_state & (1 << shift))) {
2923 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
2924 + (BITS_PER_REG*(path-1));
2925 snd_soc_update_bits(codec, tx_fs_reg,
2926 0x03, tx_fs_rate);
2927 }
2928 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302929 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2930 switch (params_format(params)) {
2931 case SNDRV_PCM_FORMAT_S16_LE:
2932 snd_soc_update_bits(codec,
2933 TABLA_A_CDC_CLK_TX_I2S_CTL,
2934 0x20, 0x20);
2935 break;
2936 case SNDRV_PCM_FORMAT_S32_LE:
2937 snd_soc_update_bits(codec,
2938 TABLA_A_CDC_CLK_TX_I2S_CTL,
2939 0x20, 0x00);
2940 break;
2941 default:
2942 pr_err("invalid format\n");
2943 break;
2944 }
2945 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
2946 0x03, tx_fs_rate);
2947 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002948 }
2949
2950 /**
2951 * TODO: Need to handle case where same RX chain takes 2 or more inputs
2952 * with varying sample rates
2953 */
2954
2955 /**
2956 * If current dai is a rx dai, set sample rate to
2957 * all the rx paths that are currently not active
2958 */
2959 if (dai->id == TABLA_RX_DAI_ID) {
2960
2961 rx_state = snd_soc_read(codec,
2962 TABLA_A_CDC_CLK_RX_B1_CTL);
2963
2964 for (path = 1, shift = 0;
2965 path <= NUM_INTERPOLATORS; path++, shift++) {
2966
2967 if (!(rx_state & (1 << shift))) {
2968 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
2969 + (BITS_PER_REG*(path-1));
2970 snd_soc_update_bits(codec, rx_fs_reg,
2971 0xE0, rx_fs_rate);
2972 }
2973 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302974 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2975 switch (params_format(params)) {
2976 case SNDRV_PCM_FORMAT_S16_LE:
2977 snd_soc_update_bits(codec,
2978 TABLA_A_CDC_CLK_RX_I2S_CTL,
2979 0x20, 0x20);
2980 break;
2981 case SNDRV_PCM_FORMAT_S32_LE:
2982 snd_soc_update_bits(codec,
2983 TABLA_A_CDC_CLK_RX_I2S_CTL,
2984 0x20, 0x00);
2985 break;
2986 default:
2987 pr_err("invalid format\n");
2988 break;
2989 }
2990 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
2991 0x03, (rx_fs_rate >> 0x05));
2992 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002993 }
2994
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002995 return 0;
2996}
2997
2998static struct snd_soc_dai_ops tabla_dai_ops = {
2999 .startup = tabla_startup,
3000 .shutdown = tabla_shutdown,
3001 .hw_params = tabla_hw_params,
3002 .set_sysclk = tabla_set_dai_sysclk,
3003 .set_fmt = tabla_set_dai_fmt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003004};
3005
3006static struct snd_soc_dai_driver tabla_dai[] = {
3007 {
3008 .name = "tabla_rx1",
3009 .id = 1,
3010 .playback = {
3011 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003012 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013 .formats = TABLA_FORMATS,
3014 .rate_max = 48000,
3015 .rate_min = 8000,
3016 .channels_min = 1,
Kiran Kandi3426e512011-09-13 22:50:10 -07003017 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003018 },
3019 .ops = &tabla_dai_ops,
3020 },
3021 {
3022 .name = "tabla_tx1",
3023 .id = 2,
3024 .capture = {
3025 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003026 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003027 .formats = TABLA_FORMATS,
3028 .rate_max = 48000,
3029 .rate_min = 8000,
3030 .channels_min = 1,
3031 .channels_max = 2,
3032 },
3033 .ops = &tabla_dai_ops,
3034 },
3035};
Santosh Mardie15e2302011-11-15 10:39:23 +05303036
3037static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3038 {
3039 .name = "tabla_i2s_rx1",
3040 .id = 1,
3041 .playback = {
3042 .stream_name = "AIF1 Playback",
3043 .rates = WCD9310_RATES,
3044 .formats = TABLA_FORMATS,
3045 .rate_max = 48000,
3046 .rate_min = 8000,
3047 .channels_min = 1,
3048 .channels_max = 4,
3049 },
3050 .ops = &tabla_dai_ops,
3051 },
3052 {
3053 .name = "tabla_i2s_tx1",
3054 .id = 2,
3055 .capture = {
3056 .stream_name = "AIF1 Capture",
3057 .rates = WCD9310_RATES,
3058 .formats = TABLA_FORMATS,
3059 .rate_max = 48000,
3060 .rate_min = 8000,
3061 .channels_min = 1,
3062 .channels_max = 4,
3063 },
3064 .ops = &tabla_dai_ops,
3065 },
3066};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003067static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003068{
3069 u8 bias_msb, bias_lsb;
3070 short bias_value;
3071
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003072 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
3073 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
3074 bias_value = (bias_msb << 8) | bias_lsb;
3075 return bias_value;
3076}
3077
3078static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
3079{
3080 u8 bias_msb, bias_lsb;
3081 short bias_value;
3082
3083 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
3084 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
3085 bias_value = (bias_msb << 8) | bias_lsb;
3086 return bias_value;
3087}
3088
Joonwoo Park0976d012011-12-22 11:48:18 -08003089static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003090{
Joonwoo Park0976d012011-12-22 11:48:18 -08003091 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003092 short bias_value;
3093
Joonwoo Park925914c2012-01-05 13:35:18 -08003094 /* Turn on the override */
3095 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003096 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003097 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3098 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
3099 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003100 usleep_range(tabla->mbhc_data.t_sta_dce,
3101 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003102 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08003103 usleep_range(tabla->mbhc_data.t_dce,
3104 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003105 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003106 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003107 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003108 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3109 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003110 usleep_range(tabla->mbhc_data.t_sta_dce,
3111 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08003112 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3113 usleep_range(tabla->mbhc_data.t_sta,
3114 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003115 bias_value = tabla_codec_read_sta_result(codec);
3116 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3117 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003118 }
Joonwoo Park925914c2012-01-05 13:35:18 -08003119 /* Turn off the override after measuring mic voltage */
3120 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003121
Joonwoo Park0976d012011-12-22 11:48:18 -08003122 pr_debug("read microphone bias value %04x\n", bias_value);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003123 return bias_value;
3124}
3125
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003126static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003127{
3128 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003129 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003130 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003131
Joonwoo Park0976d012011-12-22 11:48:18 -08003132 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003133 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07003134 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003135 }
3136
3137 tabla->mbhc_polling_active = true;
3138
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003139 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003140 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003141 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003142 tabla_codec_enable_clock_block(codec, 1);
3143 }
3144
3145 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
3146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003147 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
3148
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003149 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08003150 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
3151 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07003152
Joonwoo Parkf4267c22012-01-10 13:25:24 -08003153 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003154
3155 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003156 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003157
3158 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
3159 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
3160 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
3161
3162 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003163 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3164 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165
Joonwoo Park925914c2012-01-05 13:35:18 -08003166 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003167 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3168
Bradley Rubincb1e2732011-06-23 16:49:20 -07003169 tabla_codec_calibrate_hs_polling(codec);
3170
Joonwoo Park0976d012011-12-22 11:48:18 -08003171 bias_value = tabla_codec_sta_dce(codec, 0);
3172 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3173 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003174 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003175
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003176 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177}
3178
3179static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
3180 int insertion)
3181{
3182 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003183 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08003184 const struct tabla_mbhc_general_cfg *generic =
3185 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3186 const struct tabla_mbhc_plug_detect_cfg *plug_det =
3187 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003188 u8 wg_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003189
Joonwoo Park0976d012011-12-22 11:48:18 -08003190 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003191 pr_err("Error, no tabla calibration\n");
3192 return -EINVAL;
3193 }
3194
3195 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
3196
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003197 if (insertion) {
3198 /* Make sure mic bias and Mic line schmitt trigger
3199 * are turned OFF
3200 */
3201 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
3202 0x81, 0x01);
3203 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3204 0x90, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003205 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
3206 wg_time += 1;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003207
3208 /* Enable HPH Schmitt Trigger */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003209 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003210 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
Joonwoo Park0976d012011-12-22 11:48:18 -08003211 plug_det->hph_current << 2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003212
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003213 /* Turn off HPH PAs and DAC's during insertion detection to
3214 * avoid false insertion interrupts
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003215 */
3216 if (tabla->mbhc_micbias_switched)
3217 tabla_codec_switch_micbias(codec, 0);
3218 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003219 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003220 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003221 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003222 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003223 usleep_range(wg_time * 1000, wg_time * 1000);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003224
3225 /* setup for insetion detection */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003226 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003227 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003228 } else {
3229 /* Make sure the HPH schmitt trigger is OFF */
3230 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3231
3232 /* enable the mic line schmitt trigger */
3233 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08003234 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003235 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3236 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003237 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003238 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3239 0x10, 0x10);
3240
3241 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003243 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244
3245 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
3246 if (!(tabla->clock_active)) {
3247 tabla_codec_enable_config_mode(codec, 1);
3248 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003249 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08003250 usleep_range(generic->t_shutdown_plug_rem,
3251 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003252 tabla_codec_enable_config_mode(codec, 0);
3253 } else
3254 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003255 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003256 }
3257
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003258 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259
3260 /* If central bandgap disabled */
3261 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
3262 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08003263 usleep_range(generic->t_bg_fast_settle,
3264 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003265 central_bias_enabled = 1;
3266 }
3267
3268 /* If LDO_H disabled */
3269 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
3270 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
3271 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003272 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003273 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
3274
3275 if (central_bias_enabled)
3276 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
3277 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003278
Joonwoo Park0976d012011-12-22 11:48:18 -08003279 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, tabla->micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003280
3281 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3282 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3283 return 0;
3284}
3285
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003286static void tabla_lock_sleep(struct tabla_priv *tabla)
3287{
3288 int ret;
3289 while (!(ret = wait_event_timeout(tabla->pm_wq,
3290 atomic_inc_not_zero(&tabla->pm_cnt),
3291 2 * HZ))) {
3292 pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
3293 __func__, ret, atomic_read(&tabla->pm_cnt));
3294 WARN_ON_ONCE(1);
3295 }
3296}
3297
3298static void tabla_unlock_sleep(struct tabla_priv *tabla)
3299{
3300 atomic_dec(&tabla->pm_cnt);
3301 wake_up(&tabla->pm_wq);
3302}
3303
Joonwoo Park0976d012011-12-22 11:48:18 -08003304static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
3305 s16 vin_mv)
3306{
3307 short diff, zero;
3308 struct tabla_priv *tabla;
3309 u32 mb_mv, in;
3310
3311 tabla = snd_soc_codec_get_drvdata(codec);
3312 mb_mv = tabla->mbhc_data.micb_mv;
3313
3314 if (mb_mv == 0) {
3315 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
3316 return -EINVAL;
3317 }
3318
3319 if (dce) {
3320 diff = tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z;
3321 zero = tabla->mbhc_data.dce_z;
3322 } else {
3323 diff = tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z;
3324 zero = tabla->mbhc_data.sta_z;
3325 }
3326 in = (u32) diff * vin_mv;
3327
3328 return (u16) (in / mb_mv) + zero;
3329}
3330
3331static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
3332 u16 bias_value)
3333{
3334 struct tabla_priv *tabla;
3335 s32 mv;
3336
3337 tabla = snd_soc_codec_get_drvdata(codec);
3338
3339 if (dce) {
3340 mv = ((s32)bias_value - (s32)tabla->mbhc_data.dce_z) *
3341 (s32)tabla->mbhc_data.micb_mv /
3342 (s32)(tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z);
3343 } else {
3344 mv = ((s32)bias_value - (s32)tabla->mbhc_data.sta_z) *
3345 (s32)tabla->mbhc_data.micb_mv /
3346 (s32)(tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z);
3347 }
3348
3349 return mv;
3350}
3351
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003352static void btn0_lpress_fn(struct work_struct *work)
3353{
3354 struct delayed_work *delayed_work;
3355 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08003356 short bias_value;
3357 int dce_mv, sta_mv;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003358
3359 pr_debug("%s:\n", __func__);
3360
3361 delayed_work = to_delayed_work(work);
3362 tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
3363
3364 if (tabla) {
3365 if (tabla->button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003366 bias_value = tabla_codec_read_sta_result(tabla->codec);
3367 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
3368 bias_value);
3369 bias_value = tabla_codec_read_dce_result(tabla->codec);
3370 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
3371 bias_value);
3372 pr_debug("%s: Reporting long button press event"
3373 " STA: %d, DCE: %d\n", __func__,
3374 sta_mv, dce_mv);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003375 tabla_snd_soc_jack_report(tabla, tabla->button_jack,
3376 SND_JACK_BTN_0,
3377 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003378 }
3379 } else {
3380 pr_err("%s: Bad tabla private data\n", __func__);
3381 }
3382
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003383 tabla_unlock_sleep(tabla);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003384}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003385
Joonwoo Park0976d012011-12-22 11:48:18 -08003386void tabla_mbhc_cal(struct snd_soc_codec *codec)
3387{
3388 struct tabla_priv *tabla;
3389 struct tabla_mbhc_btn_detect_cfg *btn_det;
3390 u8 cfilt_mode, bg_mode;
3391 u8 ncic, nmeas, navg;
3392 u32 mclk_rate;
3393 u32 dce_wait, sta_wait;
3394 u8 *n_cic;
3395
3396 tabla = snd_soc_codec_get_drvdata(codec);
3397
3398 /* First compute the DCE / STA wait times
3399 * depending on tunable parameters.
3400 * The value is computed in microseconds
3401 */
3402 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3403 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003404 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Park0976d012011-12-22 11:48:18 -08003405 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
3406 navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
3407 mclk_rate = tabla->mclk_freq;
Joonwoo Park433149a2012-01-11 09:53:54 -08003408 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
3409 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08003410
3411 tabla->mbhc_data.t_dce = dce_wait;
3412 tabla->mbhc_data.t_sta = sta_wait;
3413
3414 /* LDOH and CFILT are already configured during pdata handling.
3415 * Only need to make sure CFILT and bandgap are in Fast mode.
3416 * Need to restore defaults once calculation is done.
3417 */
3418 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
3419 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
3420 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
3421 0x02);
3422
3423 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
3424 * to perform ADC calibration
3425 */
3426 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
3427 tabla->micbias << 5);
3428 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
3429 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
3430 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
3431 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
3432
3433 /* DCE measurement for 0 volts */
3434 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3435 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3436 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3437 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3438 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
3439 usleep_range(100, 100);
3440 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3441 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3442 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
3443
3444 /* DCE measurment for MB voltage */
3445 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3446 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3447 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3448 usleep_range(100, 100);
3449 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3450 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3451 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
3452
3453 /* Sta measuremnt for 0 volts */
3454 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3455 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3456 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3457 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3458 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
3459 usleep_range(100, 100);
3460 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3461 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
3462 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
3463
3464 /* STA Measurement for MB Voltage */
3465 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3466 usleep_range(100, 100);
3467 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3468 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
3469 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
3470
3471 /* Restore default settings. */
3472 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3473 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3474 cfilt_mode);
3475 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
3476
3477 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
3478 usleep_range(100, 100);
3479}
3480
3481void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
3482 const enum tabla_mbhc_btn_det_mem mem)
3483{
3484 void *ret = &btn_det->_v_btn_low;
3485
3486 switch (mem) {
3487 case TABLA_BTN_DET_GAIN:
3488 ret += sizeof(btn_det->_n_cic);
3489 case TABLA_BTN_DET_N_CIC:
3490 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08003491 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08003492 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
3493 case TABLA_BTN_DET_V_BTN_HIGH:
3494 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
3495 case TABLA_BTN_DET_V_BTN_LOW:
3496 /* do nothing */
3497 break;
3498 default:
3499 ret = NULL;
3500 }
3501
3502 return ret;
3503}
3504
3505static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
3506{
3507 struct tabla_priv *tabla;
3508 s16 btn_mv = 0, btn_delta_mv;
3509 struct tabla_mbhc_btn_detect_cfg *btn_det;
3510 struct tabla_mbhc_plug_type_cfg *plug_type;
3511 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08003512 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08003513 int i;
3514
3515 tabla = snd_soc_codec_get_drvdata(codec);
3516 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3517 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
3518
Joonwoo Parkc0672392012-01-11 11:03:14 -08003519 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003520 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003521 tabla->mbhc_data.npoll = 9;
3522 tabla->mbhc_data.nbounce_wait = 30;
3523 } else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003524 tabla->mbhc_data.npoll = 7;
3525 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08003526 }
Joonwoo Park0976d012011-12-22 11:48:18 -08003527
Joonwoo Park433149a2012-01-11 09:53:54 -08003528 tabla->mbhc_data.t_sta_dce = ((1000 * 256) / (tabla->mclk_freq / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08003529 n_ready[tabla_codec_mclk_index(tabla)]) +
3530 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08003531 tabla->mbhc_data.v_ins_hu =
3532 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
3533 tabla->mbhc_data.v_ins_h =
3534 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
3535
3536 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
3537 for (i = 0; i < btn_det->num_btn; i++)
3538 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
3539
3540 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
3541 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
3542
3543 tabla->mbhc_data.v_b1_hu =
3544 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
3545
3546 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
3547
3548 tabla->mbhc_data.v_b1_huc =
3549 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
3550
3551 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
3552 tabla->mbhc_data.v_brl = 0xFA55;
3553
3554 tabla->mbhc_data.v_no_mic =
3555 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
3556}
3557
3558void tabla_mbhc_init(struct snd_soc_codec *codec)
3559{
3560 struct tabla_priv *tabla;
3561 struct tabla_mbhc_general_cfg *generic;
3562 struct tabla_mbhc_btn_detect_cfg *btn_det;
3563 int n;
3564 u8 tabla_ver;
3565 u8 *n_cic, *gain;
3566
3567 tabla = snd_soc_codec_get_drvdata(codec);
3568 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3569 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3570
3571 tabla_ver = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
3572 tabla_ver &= 0x1F;
3573
3574 for (n = 0; n < 8; n++) {
3575 if ((tabla_ver != TABLA_VERSION_1_0 &&
3576 tabla_ver != TABLA_VERSION_1_1) || n != 7) {
3577 snd_soc_update_bits(codec,
3578 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
3579 0x07, n);
3580 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
3581 btn_det->c[n]);
3582 }
3583 }
3584 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
3585 btn_det->nc);
3586
3587 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
3588 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08003589 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003590
3591 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08003592 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
3593 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08003594
3595 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
3596 generic->mbhc_nsa << 4);
3597
3598 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
3599 btn_det->n_meas);
3600
3601 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
3602
3603 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
3604
3605 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
3606 btn_det->mbhc_nsc << 3);
3607
3608 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x03, TABLA_MICBIAS2);
3609
3610 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
3611}
3612
Patrick Lai64b43262011-12-06 17:29:15 -08003613static bool tabla_mbhc_fw_validate(const struct firmware *fw)
3614{
3615 u32 cfg_offset;
3616 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
3617 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
3618
3619 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
3620 return false;
3621
3622 /* previous check guarantees that there is enough fw data up
3623 * to num_btn
3624 */
3625 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
3626 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
3627 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
3628 return false;
3629
3630 /* previous check guarantees that there is enough fw data up
3631 * to start of impedance detection configuration
3632 */
3633 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
3634 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
3635
3636 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
3637 return false;
3638
3639 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
3640 return false;
3641
3642 return true;
3643}
3644static void mbhc_fw_read(struct work_struct *work)
3645{
3646 struct delayed_work *dwork;
3647 struct tabla_priv *tabla;
3648 struct snd_soc_codec *codec;
3649 const struct firmware *fw;
3650 int ret = -1, retry = 0, rc;
3651
3652 dwork = to_delayed_work(work);
3653 tabla = container_of(dwork, struct tabla_priv,
3654 mbhc_firmware_dwork);
3655 codec = tabla->codec;
3656
3657 while (retry < MBHC_FW_READ_ATTEMPTS) {
3658 retry++;
3659 pr_info("%s:Attempt %d to request MBHC firmware\n",
3660 __func__, retry);
3661 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
3662 codec->dev);
3663
3664 if (ret != 0) {
3665 usleep_range(MBHC_FW_READ_TIMEOUT,
3666 MBHC_FW_READ_TIMEOUT);
3667 } else {
3668 pr_info("%s: MBHC Firmware read succesful\n", __func__);
3669 break;
3670 }
3671 }
3672
3673 if (ret != 0) {
3674 pr_err("%s: Cannot load MBHC firmware use default cal\n",
3675 __func__);
3676 } else if (tabla_mbhc_fw_validate(fw) == false) {
3677 pr_err("%s: Invalid MBHC cal data size use default cal\n",
3678 __func__);
3679 release_firmware(fw);
3680 } else {
3681 tabla->calibration = (void *)fw->data;
3682 tabla->mbhc_fw = fw;
3683 }
3684
3685 tabla->mclk_cb(codec, 1);
3686 tabla_mbhc_init(codec);
3687 tabla_mbhc_cal(codec);
3688 tabla_mbhc_calc_thres(codec);
3689 tabla->mclk_cb(codec, 0);
3690 tabla_codec_calibrate_hs_polling(codec);
3691 rc = tabla_codec_enable_hs_detect(codec, 1);
3692
3693 if (IS_ERR_VALUE(rc))
3694 pr_err("%s: Failed to setup MBHC detection\n", __func__);
3695
3696}
3697
Bradley Rubincb1e2732011-06-23 16:49:20 -07003698int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park0976d012011-12-22 11:48:18 -08003699 struct snd_soc_jack *headset_jack,
3700 struct snd_soc_jack *button_jack,
3701 void *calibration, enum tabla_micbias_num micbias,
3702 int (*mclk_cb_fn) (struct snd_soc_codec*, int),
3703 int read_fw_bin, u32 mclk_rate)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003704{
3705 struct tabla_priv *tabla;
Patrick Lai64b43262011-12-06 17:29:15 -08003706 int rc = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07003707
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003708 if (!codec || !calibration) {
3709 pr_err("Error: no codec or calibration\n");
3710 return -EINVAL;
3711 }
Joonwoo Park107edf02012-01-11 11:42:24 -08003712
3713 if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
3714 if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
3715 pr_err("Error: clock rate %dHz is not yet supported\n",
3716 mclk_rate);
3717 else
3718 pr_err("Error: unsupported clock rate %d\n", mclk_rate);
3719 return -EINVAL;
3720 }
3721
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003722 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003723 tabla->headset_jack = headset_jack;
3724 tabla->button_jack = button_jack;
Joonwoo Park0976d012011-12-22 11:48:18 -08003725 tabla->micbias = micbias;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003726 tabla->calibration = calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08003727 tabla->mclk_cb = mclk_cb_fn;
3728 tabla->mclk_freq = mclk_rate;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003729 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003730
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003731 /* Put CFILT in fast mode by default */
3732 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
3733 0x40, TABLA_CFILT_FAST_MODE);
Patrick Lai64b43262011-12-06 17:29:15 -08003734 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003735 INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
Patrick Lai49efeac2011-11-03 11:01:12 -07003736 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
3737 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
Joonwoo Park0976d012011-12-22 11:48:18 -08003738
3739 if (!read_fw_bin) {
3740 tabla->mclk_cb(codec, 1);
3741 tabla_mbhc_init(codec);
3742 tabla_mbhc_cal(codec);
3743 tabla_mbhc_calc_thres(codec);
3744 tabla->mclk_cb(codec, 0);
3745 tabla_codec_calibrate_hs_polling(codec);
3746 rc = tabla_codec_enable_hs_detect(codec, 1);
3747 } else {
Patrick Lai64b43262011-12-06 17:29:15 -08003748 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
3749 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Joonwoo Park0976d012011-12-22 11:48:18 -08003750 }
Patrick Lai49efeac2011-11-03 11:01:12 -07003751
3752 if (!IS_ERR_VALUE(rc)) {
3753 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3754 0x10);
3755 tabla_enable_irq(codec->control_data,
3756 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3757 tabla_enable_irq(codec->control_data,
3758 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3759 }
3760
3761 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003762}
3763EXPORT_SYMBOL_GPL(tabla_hs_detect);
3764
Bradley Rubincb1e2732011-06-23 16:49:20 -07003765static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003766{
3767 struct tabla_priv *priv = data;
3768 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003769 short bias_value;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003770
3771 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3772 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003773 tabla_lock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003774
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003775 bias_value = tabla_codec_read_dce_result(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08003776 pr_debug("%s: button press interrupt, DCE: %d,%d\n",
3777 __func__, bias_value,
3778 tabla_codec_sta_dce_v(codec, 1, bias_value));
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003779
Bhalchandra Gajare30cf4842011-10-17 18:12:52 -07003780 bias_value = tabla_codec_read_sta_result(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08003781 pr_debug("%s: button press interrupt, STA: %d,%d\n",
3782 __func__, bias_value,
3783 tabla_codec_sta_dce_v(codec, 0, bias_value));
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003784 /*
3785 * TODO: If button pressed is not button 0,
3786 * report the button press event immediately.
3787 */
3788 priv->buttons_pressed |= SND_JACK_BTN_0;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003789
Bradley Rubin688c66a2011-08-16 12:25:13 -07003790 msleep(100);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003791
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003792 if (schedule_delayed_work(&priv->btn0_dwork,
3793 msecs_to_jiffies(400)) == 0) {
3794 WARN(1, "Button pressed twice without release event\n");
3795 tabla_unlock_sleep(priv);
3796 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003798 return IRQ_HANDLED;
3799}
3800
Bradley Rubincb1e2732011-06-23 16:49:20 -07003801static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003802{
3803 struct tabla_priv *priv = data;
3804 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08003805 int ret, mb_v;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003806
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003807 pr_debug("%s\n", __func__);
3808 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003809 tabla_lock_sleep(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003810
Bradley Rubincb1e2732011-06-23 16:49:20 -07003811 if (priv->buttons_pressed & SND_JACK_BTN_0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003812 ret = cancel_delayed_work(&priv->btn0_dwork);
3813
3814 if (ret == 0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003815 pr_debug("%s: Reporting long button release event\n",
3816 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08003817 if (priv->button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003818 tabla_snd_soc_jack_report(priv,
3819 priv->button_jack, 0,
3820 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003821 } else {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003822 /* if scheduled btn0_dwork is canceled from here,
3823 * we have to unlock from here instead btn0_work */
3824 tabla_unlock_sleep(priv);
Joonwoo Park0976d012011-12-22 11:48:18 -08003825 mb_v = tabla_codec_sta_dce(codec, 0);
3826 pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
3827 __func__, mb_v,
3828 tabla_codec_sta_dce_v(codec, 0, mb_v));
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003829
Joonwoo Park0976d012011-12-22 11:48:18 -08003830 if (mb_v < -2000 || mb_v > -670)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003831 pr_debug("%s: Fake buttton press interrupt\n",
3832 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08003833 else if (priv->button_jack) {
3834 pr_debug("%s:reporting short button "
3835 "press and release\n", __func__);
3836 tabla_snd_soc_jack_report(priv,
3837 priv->button_jack,
3838 SND_JACK_BTN_0,
3839 SND_JACK_BTN_0);
3840 tabla_snd_soc_jack_report(priv,
3841 priv->button_jack,
3842 0, SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003843 }
3844 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003845
Bradley Rubincb1e2732011-06-23 16:49:20 -07003846 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003847 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003848
Bradley Rubin688c66a2011-08-16 12:25:13 -07003849 tabla_codec_start_hs_polling(codec);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003850 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003851 return IRQ_HANDLED;
3852}
3853
Bradley Rubincb1e2732011-06-23 16:49:20 -07003854static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
3855{
3856 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08003857 const struct tabla_mbhc_general_cfg *generic =
3858 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003859
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003860 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003861 tabla_codec_enable_config_mode(codec, 1);
3862
3863 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3864 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003865
Joonwoo Park0976d012011-12-22 11:48:18 -08003866 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
3867
3868 usleep_range(generic->t_shutdown_plug_rem,
3869 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003870
3871 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003872 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003873 tabla_codec_enable_config_mode(codec, 0);
3874
3875 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
3876}
3877
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003878static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
3879{
3880 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003881
3882 tabla_codec_shutdown_hs_removal_detect(codec);
3883
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003884 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003885 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
3886 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
3887 tabla_codec_enable_clock_block(codec, 0);
3888 }
3889
3890 tabla->mbhc_polling_active = false;
3891}
3892
Patrick Lai49efeac2011-11-03 11:01:12 -07003893static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
3894{
3895 struct tabla_priv *tabla = data;
3896 struct snd_soc_codec *codec;
3897
3898 pr_info("%s: received HPHL OCP irq\n", __func__);
3899
3900 if (tabla) {
3901 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08003902 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
3903 pr_info("%s: retry\n", __func__);
3904 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3905 0x00);
3906 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3907 0x10);
3908 } else {
3909 tabla_disable_irq(codec->control_data,
3910 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3911 tabla->hphlocp_cnt = 0;
3912 tabla->hph_status |= SND_JACK_OC_HPHL;
3913 if (tabla->headset_jack)
3914 tabla_snd_soc_jack_report(tabla,
3915 tabla->headset_jack,
3916 tabla->hph_status,
3917 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07003918 }
3919 } else {
3920 pr_err("%s: Bad tabla private data\n", __func__);
3921 }
3922
3923 return IRQ_HANDLED;
3924}
3925
3926static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
3927{
3928 struct tabla_priv *tabla = data;
3929 struct snd_soc_codec *codec;
3930
3931 pr_info("%s: received HPHR OCP irq\n", __func__);
3932
3933 if (tabla) {
3934 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08003935 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
3936 pr_info("%s: retry\n", __func__);
3937 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3938 0x00);
3939 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3940 0x10);
3941 } else {
3942 tabla_disable_irq(codec->control_data,
3943 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3944 tabla->hphrocp_cnt = 0;
3945 tabla->hph_status |= SND_JACK_OC_HPHR;
3946 if (tabla->headset_jack)
3947 tabla_snd_soc_jack_report(tabla,
3948 tabla->headset_jack,
3949 tabla->hph_status,
3950 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07003951 }
3952 } else {
3953 pr_err("%s: Bad tabla private data\n", __func__);
3954 }
3955
3956 return IRQ_HANDLED;
3957}
3958
Joonwoo Parka9444452011-12-08 18:48:27 -08003959static void tabla_sync_hph_state(struct tabla_priv *tabla)
3960{
3961 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
3962 &tabla->hph_pa_dac_state)) {
3963 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
3964 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
3965 1 << 4);
3966 }
3967 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
3968 &tabla->hph_pa_dac_state)) {
3969 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
3970 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
3971 1 << 5);
3972 }
3973
3974 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
3975 &tabla->hph_pa_dac_state)) {
3976 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
3977 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
3978 0xC0, 0xC0);
3979 }
3980 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
3981 &tabla->hph_pa_dac_state)) {
3982 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
3983 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
3984 0xC0, 0xC0);
3985 }
3986}
3987
Bradley Rubincb1e2732011-06-23 16:49:20 -07003988static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
3989{
3990 struct tabla_priv *priv = data;
3991 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08003992 const struct tabla_mbhc_plug_detect_cfg *plug_det =
3993 TABLA_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
Bradley Rubin355611a2011-08-24 14:01:18 -07003994 int ldo_h_on, micb_cfilt_on;
Joonwoo Park0976d012011-12-22 11:48:18 -08003995 short mb_v;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003996 u8 is_removal;
Joonwoo Park0976d012011-12-22 11:48:18 -08003997 int mic_mv;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003998
Joonwoo Parkf4267c22012-01-10 13:25:24 -08003999 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004000 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004001 tabla_lock_sleep(priv);
4002
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004003 is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
4004 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
4005
4006 /* Turn off both HPH and MIC line schmitt triggers */
Joonwoo Park0976d012011-12-22 11:48:18 -08004007 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004008 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004009
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004010 if (priv->mbhc_fake_ins_start &&
4011 time_after(jiffies, priv->mbhc_fake_ins_start +
4012 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004013 pr_debug("%s: fake context interrupt, reset insertion\n",
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004014 __func__);
4015 priv->mbhc_fake_ins_start = 0;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004016 tabla_codec_shutdown_hs_polling(codec);
4017 tabla_codec_enable_hs_detect(codec, 1);
4018 return IRQ_HANDLED;
4019 }
4020
Bradley Rubin355611a2011-08-24 14:01:18 -07004021 ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
Joonwoo Park0976d012011-12-22 11:48:18 -08004022 micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
4023 & 0x80;
Bradley Rubin355611a2011-08-24 14:01:18 -07004024
4025 if (!ldo_h_on)
4026 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
4027 if (!micb_cfilt_on)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004028 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08004029 0x80, 0x80);
4030 if (plug_det->t_ins_complete > 20)
4031 msleep(plug_det->t_ins_complete);
4032 else
4033 usleep_range(plug_det->t_ins_complete * 1000,
4034 plug_det->t_ins_complete * 1000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004035
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004036 if (!ldo_h_on)
4037 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
4038 if (!micb_cfilt_on)
4039 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08004040 0x80, 0x0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004041
4042 if (is_removal) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004043 /*
4044 * If headphone is removed while playback is in progress,
4045 * it is possible that micbias will be switched to VDDIO.
4046 */
4047 if (priv->mbhc_micbias_switched)
4048 tabla_codec_switch_micbias(codec, 0);
Patrick Lai72aa4da2011-12-08 12:38:18 -08004049 priv->hph_status &= ~SND_JACK_HEADPHONE;
Joonwoo Parka9444452011-12-08 18:48:27 -08004050
4051 /* If headphone PA is on, check if userspace receives
4052 * removal event to sync-up PA's state */
4053 if (tabla_is_hph_pa_on(codec)) {
4054 set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
4055 set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
4056 }
4057
4058 if (tabla_is_hph_dac_on(codec, 1))
4059 set_bit(TABLA_HPHL_DAC_OFF_ACK,
4060 &priv->hph_pa_dac_state);
4061 if (tabla_is_hph_dac_on(codec, 0))
4062 set_bit(TABLA_HPHR_DAC_OFF_ACK,
4063 &priv->hph_pa_dac_state);
4064
Bradley Rubincb1e2732011-06-23 16:49:20 -07004065 if (priv->headset_jack) {
4066 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004067 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4068 priv->hph_status,
4069 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004070 }
4071 tabla_codec_shutdown_hs_removal_detect(codec);
4072 tabla_codec_enable_hs_detect(codec, 1);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004073 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004074 return IRQ_HANDLED;
4075 }
4076
Joonwoo Park0976d012011-12-22 11:48:18 -08004077 mb_v = tabla_codec_setup_hs_polling(codec);
4078 mic_mv = tabla_codec_sta_dce_v(codec, 0, mb_v);
Bradley Rubin355611a2011-08-24 14:01:18 -07004079
Joonwoo Park0976d012011-12-22 11:48:18 -08004080 if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004081 pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
4082 "STA : %d,%d\n", __func__,
4083 (priv->mbhc_fake_ins_start ?
4084 jiffies_to_msecs(jiffies -
4085 priv->mbhc_fake_ins_start) :
4086 0),
4087 mb_v, mic_mv);
4088 if (time_after(jiffies,
4089 priv->mbhc_fake_ins_start +
4090 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
4091 /* Disable HPH trigger and enable MIC line trigger */
4092 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
4093 0x00);
4094 snd_soc_update_bits(codec,
4095 priv->mbhc_bias_regs.mbhc_reg, 0x60,
4096 plug_det->mic_current << 5);
4097 snd_soc_update_bits(codec,
4098 priv->mbhc_bias_regs.mbhc_reg,
4099 0x80, 0x80);
4100 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4101 snd_soc_update_bits(codec,
4102 priv->mbhc_bias_regs.mbhc_reg,
4103 0x10, 0x10);
4104 } else {
4105 if (priv->mbhc_fake_ins_start == 0)
4106 priv->mbhc_fake_ins_start = jiffies;
4107 /* Setup normal insert detection
4108 * Enable HPH Schmitt Trigger
4109 */
4110 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH,
4111 0x13 | 0x0C,
4112 0x13 | plug_det->hph_current << 2);
4113 }
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004114 /* Setup for insertion detection */
4115 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004116 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4117 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4118
Joonwoo Park0976d012011-12-22 11:48:18 -08004119 } else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
4120 pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
4121 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004122 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07004123 priv->hph_status |= SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004124 if (priv->headset_jack) {
4125 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08004126 SND_JACK_HEADPHONE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004127 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4128 priv->hph_status,
4129 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004130 }
4131 tabla_codec_shutdown_hs_polling(codec);
4132 tabla_codec_enable_hs_detect(codec, 0);
Joonwoo Parka9444452011-12-08 18:48:27 -08004133 tabla_sync_hph_state(priv);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004134 } else {
Joonwoo Park0976d012011-12-22 11:48:18 -08004135 pr_debug("%s: Headset detected, mb_v: %d,%d\n",
4136 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004137 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07004138 priv->hph_status |= SND_JACK_HEADSET;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004139 if (priv->headset_jack) {
4140 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08004141 SND_JACK_HEADSET);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004142 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4143 priv->hph_status,
4144 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004145 }
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004146 /* avoid false button press detect */
4147 msleep(50);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004148 tabla_codec_start_hs_polling(codec);
Joonwoo Parka9444452011-12-08 18:48:27 -08004149 tabla_sync_hph_state(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004150 }
4151
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004152 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004153 return IRQ_HANDLED;
4154}
4155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
4157{
4158 struct tabla_priv *priv = data;
4159 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08004160 const struct tabla_mbhc_general_cfg *generic =
4161 TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004162 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004163
4164 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4165 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004166 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004167 tabla_lock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004168
Joonwoo Park0976d012011-12-22 11:48:18 -08004169 usleep_range(generic->t_shutdown_plug_rem,
4170 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004171
Joonwoo Park0976d012011-12-22 11:48:18 -08004172 bias_value = tabla_codec_sta_dce(codec, 1);
4173 pr_debug("removal interrupt, DCE: %d,%d\n",
4174 bias_value, tabla_codec_sta_dce_v(codec, 1, bias_value));
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004175
Joonwoo Park0976d012011-12-22 11:48:18 -08004176 if (bias_value < (short) priv->mbhc_data.v_ins_h) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004177 pr_debug("False alarm, headset not actually removed\n");
4178 tabla_codec_start_hs_polling(codec);
4179 } else {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004180 /*
4181 * If this removal is not false, first check the micbias
4182 * switch status and switch it to LDOH if it is already
4183 * switched to VDDIO.
4184 */
4185 if (priv->mbhc_micbias_switched)
4186 tabla_codec_switch_micbias(codec, 0);
Patrick Lai49efeac2011-11-03 11:01:12 -07004187 priv->hph_status &= ~SND_JACK_HEADSET;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004188 if (priv->headset_jack) {
4189 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004190 tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
4191 TABLA_JACK_MASK);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004192 }
4193 tabla_codec_shutdown_hs_polling(codec);
4194
4195 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004196 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004197
4198 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004199 return IRQ_HANDLED;
4200}
4201
4202static unsigned long slimbus_value;
4203
4204static irqreturn_t tabla_slimbus_irq(int irq, void *data)
4205{
4206 struct tabla_priv *priv = data;
4207 struct snd_soc_codec *codec = priv->codec;
4208 int i, j;
4209 u8 val;
4210
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004211 tabla_lock_sleep(priv);
4212
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004213 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
4214 slimbus_value = tabla_interface_reg_read(codec->control_data,
4215 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
4216 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
4217 val = tabla_interface_reg_read(codec->control_data,
4218 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
4219 if (val & 0x1)
4220 pr_err_ratelimited("overflow error on port %x,"
4221 " value %x\n", i*8 + j, val);
4222 if (val & 0x2)
4223 pr_err_ratelimited("underflow error on port %x,"
4224 " value %x\n", i*8 + j, val);
4225 }
4226 tabla_interface_reg_write(codec->control_data,
4227 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
4228 }
4229
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004230 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004231 return IRQ_HANDLED;
4232}
4233
Patrick Lai3043fba2011-08-01 14:15:57 -07004234
4235static int tabla_handle_pdata(struct tabla_priv *tabla)
4236{
4237 struct snd_soc_codec *codec = tabla->codec;
4238 struct tabla_pdata *pdata = tabla->pdata;
4239 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05304240 u8 leg_mode = pdata->amic_settings.legacy_mode;
4241 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4242 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4243 u8 flag = pdata->amic_settings.use_pdata;
4244 u8 i = 0, j = 0;
4245 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07004246
4247 if (!pdata) {
4248 rc = -ENODEV;
4249 goto done;
4250 }
4251
4252 /* Make sure settings are correct */
4253 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
4254 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
4255 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
4256 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
4257 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
4258 rc = -EINVAL;
4259 goto done;
4260 }
4261
4262 /* figure out k value */
4263 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
4264 pdata->micbias.cfilt1_mv);
4265 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
4266 pdata->micbias.cfilt2_mv);
4267 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
4268 pdata->micbias.cfilt3_mv);
4269
4270 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
4271 rc = -EINVAL;
4272 goto done;
4273 }
4274
4275 /* Set voltage level and always use LDO */
4276 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
4277 (pdata->micbias.ldoh_v << 2));
4278
4279 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
4280 (k1 << 2));
4281 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
4282 (k2 << 2));
4283 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
4284 (k3 << 2));
4285
4286 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
4287 (pdata->micbias.bias1_cfilt_sel << 5));
4288 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
4289 (pdata->micbias.bias2_cfilt_sel << 5));
4290 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
4291 (pdata->micbias.bias3_cfilt_sel << 5));
4292 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
4293 (pdata->micbias.bias4_cfilt_sel << 5));
4294
Santosh Mardi22920282011-10-26 02:38:40 +05304295 for (i = 0; i < 6; j++, i += 2) {
4296 if (flag & (0x01 << i)) {
4297 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
4298 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4299 val_txfe = val_txfe |
4300 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4301 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4302 0x10, value);
4303 snd_soc_update_bits(codec,
4304 TABLA_A_TX_1_2_TEST_EN + j * 10,
4305 0x30, val_txfe);
4306 }
4307 if (flag & (0x01 << (i + 1))) {
4308 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
4309 val_txfe = (txfe_bypass &
4310 (0x01 << (i + 1))) ? 0x02 : 0x00;
4311 val_txfe |= (txfe_buff &
4312 (0x01 << (i + 1))) ? 0x01 : 0x00;
4313 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4314 0x01, value);
4315 snd_soc_update_bits(codec,
4316 TABLA_A_TX_1_2_TEST_EN + j * 10,
4317 0x03, val_txfe);
4318 }
4319 }
4320 if (flag & 0x40) {
4321 value = (leg_mode & 0x40) ? 0x10 : 0x00;
4322 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
4323 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
4324 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
4325 0x13, value);
4326 }
Patrick Lai49efeac2011-11-03 11:01:12 -07004327
4328 if (pdata->ocp.use_pdata) {
4329 /* not defined in CODEC specification */
4330 if (pdata->ocp.hph_ocp_limit == 1 ||
4331 pdata->ocp.hph_ocp_limit == 5) {
4332 rc = -EINVAL;
4333 goto done;
4334 }
4335 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
4336 0x0F, pdata->ocp.num_attempts);
4337 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
4338 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4339 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
4340 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4341 }
Patrick Lai3043fba2011-08-01 14:15:57 -07004342done:
4343 return rc;
4344}
4345
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004346static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
4347
4348 /* Tabla 1.1 MICBIAS changes */
4349 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
4350 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
4351 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
4352 TABLA_REG_VAL(TABLA_A_MICB_4_INT_RBIAS, 0x24),
4353
4354 /* Tabla 1.1 HPH changes */
4355 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
4356 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
4357
4358 /* Tabla 1.1 EAR PA changes */
4359 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
4360 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
4361 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
4362
4363 /* Tabla 1.1 Lineout_5 Changes */
4364 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
4365
4366 /* Tabla 1.1 RX Changes */
4367 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
4368 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
4369 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
4370 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
4371 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
4372 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
4373 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
4374
4375 /* Tabla 1.1 RX1 and RX2 Changes */
4376 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
4377 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
4378
4379 /* Tabla 1.1 RX3 to RX7 Changes */
4380 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
4381 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
4382 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
4383 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
4384 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
4385
4386 /* Tabla 1.1 CLASSG Changes */
4387 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
4388};
4389
4390static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
4391
4392 /* Tabla 2.0 MICBIAS changes */
4393 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
4394};
4395
4396static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
4397{
4398 u32 i;
4399
4400 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
4401 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
4402 tabla_1_1_reg_defaults[i].val);
4403
4404 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
4405 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
4406 tabla_2_0_reg_defaults[i].val);
4407}
4408
4409static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08004410 /* Initialize current threshold to 350MA
4411 * number of wait and run cycles to 4096
4412 */
Patrick Lai49efeac2011-11-03 11:01:12 -07004413 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08004414 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004415
Santosh Mardi32171012011-10-28 23:32:06 +05304416 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
4417
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004418 /* Initialize gain registers to use register gain */
4419 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
4420 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
4421 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
4422 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
4423 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
4424 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
4425
4426 /* Initialize mic biases to differential mode */
4427 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
4428 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
4429 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
4430 {TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24},
4431
4432 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
4433
4434 /* Use 16 bit sample size for TX1 to TX6 */
4435 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
4436 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4437 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4438 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4439 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
4440 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
4441
4442 /* Use 16 bit sample size for TX7 to TX10 */
4443 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
4444 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
4445 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
4446 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
4447
4448 /* Use 16 bit sample size for RX */
4449 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4450 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
4451
4452 /*enable HPF filter for TX paths */
4453 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
4454 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
4455 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
4456 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
4457 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
4458 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
4459 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
4460 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
4461 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
4462 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
4463};
4464
4465static void tabla_codec_init_reg(struct snd_soc_codec *codec)
4466{
4467 u32 i;
4468
4469 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
4470 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
4471 tabla_codec_reg_init_val[i].mask,
4472 tabla_codec_reg_init_val[i].val);
4473}
4474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004475static int tabla_codec_probe(struct snd_soc_codec *codec)
4476{
4477 struct tabla *control;
4478 struct tabla_priv *tabla;
4479 struct snd_soc_dapm_context *dapm = &codec->dapm;
4480 int ret = 0;
4481 int i;
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004482 u8 tabla_version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004483
4484 codec->control_data = dev_get_drvdata(codec->dev->parent);
4485 control = codec->control_data;
4486
4487 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
4488 if (!tabla) {
4489 dev_err(codec->dev, "Failed to allocate private data\n");
4490 return -ENOMEM;
4491 }
4492
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004493 /* Make sure mbhc micbias register addresses are zeroed out */
4494 memset(&tabla->mbhc_bias_regs, 0,
4495 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004496 tabla->cfilt_k_value = 0;
4497 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004498
Joonwoo Park0976d012011-12-22 11:48:18 -08004499 /* Make sure mbhc intenal calibration data is zeroed out */
4500 memset(&tabla->mbhc_data, 0,
4501 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08004502 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08004503 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
4504 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004505 snd_soc_codec_set_drvdata(codec, tabla);
4506
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004507 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508 tabla->bandgap_type = TABLA_BANDGAP_OFF;
4509 tabla->clock_active = false;
4510 tabla->config_mode_active = false;
4511 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004512 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004513 tabla->no_mic_headset_override = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004514 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07004515 tabla->pdata = dev_get_platdata(codec->dev->parent);
Santosh Mardie15e2302011-11-15 10:39:23 +05304516 tabla->intf_type = tabla_get_intf_type();
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004517 atomic_set(&tabla->pm_cnt, 1);
4518 init_waitqueue_head(&tabla->pm_wq);
Patrick Lai3043fba2011-08-01 14:15:57 -07004519
Santosh Mardi22920282011-10-26 02:38:40 +05304520 tabla_update_reg_defaults(codec);
4521 tabla_codec_init_reg(codec);
Patrick Lai3043fba2011-08-01 14:15:57 -07004522
Santosh Mardi22920282011-10-26 02:38:40 +05304523 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07004524 if (IS_ERR_VALUE(ret)) {
4525 pr_err("%s: bad pdata\n", __func__);
4526 goto err_pdata;
4527 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528
4529 /* TODO only enable bandgap when necessary in order to save power */
4530 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_AUDIO_MODE);
4531 tabla_codec_enable_clock_block(codec, 0);
4532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004533 snd_soc_add_controls(codec, tabla_snd_controls,
4534 ARRAY_SIZE(tabla_snd_controls));
4535 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
4536 ARRAY_SIZE(tabla_dapm_widgets));
Santosh Mardie15e2302011-11-15 10:39:23 +05304537 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
4538 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
4539 ARRAY_SIZE(tabla_dapm_i2s_widgets));
4540 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
4541 ARRAY_SIZE(audio_i2s_map));
4542 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004543 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004544
4545 tabla_version = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
Joonwoo Park0976d012011-12-22 11:48:18 -08004546 pr_info("%s : Tabla version reg 0x%2x\n", __func__,
4547 (u32)tabla_version);
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004548
4549 tabla_version &= 0x1F;
4550 pr_info("%s : Tabla version %u\n", __func__, (u32)tabla_version);
4551
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004552 if ((tabla_version == TABLA_VERSION_1_0) ||
4553 (tabla_version == TABLA_VERSION_1_1)) {
4554 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004555 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
4556
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004557 } else if (tabla_version == TABLA_VERSION_2_0) {
4558 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
4559 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
4560 } else {
4561 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
4562 __func__, (u32)tabla_version);
4563 goto err_pdata;
4564 }
4565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004566 snd_soc_dapm_sync(dapm);
4567
4568 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
4569 tabla_hs_insert_irq, "Headset insert detect", tabla);
4570 if (ret) {
4571 pr_err("%s: Failed to request irq %d\n", __func__,
4572 TABLA_IRQ_MBHC_INSERTION);
4573 goto err_insert_irq;
4574 }
4575 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4576
4577 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
4578 tabla_hs_remove_irq, "Headset remove detect", tabla);
4579 if (ret) {
4580 pr_err("%s: Failed to request irq %d\n", __func__,
4581 TABLA_IRQ_MBHC_REMOVAL);
4582 goto err_remove_irq;
4583 }
4584 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4585
4586 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004587 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004588 if (ret) {
4589 pr_err("%s: Failed to request irq %d\n", __func__,
4590 TABLA_IRQ_MBHC_POTENTIAL);
4591 goto err_potential_irq;
4592 }
4593 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4594
Bradley Rubincb1e2732011-06-23 16:49:20 -07004595 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
4596 tabla_release_handler, "Button Release detect", tabla);
4597 if (ret) {
4598 pr_err("%s: Failed to request irq %d\n", __func__,
4599 TABLA_IRQ_MBHC_RELEASE);
4600 goto err_release_irq;
4601 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004602 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004604 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
4605 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
4606 if (ret) {
4607 pr_err("%s: Failed to request irq %d\n", __func__,
4608 TABLA_IRQ_SLIMBUS);
4609 goto err_slimbus_irq;
4610 }
4611
4612 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
4613 tabla_interface_reg_write(codec->control_data,
4614 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
4615
Patrick Lai49efeac2011-11-03 11:01:12 -07004616 ret = tabla_request_irq(codec->control_data,
4617 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
4618 "HPH_L OCP detect", tabla);
4619 if (ret) {
4620 pr_err("%s: Failed to request irq %d\n", __func__,
4621 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4622 goto err_hphl_ocp_irq;
4623 }
Patrick Lai92032be2011-12-19 14:14:25 -08004624 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004625
4626 ret = tabla_request_irq(codec->control_data,
4627 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
4628 "HPH_R OCP detect", tabla);
4629 if (ret) {
4630 pr_err("%s: Failed to request irq %d\n", __func__,
4631 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4632 goto err_hphr_ocp_irq;
4633 }
Patrick Lai92032be2011-12-19 14:14:25 -08004634 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004635
Bradley Rubincb3950a2011-08-18 13:07:26 -07004636#ifdef CONFIG_DEBUG_FS
4637 debug_tabla_priv = tabla;
4638#endif
4639
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004640 return ret;
4641
Patrick Lai49efeac2011-11-03 11:01:12 -07004642err_hphr_ocp_irq:
4643 tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
4644err_hphl_ocp_irq:
4645 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004646err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07004647 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
4648err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004649 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4650err_potential_irq:
4651 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4652err_remove_irq:
4653 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4654err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07004655err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004656 kfree(tabla);
4657 return ret;
4658}
4659static int tabla_codec_remove(struct snd_soc_codec *codec)
4660{
4661 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4662 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004663 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004664 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4665 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4666 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4667 tabla_codec_disable_clock_block(codec);
4668 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08004669 if (tabla->mbhc_fw)
4670 release_firmware(tabla->mbhc_fw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004671 kfree(tabla);
4672 return 0;
4673}
4674static struct snd_soc_codec_driver soc_codec_dev_tabla = {
4675 .probe = tabla_codec_probe,
4676 .remove = tabla_codec_remove,
4677 .read = tabla_read,
4678 .write = tabla_write,
4679
4680 .readable_register = tabla_readable,
4681 .volatile_register = tabla_volatile,
4682
4683 .reg_cache_size = TABLA_CACHE_SIZE,
4684 .reg_cache_default = tabla_reg_defaults,
4685 .reg_word_size = 1,
4686};
Bradley Rubincb3950a2011-08-18 13:07:26 -07004687
4688#ifdef CONFIG_DEBUG_FS
4689static struct dentry *debugfs_poke;
4690
4691static int codec_debug_open(struct inode *inode, struct file *file)
4692{
4693 file->private_data = inode->i_private;
4694 return 0;
4695}
4696
4697static ssize_t codec_debug_write(struct file *filp,
4698 const char __user *ubuf, size_t cnt, loff_t *ppos)
4699{
4700 char lbuf[32];
4701 char *buf;
4702 int rc;
4703
4704 if (cnt > sizeof(lbuf) - 1)
4705 return -EINVAL;
4706
4707 rc = copy_from_user(lbuf, ubuf, cnt);
4708 if (rc)
4709 return -EFAULT;
4710
4711 lbuf[cnt] = '\0';
4712 buf = (char *)lbuf;
4713 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
4714 ? false : true;
4715
4716 return rc;
4717}
4718
4719static const struct file_operations codec_debug_ops = {
4720 .open = codec_debug_open,
4721 .write = codec_debug_write,
4722};
4723#endif
4724
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004725#ifdef CONFIG_PM
4726static int tabla_suspend(struct device *dev)
4727{
4728 int ret = 0, cnt;
4729 struct platform_device *pdev = to_platform_device(dev);
4730 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4731
4732 cnt = atomic_read(&tabla->pm_cnt);
4733 if (cnt > 0) {
4734 if (wait_event_timeout(tabla->pm_wq,
4735 (atomic_cmpxchg(&tabla->pm_cnt, 1, 0)
4736 == 1), 5 * HZ)) {
4737 dev_dbg(dev, "system suspend pm_cnt %d\n",
4738 atomic_read(&tabla->pm_cnt));
4739 } else {
4740 dev_err(dev, "%s timed out pm_cnt = %d\n",
4741 __func__, atomic_read(&tabla->pm_cnt));
4742 WARN_ON_ONCE(1);
4743 ret = -EBUSY;
4744 }
4745 } else if (cnt == 0)
4746 dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
4747 atomic_read(&tabla->pm_cnt));
4748 else {
4749 WARN(1, "unexpected pm_cnt %d\n", cnt);
4750 ret = -EFAULT;
4751 }
4752
4753 return ret;
4754}
4755
4756static int tabla_resume(struct device *dev)
4757{
4758 int ret = 0, cnt;
4759 struct platform_device *pdev = to_platform_device(dev);
4760 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4761
4762 cnt = atomic_cmpxchg(&tabla->pm_cnt, 0, 1);
4763 if (cnt == 0) {
4764 dev_dbg(dev, "system resume, pm_cnt %d\n",
4765 atomic_read(&tabla->pm_cnt));
4766 wake_up_all(&tabla->pm_wq);
4767 } else if (cnt > 0)
4768 dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
4769 else {
4770 WARN(1, "unexpected pm_cnt %d\n", cnt);
4771 ret = -EFAULT;
4772 }
4773
4774 return ret;
4775}
4776
4777static const struct dev_pm_ops tabla_pm_ops = {
4778 .suspend = tabla_suspend,
4779 .resume = tabla_resume,
4780};
4781#endif
4782
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004783static int __devinit tabla_probe(struct platform_device *pdev)
4784{
Santosh Mardie15e2302011-11-15 10:39:23 +05304785 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004786#ifdef CONFIG_DEBUG_FS
4787 debugfs_poke = debugfs_create_file("TRRS",
4788 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
4789
4790#endif
Santosh Mardie15e2302011-11-15 10:39:23 +05304791 if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
4792 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4793 tabla_dai, ARRAY_SIZE(tabla_dai));
4794 else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
4795 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4796 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
4797 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004798}
4799static int __devexit tabla_remove(struct platform_device *pdev)
4800{
4801 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07004802
4803#ifdef CONFIG_DEBUG_FS
4804 debugfs_remove(debugfs_poke);
4805#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004806 return 0;
4807}
4808static struct platform_driver tabla_codec_driver = {
4809 .probe = tabla_probe,
4810 .remove = tabla_remove,
4811 .driver = {
4812 .name = "tabla_codec",
4813 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004814#ifdef CONFIG_PM
4815 .pm = &tabla_pm_ops,
4816#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004817 },
4818};
4819
4820static int __init tabla_codec_init(void)
4821{
4822 return platform_driver_register(&tabla_codec_driver);
4823}
4824
4825static void __exit tabla_codec_exit(void)
4826{
4827 platform_driver_unregister(&tabla_codec_driver);
4828}
4829
4830module_init(tabla_codec_init);
4831module_exit(tabla_codec_exit);
4832
4833MODULE_DESCRIPTION("Tabla codec driver");
4834MODULE_VERSION("1.0");
4835MODULE_LICENSE("GPL v2");