blob: d4e9ecf077b04759d15398b0b508801b12d80807 [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
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800125struct tabla_reg_address {
126 u16 micb_4_ctl;
127 u16 micb_4_int_rbias;
128 u16 micb_4_mbhc;
129};
130
Bradley Rubin229c6a52011-07-12 16:18:48 -0700131struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700132 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800133 struct tabla_reg_address reg_addr;
Joonwoo Park0976d012011-12-22 11:48:18 -0800134 u32 mclk_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700136 u32 cfilt1_cnt;
137 u32 cfilt2_cnt;
138 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700139 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700140 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700141 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 bool clock_active;
143 bool config_mode_active;
144 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800145 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700146 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147
Joonwoo Park0976d012011-12-22 11:48:18 -0800148 enum tabla_micbias_num micbias;
149 /* void* calibration contains:
150 * struct tabla_mbhc_general_cfg generic;
151 * struct tabla_mbhc_plug_detect_cfg plug_det;
152 * struct tabla_mbhc_plug_type_cfg plug_type;
153 * struct tabla_mbhc_btn_detect_cfg btn_det;
154 * struct tabla_mbhc_imped_detect_cfg imped_det;
155 * Note: various size depends on btn_det->num_btn
156 */
157 void *calibration;
158 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159
Bradley Rubincb1e2732011-06-23 16:49:20 -0700160 struct snd_soc_jack *headset_jack;
161 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700162
Patrick Lai3043fba2011-08-01 14:15:57 -0700163 struct tabla_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700164 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700165
166 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700167 /* Delayed work to report long button press */
168 struct delayed_work btn0_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700169
170 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700171 u8 cfilt_k_value;
172 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700173
Joonwoo Parka9444452011-12-08 18:48:27 -0800174 /* track PA/DAC state */
175 unsigned long hph_pa_dac_state;
176
Santosh Mardie15e2302011-11-15 10:39:23 +0530177 /*track tabla interface type*/
178 u8 intf_type;
179
Patrick Lai49efeac2011-11-03 11:01:12 -0700180 u32 hph_status; /* track headhpone status */
181 /* define separate work for left and right headphone OCP to avoid
182 * additional checking on which OCP event to report so no locking
183 * to ensure synchronization is required
184 */
185 struct work_struct hphlocp_work; /* reporting left hph ocp off */
186 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800187
188 /* pm_cnt holds number of sleep lock holders + 1
189 * so if pm_cnt is 1 system is sleep-able. */
190 atomic_t pm_cnt;
191 wait_queue_head_t pm_wq;
Patrick Laic7cae882011-11-18 11:52:49 -0800192
193 u8 hphlocp_cnt; /* headphone left ocp retry */
194 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800195
196 /* Callback function to enable MCLK */
197 int (*mclk_cb) (struct snd_soc_codec*, int);
Patrick Lai64b43262011-12-06 17:29:15 -0800198
199 /* Work to perform MBHC Firmware Read */
200 struct delayed_work mbhc_firmware_dwork;
201 const struct firmware *mbhc_fw;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202};
203
Bradley Rubincb3950a2011-08-18 13:07:26 -0700204#ifdef CONFIG_DEBUG_FS
205struct tabla_priv *debug_tabla_priv;
206#endif
207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700208static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
209 struct snd_kcontrol *kcontrol, int event)
210{
211 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700212
213 pr_debug("%s %d\n", __func__, event);
214 switch (event) {
215 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
217 0x01);
218 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
219 usleep_range(200, 200);
220 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
221 break;
222 case SND_SOC_DAPM_PRE_PMD:
223 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
224 0x10);
225 usleep_range(20, 20);
226 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
227 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
228 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
229 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
230 0x00);
231 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232 break;
233 }
234 return 0;
235}
236
Bradley Rubina7096d02011-08-03 18:29:02 -0700237static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
238 struct snd_ctl_elem_value *ucontrol)
239{
240 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
241 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
242 ucontrol->value.integer.value[0] = tabla->anc_slot;
243 return 0;
244}
245
246static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
247 struct snd_ctl_elem_value *ucontrol)
248{
249 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
250 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
251 tabla->anc_slot = ucontrol->value.integer.value[0];
252 return 0;
253}
254
Kiran Kandid2d86b52011-09-09 17:44:28 -0700255static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
256 struct snd_ctl_elem_value *ucontrol)
257{
258 u8 ear_pa_gain;
259 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
260
261 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
262
263 ear_pa_gain = ear_pa_gain >> 5;
264
265 if (ear_pa_gain == 0x00) {
266 ucontrol->value.integer.value[0] = 0;
267 } else if (ear_pa_gain == 0x04) {
268 ucontrol->value.integer.value[0] = 1;
269 } else {
270 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
271 __func__, ear_pa_gain);
272 return -EINVAL;
273 }
274
275 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
276
277 return 0;
278}
279
280static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
281 struct snd_ctl_elem_value *ucontrol)
282{
283 u8 ear_pa_gain;
284 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
285
286 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
287 ucontrol->value.integer.value[0]);
288
289 switch (ucontrol->value.integer.value[0]) {
290 case 0:
291 ear_pa_gain = 0x00;
292 break;
293 case 1:
294 ear_pa_gain = 0x80;
295 break;
296 default:
297 return -EINVAL;
298 }
299
300 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
301 return 0;
302}
303
Ben Romberger1f045a72011-11-04 10:14:57 -0700304static int tabla_get_iir_enable_audio_mixer(
305 struct snd_kcontrol *kcontrol,
306 struct snd_ctl_elem_value *ucontrol)
307{
308 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
309 int iir_idx = ((struct soc_multi_mixer_control *)
310 kcontrol->private_value)->reg;
311 int band_idx = ((struct soc_multi_mixer_control *)
312 kcontrol->private_value)->shift;
313
314 ucontrol->value.integer.value[0] =
315 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
316 (1 << band_idx);
317
318 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
319 iir_idx, band_idx,
320 (uint32_t)ucontrol->value.integer.value[0]);
321 return 0;
322}
323
324static int tabla_put_iir_enable_audio_mixer(
325 struct snd_kcontrol *kcontrol,
326 struct snd_ctl_elem_value *ucontrol)
327{
328 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
329 int iir_idx = ((struct soc_multi_mixer_control *)
330 kcontrol->private_value)->reg;
331 int band_idx = ((struct soc_multi_mixer_control *)
332 kcontrol->private_value)->shift;
333 int value = ucontrol->value.integer.value[0];
334
335 /* Mask first 5 bits, 6-8 are reserved */
336 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
337 (1 << band_idx), (value << band_idx));
338
339 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
340 iir_idx, band_idx, value);
341 return 0;
342}
343static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
344 int iir_idx, int band_idx,
345 int coeff_idx)
346{
347 /* Address does not automatically update if reading */
348 snd_soc_update_bits(codec,
349 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
350 0x1F, band_idx * BAND_MAX + coeff_idx);
351
352 /* Mask bits top 2 bits since they are reserved */
353 return ((snd_soc_read(codec,
354 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
355 (snd_soc_read(codec,
356 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
357 (snd_soc_read(codec,
358 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
359 (snd_soc_read(codec,
360 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
361 0x3FFFFFFF;
362}
363
364static int tabla_get_iir_band_audio_mixer(
365 struct snd_kcontrol *kcontrol,
366 struct snd_ctl_elem_value *ucontrol)
367{
368 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
369 int iir_idx = ((struct soc_multi_mixer_control *)
370 kcontrol->private_value)->reg;
371 int band_idx = ((struct soc_multi_mixer_control *)
372 kcontrol->private_value)->shift;
373
374 ucontrol->value.integer.value[0] =
375 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
376 ucontrol->value.integer.value[1] =
377 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
378 ucontrol->value.integer.value[2] =
379 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
380 ucontrol->value.integer.value[3] =
381 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
382 ucontrol->value.integer.value[4] =
383 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
384
385 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
386 "%s: IIR #%d band #%d b1 = 0x%x\n"
387 "%s: IIR #%d band #%d b2 = 0x%x\n"
388 "%s: IIR #%d band #%d a1 = 0x%x\n"
389 "%s: IIR #%d band #%d a2 = 0x%x\n",
390 __func__, iir_idx, band_idx,
391 (uint32_t)ucontrol->value.integer.value[0],
392 __func__, iir_idx, band_idx,
393 (uint32_t)ucontrol->value.integer.value[1],
394 __func__, iir_idx, band_idx,
395 (uint32_t)ucontrol->value.integer.value[2],
396 __func__, iir_idx, band_idx,
397 (uint32_t)ucontrol->value.integer.value[3],
398 __func__, iir_idx, band_idx,
399 (uint32_t)ucontrol->value.integer.value[4]);
400 return 0;
401}
402
403static void set_iir_band_coeff(struct snd_soc_codec *codec,
404 int iir_idx, int band_idx,
405 int coeff_idx, uint32_t value)
406{
407 /* Mask top 3 bits, 6-8 are reserved */
408 /* Update address manually each time */
409 snd_soc_update_bits(codec,
410 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
411 0x1F, band_idx * BAND_MAX + coeff_idx);
412
413 /* Mask top 2 bits, 7-8 are reserved */
414 snd_soc_update_bits(codec,
415 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
416 0x3F, (value >> 24) & 0x3F);
417
418 /* Isolate 8bits at a time */
419 snd_soc_update_bits(codec,
420 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
421 0xFF, (value >> 16) & 0xFF);
422
423 snd_soc_update_bits(codec,
424 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
425 0xFF, (value >> 8) & 0xFF);
426
427 snd_soc_update_bits(codec,
428 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
429 0xFF, value & 0xFF);
430}
431
432static int tabla_put_iir_band_audio_mixer(
433 struct snd_kcontrol *kcontrol,
434 struct snd_ctl_elem_value *ucontrol)
435{
436 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
437 int iir_idx = ((struct soc_multi_mixer_control *)
438 kcontrol->private_value)->reg;
439 int band_idx = ((struct soc_multi_mixer_control *)
440 kcontrol->private_value)->shift;
441
442 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
443 ucontrol->value.integer.value[0]);
444 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
445 ucontrol->value.integer.value[1]);
446 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
447 ucontrol->value.integer.value[2]);
448 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
449 ucontrol->value.integer.value[3]);
450 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
451 ucontrol->value.integer.value[4]);
452
453 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
454 "%s: IIR #%d band #%d b1 = 0x%x\n"
455 "%s: IIR #%d band #%d b2 = 0x%x\n"
456 "%s: IIR #%d band #%d a1 = 0x%x\n"
457 "%s: IIR #%d band #%d a2 = 0x%x\n",
458 __func__, iir_idx, band_idx,
459 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
460 __func__, iir_idx, band_idx,
461 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
462 __func__, iir_idx, band_idx,
463 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
464 __func__, iir_idx, band_idx,
465 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
466 __func__, iir_idx, band_idx,
467 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
468 return 0;
469}
470
Kiran Kandid2d86b52011-09-09 17:44:28 -0700471static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
472static const struct soc_enum tabla_ear_pa_gain_enum[] = {
473 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
474};
475
Santosh Mardi024010f2011-10-18 06:27:21 +0530476/*cut of frequency for high pass filter*/
477static const char *cf_text[] = {
478 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
479};
480
481static const struct soc_enum cf_dec1_enum =
482 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
483
484static const struct soc_enum cf_dec2_enum =
485 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
486
487static const struct soc_enum cf_dec3_enum =
488 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
489
490static const struct soc_enum cf_dec4_enum =
491 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
492
493static const struct soc_enum cf_dec5_enum =
494 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
495
496static const struct soc_enum cf_dec6_enum =
497 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
498
499static const struct soc_enum cf_dec7_enum =
500 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
501
502static const struct soc_enum cf_dec8_enum =
503 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
504
505static const struct soc_enum cf_dec9_enum =
506 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
507
508static const struct soc_enum cf_dec10_enum =
509 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
510
511static const struct soc_enum cf_rxmix1_enum =
512 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
513
514static const struct soc_enum cf_rxmix2_enum =
515 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
516
517static const struct soc_enum cf_rxmix3_enum =
518 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
519
520static const struct soc_enum cf_rxmix4_enum =
521 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
522
523static const struct soc_enum cf_rxmix5_enum =
524 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
525;
526static const struct soc_enum cf_rxmix6_enum =
527 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
528
529static const struct soc_enum cf_rxmix7_enum =
530 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
531
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700532static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700533
534 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
535 tabla_pa_gain_get, tabla_pa_gain_put),
536
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700537 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
538 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700539 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
540 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700541 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
542 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700543 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
544 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700545 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
546 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700548 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
549 line_gain),
550 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
551 line_gain),
552
Bradley Rubin410383f2011-07-22 13:44:23 -0700553 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
554 -84, 40, digital_gain),
555 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
556 -84, 40, digital_gain),
557 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
558 -84, 40, digital_gain),
559 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
560 -84, 40, digital_gain),
561 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
562 -84, 40, digital_gain),
563 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
564 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700565
Bradley Rubin410383f2011-07-22 13:44:23 -0700566 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700567 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700568 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700570 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
571 digital_gain),
572 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
573 digital_gain),
574 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
575 digital_gain),
576 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
577 digital_gain),
578 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
579 digital_gain),
580 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
581 digital_gain),
582 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
583 digital_gain),
584 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
585 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700586 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
587 40, digital_gain),
588 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
589 40, digital_gain),
590 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
591 40, digital_gain),
592 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
593 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700594 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
595 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700596 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
597 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700598 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
599 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600
601 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800602 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700603 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700604
605 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
606 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530607 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
608 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
609 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
610 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
611 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
612 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
613 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
614 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
615 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
616 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
617
618 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
619 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
620 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
621 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
622 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
623 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
624 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
625 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
626 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
627 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
628
629 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
630 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
631 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
632 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
633 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
634 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
635 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
636
637 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
638 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
639 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
640 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
641 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
642 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
643 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700644
645 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
646 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
647 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
648 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
649 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
650 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
651 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
652 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
653 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
654 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
655 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
656 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
657 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
658 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
659 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
660 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
661 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
662 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
663 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
664 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
665
666 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
667 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
668 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
669 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
670 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
671 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
672 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
673 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
674 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
675 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
676 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
677 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
678 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
679 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
680 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
681 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
682 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
683 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
684 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
685 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700686};
687
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800688static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
689 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
690};
691
692static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
693 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
694};
695
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696static const char *rx_mix1_text[] = {
697 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
698 "RX5", "RX6", "RX7"
699};
700
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700701static const char *rx_dsm_text[] = {
702 "CIC_OUT", "DSM_INV"
703};
704
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700705static const char *sb_tx1_mux_text[] = {
706 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
707 "DEC1"
708};
709
710static const char *sb_tx5_mux_text[] = {
711 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
712 "DEC5"
713};
714
715static const char *sb_tx6_mux_text[] = {
716 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
717 "DEC6"
718};
719
720static const char const *sb_tx7_to_tx10_mux_text[] = {
721 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
722 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
723 "DEC9", "DEC10"
724};
725
726static const char *dec1_mux_text[] = {
727 "ZERO", "DMIC1", "ADC6",
728};
729
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700730static const char *dec2_mux_text[] = {
731 "ZERO", "DMIC2", "ADC5",
732};
733
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700734static const char *dec3_mux_text[] = {
735 "ZERO", "DMIC3", "ADC4",
736};
737
738static const char *dec4_mux_text[] = {
739 "ZERO", "DMIC4", "ADC3",
740};
741
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700742static const char *dec5_mux_text[] = {
743 "ZERO", "DMIC5", "ADC2",
744};
745
746static const char *dec6_mux_text[] = {
747 "ZERO", "DMIC6", "ADC1",
748};
749
750static const char const *dec7_mux_text[] = {
751 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
752};
753
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700754static const char *dec8_mux_text[] = {
755 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
756};
757
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700758static const char *dec9_mux_text[] = {
759 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
760};
761
762static const char *dec10_mux_text[] = {
763 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
764};
765
Bradley Rubin229c6a52011-07-12 16:18:48 -0700766static const char const *anc_mux_text[] = {
767 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
768 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
769};
770
771static const char const *anc1_fb_mux_text[] = {
772 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
773};
774
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700775static const char *iir1_inp1_text[] = {
776 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
777 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
778};
779
780static const struct soc_enum rx_mix1_inp1_chain_enum =
781 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
782
Bradley Rubin229c6a52011-07-12 16:18:48 -0700783static const struct soc_enum rx_mix1_inp2_chain_enum =
784 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
785
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700786static const struct soc_enum rx2_mix1_inp1_chain_enum =
787 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
788
Bradley Rubin229c6a52011-07-12 16:18:48 -0700789static const struct soc_enum rx2_mix1_inp2_chain_enum =
790 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
791
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700792static const struct soc_enum rx3_mix1_inp1_chain_enum =
793 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
794
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700795static const struct soc_enum rx3_mix1_inp2_chain_enum =
796 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
797
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700798static const struct soc_enum rx4_mix1_inp1_chain_enum =
799 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
800
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700801static const struct soc_enum rx4_mix1_inp2_chain_enum =
802 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700804static const struct soc_enum rx5_mix1_inp1_chain_enum =
805 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
806
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700807static const struct soc_enum rx5_mix1_inp2_chain_enum =
808 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
809
810static const struct soc_enum rx6_mix1_inp1_chain_enum =
811 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
812
813static const struct soc_enum rx6_mix1_inp2_chain_enum =
814 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
815
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700816static const struct soc_enum rx7_mix1_inp1_chain_enum =
817 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
818
819static const struct soc_enum rx7_mix1_inp2_chain_enum =
820 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
821
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700822static const struct soc_enum rx4_dsm_enum =
823 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
824
825static const struct soc_enum rx6_dsm_enum =
826 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
827
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828static const struct soc_enum sb_tx5_mux_enum =
829 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
830
831static const struct soc_enum sb_tx6_mux_enum =
832 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
833
834static const struct soc_enum sb_tx7_mux_enum =
835 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
836 sb_tx7_to_tx10_mux_text);
837
838static const struct soc_enum sb_tx8_mux_enum =
839 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
840 sb_tx7_to_tx10_mux_text);
841
Kiran Kandi3426e512011-09-13 22:50:10 -0700842static const struct soc_enum sb_tx9_mux_enum =
843 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
844 sb_tx7_to_tx10_mux_text);
845
846static const struct soc_enum sb_tx10_mux_enum =
847 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
848 sb_tx7_to_tx10_mux_text);
849
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850static const struct soc_enum sb_tx1_mux_enum =
851 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
852
853static const struct soc_enum dec1_mux_enum =
854 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
855
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700856static const struct soc_enum dec2_mux_enum =
857 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
858
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700859static const struct soc_enum dec3_mux_enum =
860 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
861
862static const struct soc_enum dec4_mux_enum =
863 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865static const struct soc_enum dec5_mux_enum =
866 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
867
868static const struct soc_enum dec6_mux_enum =
869 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
870
871static const struct soc_enum dec7_mux_enum =
872 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
873
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700874static const struct soc_enum dec8_mux_enum =
875 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
876
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700877static const struct soc_enum dec9_mux_enum =
878 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
879
880static const struct soc_enum dec10_mux_enum =
881 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
882
Bradley Rubin229c6a52011-07-12 16:18:48 -0700883static const struct soc_enum anc1_mux_enum =
884 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
885
886static const struct soc_enum anc2_mux_enum =
887 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
888
889static const struct soc_enum anc1_fb_mux_enum =
890 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892static const struct soc_enum iir1_inp1_mux_enum =
893 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
894
895static const struct snd_kcontrol_new rx_mix1_inp1_mux =
896 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
897
Bradley Rubin229c6a52011-07-12 16:18:48 -0700898static const struct snd_kcontrol_new rx_mix1_inp2_mux =
899 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
902 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
903
Bradley Rubin229c6a52011-07-12 16:18:48 -0700904static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
905 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
908 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
909
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700910static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
911 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
912
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
914 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
915
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700916static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
917 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700919static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
920 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
921
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700922static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
923 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
924
925static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
926 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
927
928static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
929 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
930
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700931static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
932 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
933
934static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
935 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
936
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700937static const struct snd_kcontrol_new rx4_dsm_mux =
938 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
939
940static const struct snd_kcontrol_new rx6_dsm_mux =
941 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943static const struct snd_kcontrol_new sb_tx5_mux =
944 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
945
946static const struct snd_kcontrol_new sb_tx6_mux =
947 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
948
949static const struct snd_kcontrol_new sb_tx7_mux =
950 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
951
952static const struct snd_kcontrol_new sb_tx8_mux =
953 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
954
Kiran Kandi3426e512011-09-13 22:50:10 -0700955static const struct snd_kcontrol_new sb_tx9_mux =
956 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
957
958static const struct snd_kcontrol_new sb_tx10_mux =
959 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
960
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961static const struct snd_kcontrol_new sb_tx1_mux =
962 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
963
964static const struct snd_kcontrol_new dec1_mux =
965 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
966
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700967static const struct snd_kcontrol_new dec2_mux =
968 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
969
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700970static const struct snd_kcontrol_new dec3_mux =
971 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
972
973static const struct snd_kcontrol_new dec4_mux =
974 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
975
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976static const struct snd_kcontrol_new dec5_mux =
977 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
978
979static const struct snd_kcontrol_new dec6_mux =
980 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
981
982static const struct snd_kcontrol_new dec7_mux =
983 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
984
Bradley Rubin229c6a52011-07-12 16:18:48 -0700985static const struct snd_kcontrol_new anc1_mux =
986 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700987static const struct snd_kcontrol_new dec8_mux =
988 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
989
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700990static const struct snd_kcontrol_new dec9_mux =
991 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
992
993static const struct snd_kcontrol_new dec10_mux =
994 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
995
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996static const struct snd_kcontrol_new iir1_inp1_mux =
997 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
998
Bradley Rubin229c6a52011-07-12 16:18:48 -0700999static const struct snd_kcontrol_new anc2_mux =
1000 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001
Bradley Rubin229c6a52011-07-12 16:18:48 -07001002static const struct snd_kcontrol_new anc1_fb_mux =
1003 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004
Bradley Rubin229c6a52011-07-12 16:18:48 -07001005static const struct snd_kcontrol_new dac1_switch[] = {
1006 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1007};
1008static const struct snd_kcontrol_new hphl_switch[] = {
1009 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1010};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001011
1012static const struct snd_kcontrol_new lineout3_ground_switch =
1013 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1014
1015static const struct snd_kcontrol_new lineout4_ground_switch =
1016 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
1019 int enable)
1020{
1021 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1022
1023 pr_debug("%s %d\n", __func__, enable);
1024
1025 if (enable) {
1026 tabla->adc_count++;
1027 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1028 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1029 } else {
1030 tabla->adc_count--;
1031 if (!tabla->adc_count) {
1032 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
1033 0x2, 0x0);
1034 if (!tabla->mbhc_polling_active)
1035 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
1036 0xE0, 0x0);
1037 }
1038 }
1039}
1040
1041static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1042 struct snd_kcontrol *kcontrol, int event)
1043{
1044 struct snd_soc_codec *codec = w->codec;
1045 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001046 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047
1048 pr_debug("%s %d\n", __func__, event);
1049
1050 if (w->reg == TABLA_A_TX_1_2_EN)
1051 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1052 else if (w->reg == TABLA_A_TX_3_4_EN)
1053 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1054 else if (w->reg == TABLA_A_TX_5_6_EN)
1055 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1056 else {
1057 pr_err("%s: Error, invalid adc register\n", __func__);
1058 return -EINVAL;
1059 }
1060
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001061 if (w->shift == 3)
1062 init_bit_shift = 6;
1063 else if (w->shift == 7)
1064 init_bit_shift = 7;
1065 else {
1066 pr_err("%s: Error, invalid init bit postion adc register\n",
1067 __func__);
1068 return -EINVAL;
1069 }
1070
1071
1072
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001073 switch (event) {
1074 case SND_SOC_DAPM_PRE_PMU:
1075 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001076 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1077 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078 break;
1079 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001080
1081 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1082
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001083 break;
1084 case SND_SOC_DAPM_POST_PMD:
1085 tabla_codec_enable_adc_block(codec, 0);
1086 break;
1087 }
1088 return 0;
1089}
1090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1092 struct snd_kcontrol *kcontrol, int event)
1093{
1094 struct snd_soc_codec *codec = w->codec;
1095 u16 lineout_gain_reg;
1096
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001097 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001098
1099 switch (w->shift) {
1100 case 0:
1101 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1102 break;
1103 case 1:
1104 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1105 break;
1106 case 2:
1107 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1108 break;
1109 case 3:
1110 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1111 break;
1112 case 4:
1113 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1114 break;
1115 default:
1116 pr_err("%s: Error, incorrect lineout register value\n",
1117 __func__);
1118 return -EINVAL;
1119 }
1120
1121 switch (event) {
1122 case SND_SOC_DAPM_PRE_PMU:
1123 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1124 break;
1125 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001126 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001127 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001128 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 break;
1130 case SND_SOC_DAPM_POST_PMD:
1131 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1132 break;
1133 }
1134 return 0;
1135}
1136
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001137
1138static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 struct snd_kcontrol *kcontrol, int event)
1140{
1141 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001142 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1143 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001144 unsigned int dmic;
1145 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001146
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001147 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1148 if (ret < 0) {
1149 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001150 return -EINVAL;
1151 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001153 switch (dmic) {
1154 case 1:
1155 case 2:
1156 dmic_clk_sel = 0x02;
1157 dmic_clk_en = 0x01;
1158 break;
1159
1160 case 3:
1161 case 4:
1162 dmic_clk_sel = 0x08;
1163 dmic_clk_en = 0x04;
1164 break;
1165
1166 case 5:
1167 case 6:
1168 dmic_clk_sel = 0x20;
1169 dmic_clk_en = 0x10;
1170 break;
1171
1172 default:
1173 pr_err("%s: Invalid DMIC Selection\n", __func__);
1174 return -EINVAL;
1175 }
1176
1177 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1178 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182 switch (event) {
1183 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001184 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1185
1186 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1187 dmic_clk_sel, dmic_clk_sel);
1188
1189 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1190
1191 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1192 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193 break;
1194 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001195 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1196 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 break;
1198 }
1199 return 0;
1200}
1201
Bradley Rubin229c6a52011-07-12 16:18:48 -07001202static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1203 struct snd_kcontrol *kcontrol, int event)
1204{
1205 struct snd_soc_codec *codec = w->codec;
1206 const char *filename;
1207 const struct firmware *fw;
1208 int i;
1209 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001210 int num_anc_slots;
1211 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001212 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001213 u32 anc_writes_size = 0;
1214 int anc_size_remaining;
1215 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001216 u16 reg;
1217 u8 mask, val, old_val;
1218
1219 pr_debug("%s %d\n", __func__, event);
1220 switch (event) {
1221 case SND_SOC_DAPM_PRE_PMU:
1222
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001223 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001224
1225 ret = request_firmware(&fw, filename, codec->dev);
1226 if (ret != 0) {
1227 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1228 ret);
1229 return -ENODEV;
1230 }
1231
Bradley Rubina7096d02011-08-03 18:29:02 -07001232 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001233 dev_err(codec->dev, "Not enough data\n");
1234 release_firmware(fw);
1235 return -ENOMEM;
1236 }
1237
1238 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001239 anc_head = (struct anc_header *)(fw->data);
1240 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1241 anc_size_remaining = fw->size - sizeof(struct anc_header);
1242 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001243
Bradley Rubina7096d02011-08-03 18:29:02 -07001244 if (tabla->anc_slot >= num_anc_slots) {
1245 dev_err(codec->dev, "Invalid ANC slot selected\n");
1246 release_firmware(fw);
1247 return -EINVAL;
1248 }
1249
1250 for (i = 0; i < num_anc_slots; i++) {
1251
1252 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1253 dev_err(codec->dev, "Invalid register format\n");
1254 release_firmware(fw);
1255 return -EINVAL;
1256 }
1257 anc_writes_size = (u32)(*anc_ptr);
1258 anc_size_remaining -= sizeof(u32);
1259 anc_ptr += 1;
1260
1261 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1262 > anc_size_remaining) {
1263 dev_err(codec->dev, "Invalid register format\n");
1264 release_firmware(fw);
1265 return -ENOMEM;
1266 }
1267
1268 if (tabla->anc_slot == i)
1269 break;
1270
1271 anc_size_remaining -= (anc_writes_size *
1272 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001273 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001274 }
1275 if (i == num_anc_slots) {
1276 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001277 release_firmware(fw);
1278 return -ENOMEM;
1279 }
1280
Bradley Rubina7096d02011-08-03 18:29:02 -07001281 for (i = 0; i < anc_writes_size; i++) {
1282 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001283 mask, val);
1284 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001285 snd_soc_write(codec, reg, (old_val & ~mask) |
1286 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001287 }
1288 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001289
1290 break;
1291 case SND_SOC_DAPM_POST_PMD:
1292 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1293 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1294 break;
1295 }
1296 return 0;
1297}
1298
1299
Bradley Rubincb3950a2011-08-18 13:07:26 -07001300static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
1301{
1302 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
1303 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
1304}
1305
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001306static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1307{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001308 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1309
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001310 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001311 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001312 if (!tabla->no_mic_headset_override) {
1313 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1314 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1315 } else {
1316 tabla_codec_disable_button_presses(codec);
1317 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001318 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1319 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1320 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1321}
1322
1323static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1324{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001325 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1326
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001327 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1328 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001329 if (!tabla->no_mic_headset_override) {
1330 tabla_disable_irq(codec->control_data,
1331 TABLA_IRQ_MBHC_POTENTIAL);
1332 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1333 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001334}
1335
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001336static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1337 int mode)
1338{
1339 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1340 u8 reg_mode_val, cur_mode_val;
1341 bool mbhc_was_polling = false;
1342
1343 if (mode)
1344 reg_mode_val = TABLA_CFILT_FAST_MODE;
1345 else
1346 reg_mode_val = TABLA_CFILT_SLOW_MODE;
1347
1348 cur_mode_val = snd_soc_read(codec,
1349 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
1350
1351 if (cur_mode_val != reg_mode_val) {
1352 if (tabla->mbhc_polling_active) {
1353 tabla_codec_pause_hs_polling(codec);
1354 mbhc_was_polling = true;
1355 }
1356 snd_soc_update_bits(codec,
1357 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1358 if (mbhc_was_polling)
1359 tabla_codec_start_hs_polling(codec);
1360 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
1361 cur_mode_val, reg_mode_val);
1362 } else {
1363 pr_debug("%s: CFILT Value is already %x\n",
1364 __func__, cur_mode_val);
1365 }
1366}
1367
1368static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1369 u8 cfilt_sel, int inc)
1370{
1371 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1372 u32 *cfilt_cnt_ptr = NULL;
1373 u16 micb_cfilt_reg;
1374
1375 switch (cfilt_sel) {
1376 case TABLA_CFILT1_SEL:
1377 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
1378 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
1379 break;
1380 case TABLA_CFILT2_SEL:
1381 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
1382 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
1383 break;
1384 case TABLA_CFILT3_SEL:
1385 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
1386 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
1387 break;
1388 default:
1389 return; /* should not happen */
1390 }
1391
1392 if (inc) {
1393 if (!(*cfilt_cnt_ptr)++) {
1394 /* Switch CFILT to slow mode if MBHC CFILT being used */
1395 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1396 tabla_codec_switch_cfilt_mode(codec, 0);
1397
1398 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1399 }
1400 } else {
1401 /* check if count not zero, decrement
1402 * then check if zero, go ahead disable cfilter
1403 */
1404 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1405 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1406
1407 /* Switch CFILT to fast mode if MBHC CFILT being used */
1408 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1409 tabla_codec_switch_cfilt_mode(codec, 1);
1410 }
1411 }
1412}
1413
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001414static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1415{
1416 int rc = -EINVAL;
1417 unsigned min_mv, max_mv;
1418
1419 switch (ldoh_v) {
1420 case TABLA_LDOH_1P95_V:
1421 min_mv = 160;
1422 max_mv = 1800;
1423 break;
1424 case TABLA_LDOH_2P35_V:
1425 min_mv = 200;
1426 max_mv = 2200;
1427 break;
1428 case TABLA_LDOH_2P75_V:
1429 min_mv = 240;
1430 max_mv = 2600;
1431 break;
1432 case TABLA_LDOH_2P85_V:
1433 min_mv = 250;
1434 max_mv = 2700;
1435 break;
1436 default:
1437 goto done;
1438 }
1439
1440 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1441 goto done;
1442
1443 for (rc = 4; rc <= 44; rc++) {
1444 min_mv = max_mv * (rc) / 44;
1445 if (min_mv >= cfilt_mv) {
1446 rc -= 4;
1447 break;
1448 }
1449 }
1450done:
1451 return rc;
1452}
1453
1454static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
1455{
1456 u8 hph_reg_val = 0;
1457 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
1458
1459 return (hph_reg_val & 0x30) ? true : false;
1460}
1461
Joonwoo Parka9444452011-12-08 18:48:27 -08001462static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
1463{
1464 u8 hph_reg_val = 0;
1465 if (left)
1466 hph_reg_val = snd_soc_read(codec,
1467 TABLA_A_RX_HPH_L_DAC_CTL);
1468 else
1469 hph_reg_val = snd_soc_read(codec,
1470 TABLA_A_RX_HPH_R_DAC_CTL);
1471
1472 return (hph_reg_val & 0xC0) ? true : false;
1473}
1474
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001475static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
1476 int vddio_switch)
1477{
1478 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1479 int cfilt_k_val;
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001480 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001481
1482 switch (vddio_switch) {
1483 case 1:
1484 if (tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001485
1486 tabla_codec_pause_hs_polling(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08001487 /* VDDIO switch enabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001488 tabla->cfilt_k_value = snd_soc_read(codec,
1489 tabla->mbhc_bias_regs.cfilt_val);
1490 cfilt_k_val = tabla_find_k_value(
1491 tabla->pdata->micbias.ldoh_v, 1800);
1492 snd_soc_update_bits(codec,
1493 tabla->mbhc_bias_regs.cfilt_val,
1494 0xFC, (cfilt_k_val << 2));
1495
1496 snd_soc_update_bits(codec,
1497 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1498 snd_soc_update_bits(codec,
1499 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001500 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001501
1502 tabla->mbhc_micbias_switched = true;
Joonwoo Park0976d012011-12-22 11:48:18 -08001503 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001504 }
1505 break;
1506
1507 case 0:
1508 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001509 if (tabla->mbhc_polling_active) {
1510 tabla_codec_pause_hs_polling(codec);
1511 mbhc_was_polling = true;
1512 }
Joonwoo Park0976d012011-12-22 11:48:18 -08001513 /* VDDIO switch disabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001514 if (tabla->cfilt_k_value != 0)
1515 snd_soc_update_bits(codec,
1516 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
1517 tabla->cfilt_k_value);
1518 snd_soc_update_bits(codec,
1519 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1520 snd_soc_update_bits(codec,
1521 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1522
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001523 if (mbhc_was_polling)
1524 tabla_codec_start_hs_polling(codec);
1525
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001526 tabla->mbhc_micbias_switched = false;
Joonwoo Park0976d012011-12-22 11:48:18 -08001527 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001528 }
1529 break;
1530 }
1531}
1532
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1534 struct snd_kcontrol *kcontrol, int event)
1535{
1536 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07001537 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1538 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001539 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001540 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001541 char *internal1_text = "Internal1";
1542 char *internal2_text = "Internal2";
1543 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544
1545 pr_debug("%s %d\n", __func__, event);
1546 switch (w->reg) {
1547 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001549 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001550 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 break;
1552 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001554 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001555 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 break;
1557 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001559 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001560 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001561 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001562 case TABLA_1_A_MICB_4_CTL:
1563 case TABLA_2_A_MICB_4_CTL:
1564 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07001565 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001566 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 break;
1568 default:
1569 pr_err("%s: Error, invalid micbias register\n", __func__);
1570 return -EINVAL;
1571 }
1572
1573 switch (event) {
1574 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001575 /* Decide whether to switch the micbias for MBHC */
1576 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1577 && tabla->mbhc_micbias_switched)
1578 tabla_codec_switch_micbias(codec, 0);
1579
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001580 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07001581 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001582
1583 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001585 else if (strnstr(w->name, internal2_text, 30))
1586 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1587 else if (strnstr(w->name, internal3_text, 30))
1588 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
1589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001590 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001591 case SND_SOC_DAPM_POST_PMU:
1592 if (tabla->mbhc_polling_active &&
Joonwoo Park0976d012011-12-22 11:48:18 -08001593 tabla->micbias == micb_line) {
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001594 tabla_codec_pause_hs_polling(codec);
1595 tabla_codec_start_hs_polling(codec);
1596 }
1597 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001600
1601 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1602 && tabla_is_hph_pa_on(codec))
1603 tabla_codec_switch_micbias(codec, 1);
1604
Bradley Rubin229c6a52011-07-12 16:18:48 -07001605 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001606 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001607 else if (strnstr(w->name, internal2_text, 30))
1608 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1609 else if (strnstr(w->name, internal3_text, 30))
1610 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1611
Patrick Lai3043fba2011-08-01 14:15:57 -07001612 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 break;
1614 }
1615
1616 return 0;
1617}
1618
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
1620 struct snd_kcontrol *kcontrol, int event)
1621{
1622 struct snd_soc_codec *codec = w->codec;
1623 u16 dec_reset_reg;
1624
1625 pr_debug("%s %d\n", __func__, event);
1626
1627 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1628 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
1629 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
1630 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
1631 else {
1632 pr_err("%s: Error, incorrect dec\n", __func__);
1633 return -EINVAL;
1634 }
1635
1636 switch (event) {
1637 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001638 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1639 1 << w->shift);
1640 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1641 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001642 }
1643 return 0;
1644}
1645
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001646static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001647 struct snd_kcontrol *kcontrol, int event)
1648{
1649 struct snd_soc_codec *codec = w->codec;
1650
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001651 pr_debug("%s %d %s\n", __func__, event, w->name);
1652
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001653 switch (event) {
1654 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001655 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1656 1 << w->shift, 1 << w->shift);
1657 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1658 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659 break;
1660 }
1661 return 0;
1662}
1663
Bradley Rubin229c6a52011-07-12 16:18:48 -07001664static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1665 struct snd_kcontrol *kcontrol, int event)
1666{
1667 switch (event) {
1668 case SND_SOC_DAPM_POST_PMU:
1669 case SND_SOC_DAPM_POST_PMD:
1670 usleep_range(1000, 1000);
1671 break;
1672 }
1673 return 0;
1674}
1675
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001676
1677static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1678{
1679 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1680
1681 if (enable) {
1682 tabla->rx_bias_count++;
1683 if (tabla->rx_bias_count == 1)
1684 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1685 0x80, 0x80);
1686 } else {
1687 tabla->rx_bias_count--;
1688 if (!tabla->rx_bias_count)
1689 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1690 0x80, 0x00);
1691 }
1692}
1693
1694static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1695 struct snd_kcontrol *kcontrol, int event)
1696{
1697 struct snd_soc_codec *codec = w->codec;
1698
1699 pr_debug("%s %d\n", __func__, event);
1700
1701 switch (event) {
1702 case SND_SOC_DAPM_PRE_PMU:
1703 tabla_enable_rx_bias(codec, 1);
1704 break;
1705 case SND_SOC_DAPM_POST_PMD:
1706 tabla_enable_rx_bias(codec, 0);
1707 break;
1708 }
1709 return 0;
1710}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001711static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
1712 struct snd_kcontrol *kcontrol, int event)
1713{
1714 struct snd_soc_codec *codec = w->codec;
1715
1716 pr_debug("%s %s %d\n", __func__, w->name, event);
1717
1718 switch (event) {
1719 case SND_SOC_DAPM_PRE_PMU:
1720 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1721 break;
1722 case SND_SOC_DAPM_POST_PMD:
1723 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1724 break;
1725 }
1726 return 0;
1727}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001728
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001729static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
1730 struct snd_soc_jack *jack, int status,
1731 int mask)
1732{
1733 /* XXX: wake_lock_timeout()? */
1734 snd_soc_jack_report(jack, status, mask);
1735}
1736
Patrick Lai49efeac2011-11-03 11:01:12 -07001737static void hphocp_off_report(struct tabla_priv *tabla,
1738 u32 jack_status, int irq)
1739{
1740 struct snd_soc_codec *codec;
1741
1742 if (tabla) {
1743 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
1744 codec = tabla->codec;
1745 tabla->hph_status &= ~jack_status;
1746 if (tabla->headset_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001747 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
1748 tabla->hph_status,
1749 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08001750 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
1751 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08001752 /* reset retry counter as PA is turned off signifying
1753 * start of new OCP detection session
1754 */
1755 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
1756 tabla->hphlocp_cnt = 0;
1757 else
1758 tabla->hphrocp_cnt = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07001759 tabla_enable_irq(codec->control_data, irq);
1760 } else {
1761 pr_err("%s: Bad tabla private data\n", __func__);
1762 }
1763}
1764
1765static void hphlocp_off_report(struct work_struct *work)
1766{
1767 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1768 hphlocp_work);
1769 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
1770}
1771
1772static void hphrocp_off_report(struct work_struct *work)
1773{
1774 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1775 hphrocp_work);
1776 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
1777}
1778
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001779static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
1780 struct snd_kcontrol *kcontrol, int event)
1781{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001782 struct snd_soc_codec *codec = w->codec;
1783 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1784 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001785 pr_debug("%s: event = %d\n", __func__, event);
1786
1787 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001788 case SND_SOC_DAPM_PRE_PMU:
1789 mbhc_micb_ctl_val = snd_soc_read(codec,
1790 tabla->mbhc_bias_regs.ctl_reg);
1791
1792 if (!(mbhc_micb_ctl_val & 0x80)
1793 && !tabla->mbhc_micbias_switched)
1794 tabla_codec_switch_micbias(codec, 1);
1795
1796 break;
1797
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001798 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07001799 /* schedule work is required because at the time HPH PA DAPM
1800 * event callback is called by DAPM framework, CODEC dapm mutex
1801 * would have been locked while snd_soc_jack_report also
1802 * attempts to acquire same lock.
1803 */
Joonwoo Parka9444452011-12-08 18:48:27 -08001804 if (w->shift == 5) {
1805 clear_bit(TABLA_HPHL_PA_OFF_ACK,
1806 &tabla->hph_pa_dac_state);
1807 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
1808 &tabla->hph_pa_dac_state);
1809 if (tabla->hph_status & SND_JACK_OC_HPHL)
1810 schedule_work(&tabla->hphlocp_work);
1811 } else if (w->shift == 4) {
1812 clear_bit(TABLA_HPHR_PA_OFF_ACK,
1813 &tabla->hph_pa_dac_state);
1814 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
1815 &tabla->hph_pa_dac_state);
1816 if (tabla->hph_status & SND_JACK_OC_HPHR)
1817 schedule_work(&tabla->hphrocp_work);
1818 }
1819
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001820 if (tabla->mbhc_micbias_switched)
1821 tabla_codec_switch_micbias(codec, 0);
1822
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001823 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
1824 w->name);
1825 usleep_range(10000, 10000);
1826
1827 break;
1828 }
1829 return 0;
1830}
1831
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001832static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001833 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001834{
1835 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001836 unsigned int cfilt;
1837
Joonwoo Park0976d012011-12-22 11:48:18 -08001838 switch (tabla->micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001839 case TABLA_MICBIAS1:
1840 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
1841 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
1842 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
1843 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
1844 break;
1845 case TABLA_MICBIAS2:
1846 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
1847 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
1848 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
1849 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
1850 break;
1851 case TABLA_MICBIAS3:
1852 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
1853 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
1854 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
1855 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
1856 break;
1857 case TABLA_MICBIAS4:
1858 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001859 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
1860 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
1861 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001862 break;
1863 default:
1864 /* Should never reach here */
1865 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07001866 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001867 }
1868
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001869 micbias_regs->cfilt_sel = cfilt;
1870
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001871 switch (cfilt) {
1872 case TABLA_CFILT1_SEL:
1873 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
1874 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001875 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001876 break;
1877 case TABLA_CFILT2_SEL:
1878 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
1879 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001880 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001881 break;
1882 case TABLA_CFILT3_SEL:
1883 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
1884 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001885 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001886 break;
1887 }
1888}
Santosh Mardie15e2302011-11-15 10:39:23 +05301889static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
1890 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
1891 4, 0, NULL, 0),
1892 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
1893 0, NULL, 0),
1894};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001895
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001896static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
1897 struct snd_kcontrol *kcontrol, int event)
1898{
1899 struct snd_soc_codec *codec = w->codec;
1900
1901 pr_debug("%s %s %d\n", __func__, w->name, event);
1902
1903 switch (event) {
1904 case SND_SOC_DAPM_PRE_PMU:
1905 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1906 break;
1907
1908 case SND_SOC_DAPM_POST_PMD:
1909 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1910 break;
1911 }
1912 return 0;
1913}
1914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001915static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
1916 /*RX stuff */
1917 SND_SOC_DAPM_OUTPUT("EAR"),
1918
Kiran Kandid2d86b52011-09-09 17:44:28 -07001919 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001920
Bradley Rubin229c6a52011-07-12 16:18:48 -07001921 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
1922 ARRAY_SIZE(dac1_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001923
Bradley Rubin229c6a52011-07-12 16:18:48 -07001924 SND_SOC_DAPM_AIF_IN("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1925 SND_SOC_DAPM_AIF_IN("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Santosh Mardie15e2302011-11-15 10:39:23 +05301926 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
1927 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928
1929 /* Headphone */
1930 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001931 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001932 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1933 SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07001934 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
1935 hphl_switch, ARRAY_SIZE(hphl_switch)),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001936
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001937 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001938 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
1939 SND_SOC_DAPM_POST_PMD),
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001940
1941 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
1942 tabla_hphr_dac_event,
1943 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001944
1945 /* Speaker */
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001946 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
1947 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
1948 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
1949 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
1950 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001951
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001952 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
1953 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1954 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1955 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
1956 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1957 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1958 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
1959 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1960 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1961 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
1962 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1963 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1964 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001965 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
1966 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001967
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001968 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
1969 , tabla_lineout_dac_event,
1970 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1971 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
1972 , tabla_lineout_dac_event,
1973 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1974 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
1975 , tabla_lineout_dac_event,
1976 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1977 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
1978 &lineout3_ground_switch),
1979 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
1980 , tabla_lineout_dac_event,
1981 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1982 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
1983 &lineout4_ground_switch),
1984 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
1985 , tabla_lineout_dac_event,
1986 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001987
Bradley Rubin229c6a52011-07-12 16:18:48 -07001988 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
1989 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1990 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
1991 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1992 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
1993 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1994 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
1995 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1996 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
1997 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
1998 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
1999 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002000 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
2001 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002002
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002003
2004 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
2005 &rx4_dsm_mux, tabla_codec_reset_interpolator,
2006 SND_SOC_DAPM_PRE_PMU),
2007
2008 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
2009 &rx6_dsm_mux, tabla_codec_reset_interpolator,
2010 SND_SOC_DAPM_PRE_PMU),
2011
Bradley Rubin229c6a52011-07-12 16:18:48 -07002012 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
2013 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
2014
2015 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2016 &rx_mix1_inp1_mux),
2017 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2018 &rx_mix1_inp2_mux),
2019 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2020 &rx2_mix1_inp1_mux),
2021 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2022 &rx2_mix1_inp2_mux),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002023 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2024 &rx3_mix1_inp1_mux),
2025 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2026 &rx3_mix1_inp2_mux),
2027 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2028 &rx4_mix1_inp1_mux),
2029 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2030 &rx4_mix1_inp2_mux),
2031 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2032 &rx5_mix1_inp1_mux),
2033 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2034 &rx5_mix1_inp2_mux),
2035 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2036 &rx6_mix1_inp1_mux),
2037 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2038 &rx6_mix1_inp2_mux),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002039 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2040 &rx7_mix1_inp1_mux),
2041 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2042 &rx7_mix1_inp2_mux),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002043
Bradley Rubin229c6a52011-07-12 16:18:48 -07002044 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
2045 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2046 SND_SOC_DAPM_PRE_PMD),
2047
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002048 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2049 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2050 SND_SOC_DAPM_POST_PMD),
2051
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052 /* TX */
Bradley Rubin229c6a52011-07-12 16:18:48 -07002053
Bradley Rubine1d08622011-07-20 18:01:35 -07002054 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
2055 0),
2056
Bradley Rubin229c6a52011-07-12 16:18:48 -07002057 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
2058 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
2059
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002060 SND_SOC_DAPM_INPUT("AMIC1"),
2061 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
2062 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002063 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002064 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
2065 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002066 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002067 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002069 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002070 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
2071 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2072 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2073
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002074 SND_SOC_DAPM_INPUT("AMIC3"),
2075 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
2076 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2077 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2078
2079 SND_SOC_DAPM_INPUT("AMIC4"),
2080 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
2081 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2082 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2083
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002084 SND_SOC_DAPM_INPUT("AMIC5"),
2085 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
2086 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
2087
2088 SND_SOC_DAPM_INPUT("AMIC6"),
2089 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
2090 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
2091
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002092 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 -07002093 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002094
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002095 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 -07002096 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002097
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002098 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 -07002099 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002100
2101 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 -07002102 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002103
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002104 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 -07002105 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002106
2107 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 -07002108 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002109
2110 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 -07002111 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002112
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002113 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 -07002114 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002115
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002116 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 -07002117 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002118
2119 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 -07002120 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002121
Bradley Rubin229c6a52011-07-12 16:18:48 -07002122 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
2123 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
2124
2125 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
2126 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
2127 SND_SOC_DAPM_POST_PMD),
2128
2129 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
2130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002131 SND_SOC_DAPM_INPUT("AMIC2"),
2132 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
2133 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002134 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002135 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
2136 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002137 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002138 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
2139 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002140 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002141 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002143 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002144 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
2145 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002146 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002147 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
2148 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002149 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bradley Rubin229c6a52011-07-12 16:18:48 -07002150 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002151 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002152 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002153 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
2154 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2155 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2156
2157 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
2158 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
2159 0, 0),
2160
2161 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
2162 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
2163 4, 0),
2164
2165 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
2166 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
2167 5, 0),
2168
2169 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
2170 SND_SOC_DAPM_AIF_OUT("SLIM TX7", "AIF1 Capture", NULL, SND_SOC_NOPM,
2171 0, 0),
2172
2173 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
2174 SND_SOC_DAPM_AIF_OUT("SLIM TX8", "AIF1 Capture", NULL, SND_SOC_NOPM,
2175 0, 0),
2176
Kiran Kandi3426e512011-09-13 22:50:10 -07002177 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
2178 SND_SOC_DAPM_AIF_OUT("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
2179 0, 0),
2180
2181 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
2182 SND_SOC_DAPM_AIF_OUT("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
2183 0, 0),
2184
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002185 /* Digital Mic Inputs */
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002186 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2187 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2188 SND_SOC_DAPM_POST_PMD),
2189
2190 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2191 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2192 SND_SOC_DAPM_POST_PMD),
2193
2194 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
2195 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2196 SND_SOC_DAPM_POST_PMD),
2197
2198 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
2199 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2200 SND_SOC_DAPM_POST_PMD),
2201
2202 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
2203 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2204 SND_SOC_DAPM_POST_PMD),
2205
2206 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
2207 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2208 SND_SOC_DAPM_POST_PMD),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002209
2210 /* Sidetone */
2211 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2212 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2213};
2214
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002215static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
2216 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
2217 0, tabla_codec_enable_micbias,
2218 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2219 SND_SOC_DAPM_POST_PMD),
2220};
2221
2222static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
2223 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
2224 0, tabla_codec_enable_micbias,
2225 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2226 SND_SOC_DAPM_POST_PMD),
2227};
2228
Santosh Mardie15e2302011-11-15 10:39:23 +05302229static const struct snd_soc_dapm_route audio_i2s_map[] = {
2230 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2231 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2232 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2233 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2234 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2235
2236 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2237 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2238 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2239 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2240};
2241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002242static const struct snd_soc_dapm_route audio_map[] = {
2243 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244
2245 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2246 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2247
2248 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2249 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2250
2251 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2252 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2253
2254 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2255 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002256 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002257 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2258 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002259 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2260 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002261 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2262 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002263 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2264 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265
2266 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002267 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2268 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2269 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002270 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002271 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2272 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2273
Kiran Kandi3426e512011-09-13 22:50:10 -07002274 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
2275 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
2276 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
2277 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
2278 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
2279 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
2280 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
2281 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
2282 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
2283 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
2284 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
2285
2286 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
2287 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
2288 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
2289 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
2290 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
2291 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
2292 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
2293 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
2294 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
2295 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
2296 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
2297
2298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 /* Earpiece (RX MIX1) */
2300 {"EAR", NULL, "EAR PA"},
Kiran Kandiac034ac2011-07-29 16:39:08 -07002301 {"EAR PA", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002302 {"DAC1", NULL, "CP"},
2303
2304 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2305 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2306 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002307
2308 /* Headset (RX MIX1 and RX MIX2) */
2309 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002311
2312 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002314
2315 {"HPHL DAC", NULL, "CP"},
2316 {"HPHR DAC", NULL, "CP"},
2317
2318 {"ANC", NULL, "ANC1 MUX"},
2319 {"ANC", NULL, "ANC2 MUX"},
2320 {"ANC1 MUX", "ADC1", "ADC1"},
2321 {"ANC1 MUX", "ADC2", "ADC2"},
2322 {"ANC1 MUX", "ADC3", "ADC3"},
2323 {"ANC1 MUX", "ADC4", "ADC4"},
2324 {"ANC2 MUX", "ADC1", "ADC1"},
2325 {"ANC2 MUX", "ADC2", "ADC2"},
2326 {"ANC2 MUX", "ADC3", "ADC3"},
2327 {"ANC2 MUX", "ADC4", "ADC4"},
2328
Bradley Rubine1d08622011-07-20 18:01:35 -07002329 {"ANC", NULL, "CDC_CONN"},
2330
Bradley Rubin229c6a52011-07-12 16:18:48 -07002331 {"DAC1", "Switch", "RX1 CHAIN"},
2332 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002333 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002335 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2336 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2337 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2338 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2339 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002340
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002341 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2342 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2343 {"LINEOUT3 PA", NULL, "LINEOUT3 DAC"},
2344 {"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
2345 {"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002346
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002347 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2348 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2349
Bradley Rubin229c6a52011-07-12 16:18:48 -07002350 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2351 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2352 {"RX1 CHAIN", NULL, "ANC"},
2353 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002354
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002355 {"CP", NULL, "RX_BIAS"},
2356 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2357 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2358 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2359 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002360 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002361
Bradley Rubin229c6a52011-07-12 16:18:48 -07002362 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2363 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2364 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2365 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002366 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2367 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2368 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2369 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2370 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2371 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2372 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2373 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002374 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2375 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002376
Bradley Rubin229c6a52011-07-12 16:18:48 -07002377 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2378 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302379 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2380 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002381 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2382 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2383 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302384 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2385 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002386 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2387 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2388 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302389 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2390 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002391 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002392 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2393 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302394 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2395 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002396 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002397 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2398 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302399 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2400 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002401 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002402 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2403 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302404 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2405 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002406 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002407 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2408 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302409 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2410 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002411 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002412 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2413 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302414 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2415 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002416 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002417 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2418 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302419 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2420 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002421 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002422 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2423 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302424 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2425 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002426 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002427 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2428 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302429 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2430 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002431 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002432 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2433 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302434 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2435 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002436 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002437 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2438 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302439 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2440 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002441 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002442 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2443 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302444 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2445 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002446 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002447
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002448 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002449 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002450 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002451 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002452 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002453 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002454 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002455 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002456 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002457 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002458 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002459 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002460 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002461 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002462 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002463 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002464 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002465 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002466 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002467 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002468 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002469 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002470 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002471 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002472 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002473 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002474 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002475 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002476
2477 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002478 {"ADC1", NULL, "AMIC1"},
2479 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002480 {"ADC3", NULL, "AMIC3"},
2481 {"ADC4", NULL, "AMIC4"},
2482 {"ADC5", NULL, "AMIC5"},
2483 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002484
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002485 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002486 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2487 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2488 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2489 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2490 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002492 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
2493 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
2494 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
2495 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002496
2497 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2498 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2499 {"MIC BIAS1 External", NULL, "LDO_H"},
2500 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2501 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2502 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2503 {"MIC BIAS2 External", NULL, "LDO_H"},
2504 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2505 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2506 {"MIC BIAS3 External", NULL, "LDO_H"},
2507 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002508};
2509
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002510static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
2511
2512 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2513 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2514
2515 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
2516
2517 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
2518 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
2519 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
2520
2521 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2522 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2523
2524 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2525 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
2526 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
2527};
2528
Kiran Kandi7a9fd902011-11-14 13:51:45 -08002529
2530static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
2531
2532 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2533 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2534
2535 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
2536
2537 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
2538
2539 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2540 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2541
2542 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2543};
2544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002545static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
2546{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002547 int i;
2548 struct tabla *tabla_core = dev_get_drvdata(ssc->dev->parent);
2549
2550 if (TABLA_IS_1_X(tabla_core->version)) {
2551 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
2552 if (tabla_1_reg_readable[i] == reg)
2553 return 1;
2554 }
2555 } else {
2556 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
2557 if (tabla_2_reg_readable[i] == reg)
2558 return 1;
2559 }
2560 }
2561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002562 return tabla_reg_readable[reg];
2563}
2564
2565static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2566{
2567 /* Registers lower than 0x100 are top level registers which can be
2568 * written by the Tabla core driver.
2569 */
2570
2571 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2572 return 1;
2573
Ben Romberger1f045a72011-11-04 10:14:57 -07002574 /* IIR Coeff registers are not cacheable */
2575 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
2576 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
2577 return 1;
2578
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579 return 0;
2580}
2581
2582#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2583static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
2584 unsigned int value)
2585{
2586 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002587
2588 BUG_ON(reg > TABLA_MAX_REGISTER);
2589
2590 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002591 ret = snd_soc_cache_write(codec, reg, value);
2592 if (ret != 0)
2593 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2594 reg, ret);
2595 }
2596
2597 return tabla_reg_write(codec->control_data, reg, value);
2598}
2599static unsigned int tabla_read(struct snd_soc_codec *codec,
2600 unsigned int reg)
2601{
2602 unsigned int val;
2603 int ret;
2604
2605 BUG_ON(reg > TABLA_MAX_REGISTER);
2606
2607 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
2608 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002609 ret = snd_soc_cache_read(codec, reg, &val);
2610 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002611 return val;
2612 } else
2613 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2614 reg, ret);
2615 }
2616
2617 val = tabla_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 return val;
2619}
2620
2621static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2622{
2623 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
2624 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2625 0x80);
2626 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
2627 0x04);
2628 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2629 0x01);
2630 usleep_range(1000, 1000);
2631 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2632 0x00);
2633}
2634
2635static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
2636 enum tabla_bandgap_type choice)
2637{
2638 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2639
2640 /* TODO lock resources accessed by audio streams and threaded
2641 * interrupt handlers
2642 */
2643
2644 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
2645 tabla->bandgap_type);
2646
2647 if (tabla->bandgap_type == choice)
2648 return;
2649
2650 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
2651 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2652 tabla_codec_enable_audio_mode_bandgap(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302653 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002654 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
2655 0x2);
2656 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2657 0x80);
2658 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
2659 0x4);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302660 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2661 0x01);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002662 usleep_range(1000, 1000);
2663 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2664 0x00);
2665 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
2666 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2667 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2668 usleep_range(100, 100);
2669 tabla_codec_enable_audio_mode_bandgap(codec);
2670 } else if (choice == TABLA_BANDGAP_OFF) {
2671 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2672 } else {
2673 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2674 }
2675 tabla->bandgap_type = choice;
2676}
2677
2678static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
2679 int enable)
2680{
2681 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2682
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002683 pr_debug("%s: enable = %d\n", __func__, enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 if (enable) {
2685 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
2686 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
2687 usleep_range(5, 5);
2688 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
2689 0x80);
2690 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
2691 0x80);
2692 usleep_range(10, 10);
2693 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
2694 usleep_range(20, 20);
2695 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
2696 } else {
2697 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
2698 0);
2699 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002700 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002701 }
2702 tabla->config_mode_active = enable ? true : false;
2703
2704 return 0;
2705}
2706
2707static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
2708 int config_mode)
2709{
2710 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2711
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002712 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002713
2714 if (config_mode) {
2715 tabla_codec_enable_config_mode(codec, 1);
2716 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
2717 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2718 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
2719 usleep_range(1000, 1000);
2720 } else
2721 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
2722
2723 if (!config_mode && tabla->mbhc_polling_active) {
2724 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2725 tabla_codec_enable_config_mode(codec, 0);
2726
2727 }
2728
2729 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
2730 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
2731 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
2732 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
2733 usleep_range(50, 50);
2734 tabla->clock_active = true;
2735 return 0;
2736}
2737static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
2738{
2739 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2740 pr_debug("%s\n", __func__);
2741 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
2742 ndelay(160);
2743 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
2744 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
2745 tabla->clock_active = false;
2746}
2747
Joonwoo Park107edf02012-01-11 11:42:24 -08002748static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
2749{
2750 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
2751 return 0;
2752 else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
2753 return 1;
2754 else {
2755 BUG_ON(1);
2756 return -EINVAL;
2757 }
2758}
2759
Bradley Rubincb1e2732011-06-23 16:49:20 -07002760static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2761{
Joonwoo Parkc0672392012-01-11 11:03:14 -08002762 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08002763 struct tabla_mbhc_btn_detect_cfg *btn_det;
2764 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002765
Joonwoo Park0976d012011-12-22 11:48:18 -08002766 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002767
Joonwoo Park0976d012011-12-22 11:48:18 -08002768 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2769 tabla->mbhc_data.v_ins_hu & 0xFF);
2770 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2771 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002772
Joonwoo Park0976d012011-12-22 11:48:18 -08002773 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2774 tabla->mbhc_data.v_b1_hu & 0xFF);
2775 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2776 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
2777
2778 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2779 tabla->mbhc_data.v_b1_h & 0xFF);
2780 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2781 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
2782
2783 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
2784 tabla->mbhc_data.v_brh & 0xFF);
2785 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
2786 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
2787
2788 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
2789 tabla->mbhc_data.v_brl & 0xFF);
2790 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
2791 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
2792
Joonwoo Parkc0672392012-01-11 11:03:14 -08002793 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08002794 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08002795 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08002796 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
2797 tabla->mbhc_data.npoll);
2798 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
2799 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08002800 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08002801 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
2802 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002803}
2804
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002805static int tabla_startup(struct snd_pcm_substream *substream,
2806 struct snd_soc_dai *dai)
2807{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002808 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2809 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002810
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002811 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812}
2813
2814static void tabla_shutdown(struct snd_pcm_substream *substream,
2815 struct snd_soc_dai *dai)
2816{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002817 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2818 substream->name, substream->stream);
2819}
2820
2821int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
2822{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002823 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2824
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002825 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002826
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002827 if (mclk_enable) {
2828 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002829
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002830 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07002831 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002832 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002833 TABLA_BANDGAP_AUDIO_MODE);
2834 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002835 tabla_codec_calibrate_hs_polling(codec);
2836 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302837 } else {
2838 tabla_codec_enable_bandgap(codec,
2839 TABLA_BANDGAP_AUDIO_MODE);
2840 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002841 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002842 } else {
2843
2844 if (!tabla->mclk_enabled) {
2845 pr_err("Error, MCLK already diabled\n");
2846 return -EINVAL;
2847 }
2848 tabla->mclk_enabled = false;
2849
2850 if (tabla->mbhc_polling_active) {
2851 if (!tabla->mclk_enabled) {
2852 tabla_codec_pause_hs_polling(codec);
2853 tabla_codec_enable_bandgap(codec,
2854 TABLA_BANDGAP_MBHC_MODE);
2855 tabla_enable_rx_bias(codec, 1);
2856 tabla_codec_enable_clock_block(codec, 1);
2857 tabla_codec_calibrate_hs_polling(codec);
2858 tabla_codec_start_hs_polling(codec);
2859 }
2860 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
2861 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302862 } else {
2863 tabla_codec_disable_clock_block(codec);
2864 tabla_codec_enable_bandgap(codec,
2865 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002866 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002867 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002868 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869}
2870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002871static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
2872 int clk_id, unsigned int freq, int dir)
2873{
2874 pr_debug("%s\n", __func__);
2875 return 0;
2876}
2877
2878static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2879{
Santosh Mardie15e2302011-11-15 10:39:23 +05302880 u8 val = 0;
2881 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
2882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002883 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05302884 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2885 case SND_SOC_DAIFMT_CBS_CFS:
2886 /* CPU is master */
2887 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2888 if (dai->id == TABLA_TX_DAI_ID)
2889 snd_soc_update_bits(dai->codec,
2890 TABLA_A_CDC_CLK_TX_I2S_CTL,
2891 TABLA_I2S_MASTER_MODE_MASK, 0);
2892 else if (dai->id == TABLA_RX_DAI_ID)
2893 snd_soc_update_bits(dai->codec,
2894 TABLA_A_CDC_CLK_RX_I2S_CTL,
2895 TABLA_I2S_MASTER_MODE_MASK, 0);
2896 }
2897 break;
2898 case SND_SOC_DAIFMT_CBM_CFM:
2899 /* CPU is slave */
2900 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2901 val = TABLA_I2S_MASTER_MODE_MASK;
2902 if (dai->id == TABLA_TX_DAI_ID)
2903 snd_soc_update_bits(dai->codec,
2904 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
2905 else if (dai->id == TABLA_RX_DAI_ID)
2906 snd_soc_update_bits(dai->codec,
2907 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
2908 }
2909 break;
2910 default:
2911 return -EINVAL;
2912 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002913 return 0;
2914}
2915
2916static int tabla_hw_params(struct snd_pcm_substream *substream,
2917 struct snd_pcm_hw_params *params,
2918 struct snd_soc_dai *dai)
2919{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002920 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05302921 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07002922 u8 path, shift;
2923 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002924 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
2925
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002926 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002927
2928 switch (params_rate(params)) {
2929 case 8000:
2930 tx_fs_rate = 0x00;
2931 rx_fs_rate = 0x00;
2932 break;
2933 case 16000:
2934 tx_fs_rate = 0x01;
2935 rx_fs_rate = 0x20;
2936 break;
2937 case 32000:
2938 tx_fs_rate = 0x02;
2939 rx_fs_rate = 0x40;
2940 break;
2941 case 48000:
2942 tx_fs_rate = 0x03;
2943 rx_fs_rate = 0x60;
2944 break;
2945 default:
2946 pr_err("%s: Invalid sampling rate %d\n", __func__,
2947 params_rate(params));
2948 return -EINVAL;
2949 }
2950
2951
2952 /**
2953 * If current dai is a tx dai, set sample rate to
2954 * all the txfe paths that are currently not active
2955 */
2956 if (dai->id == TABLA_TX_DAI_ID) {
2957
2958 tx_state = snd_soc_read(codec,
2959 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
2960
2961 for (path = 1, shift = 0;
2962 path <= NUM_DECIMATORS; path++, shift++) {
2963
2964 if (path == BITS_PER_REG + 1) {
2965 shift = 0;
2966 tx_state = snd_soc_read(codec,
2967 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
2968 }
2969
2970 if (!(tx_state & (1 << shift))) {
2971 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
2972 + (BITS_PER_REG*(path-1));
2973 snd_soc_update_bits(codec, tx_fs_reg,
2974 0x03, tx_fs_rate);
2975 }
2976 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302977 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2978 switch (params_format(params)) {
2979 case SNDRV_PCM_FORMAT_S16_LE:
2980 snd_soc_update_bits(codec,
2981 TABLA_A_CDC_CLK_TX_I2S_CTL,
2982 0x20, 0x20);
2983 break;
2984 case SNDRV_PCM_FORMAT_S32_LE:
2985 snd_soc_update_bits(codec,
2986 TABLA_A_CDC_CLK_TX_I2S_CTL,
2987 0x20, 0x00);
2988 break;
2989 default:
2990 pr_err("invalid format\n");
2991 break;
2992 }
2993 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
2994 0x03, tx_fs_rate);
2995 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002996 }
2997
2998 /**
2999 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3000 * with varying sample rates
3001 */
3002
3003 /**
3004 * If current dai is a rx dai, set sample rate to
3005 * all the rx paths that are currently not active
3006 */
3007 if (dai->id == TABLA_RX_DAI_ID) {
3008
3009 rx_state = snd_soc_read(codec,
3010 TABLA_A_CDC_CLK_RX_B1_CTL);
3011
3012 for (path = 1, shift = 0;
3013 path <= NUM_INTERPOLATORS; path++, shift++) {
3014
3015 if (!(rx_state & (1 << shift))) {
3016 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
3017 + (BITS_PER_REG*(path-1));
3018 snd_soc_update_bits(codec, rx_fs_reg,
3019 0xE0, rx_fs_rate);
3020 }
3021 }
Santosh Mardie15e2302011-11-15 10:39:23 +05303022 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
3023 switch (params_format(params)) {
3024 case SNDRV_PCM_FORMAT_S16_LE:
3025 snd_soc_update_bits(codec,
3026 TABLA_A_CDC_CLK_RX_I2S_CTL,
3027 0x20, 0x20);
3028 break;
3029 case SNDRV_PCM_FORMAT_S32_LE:
3030 snd_soc_update_bits(codec,
3031 TABLA_A_CDC_CLK_RX_I2S_CTL,
3032 0x20, 0x00);
3033 break;
3034 default:
3035 pr_err("invalid format\n");
3036 break;
3037 }
3038 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
3039 0x03, (rx_fs_rate >> 0x05));
3040 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003041 }
3042
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003043 return 0;
3044}
3045
3046static struct snd_soc_dai_ops tabla_dai_ops = {
3047 .startup = tabla_startup,
3048 .shutdown = tabla_shutdown,
3049 .hw_params = tabla_hw_params,
3050 .set_sysclk = tabla_set_dai_sysclk,
3051 .set_fmt = tabla_set_dai_fmt,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003052};
3053
3054static struct snd_soc_dai_driver tabla_dai[] = {
3055 {
3056 .name = "tabla_rx1",
3057 .id = 1,
3058 .playback = {
3059 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003060 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003061 .formats = TABLA_FORMATS,
3062 .rate_max = 48000,
3063 .rate_min = 8000,
3064 .channels_min = 1,
Kiran Kandi3426e512011-09-13 22:50:10 -07003065 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 },
3067 .ops = &tabla_dai_ops,
3068 },
3069 {
3070 .name = "tabla_tx1",
3071 .id = 2,
3072 .capture = {
3073 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003074 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003075 .formats = TABLA_FORMATS,
3076 .rate_max = 48000,
3077 .rate_min = 8000,
3078 .channels_min = 1,
3079 .channels_max = 2,
3080 },
3081 .ops = &tabla_dai_ops,
3082 },
3083};
Santosh Mardie15e2302011-11-15 10:39:23 +05303084
3085static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3086 {
3087 .name = "tabla_i2s_rx1",
3088 .id = 1,
3089 .playback = {
3090 .stream_name = "AIF1 Playback",
3091 .rates = WCD9310_RATES,
3092 .formats = TABLA_FORMATS,
3093 .rate_max = 48000,
3094 .rate_min = 8000,
3095 .channels_min = 1,
3096 .channels_max = 4,
3097 },
3098 .ops = &tabla_dai_ops,
3099 },
3100 {
3101 .name = "tabla_i2s_tx1",
3102 .id = 2,
3103 .capture = {
3104 .stream_name = "AIF1 Capture",
3105 .rates = WCD9310_RATES,
3106 .formats = TABLA_FORMATS,
3107 .rate_max = 48000,
3108 .rate_min = 8000,
3109 .channels_min = 1,
3110 .channels_max = 4,
3111 },
3112 .ops = &tabla_dai_ops,
3113 },
3114};
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003115static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003116{
3117 u8 bias_msb, bias_lsb;
3118 short bias_value;
3119
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003120 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
3121 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
3122 bias_value = (bias_msb << 8) | bias_lsb;
3123 return bias_value;
3124}
3125
3126static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
3127{
3128 u8 bias_msb, bias_lsb;
3129 short bias_value;
3130
3131 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
3132 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
3133 bias_value = (bias_msb << 8) | bias_lsb;
3134 return bias_value;
3135}
3136
Joonwoo Park0976d012011-12-22 11:48:18 -08003137static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003138{
Joonwoo Park0976d012011-12-22 11:48:18 -08003139 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003140 short bias_value;
3141
Joonwoo Park925914c2012-01-05 13:35:18 -08003142 /* Turn on the override */
3143 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003144 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003145 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3146 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
3147 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003148 usleep_range(tabla->mbhc_data.t_sta_dce,
3149 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003150 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08003151 usleep_range(tabla->mbhc_data.t_dce,
3152 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003153 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003154 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003155 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003156 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3157 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003158 usleep_range(tabla->mbhc_data.t_sta_dce,
3159 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08003160 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3161 usleep_range(tabla->mbhc_data.t_sta,
3162 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003163 bias_value = tabla_codec_read_sta_result(codec);
3164 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3165 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003166 }
Joonwoo Park925914c2012-01-05 13:35:18 -08003167 /* Turn off the override after measuring mic voltage */
3168 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003169
Bradley Rubincb1e2732011-06-23 16:49:20 -07003170 return bias_value;
3171}
3172
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003173static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003174{
3175 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003176 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003177 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003178
Joonwoo Park0976d012011-12-22 11:48:18 -08003179 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003180 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07003181 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003182 }
3183
3184 tabla->mbhc_polling_active = true;
3185
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003186 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003187 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003188 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003189 tabla_codec_enable_clock_block(codec, 1);
3190 }
3191
3192 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
3193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003194 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
3195
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003196 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08003197 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
3198 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07003199
Joonwoo Parkf4267c22012-01-10 13:25:24 -08003200 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003201
3202 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003203 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003204
3205 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
3206 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
3207 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
3208
3209 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003210 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3211 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003212
Joonwoo Park925914c2012-01-05 13:35:18 -08003213 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3215
Bradley Rubincb1e2732011-06-23 16:49:20 -07003216 tabla_codec_calibrate_hs_polling(codec);
3217
Joonwoo Park0976d012011-12-22 11:48:18 -08003218 bias_value = tabla_codec_sta_dce(codec, 0);
3219 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3220 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003221 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003222
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003223 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003224}
3225
3226static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
3227 int insertion)
3228{
3229 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003230 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08003231 const struct tabla_mbhc_general_cfg *generic =
3232 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3233 const struct tabla_mbhc_plug_detect_cfg *plug_det =
3234 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003235 u8 wg_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003236
Joonwoo Park0976d012011-12-22 11:48:18 -08003237 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003238 pr_err("Error, no tabla calibration\n");
3239 return -EINVAL;
3240 }
3241
3242 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
3243
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003244 if (insertion) {
3245 /* Make sure mic bias and Mic line schmitt trigger
3246 * are turned OFF
3247 */
3248 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
3249 0x81, 0x01);
3250 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3251 0x90, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003252 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
3253 wg_time += 1;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003254
3255 /* Enable HPH Schmitt Trigger */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003256 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003257 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
Joonwoo Park0976d012011-12-22 11:48:18 -08003258 plug_det->hph_current << 2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003259
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003260 /* Turn off HPH PAs and DAC's during insertion detection to
3261 * avoid false insertion interrupts
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003262 */
3263 if (tabla->mbhc_micbias_switched)
3264 tabla_codec_switch_micbias(codec, 0);
3265 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003266 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003267 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003268 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003269 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003270 usleep_range(wg_time * 1000, wg_time * 1000);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003271
3272 /* setup for insetion detection */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003273 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003274 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003275 } else {
3276 /* Make sure the HPH schmitt trigger is OFF */
3277 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3278
3279 /* enable the mic line schmitt trigger */
3280 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08003281 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003282 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3283 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003284 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003285 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3286 0x10, 0x10);
3287
3288 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003290 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003291
3292 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
3293 if (!(tabla->clock_active)) {
3294 tabla_codec_enable_config_mode(codec, 1);
3295 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003296 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08003297 usleep_range(generic->t_shutdown_plug_rem,
3298 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003299 tabla_codec_enable_config_mode(codec, 0);
3300 } else
3301 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003302 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003303 }
3304
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003305 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003306
3307 /* If central bandgap disabled */
3308 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
3309 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08003310 usleep_range(generic->t_bg_fast_settle,
3311 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003312 central_bias_enabled = 1;
3313 }
3314
3315 /* If LDO_H disabled */
3316 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
3317 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
3318 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003319 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003320 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
3321
3322 if (central_bias_enabled)
3323 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
3324 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003325
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003326 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
3327 tabla->micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003328
3329 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3330 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3331 return 0;
3332}
3333
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003334static void tabla_lock_sleep(struct tabla_priv *tabla)
3335{
3336 int ret;
3337 while (!(ret = wait_event_timeout(tabla->pm_wq,
3338 atomic_inc_not_zero(&tabla->pm_cnt),
3339 2 * HZ))) {
3340 pr_err("%s: didn't wake up for 2000ms (%d), pm_cnt %d\n",
3341 __func__, ret, atomic_read(&tabla->pm_cnt));
3342 WARN_ON_ONCE(1);
3343 }
3344}
3345
3346static void tabla_unlock_sleep(struct tabla_priv *tabla)
3347{
3348 atomic_dec(&tabla->pm_cnt);
3349 wake_up(&tabla->pm_wq);
3350}
3351
Joonwoo Park0976d012011-12-22 11:48:18 -08003352static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
3353 s16 vin_mv)
3354{
3355 short diff, zero;
3356 struct tabla_priv *tabla;
3357 u32 mb_mv, in;
3358
3359 tabla = snd_soc_codec_get_drvdata(codec);
3360 mb_mv = tabla->mbhc_data.micb_mv;
3361
3362 if (mb_mv == 0) {
3363 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
3364 return -EINVAL;
3365 }
3366
3367 if (dce) {
3368 diff = tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z;
3369 zero = tabla->mbhc_data.dce_z;
3370 } else {
3371 diff = tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z;
3372 zero = tabla->mbhc_data.sta_z;
3373 }
3374 in = (u32) diff * vin_mv;
3375
3376 return (u16) (in / mb_mv) + zero;
3377}
3378
3379static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
3380 u16 bias_value)
3381{
3382 struct tabla_priv *tabla;
3383 s32 mv;
3384
3385 tabla = snd_soc_codec_get_drvdata(codec);
3386
3387 if (dce) {
3388 mv = ((s32)bias_value - (s32)tabla->mbhc_data.dce_z) *
3389 (s32)tabla->mbhc_data.micb_mv /
3390 (s32)(tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z);
3391 } else {
3392 mv = ((s32)bias_value - (s32)tabla->mbhc_data.sta_z) *
3393 (s32)tabla->mbhc_data.micb_mv /
3394 (s32)(tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z);
3395 }
3396
3397 return mv;
3398}
3399
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003400static void btn0_lpress_fn(struct work_struct *work)
3401{
3402 struct delayed_work *delayed_work;
3403 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08003404 short bias_value;
3405 int dce_mv, sta_mv;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003406
3407 pr_debug("%s:\n", __func__);
3408
3409 delayed_work = to_delayed_work(work);
3410 tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
3411
3412 if (tabla) {
3413 if (tabla->button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003414 bias_value = tabla_codec_read_sta_result(tabla->codec);
3415 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
3416 bias_value);
3417 bias_value = tabla_codec_read_dce_result(tabla->codec);
3418 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
3419 bias_value);
3420 pr_debug("%s: Reporting long button press event"
3421 " STA: %d, DCE: %d\n", __func__,
3422 sta_mv, dce_mv);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003423 tabla_snd_soc_jack_report(tabla, tabla->button_jack,
3424 SND_JACK_BTN_0,
3425 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003426 }
3427 } else {
3428 pr_err("%s: Bad tabla private data\n", __func__);
3429 }
3430
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003431 tabla_unlock_sleep(tabla);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003432}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003433
Joonwoo Park0976d012011-12-22 11:48:18 -08003434void tabla_mbhc_cal(struct snd_soc_codec *codec)
3435{
3436 struct tabla_priv *tabla;
3437 struct tabla_mbhc_btn_detect_cfg *btn_det;
3438 u8 cfilt_mode, bg_mode;
3439 u8 ncic, nmeas, navg;
3440 u32 mclk_rate;
3441 u32 dce_wait, sta_wait;
3442 u8 *n_cic;
3443
3444 tabla = snd_soc_codec_get_drvdata(codec);
3445
3446 /* First compute the DCE / STA wait times
3447 * depending on tunable parameters.
3448 * The value is computed in microseconds
3449 */
3450 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3451 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003452 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Park0976d012011-12-22 11:48:18 -08003453 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
3454 navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
3455 mclk_rate = tabla->mclk_freq;
Joonwoo Park433149a2012-01-11 09:53:54 -08003456 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
3457 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08003458
3459 tabla->mbhc_data.t_dce = dce_wait;
3460 tabla->mbhc_data.t_sta = sta_wait;
3461
3462 /* LDOH and CFILT are already configured during pdata handling.
3463 * Only need to make sure CFILT and bandgap are in Fast mode.
3464 * Need to restore defaults once calculation is done.
3465 */
3466 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
3467 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
3468 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
3469 0x02);
3470
3471 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
3472 * to perform ADC calibration
3473 */
3474 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
3475 tabla->micbias << 5);
3476 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
3477 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
3478 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
3479 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
3480
3481 /* DCE measurement for 0 volts */
3482 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3483 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3484 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08003485 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
3486 usleep_range(100, 100);
3487 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3488 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3489 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
3490
3491 /* DCE measurment for MB voltage */
3492 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3493 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3494 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3495 usleep_range(100, 100);
3496 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3497 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3498 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
3499
3500 /* Sta measuremnt for 0 volts */
3501 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3502 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3503 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08003504 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
3505 usleep_range(100, 100);
3506 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3507 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
3508 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
3509
3510 /* STA Measurement for MB Voltage */
3511 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3512 usleep_range(100, 100);
3513 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3514 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
3515 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
3516
3517 /* Restore default settings. */
3518 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3519 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3520 cfilt_mode);
3521 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
3522
3523 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
3524 usleep_range(100, 100);
3525}
3526
3527void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
3528 const enum tabla_mbhc_btn_det_mem mem)
3529{
3530 void *ret = &btn_det->_v_btn_low;
3531
3532 switch (mem) {
3533 case TABLA_BTN_DET_GAIN:
3534 ret += sizeof(btn_det->_n_cic);
3535 case TABLA_BTN_DET_N_CIC:
3536 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08003537 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08003538 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
3539 case TABLA_BTN_DET_V_BTN_HIGH:
3540 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
3541 case TABLA_BTN_DET_V_BTN_LOW:
3542 /* do nothing */
3543 break;
3544 default:
3545 ret = NULL;
3546 }
3547
3548 return ret;
3549}
3550
3551static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
3552{
3553 struct tabla_priv *tabla;
3554 s16 btn_mv = 0, btn_delta_mv;
3555 struct tabla_mbhc_btn_detect_cfg *btn_det;
3556 struct tabla_mbhc_plug_type_cfg *plug_type;
3557 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08003558 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08003559 int i;
3560
3561 tabla = snd_soc_codec_get_drvdata(codec);
3562 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3563 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
3564
Joonwoo Parkc0672392012-01-11 11:03:14 -08003565 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003566 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003567 tabla->mbhc_data.npoll = 9;
3568 tabla->mbhc_data.nbounce_wait = 30;
3569 } else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003570 tabla->mbhc_data.npoll = 7;
3571 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08003572 }
Joonwoo Park0976d012011-12-22 11:48:18 -08003573
Joonwoo Park433149a2012-01-11 09:53:54 -08003574 tabla->mbhc_data.t_sta_dce = ((1000 * 256) / (tabla->mclk_freq / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08003575 n_ready[tabla_codec_mclk_index(tabla)]) +
3576 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08003577 tabla->mbhc_data.v_ins_hu =
3578 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
3579 tabla->mbhc_data.v_ins_h =
3580 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
3581
3582 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
3583 for (i = 0; i < btn_det->num_btn; i++)
3584 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
3585
3586 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
3587 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
3588
3589 tabla->mbhc_data.v_b1_hu =
3590 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
3591
3592 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
3593
3594 tabla->mbhc_data.v_b1_huc =
3595 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
3596
3597 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
3598 tabla->mbhc_data.v_brl = 0xFA55;
3599
3600 tabla->mbhc_data.v_no_mic =
3601 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
3602}
3603
3604void tabla_mbhc_init(struct snd_soc_codec *codec)
3605{
3606 struct tabla_priv *tabla;
3607 struct tabla_mbhc_general_cfg *generic;
3608 struct tabla_mbhc_btn_detect_cfg *btn_det;
3609 int n;
3610 u8 tabla_ver;
3611 u8 *n_cic, *gain;
3612
3613 tabla = snd_soc_codec_get_drvdata(codec);
3614 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3615 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3616
3617 tabla_ver = snd_soc_read(codec, TABLA_A_CHIP_VERSION);
3618 tabla_ver &= 0x1F;
3619
3620 for (n = 0; n < 8; n++) {
3621 if ((tabla_ver != TABLA_VERSION_1_0 &&
3622 tabla_ver != TABLA_VERSION_1_1) || n != 7) {
3623 snd_soc_update_bits(codec,
3624 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
3625 0x07, n);
3626 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
3627 btn_det->c[n]);
3628 }
3629 }
3630 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
3631 btn_det->nc);
3632
3633 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
3634 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08003635 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003636
3637 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08003638 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
3639 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08003640
3641 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
3642 generic->mbhc_nsa << 4);
3643
3644 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
3645 btn_det->n_meas);
3646
3647 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
3648
3649 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
3650
3651 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
3652 btn_det->mbhc_nsc << 3);
3653
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003654 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
3655 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08003656
3657 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
3658}
3659
Patrick Lai64b43262011-12-06 17:29:15 -08003660static bool tabla_mbhc_fw_validate(const struct firmware *fw)
3661{
3662 u32 cfg_offset;
3663 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
3664 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
3665
3666 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
3667 return false;
3668
3669 /* previous check guarantees that there is enough fw data up
3670 * to num_btn
3671 */
3672 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
3673 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
3674 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
3675 return false;
3676
3677 /* previous check guarantees that there is enough fw data up
3678 * to start of impedance detection configuration
3679 */
3680 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
3681 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
3682
3683 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
3684 return false;
3685
3686 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
3687 return false;
3688
3689 return true;
3690}
3691static void mbhc_fw_read(struct work_struct *work)
3692{
3693 struct delayed_work *dwork;
3694 struct tabla_priv *tabla;
3695 struct snd_soc_codec *codec;
3696 const struct firmware *fw;
3697 int ret = -1, retry = 0, rc;
3698
3699 dwork = to_delayed_work(work);
3700 tabla = container_of(dwork, struct tabla_priv,
3701 mbhc_firmware_dwork);
3702 codec = tabla->codec;
3703
3704 while (retry < MBHC_FW_READ_ATTEMPTS) {
3705 retry++;
3706 pr_info("%s:Attempt %d to request MBHC firmware\n",
3707 __func__, retry);
3708 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
3709 codec->dev);
3710
3711 if (ret != 0) {
3712 usleep_range(MBHC_FW_READ_TIMEOUT,
3713 MBHC_FW_READ_TIMEOUT);
3714 } else {
3715 pr_info("%s: MBHC Firmware read succesful\n", __func__);
3716 break;
3717 }
3718 }
3719
3720 if (ret != 0) {
3721 pr_err("%s: Cannot load MBHC firmware use default cal\n",
3722 __func__);
3723 } else if (tabla_mbhc_fw_validate(fw) == false) {
3724 pr_err("%s: Invalid MBHC cal data size use default cal\n",
3725 __func__);
3726 release_firmware(fw);
3727 } else {
3728 tabla->calibration = (void *)fw->data;
3729 tabla->mbhc_fw = fw;
3730 }
3731
3732 tabla->mclk_cb(codec, 1);
3733 tabla_mbhc_init(codec);
3734 tabla_mbhc_cal(codec);
3735 tabla_mbhc_calc_thres(codec);
3736 tabla->mclk_cb(codec, 0);
3737 tabla_codec_calibrate_hs_polling(codec);
3738 rc = tabla_codec_enable_hs_detect(codec, 1);
3739
3740 if (IS_ERR_VALUE(rc))
3741 pr_err("%s: Failed to setup MBHC detection\n", __func__);
3742
3743}
3744
Bradley Rubincb1e2732011-06-23 16:49:20 -07003745int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park0976d012011-12-22 11:48:18 -08003746 struct snd_soc_jack *headset_jack,
3747 struct snd_soc_jack *button_jack,
3748 void *calibration, enum tabla_micbias_num micbias,
3749 int (*mclk_cb_fn) (struct snd_soc_codec*, int),
3750 int read_fw_bin, u32 mclk_rate)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003751{
3752 struct tabla_priv *tabla;
Patrick Lai64b43262011-12-06 17:29:15 -08003753 int rc = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07003754
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003755 if (!codec || !calibration) {
3756 pr_err("Error: no codec or calibration\n");
3757 return -EINVAL;
3758 }
Joonwoo Park107edf02012-01-11 11:42:24 -08003759
3760 if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
3761 if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
3762 pr_err("Error: clock rate %dHz is not yet supported\n",
3763 mclk_rate);
3764 else
3765 pr_err("Error: unsupported clock rate %d\n", mclk_rate);
3766 return -EINVAL;
3767 }
3768
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003769 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003770 tabla->headset_jack = headset_jack;
3771 tabla->button_jack = button_jack;
Joonwoo Park0976d012011-12-22 11:48:18 -08003772 tabla->micbias = micbias;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003773 tabla->calibration = calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08003774 tabla->mclk_cb = mclk_cb_fn;
3775 tabla->mclk_freq = mclk_rate;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003776 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003777
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003778 /* Put CFILT in fast mode by default */
3779 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
3780 0x40, TABLA_CFILT_FAST_MODE);
Patrick Lai64b43262011-12-06 17:29:15 -08003781 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003782 INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
Patrick Lai49efeac2011-11-03 11:01:12 -07003783 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
3784 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
Joonwoo Park0976d012011-12-22 11:48:18 -08003785
3786 if (!read_fw_bin) {
3787 tabla->mclk_cb(codec, 1);
3788 tabla_mbhc_init(codec);
3789 tabla_mbhc_cal(codec);
3790 tabla_mbhc_calc_thres(codec);
3791 tabla->mclk_cb(codec, 0);
3792 tabla_codec_calibrate_hs_polling(codec);
3793 rc = tabla_codec_enable_hs_detect(codec, 1);
3794 } else {
Patrick Lai64b43262011-12-06 17:29:15 -08003795 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
3796 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Joonwoo Park0976d012011-12-22 11:48:18 -08003797 }
Patrick Lai49efeac2011-11-03 11:01:12 -07003798
3799 if (!IS_ERR_VALUE(rc)) {
3800 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3801 0x10);
3802 tabla_enable_irq(codec->control_data,
3803 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3804 tabla_enable_irq(codec->control_data,
3805 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3806 }
3807
3808 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003809}
3810EXPORT_SYMBOL_GPL(tabla_hs_detect);
3811
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003812static int tabla_determine_button(const struct tabla_priv *priv,
3813 const s32 bias_mv)
3814{
3815 s16 *v_btn_low, *v_btn_high;
3816 struct tabla_mbhc_btn_detect_cfg *btn_det;
3817 int i, btn = -1;
3818
3819 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
3820 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
3821 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
3822 TABLA_BTN_DET_V_BTN_HIGH);
3823 for (i = 0; i < btn_det->num_btn; i++) {
3824 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
3825 btn = i;
3826 break;
3827 }
3828 }
3829
3830 if (btn == -1)
3831 pr_debug("%s: couldn't find button number for mic mv %d\n",
3832 __func__, bias_mv);
3833
3834 return btn;
3835}
3836
3837static int tabla_get_button_mask(const int btn)
3838{
3839 int mask = 0;
3840 switch (btn) {
3841 case 0:
3842 mask = SND_JACK_BTN_0;
3843 break;
3844 case 1:
3845 mask = SND_JACK_BTN_1;
3846 break;
3847 case 2:
3848 mask = SND_JACK_BTN_2;
3849 break;
3850 case 3:
3851 mask = SND_JACK_BTN_3;
3852 break;
3853 case 4:
3854 mask = SND_JACK_BTN_4;
3855 break;
3856 case 5:
3857 mask = SND_JACK_BTN_5;
3858 break;
3859 case 6:
3860 mask = SND_JACK_BTN_6;
3861 break;
3862 case 7:
3863 mask = SND_JACK_BTN_7;
3864 break;
3865 }
3866 return mask;
3867}
3868
Bradley Rubincb1e2732011-06-23 16:49:20 -07003869static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003870{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003871 int i, mask;
3872 short bias_value_dce;
3873 s32 bias_mv_dce;
3874 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003875 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003876 const struct tabla_mbhc_btn_detect_cfg *d =
3877 TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
3878 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003879 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07003880
3881 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
3882 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003883 tabla_lock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003884
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003885 bias_value_dce = tabla_codec_read_dce_result(codec);
3886 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003887
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003888 /* determine pressed button */
3889 btnmeas[meas++] = tabla_determine_button(priv, bias_mv_dce);
3890 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
3891 meas - 1, bias_value_dce, bias_mv_dce, btnmeas[meas - 1]);
3892 if (d->n_btn_meas == 0)
3893 btn = btnmeas[0];
3894 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
3895 bias_value_dce = tabla_codec_sta_dce(codec, 1);
3896 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
3897 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
3898 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
3899 __func__, meas, bias_value_dce, bias_mv_dce,
3900 btnmeas[meas]);
3901 /* if large enough measurements are collected,
3902 * start to check if last all n_btn_con measurements were
3903 * in same button low/high range */
3904 if (meas + 1 >= d->n_btn_con) {
3905 for (i = 0; i < d->n_btn_con; i++)
3906 if ((btnmeas[meas] < 0) ||
3907 (btnmeas[meas] != btnmeas[meas - i]))
3908 break;
3909 if (i == d->n_btn_con) {
3910 /* button pressed */
3911 btn = btnmeas[meas];
3912 break;
3913 }
3914 }
3915 /* if left measurements are less than n_btn_con,
3916 * it's impossible to find button number */
3917 if ((d->n_btn_meas - meas) < d->n_btn_con)
3918 break;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003919 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003920
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003921 if (btn >= 0) {
3922 mask = tabla_get_button_mask(btn);
3923 priv->buttons_pressed |= mask;
3924
3925 msleep(100);
3926
3927 /* XXX: assuming button 0 has the lowest micbias voltage */
3928 if (btn == 0) {
3929 if (schedule_delayed_work(&priv->btn0_dwork,
3930 msecs_to_jiffies(400)) == 0) {
3931 WARN(1, "Button pressed twice without release"
3932 "event\n");
3933 tabla_unlock_sleep(priv);
3934 }
3935 } else {
3936 pr_debug("%s: Reporting short button %d(0x%x) press\n",
3937 __func__, btn, mask);
3938 tabla_snd_soc_jack_report(priv, priv->button_jack, mask,
3939 mask);
3940 }
3941 } else
3942 pr_debug("%s: bogus button press, too short press?\n",
3943 __func__);
3944
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003945 return IRQ_HANDLED;
3946}
3947
Bradley Rubincb1e2732011-06-23 16:49:20 -07003948static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003949{
3950 struct tabla_priv *priv = data;
3951 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08003952 int ret;
3953 short mb_v;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003954
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003955 pr_debug("%s: enter\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07003956 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003957 tabla_lock_sleep(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003958
Bradley Rubincb1e2732011-06-23 16:49:20 -07003959 if (priv->buttons_pressed & SND_JACK_BTN_0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003960 ret = cancel_delayed_work(&priv->btn0_dwork);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003961 if (ret == 0) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003962 pr_debug("%s: Reporting long button 0 release event\n",
3963 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08003964 if (priv->button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003965 tabla_snd_soc_jack_report(priv,
3966 priv->button_jack, 0,
3967 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003968 } else {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003969 /* if scheduled btn0_dwork is canceled from here,
3970 * we have to unlock from here instead btn0_work */
3971 tabla_unlock_sleep(priv);
Joonwoo Park0976d012011-12-22 11:48:18 -08003972 mb_v = tabla_codec_sta_dce(codec, 0);
3973 pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
3974 __func__, mb_v,
3975 tabla_codec_sta_dce_v(codec, 0, mb_v));
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003976
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08003977 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
3978 mb_v > (short)priv->mbhc_data.v_ins_hu)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003979 pr_debug("%s: Fake buttton press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003980 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08003981 else if (priv->button_jack) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003982 pr_debug("%s: Reporting short button 0 "
Joonwoo Park0976d012011-12-22 11:48:18 -08003983 "press and release\n", __func__);
3984 tabla_snd_soc_jack_report(priv,
3985 priv->button_jack,
3986 SND_JACK_BTN_0,
3987 SND_JACK_BTN_0);
3988 tabla_snd_soc_jack_report(priv,
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003989 priv->button_jack, 0,
3990 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003991 }
3992 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003993
Bradley Rubincb1e2732011-06-23 16:49:20 -07003994 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003995 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003996
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003997 if (priv->buttons_pressed) {
3998 pr_debug("%s:reporting button release mask 0x%x\n", __func__,
3999 priv->buttons_pressed);
4000 tabla_snd_soc_jack_report(priv, priv->button_jack, 0,
4001 priv->buttons_pressed);
4002 /* hardware doesn't detect another button press until
4003 * already pressed button is released.
4004 * therefore buttons_pressed has only one button's mask. */
4005 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
4006 }
4007
Bradley Rubin688c66a2011-08-16 12:25:13 -07004008 tabla_codec_start_hs_polling(codec);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004009 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010 return IRQ_HANDLED;
4011}
4012
Bradley Rubincb1e2732011-06-23 16:49:20 -07004013static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
4014{
4015 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08004016 const struct tabla_mbhc_general_cfg *generic =
4017 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004018
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004019 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004020 tabla_codec_enable_config_mode(codec, 1);
4021
4022 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
4023 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004024
Joonwoo Park0976d012011-12-22 11:48:18 -08004025 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
4026
4027 usleep_range(generic->t_shutdown_plug_rem,
4028 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004029
4030 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004031 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004032 tabla_codec_enable_config_mode(codec, 0);
4033
4034 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
4035}
4036
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004037static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
4038{
4039 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004040
4041 tabla_codec_shutdown_hs_removal_detect(codec);
4042
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004043 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004044 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05304045 tabla_codec_disable_clock_block(codec);
4046 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004047 }
4048
4049 tabla->mbhc_polling_active = false;
4050}
4051
Patrick Lai49efeac2011-11-03 11:01:12 -07004052static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
4053{
4054 struct tabla_priv *tabla = data;
4055 struct snd_soc_codec *codec;
4056
4057 pr_info("%s: received HPHL OCP irq\n", __func__);
4058
4059 if (tabla) {
4060 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004061 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
4062 pr_info("%s: retry\n", __func__);
4063 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4064 0x00);
4065 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4066 0x10);
4067 } else {
4068 tabla_disable_irq(codec->control_data,
4069 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4070 tabla->hphlocp_cnt = 0;
4071 tabla->hph_status |= SND_JACK_OC_HPHL;
4072 if (tabla->headset_jack)
4073 tabla_snd_soc_jack_report(tabla,
4074 tabla->headset_jack,
4075 tabla->hph_status,
4076 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07004077 }
4078 } else {
4079 pr_err("%s: Bad tabla private data\n", __func__);
4080 }
4081
4082 return IRQ_HANDLED;
4083}
4084
4085static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
4086{
4087 struct tabla_priv *tabla = data;
4088 struct snd_soc_codec *codec;
4089
4090 pr_info("%s: received HPHR OCP irq\n", __func__);
4091
4092 if (tabla) {
4093 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004094 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
4095 pr_info("%s: retry\n", __func__);
4096 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4097 0x00);
4098 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4099 0x10);
4100 } else {
4101 tabla_disable_irq(codec->control_data,
4102 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4103 tabla->hphrocp_cnt = 0;
4104 tabla->hph_status |= SND_JACK_OC_HPHR;
4105 if (tabla->headset_jack)
4106 tabla_snd_soc_jack_report(tabla,
4107 tabla->headset_jack,
4108 tabla->hph_status,
4109 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07004110 }
4111 } else {
4112 pr_err("%s: Bad tabla private data\n", __func__);
4113 }
4114
4115 return IRQ_HANDLED;
4116}
4117
Joonwoo Parka9444452011-12-08 18:48:27 -08004118static void tabla_sync_hph_state(struct tabla_priv *tabla)
4119{
4120 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4121 &tabla->hph_pa_dac_state)) {
4122 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4123 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4124 1 << 4);
4125 }
4126 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4127 &tabla->hph_pa_dac_state)) {
4128 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4129 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4130 1 << 5);
4131 }
4132
4133 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4134 &tabla->hph_pa_dac_state)) {
4135 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4136 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4137 0xC0, 0xC0);
4138 }
4139 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4140 &tabla->hph_pa_dac_state)) {
4141 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4142 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4143 0xC0, 0xC0);
4144 }
4145}
4146
Bradley Rubincb1e2732011-06-23 16:49:20 -07004147static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
4148{
4149 struct tabla_priv *priv = data;
4150 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08004151 const struct tabla_mbhc_plug_detect_cfg *plug_det =
4152 TABLA_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
Bradley Rubin355611a2011-08-24 14:01:18 -07004153 int ldo_h_on, micb_cfilt_on;
Joonwoo Park0976d012011-12-22 11:48:18 -08004154 short mb_v;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004155 u8 is_removal;
Joonwoo Park0976d012011-12-22 11:48:18 -08004156 int mic_mv;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004157
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004158 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004159 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004160 tabla_lock_sleep(priv);
4161
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004162 is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
4163 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
4164
4165 /* Turn off both HPH and MIC line schmitt triggers */
Joonwoo Park0976d012011-12-22 11:48:18 -08004166 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004167 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004168
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004169 if (priv->mbhc_fake_ins_start &&
4170 time_after(jiffies, priv->mbhc_fake_ins_start +
4171 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004172 pr_debug("%s: fake context interrupt, reset insertion\n",
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004173 __func__);
4174 priv->mbhc_fake_ins_start = 0;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004175 tabla_codec_shutdown_hs_polling(codec);
4176 tabla_codec_enable_hs_detect(codec, 1);
4177 return IRQ_HANDLED;
4178 }
4179
Bradley Rubin355611a2011-08-24 14:01:18 -07004180 ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
Joonwoo Park0976d012011-12-22 11:48:18 -08004181 micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
4182 & 0x80;
Bradley Rubin355611a2011-08-24 14:01:18 -07004183
4184 if (!ldo_h_on)
4185 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
4186 if (!micb_cfilt_on)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004187 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08004188 0x80, 0x80);
4189 if (plug_det->t_ins_complete > 20)
4190 msleep(plug_det->t_ins_complete);
4191 else
4192 usleep_range(plug_det->t_ins_complete * 1000,
4193 plug_det->t_ins_complete * 1000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004194
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004195 if (!ldo_h_on)
4196 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
4197 if (!micb_cfilt_on)
4198 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08004199 0x80, 0x0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004200
4201 if (is_removal) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004202 /*
4203 * If headphone is removed while playback is in progress,
4204 * it is possible that micbias will be switched to VDDIO.
4205 */
4206 if (priv->mbhc_micbias_switched)
4207 tabla_codec_switch_micbias(codec, 0);
Patrick Lai72aa4da2011-12-08 12:38:18 -08004208 priv->hph_status &= ~SND_JACK_HEADPHONE;
Joonwoo Parka9444452011-12-08 18:48:27 -08004209
4210 /* If headphone PA is on, check if userspace receives
4211 * removal event to sync-up PA's state */
4212 if (tabla_is_hph_pa_on(codec)) {
4213 set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
4214 set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
4215 }
4216
4217 if (tabla_is_hph_dac_on(codec, 1))
4218 set_bit(TABLA_HPHL_DAC_OFF_ACK,
4219 &priv->hph_pa_dac_state);
4220 if (tabla_is_hph_dac_on(codec, 0))
4221 set_bit(TABLA_HPHR_DAC_OFF_ACK,
4222 &priv->hph_pa_dac_state);
4223
Bradley Rubincb1e2732011-06-23 16:49:20 -07004224 if (priv->headset_jack) {
4225 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004226 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4227 priv->hph_status,
4228 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004229 }
4230 tabla_codec_shutdown_hs_removal_detect(codec);
4231 tabla_codec_enable_hs_detect(codec, 1);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004232 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004233 return IRQ_HANDLED;
4234 }
4235
Joonwoo Park0976d012011-12-22 11:48:18 -08004236 mb_v = tabla_codec_setup_hs_polling(codec);
4237 mic_mv = tabla_codec_sta_dce_v(codec, 0, mb_v);
Bradley Rubin355611a2011-08-24 14:01:18 -07004238
Joonwoo Park0976d012011-12-22 11:48:18 -08004239 if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004240 pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
4241 "STA : %d,%d\n", __func__,
4242 (priv->mbhc_fake_ins_start ?
4243 jiffies_to_msecs(jiffies -
4244 priv->mbhc_fake_ins_start) :
4245 0),
4246 mb_v, mic_mv);
4247 if (time_after(jiffies,
4248 priv->mbhc_fake_ins_start +
4249 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
4250 /* Disable HPH trigger and enable MIC line trigger */
4251 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
4252 0x00);
4253 snd_soc_update_bits(codec,
4254 priv->mbhc_bias_regs.mbhc_reg, 0x60,
4255 plug_det->mic_current << 5);
4256 snd_soc_update_bits(codec,
4257 priv->mbhc_bias_regs.mbhc_reg,
4258 0x80, 0x80);
4259 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4260 snd_soc_update_bits(codec,
4261 priv->mbhc_bias_regs.mbhc_reg,
4262 0x10, 0x10);
4263 } else {
4264 if (priv->mbhc_fake_ins_start == 0)
4265 priv->mbhc_fake_ins_start = jiffies;
4266 /* Setup normal insert detection
4267 * Enable HPH Schmitt Trigger
4268 */
4269 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH,
4270 0x13 | 0x0C,
4271 0x13 | plug_det->hph_current << 2);
4272 }
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004273 /* Setup for insertion detection */
4274 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004275 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4276 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4277
Joonwoo Park0976d012011-12-22 11:48:18 -08004278 } else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
4279 pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
4280 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004281 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07004282 priv->hph_status |= SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004283 if (priv->headset_jack) {
4284 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08004285 SND_JACK_HEADPHONE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004286 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4287 priv->hph_status,
4288 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004289 }
4290 tabla_codec_shutdown_hs_polling(codec);
4291 tabla_codec_enable_hs_detect(codec, 0);
Joonwoo Parka9444452011-12-08 18:48:27 -08004292 tabla_sync_hph_state(priv);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004293 } else {
Joonwoo Park0976d012011-12-22 11:48:18 -08004294 pr_debug("%s: Headset detected, mb_v: %d,%d\n",
4295 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004296 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07004297 priv->hph_status |= SND_JACK_HEADSET;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004298 if (priv->headset_jack) {
4299 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08004300 SND_JACK_HEADSET);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004301 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4302 priv->hph_status,
4303 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004304 }
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004305 /* avoid false button press detect */
4306 msleep(50);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004307 tabla_codec_start_hs_polling(codec);
Joonwoo Parka9444452011-12-08 18:48:27 -08004308 tabla_sync_hph_state(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004309 }
4310
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004311 tabla_unlock_sleep(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004312 return IRQ_HANDLED;
4313}
4314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004315static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
4316{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004317 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004318 struct tabla_priv *priv = data;
4319 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08004320 const struct tabla_mbhc_general_cfg *generic =
4321 TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004322 int fake_removal = 0;
4323 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004324
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004325 pr_debug("%s: enter, removal interrupt\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004326 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4327 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004328 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004329 tabla_lock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004330
Joonwoo Park0976d012011-12-22 11:48:18 -08004331 usleep_range(generic->t_shutdown_plug_rem,
4332 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004333
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004334 do {
4335 bias_value = tabla_codec_sta_dce(codec, 1);
4336 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
4337 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
4338 if (bias_value < (short)priv->mbhc_data.v_ins_h) {
4339 fake_removal = 1;
4340 break;
4341 }
4342 min_us -= priv->mbhc_data.t_dce;
4343 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004344
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004345 if (fake_removal) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004346 pr_debug("False alarm, headset not actually removed\n");
4347 tabla_codec_start_hs_polling(codec);
4348 } else {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004349 /*
4350 * If this removal is not false, first check the micbias
4351 * switch status and switch it to LDOH if it is already
4352 * switched to VDDIO.
4353 */
4354 if (priv->mbhc_micbias_switched)
4355 tabla_codec_switch_micbias(codec, 0);
Patrick Lai49efeac2011-11-03 11:01:12 -07004356 priv->hph_status &= ~SND_JACK_HEADSET;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004357 if (priv->headset_jack) {
4358 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004359 tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
4360 TABLA_JACK_MASK);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004361 }
4362 tabla_codec_shutdown_hs_polling(codec);
4363
4364 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004365 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004366
4367 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004368 return IRQ_HANDLED;
4369}
4370
4371static unsigned long slimbus_value;
4372
4373static irqreturn_t tabla_slimbus_irq(int irq, void *data)
4374{
4375 struct tabla_priv *priv = data;
4376 struct snd_soc_codec *codec = priv->codec;
4377 int i, j;
4378 u8 val;
4379
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004380 tabla_lock_sleep(priv);
4381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004382 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
4383 slimbus_value = tabla_interface_reg_read(codec->control_data,
4384 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
4385 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
4386 val = tabla_interface_reg_read(codec->control_data,
4387 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
4388 if (val & 0x1)
4389 pr_err_ratelimited("overflow error on port %x,"
4390 " value %x\n", i*8 + j, val);
4391 if (val & 0x2)
4392 pr_err_ratelimited("underflow error on port %x,"
4393 " value %x\n", i*8 + j, val);
4394 }
4395 tabla_interface_reg_write(codec->control_data,
4396 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
4397 }
4398
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004399 tabla_unlock_sleep(priv);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004400 return IRQ_HANDLED;
4401}
4402
Patrick Lai3043fba2011-08-01 14:15:57 -07004403
4404static int tabla_handle_pdata(struct tabla_priv *tabla)
4405{
4406 struct snd_soc_codec *codec = tabla->codec;
4407 struct tabla_pdata *pdata = tabla->pdata;
4408 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05304409 u8 leg_mode = pdata->amic_settings.legacy_mode;
4410 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4411 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4412 u8 flag = pdata->amic_settings.use_pdata;
4413 u8 i = 0, j = 0;
4414 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07004415
4416 if (!pdata) {
4417 rc = -ENODEV;
4418 goto done;
4419 }
4420
4421 /* Make sure settings are correct */
4422 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
4423 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
4424 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
4425 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
4426 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
4427 rc = -EINVAL;
4428 goto done;
4429 }
4430
4431 /* figure out k value */
4432 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
4433 pdata->micbias.cfilt1_mv);
4434 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
4435 pdata->micbias.cfilt2_mv);
4436 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
4437 pdata->micbias.cfilt3_mv);
4438
4439 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
4440 rc = -EINVAL;
4441 goto done;
4442 }
4443
4444 /* Set voltage level and always use LDO */
4445 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
4446 (pdata->micbias.ldoh_v << 2));
4447
4448 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
4449 (k1 << 2));
4450 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
4451 (k2 << 2));
4452 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
4453 (k3 << 2));
4454
4455 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
4456 (pdata->micbias.bias1_cfilt_sel << 5));
4457 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
4458 (pdata->micbias.bias2_cfilt_sel << 5));
4459 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
4460 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004461 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
4462 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07004463
Santosh Mardi22920282011-10-26 02:38:40 +05304464 for (i = 0; i < 6; j++, i += 2) {
4465 if (flag & (0x01 << i)) {
4466 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
4467 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4468 val_txfe = val_txfe |
4469 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4470 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4471 0x10, value);
4472 snd_soc_update_bits(codec,
4473 TABLA_A_TX_1_2_TEST_EN + j * 10,
4474 0x30, val_txfe);
4475 }
4476 if (flag & (0x01 << (i + 1))) {
4477 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
4478 val_txfe = (txfe_bypass &
4479 (0x01 << (i + 1))) ? 0x02 : 0x00;
4480 val_txfe |= (txfe_buff &
4481 (0x01 << (i + 1))) ? 0x01 : 0x00;
4482 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4483 0x01, value);
4484 snd_soc_update_bits(codec,
4485 TABLA_A_TX_1_2_TEST_EN + j * 10,
4486 0x03, val_txfe);
4487 }
4488 }
4489 if (flag & 0x40) {
4490 value = (leg_mode & 0x40) ? 0x10 : 0x00;
4491 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
4492 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
4493 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
4494 0x13, value);
4495 }
Patrick Lai49efeac2011-11-03 11:01:12 -07004496
4497 if (pdata->ocp.use_pdata) {
4498 /* not defined in CODEC specification */
4499 if (pdata->ocp.hph_ocp_limit == 1 ||
4500 pdata->ocp.hph_ocp_limit == 5) {
4501 rc = -EINVAL;
4502 goto done;
4503 }
4504 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
4505 0x0F, pdata->ocp.num_attempts);
4506 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
4507 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4508 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
4509 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4510 }
Patrick Lai3043fba2011-08-01 14:15:57 -07004511done:
4512 return rc;
4513}
4514
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004515static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
4516
4517 /* Tabla 1.1 MICBIAS changes */
4518 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
4519 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
4520 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004521
4522 /* Tabla 1.1 HPH changes */
4523 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
4524 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
4525
4526 /* Tabla 1.1 EAR PA changes */
4527 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
4528 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
4529 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
4530
4531 /* Tabla 1.1 Lineout_5 Changes */
4532 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
4533
4534 /* Tabla 1.1 RX Changes */
4535 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
4536 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
4537 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
4538 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
4539 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
4540 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
4541 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
4542
4543 /* Tabla 1.1 RX1 and RX2 Changes */
4544 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
4545 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
4546
4547 /* Tabla 1.1 RX3 to RX7 Changes */
4548 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
4549 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
4550 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
4551 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
4552 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
4553
4554 /* Tabla 1.1 CLASSG Changes */
4555 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
4556};
4557
4558static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004559 /* Tabla 2.0 MICBIAS changes */
4560 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
4561};
4562
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004563static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
4564 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
4565};
4566
4567static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
4568 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
4569};
4570
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004571static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
4572{
4573 u32 i;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004574 struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004575
4576 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
4577 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
4578 tabla_1_1_reg_defaults[i].val);
4579
4580 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
4581 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
4582 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004583
4584 if (TABLA_IS_1_X(tabla_core->version)) {
4585 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
4586 i++)
4587 snd_soc_write(codec,
4588 tabla_1_x_only_reg_2_0_defaults[i].reg,
4589 tabla_1_x_only_reg_2_0_defaults[i].val);
4590 } else {
4591 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
4592 snd_soc_write(codec,
4593 tabla_2_only_reg_2_0_defaults[i].reg,
4594 tabla_2_only_reg_2_0_defaults[i].val);
4595 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004596}
4597
4598static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08004599 /* Initialize current threshold to 350MA
4600 * number of wait and run cycles to 4096
4601 */
Patrick Lai49efeac2011-11-03 11:01:12 -07004602 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08004603 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004604
Santosh Mardi32171012011-10-28 23:32:06 +05304605 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
4606
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004607 /* Initialize gain registers to use register gain */
4608 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
4609 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
4610 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
4611 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
4612 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
4613 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
4614
4615 /* Initialize mic biases to differential mode */
4616 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
4617 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
4618 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004619
4620 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
4621
4622 /* Use 16 bit sample size for TX1 to TX6 */
4623 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
4624 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4625 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4626 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4627 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
4628 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
4629
4630 /* Use 16 bit sample size for TX7 to TX10 */
4631 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
4632 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
4633 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
4634 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
4635
4636 /* Use 16 bit sample size for RX */
4637 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4638 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
4639
4640 /*enable HPF filter for TX paths */
4641 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
4642 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
4643 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
4644 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
4645 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
4646 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
4647 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
4648 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
4649 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
4650 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
4651};
4652
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004653static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
4654 /* Initialize mic biases to differential mode */
4655 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
4656};
4657
4658static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
4659 /* Initialize mic biases to differential mode */
4660 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
4661};
4662
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004663static void tabla_codec_init_reg(struct snd_soc_codec *codec)
4664{
4665 u32 i;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004666 struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004667
4668 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
4669 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
4670 tabla_codec_reg_init_val[i].mask,
4671 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004672 if (TABLA_IS_1_X(tabla_core->version)) {
4673 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
4674 snd_soc_update_bits(codec,
4675 tabla_1_x_codec_reg_init_val[i].reg,
4676 tabla_1_x_codec_reg_init_val[i].mask,
4677 tabla_1_x_codec_reg_init_val[i].val);
4678 } else {
4679 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
4680 i++)
4681 snd_soc_update_bits(codec,
4682 tabla_2_higher_codec_reg_init_val[i].reg,
4683 tabla_2_higher_codec_reg_init_val[i].mask,
4684 tabla_2_higher_codec_reg_init_val[i].val);
4685 }
4686}
4687
4688static void tabla_update_reg_address(struct tabla_priv *priv)
4689{
4690 struct tabla *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
4691 struct tabla_reg_address *reg_addr = &priv->reg_addr;
4692
4693 if (TABLA_IS_1_X(tabla_core->version)) {
4694 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
4695 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
4696 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
4697 } else if (TABLA_IS_2_0(tabla_core->version)) {
4698 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
4699 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
4700 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
4701 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004702}
4703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004704static int tabla_codec_probe(struct snd_soc_codec *codec)
4705{
4706 struct tabla *control;
4707 struct tabla_priv *tabla;
4708 struct snd_soc_dapm_context *dapm = &codec->dapm;
4709 int ret = 0;
4710 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004711
4712 codec->control_data = dev_get_drvdata(codec->dev->parent);
4713 control = codec->control_data;
4714
4715 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
4716 if (!tabla) {
4717 dev_err(codec->dev, "Failed to allocate private data\n");
4718 return -ENOMEM;
4719 }
4720
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004721 /* Make sure mbhc micbias register addresses are zeroed out */
4722 memset(&tabla->mbhc_bias_regs, 0,
4723 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004724 tabla->cfilt_k_value = 0;
4725 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004726
Joonwoo Park0976d012011-12-22 11:48:18 -08004727 /* Make sure mbhc intenal calibration data is zeroed out */
4728 memset(&tabla->mbhc_data, 0,
4729 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08004730 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08004731 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
4732 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004733 snd_soc_codec_set_drvdata(codec, tabla);
4734
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004735 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004736 tabla->bandgap_type = TABLA_BANDGAP_OFF;
4737 tabla->clock_active = false;
4738 tabla->config_mode_active = false;
4739 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004740 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004741 tabla->no_mic_headset_override = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004742 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07004743 tabla->pdata = dev_get_platdata(codec->dev->parent);
Santosh Mardie15e2302011-11-15 10:39:23 +05304744 tabla->intf_type = tabla_get_intf_type();
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004745 atomic_set(&tabla->pm_cnt, 1);
4746 init_waitqueue_head(&tabla->pm_wq);
Patrick Lai3043fba2011-08-01 14:15:57 -07004747
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004748 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05304749 tabla_update_reg_defaults(codec);
4750 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05304751 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07004752 if (IS_ERR_VALUE(ret)) {
4753 pr_err("%s: bad pdata\n", __func__);
4754 goto err_pdata;
4755 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004757 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004758 ARRAY_SIZE(tabla_snd_controls));
4759 if (TABLA_IS_1_X(control->version))
4760 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
4761 ARRAY_SIZE(tabla_1_x_snd_controls));
4762 else
4763 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
4764 ARRAY_SIZE(tabla_2_higher_snd_controls));
4765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004766 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004767 ARRAY_SIZE(tabla_dapm_widgets));
4768 if (TABLA_IS_1_X(control->version))
4769 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
4770 ARRAY_SIZE(tabla_1_x_dapm_widgets));
4771 else
4772 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
4773 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
4774
Santosh Mardie15e2302011-11-15 10:39:23 +05304775 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
4776 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
4777 ARRAY_SIZE(tabla_dapm_i2s_widgets));
4778 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
4779 ARRAY_SIZE(audio_i2s_map));
4780 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004781 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004782
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004783 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004784 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004785 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
4786 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004787 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004788 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004789 } else {
4790 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004791 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004792 goto err_pdata;
4793 }
4794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004795 snd_soc_dapm_sync(dapm);
4796
4797 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
4798 tabla_hs_insert_irq, "Headset insert detect", tabla);
4799 if (ret) {
4800 pr_err("%s: Failed to request irq %d\n", __func__,
4801 TABLA_IRQ_MBHC_INSERTION);
4802 goto err_insert_irq;
4803 }
4804 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4805
4806 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
4807 tabla_hs_remove_irq, "Headset remove detect", tabla);
4808 if (ret) {
4809 pr_err("%s: Failed to request irq %d\n", __func__,
4810 TABLA_IRQ_MBHC_REMOVAL);
4811 goto err_remove_irq;
4812 }
4813 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4814
4815 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004816 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004817 if (ret) {
4818 pr_err("%s: Failed to request irq %d\n", __func__,
4819 TABLA_IRQ_MBHC_POTENTIAL);
4820 goto err_potential_irq;
4821 }
4822 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4823
Bradley Rubincb1e2732011-06-23 16:49:20 -07004824 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
4825 tabla_release_handler, "Button Release detect", tabla);
4826 if (ret) {
4827 pr_err("%s: Failed to request irq %d\n", __func__,
4828 TABLA_IRQ_MBHC_RELEASE);
4829 goto err_release_irq;
4830 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004831 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004832
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004833 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
4834 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
4835 if (ret) {
4836 pr_err("%s: Failed to request irq %d\n", __func__,
4837 TABLA_IRQ_SLIMBUS);
4838 goto err_slimbus_irq;
4839 }
4840
4841 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
4842 tabla_interface_reg_write(codec->control_data,
4843 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
4844
Patrick Lai49efeac2011-11-03 11:01:12 -07004845 ret = tabla_request_irq(codec->control_data,
4846 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
4847 "HPH_L OCP detect", tabla);
4848 if (ret) {
4849 pr_err("%s: Failed to request irq %d\n", __func__,
4850 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4851 goto err_hphl_ocp_irq;
4852 }
Patrick Lai92032be2011-12-19 14:14:25 -08004853 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004854
4855 ret = tabla_request_irq(codec->control_data,
4856 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
4857 "HPH_R OCP detect", tabla);
4858 if (ret) {
4859 pr_err("%s: Failed to request irq %d\n", __func__,
4860 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4861 goto err_hphr_ocp_irq;
4862 }
Patrick Lai92032be2011-12-19 14:14:25 -08004863 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07004864
Bradley Rubincb3950a2011-08-18 13:07:26 -07004865#ifdef CONFIG_DEBUG_FS
4866 debug_tabla_priv = tabla;
4867#endif
4868
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004869 return ret;
4870
Patrick Lai49efeac2011-11-03 11:01:12 -07004871err_hphr_ocp_irq:
4872 tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
4873err_hphl_ocp_irq:
4874 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004875err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07004876 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
4877err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004878 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4879err_potential_irq:
4880 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4881err_remove_irq:
4882 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4883err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07004884err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004885 kfree(tabla);
4886 return ret;
4887}
4888static int tabla_codec_remove(struct snd_soc_codec *codec)
4889{
4890 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4891 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004892 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004893 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
4894 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
4895 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
4896 tabla_codec_disable_clock_block(codec);
4897 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08004898 if (tabla->mbhc_fw)
4899 release_firmware(tabla->mbhc_fw);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004900 kfree(tabla);
4901 return 0;
4902}
4903static struct snd_soc_codec_driver soc_codec_dev_tabla = {
4904 .probe = tabla_codec_probe,
4905 .remove = tabla_codec_remove,
4906 .read = tabla_read,
4907 .write = tabla_write,
4908
4909 .readable_register = tabla_readable,
4910 .volatile_register = tabla_volatile,
4911
4912 .reg_cache_size = TABLA_CACHE_SIZE,
4913 .reg_cache_default = tabla_reg_defaults,
4914 .reg_word_size = 1,
4915};
Bradley Rubincb3950a2011-08-18 13:07:26 -07004916
4917#ifdef CONFIG_DEBUG_FS
4918static struct dentry *debugfs_poke;
4919
4920static int codec_debug_open(struct inode *inode, struct file *file)
4921{
4922 file->private_data = inode->i_private;
4923 return 0;
4924}
4925
4926static ssize_t codec_debug_write(struct file *filp,
4927 const char __user *ubuf, size_t cnt, loff_t *ppos)
4928{
4929 char lbuf[32];
4930 char *buf;
4931 int rc;
4932
4933 if (cnt > sizeof(lbuf) - 1)
4934 return -EINVAL;
4935
4936 rc = copy_from_user(lbuf, ubuf, cnt);
4937 if (rc)
4938 return -EFAULT;
4939
4940 lbuf[cnt] = '\0';
4941 buf = (char *)lbuf;
4942 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
4943 ? false : true;
4944
4945 return rc;
4946}
4947
4948static const struct file_operations codec_debug_ops = {
4949 .open = codec_debug_open,
4950 .write = codec_debug_write,
4951};
4952#endif
4953
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004954#ifdef CONFIG_PM
4955static int tabla_suspend(struct device *dev)
4956{
4957 int ret = 0, cnt;
4958 struct platform_device *pdev = to_platform_device(dev);
4959 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4960
4961 cnt = atomic_read(&tabla->pm_cnt);
4962 if (cnt > 0) {
4963 if (wait_event_timeout(tabla->pm_wq,
4964 (atomic_cmpxchg(&tabla->pm_cnt, 1, 0)
4965 == 1), 5 * HZ)) {
4966 dev_dbg(dev, "system suspend pm_cnt %d\n",
4967 atomic_read(&tabla->pm_cnt));
4968 } else {
4969 dev_err(dev, "%s timed out pm_cnt = %d\n",
4970 __func__, atomic_read(&tabla->pm_cnt));
4971 WARN_ON_ONCE(1);
4972 ret = -EBUSY;
4973 }
4974 } else if (cnt == 0)
4975 dev_warn(dev, "system is already in suspend, pm_cnt %d\n",
4976 atomic_read(&tabla->pm_cnt));
4977 else {
4978 WARN(1, "unexpected pm_cnt %d\n", cnt);
4979 ret = -EFAULT;
4980 }
4981
4982 return ret;
4983}
4984
4985static int tabla_resume(struct device *dev)
4986{
4987 int ret = 0, cnt;
4988 struct platform_device *pdev = to_platform_device(dev);
4989 struct tabla_priv *tabla = platform_get_drvdata(pdev);
4990
4991 cnt = atomic_cmpxchg(&tabla->pm_cnt, 0, 1);
4992 if (cnt == 0) {
4993 dev_dbg(dev, "system resume, pm_cnt %d\n",
4994 atomic_read(&tabla->pm_cnt));
4995 wake_up_all(&tabla->pm_wq);
4996 } else if (cnt > 0)
4997 dev_warn(dev, "system is already awake, pm_cnt %d\n", cnt);
4998 else {
4999 WARN(1, "unexpected pm_cnt %d\n", cnt);
5000 ret = -EFAULT;
5001 }
5002
5003 return ret;
5004}
5005
5006static const struct dev_pm_ops tabla_pm_ops = {
5007 .suspend = tabla_suspend,
5008 .resume = tabla_resume,
5009};
5010#endif
5011
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005012static int __devinit tabla_probe(struct platform_device *pdev)
5013{
Santosh Mardie15e2302011-11-15 10:39:23 +05305014 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07005015#ifdef CONFIG_DEBUG_FS
5016 debugfs_poke = debugfs_create_file("TRRS",
5017 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
5018
5019#endif
Santosh Mardie15e2302011-11-15 10:39:23 +05305020 if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
5021 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
5022 tabla_dai, ARRAY_SIZE(tabla_dai));
5023 else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
5024 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
5025 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
5026 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005027}
5028static int __devexit tabla_remove(struct platform_device *pdev)
5029{
5030 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07005031
5032#ifdef CONFIG_DEBUG_FS
5033 debugfs_remove(debugfs_poke);
5034#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005035 return 0;
5036}
5037static struct platform_driver tabla_codec_driver = {
5038 .probe = tabla_probe,
5039 .remove = tabla_remove,
5040 .driver = {
5041 .name = "tabla_codec",
5042 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005043#ifdef CONFIG_PM
5044 .pm = &tabla_pm_ops,
5045#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005046 },
5047};
5048
5049static int __init tabla_codec_init(void)
5050{
5051 return platform_driver_register(&tabla_codec_driver);
5052}
5053
5054static void __exit tabla_codec_exit(void)
5055{
5056 platform_driver_unregister(&tabla_codec_driver);
5057}
5058
5059module_init(tabla_codec_init);
5060module_exit(tabla_codec_exit);
5061
5062MODULE_DESCRIPTION("Tabla codec driver");
5063MODULE_VERSION("1.0");
5064MODULE_LICENSE("GPL v2");