blob: 50dede536fee4e02aeb343f2d9b1062795e2db25 [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/soc.h>
27#include <sound/soc-dapm.h>
28#include <sound/tlv.h>
29#include <linux/bitops.h>
30#include <linux/delay.h>
31#include "wcd9310.h"
32
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070033#define WCD9310_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
34 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
35
36#define NUM_DECIMATORS 10
37#define NUM_INTERPOLATORS 7
38#define BITS_PER_REG 8
39#define TABLA_RX_DAI_ID 1
40#define TABLA_TX_DAI_ID 2
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080041#define TABLA_CFILT_FAST_MODE 0x00
42#define TABLA_CFILT_SLOW_MODE 0x40
Patrick Lai64b43262011-12-06 17:29:15 -080043#define MBHC_FW_READ_ATTEMPTS 15
44#define MBHC_FW_READ_TIMEOUT 2000000
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070045
Patrick Lai49efeac2011-11-03 11:01:12 -070046#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
47
Santosh Mardie15e2302011-11-15 10:39:23 +053048#define TABLA_I2S_MASTER_MODE_MASK 0x08
49
Patrick Laic7cae882011-11-18 11:52:49 -080050#define TABLA_OCP_ATTEMPT 1
51
Joonwoo Park0976d012011-12-22 11:48:18 -080052#define TABLA_MCLK_RATE_12288KHZ 12288000
53#define TABLA_MCLK_RATE_9600KHZ 9600000
54
Joonwoo Parkf4267c22012-01-10 13:25:24 -080055#define TABLA_FAKE_INS_THRESHOLD_MS 2500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -080056#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
Joonwoo Parkf4267c22012-01-10 13:25:24 -080057
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);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302613 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002614 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
2615 0x2);
2616 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2617 0x80);
2618 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
2619 0x4);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302620 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2621 0x01);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622 usleep_range(1000, 1000);
2623 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2624 0x00);
2625 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
2626 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2627 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2628 usleep_range(100, 100);
2629 tabla_codec_enable_audio_mode_bandgap(codec);
2630 } else if (choice == TABLA_BANDGAP_OFF) {
2631 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2632 } else {
2633 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2634 }
2635 tabla->bandgap_type = choice;
2636}
2637
2638static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
2639 int enable)
2640{
2641 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2642
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002643 pr_debug("%s: enable = %d\n", __func__, enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644 if (enable) {
2645 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
2646 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
2647 usleep_range(5, 5);
2648 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
2649 0x80);
2650 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
2651 0x80);
2652 usleep_range(10, 10);
2653 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
2654 usleep_range(20, 20);
2655 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
2656 } else {
2657 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
2658 0);
2659 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002660 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002661 }
2662 tabla->config_mode_active = enable ? true : false;
2663
2664 return 0;
2665}
2666
2667static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
2668 int config_mode)
2669{
2670 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2671
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002672 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002673
2674 if (config_mode) {
2675 tabla_codec_enable_config_mode(codec, 1);
2676 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
2677 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2678 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
2679 usleep_range(1000, 1000);
2680 } else
2681 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
2682
2683 if (!config_mode && tabla->mbhc_polling_active) {
2684 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2685 tabla_codec_enable_config_mode(codec, 0);
2686
2687 }
2688
2689 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
2690 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
2691 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
2692 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
2693 usleep_range(50, 50);
2694 tabla->clock_active = true;
2695 return 0;
2696}
2697static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
2698{
2699 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2700 pr_debug("%s\n", __func__);
2701 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
2702 ndelay(160);
2703 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
2704 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
2705 tabla->clock_active = false;
2706}
2707
Joonwoo Park107edf02012-01-11 11:42:24 -08002708static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
2709{
2710 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
2711 return 0;
2712 else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
2713 return 1;
2714 else {
2715 BUG_ON(1);
2716 return -EINVAL;
2717 }
2718}
2719
Bradley Rubincb1e2732011-06-23 16:49:20 -07002720static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2721{
Joonwoo Parkc0672392012-01-11 11:03:14 -08002722 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08002723 struct tabla_mbhc_btn_detect_cfg *btn_det;
2724 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002725
Joonwoo Park0976d012011-12-22 11:48:18 -08002726 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002727
Joonwoo Park0976d012011-12-22 11:48:18 -08002728 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2729 tabla->mbhc_data.v_ins_hu & 0xFF);
2730 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2731 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002732
Joonwoo Park0976d012011-12-22 11:48:18 -08002733 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2734 tabla->mbhc_data.v_b1_hu & 0xFF);
2735 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2736 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
2737
2738 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2739 tabla->mbhc_data.v_b1_h & 0xFF);
2740 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2741 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
2742
2743 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
2744 tabla->mbhc_data.v_brh & 0xFF);
2745 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
2746 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
2747
2748 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
2749 tabla->mbhc_data.v_brl & 0xFF);
2750 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
2751 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
2752
Joonwoo Parkc0672392012-01-11 11:03:14 -08002753 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08002754 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08002755 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08002756 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
2757 tabla->mbhc_data.npoll);
2758 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
2759 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08002760 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);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302797 } else {
2798 tabla_codec_enable_bandgap(codec,
2799 TABLA_BANDGAP_AUDIO_MODE);
2800 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002801 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002802 } else {
2803
2804 if (!tabla->mclk_enabled) {
2805 pr_err("Error, MCLK already diabled\n");
2806 return -EINVAL;
2807 }
2808 tabla->mclk_enabled = false;
2809
2810 if (tabla->mbhc_polling_active) {
2811 if (!tabla->mclk_enabled) {
2812 tabla_codec_pause_hs_polling(codec);
2813 tabla_codec_enable_bandgap(codec,
2814 TABLA_BANDGAP_MBHC_MODE);
2815 tabla_enable_rx_bias(codec, 1);
2816 tabla_codec_enable_clock_block(codec, 1);
2817 tabla_codec_calibrate_hs_polling(codec);
2818 tabla_codec_start_hs_polling(codec);
2819 }
2820 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
2821 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302822 } else {
2823 tabla_codec_disable_clock_block(codec);
2824 tabla_codec_enable_bandgap(codec,
2825 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002826 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002827 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002828 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829}
2830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002831static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
2832 int clk_id, unsigned int freq, int dir)
2833{
2834 pr_debug("%s\n", __func__);
2835 return 0;
2836}
2837
2838static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2839{
Santosh Mardie15e2302011-11-15 10:39:23 +05302840 u8 val = 0;
2841 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
2842
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002843 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05302844 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2845 case SND_SOC_DAIFMT_CBS_CFS:
2846 /* CPU is master */
2847 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2848 if (dai->id == TABLA_TX_DAI_ID)
2849 snd_soc_update_bits(dai->codec,
2850 TABLA_A_CDC_CLK_TX_I2S_CTL,
2851 TABLA_I2S_MASTER_MODE_MASK, 0);
2852 else if (dai->id == TABLA_RX_DAI_ID)
2853 snd_soc_update_bits(dai->codec,
2854 TABLA_A_CDC_CLK_RX_I2S_CTL,
2855 TABLA_I2S_MASTER_MODE_MASK, 0);
2856 }
2857 break;
2858 case SND_SOC_DAIFMT_CBM_CFM:
2859 /* CPU is slave */
2860 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2861 val = TABLA_I2S_MASTER_MODE_MASK;
2862 if (dai->id == TABLA_TX_DAI_ID)
2863 snd_soc_update_bits(dai->codec,
2864 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
2865 else if (dai->id == TABLA_RX_DAI_ID)
2866 snd_soc_update_bits(dai->codec,
2867 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
2868 }
2869 break;
2870 default:
2871 return -EINVAL;
2872 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002873 return 0;
2874}
2875
2876static int tabla_hw_params(struct snd_pcm_substream *substream,
2877 struct snd_pcm_hw_params *params,
2878 struct snd_soc_dai *dai)
2879{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002880 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05302881 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07002882 u8 path, shift;
2883 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002884 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
2885
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002886 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002887
2888 switch (params_rate(params)) {
2889 case 8000:
2890 tx_fs_rate = 0x00;
2891 rx_fs_rate = 0x00;
2892 break;
2893 case 16000:
2894 tx_fs_rate = 0x01;
2895 rx_fs_rate = 0x20;
2896 break;
2897 case 32000:
2898 tx_fs_rate = 0x02;
2899 rx_fs_rate = 0x40;
2900 break;
2901 case 48000:
2902 tx_fs_rate = 0x03;
2903 rx_fs_rate = 0x60;
2904 break;
2905 default:
2906 pr_err("%s: Invalid sampling rate %d\n", __func__,
2907 params_rate(params));
2908 return -EINVAL;
2909 }
2910
2911
2912 /**
2913 * If current dai is a tx dai, set sample rate to
2914 * all the txfe paths that are currently not active
2915 */
2916 if (dai->id == TABLA_TX_DAI_ID) {
2917
2918 tx_state = snd_soc_read(codec,
2919 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
2920
2921 for (path = 1, shift = 0;
2922 path <= NUM_DECIMATORS; path++, shift++) {
2923
2924 if (path == BITS_PER_REG + 1) {
2925 shift = 0;
2926 tx_state = snd_soc_read(codec,
2927 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
2928 }
2929
2930 if (!(tx_state & (1 << shift))) {
2931 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
2932 + (BITS_PER_REG*(path-1));
2933 snd_soc_update_bits(codec, tx_fs_reg,
2934 0x03, tx_fs_rate);
2935 }
2936 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302937 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2938 switch (params_format(params)) {
2939 case SNDRV_PCM_FORMAT_S16_LE:
2940 snd_soc_update_bits(codec,
2941 TABLA_A_CDC_CLK_TX_I2S_CTL,
2942 0x20, 0x20);
2943 break;
2944 case SNDRV_PCM_FORMAT_S32_LE:
2945 snd_soc_update_bits(codec,
2946 TABLA_A_CDC_CLK_TX_I2S_CTL,
2947 0x20, 0x00);
2948 break;
2949 default:
2950 pr_err("invalid format\n");
2951 break;
2952 }
2953 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
2954 0x03, tx_fs_rate);
2955 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002956 }
2957
2958 /**
2959 * TODO: Need to handle case where same RX chain takes 2 or more inputs
2960 * with varying sample rates
2961 */
2962
2963 /**
2964 * If current dai is a rx dai, set sample rate to
2965 * all the rx paths that are currently not active
2966 */
2967 if (dai->id == TABLA_RX_DAI_ID) {
2968
2969 rx_state = snd_soc_read(codec,
2970 TABLA_A_CDC_CLK_RX_B1_CTL);
2971
2972 for (path = 1, shift = 0;
2973 path <= NUM_INTERPOLATORS; path++, shift++) {
2974
2975 if (!(rx_state & (1 << shift))) {
2976 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
2977 + (BITS_PER_REG*(path-1));
2978 snd_soc_update_bits(codec, rx_fs_reg,
2979 0xE0, rx_fs_rate);
2980 }
2981 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302982 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2983 switch (params_format(params)) {
2984 case SNDRV_PCM_FORMAT_S16_LE:
2985 snd_soc_update_bits(codec,
2986 TABLA_A_CDC_CLK_RX_I2S_CTL,
2987 0x20, 0x20);
2988 break;
2989 case SNDRV_PCM_FORMAT_S32_LE:
2990 snd_soc_update_bits(codec,
2991 TABLA_A_CDC_CLK_RX_I2S_CTL,
2992 0x20, 0x00);
2993 break;
2994 default:
2995 pr_err("invalid format\n");
2996 break;
2997 }
2998 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
2999 0x03, (rx_fs_rate >> 0x05));
3000 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003001 }
3002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 return 0;
3004}
3005
3006static struct snd_soc_dai_ops tabla_dai_ops = {
3007 .startup = tabla_startup,
3008 .shutdown = tabla_shutdown,
3009 .hw_params = tabla_hw_params,
3010 .set_sysclk = tabla_set_dai_sysclk,
3011 .set_fmt = tabla_set_dai_fmt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003012};
3013
3014static struct snd_soc_dai_driver tabla_dai[] = {
3015 {
3016 .name = "tabla_rx1",
3017 .id = 1,
3018 .playback = {
3019 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003020 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003021 .formats = TABLA_FORMATS,
3022 .rate_max = 48000,
3023 .rate_min = 8000,
3024 .channels_min = 1,
Kiran Kandi3426e512011-09-13 22:50:10 -07003025 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003026 },
3027 .ops = &tabla_dai_ops,
3028 },
3029 {
3030 .name = "tabla_tx1",
3031 .id = 2,
3032 .capture = {
3033 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003034 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003035 .formats = TABLA_FORMATS,
3036 .rate_max = 48000,
3037 .rate_min = 8000,
3038 .channels_min = 1,
3039 .channels_max = 2,
3040 },
3041 .ops = &tabla_dai_ops,
3042 },
3043};
Santosh Mardie15e2302011-11-15 10:39:23 +05303044
3045static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3046 {
3047 .name = "tabla_i2s_rx1",
3048 .id = 1,
3049 .playback = {
3050 .stream_name = "AIF1 Playback",
3051 .rates = WCD9310_RATES,
3052 .formats = TABLA_FORMATS,
3053 .rate_max = 48000,
3054 .rate_min = 8000,
3055 .channels_min = 1,
3056 .channels_max = 4,
3057 },
3058 .ops = &tabla_dai_ops,
3059 },
3060 {
3061 .name = "tabla_i2s_tx1",
3062 .id = 2,
3063 .capture = {
3064 .stream_name = "AIF1 Capture",
3065 .rates = WCD9310_RATES,
3066 .formats = TABLA_FORMATS,
3067 .rate_max = 48000,
3068 .rate_min = 8000,
3069 .channels_min = 1,
3070 .channels_max = 4,
3071 },
3072 .ops = &tabla_dai_ops,
3073 },
3074};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003075static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003076{
3077 u8 bias_msb, bias_lsb;
3078 short bias_value;
3079
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003080 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
3081 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
3082 bias_value = (bias_msb << 8) | bias_lsb;
3083 return bias_value;
3084}
3085
3086static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
3087{
3088 u8 bias_msb, bias_lsb;
3089 short bias_value;
3090
3091 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
3092 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
3093 bias_value = (bias_msb << 8) | bias_lsb;
3094 return bias_value;
3095}
3096
Joonwoo Park0976d012011-12-22 11:48:18 -08003097static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003098{
Joonwoo Park0976d012011-12-22 11:48:18 -08003099 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003100 short bias_value;
3101
Joonwoo Park925914c2012-01-05 13:35:18 -08003102 /* Turn on the override */
3103 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003104 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003105 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3106 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
3107 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003108 usleep_range(tabla->mbhc_data.t_sta_dce,
3109 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003110 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08003111 usleep_range(tabla->mbhc_data.t_dce,
3112 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003113 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003114 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003115 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003116 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3117 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003118 usleep_range(tabla->mbhc_data.t_sta_dce,
3119 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08003120 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3121 usleep_range(tabla->mbhc_data.t_sta,
3122 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003123 bias_value = tabla_codec_read_sta_result(codec);
3124 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3125 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003126 }
Joonwoo Park925914c2012-01-05 13:35:18 -08003127 /* Turn off the override after measuring mic voltage */
3128 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003129
Bradley Rubincb1e2732011-06-23 16:49:20 -07003130 return bias_value;
3131}
3132
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003133static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003134{
3135 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003136 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003137 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003138
Joonwoo Park0976d012011-12-22 11:48:18 -08003139 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003140 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07003141 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003142 }
3143
3144 tabla->mbhc_polling_active = true;
3145
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003146 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003147 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003148 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003149 tabla_codec_enable_clock_block(codec, 1);
3150 }
3151
3152 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
3153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003154 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
3155
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003156 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08003157 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
3158 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07003159
Joonwoo Parkf4267c22012-01-10 13:25:24 -08003160 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003161
3162 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003163 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003164
3165 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
3166 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
3167 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
3168
3169 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003170 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3171 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003172
Joonwoo Park925914c2012-01-05 13:35:18 -08003173 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003174 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3175
Bradley Rubincb1e2732011-06-23 16:49:20 -07003176 tabla_codec_calibrate_hs_polling(codec);
3177
Joonwoo Park0976d012011-12-22 11:48:18 -08003178 bias_value = tabla_codec_sta_dce(codec, 0);
3179 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3180 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003181 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003182
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003183 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003184}
3185
3186static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
3187 int insertion)
3188{
3189 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003190 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08003191 const struct tabla_mbhc_general_cfg *generic =
3192 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3193 const struct tabla_mbhc_plug_detect_cfg *plug_det =
3194 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003195 u8 wg_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003196
Joonwoo Park0976d012011-12-22 11:48:18 -08003197 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003198 pr_err("Error, no tabla calibration\n");
3199 return -EINVAL;
3200 }
3201
3202 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
3203
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003204 if (insertion) {
3205 /* Make sure mic bias and Mic line schmitt trigger
3206 * are turned OFF
3207 */
3208 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
3209 0x81, 0x01);
3210 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3211 0x90, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003212 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
3213 wg_time += 1;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003214
3215 /* Enable HPH Schmitt Trigger */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003216 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003217 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
Joonwoo Park0976d012011-12-22 11:48:18 -08003218 plug_det->hph_current << 2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003219
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003220 /* Turn off HPH PAs and DAC's during insertion detection to
3221 * avoid false insertion interrupts
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003222 */
3223 if (tabla->mbhc_micbias_switched)
3224 tabla_codec_switch_micbias(codec, 0);
3225 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003226 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003227 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003228 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003229 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003230 usleep_range(wg_time * 1000, wg_time * 1000);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003231
3232 /* setup for insetion detection */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003233 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003234 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003235 } else {
3236 /* Make sure the HPH schmitt trigger is OFF */
3237 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3238
3239 /* enable the mic line schmitt trigger */
3240 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08003241 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003242 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3243 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003244 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003245 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3246 0x10, 0x10);
3247
3248 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003249 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003250 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003251
3252 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
3253 if (!(tabla->clock_active)) {
3254 tabla_codec_enable_config_mode(codec, 1);
3255 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003256 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08003257 usleep_range(generic->t_shutdown_plug_rem,
3258 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259 tabla_codec_enable_config_mode(codec, 0);
3260 } else
3261 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003262 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003263 }
3264
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003265 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003266
3267 /* If central bandgap disabled */
3268 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
3269 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08003270 usleep_range(generic->t_bg_fast_settle,
3271 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003272 central_bias_enabled = 1;
3273 }
3274
3275 /* If LDO_H disabled */
3276 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
3277 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
3278 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003279 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003280 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
3281
3282 if (central_bias_enabled)
3283 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
3284 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003285
Joonwoo Park0976d012011-12-22 11:48:18 -08003286 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x3, tabla->micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003287
3288 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3289 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3290 return 0;
3291}
3292
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003293static void tabla_lock_sleep(struct tabla_priv *tabla)
3294{
3295 int ret;
3296 while (!(ret = wait_event_timeout(tabla->pm_wq,
3297 atomic_inc_not_zero(&tabla->pm_cnt),
3298 2 * HZ))) {
3299 pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
3300 __func__, ret, atomic_read(&tabla->pm_cnt));
3301 WARN_ON_ONCE(1);
3302 }
3303}
3304
3305static void tabla_unlock_sleep(struct tabla_priv *tabla)
3306{
3307 atomic_dec(&tabla->pm_cnt);
3308 wake_up(&tabla->pm_wq);
3309}
3310
Joonwoo Park0976d012011-12-22 11:48:18 -08003311static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
3312 s16 vin_mv)
3313{
3314 short diff, zero;
3315 struct tabla_priv *tabla;
3316 u32 mb_mv, in;
3317
3318 tabla = snd_soc_codec_get_drvdata(codec);
3319 mb_mv = tabla->mbhc_data.micb_mv;
3320
3321 if (mb_mv == 0) {
3322 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
3323 return -EINVAL;
3324 }
3325
3326 if (dce) {
3327 diff = tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z;
3328 zero = tabla->mbhc_data.dce_z;
3329 } else {
3330 diff = tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z;
3331 zero = tabla->mbhc_data.sta_z;
3332 }
3333 in = (u32) diff * vin_mv;
3334
3335 return (u16) (in / mb_mv) + zero;
3336}
3337
3338static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
3339 u16 bias_value)
3340{
3341 struct tabla_priv *tabla;
3342 s32 mv;
3343
3344 tabla = snd_soc_codec_get_drvdata(codec);
3345
3346 if (dce) {
3347 mv = ((s32)bias_value - (s32)tabla->mbhc_data.dce_z) *
3348 (s32)tabla->mbhc_data.micb_mv /
3349 (s32)(tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z);
3350 } else {
3351 mv = ((s32)bias_value - (s32)tabla->mbhc_data.sta_z) *
3352 (s32)tabla->mbhc_data.micb_mv /
3353 (s32)(tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z);
3354 }
3355
3356 return mv;
3357}
3358
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003359static void btn0_lpress_fn(struct work_struct *work)
3360{
3361 struct delayed_work *delayed_work;
3362 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08003363 short bias_value;
3364 int dce_mv, sta_mv;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003365
3366 pr_debug("%s:\n", __func__);
3367
3368 delayed_work = to_delayed_work(work);
3369 tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
3370
3371 if (tabla) {
3372 if (tabla->button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003373 bias_value = tabla_codec_read_sta_result(tabla->codec);
3374 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
3375 bias_value);
3376 bias_value = tabla_codec_read_dce_result(tabla->codec);
3377 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
3378 bias_value);
3379 pr_debug("%s: Reporting long button press event"
3380 " STA: %d, DCE: %d\n", __func__,
3381 sta_mv, dce_mv);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003382 tabla_snd_soc_jack_report(tabla, tabla->button_jack,
3383 SND_JACK_BTN_0,
3384 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003385 }
3386 } else {
3387 pr_err("%s: Bad tabla private data\n", __func__);
3388 }
3389
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003390 tabla_unlock_sleep(tabla);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003391}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003392
Joonwoo Park0976d012011-12-22 11:48:18 -08003393void tabla_mbhc_cal(struct snd_soc_codec *codec)
3394{
3395 struct tabla_priv *tabla;
3396 struct tabla_mbhc_btn_detect_cfg *btn_det;
3397 u8 cfilt_mode, bg_mode;
3398 u8 ncic, nmeas, navg;
3399 u32 mclk_rate;
3400 u32 dce_wait, sta_wait;
3401 u8 *n_cic;
3402
3403 tabla = snd_soc_codec_get_drvdata(codec);
3404
3405 /* First compute the DCE / STA wait times
3406 * depending on tunable parameters.
3407 * The value is computed in microseconds
3408 */
3409 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3410 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003411 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Park0976d012011-12-22 11:48:18 -08003412 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
3413 navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
3414 mclk_rate = tabla->mclk_freq;
Joonwoo Park433149a2012-01-11 09:53:54 -08003415 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
3416 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08003417
3418 tabla->mbhc_data.t_dce = dce_wait;
3419 tabla->mbhc_data.t_sta = sta_wait;
3420
3421 /* LDOH and CFILT are already configured during pdata handling.
3422 * Only need to make sure CFILT and bandgap are in Fast mode.
3423 * Need to restore defaults once calculation is done.
3424 */
3425 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
3426 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
3427 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
3428 0x02);
3429
3430 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
3431 * to perform ADC calibration
3432 */
3433 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
3434 tabla->micbias << 5);
3435 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
3436 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
3437 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
3438 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
3439
3440 /* DCE measurement for 0 volts */
3441 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3442 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3443 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3444 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3445 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
3446 usleep_range(100, 100);
3447 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3448 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3449 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
3450
3451 /* DCE measurment for MB voltage */
3452 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3453 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3454 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3455 usleep_range(100, 100);
3456 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3457 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3458 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
3459
3460 /* Sta measuremnt for 0 volts */
3461 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3462 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3463 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3464 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3465 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
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_z = tabla_codec_read_sta_result(codec);
3470
3471 /* STA Measurement for MB Voltage */
3472 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3473 usleep_range(100, 100);
3474 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3475 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
3476 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
3477
3478 /* Restore default settings. */
3479 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3480 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3481 cfilt_mode);
3482 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
3483
3484 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
3485 usleep_range(100, 100);
3486}
3487
3488void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
3489 const enum tabla_mbhc_btn_det_mem mem)
3490{
3491 void *ret = &btn_det->_v_btn_low;
3492
3493 switch (mem) {
3494 case TABLA_BTN_DET_GAIN:
3495 ret += sizeof(btn_det->_n_cic);
3496 case TABLA_BTN_DET_N_CIC:
3497 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08003498 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08003499 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
3500 case TABLA_BTN_DET_V_BTN_HIGH:
3501 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
3502 case TABLA_BTN_DET_V_BTN_LOW:
3503 /* do nothing */
3504 break;
3505 default:
3506 ret = NULL;
3507 }
3508
3509 return ret;
3510}
3511
3512static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
3513{
3514 struct tabla_priv *tabla;
3515 s16 btn_mv = 0, btn_delta_mv;
3516 struct tabla_mbhc_btn_detect_cfg *btn_det;
3517 struct tabla_mbhc_plug_type_cfg *plug_type;
3518 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08003519 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08003520 int i;
3521
3522 tabla = snd_soc_codec_get_drvdata(codec);
3523 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3524 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
3525
Joonwoo Parkc0672392012-01-11 11:03:14 -08003526 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003527 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003528 tabla->mbhc_data.npoll = 9;
3529 tabla->mbhc_data.nbounce_wait = 30;
3530 } else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003531 tabla->mbhc_data.npoll = 7;
3532 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08003533 }
Joonwoo Park0976d012011-12-22 11:48:18 -08003534
Joonwoo Park433149a2012-01-11 09:53:54 -08003535 tabla->mbhc_data.t_sta_dce = ((1000 * 256) / (tabla->mclk_freq / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08003536 n_ready[tabla_codec_mclk_index(tabla)]) +
3537 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08003538 tabla->mbhc_data.v_ins_hu =
3539 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
3540 tabla->mbhc_data.v_ins_h =
3541 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
3542
3543 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
3544 for (i = 0; i < btn_det->num_btn; i++)
3545 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
3546
3547 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
3548 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
3549
3550 tabla->mbhc_data.v_b1_hu =
3551 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
3552
3553 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
3554
3555 tabla->mbhc_data.v_b1_huc =
3556 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
3557
3558 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
3559 tabla->mbhc_data.v_brl = 0xFA55;
3560
3561 tabla->mbhc_data.v_no_mic =
3562 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
3563}
3564
3565void tabla_mbhc_init(struct snd_soc_codec *codec)
3566{
3567 struct tabla_priv *tabla;
3568 struct tabla_mbhc_general_cfg *generic;
3569 struct tabla_mbhc_btn_detect_cfg *btn_det;
3570 int n;
3571 u8 tabla_ver;
3572 u8 *n_cic, *gain;
3573
3574 tabla = snd_soc_codec_get_drvdata(codec);
3575 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3576 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3577
3578 tabla_ver = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
3579 tabla_ver &= 0x1F;
3580
3581 for (n = 0; n < 8; n++) {
3582 if ((tabla_ver != TABLA_VERSION_1_0 &&
3583 tabla_ver != TABLA_VERSION_1_1) || n != 7) {
3584 snd_soc_update_bits(codec,
3585 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
3586 0x07, n);
3587 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
3588 btn_det->c[n]);
3589 }
3590 }
3591 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
3592 btn_det->nc);
3593
3594 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
3595 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08003596 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003597
3598 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08003599 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
3600 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08003601
3602 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
3603 generic->mbhc_nsa << 4);
3604
3605 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
3606 btn_det->n_meas);
3607
3608 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
3609
3610 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
3611
3612 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
3613 btn_det->mbhc_nsc << 3);
3614
3615 snd_soc_update_bits(codec, TABLA_A_MICB_4_MBHC, 0x03, TABLA_MICBIAS2);
3616
3617 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
3618}
3619
Patrick Lai64b43262011-12-06 17:29:15 -08003620static bool tabla_mbhc_fw_validate(const struct firmware *fw)
3621{
3622 u32 cfg_offset;
3623 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
3624 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
3625
3626 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
3627 return false;
3628
3629 /* previous check guarantees that there is enough fw data up
3630 * to num_btn
3631 */
3632 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
3633 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
3634 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
3635 return false;
3636
3637 /* previous check guarantees that there is enough fw data up
3638 * to start of impedance detection configuration
3639 */
3640 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
3641 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
3642
3643 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
3644 return false;
3645
3646 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
3647 return false;
3648
3649 return true;
3650}
3651static void mbhc_fw_read(struct work_struct *work)
3652{
3653 struct delayed_work *dwork;
3654 struct tabla_priv *tabla;
3655 struct snd_soc_codec *codec;
3656 const struct firmware *fw;
3657 int ret = -1, retry = 0, rc;
3658
3659 dwork = to_delayed_work(work);
3660 tabla = container_of(dwork, struct tabla_priv,
3661 mbhc_firmware_dwork);
3662 codec = tabla->codec;
3663
3664 while (retry < MBHC_FW_READ_ATTEMPTS) {
3665 retry++;
3666 pr_info("%s:Attempt %d to request MBHC firmware\n",
3667 __func__, retry);
3668 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
3669 codec->dev);
3670
3671 if (ret != 0) {
3672 usleep_range(MBHC_FW_READ_TIMEOUT,
3673 MBHC_FW_READ_TIMEOUT);
3674 } else {
3675 pr_info("%s: MBHC Firmware read succesful\n", __func__);
3676 break;
3677 }
3678 }
3679
3680 if (ret != 0) {
3681 pr_err("%s: Cannot load MBHC firmware use default cal\n",
3682 __func__);
3683 } else if (tabla_mbhc_fw_validate(fw) == false) {
3684 pr_err("%s: Invalid MBHC cal data size use default cal\n",
3685 __func__);
3686 release_firmware(fw);
3687 } else {
3688 tabla->calibration = (void *)fw->data;
3689 tabla->mbhc_fw = fw;
3690 }
3691
3692 tabla->mclk_cb(codec, 1);
3693 tabla_mbhc_init(codec);
3694 tabla_mbhc_cal(codec);
3695 tabla_mbhc_calc_thres(codec);
3696 tabla->mclk_cb(codec, 0);
3697 tabla_codec_calibrate_hs_polling(codec);
3698 rc = tabla_codec_enable_hs_detect(codec, 1);
3699
3700 if (IS_ERR_VALUE(rc))
3701 pr_err("%s: Failed to setup MBHC detection\n", __func__);
3702
3703}
3704
Bradley Rubincb1e2732011-06-23 16:49:20 -07003705int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park0976d012011-12-22 11:48:18 -08003706 struct snd_soc_jack *headset_jack,
3707 struct snd_soc_jack *button_jack,
3708 void *calibration, enum tabla_micbias_num micbias,
3709 int (*mclk_cb_fn) (struct snd_soc_codec*, int),
3710 int read_fw_bin, u32 mclk_rate)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003711{
3712 struct tabla_priv *tabla;
Patrick Lai64b43262011-12-06 17:29:15 -08003713 int rc = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07003714
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003715 if (!codec || !calibration) {
3716 pr_err("Error: no codec or calibration\n");
3717 return -EINVAL;
3718 }
Joonwoo Park107edf02012-01-11 11:42:24 -08003719
3720 if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
3721 if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
3722 pr_err("Error: clock rate %dHz is not yet supported\n",
3723 mclk_rate);
3724 else
3725 pr_err("Error: unsupported clock rate %d\n", mclk_rate);
3726 return -EINVAL;
3727 }
3728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003729 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003730 tabla->headset_jack = headset_jack;
3731 tabla->button_jack = button_jack;
Joonwoo Park0976d012011-12-22 11:48:18 -08003732 tabla->micbias = micbias;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003733 tabla->calibration = calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08003734 tabla->mclk_cb = mclk_cb_fn;
3735 tabla->mclk_freq = mclk_rate;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003736 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003738 /* Put CFILT in fast mode by default */
3739 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
3740 0x40, TABLA_CFILT_FAST_MODE);
Patrick Lai64b43262011-12-06 17:29:15 -08003741 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003742 INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
Patrick Lai49efeac2011-11-03 11:01:12 -07003743 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
3744 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
Joonwoo Park0976d012011-12-22 11:48:18 -08003745
3746 if (!read_fw_bin) {
3747 tabla->mclk_cb(codec, 1);
3748 tabla_mbhc_init(codec);
3749 tabla_mbhc_cal(codec);
3750 tabla_mbhc_calc_thres(codec);
3751 tabla->mclk_cb(codec, 0);
3752 tabla_codec_calibrate_hs_polling(codec);
3753 rc = tabla_codec_enable_hs_detect(codec, 1);
3754 } else {
Patrick Lai64b43262011-12-06 17:29:15 -08003755 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
3756 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Joonwoo Park0976d012011-12-22 11:48:18 -08003757 }
Patrick Lai49efeac2011-11-03 11:01:12 -07003758
3759 if (!IS_ERR_VALUE(rc)) {
3760 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3761 0x10);
3762 tabla_enable_irq(codec->control_data,
3763 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3764 tabla_enable_irq(codec->control_data,
3765 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3766 }
3767
3768 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769}
3770EXPORT_SYMBOL_GPL(tabla_hs_detect);
3771
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003772static int tabla_determine_button(const struct tabla_priv *priv,
3773 const s32 bias_mv)
3774{
3775 s16 *v_btn_low, *v_btn_high;
3776 struct tabla_mbhc_btn_detect_cfg *btn_det;
3777 int i, btn = -1;
3778
3779 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
3780 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
3781 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
3782 TABLA_BTN_DET_V_BTN_HIGH);
3783 for (i = 0; i < btn_det->num_btn; i++) {
3784 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
3785 btn = i;
3786 break;
3787 }
3788 }
3789
3790 if (btn == -1)
3791 pr_debug("%s: couldn't find button number for mic mv %d\n",
3792 __func__, bias_mv);
3793
3794 return btn;
3795}
3796
3797static int tabla_get_button_mask(const int btn)
3798{
3799 int mask = 0;
3800 switch (btn) {
3801 case 0:
3802 mask = SND_JACK_BTN_0;
3803 break;
3804 case 1:
3805 mask = SND_JACK_BTN_1;
3806 break;
3807 case 2:
3808 mask = SND_JACK_BTN_2;
3809 break;
3810 case 3:
3811 mask = SND_JACK_BTN_3;
3812 break;
3813 case 4:
3814 mask = SND_JACK_BTN_4;
3815 break;
3816 case 5:
3817 mask = SND_JACK_BTN_5;
3818 break;
3819 case 6:
3820 mask = SND_JACK_BTN_6;
3821 break;
3822 case 7:
3823 mask = SND_JACK_BTN_7;
3824 break;
3825 }
3826 return mask;
3827}
3828
Bradley Rubincb1e2732011-06-23 16:49:20 -07003829static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003830{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003831 int i, mask;
3832 short bias_value_dce;
3833 s32 bias_mv_dce;
3834 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003835 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003836 const struct tabla_mbhc_btn_detect_cfg *d =
3837 TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
3838 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003839 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003840
3841 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3842 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003843 tabla_lock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003844
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003845 bias_value_dce = tabla_codec_read_dce_result(codec);
3846 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003847
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003848 /* determine pressed button */
3849 btnmeas[meas++] = tabla_determine_button(priv, bias_mv_dce);
3850 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
3851 meas - 1, bias_value_dce, bias_mv_dce, btnmeas[meas - 1]);
3852 if (d->n_btn_meas == 0)
3853 btn = btnmeas[0];
3854 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
3855 bias_value_dce = tabla_codec_sta_dce(codec, 1);
3856 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
3857 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
3858 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
3859 __func__, meas, bias_value_dce, bias_mv_dce,
3860 btnmeas[meas]);
3861 /* if large enough measurements are collected,
3862 * start to check if last all n_btn_con measurements were
3863 * in same button low/high range */
3864 if (meas + 1 >= d->n_btn_con) {
3865 for (i = 0; i < d->n_btn_con; i++)
3866 if ((btnmeas[meas] < 0) ||
3867 (btnmeas[meas] != btnmeas[meas - i]))
3868 break;
3869 if (i == d->n_btn_con) {
3870 /* button pressed */
3871 btn = btnmeas[meas];
3872 break;
3873 }
3874 }
3875 /* if left measurements are less than n_btn_con,
3876 * it's impossible to find button number */
3877 if ((d->n_btn_meas - meas) < d->n_btn_con)
3878 break;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003879 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003880
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003881 if (btn >= 0) {
3882 mask = tabla_get_button_mask(btn);
3883 priv->buttons_pressed |= mask;
3884
3885 msleep(100);
3886
3887 /* XXX: assuming button 0 has the lowest micbias voltage */
3888 if (btn == 0) {
3889 if (schedule_delayed_work(&priv->btn0_dwork,
3890 msecs_to_jiffies(400)) == 0) {
3891 WARN(1, "Button pressed twice without release"
3892 "event\n");
3893 tabla_unlock_sleep(priv);
3894 }
3895 } else {
3896 pr_debug("%s: Reporting short button %d(0x%x) press\n",
3897 __func__, btn, mask);
3898 tabla_snd_soc_jack_report(priv, priv->button_jack, mask,
3899 mask);
3900 }
3901 } else
3902 pr_debug("%s: bogus button press, too short press?\n",
3903 __func__);
3904
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003905 return IRQ_HANDLED;
3906}
3907
Bradley Rubincb1e2732011-06-23 16:49:20 -07003908static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003909{
3910 struct tabla_priv *priv = data;
3911 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08003912 int ret;
3913 short mb_v;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003914
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003915 pr_debug("%s: enter\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003916 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003917 tabla_lock_sleep(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003918
Bradley Rubincb1e2732011-06-23 16:49:20 -07003919 if (priv->buttons_pressed & SND_JACK_BTN_0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003920 ret = cancel_delayed_work(&priv->btn0_dwork);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003921 if (ret == 0) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003922 pr_debug("%s: Reporting long button 0 release event\n",
3923 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08003924 if (priv->button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003925 tabla_snd_soc_jack_report(priv,
3926 priv->button_jack, 0,
3927 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003928 } else {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003929 /* if scheduled btn0_dwork is canceled from here,
3930 * we have to unlock from here instead btn0_work */
3931 tabla_unlock_sleep(priv);
Joonwoo Park0976d012011-12-22 11:48:18 -08003932 mb_v = tabla_codec_sta_dce(codec, 0);
3933 pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
3934 __func__, mb_v,
3935 tabla_codec_sta_dce_v(codec, 0, mb_v));
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003936
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08003937 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
3938 mb_v > (short)priv->mbhc_data.v_ins_hu)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003939 pr_debug("%s: Fake buttton press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003940 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08003941 else if (priv->button_jack) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003942 pr_debug("%s: Reporting short button 0 "
Joonwoo Park0976d012011-12-22 11:48:18 -08003943 "press and release\n", __func__);
3944 tabla_snd_soc_jack_report(priv,
3945 priv->button_jack,
3946 SND_JACK_BTN_0,
3947 SND_JACK_BTN_0);
3948 tabla_snd_soc_jack_report(priv,
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003949 priv->button_jack, 0,
3950 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003951 }
3952 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003953
Bradley Rubincb1e2732011-06-23 16:49:20 -07003954 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003955 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003956
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003957 if (priv->buttons_pressed) {
3958 pr_debug("%s:reporting button release mask 0x%x\n", __func__,
3959 priv->buttons_pressed);
3960 tabla_snd_soc_jack_report(priv, priv->button_jack, 0,
3961 priv->buttons_pressed);
3962 /* hardware doesn't detect another button press until
3963 * already pressed button is released.
3964 * therefore buttons_pressed has only one button's mask. */
3965 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
3966 }
3967
Bradley Rubin688c66a2011-08-16 12:25:13 -07003968 tabla_codec_start_hs_polling(codec);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003969 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003970 return IRQ_HANDLED;
3971}
3972
Bradley Rubincb1e2732011-06-23 16:49:20 -07003973static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
3974{
3975 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08003976 const struct tabla_mbhc_general_cfg *generic =
3977 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003978
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003979 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003980 tabla_codec_enable_config_mode(codec, 1);
3981
3982 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
3983 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003984
Joonwoo Park0976d012011-12-22 11:48:18 -08003985 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
3986
3987 usleep_range(generic->t_shutdown_plug_rem,
3988 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003989
3990 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003991 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003992 tabla_codec_enable_config_mode(codec, 0);
3993
3994 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
3995}
3996
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003997static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
3998{
3999 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004000
4001 tabla_codec_shutdown_hs_removal_detect(codec);
4002
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004003 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004004 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05304005 tabla_codec_disable_clock_block(codec);
4006 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004007 }
4008
4009 tabla->mbhc_polling_active = false;
4010}
4011
Patrick Lai49efeac2011-11-03 11:01:12 -07004012static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
4013{
4014 struct tabla_priv *tabla = data;
4015 struct snd_soc_codec *codec;
4016
4017 pr_info("%s: received HPHL OCP irq\n", __func__);
4018
4019 if (tabla) {
4020 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004021 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
4022 pr_info("%s: retry\n", __func__);
4023 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4024 0x00);
4025 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4026 0x10);
4027 } else {
4028 tabla_disable_irq(codec->control_data,
4029 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4030 tabla->hphlocp_cnt = 0;
4031 tabla->hph_status |= SND_JACK_OC_HPHL;
4032 if (tabla->headset_jack)
4033 tabla_snd_soc_jack_report(tabla,
4034 tabla->headset_jack,
4035 tabla->hph_status,
4036 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07004037 }
4038 } else {
4039 pr_err("%s: Bad tabla private data\n", __func__);
4040 }
4041
4042 return IRQ_HANDLED;
4043}
4044
4045static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
4046{
4047 struct tabla_priv *tabla = data;
4048 struct snd_soc_codec *codec;
4049
4050 pr_info("%s: received HPHR OCP irq\n", __func__);
4051
4052 if (tabla) {
4053 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004054 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
4055 pr_info("%s: retry\n", __func__);
4056 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4057 0x00);
4058 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4059 0x10);
4060 } else {
4061 tabla_disable_irq(codec->control_data,
4062 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4063 tabla->hphrocp_cnt = 0;
4064 tabla->hph_status |= SND_JACK_OC_HPHR;
4065 if (tabla->headset_jack)
4066 tabla_snd_soc_jack_report(tabla,
4067 tabla->headset_jack,
4068 tabla->hph_status,
4069 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07004070 }
4071 } else {
4072 pr_err("%s: Bad tabla private data\n", __func__);
4073 }
4074
4075 return IRQ_HANDLED;
4076}
4077
Joonwoo Parka9444452011-12-08 18:48:27 -08004078static void tabla_sync_hph_state(struct tabla_priv *tabla)
4079{
4080 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4081 &tabla->hph_pa_dac_state)) {
4082 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4083 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4084 1 << 4);
4085 }
4086 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4087 &tabla->hph_pa_dac_state)) {
4088 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4089 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4090 1 << 5);
4091 }
4092
4093 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4094 &tabla->hph_pa_dac_state)) {
4095 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4096 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4097 0xC0, 0xC0);
4098 }
4099 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4100 &tabla->hph_pa_dac_state)) {
4101 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4102 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4103 0xC0, 0xC0);
4104 }
4105}
4106
Bradley Rubincb1e2732011-06-23 16:49:20 -07004107static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
4108{
4109 struct tabla_priv *priv = data;
4110 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08004111 const struct tabla_mbhc_plug_detect_cfg *plug_det =
4112 TABLA_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
Bradley Rubin355611a2011-08-24 14:01:18 -07004113 int ldo_h_on, micb_cfilt_on;
Joonwoo Park0976d012011-12-22 11:48:18 -08004114 short mb_v;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004115 u8 is_removal;
Joonwoo Park0976d012011-12-22 11:48:18 -08004116 int mic_mv;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004117
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004118 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004119 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004120 tabla_lock_sleep(priv);
4121
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004122 is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
4123 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
4124
4125 /* Turn off both HPH and MIC line schmitt triggers */
Joonwoo Park0976d012011-12-22 11:48:18 -08004126 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004127 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004128
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004129 if (priv->mbhc_fake_ins_start &&
4130 time_after(jiffies, priv->mbhc_fake_ins_start +
4131 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004132 pr_debug("%s: fake context interrupt, reset insertion\n",
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004133 __func__);
4134 priv->mbhc_fake_ins_start = 0;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004135 tabla_codec_shutdown_hs_polling(codec);
4136 tabla_codec_enable_hs_detect(codec, 1);
4137 return IRQ_HANDLED;
4138 }
4139
Bradley Rubin355611a2011-08-24 14:01:18 -07004140 ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
Joonwoo Park0976d012011-12-22 11:48:18 -08004141 micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
4142 & 0x80;
Bradley Rubin355611a2011-08-24 14:01:18 -07004143
4144 if (!ldo_h_on)
4145 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
4146 if (!micb_cfilt_on)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004147 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08004148 0x80, 0x80);
4149 if (plug_det->t_ins_complete > 20)
4150 msleep(plug_det->t_ins_complete);
4151 else
4152 usleep_range(plug_det->t_ins_complete * 1000,
4153 plug_det->t_ins_complete * 1000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004154
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004155 if (!ldo_h_on)
4156 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
4157 if (!micb_cfilt_on)
4158 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08004159 0x80, 0x0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004160
4161 if (is_removal) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004162 /*
4163 * If headphone is removed while playback is in progress,
4164 * it is possible that micbias will be switched to VDDIO.
4165 */
4166 if (priv->mbhc_micbias_switched)
4167 tabla_codec_switch_micbias(codec, 0);
Patrick Lai72aa4da2011-12-08 12:38:18 -08004168 priv->hph_status &= ~SND_JACK_HEADPHONE;
Joonwoo Parka9444452011-12-08 18:48:27 -08004169
4170 /* If headphone PA is on, check if userspace receives
4171 * removal event to sync-up PA's state */
4172 if (tabla_is_hph_pa_on(codec)) {
4173 set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
4174 set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
4175 }
4176
4177 if (tabla_is_hph_dac_on(codec, 1))
4178 set_bit(TABLA_HPHL_DAC_OFF_ACK,
4179 &priv->hph_pa_dac_state);
4180 if (tabla_is_hph_dac_on(codec, 0))
4181 set_bit(TABLA_HPHR_DAC_OFF_ACK,
4182 &priv->hph_pa_dac_state);
4183
Bradley Rubincb1e2732011-06-23 16:49:20 -07004184 if (priv->headset_jack) {
4185 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004186 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4187 priv->hph_status,
4188 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004189 }
4190 tabla_codec_shutdown_hs_removal_detect(codec);
4191 tabla_codec_enable_hs_detect(codec, 1);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004192 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004193 return IRQ_HANDLED;
4194 }
4195
Joonwoo Park0976d012011-12-22 11:48:18 -08004196 mb_v = tabla_codec_setup_hs_polling(codec);
4197 mic_mv = tabla_codec_sta_dce_v(codec, 0, mb_v);
Bradley Rubin355611a2011-08-24 14:01:18 -07004198
Joonwoo Park0976d012011-12-22 11:48:18 -08004199 if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004200 pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
4201 "STA : %d,%d\n", __func__,
4202 (priv->mbhc_fake_ins_start ?
4203 jiffies_to_msecs(jiffies -
4204 priv->mbhc_fake_ins_start) :
4205 0),
4206 mb_v, mic_mv);
4207 if (time_after(jiffies,
4208 priv->mbhc_fake_ins_start +
4209 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
4210 /* Disable HPH trigger and enable MIC line trigger */
4211 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
4212 0x00);
4213 snd_soc_update_bits(codec,
4214 priv->mbhc_bias_regs.mbhc_reg, 0x60,
4215 plug_det->mic_current << 5);
4216 snd_soc_update_bits(codec,
4217 priv->mbhc_bias_regs.mbhc_reg,
4218 0x80, 0x80);
4219 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4220 snd_soc_update_bits(codec,
4221 priv->mbhc_bias_regs.mbhc_reg,
4222 0x10, 0x10);
4223 } else {
4224 if (priv->mbhc_fake_ins_start == 0)
4225 priv->mbhc_fake_ins_start = jiffies;
4226 /* Setup normal insert detection
4227 * Enable HPH Schmitt Trigger
4228 */
4229 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH,
4230 0x13 | 0x0C,
4231 0x13 | plug_det->hph_current << 2);
4232 }
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004233 /* Setup for insertion detection */
4234 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004235 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4236 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4237
Joonwoo Park0976d012011-12-22 11:48:18 -08004238 } else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
4239 pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
4240 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004241 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07004242 priv->hph_status |= SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004243 if (priv->headset_jack) {
4244 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08004245 SND_JACK_HEADPHONE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004246 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4247 priv->hph_status,
4248 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004249 }
4250 tabla_codec_shutdown_hs_polling(codec);
4251 tabla_codec_enable_hs_detect(codec, 0);
Joonwoo Parka9444452011-12-08 18:48:27 -08004252 tabla_sync_hph_state(priv);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004253 } else {
Joonwoo Park0976d012011-12-22 11:48:18 -08004254 pr_debug("%s: Headset detected, mb_v: %d,%d\n",
4255 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004256 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07004257 priv->hph_status |= SND_JACK_HEADSET;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004258 if (priv->headset_jack) {
4259 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08004260 SND_JACK_HEADSET);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004261 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4262 priv->hph_status,
4263 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004264 }
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004265 /* avoid false button press detect */
4266 msleep(50);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004267 tabla_codec_start_hs_polling(codec);
Joonwoo Parka9444452011-12-08 18:48:27 -08004268 tabla_sync_hph_state(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004269 }
4270
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004271 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004272 return IRQ_HANDLED;
4273}
4274
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004275static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
4276{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004277 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004278 struct tabla_priv *priv = data;
4279 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08004280 const struct tabla_mbhc_general_cfg *generic =
4281 TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004282 int fake_removal = 0;
4283 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004284
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004285 pr_debug("%s: enter, removal interrupt\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004286 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4287 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004288 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004289 tabla_lock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004290
Joonwoo Park0976d012011-12-22 11:48:18 -08004291 usleep_range(generic->t_shutdown_plug_rem,
4292 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004293
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004294 do {
4295 bias_value = tabla_codec_sta_dce(codec, 1);
4296 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
4297 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
4298 if (bias_value < (short)priv->mbhc_data.v_ins_h) {
4299 fake_removal = 1;
4300 break;
4301 }
4302 min_us -= priv->mbhc_data.t_dce;
4303 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004304
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004305 if (fake_removal) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004306 pr_debug("False alarm, headset not actually removed\n");
4307 tabla_codec_start_hs_polling(codec);
4308 } else {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004309 /*
4310 * If this removal is not false, first check the micbias
4311 * switch status and switch it to LDOH if it is already
4312 * switched to VDDIO.
4313 */
4314 if (priv->mbhc_micbias_switched)
4315 tabla_codec_switch_micbias(codec, 0);
Patrick Lai49efeac2011-11-03 11:01:12 -07004316 priv->hph_status &= ~SND_JACK_HEADSET;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004317 if (priv->headset_jack) {
4318 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004319 tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
4320 TABLA_JACK_MASK);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004321 }
4322 tabla_codec_shutdown_hs_polling(codec);
4323
4324 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004325 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004326
4327 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004328 return IRQ_HANDLED;
4329}
4330
4331static unsigned long slimbus_value;
4332
4333static irqreturn_t tabla_slimbus_irq(int irq, void *data)
4334{
4335 struct tabla_priv *priv = data;
4336 struct snd_soc_codec *codec = priv->codec;
4337 int i, j;
4338 u8 val;
4339
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004340 tabla_lock_sleep(priv);
4341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004342 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
4343 slimbus_value = tabla_interface_reg_read(codec->control_data,
4344 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
4345 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
4346 val = tabla_interface_reg_read(codec->control_data,
4347 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
4348 if (val & 0x1)
4349 pr_err_ratelimited("overflow error on port %x,"
4350 " value %x\n", i*8 + j, val);
4351 if (val & 0x2)
4352 pr_err_ratelimited("underflow error on port %x,"
4353 " value %x\n", i*8 + j, val);
4354 }
4355 tabla_interface_reg_write(codec->control_data,
4356 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
4357 }
4358
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004359 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004360 return IRQ_HANDLED;
4361}
4362
Patrick Lai3043fba2011-08-01 14:15:57 -07004363
4364static int tabla_handle_pdata(struct tabla_priv *tabla)
4365{
4366 struct snd_soc_codec *codec = tabla->codec;
4367 struct tabla_pdata *pdata = tabla->pdata;
4368 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05304369 u8 leg_mode = pdata->amic_settings.legacy_mode;
4370 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4371 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4372 u8 flag = pdata->amic_settings.use_pdata;
4373 u8 i = 0, j = 0;
4374 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07004375
4376 if (!pdata) {
4377 rc = -ENODEV;
4378 goto done;
4379 }
4380
4381 /* Make sure settings are correct */
4382 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
4383 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
4384 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
4385 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
4386 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
4387 rc = -EINVAL;
4388 goto done;
4389 }
4390
4391 /* figure out k value */
4392 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
4393 pdata->micbias.cfilt1_mv);
4394 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
4395 pdata->micbias.cfilt2_mv);
4396 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
4397 pdata->micbias.cfilt3_mv);
4398
4399 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
4400 rc = -EINVAL;
4401 goto done;
4402 }
4403
4404 /* Set voltage level and always use LDO */
4405 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
4406 (pdata->micbias.ldoh_v << 2));
4407
4408 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
4409 (k1 << 2));
4410 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
4411 (k2 << 2));
4412 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
4413 (k3 << 2));
4414
4415 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
4416 (pdata->micbias.bias1_cfilt_sel << 5));
4417 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
4418 (pdata->micbias.bias2_cfilt_sel << 5));
4419 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
4420 (pdata->micbias.bias3_cfilt_sel << 5));
4421 snd_soc_update_bits(codec, TABLA_A_MICB_4_CTL, 0x60,
4422 (pdata->micbias.bias4_cfilt_sel << 5));
4423
Santosh Mardi22920282011-10-26 02:38:40 +05304424 for (i = 0; i < 6; j++, i += 2) {
4425 if (flag & (0x01 << i)) {
4426 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
4427 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4428 val_txfe = val_txfe |
4429 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4430 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4431 0x10, value);
4432 snd_soc_update_bits(codec,
4433 TABLA_A_TX_1_2_TEST_EN + j * 10,
4434 0x30, val_txfe);
4435 }
4436 if (flag & (0x01 << (i + 1))) {
4437 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
4438 val_txfe = (txfe_bypass &
4439 (0x01 << (i + 1))) ? 0x02 : 0x00;
4440 val_txfe |= (txfe_buff &
4441 (0x01 << (i + 1))) ? 0x01 : 0x00;
4442 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4443 0x01, value);
4444 snd_soc_update_bits(codec,
4445 TABLA_A_TX_1_2_TEST_EN + j * 10,
4446 0x03, val_txfe);
4447 }
4448 }
4449 if (flag & 0x40) {
4450 value = (leg_mode & 0x40) ? 0x10 : 0x00;
4451 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
4452 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
4453 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
4454 0x13, value);
4455 }
Patrick Lai49efeac2011-11-03 11:01:12 -07004456
4457 if (pdata->ocp.use_pdata) {
4458 /* not defined in CODEC specification */
4459 if (pdata->ocp.hph_ocp_limit == 1 ||
4460 pdata->ocp.hph_ocp_limit == 5) {
4461 rc = -EINVAL;
4462 goto done;
4463 }
4464 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
4465 0x0F, pdata->ocp.num_attempts);
4466 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
4467 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4468 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
4469 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4470 }
Patrick Lai3043fba2011-08-01 14:15:57 -07004471done:
4472 return rc;
4473}
4474
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004475static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
4476
4477 /* Tabla 1.1 MICBIAS changes */
4478 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
4479 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
4480 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
4481 TABLA_REG_VAL(TABLA_A_MICB_4_INT_RBIAS, 0x24),
4482
4483 /* Tabla 1.1 HPH changes */
4484 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
4485 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
4486
4487 /* Tabla 1.1 EAR PA changes */
4488 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
4489 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
4490 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
4491
4492 /* Tabla 1.1 Lineout_5 Changes */
4493 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
4494
4495 /* Tabla 1.1 RX Changes */
4496 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
4497 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
4498 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
4499 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
4500 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
4501 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
4502 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
4503
4504 /* Tabla 1.1 RX1 and RX2 Changes */
4505 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
4506 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
4507
4508 /* Tabla 1.1 RX3 to RX7 Changes */
4509 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
4510 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
4511 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
4512 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
4513 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
4514
4515 /* Tabla 1.1 CLASSG Changes */
4516 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
4517};
4518
4519static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
4520
4521 /* Tabla 2.0 MICBIAS changes */
4522 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
4523};
4524
4525static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
4526{
4527 u32 i;
4528
4529 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
4530 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
4531 tabla_1_1_reg_defaults[i].val);
4532
4533 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
4534 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
4535 tabla_2_0_reg_defaults[i].val);
4536}
4537
4538static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08004539 /* Initialize current threshold to 350MA
4540 * number of wait and run cycles to 4096
4541 */
Patrick Lai49efeac2011-11-03 11:01:12 -07004542 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08004543 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004544
Santosh Mardi32171012011-10-28 23:32:06 +05304545 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
4546
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004547 /* Initialize gain registers to use register gain */
4548 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
4549 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
4550 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
4551 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
4552 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
4553 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
4554
4555 /* Initialize mic biases to differential mode */
4556 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
4557 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
4558 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
4559 {TABLA_A_MICB_4_INT_RBIAS, 0x24, 0x24},
4560
4561 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
4562
4563 /* Use 16 bit sample size for TX1 to TX6 */
4564 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
4565 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4566 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4567 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4568 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
4569 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
4570
4571 /* Use 16 bit sample size for TX7 to TX10 */
4572 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
4573 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
4574 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
4575 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
4576
4577 /* Use 16 bit sample size for RX */
4578 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4579 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
4580
4581 /*enable HPF filter for TX paths */
4582 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
4583 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
4584 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
4585 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
4586 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
4587 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
4588 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
4589 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
4590 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
4591 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
4592};
4593
4594static void tabla_codec_init_reg(struct snd_soc_codec *codec)
4595{
4596 u32 i;
4597
4598 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
4599 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
4600 tabla_codec_reg_init_val[i].mask,
4601 tabla_codec_reg_init_val[i].val);
4602}
4603
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004604static int tabla_codec_probe(struct snd_soc_codec *codec)
4605{
4606 struct tabla *control;
4607 struct tabla_priv *tabla;
4608 struct snd_soc_dapm_context *dapm = &codec->dapm;
4609 int ret = 0;
4610 int i;
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004611 u8 tabla_version;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004612
4613 codec->control_data = dev_get_drvdata(codec->dev->parent);
4614 control = codec->control_data;
4615
4616 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
4617 if (!tabla) {
4618 dev_err(codec->dev, "Failed to allocate private data\n");
4619 return -ENOMEM;
4620 }
4621
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004622 /* Make sure mbhc micbias register addresses are zeroed out */
4623 memset(&tabla->mbhc_bias_regs, 0,
4624 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004625 tabla->cfilt_k_value = 0;
4626 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004627
Joonwoo Park0976d012011-12-22 11:48:18 -08004628 /* Make sure mbhc intenal calibration data is zeroed out */
4629 memset(&tabla->mbhc_data, 0,
4630 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08004631 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08004632 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
4633 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004634 snd_soc_codec_set_drvdata(codec, tabla);
4635
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004636 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004637 tabla->bandgap_type = TABLA_BANDGAP_OFF;
4638 tabla->clock_active = false;
4639 tabla->config_mode_active = false;
4640 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004641 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004642 tabla->no_mic_headset_override = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004643 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07004644 tabla->pdata = dev_get_platdata(codec->dev->parent);
Santosh Mardie15e2302011-11-15 10:39:23 +05304645 tabla->intf_type = tabla_get_intf_type();
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004646 atomic_set(&tabla->pm_cnt, 1);
4647 init_waitqueue_head(&tabla->pm_wq);
Patrick Lai3043fba2011-08-01 14:15:57 -07004648
Santosh Mardi22920282011-10-26 02:38:40 +05304649 tabla_update_reg_defaults(codec);
4650 tabla_codec_init_reg(codec);
Patrick Lai3043fba2011-08-01 14:15:57 -07004651
Santosh Mardi22920282011-10-26 02:38:40 +05304652 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07004653 if (IS_ERR_VALUE(ret)) {
4654 pr_err("%s: bad pdata\n", __func__);
4655 goto err_pdata;
4656 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004657
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004658 snd_soc_add_controls(codec, tabla_snd_controls,
4659 ARRAY_SIZE(tabla_snd_controls));
4660 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
4661 ARRAY_SIZE(tabla_dapm_widgets));
Santosh Mardie15e2302011-11-15 10:39:23 +05304662 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
4663 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
4664 ARRAY_SIZE(tabla_dapm_i2s_widgets));
4665 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
4666 ARRAY_SIZE(audio_i2s_map));
4667 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004668 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004669
4670 tabla_version = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
Joonwoo Park0976d012011-12-22 11:48:18 -08004671 pr_info("%s : Tabla version reg 0x%2x\n", __func__,
4672 (u32)tabla_version);
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004673
4674 tabla_version &= 0x1F;
4675 pr_info("%s : Tabla version %u\n", __func__, (u32)tabla_version);
4676
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004677 if ((tabla_version == TABLA_VERSION_1_0) ||
4678 (tabla_version == TABLA_VERSION_1_1)) {
4679 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004680 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
4681
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004682 } else if (tabla_version == TABLA_VERSION_2_0) {
4683 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
4684 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
4685 } else {
4686 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
4687 __func__, (u32)tabla_version);
4688 goto err_pdata;
4689 }
4690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004691 snd_soc_dapm_sync(dapm);
4692
4693 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
4694 tabla_hs_insert_irq, "Headset insert detect", tabla);
4695 if (ret) {
4696 pr_err("%s: Failed to request irq %d\n", __func__,
4697 TABLA_IRQ_MBHC_INSERTION);
4698 goto err_insert_irq;
4699 }
4700 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4701
4702 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
4703 tabla_hs_remove_irq, "Headset remove detect", tabla);
4704 if (ret) {
4705 pr_err("%s: Failed to request irq %d\n", __func__,
4706 TABLA_IRQ_MBHC_REMOVAL);
4707 goto err_remove_irq;
4708 }
4709 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4710
4711 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004712 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004713 if (ret) {
4714 pr_err("%s: Failed to request irq %d\n", __func__,
4715 TABLA_IRQ_MBHC_POTENTIAL);
4716 goto err_potential_irq;
4717 }
4718 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4719
Bradley Rubincb1e2732011-06-23 16:49:20 -07004720 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
4721 tabla_release_handler, "Button Release detect", tabla);
4722 if (ret) {
4723 pr_err("%s: Failed to request irq %d\n", __func__,
4724 TABLA_IRQ_MBHC_RELEASE);
4725 goto err_release_irq;
4726 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004727 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004728
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004729 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
4730 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
4731 if (ret) {
4732 pr_err("%s: Failed to request irq %d\n", __func__,
4733 TABLA_IRQ_SLIMBUS);
4734 goto err_slimbus_irq;
4735 }
4736
4737 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
4738 tabla_interface_reg_write(codec->control_data,
4739 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
4740
Patrick Lai49efeac2011-11-03 11:01:12 -07004741 ret = tabla_request_irq(codec->control_data,
4742 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
4743 "HPH_L OCP detect", tabla);
4744 if (ret) {
4745 pr_err("%s: Failed to request irq %d\n", __func__,
4746 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4747 goto err_hphl_ocp_irq;
4748 }
Patrick Lai92032be2011-12-19 14:14:25 -08004749 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004750
4751 ret = tabla_request_irq(codec->control_data,
4752 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
4753 "HPH_R OCP detect", tabla);
4754 if (ret) {
4755 pr_err("%s: Failed to request irq %d\n", __func__,
4756 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4757 goto err_hphr_ocp_irq;
4758 }
Patrick Lai92032be2011-12-19 14:14:25 -08004759 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004760
Bradley Rubincb3950a2011-08-18 13:07:26 -07004761#ifdef CONFIG_DEBUG_FS
4762 debug_tabla_priv = tabla;
4763#endif
4764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004765 return ret;
4766
Patrick Lai49efeac2011-11-03 11:01:12 -07004767err_hphr_ocp_irq:
4768 tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
4769err_hphl_ocp_irq:
4770 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004771err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07004772 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
4773err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004774 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4775err_potential_irq:
4776 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4777err_remove_irq:
4778 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4779err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07004780err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004781 kfree(tabla);
4782 return ret;
4783}
4784static int tabla_codec_remove(struct snd_soc_codec *codec)
4785{
4786 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4787 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004788 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004789 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4790 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4791 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4792 tabla_codec_disable_clock_block(codec);
4793 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08004794 if (tabla->mbhc_fw)
4795 release_firmware(tabla->mbhc_fw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004796 kfree(tabla);
4797 return 0;
4798}
4799static struct snd_soc_codec_driver soc_codec_dev_tabla = {
4800 .probe = tabla_codec_probe,
4801 .remove = tabla_codec_remove,
4802 .read = tabla_read,
4803 .write = tabla_write,
4804
4805 .readable_register = tabla_readable,
4806 .volatile_register = tabla_volatile,
4807
4808 .reg_cache_size = TABLA_CACHE_SIZE,
4809 .reg_cache_default = tabla_reg_defaults,
4810 .reg_word_size = 1,
4811};
Bradley Rubincb3950a2011-08-18 13:07:26 -07004812
4813#ifdef CONFIG_DEBUG_FS
4814static struct dentry *debugfs_poke;
4815
4816static int codec_debug_open(struct inode *inode, struct file *file)
4817{
4818 file->private_data = inode->i_private;
4819 return 0;
4820}
4821
4822static ssize_t codec_debug_write(struct file *filp,
4823 const char __user *ubuf, size_t cnt, loff_t *ppos)
4824{
4825 char lbuf[32];
4826 char *buf;
4827 int rc;
4828
4829 if (cnt > sizeof(lbuf) - 1)
4830 return -EINVAL;
4831
4832 rc = copy_from_user(lbuf, ubuf, cnt);
4833 if (rc)
4834 return -EFAULT;
4835
4836 lbuf[cnt] = '\0';
4837 buf = (char *)lbuf;
4838 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
4839 ? false : true;
4840
4841 return rc;
4842}
4843
4844static const struct file_operations codec_debug_ops = {
4845 .open = codec_debug_open,
4846 .write = codec_debug_write,
4847};
4848#endif
4849
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004850#ifdef CONFIG_PM
4851static int tabla_suspend(struct device *dev)
4852{
4853 int ret = 0, cnt;
4854 struct platform_device *pdev = to_platform_device(dev);
4855 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4856
4857 cnt = atomic_read(&tabla->pm_cnt);
4858 if (cnt > 0) {
4859 if (wait_event_timeout(tabla->pm_wq,
4860 (atomic_cmpxchg(&tabla->pm_cnt, 1, 0)
4861 == 1), 5 * HZ)) {
4862 dev_dbg(dev, "system suspend pm_cnt %d\n",
4863 atomic_read(&tabla->pm_cnt));
4864 } else {
4865 dev_err(dev, "%s timed out pm_cnt = %d\n",
4866 __func__, atomic_read(&tabla->pm_cnt));
4867 WARN_ON_ONCE(1);
4868 ret = -EBUSY;
4869 }
4870 } else if (cnt == 0)
4871 dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
4872 atomic_read(&tabla->pm_cnt));
4873 else {
4874 WARN(1, "unexpected pm_cnt %d\n", cnt);
4875 ret = -EFAULT;
4876 }
4877
4878 return ret;
4879}
4880
4881static int tabla_resume(struct device *dev)
4882{
4883 int ret = 0, cnt;
4884 struct platform_device *pdev = to_platform_device(dev);
4885 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4886
4887 cnt = atomic_cmpxchg(&tabla->pm_cnt, 0, 1);
4888 if (cnt == 0) {
4889 dev_dbg(dev, "system resume, pm_cnt %d\n",
4890 atomic_read(&tabla->pm_cnt));
4891 wake_up_all(&tabla->pm_wq);
4892 } else if (cnt > 0)
4893 dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
4894 else {
4895 WARN(1, "unexpected pm_cnt %d\n", cnt);
4896 ret = -EFAULT;
4897 }
4898
4899 return ret;
4900}
4901
4902static const struct dev_pm_ops tabla_pm_ops = {
4903 .suspend = tabla_suspend,
4904 .resume = tabla_resume,
4905};
4906#endif
4907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004908static int __devinit tabla_probe(struct platform_device *pdev)
4909{
Santosh Mardie15e2302011-11-15 10:39:23 +05304910 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004911#ifdef CONFIG_DEBUG_FS
4912 debugfs_poke = debugfs_create_file("TRRS",
4913 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
4914
4915#endif
Santosh Mardie15e2302011-11-15 10:39:23 +05304916 if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
4917 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4918 tabla_dai, ARRAY_SIZE(tabla_dai));
4919 else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
4920 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
4921 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
4922 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004923}
4924static int __devexit tabla_remove(struct platform_device *pdev)
4925{
4926 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07004927
4928#ifdef CONFIG_DEBUG_FS
4929 debugfs_remove(debugfs_poke);
4930#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004931 return 0;
4932}
4933static struct platform_driver tabla_codec_driver = {
4934 .probe = tabla_probe,
4935 .remove = tabla_remove,
4936 .driver = {
4937 .name = "tabla_codec",
4938 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004939#ifdef CONFIG_PM
4940 .pm = &tabla_pm_ops,
4941#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004942 },
4943};
4944
4945static int __init tabla_codec_init(void)
4946{
4947 return platform_driver_register(&tabla_codec_driver);
4948}
4949
4950static void __exit tabla_codec_exit(void)
4951{
4952 platform_driver_unregister(&tabla_codec_driver);
4953}
4954
4955module_init(tabla_codec_init);
4956module_exit(tabla_codec_exit);
4957
4958MODULE_DESCRIPTION("Tabla codec driver");
4959MODULE_VERSION("1.0");
4960MODULE_LICENSE("GPL v2");