blob: e5206b74cfd606f989bb3b0a6b3cc97beb4f05ce [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
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080039#define TABLA_CFILT_FAST_MODE 0x00
40#define TABLA_CFILT_SLOW_MODE 0x40
Patrick Lai64b43262011-12-06 17:29:15 -080041#define MBHC_FW_READ_ATTEMPTS 15
42#define MBHC_FW_READ_TIMEOUT 2000000
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070043
Patrick Lai49efeac2011-11-03 11:01:12 -070044#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
45
Santosh Mardie15e2302011-11-15 10:39:23 +053046#define TABLA_I2S_MASTER_MODE_MASK 0x08
47
Patrick Laic7cae882011-11-18 11:52:49 -080048#define TABLA_OCP_ATTEMPT 1
49
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080050#define AIF1_PB 1
51#define AIF1_CAP 2
52#define NUM_CODEC_DAIS 2
53
54struct tabla_codec_dai_data {
55 u32 rate;
56 u32 *ch_num;
57 u32 ch_act;
58 u32 ch_tot;
59};
60
Joonwoo Park0976d012011-12-22 11:48:18 -080061#define TABLA_MCLK_RATE_12288KHZ 12288000
62#define TABLA_MCLK_RATE_9600KHZ 9600000
63
Joonwoo Parkf4267c22012-01-10 13:25:24 -080064#define TABLA_FAKE_INS_THRESHOLD_MS 2500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -080065#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
Joonwoo Parkf4267c22012-01-10 13:25:24 -080066
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070067static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
68static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
69static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080070static struct snd_soc_dai_driver tabla_dai[];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071
72enum tabla_bandgap_type {
73 TABLA_BANDGAP_OFF = 0,
74 TABLA_BANDGAP_AUDIO_MODE,
75 TABLA_BANDGAP_MBHC_MODE,
76};
77
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070078struct mbhc_micbias_regs {
79 u16 cfilt_val;
80 u16 cfilt_ctl;
81 u16 mbhc_reg;
82 u16 int_rbias;
83 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080084 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070085};
86
Ben Romberger1f045a72011-11-04 10:14:57 -070087/* Codec supports 2 IIR filters */
88enum {
89 IIR1 = 0,
90 IIR2,
91 IIR_MAX,
92};
93/* Codec supports 5 bands */
94enum {
95 BAND1 = 0,
96 BAND2,
97 BAND3,
98 BAND4,
99 BAND5,
100 BAND_MAX,
101};
102
Joonwoo Parka9444452011-12-08 18:48:27 -0800103/* Flags to track of PA and DAC state.
104 * PA and DAC should be tracked separately as AUXPGA loopback requires
105 * only PA to be turned on without DAC being on. */
106enum tabla_priv_ack_flags {
107 TABLA_HPHL_PA_OFF_ACK = 0,
108 TABLA_HPHR_PA_OFF_ACK,
109 TABLA_HPHL_DAC_OFF_ACK,
110 TABLA_HPHR_DAC_OFF_ACK
111};
112
Joonwoo Park0976d012011-12-22 11:48:18 -0800113/* Data used by MBHC */
114struct mbhc_internal_cal_data {
115 u16 dce_z;
116 u16 dce_mb;
117 u16 sta_z;
118 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800119 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800120 u32 t_dce;
121 u32 t_sta;
122 u32 micb_mv;
123 u16 v_ins_hu;
124 u16 v_ins_h;
125 u16 v_b1_hu;
126 u16 v_b1_h;
127 u16 v_b1_huc;
128 u16 v_brh;
129 u16 v_brl;
130 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800131 u8 npoll;
132 u8 nbounce_wait;
133};
134
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800135struct tabla_reg_address {
136 u16 micb_4_ctl;
137 u16 micb_4_int_rbias;
138 u16 micb_4_mbhc;
139};
140
Bradley Rubin229c6a52011-07-12 16:18:48 -0700141struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700142 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800143 struct tabla_reg_address reg_addr;
Joonwoo Park0976d012011-12-22 11:48:18 -0800144 u32 mclk_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700145 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700146 u32 cfilt1_cnt;
147 u32 cfilt2_cnt;
148 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700149 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700151 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700152 bool clock_active;
153 bool config_mode_active;
154 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800155 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700156 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157
Joonwoo Park0976d012011-12-22 11:48:18 -0800158 enum tabla_micbias_num micbias;
159 /* void* calibration contains:
160 * struct tabla_mbhc_general_cfg generic;
161 * struct tabla_mbhc_plug_detect_cfg plug_det;
162 * struct tabla_mbhc_plug_type_cfg plug_type;
163 * struct tabla_mbhc_btn_detect_cfg btn_det;
164 * struct tabla_mbhc_imped_detect_cfg imped_det;
165 * Note: various size depends on btn_det->num_btn
166 */
167 void *calibration;
168 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700169
Bradley Rubincb1e2732011-06-23 16:49:20 -0700170 struct snd_soc_jack *headset_jack;
171 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700172
Patrick Lai3043fba2011-08-01 14:15:57 -0700173 struct tabla_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700174 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700175
176 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700177 /* Delayed work to report long button press */
178 struct delayed_work btn0_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700179
180 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700181 u8 cfilt_k_value;
182 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700183
Joonwoo Parka9444452011-12-08 18:48:27 -0800184 /* track PA/DAC state */
185 unsigned long hph_pa_dac_state;
186
Santosh Mardie15e2302011-11-15 10:39:23 +0530187 /*track tabla interface type*/
188 u8 intf_type;
189
Patrick Lai49efeac2011-11-03 11:01:12 -0700190 u32 hph_status; /* track headhpone status */
191 /* define separate work for left and right headphone OCP to avoid
192 * additional checking on which OCP event to report so no locking
193 * to ensure synchronization is required
194 */
195 struct work_struct hphlocp_work; /* reporting left hph ocp off */
196 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800197
Patrick Laic7cae882011-11-18 11:52:49 -0800198 u8 hphlocp_cnt; /* headphone left ocp retry */
199 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800200
201 /* Callback function to enable MCLK */
202 int (*mclk_cb) (struct snd_soc_codec*, int);
Patrick Lai64b43262011-12-06 17:29:15 -0800203
204 /* Work to perform MBHC Firmware Read */
205 struct delayed_work mbhc_firmware_dwork;
206 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800207
208 /* num of slim ports required */
209 struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700210};
211
Bradley Rubincb3950a2011-08-18 13:07:26 -0700212#ifdef CONFIG_DEBUG_FS
213struct tabla_priv *debug_tabla_priv;
214#endif
215
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700216static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
217 struct snd_kcontrol *kcontrol, int event)
218{
219 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220
221 pr_debug("%s %d\n", __func__, event);
222 switch (event) {
223 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
225 0x01);
226 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
227 usleep_range(200, 200);
228 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
229 break;
230 case SND_SOC_DAPM_PRE_PMD:
231 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
232 0x10);
233 usleep_range(20, 20);
234 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
235 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
236 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
237 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
238 0x00);
239 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 break;
241 }
242 return 0;
243}
244
Bradley Rubina7096d02011-08-03 18:29:02 -0700245static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
246 struct snd_ctl_elem_value *ucontrol)
247{
248 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
249 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
250 ucontrol->value.integer.value[0] = tabla->anc_slot;
251 return 0;
252}
253
254static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
255 struct snd_ctl_elem_value *ucontrol)
256{
257 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
258 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
259 tabla->anc_slot = ucontrol->value.integer.value[0];
260 return 0;
261}
262
Kiran Kandid2d86b52011-09-09 17:44:28 -0700263static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
264 struct snd_ctl_elem_value *ucontrol)
265{
266 u8 ear_pa_gain;
267 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
268
269 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
270
271 ear_pa_gain = ear_pa_gain >> 5;
272
273 if (ear_pa_gain == 0x00) {
274 ucontrol->value.integer.value[0] = 0;
275 } else if (ear_pa_gain == 0x04) {
276 ucontrol->value.integer.value[0] = 1;
277 } else {
278 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
279 __func__, ear_pa_gain);
280 return -EINVAL;
281 }
282
283 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
284
285 return 0;
286}
287
288static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
289 struct snd_ctl_elem_value *ucontrol)
290{
291 u8 ear_pa_gain;
292 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
293
294 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
295 ucontrol->value.integer.value[0]);
296
297 switch (ucontrol->value.integer.value[0]) {
298 case 0:
299 ear_pa_gain = 0x00;
300 break;
301 case 1:
302 ear_pa_gain = 0x80;
303 break;
304 default:
305 return -EINVAL;
306 }
307
308 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
309 return 0;
310}
311
Ben Romberger1f045a72011-11-04 10:14:57 -0700312static int tabla_get_iir_enable_audio_mixer(
313 struct snd_kcontrol *kcontrol,
314 struct snd_ctl_elem_value *ucontrol)
315{
316 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
317 int iir_idx = ((struct soc_multi_mixer_control *)
318 kcontrol->private_value)->reg;
319 int band_idx = ((struct soc_multi_mixer_control *)
320 kcontrol->private_value)->shift;
321
322 ucontrol->value.integer.value[0] =
323 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
324 (1 << band_idx);
325
326 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
327 iir_idx, band_idx,
328 (uint32_t)ucontrol->value.integer.value[0]);
329 return 0;
330}
331
332static int tabla_put_iir_enable_audio_mixer(
333 struct snd_kcontrol *kcontrol,
334 struct snd_ctl_elem_value *ucontrol)
335{
336 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
337 int iir_idx = ((struct soc_multi_mixer_control *)
338 kcontrol->private_value)->reg;
339 int band_idx = ((struct soc_multi_mixer_control *)
340 kcontrol->private_value)->shift;
341 int value = ucontrol->value.integer.value[0];
342
343 /* Mask first 5 bits, 6-8 are reserved */
344 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
345 (1 << band_idx), (value << band_idx));
346
347 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
348 iir_idx, band_idx, value);
349 return 0;
350}
351static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
352 int iir_idx, int band_idx,
353 int coeff_idx)
354{
355 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800356 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700357 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800358 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700359
360 /* Mask bits top 2 bits since they are reserved */
361 return ((snd_soc_read(codec,
362 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
363 (snd_soc_read(codec,
364 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
365 (snd_soc_read(codec,
366 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
367 (snd_soc_read(codec,
368 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
369 0x3FFFFFFF;
370}
371
372static int tabla_get_iir_band_audio_mixer(
373 struct snd_kcontrol *kcontrol,
374 struct snd_ctl_elem_value *ucontrol)
375{
376 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
377 int iir_idx = ((struct soc_multi_mixer_control *)
378 kcontrol->private_value)->reg;
379 int band_idx = ((struct soc_multi_mixer_control *)
380 kcontrol->private_value)->shift;
381
382 ucontrol->value.integer.value[0] =
383 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
384 ucontrol->value.integer.value[1] =
385 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
386 ucontrol->value.integer.value[2] =
387 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
388 ucontrol->value.integer.value[3] =
389 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
390 ucontrol->value.integer.value[4] =
391 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
392
393 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
394 "%s: IIR #%d band #%d b1 = 0x%x\n"
395 "%s: IIR #%d band #%d b2 = 0x%x\n"
396 "%s: IIR #%d band #%d a1 = 0x%x\n"
397 "%s: IIR #%d band #%d a2 = 0x%x\n",
398 __func__, iir_idx, band_idx,
399 (uint32_t)ucontrol->value.integer.value[0],
400 __func__, iir_idx, band_idx,
401 (uint32_t)ucontrol->value.integer.value[1],
402 __func__, iir_idx, band_idx,
403 (uint32_t)ucontrol->value.integer.value[2],
404 __func__, iir_idx, band_idx,
405 (uint32_t)ucontrol->value.integer.value[3],
406 __func__, iir_idx, band_idx,
407 (uint32_t)ucontrol->value.integer.value[4]);
408 return 0;
409}
410
411static void set_iir_band_coeff(struct snd_soc_codec *codec,
412 int iir_idx, int band_idx,
413 int coeff_idx, uint32_t value)
414{
415 /* Mask top 3 bits, 6-8 are reserved */
416 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800417 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700418 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800419 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700420
421 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800422 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700423 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800424 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700425
426 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800427 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700428 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800429 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700430
Ben Romberger0915aae2012-02-06 23:32:43 -0800431 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700432 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800433 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700434
Ben Romberger0915aae2012-02-06 23:32:43 -0800435 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700436 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800437 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700438}
439
440static int tabla_put_iir_band_audio_mixer(
441 struct snd_kcontrol *kcontrol,
442 struct snd_ctl_elem_value *ucontrol)
443{
444 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
445 int iir_idx = ((struct soc_multi_mixer_control *)
446 kcontrol->private_value)->reg;
447 int band_idx = ((struct soc_multi_mixer_control *)
448 kcontrol->private_value)->shift;
449
450 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
451 ucontrol->value.integer.value[0]);
452 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
453 ucontrol->value.integer.value[1]);
454 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
455 ucontrol->value.integer.value[2]);
456 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
457 ucontrol->value.integer.value[3]);
458 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
459 ucontrol->value.integer.value[4]);
460
461 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
462 "%s: IIR #%d band #%d b1 = 0x%x\n"
463 "%s: IIR #%d band #%d b2 = 0x%x\n"
464 "%s: IIR #%d band #%d a1 = 0x%x\n"
465 "%s: IIR #%d band #%d a2 = 0x%x\n",
466 __func__, iir_idx, band_idx,
467 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
468 __func__, iir_idx, band_idx,
469 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
470 __func__, iir_idx, band_idx,
471 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
472 __func__, iir_idx, band_idx,
473 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
474 __func__, iir_idx, band_idx,
475 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
476 return 0;
477}
478
Kiran Kandid2d86b52011-09-09 17:44:28 -0700479static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
480static const struct soc_enum tabla_ear_pa_gain_enum[] = {
481 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
482};
483
Santosh Mardi024010f2011-10-18 06:27:21 +0530484/*cut of frequency for high pass filter*/
485static const char *cf_text[] = {
486 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
487};
488
489static const struct soc_enum cf_dec1_enum =
490 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
491
492static const struct soc_enum cf_dec2_enum =
493 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
494
495static const struct soc_enum cf_dec3_enum =
496 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
497
498static const struct soc_enum cf_dec4_enum =
499 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
500
501static const struct soc_enum cf_dec5_enum =
502 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
503
504static const struct soc_enum cf_dec6_enum =
505 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
506
507static const struct soc_enum cf_dec7_enum =
508 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
509
510static const struct soc_enum cf_dec8_enum =
511 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
512
513static const struct soc_enum cf_dec9_enum =
514 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
515
516static const struct soc_enum cf_dec10_enum =
517 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
518
519static const struct soc_enum cf_rxmix1_enum =
520 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
521
522static const struct soc_enum cf_rxmix2_enum =
523 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
524
525static const struct soc_enum cf_rxmix3_enum =
526 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
527
528static const struct soc_enum cf_rxmix4_enum =
529 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
530
531static const struct soc_enum cf_rxmix5_enum =
532 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
533;
534static const struct soc_enum cf_rxmix6_enum =
535 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
536
537static const struct soc_enum cf_rxmix7_enum =
538 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
539
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700540static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700541
542 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
543 tabla_pa_gain_get, tabla_pa_gain_put),
544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700545 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
546 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700547 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
548 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
550 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700551 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
552 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700553 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
554 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
557 line_gain),
558 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
559 line_gain),
560
Bradley Rubin410383f2011-07-22 13:44:23 -0700561 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
562 -84, 40, digital_gain),
563 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
564 -84, 40, digital_gain),
565 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
566 -84, 40, digital_gain),
567 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
568 -84, 40, digital_gain),
569 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
570 -84, 40, digital_gain),
571 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
572 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573
Bradley Rubin410383f2011-07-22 13:44:23 -0700574 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700575 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700576 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700578 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
579 digital_gain),
580 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
581 digital_gain),
582 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
583 digital_gain),
584 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
585 digital_gain),
586 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
587 digital_gain),
588 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
589 digital_gain),
590 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
591 digital_gain),
592 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
593 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700594 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
595 40, digital_gain),
596 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
597 40, digital_gain),
598 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
599 40, digital_gain),
600 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
601 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700602 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
603 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700604 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
605 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700606 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
607 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608
609 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800610 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700611 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700612
613 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
614 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530615 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
616 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
617 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
618 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
619 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
620 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
621 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
622 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
623 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
624 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
625
626 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
627 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
628 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
629 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
630 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
631 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
632 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
633 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
634 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
635 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
636
637 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
638 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
639 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
640 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
641 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
642 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
643 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
644
645 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
646 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
647 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
648 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
649 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
650 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
651 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700652
653 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
654 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
655 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
656 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
657 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
658 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
659 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
660 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
661 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
662 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
663 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
664 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
665 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
666 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
667 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
668 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
669 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
670 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
671 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
672 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
673
674 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
675 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
676 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
677 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
678 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
679 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
680 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
681 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
682 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
683 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
684 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
685 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
686 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
687 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
688 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
689 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
690 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
691 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
692 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
693 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694};
695
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800696static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
697 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
698};
699
700static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
701 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
702};
703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704static const char *rx_mix1_text[] = {
705 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
706 "RX5", "RX6", "RX7"
707};
708
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700709static const char *rx_dsm_text[] = {
710 "CIC_OUT", "DSM_INV"
711};
712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700713static const char *sb_tx1_mux_text[] = {
714 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
715 "DEC1"
716};
717
718static const char *sb_tx5_mux_text[] = {
719 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
720 "DEC5"
721};
722
723static const char *sb_tx6_mux_text[] = {
724 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
725 "DEC6"
726};
727
728static const char const *sb_tx7_to_tx10_mux_text[] = {
729 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
730 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
731 "DEC9", "DEC10"
732};
733
734static const char *dec1_mux_text[] = {
735 "ZERO", "DMIC1", "ADC6",
736};
737
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700738static const char *dec2_mux_text[] = {
739 "ZERO", "DMIC2", "ADC5",
740};
741
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700742static const char *dec3_mux_text[] = {
743 "ZERO", "DMIC3", "ADC4",
744};
745
746static const char *dec4_mux_text[] = {
747 "ZERO", "DMIC4", "ADC3",
748};
749
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700750static const char *dec5_mux_text[] = {
751 "ZERO", "DMIC5", "ADC2",
752};
753
754static const char *dec6_mux_text[] = {
755 "ZERO", "DMIC6", "ADC1",
756};
757
758static const char const *dec7_mux_text[] = {
759 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
760};
761
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700762static const char *dec8_mux_text[] = {
763 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
764};
765
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700766static const char *dec9_mux_text[] = {
767 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
768};
769
770static const char *dec10_mux_text[] = {
771 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
772};
773
Bradley Rubin229c6a52011-07-12 16:18:48 -0700774static const char const *anc_mux_text[] = {
775 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
776 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
777};
778
779static const char const *anc1_fb_mux_text[] = {
780 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
781};
782
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783static const char *iir1_inp1_text[] = {
784 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
785 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
786};
787
788static const struct soc_enum rx_mix1_inp1_chain_enum =
789 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
790
Bradley Rubin229c6a52011-07-12 16:18:48 -0700791static const struct soc_enum rx_mix1_inp2_chain_enum =
792 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700794static const struct soc_enum rx2_mix1_inp1_chain_enum =
795 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
796
Bradley Rubin229c6a52011-07-12 16:18:48 -0700797static const struct soc_enum rx2_mix1_inp2_chain_enum =
798 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
799
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700800static const struct soc_enum rx3_mix1_inp1_chain_enum =
801 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
802
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700803static const struct soc_enum rx3_mix1_inp2_chain_enum =
804 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806static const struct soc_enum rx4_mix1_inp1_chain_enum =
807 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
808
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700809static const struct soc_enum rx4_mix1_inp2_chain_enum =
810 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
811
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812static const struct soc_enum rx5_mix1_inp1_chain_enum =
813 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
814
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700815static const struct soc_enum rx5_mix1_inp2_chain_enum =
816 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
817
818static const struct soc_enum rx6_mix1_inp1_chain_enum =
819 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
820
821static const struct soc_enum rx6_mix1_inp2_chain_enum =
822 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
823
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700824static const struct soc_enum rx7_mix1_inp1_chain_enum =
825 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
826
827static const struct soc_enum rx7_mix1_inp2_chain_enum =
828 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
829
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700830static const struct soc_enum rx4_dsm_enum =
831 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
832
833static const struct soc_enum rx6_dsm_enum =
834 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
835
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836static const struct soc_enum sb_tx5_mux_enum =
837 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
838
839static const struct soc_enum sb_tx6_mux_enum =
840 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
841
842static const struct soc_enum sb_tx7_mux_enum =
843 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
844 sb_tx7_to_tx10_mux_text);
845
846static const struct soc_enum sb_tx8_mux_enum =
847 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
848 sb_tx7_to_tx10_mux_text);
849
Kiran Kandi3426e512011-09-13 22:50:10 -0700850static const struct soc_enum sb_tx9_mux_enum =
851 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
852 sb_tx7_to_tx10_mux_text);
853
854static const struct soc_enum sb_tx10_mux_enum =
855 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
856 sb_tx7_to_tx10_mux_text);
857
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858static const struct soc_enum sb_tx1_mux_enum =
859 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
860
861static const struct soc_enum dec1_mux_enum =
862 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
863
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700864static const struct soc_enum dec2_mux_enum =
865 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
866
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700867static const struct soc_enum dec3_mux_enum =
868 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
869
870static const struct soc_enum dec4_mux_enum =
871 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
872
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700873static const struct soc_enum dec5_mux_enum =
874 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
875
876static const struct soc_enum dec6_mux_enum =
877 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
878
879static const struct soc_enum dec7_mux_enum =
880 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
881
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700882static const struct soc_enum dec8_mux_enum =
883 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
884
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700885static const struct soc_enum dec9_mux_enum =
886 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
887
888static const struct soc_enum dec10_mux_enum =
889 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
890
Bradley Rubin229c6a52011-07-12 16:18:48 -0700891static const struct soc_enum anc1_mux_enum =
892 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
893
894static const struct soc_enum anc2_mux_enum =
895 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
896
897static const struct soc_enum anc1_fb_mux_enum =
898 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
899
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900static const struct soc_enum iir1_inp1_mux_enum =
901 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
902
903static const struct snd_kcontrol_new rx_mix1_inp1_mux =
904 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
905
Bradley Rubin229c6a52011-07-12 16:18:48 -0700906static const struct snd_kcontrol_new rx_mix1_inp2_mux =
907 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700909static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
910 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
911
Bradley Rubin229c6a52011-07-12 16:18:48 -0700912static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
913 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
916 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
917
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700918static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
919 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
920
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
922 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
923
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700924static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
925 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
928 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
929
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700930static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
931 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
932
933static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
934 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
935
936static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
937 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
938
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700939static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
940 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
941
942static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
943 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
944
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700945static const struct snd_kcontrol_new rx4_dsm_mux =
946 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
947
948static const struct snd_kcontrol_new rx6_dsm_mux =
949 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
950
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700951static const struct snd_kcontrol_new sb_tx5_mux =
952 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
953
954static const struct snd_kcontrol_new sb_tx6_mux =
955 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
956
957static const struct snd_kcontrol_new sb_tx7_mux =
958 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
959
960static const struct snd_kcontrol_new sb_tx8_mux =
961 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
962
Kiran Kandi3426e512011-09-13 22:50:10 -0700963static const struct snd_kcontrol_new sb_tx9_mux =
964 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
965
966static const struct snd_kcontrol_new sb_tx10_mux =
967 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
968
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969static const struct snd_kcontrol_new sb_tx1_mux =
970 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
971
972static const struct snd_kcontrol_new dec1_mux =
973 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
974
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700975static const struct snd_kcontrol_new dec2_mux =
976 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
977
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700978static const struct snd_kcontrol_new dec3_mux =
979 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
980
981static const struct snd_kcontrol_new dec4_mux =
982 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
983
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700984static const struct snd_kcontrol_new dec5_mux =
985 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
986
987static const struct snd_kcontrol_new dec6_mux =
988 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
989
990static const struct snd_kcontrol_new dec7_mux =
991 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
992
Bradley Rubin229c6a52011-07-12 16:18:48 -0700993static const struct snd_kcontrol_new anc1_mux =
994 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700995static const struct snd_kcontrol_new dec8_mux =
996 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
997
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700998static const struct snd_kcontrol_new dec9_mux =
999 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
1000
1001static const struct snd_kcontrol_new dec10_mux =
1002 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
1003
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004static const struct snd_kcontrol_new iir1_inp1_mux =
1005 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1006
Bradley Rubin229c6a52011-07-12 16:18:48 -07001007static const struct snd_kcontrol_new anc2_mux =
1008 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009
Bradley Rubin229c6a52011-07-12 16:18:48 -07001010static const struct snd_kcontrol_new anc1_fb_mux =
1011 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012
Bradley Rubin229c6a52011-07-12 16:18:48 -07001013static const struct snd_kcontrol_new dac1_switch[] = {
1014 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1015};
1016static const struct snd_kcontrol_new hphl_switch[] = {
1017 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1018};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001019
1020static const struct snd_kcontrol_new lineout3_ground_switch =
1021 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1022
1023static const struct snd_kcontrol_new lineout4_ground_switch =
1024 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
1027 int enable)
1028{
1029 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1030
1031 pr_debug("%s %d\n", __func__, enable);
1032
1033 if (enable) {
1034 tabla->adc_count++;
1035 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1036 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1037 } else {
1038 tabla->adc_count--;
1039 if (!tabla->adc_count) {
1040 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
1041 0x2, 0x0);
1042 if (!tabla->mbhc_polling_active)
1043 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
1044 0xE0, 0x0);
1045 }
1046 }
1047}
1048
1049static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1050 struct snd_kcontrol *kcontrol, int event)
1051{
1052 struct snd_soc_codec *codec = w->codec;
1053 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001054 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055
1056 pr_debug("%s %d\n", __func__, event);
1057
1058 if (w->reg == TABLA_A_TX_1_2_EN)
1059 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1060 else if (w->reg == TABLA_A_TX_3_4_EN)
1061 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1062 else if (w->reg == TABLA_A_TX_5_6_EN)
1063 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1064 else {
1065 pr_err("%s: Error, invalid adc register\n", __func__);
1066 return -EINVAL;
1067 }
1068
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001069 if (w->shift == 3)
1070 init_bit_shift = 6;
1071 else if (w->shift == 7)
1072 init_bit_shift = 7;
1073 else {
1074 pr_err("%s: Error, invalid init bit postion adc register\n",
1075 __func__);
1076 return -EINVAL;
1077 }
1078
1079
1080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 switch (event) {
1082 case SND_SOC_DAPM_PRE_PMU:
1083 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001084 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1085 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086 break;
1087 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001088
1089 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091 break;
1092 case SND_SOC_DAPM_POST_PMD:
1093 tabla_codec_enable_adc_block(codec, 0);
1094 break;
1095 }
1096 return 0;
1097}
1098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1100 struct snd_kcontrol *kcontrol, int event)
1101{
1102 struct snd_soc_codec *codec = w->codec;
1103 u16 lineout_gain_reg;
1104
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001105 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106
1107 switch (w->shift) {
1108 case 0:
1109 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1110 break;
1111 case 1:
1112 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1113 break;
1114 case 2:
1115 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1116 break;
1117 case 3:
1118 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1119 break;
1120 case 4:
1121 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1122 break;
1123 default:
1124 pr_err("%s: Error, incorrect lineout register value\n",
1125 __func__);
1126 return -EINVAL;
1127 }
1128
1129 switch (event) {
1130 case SND_SOC_DAPM_PRE_PMU:
1131 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1132 break;
1133 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001134 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001135 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001136 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 break;
1138 case SND_SOC_DAPM_POST_PMD:
1139 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1140 break;
1141 }
1142 return 0;
1143}
1144
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001145
1146static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 struct snd_kcontrol *kcontrol, int event)
1148{
1149 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001150 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1151 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001152 unsigned int dmic;
1153 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001154
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001155 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1156 if (ret < 0) {
1157 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001158 return -EINVAL;
1159 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001161 switch (dmic) {
1162 case 1:
1163 case 2:
1164 dmic_clk_sel = 0x02;
1165 dmic_clk_en = 0x01;
1166 break;
1167
1168 case 3:
1169 case 4:
1170 dmic_clk_sel = 0x08;
1171 dmic_clk_en = 0x04;
1172 break;
1173
1174 case 5:
1175 case 6:
1176 dmic_clk_sel = 0x20;
1177 dmic_clk_en = 0x10;
1178 break;
1179
1180 default:
1181 pr_err("%s: Invalid DMIC Selection\n", __func__);
1182 return -EINVAL;
1183 }
1184
1185 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1186 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1187
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190 switch (event) {
1191 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001192 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1193
1194 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1195 dmic_clk_sel, dmic_clk_sel);
1196
1197 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1198
1199 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1200 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201 break;
1202 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001203 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1204 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205 break;
1206 }
1207 return 0;
1208}
1209
Bradley Rubin229c6a52011-07-12 16:18:48 -07001210static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1211 struct snd_kcontrol *kcontrol, int event)
1212{
1213 struct snd_soc_codec *codec = w->codec;
1214 const char *filename;
1215 const struct firmware *fw;
1216 int i;
1217 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001218 int num_anc_slots;
1219 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001220 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001221 u32 anc_writes_size = 0;
1222 int anc_size_remaining;
1223 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001224 u16 reg;
1225 u8 mask, val, old_val;
1226
1227 pr_debug("%s %d\n", __func__, event);
1228 switch (event) {
1229 case SND_SOC_DAPM_PRE_PMU:
1230
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001231 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001232
1233 ret = request_firmware(&fw, filename, codec->dev);
1234 if (ret != 0) {
1235 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1236 ret);
1237 return -ENODEV;
1238 }
1239
Bradley Rubina7096d02011-08-03 18:29:02 -07001240 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001241 dev_err(codec->dev, "Not enough data\n");
1242 release_firmware(fw);
1243 return -ENOMEM;
1244 }
1245
1246 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001247 anc_head = (struct anc_header *)(fw->data);
1248 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1249 anc_size_remaining = fw->size - sizeof(struct anc_header);
1250 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001251
Bradley Rubina7096d02011-08-03 18:29:02 -07001252 if (tabla->anc_slot >= num_anc_slots) {
1253 dev_err(codec->dev, "Invalid ANC slot selected\n");
1254 release_firmware(fw);
1255 return -EINVAL;
1256 }
1257
1258 for (i = 0; i < num_anc_slots; i++) {
1259
1260 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1261 dev_err(codec->dev, "Invalid register format\n");
1262 release_firmware(fw);
1263 return -EINVAL;
1264 }
1265 anc_writes_size = (u32)(*anc_ptr);
1266 anc_size_remaining -= sizeof(u32);
1267 anc_ptr += 1;
1268
1269 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1270 > anc_size_remaining) {
1271 dev_err(codec->dev, "Invalid register format\n");
1272 release_firmware(fw);
1273 return -ENOMEM;
1274 }
1275
1276 if (tabla->anc_slot == i)
1277 break;
1278
1279 anc_size_remaining -= (anc_writes_size *
1280 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001281 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001282 }
1283 if (i == num_anc_slots) {
1284 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001285 release_firmware(fw);
1286 return -ENOMEM;
1287 }
1288
Bradley Rubina7096d02011-08-03 18:29:02 -07001289 for (i = 0; i < anc_writes_size; i++) {
1290 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001291 mask, val);
1292 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001293 snd_soc_write(codec, reg, (old_val & ~mask) |
1294 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001295 }
1296 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001297
1298 break;
1299 case SND_SOC_DAPM_POST_PMD:
1300 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1301 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1302 break;
1303 }
1304 return 0;
1305}
1306
1307
Bradley Rubincb3950a2011-08-18 13:07:26 -07001308static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
1309{
1310 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
1311 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
1312}
1313
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001314static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1315{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001316 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1317
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001318 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001319 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001320 if (!tabla->no_mic_headset_override) {
1321 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
1322 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1323 } else {
1324 tabla_codec_disable_button_presses(codec);
1325 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001326 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1327 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1328 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1329}
1330
1331static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1332{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001333 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1334
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001335 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
1336 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001337 if (!tabla->no_mic_headset_override) {
1338 tabla_disable_irq(codec->control_data,
1339 TABLA_IRQ_MBHC_POTENTIAL);
1340 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
1341 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001342}
1343
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001344static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1345 int mode)
1346{
1347 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1348 u8 reg_mode_val, cur_mode_val;
1349 bool mbhc_was_polling = false;
1350
1351 if (mode)
1352 reg_mode_val = TABLA_CFILT_FAST_MODE;
1353 else
1354 reg_mode_val = TABLA_CFILT_SLOW_MODE;
1355
1356 cur_mode_val = snd_soc_read(codec,
1357 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
1358
1359 if (cur_mode_val != reg_mode_val) {
1360 if (tabla->mbhc_polling_active) {
1361 tabla_codec_pause_hs_polling(codec);
1362 mbhc_was_polling = true;
1363 }
1364 snd_soc_update_bits(codec,
1365 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1366 if (mbhc_was_polling)
1367 tabla_codec_start_hs_polling(codec);
1368 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
1369 cur_mode_val, reg_mode_val);
1370 } else {
1371 pr_debug("%s: CFILT Value is already %x\n",
1372 __func__, cur_mode_val);
1373 }
1374}
1375
1376static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1377 u8 cfilt_sel, int inc)
1378{
1379 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1380 u32 *cfilt_cnt_ptr = NULL;
1381 u16 micb_cfilt_reg;
1382
1383 switch (cfilt_sel) {
1384 case TABLA_CFILT1_SEL:
1385 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
1386 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
1387 break;
1388 case TABLA_CFILT2_SEL:
1389 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
1390 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
1391 break;
1392 case TABLA_CFILT3_SEL:
1393 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
1394 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
1395 break;
1396 default:
1397 return; /* should not happen */
1398 }
1399
1400 if (inc) {
1401 if (!(*cfilt_cnt_ptr)++) {
1402 /* Switch CFILT to slow mode if MBHC CFILT being used */
1403 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1404 tabla_codec_switch_cfilt_mode(codec, 0);
1405
1406 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
1407 }
1408 } else {
1409 /* check if count not zero, decrement
1410 * then check if zero, go ahead disable cfilter
1411 */
1412 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
1413 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
1414
1415 /* Switch CFILT to fast mode if MBHC CFILT being used */
1416 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
1417 tabla_codec_switch_cfilt_mode(codec, 1);
1418 }
1419 }
1420}
1421
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001422static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
1423{
1424 int rc = -EINVAL;
1425 unsigned min_mv, max_mv;
1426
1427 switch (ldoh_v) {
1428 case TABLA_LDOH_1P95_V:
1429 min_mv = 160;
1430 max_mv = 1800;
1431 break;
1432 case TABLA_LDOH_2P35_V:
1433 min_mv = 200;
1434 max_mv = 2200;
1435 break;
1436 case TABLA_LDOH_2P75_V:
1437 min_mv = 240;
1438 max_mv = 2600;
1439 break;
1440 case TABLA_LDOH_2P85_V:
1441 min_mv = 250;
1442 max_mv = 2700;
1443 break;
1444 default:
1445 goto done;
1446 }
1447
1448 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
1449 goto done;
1450
1451 for (rc = 4; rc <= 44; rc++) {
1452 min_mv = max_mv * (rc) / 44;
1453 if (min_mv >= cfilt_mv) {
1454 rc -= 4;
1455 break;
1456 }
1457 }
1458done:
1459 return rc;
1460}
1461
1462static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
1463{
1464 u8 hph_reg_val = 0;
1465 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
1466
1467 return (hph_reg_val & 0x30) ? true : false;
1468}
1469
Joonwoo Parka9444452011-12-08 18:48:27 -08001470static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
1471{
1472 u8 hph_reg_val = 0;
1473 if (left)
1474 hph_reg_val = snd_soc_read(codec,
1475 TABLA_A_RX_HPH_L_DAC_CTL);
1476 else
1477 hph_reg_val = snd_soc_read(codec,
1478 TABLA_A_RX_HPH_R_DAC_CTL);
1479
1480 return (hph_reg_val & 0xC0) ? true : false;
1481}
1482
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001483static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
1484 int vddio_switch)
1485{
1486 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1487 int cfilt_k_val;
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001488 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001489
1490 switch (vddio_switch) {
1491 case 1:
1492 if (tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001493
1494 tabla_codec_pause_hs_polling(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08001495 /* VDDIO switch enabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001496 tabla->cfilt_k_value = snd_soc_read(codec,
1497 tabla->mbhc_bias_regs.cfilt_val);
1498 cfilt_k_val = tabla_find_k_value(
1499 tabla->pdata->micbias.ldoh_v, 1800);
1500 snd_soc_update_bits(codec,
1501 tabla->mbhc_bias_regs.cfilt_val,
1502 0xFC, (cfilt_k_val << 2));
1503
1504 snd_soc_update_bits(codec,
1505 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
1506 snd_soc_update_bits(codec,
1507 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001508 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001509
1510 tabla->mbhc_micbias_switched = true;
Joonwoo Park0976d012011-12-22 11:48:18 -08001511 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001512 }
1513 break;
1514
1515 case 0:
1516 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001517 if (tabla->mbhc_polling_active) {
1518 tabla_codec_pause_hs_polling(codec);
1519 mbhc_was_polling = true;
1520 }
Joonwoo Park0976d012011-12-22 11:48:18 -08001521 /* VDDIO switch disabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001522 if (tabla->cfilt_k_value != 0)
1523 snd_soc_update_bits(codec,
1524 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
1525 tabla->cfilt_k_value);
1526 snd_soc_update_bits(codec,
1527 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
1528 snd_soc_update_bits(codec,
1529 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
1530
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08001531 if (mbhc_was_polling)
1532 tabla_codec_start_hs_polling(codec);
1533
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001534 tabla->mbhc_micbias_switched = false;
Joonwoo Park0976d012011-12-22 11:48:18 -08001535 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001536 }
1537 break;
1538 }
1539}
1540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1542 struct snd_kcontrol *kcontrol, int event)
1543{
1544 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07001545 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1546 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001547 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001548 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001549 char *internal1_text = "Internal1";
1550 char *internal2_text = "Internal2";
1551 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552
1553 pr_debug("%s %d\n", __func__, event);
1554 switch (w->reg) {
1555 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001556 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001557 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001558 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001559 break;
1560 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001562 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001563 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001564 break;
1565 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07001567 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001568 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001569 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001570 case TABLA_1_A_MICB_4_CTL:
1571 case TABLA_2_A_MICB_4_CTL:
1572 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07001573 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001574 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001575 break;
1576 default:
1577 pr_err("%s: Error, invalid micbias register\n", __func__);
1578 return -EINVAL;
1579 }
1580
1581 switch (event) {
1582 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001583 /* Decide whether to switch the micbias for MBHC */
1584 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1585 && tabla->mbhc_micbias_switched)
1586 tabla_codec_switch_micbias(codec, 0);
1587
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001588 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07001589 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001590
1591 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001592 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001593 else if (strnstr(w->name, internal2_text, 30))
1594 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1595 else if (strnstr(w->name, internal3_text, 30))
1596 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
1597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001599 case SND_SOC_DAPM_POST_PMU:
1600 if (tabla->mbhc_polling_active &&
Joonwoo Park0976d012011-12-22 11:48:18 -08001601 tabla->micbias == micb_line) {
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001602 tabla_codec_pause_hs_polling(codec);
1603 tabla_codec_start_hs_polling(codec);
1604 }
1605 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001608
1609 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
1610 && tabla_is_hph_pa_on(codec))
1611 tabla_codec_switch_micbias(codec, 1);
1612
Bradley Rubin229c6a52011-07-12 16:18:48 -07001613 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001615 else if (strnstr(w->name, internal2_text, 30))
1616 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1617 else if (strnstr(w->name, internal3_text, 30))
1618 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1619
Patrick Lai3043fba2011-08-01 14:15:57 -07001620 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001621 break;
1622 }
1623
1624 return 0;
1625}
1626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001627static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
1628 struct snd_kcontrol *kcontrol, int event)
1629{
1630 struct snd_soc_codec *codec = w->codec;
1631 u16 dec_reset_reg;
1632
1633 pr_debug("%s %d\n", __func__, event);
1634
1635 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
1636 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
1637 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
1638 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
1639 else {
1640 pr_err("%s: Error, incorrect dec\n", __func__);
1641 return -EINVAL;
1642 }
1643
1644 switch (event) {
1645 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1647 1 << w->shift);
1648 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1649 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001650 }
1651 return 0;
1652}
1653
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001654static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001655 struct snd_kcontrol *kcontrol, int event)
1656{
1657 struct snd_soc_codec *codec = w->codec;
1658
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001659 pr_debug("%s %d %s\n", __func__, event, w->name);
1660
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 switch (event) {
1662 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001663 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1664 1 << w->shift, 1 << w->shift);
1665 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
1666 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 break;
1668 }
1669 return 0;
1670}
1671
Bradley Rubin229c6a52011-07-12 16:18:48 -07001672static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
1673 struct snd_kcontrol *kcontrol, int event)
1674{
1675 switch (event) {
1676 case SND_SOC_DAPM_POST_PMU:
1677 case SND_SOC_DAPM_POST_PMD:
1678 usleep_range(1000, 1000);
1679 break;
1680 }
1681 return 0;
1682}
1683
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001684
1685static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1686{
1687 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1688
1689 if (enable) {
1690 tabla->rx_bias_count++;
1691 if (tabla->rx_bias_count == 1)
1692 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1693 0x80, 0x80);
1694 } else {
1695 tabla->rx_bias_count--;
1696 if (!tabla->rx_bias_count)
1697 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1698 0x80, 0x00);
1699 }
1700}
1701
1702static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1703 struct snd_kcontrol *kcontrol, int event)
1704{
1705 struct snd_soc_codec *codec = w->codec;
1706
1707 pr_debug("%s %d\n", __func__, event);
1708
1709 switch (event) {
1710 case SND_SOC_DAPM_PRE_PMU:
1711 tabla_enable_rx_bias(codec, 1);
1712 break;
1713 case SND_SOC_DAPM_POST_PMD:
1714 tabla_enable_rx_bias(codec, 0);
1715 break;
1716 }
1717 return 0;
1718}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001719static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
1720 struct snd_kcontrol *kcontrol, int event)
1721{
1722 struct snd_soc_codec *codec = w->codec;
1723
1724 pr_debug("%s %s %d\n", __func__, w->name, event);
1725
1726 switch (event) {
1727 case SND_SOC_DAPM_PRE_PMU:
1728 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1729 break;
1730 case SND_SOC_DAPM_POST_PMD:
1731 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1732 break;
1733 }
1734 return 0;
1735}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07001736
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001737static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
1738 struct snd_soc_jack *jack, int status,
1739 int mask)
1740{
1741 /* XXX: wake_lock_timeout()? */
1742 snd_soc_jack_report(jack, status, mask);
1743}
1744
Patrick Lai49efeac2011-11-03 11:01:12 -07001745static void hphocp_off_report(struct tabla_priv *tabla,
1746 u32 jack_status, int irq)
1747{
1748 struct snd_soc_codec *codec;
1749
1750 if (tabla) {
1751 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
1752 codec = tabla->codec;
1753 tabla->hph_status &= ~jack_status;
1754 if (tabla->headset_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08001755 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
1756 tabla->hph_status,
1757 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08001758 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
1759 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08001760 /* reset retry counter as PA is turned off signifying
1761 * start of new OCP detection session
1762 */
1763 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
1764 tabla->hphlocp_cnt = 0;
1765 else
1766 tabla->hphrocp_cnt = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07001767 tabla_enable_irq(codec->control_data, irq);
1768 } else {
1769 pr_err("%s: Bad tabla private data\n", __func__);
1770 }
1771}
1772
1773static void hphlocp_off_report(struct work_struct *work)
1774{
1775 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1776 hphlocp_work);
1777 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
1778}
1779
1780static void hphrocp_off_report(struct work_struct *work)
1781{
1782 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
1783 hphrocp_work);
1784 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
1785}
1786
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001787static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
1788 struct snd_kcontrol *kcontrol, int event)
1789{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001790 struct snd_soc_codec *codec = w->codec;
1791 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1792 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001793 pr_debug("%s: event = %d\n", __func__, event);
1794
1795 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001796 case SND_SOC_DAPM_PRE_PMU:
1797 mbhc_micb_ctl_val = snd_soc_read(codec,
1798 tabla->mbhc_bias_regs.ctl_reg);
1799
1800 if (!(mbhc_micb_ctl_val & 0x80)
1801 && !tabla->mbhc_micbias_switched)
1802 tabla_codec_switch_micbias(codec, 1);
1803
1804 break;
1805
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001806 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07001807 /* schedule work is required because at the time HPH PA DAPM
1808 * event callback is called by DAPM framework, CODEC dapm mutex
1809 * would have been locked while snd_soc_jack_report also
1810 * attempts to acquire same lock.
1811 */
Joonwoo Parka9444452011-12-08 18:48:27 -08001812 if (w->shift == 5) {
1813 clear_bit(TABLA_HPHL_PA_OFF_ACK,
1814 &tabla->hph_pa_dac_state);
1815 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
1816 &tabla->hph_pa_dac_state);
1817 if (tabla->hph_status & SND_JACK_OC_HPHL)
1818 schedule_work(&tabla->hphlocp_work);
1819 } else if (w->shift == 4) {
1820 clear_bit(TABLA_HPHR_PA_OFF_ACK,
1821 &tabla->hph_pa_dac_state);
1822 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
1823 &tabla->hph_pa_dac_state);
1824 if (tabla->hph_status & SND_JACK_OC_HPHR)
1825 schedule_work(&tabla->hphrocp_work);
1826 }
1827
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07001828 if (tabla->mbhc_micbias_switched)
1829 tabla_codec_switch_micbias(codec, 0);
1830
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07001831 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
1832 w->name);
1833 usleep_range(10000, 10000);
1834
1835 break;
1836 }
1837 return 0;
1838}
1839
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001840static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001841 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001842{
1843 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001844 unsigned int cfilt;
1845
Joonwoo Park0976d012011-12-22 11:48:18 -08001846 switch (tabla->micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001847 case TABLA_MICBIAS1:
1848 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
1849 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
1850 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
1851 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
1852 break;
1853 case TABLA_MICBIAS2:
1854 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
1855 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
1856 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
1857 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
1858 break;
1859 case TABLA_MICBIAS3:
1860 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
1861 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
1862 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
1863 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
1864 break;
1865 case TABLA_MICBIAS4:
1866 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001867 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
1868 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
1869 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001870 break;
1871 default:
1872 /* Should never reach here */
1873 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07001874 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001875 }
1876
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001877 micbias_regs->cfilt_sel = cfilt;
1878
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001879 switch (cfilt) {
1880 case TABLA_CFILT1_SEL:
1881 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
1882 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001883 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001884 break;
1885 case TABLA_CFILT2_SEL:
1886 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
1887 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001888 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001889 break;
1890 case TABLA_CFILT3_SEL:
1891 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
1892 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08001893 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001894 break;
1895 }
1896}
Santosh Mardie15e2302011-11-15 10:39:23 +05301897static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
1898 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
1899 4, 0, NULL, 0),
1900 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
1901 0, NULL, 0),
1902};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07001903
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001904static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
1905 struct snd_kcontrol *kcontrol, int event)
1906{
1907 struct snd_soc_codec *codec = w->codec;
1908
1909 pr_debug("%s %s %d\n", __func__, w->name, event);
1910
1911 switch (event) {
1912 case SND_SOC_DAPM_PRE_PMU:
1913 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1914 break;
1915
1916 case SND_SOC_DAPM_POST_PMD:
1917 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1918 break;
1919 }
1920 return 0;
1921}
1922
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001923static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
1924 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
1925 0, tabla_codec_enable_micbias,
1926 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
1927 SND_SOC_DAPM_POST_PMD),
1928};
1929
1930static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
1931 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
1932 0, tabla_codec_enable_micbias,
1933 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
1934 SND_SOC_DAPM_POST_PMD),
1935};
1936
Santosh Mardie15e2302011-11-15 10:39:23 +05301937static const struct snd_soc_dapm_route audio_i2s_map[] = {
1938 {"RX_I2S_CLK", NULL, "CDC_CONN"},
1939 {"SLIM RX1", NULL, "RX_I2S_CLK"},
1940 {"SLIM RX2", NULL, "RX_I2S_CLK"},
1941 {"SLIM RX3", NULL, "RX_I2S_CLK"},
1942 {"SLIM RX4", NULL, "RX_I2S_CLK"},
1943
1944 {"SLIM TX7", NULL, "TX_I2S_CLK"},
1945 {"SLIM TX8", NULL, "TX_I2S_CLK"},
1946 {"SLIM TX9", NULL, "TX_I2S_CLK"},
1947 {"SLIM TX10", NULL, "TX_I2S_CLK"},
1948};
1949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001950static const struct snd_soc_dapm_route audio_map[] = {
1951 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001952
1953 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
1954 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
1955
1956 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
1957 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
1958
1959 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
1960 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
1961
1962 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
1963 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001964 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001965 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
1966 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001967 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
1968 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001969 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
1970 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001971 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
1972 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001973
1974 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001975 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
1976 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
1977 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07001978 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001979 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
1980 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
1981
Kiran Kandi3426e512011-09-13 22:50:10 -07001982 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
1983 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
1984 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
1985 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
1986 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
1987 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
1988 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
1989 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
1990 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
1991 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
1992 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
1993
1994 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
1995 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
1996 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
1997 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
1998 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
1999 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
2000 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
2001 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
2002 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
2003 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
2004 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
2005
2006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002007 /* Earpiece (RX MIX1) */
2008 {"EAR", NULL, "EAR PA"},
Kiran Kandiac034ac2011-07-29 16:39:08 -07002009 {"EAR PA", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002010 {"DAC1", NULL, "CP"},
2011
2012 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2013 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2014 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002015
2016 /* Headset (RX MIX1 and RX MIX2) */
2017 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002019
2020 {"HPHL", NULL, "HPHL DAC"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 {"HPHR", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002022
2023 {"HPHL DAC", NULL, "CP"},
2024 {"HPHR DAC", NULL, "CP"},
2025
2026 {"ANC", NULL, "ANC1 MUX"},
2027 {"ANC", NULL, "ANC2 MUX"},
2028 {"ANC1 MUX", "ADC1", "ADC1"},
2029 {"ANC1 MUX", "ADC2", "ADC2"},
2030 {"ANC1 MUX", "ADC3", "ADC3"},
2031 {"ANC1 MUX", "ADC4", "ADC4"},
2032 {"ANC2 MUX", "ADC1", "ADC1"},
2033 {"ANC2 MUX", "ADC2", "ADC2"},
2034 {"ANC2 MUX", "ADC3", "ADC3"},
2035 {"ANC2 MUX", "ADC4", "ADC4"},
2036
Bradley Rubine1d08622011-07-20 18:01:35 -07002037 {"ANC", NULL, "CDC_CONN"},
2038
Bradley Rubin229c6a52011-07-12 16:18:48 -07002039 {"DAC1", "Switch", "RX1 CHAIN"},
2040 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002041 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002042
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002043 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2044 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2045 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2046 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2047 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002048
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002049 {"LINEOUT1 PA", NULL, "LINEOUT1 DAC"},
2050 {"LINEOUT2 PA", NULL, "LINEOUT2 DAC"},
2051 {"LINEOUT3 PA", NULL, "LINEOUT3 DAC"},
2052 {"LINEOUT4 PA", NULL, "LINEOUT4 DAC"},
2053 {"LINEOUT5 PA", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002054
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002055 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2056 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2057
Bradley Rubin229c6a52011-07-12 16:18:48 -07002058 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2059 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2060 {"RX1 CHAIN", NULL, "ANC"},
2061 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002062
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002063 {"CP", NULL, "RX_BIAS"},
2064 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2065 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2066 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2067 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002068 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002069
Bradley Rubin229c6a52011-07-12 16:18:48 -07002070 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2071 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2072 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2073 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002074 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2075 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2076 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2077 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2078 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2079 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2080 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2081 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002082 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2083 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002084
Bradley Rubin229c6a52011-07-12 16:18:48 -07002085 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2086 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302087 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2088 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002089 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2090 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2091 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302092 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2093 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002094 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2095 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2096 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302097 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2098 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002099 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002100 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2101 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302102 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2103 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002104 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002105 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2106 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302107 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2108 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002109 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002110 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2111 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302112 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2113 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002114 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002115 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2116 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302117 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2118 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002119 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002120 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2121 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302122 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2123 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002124 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002125 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2126 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302127 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2128 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002129 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002130 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2131 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302132 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2133 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002134 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002135 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2136 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302137 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2138 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002139 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002140 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2141 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302142 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2143 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002144 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002145 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2146 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302147 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2148 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002149 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002150 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2151 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302152 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2153 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Patrick Lai16261e82011-09-30 13:25:52 -07002154 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002155
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002156 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002157 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002158 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002159 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002160 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002161 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002162 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002163 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002164 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002165 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002166 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002167 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002168 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002169 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002170 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002171 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002172 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002174 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002175 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002176 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002177 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002178 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002179 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002180 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002181 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002182 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002183 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002184
2185 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002186 {"ADC1", NULL, "AMIC1"},
2187 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002188 {"ADC3", NULL, "AMIC3"},
2189 {"ADC4", NULL, "AMIC4"},
2190 {"ADC5", NULL, "AMIC5"},
2191 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002193 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002194 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2195 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2196 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2197 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2198 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002199 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002200 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
2201 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
2202 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
2203 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002204
2205 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2206 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2207 {"MIC BIAS1 External", NULL, "LDO_H"},
2208 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2209 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2210 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2211 {"MIC BIAS2 External", NULL, "LDO_H"},
2212 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2213 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2214 {"MIC BIAS3 External", NULL, "LDO_H"},
2215 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002216};
2217
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002218static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
2219
2220 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2221 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2222
2223 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
2224
2225 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
2226 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
2227 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
2228
2229 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2230 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2231
2232 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2233 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
2234 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
2235};
2236
Kiran Kandi7a9fd902011-11-14 13:51:45 -08002237
2238static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
2239
2240 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2241 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2242
2243 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
2244
2245 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
2246
2247 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2248 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2249
2250 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2251};
2252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
2254{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002255 int i;
2256 struct tabla *tabla_core = dev_get_drvdata(ssc->dev->parent);
2257
2258 if (TABLA_IS_1_X(tabla_core->version)) {
2259 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
2260 if (tabla_1_reg_readable[i] == reg)
2261 return 1;
2262 }
2263 } else {
2264 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
2265 if (tabla_2_reg_readable[i] == reg)
2266 return 1;
2267 }
2268 }
2269
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002270 return tabla_reg_readable[reg];
2271}
2272
2273static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2274{
2275 /* Registers lower than 0x100 are top level registers which can be
2276 * written by the Tabla core driver.
2277 */
2278
2279 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2280 return 1;
2281
Ben Romberger1f045a72011-11-04 10:14:57 -07002282 /* IIR Coeff registers are not cacheable */
2283 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
2284 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
2285 return 1;
2286
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002287 return 0;
2288}
2289
2290#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2291static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
2292 unsigned int value)
2293{
2294 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002295
2296 BUG_ON(reg > TABLA_MAX_REGISTER);
2297
2298 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 ret = snd_soc_cache_write(codec, reg, value);
2300 if (ret != 0)
2301 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2302 reg, ret);
2303 }
2304
2305 return tabla_reg_write(codec->control_data, reg, value);
2306}
2307static unsigned int tabla_read(struct snd_soc_codec *codec,
2308 unsigned int reg)
2309{
2310 unsigned int val;
2311 int ret;
2312
2313 BUG_ON(reg > TABLA_MAX_REGISTER);
2314
2315 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
2316 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 ret = snd_soc_cache_read(codec, reg, &val);
2318 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 return val;
2320 } else
2321 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2322 reg, ret);
2323 }
2324
2325 val = tabla_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002326 return val;
2327}
2328
2329static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2330{
2331 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
2332 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2333 0x80);
2334 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
2335 0x04);
2336 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2337 0x01);
2338 usleep_range(1000, 1000);
2339 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2340 0x00);
2341}
2342
2343static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
2344 enum tabla_bandgap_type choice)
2345{
2346 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2347
2348 /* TODO lock resources accessed by audio streams and threaded
2349 * interrupt handlers
2350 */
2351
2352 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
2353 tabla->bandgap_type);
2354
2355 if (tabla->bandgap_type == choice)
2356 return;
2357
2358 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
2359 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2360 tabla_codec_enable_audio_mode_bandgap(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302361 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002362 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
2363 0x2);
2364 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2365 0x80);
2366 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
2367 0x4);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302368 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2369 0x01);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002370 usleep_range(1000, 1000);
2371 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2372 0x00);
2373 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
2374 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2375 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2376 usleep_range(100, 100);
2377 tabla_codec_enable_audio_mode_bandgap(codec);
2378 } else if (choice == TABLA_BANDGAP_OFF) {
2379 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
2380 } else {
2381 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2382 }
2383 tabla->bandgap_type = choice;
2384}
2385
2386static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
2387 int enable)
2388{
2389 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2390
2391 if (enable) {
2392 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
2393 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
2394 usleep_range(5, 5);
2395 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
2396 0x80);
2397 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
2398 0x80);
2399 usleep_range(10, 10);
2400 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
2401 usleep_range(20, 20);
2402 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
2403 } else {
2404 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
2405 0);
2406 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002407 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002408 }
2409 tabla->config_mode_active = enable ? true : false;
2410
2411 return 0;
2412}
2413
2414static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
2415 int config_mode)
2416{
2417 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2418
Bhalchandra Gajareb95fb592012-01-18 12:49:17 -08002419 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002420
2421 if (config_mode) {
2422 tabla_codec_enable_config_mode(codec, 1);
2423 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
2424 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2425 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
2426 usleep_range(1000, 1000);
2427 } else
2428 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
2429
2430 if (!config_mode && tabla->mbhc_polling_active) {
2431 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2432 tabla_codec_enable_config_mode(codec, 0);
2433
2434 }
2435
2436 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
2437 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
2438 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
2439 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
2440 usleep_range(50, 50);
2441 tabla->clock_active = true;
2442 return 0;
2443}
2444static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
2445{
2446 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2447 pr_debug("%s\n", __func__);
2448 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
2449 ndelay(160);
2450 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
2451 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
2452 tabla->clock_active = false;
2453}
2454
Joonwoo Park107edf02012-01-11 11:42:24 -08002455static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
2456{
2457 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
2458 return 0;
2459 else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
2460 return 1;
2461 else {
2462 BUG_ON(1);
2463 return -EINVAL;
2464 }
2465}
2466
Bradley Rubincb1e2732011-06-23 16:49:20 -07002467static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
2468{
Joonwoo Parkc0672392012-01-11 11:03:14 -08002469 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08002470 struct tabla_mbhc_btn_detect_cfg *btn_det;
2471 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002472
Joonwoo Park0976d012011-12-22 11:48:18 -08002473 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002474
Joonwoo Park0976d012011-12-22 11:48:18 -08002475 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2476 tabla->mbhc_data.v_ins_hu & 0xFF);
2477 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2478 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002479
Joonwoo Park0976d012011-12-22 11:48:18 -08002480 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2481 tabla->mbhc_data.v_b1_hu & 0xFF);
2482 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2483 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
2484
2485 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2486 tabla->mbhc_data.v_b1_h & 0xFF);
2487 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2488 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
2489
2490 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
2491 tabla->mbhc_data.v_brh & 0xFF);
2492 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
2493 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
2494
2495 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
2496 tabla->mbhc_data.v_brl & 0xFF);
2497 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
2498 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
2499
Joonwoo Parkc0672392012-01-11 11:03:14 -08002500 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08002501 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08002502 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08002503 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
2504 tabla->mbhc_data.npoll);
2505 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
2506 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08002507 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08002508 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
2509 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002510}
2511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002512static int tabla_startup(struct snd_pcm_substream *substream,
2513 struct snd_soc_dai *dai)
2514{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002515 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2516 substream->name, substream->stream);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002517
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002518 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002519}
2520
2521static void tabla_shutdown(struct snd_pcm_substream *substream,
2522 struct snd_soc_dai *dai)
2523{
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002524 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
2525 substream->name, substream->stream);
2526}
2527
2528int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
2529{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002530 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2531
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002532 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002533
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002534 if (mclk_enable) {
2535 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002536
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002537 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07002538 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002540 TABLA_BANDGAP_AUDIO_MODE);
2541 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07002542 tabla_codec_calibrate_hs_polling(codec);
2543 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302544 } else {
2545 tabla_codec_enable_bandgap(codec,
2546 TABLA_BANDGAP_AUDIO_MODE);
2547 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002548 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002549 } else {
2550
2551 if (!tabla->mclk_enabled) {
2552 pr_err("Error, MCLK already diabled\n");
2553 return -EINVAL;
2554 }
2555 tabla->mclk_enabled = false;
2556
2557 if (tabla->mbhc_polling_active) {
2558 if (!tabla->mclk_enabled) {
2559 tabla_codec_pause_hs_polling(codec);
2560 tabla_codec_enable_bandgap(codec,
2561 TABLA_BANDGAP_MBHC_MODE);
2562 tabla_enable_rx_bias(codec, 1);
2563 tabla_codec_enable_clock_block(codec, 1);
2564 tabla_codec_calibrate_hs_polling(codec);
2565 tabla_codec_start_hs_polling(codec);
2566 }
2567 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
2568 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05302569 } else {
2570 tabla_codec_disable_clock_block(codec);
2571 tabla_codec_enable_bandgap(codec,
2572 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002573 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002574 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002575 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002576}
2577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002578static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
2579 int clk_id, unsigned int freq, int dir)
2580{
2581 pr_debug("%s\n", __func__);
2582 return 0;
2583}
2584
2585static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2586{
Santosh Mardie15e2302011-11-15 10:39:23 +05302587 u8 val = 0;
2588 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
2589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05302591 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2592 case SND_SOC_DAIFMT_CBS_CFS:
2593 /* CPU is master */
2594 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002595 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05302596 snd_soc_update_bits(dai->codec,
2597 TABLA_A_CDC_CLK_TX_I2S_CTL,
2598 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002599 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05302600 snd_soc_update_bits(dai->codec,
2601 TABLA_A_CDC_CLK_RX_I2S_CTL,
2602 TABLA_I2S_MASTER_MODE_MASK, 0);
2603 }
2604 break;
2605 case SND_SOC_DAIFMT_CBM_CFM:
2606 /* CPU is slave */
2607 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2608 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002609 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05302610 snd_soc_update_bits(dai->codec,
2611 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002612 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05302613 snd_soc_update_bits(dai->codec,
2614 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
2615 }
2616 break;
2617 default:
2618 return -EINVAL;
2619 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 return 0;
2621}
2622
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002623static int tabla_set_channel_map(struct snd_soc_dai *dai,
2624 unsigned int tx_num, unsigned int *tx_slot,
2625 unsigned int rx_num, unsigned int *rx_slot)
2626
2627{
2628 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
2629 u32 i = 0;
2630 if (!tx_slot && !rx_slot) {
2631 pr_err("%s: Invalid\n", __func__);
2632 return -EINVAL;
2633 }
2634 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
2635
2636 if (dai->id == AIF1_PB) {
2637 for (i = 0; i < rx_num; i++) {
2638 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
2639 tabla->dai[dai->id - 1].ch_act = 0;
2640 tabla->dai[dai->id - 1].ch_tot = rx_num;
2641 }
2642 } else if (dai->id == AIF1_CAP) {
2643 for (i = 0; i < tx_num; i++) {
2644 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
2645 tabla->dai[dai->id - 1].ch_act = 0;
2646 tabla->dai[dai->id - 1].ch_tot = tx_num;
2647 }
2648 }
2649 return 0;
2650}
2651
2652static int tabla_get_channel_map(struct snd_soc_dai *dai,
2653 unsigned int *tx_num, unsigned int *tx_slot,
2654 unsigned int *rx_num, unsigned int *rx_slot)
2655
2656{
2657 struct tabla *tabla = dev_get_drvdata(dai->codec->control_data);
2658
2659 u32 cnt = 0;
2660 u32 tx_ch[SLIM_MAX_TX_PORTS];
2661 u32 rx_ch[SLIM_MAX_RX_PORTS];
2662
2663 if (!rx_slot && !tx_slot) {
2664 pr_err("%s: Invalid\n", __func__);
2665 return -EINVAL;
2666 }
2667 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
2668 /* for virtual port, codec driver needs to do
2669 * housekeeping, for now should be ok
2670 */
2671 tabla_get_channel(tabla, rx_ch, tx_ch);
2672 if (dai->id == AIF1_PB) {
2673 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
2674 while (cnt < *rx_num) {
2675 rx_slot[cnt] = rx_ch[cnt];
2676 cnt++;
2677 }
2678 } else if (dai->id == AIF1_CAP) {
2679 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
2680 while (cnt < *tx_num) {
2681 tx_slot[cnt] = tx_ch[6 + cnt];
2682 cnt++;
2683 }
2684 }
2685 return 0;
2686}
2687
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002688static int tabla_hw_params(struct snd_pcm_substream *substream,
2689 struct snd_pcm_hw_params *params,
2690 struct snd_soc_dai *dai)
2691{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002692 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05302693 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07002694 u8 path, shift;
2695 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002696 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
2697
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002698 pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
2699 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002700
2701 switch (params_rate(params)) {
2702 case 8000:
2703 tx_fs_rate = 0x00;
2704 rx_fs_rate = 0x00;
2705 break;
2706 case 16000:
2707 tx_fs_rate = 0x01;
2708 rx_fs_rate = 0x20;
2709 break;
2710 case 32000:
2711 tx_fs_rate = 0x02;
2712 rx_fs_rate = 0x40;
2713 break;
2714 case 48000:
2715 tx_fs_rate = 0x03;
2716 rx_fs_rate = 0x60;
2717 break;
2718 default:
2719 pr_err("%s: Invalid sampling rate %d\n", __func__,
2720 params_rate(params));
2721 return -EINVAL;
2722 }
2723
2724
2725 /**
2726 * If current dai is a tx dai, set sample rate to
2727 * all the txfe paths that are currently not active
2728 */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002729 if (dai->id == AIF1_CAP) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002730
2731 tx_state = snd_soc_read(codec,
2732 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
2733
2734 for (path = 1, shift = 0;
2735 path <= NUM_DECIMATORS; path++, shift++) {
2736
2737 if (path == BITS_PER_REG + 1) {
2738 shift = 0;
2739 tx_state = snd_soc_read(codec,
2740 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
2741 }
2742
2743 if (!(tx_state & (1 << shift))) {
2744 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
2745 + (BITS_PER_REG*(path-1));
2746 snd_soc_update_bits(codec, tx_fs_reg,
2747 0x03, tx_fs_rate);
2748 }
2749 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302750 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2751 switch (params_format(params)) {
2752 case SNDRV_PCM_FORMAT_S16_LE:
2753 snd_soc_update_bits(codec,
2754 TABLA_A_CDC_CLK_TX_I2S_CTL,
2755 0x20, 0x20);
2756 break;
2757 case SNDRV_PCM_FORMAT_S32_LE:
2758 snd_soc_update_bits(codec,
2759 TABLA_A_CDC_CLK_TX_I2S_CTL,
2760 0x20, 0x00);
2761 break;
2762 default:
2763 pr_err("invalid format\n");
2764 break;
2765 }
2766 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
2767 0x03, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002768 } else {
2769 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05302770 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002771 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002772 /**
2773 * TODO: Need to handle case where same RX chain takes 2 or more inputs
2774 * with varying sample rates
2775 */
2776
2777 /**
2778 * If current dai is a rx dai, set sample rate to
2779 * all the rx paths that are currently not active
2780 */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002781 if (dai->id == AIF1_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002782
2783 rx_state = snd_soc_read(codec,
2784 TABLA_A_CDC_CLK_RX_B1_CTL);
2785
2786 for (path = 1, shift = 0;
2787 path <= NUM_INTERPOLATORS; path++, shift++) {
2788
2789 if (!(rx_state & (1 << shift))) {
2790 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
2791 + (BITS_PER_REG*(path-1));
2792 snd_soc_update_bits(codec, rx_fs_reg,
2793 0xE0, rx_fs_rate);
2794 }
2795 }
Santosh Mardie15e2302011-11-15 10:39:23 +05302796 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
2797 switch (params_format(params)) {
2798 case SNDRV_PCM_FORMAT_S16_LE:
2799 snd_soc_update_bits(codec,
2800 TABLA_A_CDC_CLK_RX_I2S_CTL,
2801 0x20, 0x20);
2802 break;
2803 case SNDRV_PCM_FORMAT_S32_LE:
2804 snd_soc_update_bits(codec,
2805 TABLA_A_CDC_CLK_RX_I2S_CTL,
2806 0x20, 0x00);
2807 break;
2808 default:
2809 pr_err("invalid format\n");
2810 break;
2811 }
2812 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
2813 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002814 } else {
2815 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05302816 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002817 }
2818
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002819 return 0;
2820}
2821
2822static struct snd_soc_dai_ops tabla_dai_ops = {
2823 .startup = tabla_startup,
2824 .shutdown = tabla_shutdown,
2825 .hw_params = tabla_hw_params,
2826 .set_sysclk = tabla_set_dai_sysclk,
2827 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002828 .set_channel_map = tabla_set_channel_map,
2829 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002830};
2831
2832static struct snd_soc_dai_driver tabla_dai[] = {
2833 {
2834 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002835 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002836 .playback = {
2837 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002838 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002839 .formats = TABLA_FORMATS,
2840 .rate_max = 48000,
2841 .rate_min = 8000,
2842 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002843 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002844 },
2845 .ops = &tabla_dai_ops,
2846 },
2847 {
2848 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002849 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002850 .capture = {
2851 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07002852 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002853 .formats = TABLA_FORMATS,
2854 .rate_max = 48000,
2855 .rate_min = 8000,
2856 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002857 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002858 },
2859 .ops = &tabla_dai_ops,
2860 },
2861};
Santosh Mardie15e2302011-11-15 10:39:23 +05302862
2863static struct snd_soc_dai_driver tabla_i2s_dai[] = {
2864 {
2865 .name = "tabla_i2s_rx1",
2866 .id = 1,
2867 .playback = {
2868 .stream_name = "AIF1 Playback",
2869 .rates = WCD9310_RATES,
2870 .formats = TABLA_FORMATS,
2871 .rate_max = 48000,
2872 .rate_min = 8000,
2873 .channels_min = 1,
2874 .channels_max = 4,
2875 },
2876 .ops = &tabla_dai_ops,
2877 },
2878 {
2879 .name = "tabla_i2s_tx1",
2880 .id = 2,
2881 .capture = {
2882 .stream_name = "AIF1 Capture",
2883 .rates = WCD9310_RATES,
2884 .formats = TABLA_FORMATS,
2885 .rate_max = 48000,
2886 .rate_min = 8000,
2887 .channels_min = 1,
2888 .channels_max = 4,
2889 },
2890 .ops = &tabla_dai_ops,
2891 },
2892};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002893
2894static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
2895 struct snd_kcontrol *kcontrol, int event)
2896{
2897 struct tabla *tabla;
2898 struct snd_soc_codec *codec = w->codec;
2899 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
2900 u32 j = 0;
2901 u32 ret = 0;
2902 codec->control_data = dev_get_drvdata(codec->dev->parent);
2903 tabla = codec->control_data;
2904 /* Execute the callback only if interface type is slimbus */
2905 if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
2906 return 0;
2907 switch (event) {
2908 case SND_SOC_DAPM_POST_PMU:
2909 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
2910 if (tabla_dai[j].id == AIF1_CAP)
2911 continue;
2912 if (!strncmp(w->sname,
2913 tabla_dai[j].playback.stream_name, 13)) {
2914 ++tabla_p->dai[j].ch_act;
2915 break;
2916 }
2917 }
2918 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
2919 ret = tabla_cfg_slim_sch_rx(tabla,
2920 tabla_p->dai[j].ch_num,
2921 tabla_p->dai[j].ch_tot,
2922 tabla_p->dai[j].rate);
2923 break;
2924 case SND_SOC_DAPM_POST_PMD:
2925 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
2926 if (tabla_dai[j].id == AIF1_CAP)
2927 continue;
2928 if (!strncmp(w->sname,
2929 tabla_dai[j].playback.stream_name, 13)) {
2930 --tabla_p->dai[j].ch_act;
2931 break;
2932 }
2933 }
2934 if (!tabla_p->dai[j].ch_act) {
2935 ret = tabla_close_slim_sch_rx(tabla,
2936 tabla_p->dai[j].ch_num,
2937 tabla_p->dai[j].ch_tot);
2938 tabla_p->dai[j].rate = 0;
2939 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
2940 tabla_p->dai[j].ch_tot));
2941 tabla_p->dai[j].ch_tot = 0;
2942 }
2943 }
2944 return ret;
2945}
2946
2947static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
2948 struct snd_kcontrol *kcontrol, int event)
2949{
2950 struct tabla *tabla;
2951 struct snd_soc_codec *codec = w->codec;
2952 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
2953 /* index to the DAI ID, for now hardcoding */
2954 u32 j = 0;
2955 u32 ret = 0;
2956
2957 codec->control_data = dev_get_drvdata(codec->dev->parent);
2958 tabla = codec->control_data;
2959
2960 /* Execute the callback only if interface type is slimbus */
2961 if (tabla_p->intf_type != TABLA_INTERFACE_TYPE_SLIMBUS)
2962 return 0;
2963 switch (event) {
2964 case SND_SOC_DAPM_POST_PMU:
2965 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
2966 if (tabla_dai[j].id == AIF1_PB)
2967 continue;
2968 if (!strncmp(w->sname,
2969 tabla_dai[j].capture.stream_name, 13)) {
2970 ++tabla_p->dai[j].ch_act;
2971 break;
2972 }
2973 }
2974 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
2975 ret = tabla_cfg_slim_sch_tx(tabla,
2976 tabla_p->dai[j].ch_num,
2977 tabla_p->dai[j].ch_tot,
2978 tabla_p->dai[j].rate);
2979 break;
2980 case SND_SOC_DAPM_POST_PMD:
2981 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
2982 if (tabla_dai[j].id == AIF1_PB)
2983 continue;
2984 if (!strncmp(w->sname,
2985 tabla_dai[j].capture.stream_name, 13)) {
2986 --tabla_p->dai[j].ch_act;
2987 break;
2988 }
2989 }
2990 if (!tabla_p->dai[j].ch_act) {
2991 ret = tabla_close_slim_sch_tx(tabla,
2992 tabla_p->dai[j].ch_num,
2993 tabla_p->dai[j].ch_tot);
2994 tabla_p->dai[j].rate = 0;
2995 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
2996 tabla_p->dai[j].ch_tot));
2997 tabla_p->dai[j].ch_tot = 0;
2998 }
2999 }
3000 return ret;
3001}
3002
3003/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3004 * Might Need to have callbacks registered only for slimbus
3005 */
3006static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
3007 /*RX stuff */
3008 SND_SOC_DAPM_OUTPUT("EAR"),
3009
3010 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
3011
3012 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
3013 ARRAY_SIZE(dac1_switch)),
3014
3015 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3016 0, tabla_codec_enable_slimrx,
3017 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3018 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3019 0, tabla_codec_enable_slimrx,
3020 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3021
3022 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3023 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3024
3025 /* Headphone */
3026 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3027 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3028 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3029 SND_SOC_DAPM_POST_PMD),
3030 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
3031 hphl_switch, ARRAY_SIZE(hphl_switch)),
3032
3033 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
3034 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3035 SND_SOC_DAPM_POST_PMD),
3036
3037 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
3038 tabla_hphr_dac_event,
3039 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3040
3041 /* Speaker */
3042 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
3043 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
3044 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
3045 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
3046 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
3047
3048 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
3049 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3050 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3051 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
3052 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3053 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3054 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
3055 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3056 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3057 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
3058 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3059 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3060 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
3061 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3062 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3063
3064 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
3065 , tabla_lineout_dac_event,
3066 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3067 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
3068 , tabla_lineout_dac_event,
3069 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3070 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
3071 , tabla_lineout_dac_event,
3072 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3073 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
3074 &lineout3_ground_switch),
3075 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
3076 , tabla_lineout_dac_event,
3077 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3078 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
3079 &lineout4_ground_switch),
3080 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
3081 , tabla_lineout_dac_event,
3082 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3083
3084 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
3085 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3086 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
3087 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3088 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
3089 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3090 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
3091 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3092 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
3093 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3094 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
3095 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3096 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
3097 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3098
3099 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
3100 &rx4_dsm_mux, tabla_codec_reset_interpolator,
3101 SND_SOC_DAPM_PRE_PMU),
3102
3103 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
3104 &rx6_dsm_mux, tabla_codec_reset_interpolator,
3105 SND_SOC_DAPM_PRE_PMU),
3106
3107 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
3108 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
3109
3110 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3111 &rx_mix1_inp1_mux),
3112 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3113 &rx_mix1_inp2_mux),
3114 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3115 &rx2_mix1_inp1_mux),
3116 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3117 &rx2_mix1_inp2_mux),
3118 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3119 &rx3_mix1_inp1_mux),
3120 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3121 &rx3_mix1_inp2_mux),
3122 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3123 &rx4_mix1_inp1_mux),
3124 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3125 &rx4_mix1_inp2_mux),
3126 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3127 &rx5_mix1_inp1_mux),
3128 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3129 &rx5_mix1_inp2_mux),
3130 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3131 &rx6_mix1_inp1_mux),
3132 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3133 &rx6_mix1_inp2_mux),
3134 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3135 &rx7_mix1_inp1_mux),
3136 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3137 &rx7_mix1_inp2_mux),
3138
3139 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
3140 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
3141 SND_SOC_DAPM_PRE_PMD),
3142
3143 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
3144 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
3145 SND_SOC_DAPM_POST_PMD),
3146
3147 /* TX */
3148
3149 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
3150 0),
3151
3152 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
3153 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
3154
3155 SND_SOC_DAPM_INPUT("AMIC1"),
3156 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
3157 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3158 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3159 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
3160 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3161 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3162 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
3163 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3164 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3165 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
3166 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3167 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3168
3169 SND_SOC_DAPM_INPUT("AMIC3"),
3170 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
3171 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3172 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3173
3174 SND_SOC_DAPM_INPUT("AMIC4"),
3175 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
3176 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3177 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3178
3179 SND_SOC_DAPM_INPUT("AMIC5"),
3180 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
3181 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3182
3183 SND_SOC_DAPM_INPUT("AMIC6"),
3184 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
3185 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3186
3187 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
3188 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3189
3190 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
3191 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3192
3193 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
3194 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3195
3196 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
3197 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3198
3199 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
3200 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3201
3202 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
3203 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3204
3205 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
3206 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3207
3208 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
3209 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3210
3211 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
3212 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3213
3214 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
3215 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3216
3217 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
3218 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
3219
3220 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
3221 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
3222 SND_SOC_DAPM_POST_PMD),
3223
3224 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
3225
3226 SND_SOC_DAPM_INPUT("AMIC2"),
3227 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
3228 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3229 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3230 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
3231 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3232 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3233 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
3234 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3235 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3236 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
3237 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3238 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3239 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
3240 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3241 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3242 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
3243 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3244 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3245 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
3246 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3247 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3248 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
3249 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3250 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3251
3252 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
3253 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
3254 0, 0),
3255
3256 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
3257 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
3258 4, 0),
3259
3260 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
3261 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
3262 5, 0),
3263
3264 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
3265 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3266 0, tabla_codec_enable_slimtx,
3267 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3268
3269 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
3270 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3271 0, tabla_codec_enable_slimtx,
3272 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3273
3274 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
3275 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
3276 0, 0, tabla_codec_enable_slimtx,
3277 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3278
3279 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
3280 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
3281 0, 0, tabla_codec_enable_slimtx,
3282 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3283
3284 /* Digital Mic Inputs */
3285 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
3286 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3287 SND_SOC_DAPM_POST_PMD),
3288
3289 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
3290 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3291 SND_SOC_DAPM_POST_PMD),
3292
3293 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
3294 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3295 SND_SOC_DAPM_POST_PMD),
3296
3297 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
3298 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3299 SND_SOC_DAPM_POST_PMD),
3300
3301 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
3302 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3303 SND_SOC_DAPM_POST_PMD),
3304 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
3305 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3306 SND_SOC_DAPM_POST_PMD),
3307
3308 /* Sidetone */
3309 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
3310 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
3311};
3312
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003313static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003314{
3315 u8 bias_msb, bias_lsb;
3316 short bias_value;
3317
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003318 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
3319 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
3320 bias_value = (bias_msb << 8) | bias_lsb;
3321 return bias_value;
3322}
3323
3324static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
3325{
3326 u8 bias_msb, bias_lsb;
3327 short bias_value;
3328
3329 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
3330 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
3331 bias_value = (bias_msb << 8) | bias_lsb;
3332 return bias_value;
3333}
3334
Joonwoo Park0976d012011-12-22 11:48:18 -08003335static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003336{
Joonwoo Park0976d012011-12-22 11:48:18 -08003337 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003338 short bias_value;
3339
Joonwoo Park925914c2012-01-05 13:35:18 -08003340 /* Turn on the override */
3341 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003342 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003343 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3344 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
3345 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003346 usleep_range(tabla->mbhc_data.t_sta_dce,
3347 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003348 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08003349 usleep_range(tabla->mbhc_data.t_dce,
3350 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003351 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003352 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003353 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003354 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3355 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003356 usleep_range(tabla->mbhc_data.t_sta_dce,
3357 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08003358 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3359 usleep_range(tabla->mbhc_data.t_sta,
3360 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003361 bias_value = tabla_codec_read_sta_result(codec);
3362 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3363 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003364 }
Joonwoo Park925914c2012-01-05 13:35:18 -08003365 /* Turn off the override after measuring mic voltage */
3366 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003367
Bradley Rubincb1e2732011-06-23 16:49:20 -07003368 return bias_value;
3369}
3370
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003371static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003372{
3373 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003374 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003375 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003376
Joonwoo Park0976d012011-12-22 11:48:18 -08003377 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003378 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07003379 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003380 }
3381
3382 tabla->mbhc_polling_active = true;
3383
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003384 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003385 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003386 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003387 tabla_codec_enable_clock_block(codec, 1);
3388 }
3389
3390 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
3391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003392 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
3393
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003394 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08003395 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
3396 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07003397
Joonwoo Parkf4267c22012-01-10 13:25:24 -08003398 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003399
3400 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003401 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003402
3403 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
3404 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
3405 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
3406
3407 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003408 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3409 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003410
Joonwoo Park925914c2012-01-05 13:35:18 -08003411 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003412 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3413
Bradley Rubincb1e2732011-06-23 16:49:20 -07003414 tabla_codec_calibrate_hs_polling(codec);
3415
Joonwoo Park0976d012011-12-22 11:48:18 -08003416 bias_value = tabla_codec_sta_dce(codec, 0);
3417 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3418 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003419 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003420
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07003421 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003422}
3423
3424static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
3425 int insertion)
3426{
3427 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003428 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08003429 const struct tabla_mbhc_general_cfg *generic =
3430 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3431 const struct tabla_mbhc_plug_detect_cfg *plug_det =
3432 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003433 u8 wg_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003434
Joonwoo Park0976d012011-12-22 11:48:18 -08003435 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003436 pr_err("Error, no tabla calibration\n");
3437 return -EINVAL;
3438 }
3439
3440 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
3441
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003442 if (insertion) {
3443 /* Make sure mic bias and Mic line schmitt trigger
3444 * are turned OFF
3445 */
3446 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
3447 0x81, 0x01);
3448 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3449 0x90, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003450 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
3451 wg_time += 1;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003452
3453 /* Enable HPH Schmitt Trigger */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003454 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003455 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
Joonwoo Park0976d012011-12-22 11:48:18 -08003456 plug_det->hph_current << 2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003457
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003458 /* Turn off HPH PAs and DAC's during insertion detection to
3459 * avoid false insertion interrupts
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003460 */
3461 if (tabla->mbhc_micbias_switched)
3462 tabla_codec_switch_micbias(codec, 0);
3463 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003464 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003465 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003466 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08003467 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003468 usleep_range(wg_time * 1000, wg_time * 1000);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003469
3470 /* setup for insetion detection */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08003471 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003473 } else {
3474 /* Make sure the HPH schmitt trigger is OFF */
3475 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
3476
3477 /* enable the mic line schmitt trigger */
3478 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08003479 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003480 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3481 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003482 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003483 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
3484 0x10, 0x10);
3485
3486 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003487 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07003488 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003489
3490 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
3491 if (!(tabla->clock_active)) {
3492 tabla_codec_enable_config_mode(codec, 1);
3493 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003494 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08003495 usleep_range(generic->t_shutdown_plug_rem,
3496 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003497 tabla_codec_enable_config_mode(codec, 0);
3498 } else
3499 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07003500 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003501 }
3502
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003503 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003504
3505 /* If central bandgap disabled */
3506 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
3507 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08003508 usleep_range(generic->t_bg_fast_settle,
3509 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003510 central_bias_enabled = 1;
3511 }
3512
3513 /* If LDO_H disabled */
3514 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
3515 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
3516 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08003517 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003518 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
3519
3520 if (central_bias_enabled)
3521 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
3522 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003523
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003524 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
3525 tabla->micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003526
3527 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
3528 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
3529 return 0;
3530}
3531
Joonwoo Park0976d012011-12-22 11:48:18 -08003532static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
3533 s16 vin_mv)
3534{
3535 short diff, zero;
3536 struct tabla_priv *tabla;
3537 u32 mb_mv, in;
3538
3539 tabla = snd_soc_codec_get_drvdata(codec);
3540 mb_mv = tabla->mbhc_data.micb_mv;
3541
3542 if (mb_mv == 0) {
3543 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
3544 return -EINVAL;
3545 }
3546
3547 if (dce) {
3548 diff = tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z;
3549 zero = tabla->mbhc_data.dce_z;
3550 } else {
3551 diff = tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z;
3552 zero = tabla->mbhc_data.sta_z;
3553 }
3554 in = (u32) diff * vin_mv;
3555
3556 return (u16) (in / mb_mv) + zero;
3557}
3558
3559static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
3560 u16 bias_value)
3561{
3562 struct tabla_priv *tabla;
3563 s32 mv;
3564
3565 tabla = snd_soc_codec_get_drvdata(codec);
3566
3567 if (dce) {
3568 mv = ((s32)bias_value - (s32)tabla->mbhc_data.dce_z) *
3569 (s32)tabla->mbhc_data.micb_mv /
3570 (s32)(tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z);
3571 } else {
3572 mv = ((s32)bias_value - (s32)tabla->mbhc_data.sta_z) *
3573 (s32)tabla->mbhc_data.micb_mv /
3574 (s32)(tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z);
3575 }
3576
3577 return mv;
3578}
3579
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003580static void btn0_lpress_fn(struct work_struct *work)
3581{
3582 struct delayed_work *delayed_work;
3583 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08003584 short bias_value;
3585 int dce_mv, sta_mv;
Joonwoo Park816b8e62012-01-23 16:03:21 -08003586 struct tabla *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003587
3588 pr_debug("%s:\n", __func__);
3589
3590 delayed_work = to_delayed_work(work);
3591 tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08003592 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003593
3594 if (tabla) {
3595 if (tabla->button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003596 bias_value = tabla_codec_read_sta_result(tabla->codec);
3597 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
3598 bias_value);
3599 bias_value = tabla_codec_read_dce_result(tabla->codec);
3600 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
3601 bias_value);
3602 pr_debug("%s: Reporting long button press event"
3603 " STA: %d, DCE: %d\n", __func__,
3604 sta_mv, dce_mv);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003605 tabla_snd_soc_jack_report(tabla, tabla->button_jack,
3606 SND_JACK_BTN_0,
3607 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003608 }
3609 } else {
3610 pr_err("%s: Bad tabla private data\n", __func__);
3611 }
3612
Joonwoo Park816b8e62012-01-23 16:03:21 -08003613 tabla_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003614}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003615
Joonwoo Park0976d012011-12-22 11:48:18 -08003616void tabla_mbhc_cal(struct snd_soc_codec *codec)
3617{
3618 struct tabla_priv *tabla;
3619 struct tabla_mbhc_btn_detect_cfg *btn_det;
3620 u8 cfilt_mode, bg_mode;
3621 u8 ncic, nmeas, navg;
3622 u32 mclk_rate;
3623 u32 dce_wait, sta_wait;
3624 u8 *n_cic;
3625
3626 tabla = snd_soc_codec_get_drvdata(codec);
3627
3628 /* First compute the DCE / STA wait times
3629 * depending on tunable parameters.
3630 * The value is computed in microseconds
3631 */
3632 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3633 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003634 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Park0976d012011-12-22 11:48:18 -08003635 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
3636 navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
3637 mclk_rate = tabla->mclk_freq;
Joonwoo Park433149a2012-01-11 09:53:54 -08003638 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
3639 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08003640
3641 tabla->mbhc_data.t_dce = dce_wait;
3642 tabla->mbhc_data.t_sta = sta_wait;
3643
3644 /* LDOH and CFILT are already configured during pdata handling.
3645 * Only need to make sure CFILT and bandgap are in Fast mode.
3646 * Need to restore defaults once calculation is done.
3647 */
3648 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
3649 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
3650 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
3651 0x02);
3652
3653 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
3654 * to perform ADC calibration
3655 */
3656 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
3657 tabla->micbias << 5);
3658 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
3659 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
3660 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
3661 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
3662
3663 /* DCE measurement for 0 volts */
3664 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3665 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3666 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08003667 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
3668 usleep_range(100, 100);
3669 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3670 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3671 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
3672
3673 /* DCE measurment for MB voltage */
3674 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3675 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
3676 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3677 usleep_range(100, 100);
3678 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
3679 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
3680 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
3681
3682 /* Sta measuremnt for 0 volts */
3683 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
3684 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3685 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08003686 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
3687 usleep_range(100, 100);
3688 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3689 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
3690 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
3691
3692 /* STA Measurement for MB Voltage */
3693 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
3694 usleep_range(100, 100);
3695 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
3696 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
3697 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
3698
3699 /* Restore default settings. */
3700 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
3701 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
3702 cfilt_mode);
3703 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
3704
3705 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
3706 usleep_range(100, 100);
3707}
3708
3709void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
3710 const enum tabla_mbhc_btn_det_mem mem)
3711{
3712 void *ret = &btn_det->_v_btn_low;
3713
3714 switch (mem) {
3715 case TABLA_BTN_DET_GAIN:
3716 ret += sizeof(btn_det->_n_cic);
3717 case TABLA_BTN_DET_N_CIC:
3718 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08003719 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08003720 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
3721 case TABLA_BTN_DET_V_BTN_HIGH:
3722 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
3723 case TABLA_BTN_DET_V_BTN_LOW:
3724 /* do nothing */
3725 break;
3726 default:
3727 ret = NULL;
3728 }
3729
3730 return ret;
3731}
3732
3733static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
3734{
3735 struct tabla_priv *tabla;
3736 s16 btn_mv = 0, btn_delta_mv;
3737 struct tabla_mbhc_btn_detect_cfg *btn_det;
3738 struct tabla_mbhc_plug_type_cfg *plug_type;
3739 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08003740 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08003741 int i;
3742
3743 tabla = snd_soc_codec_get_drvdata(codec);
3744 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3745 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
3746
Joonwoo Parkc0672392012-01-11 11:03:14 -08003747 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003748 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003749 tabla->mbhc_data.npoll = 9;
3750 tabla->mbhc_data.nbounce_wait = 30;
3751 } else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003752 tabla->mbhc_data.npoll = 7;
3753 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08003754 }
Joonwoo Park0976d012011-12-22 11:48:18 -08003755
Joonwoo Park433149a2012-01-11 09:53:54 -08003756 tabla->mbhc_data.t_sta_dce = ((1000 * 256) / (tabla->mclk_freq / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08003757 n_ready[tabla_codec_mclk_index(tabla)]) +
3758 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08003759 tabla->mbhc_data.v_ins_hu =
3760 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
3761 tabla->mbhc_data.v_ins_h =
3762 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
3763
3764 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
3765 for (i = 0; i < btn_det->num_btn; i++)
3766 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
3767
3768 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
3769 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
3770
3771 tabla->mbhc_data.v_b1_hu =
3772 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
3773
3774 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
3775
3776 tabla->mbhc_data.v_b1_huc =
3777 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
3778
3779 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
3780 tabla->mbhc_data.v_brl = 0xFA55;
3781
3782 tabla->mbhc_data.v_no_mic =
3783 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
3784}
3785
3786void tabla_mbhc_init(struct snd_soc_codec *codec)
3787{
3788 struct tabla_priv *tabla;
3789 struct tabla_mbhc_general_cfg *generic;
3790 struct tabla_mbhc_btn_detect_cfg *btn_det;
3791 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08003792 u8 *n_cic, *gain;
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08003793 struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08003794
3795 tabla = snd_soc_codec_get_drvdata(codec);
3796 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
3797 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
3798
Joonwoo Park0976d012011-12-22 11:48:18 -08003799 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08003800 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08003801 snd_soc_update_bits(codec,
3802 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
3803 0x07, n);
3804 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
3805 btn_det->c[n]);
3806 }
3807 }
3808 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
3809 btn_det->nc);
3810
3811 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
3812 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08003813 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003814
3815 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08003816 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
3817 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08003818
3819 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
3820 generic->mbhc_nsa << 4);
3821
3822 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
3823 btn_det->n_meas);
3824
3825 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
3826
3827 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
3828
3829 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
3830 btn_det->mbhc_nsc << 3);
3831
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003832 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
3833 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08003834
3835 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
3836}
3837
Patrick Lai64b43262011-12-06 17:29:15 -08003838static bool tabla_mbhc_fw_validate(const struct firmware *fw)
3839{
3840 u32 cfg_offset;
3841 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
3842 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
3843
3844 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
3845 return false;
3846
3847 /* previous check guarantees that there is enough fw data up
3848 * to num_btn
3849 */
3850 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
3851 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
3852 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
3853 return false;
3854
3855 /* previous check guarantees that there is enough fw data up
3856 * to start of impedance detection configuration
3857 */
3858 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
3859 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
3860
3861 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
3862 return false;
3863
3864 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
3865 return false;
3866
3867 return true;
3868}
3869static void mbhc_fw_read(struct work_struct *work)
3870{
3871 struct delayed_work *dwork;
3872 struct tabla_priv *tabla;
3873 struct snd_soc_codec *codec;
3874 const struct firmware *fw;
3875 int ret = -1, retry = 0, rc;
3876
3877 dwork = to_delayed_work(work);
3878 tabla = container_of(dwork, struct tabla_priv,
3879 mbhc_firmware_dwork);
3880 codec = tabla->codec;
3881
3882 while (retry < MBHC_FW_READ_ATTEMPTS) {
3883 retry++;
3884 pr_info("%s:Attempt %d to request MBHC firmware\n",
3885 __func__, retry);
3886 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
3887 codec->dev);
3888
3889 if (ret != 0) {
3890 usleep_range(MBHC_FW_READ_TIMEOUT,
3891 MBHC_FW_READ_TIMEOUT);
3892 } else {
3893 pr_info("%s: MBHC Firmware read succesful\n", __func__);
3894 break;
3895 }
3896 }
3897
3898 if (ret != 0) {
3899 pr_err("%s: Cannot load MBHC firmware use default cal\n",
3900 __func__);
3901 } else if (tabla_mbhc_fw_validate(fw) == false) {
3902 pr_err("%s: Invalid MBHC cal data size use default cal\n",
3903 __func__);
3904 release_firmware(fw);
3905 } else {
3906 tabla->calibration = (void *)fw->data;
3907 tabla->mbhc_fw = fw;
3908 }
3909
3910 tabla->mclk_cb(codec, 1);
3911 tabla_mbhc_init(codec);
3912 tabla_mbhc_cal(codec);
3913 tabla_mbhc_calc_thres(codec);
3914 tabla->mclk_cb(codec, 0);
3915 tabla_codec_calibrate_hs_polling(codec);
3916 rc = tabla_codec_enable_hs_detect(codec, 1);
3917
3918 if (IS_ERR_VALUE(rc))
3919 pr_err("%s: Failed to setup MBHC detection\n", __func__);
3920
3921}
3922
Bradley Rubincb1e2732011-06-23 16:49:20 -07003923int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park0976d012011-12-22 11:48:18 -08003924 struct snd_soc_jack *headset_jack,
3925 struct snd_soc_jack *button_jack,
3926 void *calibration, enum tabla_micbias_num micbias,
3927 int (*mclk_cb_fn) (struct snd_soc_codec*, int),
3928 int read_fw_bin, u32 mclk_rate)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003929{
3930 struct tabla_priv *tabla;
Patrick Lai64b43262011-12-06 17:29:15 -08003931 int rc = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07003932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003933 if (!codec || !calibration) {
3934 pr_err("Error: no codec or calibration\n");
3935 return -EINVAL;
3936 }
Joonwoo Park107edf02012-01-11 11:42:24 -08003937
3938 if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
3939 if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
3940 pr_err("Error: clock rate %dHz is not yet supported\n",
3941 mclk_rate);
3942 else
3943 pr_err("Error: unsupported clock rate %d\n", mclk_rate);
3944 return -EINVAL;
3945 }
3946
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003947 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003948 tabla->headset_jack = headset_jack;
3949 tabla->button_jack = button_jack;
Joonwoo Park0976d012011-12-22 11:48:18 -08003950 tabla->micbias = micbias;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003951 tabla->calibration = calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08003952 tabla->mclk_cb = mclk_cb_fn;
3953 tabla->mclk_freq = mclk_rate;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003954 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003955
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003956 /* Put CFILT in fast mode by default */
3957 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
3958 0x40, TABLA_CFILT_FAST_MODE);
Patrick Lai64b43262011-12-06 17:29:15 -08003959 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07003960 INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
Patrick Lai49efeac2011-11-03 11:01:12 -07003961 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
3962 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
Joonwoo Park0976d012011-12-22 11:48:18 -08003963
3964 if (!read_fw_bin) {
3965 tabla->mclk_cb(codec, 1);
3966 tabla_mbhc_init(codec);
3967 tabla_mbhc_cal(codec);
3968 tabla_mbhc_calc_thres(codec);
3969 tabla->mclk_cb(codec, 0);
3970 tabla_codec_calibrate_hs_polling(codec);
3971 rc = tabla_codec_enable_hs_detect(codec, 1);
3972 } else {
Patrick Lai64b43262011-12-06 17:29:15 -08003973 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
3974 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Joonwoo Park0976d012011-12-22 11:48:18 -08003975 }
Patrick Lai49efeac2011-11-03 11:01:12 -07003976
3977 if (!IS_ERR_VALUE(rc)) {
3978 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
3979 0x10);
3980 tabla_enable_irq(codec->control_data,
3981 TABLA_IRQ_HPH_PA_OCPL_FAULT);
3982 tabla_enable_irq(codec->control_data,
3983 TABLA_IRQ_HPH_PA_OCPR_FAULT);
3984 }
3985
3986 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003987}
3988EXPORT_SYMBOL_GPL(tabla_hs_detect);
3989
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08003990static int tabla_determine_button(const struct tabla_priv *priv,
3991 const s32 bias_mv)
3992{
3993 s16 *v_btn_low, *v_btn_high;
3994 struct tabla_mbhc_btn_detect_cfg *btn_det;
3995 int i, btn = -1;
3996
3997 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
3998 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
3999 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
4000 TABLA_BTN_DET_V_BTN_HIGH);
4001 for (i = 0; i < btn_det->num_btn; i++) {
4002 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
4003 btn = i;
4004 break;
4005 }
4006 }
4007
4008 if (btn == -1)
4009 pr_debug("%s: couldn't find button number for mic mv %d\n",
4010 __func__, bias_mv);
4011
4012 return btn;
4013}
4014
4015static int tabla_get_button_mask(const int btn)
4016{
4017 int mask = 0;
4018 switch (btn) {
4019 case 0:
4020 mask = SND_JACK_BTN_0;
4021 break;
4022 case 1:
4023 mask = SND_JACK_BTN_1;
4024 break;
4025 case 2:
4026 mask = SND_JACK_BTN_2;
4027 break;
4028 case 3:
4029 mask = SND_JACK_BTN_3;
4030 break;
4031 case 4:
4032 mask = SND_JACK_BTN_4;
4033 break;
4034 case 5:
4035 mask = SND_JACK_BTN_5;
4036 break;
4037 case 6:
4038 mask = SND_JACK_BTN_6;
4039 break;
4040 case 7:
4041 mask = SND_JACK_BTN_7;
4042 break;
4043 }
4044 return mask;
4045}
4046
Bradley Rubincb1e2732011-06-23 16:49:20 -07004047static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004048{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004049 int i, mask;
4050 short bias_value_dce;
4051 s32 bias_mv_dce;
4052 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004053 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004054 const struct tabla_mbhc_btn_detect_cfg *d =
4055 TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
4056 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park816b8e62012-01-23 16:03:21 -08004058 struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004059
4060 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4061 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4062
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004063 bias_value_dce = tabla_codec_read_dce_result(codec);
4064 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004065
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004066 /* determine pressed button */
4067 btnmeas[meas++] = tabla_determine_button(priv, bias_mv_dce);
4068 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
4069 meas - 1, bias_value_dce, bias_mv_dce, btnmeas[meas - 1]);
4070 if (d->n_btn_meas == 0)
4071 btn = btnmeas[0];
4072 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
4073 bias_value_dce = tabla_codec_sta_dce(codec, 1);
4074 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
4075 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
4076 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
4077 __func__, meas, bias_value_dce, bias_mv_dce,
4078 btnmeas[meas]);
4079 /* if large enough measurements are collected,
4080 * start to check if last all n_btn_con measurements were
4081 * in same button low/high range */
4082 if (meas + 1 >= d->n_btn_con) {
4083 for (i = 0; i < d->n_btn_con; i++)
4084 if ((btnmeas[meas] < 0) ||
4085 (btnmeas[meas] != btnmeas[meas - i]))
4086 break;
4087 if (i == d->n_btn_con) {
4088 /* button pressed */
4089 btn = btnmeas[meas];
4090 break;
4091 }
4092 }
4093 /* if left measurements are less than n_btn_con,
4094 * it's impossible to find button number */
4095 if ((d->n_btn_meas - meas) < d->n_btn_con)
4096 break;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004097 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004098
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004099 if (btn >= 0) {
4100 mask = tabla_get_button_mask(btn);
4101 priv->buttons_pressed |= mask;
4102
4103 msleep(100);
4104
4105 /* XXX: assuming button 0 has the lowest micbias voltage */
4106 if (btn == 0) {
Joonwoo Park816b8e62012-01-23 16:03:21 -08004107 tabla_lock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004108 if (schedule_delayed_work(&priv->btn0_dwork,
4109 msecs_to_jiffies(400)) == 0) {
4110 WARN(1, "Button pressed twice without release"
4111 "event\n");
Joonwoo Park816b8e62012-01-23 16:03:21 -08004112 tabla_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004113 }
4114 } else {
4115 pr_debug("%s: Reporting short button %d(0x%x) press\n",
4116 __func__, btn, mask);
4117 tabla_snd_soc_jack_report(priv, priv->button_jack, mask,
4118 mask);
4119 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08004120 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004121 pr_debug("%s: bogus button press, too short press?\n",
4122 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004123 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125 return IRQ_HANDLED;
4126}
4127
Bradley Rubincb1e2732011-06-23 16:49:20 -07004128static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004129{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08004130 int ret;
4131 short mb_v;
Joonwoo Park816b8e62012-01-23 16:03:21 -08004132 struct tabla_priv *priv = data;
4133 struct snd_soc_codec *codec = priv->codec;
4134 struct tabla *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004135
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004136 pr_debug("%s: enter\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004137 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004138
Bradley Rubincb1e2732011-06-23 16:49:20 -07004139 if (priv->buttons_pressed & SND_JACK_BTN_0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004140 ret = cancel_delayed_work(&priv->btn0_dwork);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004141 if (ret == 0) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004142 pr_debug("%s: Reporting long button 0 release event\n",
4143 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08004144 if (priv->button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004145 tabla_snd_soc_jack_report(priv,
4146 priv->button_jack, 0,
4147 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004148 } else {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004149 /* if scheduled btn0_dwork is canceled from here,
4150 * we have to unlock from here instead btn0_work */
Joonwoo Park816b8e62012-01-23 16:03:21 -08004151 tabla_unlock_sleep(core);
Joonwoo Park0976d012011-12-22 11:48:18 -08004152 mb_v = tabla_codec_sta_dce(codec, 0);
4153 pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
4154 __func__, mb_v,
4155 tabla_codec_sta_dce_v(codec, 0, mb_v));
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004156
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08004157 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
4158 mb_v > (short)priv->mbhc_data.v_ins_hu)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004159 pr_debug("%s: Fake buttton press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004160 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08004161 else if (priv->button_jack) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004162 pr_debug("%s: Reporting short button 0 "
Joonwoo Park0976d012011-12-22 11:48:18 -08004163 "press and release\n", __func__);
4164 tabla_snd_soc_jack_report(priv,
4165 priv->button_jack,
4166 SND_JACK_BTN_0,
4167 SND_JACK_BTN_0);
4168 tabla_snd_soc_jack_report(priv,
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004169 priv->button_jack, 0,
4170 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004171 }
4172 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004173
Bradley Rubincb1e2732011-06-23 16:49:20 -07004174 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004175 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004176
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004177 if (priv->buttons_pressed) {
4178 pr_debug("%s:reporting button release mask 0x%x\n", __func__,
4179 priv->buttons_pressed);
4180 tabla_snd_soc_jack_report(priv, priv->button_jack, 0,
4181 priv->buttons_pressed);
4182 /* hardware doesn't detect another button press until
4183 * already pressed button is released.
4184 * therefore buttons_pressed has only one button's mask. */
4185 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
4186 }
4187
Bradley Rubin688c66a2011-08-16 12:25:13 -07004188 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004189 return IRQ_HANDLED;
4190}
4191
Bradley Rubincb1e2732011-06-23 16:49:20 -07004192static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
4193{
4194 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08004195 const struct tabla_mbhc_general_cfg *generic =
4196 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004197
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004198 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004199 tabla_codec_enable_config_mode(codec, 1);
4200
4201 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
4202 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004203
Joonwoo Park0976d012011-12-22 11:48:18 -08004204 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
4205
4206 usleep_range(generic->t_shutdown_plug_rem,
4207 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004208
4209 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004210 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004211 tabla_codec_enable_config_mode(codec, 0);
4212
4213 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
4214}
4215
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004216static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
4217{
4218 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004219
4220 tabla_codec_shutdown_hs_removal_detect(codec);
4221
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004222 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004223 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05304224 tabla_codec_disable_clock_block(codec);
4225 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004226 }
4227
4228 tabla->mbhc_polling_active = false;
4229}
4230
Patrick Lai49efeac2011-11-03 11:01:12 -07004231static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
4232{
4233 struct tabla_priv *tabla = data;
4234 struct snd_soc_codec *codec;
4235
4236 pr_info("%s: received HPHL OCP irq\n", __func__);
4237
4238 if (tabla) {
4239 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004240 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
4241 pr_info("%s: retry\n", __func__);
4242 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4243 0x00);
4244 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4245 0x10);
4246 } else {
4247 tabla_disable_irq(codec->control_data,
4248 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4249 tabla->hphlocp_cnt = 0;
4250 tabla->hph_status |= SND_JACK_OC_HPHL;
4251 if (tabla->headset_jack)
4252 tabla_snd_soc_jack_report(tabla,
4253 tabla->headset_jack,
4254 tabla->hph_status,
4255 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07004256 }
4257 } else {
4258 pr_err("%s: Bad tabla private data\n", __func__);
4259 }
4260
4261 return IRQ_HANDLED;
4262}
4263
4264static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
4265{
4266 struct tabla_priv *tabla = data;
4267 struct snd_soc_codec *codec;
4268
4269 pr_info("%s: received HPHR OCP irq\n", __func__);
4270
4271 if (tabla) {
4272 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004273 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
4274 pr_info("%s: retry\n", __func__);
4275 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4276 0x00);
4277 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4278 0x10);
4279 } else {
4280 tabla_disable_irq(codec->control_data,
4281 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4282 tabla->hphrocp_cnt = 0;
4283 tabla->hph_status |= SND_JACK_OC_HPHR;
4284 if (tabla->headset_jack)
4285 tabla_snd_soc_jack_report(tabla,
4286 tabla->headset_jack,
4287 tabla->hph_status,
4288 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07004289 }
4290 } else {
4291 pr_err("%s: Bad tabla private data\n", __func__);
4292 }
4293
4294 return IRQ_HANDLED;
4295}
4296
Joonwoo Parka9444452011-12-08 18:48:27 -08004297static void tabla_sync_hph_state(struct tabla_priv *tabla)
4298{
4299 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4300 &tabla->hph_pa_dac_state)) {
4301 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4302 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4303 1 << 4);
4304 }
4305 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4306 &tabla->hph_pa_dac_state)) {
4307 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4308 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4309 1 << 5);
4310 }
4311
4312 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4313 &tabla->hph_pa_dac_state)) {
4314 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4315 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4316 0xC0, 0xC0);
4317 }
4318 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4319 &tabla->hph_pa_dac_state)) {
4320 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4321 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4322 0xC0, 0xC0);
4323 }
4324}
4325
Bradley Rubincb1e2732011-06-23 16:49:20 -07004326static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
4327{
4328 struct tabla_priv *priv = data;
4329 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08004330 const struct tabla_mbhc_plug_detect_cfg *plug_det =
4331 TABLA_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
Bradley Rubin355611a2011-08-24 14:01:18 -07004332 int ldo_h_on, micb_cfilt_on;
Joonwoo Park0976d012011-12-22 11:48:18 -08004333 short mb_v;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004334 u8 is_removal;
Joonwoo Park0976d012011-12-22 11:48:18 -08004335 int mic_mv;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004336
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004337 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004338 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004339
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004340 is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
4341 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
4342
4343 /* Turn off both HPH and MIC line schmitt triggers */
Joonwoo Park0976d012011-12-22 11:48:18 -08004344 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004345 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004346
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004347 if (priv->mbhc_fake_ins_start &&
4348 time_after(jiffies, priv->mbhc_fake_ins_start +
4349 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004350 pr_debug("%s: fake context interrupt, reset insertion\n",
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004351 __func__);
4352 priv->mbhc_fake_ins_start = 0;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004353 tabla_codec_shutdown_hs_polling(codec);
4354 tabla_codec_enable_hs_detect(codec, 1);
4355 return IRQ_HANDLED;
4356 }
4357
Bradley Rubin355611a2011-08-24 14:01:18 -07004358 ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
Joonwoo Park0976d012011-12-22 11:48:18 -08004359 micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
4360 & 0x80;
Bradley Rubin355611a2011-08-24 14:01:18 -07004361
4362 if (!ldo_h_on)
4363 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
4364 if (!micb_cfilt_on)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004365 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08004366 0x80, 0x80);
4367 if (plug_det->t_ins_complete > 20)
4368 msleep(plug_det->t_ins_complete);
4369 else
4370 usleep_range(plug_det->t_ins_complete * 1000,
4371 plug_det->t_ins_complete * 1000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004372
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004373 if (!ldo_h_on)
4374 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
4375 if (!micb_cfilt_on)
4376 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08004377 0x80, 0x0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004378
4379 if (is_removal) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004380 /*
4381 * If headphone is removed while playback is in progress,
4382 * it is possible that micbias will be switched to VDDIO.
4383 */
4384 if (priv->mbhc_micbias_switched)
4385 tabla_codec_switch_micbias(codec, 0);
Patrick Lai72aa4da2011-12-08 12:38:18 -08004386 priv->hph_status &= ~SND_JACK_HEADPHONE;
Joonwoo Parka9444452011-12-08 18:48:27 -08004387
4388 /* If headphone PA is on, check if userspace receives
4389 * removal event to sync-up PA's state */
4390 if (tabla_is_hph_pa_on(codec)) {
4391 set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
4392 set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
4393 }
4394
4395 if (tabla_is_hph_dac_on(codec, 1))
4396 set_bit(TABLA_HPHL_DAC_OFF_ACK,
4397 &priv->hph_pa_dac_state);
4398 if (tabla_is_hph_dac_on(codec, 0))
4399 set_bit(TABLA_HPHR_DAC_OFF_ACK,
4400 &priv->hph_pa_dac_state);
4401
Bradley Rubincb1e2732011-06-23 16:49:20 -07004402 if (priv->headset_jack) {
4403 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004404 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4405 priv->hph_status,
4406 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004407 }
4408 tabla_codec_shutdown_hs_removal_detect(codec);
4409 tabla_codec_enable_hs_detect(codec, 1);
4410 return IRQ_HANDLED;
4411 }
4412
Joonwoo Park0976d012011-12-22 11:48:18 -08004413 mb_v = tabla_codec_setup_hs_polling(codec);
4414 mic_mv = tabla_codec_sta_dce_v(codec, 0, mb_v);
Bradley Rubin355611a2011-08-24 14:01:18 -07004415
Joonwoo Park0976d012011-12-22 11:48:18 -08004416 if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004417 pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
4418 "STA : %d,%d\n", __func__,
4419 (priv->mbhc_fake_ins_start ?
4420 jiffies_to_msecs(jiffies -
4421 priv->mbhc_fake_ins_start) :
4422 0),
4423 mb_v, mic_mv);
4424 if (time_after(jiffies,
4425 priv->mbhc_fake_ins_start +
4426 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
4427 /* Disable HPH trigger and enable MIC line trigger */
4428 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
4429 0x00);
4430 snd_soc_update_bits(codec,
4431 priv->mbhc_bias_regs.mbhc_reg, 0x60,
4432 plug_det->mic_current << 5);
4433 snd_soc_update_bits(codec,
4434 priv->mbhc_bias_regs.mbhc_reg,
4435 0x80, 0x80);
4436 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4437 snd_soc_update_bits(codec,
4438 priv->mbhc_bias_regs.mbhc_reg,
4439 0x10, 0x10);
4440 } else {
4441 if (priv->mbhc_fake_ins_start == 0)
4442 priv->mbhc_fake_ins_start = jiffies;
4443 /* Setup normal insert detection
4444 * Enable HPH Schmitt Trigger
4445 */
4446 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH,
4447 0x13 | 0x0C,
4448 0x13 | plug_det->hph_current << 2);
4449 }
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004450 /* Setup for insertion detection */
4451 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004452 tabla_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4453 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4454
Joonwoo Park0976d012011-12-22 11:48:18 -08004455 } else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
4456 pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
4457 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004458 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07004459 priv->hph_status |= SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004460 if (priv->headset_jack) {
4461 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08004462 SND_JACK_HEADPHONE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004463 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4464 priv->hph_status,
4465 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004466 }
4467 tabla_codec_shutdown_hs_polling(codec);
4468 tabla_codec_enable_hs_detect(codec, 0);
Joonwoo Parka9444452011-12-08 18:48:27 -08004469 tabla_sync_hph_state(priv);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004470 } else {
Joonwoo Park0976d012011-12-22 11:48:18 -08004471 pr_debug("%s: Headset detected, mb_v: %d,%d\n",
4472 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004473 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07004474 priv->hph_status |= SND_JACK_HEADSET;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004475 if (priv->headset_jack) {
4476 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08004477 SND_JACK_HEADSET);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004478 tabla_snd_soc_jack_report(priv, priv->headset_jack,
4479 priv->hph_status,
4480 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004481 }
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004482 /* avoid false button press detect */
4483 msleep(50);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004484 tabla_codec_start_hs_polling(codec);
Joonwoo Parka9444452011-12-08 18:48:27 -08004485 tabla_sync_hph_state(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004486 }
4487
4488 return IRQ_HANDLED;
4489}
4490
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004491static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
4492{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004493 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004494 struct tabla_priv *priv = data;
4495 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08004496 const struct tabla_mbhc_general_cfg *generic =
4497 TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004498 int fake_removal = 0;
4499 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004501 pr_debug("%s: enter, removal interrupt\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004502 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4503 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07004504 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004505
Joonwoo Park0976d012011-12-22 11:48:18 -08004506 usleep_range(generic->t_shutdown_plug_rem,
4507 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004508
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004509 do {
4510 bias_value = tabla_codec_sta_dce(codec, 1);
4511 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
4512 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
4513 if (bias_value < (short)priv->mbhc_data.v_ins_h) {
4514 fake_removal = 1;
4515 break;
4516 }
4517 min_us -= priv->mbhc_data.t_dce;
4518 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004519
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004520 if (fake_removal) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004521 pr_debug("False alarm, headset not actually removed\n");
4522 tabla_codec_start_hs_polling(codec);
4523 } else {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004524 /*
4525 * If this removal is not false, first check the micbias
4526 * switch status and switch it to LDOH if it is already
4527 * switched to VDDIO.
4528 */
4529 if (priv->mbhc_micbias_switched)
4530 tabla_codec_switch_micbias(codec, 0);
Patrick Lai49efeac2011-11-03 11:01:12 -07004531 priv->hph_status &= ~SND_JACK_HEADSET;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004532 if (priv->headset_jack) {
4533 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004534 tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
4535 TABLA_JACK_MASK);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004536 }
4537 tabla_codec_shutdown_hs_polling(codec);
4538
4539 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004540 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004542 return IRQ_HANDLED;
4543}
4544
4545static unsigned long slimbus_value;
4546
4547static irqreturn_t tabla_slimbus_irq(int irq, void *data)
4548{
4549 struct tabla_priv *priv = data;
4550 struct snd_soc_codec *codec = priv->codec;
4551 int i, j;
4552 u8 val;
4553
4554 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++) {
4555 slimbus_value = tabla_interface_reg_read(codec->control_data,
4556 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
4557 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
4558 val = tabla_interface_reg_read(codec->control_data,
4559 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
4560 if (val & 0x1)
4561 pr_err_ratelimited("overflow error on port %x,"
4562 " value %x\n", i*8 + j, val);
4563 if (val & 0x2)
4564 pr_err_ratelimited("underflow error on port %x,"
4565 " value %x\n", i*8 + j, val);
4566 }
4567 tabla_interface_reg_write(codec->control_data,
4568 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
4569 }
4570
4571 return IRQ_HANDLED;
4572}
4573
Patrick Lai3043fba2011-08-01 14:15:57 -07004574
4575static int tabla_handle_pdata(struct tabla_priv *tabla)
4576{
4577 struct snd_soc_codec *codec = tabla->codec;
4578 struct tabla_pdata *pdata = tabla->pdata;
4579 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05304580 u8 leg_mode = pdata->amic_settings.legacy_mode;
4581 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4582 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4583 u8 flag = pdata->amic_settings.use_pdata;
4584 u8 i = 0, j = 0;
4585 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07004586
4587 if (!pdata) {
4588 rc = -ENODEV;
4589 goto done;
4590 }
4591
4592 /* Make sure settings are correct */
4593 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
4594 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
4595 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
4596 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
4597 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
4598 rc = -EINVAL;
4599 goto done;
4600 }
4601
4602 /* figure out k value */
4603 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
4604 pdata->micbias.cfilt1_mv);
4605 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
4606 pdata->micbias.cfilt2_mv);
4607 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
4608 pdata->micbias.cfilt3_mv);
4609
4610 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
4611 rc = -EINVAL;
4612 goto done;
4613 }
4614
4615 /* Set voltage level and always use LDO */
4616 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
4617 (pdata->micbias.ldoh_v << 2));
4618
4619 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
4620 (k1 << 2));
4621 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
4622 (k2 << 2));
4623 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
4624 (k3 << 2));
4625
4626 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
4627 (pdata->micbias.bias1_cfilt_sel << 5));
4628 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
4629 (pdata->micbias.bias2_cfilt_sel << 5));
4630 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
4631 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004632 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
4633 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07004634
Santosh Mardi22920282011-10-26 02:38:40 +05304635 for (i = 0; i < 6; j++, i += 2) {
4636 if (flag & (0x01 << i)) {
4637 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
4638 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4639 val_txfe = val_txfe |
4640 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4641 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4642 0x10, value);
4643 snd_soc_update_bits(codec,
4644 TABLA_A_TX_1_2_TEST_EN + j * 10,
4645 0x30, val_txfe);
4646 }
4647 if (flag & (0x01 << (i + 1))) {
4648 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
4649 val_txfe = (txfe_bypass &
4650 (0x01 << (i + 1))) ? 0x02 : 0x00;
4651 val_txfe |= (txfe_buff &
4652 (0x01 << (i + 1))) ? 0x01 : 0x00;
4653 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
4654 0x01, value);
4655 snd_soc_update_bits(codec,
4656 TABLA_A_TX_1_2_TEST_EN + j * 10,
4657 0x03, val_txfe);
4658 }
4659 }
4660 if (flag & 0x40) {
4661 value = (leg_mode & 0x40) ? 0x10 : 0x00;
4662 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
4663 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
4664 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
4665 0x13, value);
4666 }
Patrick Lai49efeac2011-11-03 11:01:12 -07004667
4668 if (pdata->ocp.use_pdata) {
4669 /* not defined in CODEC specification */
4670 if (pdata->ocp.hph_ocp_limit == 1 ||
4671 pdata->ocp.hph_ocp_limit == 5) {
4672 rc = -EINVAL;
4673 goto done;
4674 }
4675 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
4676 0x0F, pdata->ocp.num_attempts);
4677 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
4678 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4679 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
4680 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4681 }
Patrick Lai3043fba2011-08-01 14:15:57 -07004682done:
4683 return rc;
4684}
4685
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004686static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
4687
4688 /* Tabla 1.1 MICBIAS changes */
4689 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
4690 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
4691 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004692
4693 /* Tabla 1.1 HPH changes */
4694 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
4695 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
4696
4697 /* Tabla 1.1 EAR PA changes */
4698 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
4699 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
4700 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
4701
4702 /* Tabla 1.1 Lineout_5 Changes */
4703 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
4704
4705 /* Tabla 1.1 RX Changes */
4706 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
4707 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
4708 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
4709 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
4710 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
4711 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
4712 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
4713
4714 /* Tabla 1.1 RX1 and RX2 Changes */
4715 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
4716 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
4717
4718 /* Tabla 1.1 RX3 to RX7 Changes */
4719 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
4720 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
4721 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
4722 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
4723 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
4724
4725 /* Tabla 1.1 CLASSG Changes */
4726 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
4727};
4728
4729static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004730 /* Tabla 2.0 MICBIAS changes */
4731 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
4732};
4733
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004734static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
4735 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
4736};
4737
4738static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
4739 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
4740};
4741
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004742static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
4743{
4744 u32 i;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004745 struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004746
4747 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
4748 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
4749 tabla_1_1_reg_defaults[i].val);
4750
4751 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
4752 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
4753 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004754
4755 if (TABLA_IS_1_X(tabla_core->version)) {
4756 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
4757 i++)
4758 snd_soc_write(codec,
4759 tabla_1_x_only_reg_2_0_defaults[i].reg,
4760 tabla_1_x_only_reg_2_0_defaults[i].val);
4761 } else {
4762 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
4763 snd_soc_write(codec,
4764 tabla_2_only_reg_2_0_defaults[i].reg,
4765 tabla_2_only_reg_2_0_defaults[i].val);
4766 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004767}
4768
4769static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08004770 /* Initialize current threshold to 350MA
4771 * number of wait and run cycles to 4096
4772 */
Patrick Lai49efeac2011-11-03 11:01:12 -07004773 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08004774 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004775
Santosh Mardi32171012011-10-28 23:32:06 +05304776 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
4777
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004778 /* Initialize gain registers to use register gain */
4779 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
4780 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
4781 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
4782 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
4783 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
4784 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
4785
4786 /* Initialize mic biases to differential mode */
4787 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
4788 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
4789 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004790
4791 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
4792
4793 /* Use 16 bit sample size for TX1 to TX6 */
4794 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
4795 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4796 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4797 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4798 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
4799 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
4800
4801 /* Use 16 bit sample size for TX7 to TX10 */
4802 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
4803 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
4804 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
4805 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
4806
4807 /* Use 16 bit sample size for RX */
4808 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4809 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
4810
4811 /*enable HPF filter for TX paths */
4812 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
4813 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
4814 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
4815 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
4816 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
4817 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
4818 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
4819 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
4820 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
4821 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
4822};
4823
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004824static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
4825 /* Initialize mic biases to differential mode */
4826 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
4827};
4828
4829static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
4830 /* Initialize mic biases to differential mode */
4831 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
4832};
4833
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004834static void tabla_codec_init_reg(struct snd_soc_codec *codec)
4835{
4836 u32 i;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004837 struct tabla *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004838
4839 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
4840 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
4841 tabla_codec_reg_init_val[i].mask,
4842 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004843 if (TABLA_IS_1_X(tabla_core->version)) {
4844 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
4845 snd_soc_update_bits(codec,
4846 tabla_1_x_codec_reg_init_val[i].reg,
4847 tabla_1_x_codec_reg_init_val[i].mask,
4848 tabla_1_x_codec_reg_init_val[i].val);
4849 } else {
4850 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
4851 i++)
4852 snd_soc_update_bits(codec,
4853 tabla_2_higher_codec_reg_init_val[i].reg,
4854 tabla_2_higher_codec_reg_init_val[i].mask,
4855 tabla_2_higher_codec_reg_init_val[i].val);
4856 }
4857}
4858
4859static void tabla_update_reg_address(struct tabla_priv *priv)
4860{
4861 struct tabla *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
4862 struct tabla_reg_address *reg_addr = &priv->reg_addr;
4863
4864 if (TABLA_IS_1_X(tabla_core->version)) {
4865 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
4866 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
4867 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
4868 } else if (TABLA_IS_2_0(tabla_core->version)) {
4869 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
4870 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
4871 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
4872 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07004873}
4874
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004875static int tabla_codec_probe(struct snd_soc_codec *codec)
4876{
4877 struct tabla *control;
4878 struct tabla_priv *tabla;
4879 struct snd_soc_dapm_context *dapm = &codec->dapm;
4880 int ret = 0;
4881 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004882 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004883
4884 codec->control_data = dev_get_drvdata(codec->dev->parent);
4885 control = codec->control_data;
4886
4887 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
4888 if (!tabla) {
4889 dev_err(codec->dev, "Failed to allocate private data\n");
4890 return -ENOMEM;
4891 }
4892
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004893 /* Make sure mbhc micbias register addresses are zeroed out */
4894 memset(&tabla->mbhc_bias_regs, 0,
4895 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004896 tabla->cfilt_k_value = 0;
4897 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004898
Joonwoo Park0976d012011-12-22 11:48:18 -08004899 /* Make sure mbhc intenal calibration data is zeroed out */
4900 memset(&tabla->mbhc_data, 0,
4901 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08004902 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08004903 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
4904 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004905 snd_soc_codec_set_drvdata(codec, tabla);
4906
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004907 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004908 tabla->bandgap_type = TABLA_BANDGAP_OFF;
4909 tabla->clock_active = false;
4910 tabla->config_mode_active = false;
4911 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004912 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07004913 tabla->no_mic_headset_override = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004914 tabla->codec = codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07004915 tabla->pdata = dev_get_platdata(codec->dev->parent);
Santosh Mardie15e2302011-11-15 10:39:23 +05304916 tabla->intf_type = tabla_get_intf_type();
Patrick Lai3043fba2011-08-01 14:15:57 -07004917
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004918 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05304919 tabla_update_reg_defaults(codec);
4920 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05304921 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07004922 if (IS_ERR_VALUE(ret)) {
4923 pr_err("%s: bad pdata\n", __func__);
4924 goto err_pdata;
4925 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004927 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004928 ARRAY_SIZE(tabla_snd_controls));
4929 if (TABLA_IS_1_X(control->version))
4930 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
4931 ARRAY_SIZE(tabla_1_x_snd_controls));
4932 else
4933 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
4934 ARRAY_SIZE(tabla_2_higher_snd_controls));
4935
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004936 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004937 ARRAY_SIZE(tabla_dapm_widgets));
4938 if (TABLA_IS_1_X(control->version))
4939 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
4940 ARRAY_SIZE(tabla_1_x_dapm_widgets));
4941 else
4942 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
4943 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
4944
Santosh Mardie15e2302011-11-15 10:39:23 +05304945 if (tabla->intf_type == TABLA_INTERFACE_TYPE_I2C) {
4946 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
4947 ARRAY_SIZE(tabla_dapm_i2s_widgets));
4948 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
4949 ARRAY_SIZE(audio_i2s_map));
4950 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004951 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004952
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004953 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004954 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004955 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
4956 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004957 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004958 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004959 } else {
4960 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004961 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004962 goto err_pdata;
4963 }
4964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004965 snd_soc_dapm_sync(dapm);
4966
4967 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
4968 tabla_hs_insert_irq, "Headset insert detect", tabla);
4969 if (ret) {
4970 pr_err("%s: Failed to request irq %d\n", __func__,
4971 TABLA_IRQ_MBHC_INSERTION);
4972 goto err_insert_irq;
4973 }
4974 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
4975
4976 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
4977 tabla_hs_remove_irq, "Headset remove detect", tabla);
4978 if (ret) {
4979 pr_err("%s: Failed to request irq %d\n", __func__,
4980 TABLA_IRQ_MBHC_REMOVAL);
4981 goto err_remove_irq;
4982 }
4983 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4984
4985 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004986 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004987 if (ret) {
4988 pr_err("%s: Failed to request irq %d\n", __func__,
4989 TABLA_IRQ_MBHC_POTENTIAL);
4990 goto err_potential_irq;
4991 }
4992 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4993
Bradley Rubincb1e2732011-06-23 16:49:20 -07004994 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
4995 tabla_release_handler, "Button Release detect", tabla);
4996 if (ret) {
4997 pr_err("%s: Failed to request irq %d\n", __func__,
4998 TABLA_IRQ_MBHC_RELEASE);
4999 goto err_release_irq;
5000 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07005001 tabla_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005003 ret = tabla_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
5004 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
5005 if (ret) {
5006 pr_err("%s: Failed to request irq %d\n", __func__,
5007 TABLA_IRQ_SLIMBUS);
5008 goto err_slimbus_irq;
5009 }
5010
5011 for (i = 0; i < TABLA_SLIM_NUM_PORT_REG; i++)
5012 tabla_interface_reg_write(codec->control_data,
5013 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
5014
Patrick Lai49efeac2011-11-03 11:01:12 -07005015 ret = tabla_request_irq(codec->control_data,
5016 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
5017 "HPH_L OCP detect", tabla);
5018 if (ret) {
5019 pr_err("%s: Failed to request irq %d\n", __func__,
5020 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5021 goto err_hphl_ocp_irq;
5022 }
Patrick Lai92032be2011-12-19 14:14:25 -08005023 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07005024
5025 ret = tabla_request_irq(codec->control_data,
5026 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
5027 "HPH_R OCP detect", tabla);
5028 if (ret) {
5029 pr_err("%s: Failed to request irq %d\n", __func__,
5030 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5031 goto err_hphr_ocp_irq;
5032 }
Patrick Lai92032be2011-12-19 14:14:25 -08005033 tabla_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005034 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
5035 switch (tabla_dai[i].id) {
5036 case AIF1_PB:
5037 ch_cnt = tabla_dai[i].playback.channels_max;
5038 break;
5039 case AIF1_CAP:
5040 ch_cnt = tabla_dai[i].capture.channels_max;
5041 break;
5042 default:
5043 continue;
5044 }
5045 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
5046 ch_cnt), GFP_KERNEL);
5047 }
Patrick Lai49efeac2011-11-03 11:01:12 -07005048
Bradley Rubincb3950a2011-08-18 13:07:26 -07005049#ifdef CONFIG_DEBUG_FS
5050 debug_tabla_priv = tabla;
5051#endif
5052
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005053 return ret;
5054
Patrick Lai49efeac2011-11-03 11:01:12 -07005055err_hphr_ocp_irq:
5056 tabla_free_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
5057err_hphl_ocp_irq:
5058 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005059err_slimbus_irq:
Bradley Rubincb1e2732011-06-23 16:49:20 -07005060 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
5061err_release_irq:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005062 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
5063err_potential_irq:
5064 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
5065err_remove_irq:
5066 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
5067err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07005068err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005069 kfree(tabla);
5070 return ret;
5071}
5072static int tabla_codec_remove(struct snd_soc_codec *codec)
5073{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005074 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005075 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5076 tabla_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005077 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005078 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
5079 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
5080 tabla_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
5081 tabla_codec_disable_clock_block(codec);
5082 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08005083 if (tabla->mbhc_fw)
5084 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005085 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
5086 kfree(tabla->dai[i].ch_num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005087 kfree(tabla);
5088 return 0;
5089}
5090static struct snd_soc_codec_driver soc_codec_dev_tabla = {
5091 .probe = tabla_codec_probe,
5092 .remove = tabla_codec_remove,
5093 .read = tabla_read,
5094 .write = tabla_write,
5095
5096 .readable_register = tabla_readable,
5097 .volatile_register = tabla_volatile,
5098
5099 .reg_cache_size = TABLA_CACHE_SIZE,
5100 .reg_cache_default = tabla_reg_defaults,
5101 .reg_word_size = 1,
5102};
Bradley Rubincb3950a2011-08-18 13:07:26 -07005103
5104#ifdef CONFIG_DEBUG_FS
5105static struct dentry *debugfs_poke;
5106
5107static int codec_debug_open(struct inode *inode, struct file *file)
5108{
5109 file->private_data = inode->i_private;
5110 return 0;
5111}
5112
5113static ssize_t codec_debug_write(struct file *filp,
5114 const char __user *ubuf, size_t cnt, loff_t *ppos)
5115{
5116 char lbuf[32];
5117 char *buf;
5118 int rc;
5119
5120 if (cnt > sizeof(lbuf) - 1)
5121 return -EINVAL;
5122
5123 rc = copy_from_user(lbuf, ubuf, cnt);
5124 if (rc)
5125 return -EFAULT;
5126
5127 lbuf[cnt] = '\0';
5128 buf = (char *)lbuf;
5129 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
5130 ? false : true;
Bradley Rubincb3950a2011-08-18 13:07:26 -07005131 return rc;
5132}
5133
5134static const struct file_operations codec_debug_ops = {
5135 .open = codec_debug_open,
5136 .write = codec_debug_write,
5137};
5138#endif
5139
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005140#ifdef CONFIG_PM
5141static int tabla_suspend(struct device *dev)
5142{
Joonwoo Park816b8e62012-01-23 16:03:21 -08005143 dev_dbg(dev, "%s: system suspend\n", __func__);
5144 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005145}
5146
5147static int tabla_resume(struct device *dev)
5148{
Joonwoo Park816b8e62012-01-23 16:03:21 -08005149 dev_dbg(dev, "%s: system resume\n", __func__);
5150 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005151}
5152
5153static const struct dev_pm_ops tabla_pm_ops = {
5154 .suspend = tabla_suspend,
5155 .resume = tabla_resume,
5156};
5157#endif
5158
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005159static int __devinit tabla_probe(struct platform_device *pdev)
5160{
Santosh Mardie15e2302011-11-15 10:39:23 +05305161 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07005162#ifdef CONFIG_DEBUG_FS
5163 debugfs_poke = debugfs_create_file("TRRS",
5164 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
5165
5166#endif
Santosh Mardie15e2302011-11-15 10:39:23 +05305167 if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_SLIMBUS)
5168 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
5169 tabla_dai, ARRAY_SIZE(tabla_dai));
5170 else if (tabla_get_intf_type() == TABLA_INTERFACE_TYPE_I2C)
5171 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
5172 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
5173 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005174}
5175static int __devexit tabla_remove(struct platform_device *pdev)
5176{
5177 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07005178
5179#ifdef CONFIG_DEBUG_FS
5180 debugfs_remove(debugfs_poke);
5181#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005182 return 0;
5183}
5184static struct platform_driver tabla_codec_driver = {
5185 .probe = tabla_probe,
5186 .remove = tabla_remove,
5187 .driver = {
5188 .name = "tabla_codec",
5189 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005190#ifdef CONFIG_PM
5191 .pm = &tabla_pm_ops,
5192#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005193 },
5194};
5195
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005196static struct platform_driver tabla1x_codec_driver = {
5197 .probe = tabla_probe,
5198 .remove = tabla_remove,
5199 .driver = {
5200 .name = "tabla1x_codec",
5201 .owner = THIS_MODULE,
5202#ifdef CONFIG_PM
5203 .pm = &tabla_pm_ops,
5204#endif
5205 },
5206};
5207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005208static int __init tabla_codec_init(void)
5209{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005210 int rtn = platform_driver_register(&tabla_codec_driver);
5211 if (rtn == 0) {
5212 rtn = platform_driver_register(&tabla1x_codec_driver);
5213 if (rtn != 0)
5214 platform_driver_unregister(&tabla_codec_driver);
5215 }
5216 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005217}
5218
5219static void __exit tabla_codec_exit(void)
5220{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005221 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005222 platform_driver_unregister(&tabla_codec_driver);
5223}
5224
5225module_init(tabla_codec_init);
5226module_exit(tabla_codec_exit);
5227
5228MODULE_DESCRIPTION("Tabla codec driver");
5229MODULE_VERSION("1.0");
5230MODULE_LICENSE("GPL v2");