blob: 828aacaa4d115c151ed6ba397561f3d4a7c67843 [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>
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053021#include <linux/mfd/wcd9xxx/core.h>
22#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
23#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
24#include <linux/mfd/wcd9xxx/pdata.h>
Santosh Mardie15e2302011-11-15 10:39:23 +053025#include <sound/pcm.h>
26#include <sound/pcm_params.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#include <sound/soc.h>
28#include <sound/soc-dapm.h>
29#include <sound/tlv.h>
30#include <linux/bitops.h>
31#include <linux/delay.h>
Kuirong Wanga545e722012-02-06 19:12:54 -080032#include <linux/pm_runtime.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070033#include "wcd9310.h"
34
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070035#define WCD9310_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
36 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
37
38#define NUM_DECIMATORS 10
39#define NUM_INTERPOLATORS 7
40#define BITS_PER_REG 8
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080041#define TABLA_CFILT_FAST_MODE 0x00
42#define TABLA_CFILT_SLOW_MODE 0x40
Patrick Lai64b43262011-12-06 17:29:15 -080043#define MBHC_FW_READ_ATTEMPTS 15
44#define MBHC_FW_READ_TIMEOUT 2000000
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070045
Patrick Lai49efeac2011-11-03 11:01:12 -070046#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
47
Santosh Mardie15e2302011-11-15 10:39:23 +053048#define TABLA_I2S_MASTER_MODE_MASK 0x08
49
Patrick Laic7cae882011-11-18 11:52:49 -080050#define TABLA_OCP_ATTEMPT 1
51
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080052#define AIF1_PB 1
53#define AIF1_CAP 2
Neema Shettyd3a89262012-02-16 10:23:50 -080054#define AIF2_PB 3
55#define NUM_CODEC_DAIS 3
Kuirong Wang0f8ade32012-02-27 16:29:45 -080056#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080057
58struct tabla_codec_dai_data {
59 u32 rate;
60 u32 *ch_num;
61 u32 ch_act;
62 u32 ch_tot;
63};
64
Joonwoo Park0976d012011-12-22 11:48:18 -080065#define TABLA_MCLK_RATE_12288KHZ 12288000
66#define TABLA_MCLK_RATE_9600KHZ 9600000
67
Joonwoo Parkf4267c22012-01-10 13:25:24 -080068#define TABLA_FAKE_INS_THRESHOLD_MS 2500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -080069#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
Joonwoo Parkf4267c22012-01-10 13:25:24 -080070
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070071static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
72static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
73static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080074static struct snd_soc_dai_driver tabla_dai[];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -080075static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070076
77enum tabla_bandgap_type {
78 TABLA_BANDGAP_OFF = 0,
79 TABLA_BANDGAP_AUDIO_MODE,
80 TABLA_BANDGAP_MBHC_MODE,
81};
82
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070083struct mbhc_micbias_regs {
84 u16 cfilt_val;
85 u16 cfilt_ctl;
86 u16 mbhc_reg;
87 u16 int_rbias;
88 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080089 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -070090};
91
Ben Romberger1f045a72011-11-04 10:14:57 -070092/* Codec supports 2 IIR filters */
93enum {
94 IIR1 = 0,
95 IIR2,
96 IIR_MAX,
97};
98/* Codec supports 5 bands */
99enum {
100 BAND1 = 0,
101 BAND2,
102 BAND3,
103 BAND4,
104 BAND5,
105 BAND_MAX,
106};
107
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800108enum {
109 COMPANDER_1 = 0,
110 COMPANDER_2,
111 COMPANDER_MAX,
112};
113
114enum {
115 COMPANDER_FS_8KHZ = 0,
116 COMPANDER_FS_16KHZ,
117 COMPANDER_FS_32KHZ,
118 COMPANDER_FS_48KHZ,
119 COMPANDER_FS_MAX,
120};
121
Joonwoo Parka9444452011-12-08 18:48:27 -0800122/* Flags to track of PA and DAC state.
123 * PA and DAC should be tracked separately as AUXPGA loopback requires
124 * only PA to be turned on without DAC being on. */
125enum tabla_priv_ack_flags {
126 TABLA_HPHL_PA_OFF_ACK = 0,
127 TABLA_HPHR_PA_OFF_ACK,
128 TABLA_HPHL_DAC_OFF_ACK,
129 TABLA_HPHR_DAC_OFF_ACK
130};
131
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800132
133struct comp_sample_dependent_params {
134 u32 peak_det_timeout;
135 u32 rms_meter_div_fact;
136 u32 rms_meter_resamp_fact;
137};
138
Joonwoo Park0976d012011-12-22 11:48:18 -0800139/* Data used by MBHC */
140struct mbhc_internal_cal_data {
141 u16 dce_z;
142 u16 dce_mb;
143 u16 sta_z;
144 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800145 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800146 u32 t_dce;
147 u32 t_sta;
148 u32 micb_mv;
149 u16 v_ins_hu;
150 u16 v_ins_h;
151 u16 v_b1_hu;
152 u16 v_b1_h;
153 u16 v_b1_huc;
154 u16 v_brh;
155 u16 v_brl;
156 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800157 u8 npoll;
158 u8 nbounce_wait;
159};
160
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800161struct tabla_reg_address {
162 u16 micb_4_ctl;
163 u16 micb_4_int_rbias;
164 u16 micb_4_mbhc;
165};
166
Bradley Rubin229c6a52011-07-12 16:18:48 -0700167struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800169 struct tabla_reg_address reg_addr;
Joonwoo Park0976d012011-12-22 11:48:18 -0800170 u32 mclk_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700171 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700172 u32 cfilt1_cnt;
173 u32 cfilt2_cnt;
174 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700175 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700176 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700177 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178 bool clock_active;
179 bool config_mode_active;
180 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800181 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700182 int buttons_pressed;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700183
Joonwoo Park0976d012011-12-22 11:48:18 -0800184 enum tabla_micbias_num micbias;
185 /* void* calibration contains:
186 * struct tabla_mbhc_general_cfg generic;
187 * struct tabla_mbhc_plug_detect_cfg plug_det;
188 * struct tabla_mbhc_plug_type_cfg plug_type;
189 * struct tabla_mbhc_btn_detect_cfg btn_det;
190 * struct tabla_mbhc_imped_detect_cfg imped_det;
191 * Note: various size depends on btn_det->num_btn
192 */
193 void *calibration;
194 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195
Bradley Rubincb1e2732011-06-23 16:49:20 -0700196 struct snd_soc_jack *headset_jack;
197 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700198
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530199 struct wcd9xxx_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700200 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700201
202 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700203 /* Delayed work to report long button press */
204 struct delayed_work btn0_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700205
206 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700207 u8 cfilt_k_value;
208 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700209
Joonwoo Parka9444452011-12-08 18:48:27 -0800210 /* track PA/DAC state */
211 unsigned long hph_pa_dac_state;
212
Santosh Mardie15e2302011-11-15 10:39:23 +0530213 /*track tabla interface type*/
214 u8 intf_type;
215
Patrick Lai49efeac2011-11-03 11:01:12 -0700216 u32 hph_status; /* track headhpone status */
217 /* define separate work for left and right headphone OCP to avoid
218 * additional checking on which OCP event to report so no locking
219 * to ensure synchronization is required
220 */
221 struct work_struct hphlocp_work; /* reporting left hph ocp off */
222 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800223
Patrick Laic7cae882011-11-18 11:52:49 -0800224 u8 hphlocp_cnt; /* headphone left ocp retry */
225 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800226
227 /* Callback function to enable MCLK */
228 int (*mclk_cb) (struct snd_soc_codec*, int);
Patrick Lai64b43262011-12-06 17:29:15 -0800229
230 /* Work to perform MBHC Firmware Read */
231 struct delayed_work mbhc_firmware_dwork;
232 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800233
234 /* num of slim ports required */
235 struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800236
237 /*compander*/
238 int comp_enabled[COMPANDER_MAX];
239 u32 comp_fs[COMPANDER_MAX];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800240
241 /* Maintain the status of AUX PGA */
242 int aux_pga_cnt;
243 u8 aux_l_gain;
244 u8 aux_r_gain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245};
246
Bradley Rubincb3950a2011-08-18 13:07:26 -0700247#ifdef CONFIG_DEBUG_FS
248struct tabla_priv *debug_tabla_priv;
249#endif
250
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800251static const u32 comp_shift[] = {
252 0,
253 2,
254};
255
256static const int comp_rx_path[] = {
257 COMPANDER_1,
258 COMPANDER_1,
259 COMPANDER_2,
260 COMPANDER_2,
261 COMPANDER_2,
262 COMPANDER_2,
263 COMPANDER_MAX,
264};
265
266static const struct comp_sample_dependent_params comp_samp_params[] = {
267 {
268 .peak_det_timeout = 0x2,
269 .rms_meter_div_fact = 0x8 << 4,
270 .rms_meter_resamp_fact = 0x21,
271 },
272 {
273 .peak_det_timeout = 0x3,
274 .rms_meter_div_fact = 0x9 << 4,
275 .rms_meter_resamp_fact = 0x28,
276 },
277
278 {
279 .peak_det_timeout = 0x5,
280 .rms_meter_div_fact = 0xB << 4,
281 .rms_meter_resamp_fact = 0x28,
282 },
283
284 {
285 .peak_det_timeout = 0x5,
286 .rms_meter_div_fact = 0xB << 4,
287 .rms_meter_resamp_fact = 0x28,
288 },
289};
290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
292 struct snd_kcontrol *kcontrol, int event)
293{
294 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295
296 pr_debug("%s %d\n", __func__, event);
297 switch (event) {
298 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700299 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
300 0x01);
301 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
302 usleep_range(200, 200);
303 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
304 break;
305 case SND_SOC_DAPM_PRE_PMD:
306 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
307 0x10);
308 usleep_range(20, 20);
309 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
310 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
311 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
312 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
313 0x00);
314 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700315 break;
316 }
317 return 0;
318}
319
Bradley Rubina7096d02011-08-03 18:29:02 -0700320static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
321 struct snd_ctl_elem_value *ucontrol)
322{
323 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
324 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
325 ucontrol->value.integer.value[0] = tabla->anc_slot;
326 return 0;
327}
328
329static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
330 struct snd_ctl_elem_value *ucontrol)
331{
332 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
333 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
334 tabla->anc_slot = ucontrol->value.integer.value[0];
335 return 0;
336}
337
Kiran Kandid2d86b52011-09-09 17:44:28 -0700338static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
339 struct snd_ctl_elem_value *ucontrol)
340{
341 u8 ear_pa_gain;
342 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
343
344 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
345
346 ear_pa_gain = ear_pa_gain >> 5;
347
348 if (ear_pa_gain == 0x00) {
349 ucontrol->value.integer.value[0] = 0;
350 } else if (ear_pa_gain == 0x04) {
351 ucontrol->value.integer.value[0] = 1;
352 } else {
353 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
354 __func__, ear_pa_gain);
355 return -EINVAL;
356 }
357
358 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
359
360 return 0;
361}
362
363static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
364 struct snd_ctl_elem_value *ucontrol)
365{
366 u8 ear_pa_gain;
367 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
368
369 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
370 ucontrol->value.integer.value[0]);
371
372 switch (ucontrol->value.integer.value[0]) {
373 case 0:
374 ear_pa_gain = 0x00;
375 break;
376 case 1:
377 ear_pa_gain = 0x80;
378 break;
379 default:
380 return -EINVAL;
381 }
382
383 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
384 return 0;
385}
386
Ben Romberger1f045a72011-11-04 10:14:57 -0700387static int tabla_get_iir_enable_audio_mixer(
388 struct snd_kcontrol *kcontrol,
389 struct snd_ctl_elem_value *ucontrol)
390{
391 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
392 int iir_idx = ((struct soc_multi_mixer_control *)
393 kcontrol->private_value)->reg;
394 int band_idx = ((struct soc_multi_mixer_control *)
395 kcontrol->private_value)->shift;
396
397 ucontrol->value.integer.value[0] =
398 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
399 (1 << band_idx);
400
401 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
402 iir_idx, band_idx,
403 (uint32_t)ucontrol->value.integer.value[0]);
404 return 0;
405}
406
407static int tabla_put_iir_enable_audio_mixer(
408 struct snd_kcontrol *kcontrol,
409 struct snd_ctl_elem_value *ucontrol)
410{
411 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
412 int iir_idx = ((struct soc_multi_mixer_control *)
413 kcontrol->private_value)->reg;
414 int band_idx = ((struct soc_multi_mixer_control *)
415 kcontrol->private_value)->shift;
416 int value = ucontrol->value.integer.value[0];
417
418 /* Mask first 5 bits, 6-8 are reserved */
419 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
420 (1 << band_idx), (value << band_idx));
421
422 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
423 iir_idx, band_idx, value);
424 return 0;
425}
426static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
427 int iir_idx, int band_idx,
428 int coeff_idx)
429{
430 /* Address does not automatically update if reading */
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_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800433 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700434
435 /* Mask bits top 2 bits since they are reserved */
436 return ((snd_soc_read(codec,
437 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
438 (snd_soc_read(codec,
439 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
440 (snd_soc_read(codec,
441 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
442 (snd_soc_read(codec,
443 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
444 0x3FFFFFFF;
445}
446
447static int tabla_get_iir_band_audio_mixer(
448 struct snd_kcontrol *kcontrol,
449 struct snd_ctl_elem_value *ucontrol)
450{
451 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
452 int iir_idx = ((struct soc_multi_mixer_control *)
453 kcontrol->private_value)->reg;
454 int band_idx = ((struct soc_multi_mixer_control *)
455 kcontrol->private_value)->shift;
456
457 ucontrol->value.integer.value[0] =
458 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
459 ucontrol->value.integer.value[1] =
460 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
461 ucontrol->value.integer.value[2] =
462 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
463 ucontrol->value.integer.value[3] =
464 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
465 ucontrol->value.integer.value[4] =
466 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
467
468 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
469 "%s: IIR #%d band #%d b1 = 0x%x\n"
470 "%s: IIR #%d band #%d b2 = 0x%x\n"
471 "%s: IIR #%d band #%d a1 = 0x%x\n"
472 "%s: IIR #%d band #%d a2 = 0x%x\n",
473 __func__, iir_idx, band_idx,
474 (uint32_t)ucontrol->value.integer.value[0],
475 __func__, iir_idx, band_idx,
476 (uint32_t)ucontrol->value.integer.value[1],
477 __func__, iir_idx, band_idx,
478 (uint32_t)ucontrol->value.integer.value[2],
479 __func__, iir_idx, band_idx,
480 (uint32_t)ucontrol->value.integer.value[3],
481 __func__, iir_idx, band_idx,
482 (uint32_t)ucontrol->value.integer.value[4]);
483 return 0;
484}
485
486static void set_iir_band_coeff(struct snd_soc_codec *codec,
487 int iir_idx, int band_idx,
488 int coeff_idx, uint32_t value)
489{
490 /* Mask top 3 bits, 6-8 are reserved */
491 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800492 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700493 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800494 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700495
496 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800497 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700498 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800499 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700500
501 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800502 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700503 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800504 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700505
Ben Romberger0915aae2012-02-06 23:32:43 -0800506 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700507 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800508 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700509
Ben Romberger0915aae2012-02-06 23:32:43 -0800510 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700511 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800512 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700513}
514
515static int tabla_put_iir_band_audio_mixer(
516 struct snd_kcontrol *kcontrol,
517 struct snd_ctl_elem_value *ucontrol)
518{
519 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
520 int iir_idx = ((struct soc_multi_mixer_control *)
521 kcontrol->private_value)->reg;
522 int band_idx = ((struct soc_multi_mixer_control *)
523 kcontrol->private_value)->shift;
524
525 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
526 ucontrol->value.integer.value[0]);
527 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
528 ucontrol->value.integer.value[1]);
529 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
530 ucontrol->value.integer.value[2]);
531 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
532 ucontrol->value.integer.value[3]);
533 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
534 ucontrol->value.integer.value[4]);
535
536 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
537 "%s: IIR #%d band #%d b1 = 0x%x\n"
538 "%s: IIR #%d band #%d b2 = 0x%x\n"
539 "%s: IIR #%d band #%d a1 = 0x%x\n"
540 "%s: IIR #%d band #%d a2 = 0x%x\n",
541 __func__, iir_idx, band_idx,
542 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
543 __func__, iir_idx, band_idx,
544 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
545 __func__, iir_idx, band_idx,
546 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
547 __func__, iir_idx, band_idx,
548 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
549 __func__, iir_idx, band_idx,
550 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
551 return 0;
552}
553
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800554static int tabla_compander_gain_offset(
555 struct snd_soc_codec *codec, u32 enable,
556 unsigned int reg, int mask, int event)
557{
558 int pa_mode = snd_soc_read(codec, reg) & mask;
559 int gain_offset = 0;
560 /* if PMU && enable is 1-> offset is 3
561 * if PMU && enable is 0-> offset is 0
562 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
563 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
564 */
565
566 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
567 gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
568 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
569 gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
570 return gain_offset;
571}
572
573
574static int tabla_config_gain_compander(
575 struct snd_soc_codec *codec,
576 u32 compander, u32 enable, int event)
577{
578 int value = 0;
579 int mask = 1 << 4;
580 int gain = 0;
581 int gain_offset;
582 if (compander >= COMPANDER_MAX) {
583 pr_err("%s: Error, invalid compander channel\n", __func__);
584 return -EINVAL;
585 }
586
587 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
588 value = 1 << 4;
589
590 if (compander == COMPANDER_1) {
591 gain_offset = tabla_compander_gain_offset(codec, enable,
592 TABLA_A_RX_HPH_L_GAIN, mask, event);
593 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
594 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
595 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
596 0xFF, gain - gain_offset);
597 gain_offset = tabla_compander_gain_offset(codec, enable,
598 TABLA_A_RX_HPH_R_GAIN, mask, event);
599 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
600 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
601 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
602 0xFF, gain - gain_offset);
603 } else if (compander == COMPANDER_2) {
604 gain_offset = tabla_compander_gain_offset(codec, enable,
605 TABLA_A_RX_LINE_1_GAIN, mask, event);
606 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
607 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
608 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
609 0xFF, gain - gain_offset);
610 gain_offset = tabla_compander_gain_offset(codec, enable,
611 TABLA_A_RX_LINE_3_GAIN, mask, event);
612 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
613 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
614 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
615 0xFF, gain - gain_offset);
616 gain_offset = tabla_compander_gain_offset(codec, enable,
617 TABLA_A_RX_LINE_2_GAIN, mask, event);
618 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
619 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
620 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
621 0xFF, gain - gain_offset);
622 gain_offset = tabla_compander_gain_offset(codec, enable,
623 TABLA_A_RX_LINE_4_GAIN, mask, event);
624 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
625 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
626 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
627 0xFF, gain - gain_offset);
628 }
629 return 0;
630}
631static int tabla_get_compander(struct snd_kcontrol *kcontrol,
632 struct snd_ctl_elem_value *ucontrol)
633{
634
635 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
636 int comp = ((struct soc_multi_mixer_control *)
637 kcontrol->private_value)->max;
638 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
639
640 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
641
642 return 0;
643}
644
645static int tabla_set_compander(struct snd_kcontrol *kcontrol,
646 struct snd_ctl_elem_value *ucontrol)
647{
648 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
649 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
650 int comp = ((struct soc_multi_mixer_control *)
651 kcontrol->private_value)->max;
652 int value = ucontrol->value.integer.value[0];
653
654 if (value == tabla->comp_enabled[comp]) {
655 pr_debug("%s: compander #%d enable %d no change\n",
656 __func__, comp, value);
657 return 0;
658 }
659 tabla->comp_enabled[comp] = value;
660 return 0;
661}
662
663
664static int tabla_config_compander(struct snd_soc_dapm_widget *w,
665 struct snd_kcontrol *kcontrol,
666 int event)
667{
668 struct snd_soc_codec *codec = w->codec;
669 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
670 u32 rate = tabla->comp_fs[w->shift];
671
672 switch (event) {
673 case SND_SOC_DAPM_PRE_PMU:
674 if (tabla->comp_enabled[w->shift] != 0) {
675 /* Enable both L/R compander clocks */
676 snd_soc_update_bits(codec,
677 TABLA_A_CDC_CLK_RX_B2_CTL,
678 0x03 << comp_shift[w->shift],
679 0x03 << comp_shift[w->shift]);
680 /* Clar the HALT for the compander*/
681 snd_soc_update_bits(codec,
682 TABLA_A_CDC_COMP1_B1_CTL +
683 w->shift * 8, 1 << 2, 0);
684 /* Toggle compander reset bits*/
685 snd_soc_update_bits(codec,
686 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
687 0x03 << comp_shift[w->shift],
688 0x03 << comp_shift[w->shift]);
689 snd_soc_update_bits(codec,
690 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
691 0x03 << comp_shift[w->shift], 0);
692 tabla_config_gain_compander(codec, w->shift, 1, event);
693 /* Update the RMS meter resampling*/
694 snd_soc_update_bits(codec,
695 TABLA_A_CDC_COMP1_B3_CTL +
696 w->shift * 8, 0xFF, 0x01);
697 /* Wait for 1ms*/
698 usleep_range(1000, 1000);
699 }
700 break;
701 case SND_SOC_DAPM_POST_PMU:
702 /* Set sample rate dependent paramater*/
703 if (tabla->comp_enabled[w->shift] != 0) {
704 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
705 w->shift * 8, 0x03, rate);
706 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
707 w->shift * 8, 0x0F,
708 comp_samp_params[rate].peak_det_timeout);
709 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
710 w->shift * 8, 0xF0,
711 comp_samp_params[rate].rms_meter_div_fact);
712 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
713 w->shift * 8, 0xFF,
714 comp_samp_params[rate].rms_meter_resamp_fact);
715 /* Compander enable -> 0x370/0x378*/
716 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
717 w->shift * 8, 0x03, 0x03);
718 }
719 break;
720 case SND_SOC_DAPM_PRE_PMD:
721 /* Halt the compander*/
722 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
723 w->shift * 8, 1 << 2, 1 << 2);
724 break;
725 case SND_SOC_DAPM_POST_PMD:
726 /* Restore the gain */
727 tabla_config_gain_compander(codec, w->shift,
728 tabla->comp_enabled[w->shift], event);
729 /* Disable the compander*/
730 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
731 w->shift * 8, 0x03, 0x00);
732 /* Turn off the clock for compander in pair*/
733 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
734 0x03 << comp_shift[w->shift], 0);
735 break;
736 }
737 return 0;
738}
739
Kiran Kandid2d86b52011-09-09 17:44:28 -0700740static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
741static const struct soc_enum tabla_ear_pa_gain_enum[] = {
742 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
743};
744
Santosh Mardi024010f2011-10-18 06:27:21 +0530745/*cut of frequency for high pass filter*/
746static const char *cf_text[] = {
747 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
748};
749
750static const struct soc_enum cf_dec1_enum =
751 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
752
753static const struct soc_enum cf_dec2_enum =
754 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
755
756static const struct soc_enum cf_dec3_enum =
757 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
758
759static const struct soc_enum cf_dec4_enum =
760 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
761
762static const struct soc_enum cf_dec5_enum =
763 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
764
765static const struct soc_enum cf_dec6_enum =
766 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
767
768static const struct soc_enum cf_dec7_enum =
769 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
770
771static const struct soc_enum cf_dec8_enum =
772 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
773
774static const struct soc_enum cf_dec9_enum =
775 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
776
777static const struct soc_enum cf_dec10_enum =
778 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
779
780static const struct soc_enum cf_rxmix1_enum =
781 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
782
783static const struct soc_enum cf_rxmix2_enum =
784 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
785
786static const struct soc_enum cf_rxmix3_enum =
787 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
788
789static const struct soc_enum cf_rxmix4_enum =
790 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
791
792static const struct soc_enum cf_rxmix5_enum =
793 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
794;
795static const struct soc_enum cf_rxmix6_enum =
796 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
797
798static const struct soc_enum cf_rxmix7_enum =
799 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
800
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700801static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700802
803 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
804 tabla_pa_gain_get, tabla_pa_gain_put),
805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
807 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700808 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
809 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700810 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
811 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700812 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
813 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700814 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
815 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700816
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700817 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
818 line_gain),
819 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
820 line_gain),
821
Bradley Rubin410383f2011-07-22 13:44:23 -0700822 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
823 -84, 40, digital_gain),
824 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
825 -84, 40, digital_gain),
826 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
827 -84, 40, digital_gain),
828 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
829 -84, 40, digital_gain),
830 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
831 -84, 40, digital_gain),
832 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
833 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -0800834 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
835 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836
Bradley Rubin410383f2011-07-22 13:44:23 -0700837 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700838 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700839 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700840 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700841 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
842 digital_gain),
843 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
844 digital_gain),
845 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
846 digital_gain),
847 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
848 digital_gain),
849 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
850 digital_gain),
851 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
852 digital_gain),
853 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
854 digital_gain),
855 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
856 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700857 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
858 40, digital_gain),
859 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
860 40, digital_gain),
861 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
862 40, digital_gain),
863 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
864 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700865 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
866 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700867 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
868 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700869 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
870 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800872 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
873 aux_pga_gain),
874 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
875 aux_pga_gain),
876
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700877 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800878 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700879 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700880
881 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
882 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530883 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
884 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
885 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
886 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
887 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
888 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
889 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
890 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
891 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
892 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
893
894 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
895 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
896 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
897 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
898 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
899 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
900 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
901 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
902 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
903 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
904
905 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
906 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
907 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
908 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
909 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
910 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
911 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
912
913 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
914 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
915 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
916 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
917 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
918 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
919 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700920
921 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
922 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
923 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
924 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
925 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
926 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
927 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
928 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
929 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
930 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
931 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
932 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
933 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
934 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
935 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
936 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
937 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
938 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
939 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
940 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
941
942 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
943 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
944 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
945 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
946 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
947 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
948 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
949 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
950 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
951 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
952 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
953 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
954 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
955 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
956 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
957 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
958 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
959 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
960 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
961 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800962 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
963 tabla_get_compander, tabla_set_compander),
964 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
965 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966};
967
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800968static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
969 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
970};
971
972static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
973 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
974};
975
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976static const char *rx_mix1_text[] = {
977 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
978 "RX5", "RX6", "RX7"
979};
980
Kiran Kandi8b3a8302011-09-27 16:13:28 -0700981static const char *rx_dsm_text[] = {
982 "CIC_OUT", "DSM_INV"
983};
984
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985static const char *sb_tx1_mux_text[] = {
986 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
987 "DEC1"
988};
989
990static const char *sb_tx5_mux_text[] = {
991 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
992 "DEC5"
993};
994
995static const char *sb_tx6_mux_text[] = {
996 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
997 "DEC6"
998};
999
1000static const char const *sb_tx7_to_tx10_mux_text[] = {
1001 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1002 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1003 "DEC9", "DEC10"
1004};
1005
1006static const char *dec1_mux_text[] = {
1007 "ZERO", "DMIC1", "ADC6",
1008};
1009
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001010static const char *dec2_mux_text[] = {
1011 "ZERO", "DMIC2", "ADC5",
1012};
1013
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001014static const char *dec3_mux_text[] = {
1015 "ZERO", "DMIC3", "ADC4",
1016};
1017
1018static const char *dec4_mux_text[] = {
1019 "ZERO", "DMIC4", "ADC3",
1020};
1021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022static const char *dec5_mux_text[] = {
1023 "ZERO", "DMIC5", "ADC2",
1024};
1025
1026static const char *dec6_mux_text[] = {
1027 "ZERO", "DMIC6", "ADC1",
1028};
1029
1030static const char const *dec7_mux_text[] = {
1031 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1032};
1033
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001034static const char *dec8_mux_text[] = {
1035 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1036};
1037
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001038static const char *dec9_mux_text[] = {
1039 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1040};
1041
1042static const char *dec10_mux_text[] = {
1043 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1044};
1045
Bradley Rubin229c6a52011-07-12 16:18:48 -07001046static const char const *anc_mux_text[] = {
1047 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1048 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1049};
1050
1051static const char const *anc1_fb_mux_text[] = {
1052 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1053};
1054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001055static const char *iir1_inp1_text[] = {
1056 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1057 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1058};
1059
1060static const struct soc_enum rx_mix1_inp1_chain_enum =
1061 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1062
Bradley Rubin229c6a52011-07-12 16:18:48 -07001063static const struct soc_enum rx_mix1_inp2_chain_enum =
1064 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1065
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066static const struct soc_enum rx2_mix1_inp1_chain_enum =
1067 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1068
Bradley Rubin229c6a52011-07-12 16:18:48 -07001069static const struct soc_enum rx2_mix1_inp2_chain_enum =
1070 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072static const struct soc_enum rx3_mix1_inp1_chain_enum =
1073 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1074
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001075static const struct soc_enum rx3_mix1_inp2_chain_enum =
1076 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078static const struct soc_enum rx4_mix1_inp1_chain_enum =
1079 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1080
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001081static const struct soc_enum rx4_mix1_inp2_chain_enum =
1082 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1083
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001084static const struct soc_enum rx5_mix1_inp1_chain_enum =
1085 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1086
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001087static const struct soc_enum rx5_mix1_inp2_chain_enum =
1088 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1089
1090static const struct soc_enum rx6_mix1_inp1_chain_enum =
1091 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1092
1093static const struct soc_enum rx6_mix1_inp2_chain_enum =
1094 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1095
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001096static const struct soc_enum rx7_mix1_inp1_chain_enum =
1097 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1098
1099static const struct soc_enum rx7_mix1_inp2_chain_enum =
1100 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1101
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001102static const struct soc_enum rx4_dsm_enum =
1103 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1104
1105static const struct soc_enum rx6_dsm_enum =
1106 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1107
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108static const struct soc_enum sb_tx5_mux_enum =
1109 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1110
1111static const struct soc_enum sb_tx6_mux_enum =
1112 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1113
1114static const struct soc_enum sb_tx7_mux_enum =
1115 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1116 sb_tx7_to_tx10_mux_text);
1117
1118static const struct soc_enum sb_tx8_mux_enum =
1119 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1120 sb_tx7_to_tx10_mux_text);
1121
Kiran Kandi3426e512011-09-13 22:50:10 -07001122static const struct soc_enum sb_tx9_mux_enum =
1123 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1124 sb_tx7_to_tx10_mux_text);
1125
1126static const struct soc_enum sb_tx10_mux_enum =
1127 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1128 sb_tx7_to_tx10_mux_text);
1129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130static const struct soc_enum sb_tx1_mux_enum =
1131 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1132
1133static const struct soc_enum dec1_mux_enum =
1134 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1135
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001136static const struct soc_enum dec2_mux_enum =
1137 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1138
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001139static const struct soc_enum dec3_mux_enum =
1140 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1141
1142static const struct soc_enum dec4_mux_enum =
1143 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145static const struct soc_enum dec5_mux_enum =
1146 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1147
1148static const struct soc_enum dec6_mux_enum =
1149 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1150
1151static const struct soc_enum dec7_mux_enum =
1152 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1153
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001154static const struct soc_enum dec8_mux_enum =
1155 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1156
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001157static const struct soc_enum dec9_mux_enum =
1158 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1159
1160static const struct soc_enum dec10_mux_enum =
1161 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1162
Bradley Rubin229c6a52011-07-12 16:18:48 -07001163static const struct soc_enum anc1_mux_enum =
1164 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1165
1166static const struct soc_enum anc2_mux_enum =
1167 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1168
1169static const struct soc_enum anc1_fb_mux_enum =
1170 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172static const struct soc_enum iir1_inp1_mux_enum =
1173 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
1174
1175static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1176 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1177
Bradley Rubin229c6a52011-07-12 16:18:48 -07001178static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1179 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1180
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1182 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1183
Bradley Rubin229c6a52011-07-12 16:18:48 -07001184static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1185 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1186
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001187static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1188 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1189
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001190static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1191 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1192
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001193static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1194 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1195
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001196static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1197 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1200 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1201
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001202static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1203 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1204
1205static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1206 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1207
1208static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1209 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1210
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001211static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1212 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1213
1214static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1215 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1216
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001217static const struct snd_kcontrol_new rx4_dsm_mux =
1218 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1219
1220static const struct snd_kcontrol_new rx6_dsm_mux =
1221 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1222
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001223static const struct snd_kcontrol_new sb_tx5_mux =
1224 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1225
1226static const struct snd_kcontrol_new sb_tx6_mux =
1227 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1228
1229static const struct snd_kcontrol_new sb_tx7_mux =
1230 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1231
1232static const struct snd_kcontrol_new sb_tx8_mux =
1233 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1234
Kiran Kandi3426e512011-09-13 22:50:10 -07001235static const struct snd_kcontrol_new sb_tx9_mux =
1236 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1237
1238static const struct snd_kcontrol_new sb_tx10_mux =
1239 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1240
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241static const struct snd_kcontrol_new sb_tx1_mux =
1242 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1243
1244static const struct snd_kcontrol_new dec1_mux =
1245 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1246
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001247static const struct snd_kcontrol_new dec2_mux =
1248 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1249
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001250static const struct snd_kcontrol_new dec3_mux =
1251 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1252
1253static const struct snd_kcontrol_new dec4_mux =
1254 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256static const struct snd_kcontrol_new dec5_mux =
1257 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
1258
1259static const struct snd_kcontrol_new dec6_mux =
1260 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
1261
1262static const struct snd_kcontrol_new dec7_mux =
1263 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
1264
Bradley Rubin229c6a52011-07-12 16:18:48 -07001265static const struct snd_kcontrol_new anc1_mux =
1266 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001267static const struct snd_kcontrol_new dec8_mux =
1268 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
1269
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001270static const struct snd_kcontrol_new dec9_mux =
1271 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
1272
1273static const struct snd_kcontrol_new dec10_mux =
1274 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
1275
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276static const struct snd_kcontrol_new iir1_inp1_mux =
1277 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1278
Bradley Rubin229c6a52011-07-12 16:18:48 -07001279static const struct snd_kcontrol_new anc2_mux =
1280 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281
Bradley Rubin229c6a52011-07-12 16:18:48 -07001282static const struct snd_kcontrol_new anc1_fb_mux =
1283 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284
Bradley Rubin229c6a52011-07-12 16:18:48 -07001285static const struct snd_kcontrol_new dac1_switch[] = {
1286 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1287};
1288static const struct snd_kcontrol_new hphl_switch[] = {
1289 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1290};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001291
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001292static const struct snd_kcontrol_new hphl_pa_mix[] = {
1293 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1294 7, 1, 0),
1295 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1296 7, 1, 0),
1297 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1298 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1299 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1300 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1301};
1302
1303static const struct snd_kcontrol_new hphr_pa_mix[] = {
1304 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1305 6, 1, 0),
1306 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1307 6, 1, 0),
1308 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1309 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1310 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1311 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1312};
1313
1314static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1315 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1316 5, 1, 0),
1317 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1318 5, 1, 0),
1319 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1320 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1321 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1322 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1323};
1324
1325static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1326 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1327 4, 1, 0),
1328 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1329 4, 1, 0),
1330 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1331 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1332 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1333 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1334};
1335
1336static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1337 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1338 3, 1, 0),
1339 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1340 3, 1, 0),
1341 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1342 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1343 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1344 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1345};
1346
1347static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1348 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1349 2, 1, 0),
1350 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1351 2, 1, 0),
1352 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1353 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1354 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1355 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1356};
1357
1358static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1359 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1360 1, 1, 0),
1361 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1362 1, 1, 0),
1363 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1364 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1365 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1366 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1367};
1368
1369static const struct snd_kcontrol_new ear_pa_mix[] = {
1370 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1371 0, 1, 0),
1372 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1373 0, 1, 0),
1374 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1375 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1376 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1377 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1378};
1379
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001380static const struct snd_kcontrol_new lineout3_ground_switch =
1381 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1382
1383static const struct snd_kcontrol_new lineout4_ground_switch =
1384 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001386static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
1387 int enable)
1388{
1389 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1390
1391 pr_debug("%s %d\n", __func__, enable);
1392
1393 if (enable) {
1394 tabla->adc_count++;
1395 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1396 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1397 } else {
1398 tabla->adc_count--;
1399 if (!tabla->adc_count) {
1400 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
1401 0x2, 0x0);
1402 if (!tabla->mbhc_polling_active)
1403 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
1404 0xE0, 0x0);
1405 }
1406 }
1407}
1408
1409static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1410 struct snd_kcontrol *kcontrol, int event)
1411{
1412 struct snd_soc_codec *codec = w->codec;
1413 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001414 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001415
1416 pr_debug("%s %d\n", __func__, event);
1417
1418 if (w->reg == TABLA_A_TX_1_2_EN)
1419 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1420 else if (w->reg == TABLA_A_TX_3_4_EN)
1421 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1422 else if (w->reg == TABLA_A_TX_5_6_EN)
1423 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1424 else {
1425 pr_err("%s: Error, invalid adc register\n", __func__);
1426 return -EINVAL;
1427 }
1428
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001429 if (w->shift == 3)
1430 init_bit_shift = 6;
1431 else if (w->shift == 7)
1432 init_bit_shift = 7;
1433 else {
1434 pr_err("%s: Error, invalid init bit postion adc register\n",
1435 __func__);
1436 return -EINVAL;
1437 }
1438
1439
1440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441 switch (event) {
1442 case SND_SOC_DAPM_PRE_PMU:
1443 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001444 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1445 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001446 break;
1447 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001448
1449 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 break;
1452 case SND_SOC_DAPM_POST_PMD:
1453 tabla_codec_enable_adc_block(codec, 0);
1454 break;
1455 }
1456 return 0;
1457}
1458
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001459static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1460{
1461 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL, 0x1C);
1462 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1463 0x80);
1464 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1465 0x04);
1466 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1467 0x01);
1468 usleep_range(1000, 1000);
1469 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1470 0x00);
1471}
1472
1473static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1474 enum tabla_bandgap_type choice)
1475{
1476 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1477
1478 /* TODO lock resources accessed by audio streams and threaded
1479 * interrupt handlers
1480 */
1481
1482 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1483 tabla->bandgap_type);
1484
1485 if (tabla->bandgap_type == choice)
1486 return;
1487
1488 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1489 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1490 tabla_codec_enable_audio_mode_bandgap(codec);
1491 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
1492 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1493 0x2);
1494 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1495 0x80);
1496 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1497 0x4);
1498 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1499 0x01);
1500 usleep_range(1000, 1000);
1501 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1502 0x00);
1503 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1504 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1505 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1506 usleep_range(100, 100);
1507 tabla_codec_enable_audio_mode_bandgap(codec);
1508 } else if (choice == TABLA_BANDGAP_OFF) {
1509 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1510 } else {
1511 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1512 }
1513 tabla->bandgap_type = choice;
1514}
1515
1516static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1517{
1518 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1519 pr_debug("%s\n", __func__);
1520 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1521 ndelay(160);
1522 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1523 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1524 tabla->clock_active = false;
1525}
1526
1527static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
1528{
1529 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
1530 return 0;
1531 else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
1532 return 1;
1533 else {
1534 BUG_ON(1);
1535 return -EINVAL;
1536 }
1537}
1538
1539static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1540{
1541 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1542
1543 if (enable) {
1544 tabla->rx_bias_count++;
1545 if (tabla->rx_bias_count == 1)
1546 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1547 0x80, 0x80);
1548 } else {
1549 tabla->rx_bias_count--;
1550 if (!tabla->rx_bias_count)
1551 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1552 0x80, 0x00);
1553 }
1554}
1555
1556static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1557 int enable)
1558{
1559 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1560
1561 pr_debug("%s: enable = %d\n", __func__, enable);
1562 if (enable) {
1563 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1564 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1565 usleep_range(5, 5);
1566 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1567 0x80);
1568 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1569 0x80);
1570 usleep_range(10, 10);
1571 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1572 usleep_range(20, 20);
1573 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1574 } else {
1575 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1576 0);
1577 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1578 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1579 }
1580 tabla->config_mode_active = enable ? true : false;
1581
1582 return 0;
1583}
1584
1585static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1586 int config_mode)
1587{
1588 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1589
1590 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
1591
1592 if (config_mode) {
1593 tabla_codec_enable_config_mode(codec, 1);
1594 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1595 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1596 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1597 usleep_range(1000, 1000);
1598 } else
1599 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1600
1601 if (!config_mode && tabla->mbhc_polling_active) {
1602 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1603 tabla_codec_enable_config_mode(codec, 0);
1604
1605 }
1606
1607 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1608 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1609 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1610 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1611 usleep_range(50, 50);
1612 tabla->clock_active = true;
1613 return 0;
1614}
1615
1616static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1617 struct snd_kcontrol *kcontrol, int event)
1618{
1619 struct snd_soc_codec *codec = w->codec;
1620 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1621
1622 pr_debug("%s: %d\n", __func__, event);
1623
1624 switch (event) {
1625 case SND_SOC_DAPM_PRE_PMU:
1626 tabla_codec_enable_bandgap(codec,
1627 TABLA_BANDGAP_AUDIO_MODE);
1628 tabla_enable_rx_bias(codec, 1);
1629
1630 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1631 0x08, 0x08);
1632 /* Enable Zero Cross detect for AUX PGA channel
1633 * and set the initial AUX PGA gain to NEG_0P0_DB
1634 * to avoid glitches.
1635 */
1636 if (w->reg == TABLA_A_AUX_L_EN) {
1637 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1638 0x20, 0x20);
1639 tabla->aux_l_gain = snd_soc_read(codec,
1640 TABLA_A_AUX_L_GAIN);
1641 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1642 } else {
1643 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1644 0x20, 0x20);
1645 tabla->aux_r_gain = snd_soc_read(codec,
1646 TABLA_A_AUX_R_GAIN);
1647 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1648 }
1649 if (tabla->aux_pga_cnt++ == 1
1650 && !tabla->mclk_enabled) {
1651 tabla_codec_enable_clock_block(codec, 1);
1652 pr_debug("AUX PGA enabled RC osc\n");
1653 }
1654 break;
1655
1656 case SND_SOC_DAPM_POST_PMU:
1657 if (w->reg == TABLA_A_AUX_L_EN)
1658 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1659 tabla->aux_l_gain);
1660 else
1661 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1662 tabla->aux_r_gain);
1663 break;
1664
1665 case SND_SOC_DAPM_PRE_PMD:
1666 /* Mute AUX PGA channel in use before disabling AUX PGA */
1667 if (w->reg == TABLA_A_AUX_L_EN) {
1668 tabla->aux_l_gain = snd_soc_read(codec,
1669 TABLA_A_AUX_L_GAIN);
1670 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1671 } else {
1672 tabla->aux_r_gain = snd_soc_read(codec,
1673 TABLA_A_AUX_R_GAIN);
1674 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1675 }
1676 break;
1677
1678 case SND_SOC_DAPM_POST_PMD:
1679 tabla_enable_rx_bias(codec, 0);
1680
1681 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1682 0x08, 0x00);
1683 if (w->reg == TABLA_A_AUX_L_EN) {
1684 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1685 tabla->aux_l_gain);
1686 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1687 0x20, 0x00);
1688 } else {
1689 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1690 tabla->aux_r_gain);
1691 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1692 0x20, 0x00);
1693 }
1694
1695 if (tabla->aux_pga_cnt-- == 0) {
1696 if (tabla->mbhc_polling_active)
1697 tabla_codec_enable_bandgap(codec,
1698 TABLA_BANDGAP_MBHC_MODE);
1699 else
1700 tabla_codec_enable_bandgap(codec,
1701 TABLA_BANDGAP_OFF);
1702
1703 if (!tabla->mclk_enabled &&
1704 !tabla->mbhc_polling_active) {
1705 tabla_codec_enable_clock_block(codec, 0);
1706 }
1707 }
1708 break;
1709 }
1710 return 0;
1711}
1712
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001713static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1714 struct snd_kcontrol *kcontrol, int event)
1715{
1716 struct snd_soc_codec *codec = w->codec;
1717 u16 lineout_gain_reg;
1718
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001719 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720
1721 switch (w->shift) {
1722 case 0:
1723 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1724 break;
1725 case 1:
1726 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1727 break;
1728 case 2:
1729 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1730 break;
1731 case 3:
1732 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1733 break;
1734 case 4:
1735 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1736 break;
1737 default:
1738 pr_err("%s: Error, incorrect lineout register value\n",
1739 __func__);
1740 return -EINVAL;
1741 }
1742
1743 switch (event) {
1744 case SND_SOC_DAPM_PRE_PMU:
1745 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1746 break;
1747 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001748 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001749 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001750 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751 break;
1752 case SND_SOC_DAPM_POST_PMD:
1753 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1754 break;
1755 }
1756 return 0;
1757}
1758
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001759
1760static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 struct snd_kcontrol *kcontrol, int event)
1762{
1763 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001764 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1765 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001766 unsigned int dmic;
1767 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001768
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001769 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1770 if (ret < 0) {
1771 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001772 return -EINVAL;
1773 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001775 switch (dmic) {
1776 case 1:
1777 case 2:
1778 dmic_clk_sel = 0x02;
1779 dmic_clk_en = 0x01;
1780 break;
1781
1782 case 3:
1783 case 4:
1784 dmic_clk_sel = 0x08;
1785 dmic_clk_en = 0x04;
1786 break;
1787
1788 case 5:
1789 case 6:
1790 dmic_clk_sel = 0x20;
1791 dmic_clk_en = 0x10;
1792 break;
1793
1794 default:
1795 pr_err("%s: Invalid DMIC Selection\n", __func__);
1796 return -EINVAL;
1797 }
1798
1799 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1800 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001802 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001803
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804 switch (event) {
1805 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001806 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1807
1808 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1809 dmic_clk_sel, dmic_clk_sel);
1810
1811 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1812
1813 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1814 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001815 break;
1816 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001817 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1818 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001819 break;
1820 }
1821 return 0;
1822}
1823
Bradley Rubin229c6a52011-07-12 16:18:48 -07001824static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1825 struct snd_kcontrol *kcontrol, int event)
1826{
1827 struct snd_soc_codec *codec = w->codec;
1828 const char *filename;
1829 const struct firmware *fw;
1830 int i;
1831 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001832 int num_anc_slots;
1833 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001834 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001835 u32 anc_writes_size = 0;
1836 int anc_size_remaining;
1837 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001838 u16 reg;
1839 u8 mask, val, old_val;
1840
1841 pr_debug("%s %d\n", __func__, event);
1842 switch (event) {
1843 case SND_SOC_DAPM_PRE_PMU:
1844
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001845 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001846
1847 ret = request_firmware(&fw, filename, codec->dev);
1848 if (ret != 0) {
1849 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1850 ret);
1851 return -ENODEV;
1852 }
1853
Bradley Rubina7096d02011-08-03 18:29:02 -07001854 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001855 dev_err(codec->dev, "Not enough data\n");
1856 release_firmware(fw);
1857 return -ENOMEM;
1858 }
1859
1860 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001861 anc_head = (struct anc_header *)(fw->data);
1862 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1863 anc_size_remaining = fw->size - sizeof(struct anc_header);
1864 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001865
Bradley Rubina7096d02011-08-03 18:29:02 -07001866 if (tabla->anc_slot >= num_anc_slots) {
1867 dev_err(codec->dev, "Invalid ANC slot selected\n");
1868 release_firmware(fw);
1869 return -EINVAL;
1870 }
1871
1872 for (i = 0; i < num_anc_slots; i++) {
1873
1874 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1875 dev_err(codec->dev, "Invalid register format\n");
1876 release_firmware(fw);
1877 return -EINVAL;
1878 }
1879 anc_writes_size = (u32)(*anc_ptr);
1880 anc_size_remaining -= sizeof(u32);
1881 anc_ptr += 1;
1882
1883 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1884 > anc_size_remaining) {
1885 dev_err(codec->dev, "Invalid register format\n");
1886 release_firmware(fw);
1887 return -ENOMEM;
1888 }
1889
1890 if (tabla->anc_slot == i)
1891 break;
1892
1893 anc_size_remaining -= (anc_writes_size *
1894 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001895 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001896 }
1897 if (i == num_anc_slots) {
1898 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001899 release_firmware(fw);
1900 return -ENOMEM;
1901 }
1902
Bradley Rubina7096d02011-08-03 18:29:02 -07001903 for (i = 0; i < anc_writes_size; i++) {
1904 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001905 mask, val);
1906 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001907 snd_soc_write(codec, reg, (old_val & ~mask) |
1908 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001909 }
1910 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001911
1912 break;
1913 case SND_SOC_DAPM_POST_PMD:
1914 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1915 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1916 break;
1917 }
1918 return 0;
1919}
1920
1921
Bradley Rubincb3950a2011-08-18 13:07:26 -07001922static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
1923{
1924 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
1925 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
1926}
1927
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001928static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1929{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001930 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1931
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001932 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05301933 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001934 if (!tabla->no_mic_headset_override) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05301935 wcd9xxx_enable_irq(codec->control_data,
1936 TABLA_IRQ_MBHC_POTENTIAL);
1937 wcd9xxx_enable_irq(codec->control_data,
1938 TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001939 } else {
1940 tabla_codec_disable_button_presses(codec);
1941 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001942 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1943 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1944 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1945}
1946
1947static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
1948{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001949 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1950
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001951 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05301952 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001953 if (!tabla->no_mic_headset_override) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05301954 wcd9xxx_disable_irq(codec->control_data,
Bradley Rubincb3950a2011-08-18 13:07:26 -07001955 TABLA_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05301956 wcd9xxx_disable_irq(codec->control_data,
1957 TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001958 }
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001959}
1960
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08001961static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec,
1962 int mode)
1963{
1964 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1965 u8 reg_mode_val, cur_mode_val;
1966 bool mbhc_was_polling = false;
1967
1968 if (mode)
1969 reg_mode_val = TABLA_CFILT_FAST_MODE;
1970 else
1971 reg_mode_val = TABLA_CFILT_SLOW_MODE;
1972
1973 cur_mode_val = snd_soc_read(codec,
1974 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
1975
1976 if (cur_mode_val != reg_mode_val) {
1977 if (tabla->mbhc_polling_active) {
1978 tabla_codec_pause_hs_polling(codec);
1979 mbhc_was_polling = true;
1980 }
1981 snd_soc_update_bits(codec,
1982 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
1983 if (mbhc_was_polling)
1984 tabla_codec_start_hs_polling(codec);
1985 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
1986 cur_mode_val, reg_mode_val);
1987 } else {
1988 pr_debug("%s: CFILT Value is already %x\n",
1989 __func__, cur_mode_val);
1990 }
1991}
1992
1993static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
1994 u8 cfilt_sel, int inc)
1995{
1996 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1997 u32 *cfilt_cnt_ptr = NULL;
1998 u16 micb_cfilt_reg;
1999
2000 switch (cfilt_sel) {
2001 case TABLA_CFILT1_SEL:
2002 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2003 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2004 break;
2005 case TABLA_CFILT2_SEL:
2006 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2007 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2008 break;
2009 case TABLA_CFILT3_SEL:
2010 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2011 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2012 break;
2013 default:
2014 return; /* should not happen */
2015 }
2016
2017 if (inc) {
2018 if (!(*cfilt_cnt_ptr)++) {
2019 /* Switch CFILT to slow mode if MBHC CFILT being used */
2020 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2021 tabla_codec_switch_cfilt_mode(codec, 0);
2022
2023 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2024 }
2025 } else {
2026 /* check if count not zero, decrement
2027 * then check if zero, go ahead disable cfilter
2028 */
2029 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2030 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2031
2032 /* Switch CFILT to fast mode if MBHC CFILT being used */
2033 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2034 tabla_codec_switch_cfilt_mode(codec, 1);
2035 }
2036 }
2037}
2038
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002039static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2040{
2041 int rc = -EINVAL;
2042 unsigned min_mv, max_mv;
2043
2044 switch (ldoh_v) {
2045 case TABLA_LDOH_1P95_V:
2046 min_mv = 160;
2047 max_mv = 1800;
2048 break;
2049 case TABLA_LDOH_2P35_V:
2050 min_mv = 200;
2051 max_mv = 2200;
2052 break;
2053 case TABLA_LDOH_2P75_V:
2054 min_mv = 240;
2055 max_mv = 2600;
2056 break;
2057 case TABLA_LDOH_2P85_V:
2058 min_mv = 250;
2059 max_mv = 2700;
2060 break;
2061 default:
2062 goto done;
2063 }
2064
2065 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2066 goto done;
2067
2068 for (rc = 4; rc <= 44; rc++) {
2069 min_mv = max_mv * (rc) / 44;
2070 if (min_mv >= cfilt_mv) {
2071 rc -= 4;
2072 break;
2073 }
2074 }
2075done:
2076 return rc;
2077}
2078
2079static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2080{
2081 u8 hph_reg_val = 0;
2082 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2083
2084 return (hph_reg_val & 0x30) ? true : false;
2085}
2086
Joonwoo Parka9444452011-12-08 18:48:27 -08002087static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2088{
2089 u8 hph_reg_val = 0;
2090 if (left)
2091 hph_reg_val = snd_soc_read(codec,
2092 TABLA_A_RX_HPH_L_DAC_CTL);
2093 else
2094 hph_reg_val = snd_soc_read(codec,
2095 TABLA_A_RX_HPH_R_DAC_CTL);
2096
2097 return (hph_reg_val & 0xC0) ? true : false;
2098}
2099
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002100static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2101 int vddio_switch)
2102{
2103 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2104 int cfilt_k_val;
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002105 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002106
2107 switch (vddio_switch) {
2108 case 1:
2109 if (tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002110
2111 tabla_codec_pause_hs_polling(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08002112 /* VDDIO switch enabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002113 tabla->cfilt_k_value = snd_soc_read(codec,
2114 tabla->mbhc_bias_regs.cfilt_val);
2115 cfilt_k_val = tabla_find_k_value(
2116 tabla->pdata->micbias.ldoh_v, 1800);
2117 snd_soc_update_bits(codec,
2118 tabla->mbhc_bias_regs.cfilt_val,
2119 0xFC, (cfilt_k_val << 2));
2120
2121 snd_soc_update_bits(codec,
2122 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
2123 snd_soc_update_bits(codec,
2124 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002125 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002126
2127 tabla->mbhc_micbias_switched = true;
Joonwoo Park0976d012011-12-22 11:48:18 -08002128 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002129 }
2130 break;
2131
2132 case 0:
2133 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002134 if (tabla->mbhc_polling_active) {
2135 tabla_codec_pause_hs_polling(codec);
2136 mbhc_was_polling = true;
2137 }
Joonwoo Park0976d012011-12-22 11:48:18 -08002138 /* VDDIO switch disabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002139 if (tabla->cfilt_k_value != 0)
2140 snd_soc_update_bits(codec,
2141 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
2142 tabla->cfilt_k_value);
2143 snd_soc_update_bits(codec,
2144 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
2145 snd_soc_update_bits(codec,
2146 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
2147
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002148 if (mbhc_was_polling)
2149 tabla_codec_start_hs_polling(codec);
2150
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002151 tabla->mbhc_micbias_switched = false;
Joonwoo Park0976d012011-12-22 11:48:18 -08002152 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002153 }
2154 break;
2155 }
2156}
2157
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002158static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2159 struct snd_kcontrol *kcontrol, int event)
2160{
2161 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002162 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2163 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002164 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002165 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002166 char *internal1_text = "Internal1";
2167 char *internal2_text = "Internal2";
2168 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002169
2170 pr_debug("%s %d\n", __func__, event);
2171 switch (w->reg) {
2172 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002174 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002175 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002176 break;
2177 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002178 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002179 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002180 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002181 break;
2182 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002183 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002184 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002185 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002186 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002187 case TABLA_1_A_MICB_4_CTL:
2188 case TABLA_2_A_MICB_4_CTL:
2189 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002190 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002191 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002192 break;
2193 default:
2194 pr_err("%s: Error, invalid micbias register\n", __func__);
2195 return -EINVAL;
2196 }
2197
2198 switch (event) {
2199 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002200 /* Decide whether to switch the micbias for MBHC */
2201 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
2202 && tabla->mbhc_micbias_switched)
2203 tabla_codec_switch_micbias(codec, 0);
2204
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002205 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002206 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002207
2208 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002209 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002210 else if (strnstr(w->name, internal2_text, 30))
2211 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2212 else if (strnstr(w->name, internal3_text, 30))
2213 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002215 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002216 case SND_SOC_DAPM_POST_PMU:
2217 if (tabla->mbhc_polling_active &&
Joonwoo Park0976d012011-12-22 11:48:18 -08002218 tabla->micbias == micb_line) {
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002219 tabla_codec_pause_hs_polling(codec);
2220 tabla_codec_start_hs_polling(codec);
2221 }
2222 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002223
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002224 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002225
2226 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg)
2227 && tabla_is_hph_pa_on(codec))
2228 tabla_codec_switch_micbias(codec, 1);
2229
Bradley Rubin229c6a52011-07-12 16:18:48 -07002230 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002231 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002232 else if (strnstr(w->name, internal2_text, 30))
2233 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2234 else if (strnstr(w->name, internal3_text, 30))
2235 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2236
Patrick Lai3043fba2011-08-01 14:15:57 -07002237 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002238 break;
2239 }
2240
2241 return 0;
2242}
2243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
2245 struct snd_kcontrol *kcontrol, int event)
2246{
2247 struct snd_soc_codec *codec = w->codec;
2248 u16 dec_reset_reg;
2249
2250 pr_debug("%s %d\n", __func__, event);
2251
2252 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
2253 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
2254 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
2255 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
2256 else {
2257 pr_err("%s: Error, incorrect dec\n", __func__);
2258 return -EINVAL;
2259 }
2260
2261 switch (event) {
2262 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2264 1 << w->shift);
2265 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
2266 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002267 }
2268 return 0;
2269}
2270
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002271static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 struct snd_kcontrol *kcontrol, int event)
2273{
2274 struct snd_soc_codec *codec = w->codec;
2275
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002276 pr_debug("%s %d %s\n", __func__, event, w->name);
2277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002278 switch (event) {
2279 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002280 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2281 1 << w->shift, 1 << w->shift);
2282 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2283 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002284 break;
2285 }
2286 return 0;
2287}
2288
Bradley Rubin229c6a52011-07-12 16:18:48 -07002289static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2290 struct snd_kcontrol *kcontrol, int event)
2291{
2292 switch (event) {
2293 case SND_SOC_DAPM_POST_PMU:
2294 case SND_SOC_DAPM_POST_PMD:
2295 usleep_range(1000, 1000);
2296 break;
2297 }
2298 return 0;
2299}
2300
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002301static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2302 struct snd_kcontrol *kcontrol, int event)
2303{
2304 struct snd_soc_codec *codec = w->codec;
2305
2306 pr_debug("%s %d\n", __func__, event);
2307
2308 switch (event) {
2309 case SND_SOC_DAPM_PRE_PMU:
2310 tabla_enable_rx_bias(codec, 1);
2311 break;
2312 case SND_SOC_DAPM_POST_PMD:
2313 tabla_enable_rx_bias(codec, 0);
2314 break;
2315 }
2316 return 0;
2317}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002318static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
2319 struct snd_kcontrol *kcontrol, int event)
2320{
2321 struct snd_soc_codec *codec = w->codec;
2322
2323 pr_debug("%s %s %d\n", __func__, w->name, event);
2324
2325 switch (event) {
2326 case SND_SOC_DAPM_PRE_PMU:
2327 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2328 break;
2329 case SND_SOC_DAPM_POST_PMD:
2330 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2331 break;
2332 }
2333 return 0;
2334}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002335
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002336static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
2337 struct snd_soc_jack *jack, int status,
2338 int mask)
2339{
2340 /* XXX: wake_lock_timeout()? */
2341 snd_soc_jack_report(jack, status, mask);
2342}
2343
Patrick Lai49efeac2011-11-03 11:01:12 -07002344static void hphocp_off_report(struct tabla_priv *tabla,
2345 u32 jack_status, int irq)
2346{
2347 struct snd_soc_codec *codec;
2348
2349 if (tabla) {
2350 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
2351 codec = tabla->codec;
2352 tabla->hph_status &= ~jack_status;
2353 if (tabla->headset_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002354 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
2355 tabla->hph_status,
2356 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08002357 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2358 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08002359 /* reset retry counter as PA is turned off signifying
2360 * start of new OCP detection session
2361 */
2362 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
2363 tabla->hphlocp_cnt = 0;
2364 else
2365 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302366 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07002367 } else {
2368 pr_err("%s: Bad tabla private data\n", __func__);
2369 }
2370}
2371
2372static void hphlocp_off_report(struct work_struct *work)
2373{
2374 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2375 hphlocp_work);
2376 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
2377}
2378
2379static void hphrocp_off_report(struct work_struct *work)
2380{
2381 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2382 hphrocp_work);
2383 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
2384}
2385
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002386static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
2387 struct snd_kcontrol *kcontrol, int event)
2388{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002389 struct snd_soc_codec *codec = w->codec;
2390 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2391 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002392 pr_debug("%s: event = %d\n", __func__, event);
2393
2394 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002395 case SND_SOC_DAPM_PRE_PMU:
2396 mbhc_micb_ctl_val = snd_soc_read(codec,
2397 tabla->mbhc_bias_regs.ctl_reg);
2398
2399 if (!(mbhc_micb_ctl_val & 0x80)
2400 && !tabla->mbhc_micbias_switched)
2401 tabla_codec_switch_micbias(codec, 1);
2402
2403 break;
2404
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002405 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07002406 /* schedule work is required because at the time HPH PA DAPM
2407 * event callback is called by DAPM framework, CODEC dapm mutex
2408 * would have been locked while snd_soc_jack_report also
2409 * attempts to acquire same lock.
2410 */
Joonwoo Parka9444452011-12-08 18:48:27 -08002411 if (w->shift == 5) {
2412 clear_bit(TABLA_HPHL_PA_OFF_ACK,
2413 &tabla->hph_pa_dac_state);
2414 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
2415 &tabla->hph_pa_dac_state);
2416 if (tabla->hph_status & SND_JACK_OC_HPHL)
2417 schedule_work(&tabla->hphlocp_work);
2418 } else if (w->shift == 4) {
2419 clear_bit(TABLA_HPHR_PA_OFF_ACK,
2420 &tabla->hph_pa_dac_state);
2421 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
2422 &tabla->hph_pa_dac_state);
2423 if (tabla->hph_status & SND_JACK_OC_HPHR)
2424 schedule_work(&tabla->hphrocp_work);
2425 }
2426
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002427 if (tabla->mbhc_micbias_switched)
2428 tabla_codec_switch_micbias(codec, 0);
2429
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002430 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
2431 w->name);
2432 usleep_range(10000, 10000);
2433
2434 break;
2435 }
2436 return 0;
2437}
2438
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002439static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002440 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002441{
2442 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002443 unsigned int cfilt;
2444
Joonwoo Park0976d012011-12-22 11:48:18 -08002445 switch (tabla->micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002446 case TABLA_MICBIAS1:
2447 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
2448 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
2449 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
2450 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
2451 break;
2452 case TABLA_MICBIAS2:
2453 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
2454 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
2455 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
2456 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
2457 break;
2458 case TABLA_MICBIAS3:
2459 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
2460 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
2461 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
2462 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
2463 break;
2464 case TABLA_MICBIAS4:
2465 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002466 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
2467 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
2468 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002469 break;
2470 default:
2471 /* Should never reach here */
2472 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07002473 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002474 }
2475
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002476 micbias_regs->cfilt_sel = cfilt;
2477
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002478 switch (cfilt) {
2479 case TABLA_CFILT1_SEL:
2480 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
2481 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002482 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002483 break;
2484 case TABLA_CFILT2_SEL:
2485 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
2486 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002487 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002488 break;
2489 case TABLA_CFILT3_SEL:
2490 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
2491 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002492 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002493 break;
2494 }
2495}
Santosh Mardie15e2302011-11-15 10:39:23 +05302496static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
2497 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
2498 4, 0, NULL, 0),
2499 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
2500 0, NULL, 0),
2501};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002502
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002503static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
2504 struct snd_kcontrol *kcontrol, int event)
2505{
2506 struct snd_soc_codec *codec = w->codec;
2507
2508 pr_debug("%s %s %d\n", __func__, w->name, event);
2509
2510 switch (event) {
2511 case SND_SOC_DAPM_PRE_PMU:
2512 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2513 break;
2514
2515 case SND_SOC_DAPM_POST_PMD:
2516 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2517 break;
2518 }
2519 return 0;
2520}
2521
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002522static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
2523 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302524 0, tabla_codec_enable_micbias,
2525 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2526 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002527};
2528
2529static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
2530 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302531 0, tabla_codec_enable_micbias,
2532 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2533 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002534};
2535
Santosh Mardie15e2302011-11-15 10:39:23 +05302536static const struct snd_soc_dapm_route audio_i2s_map[] = {
2537 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2538 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2539 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2540 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2541 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2542
2543 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2544 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2545 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2546 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2547};
2548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002549static const struct snd_soc_dapm_route audio_map[] = {
2550 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551
2552 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2553 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2554
2555 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2556 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2557
2558 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2559 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2560
2561 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2562 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002563 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002564 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2565 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002566 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2567 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002568 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2569 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002570 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2571 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002572
2573 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002574 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2575 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2576 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002577 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002578 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2579 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2580
Kiran Kandi3426e512011-09-13 22:50:10 -07002581 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
2582 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
2583 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
2584 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
2585 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
2586 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
2587 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
2588 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
2589 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
2590 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
2591 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
2592
2593 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
2594 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
2595 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
2596 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
2597 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
2598 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
2599 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
2600 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
2601 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
2602 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
2603 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
2604
2605
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002606 /* Earpiece (RX MIX1) */
2607 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002608 {"EAR PA", NULL, "EAR_PA_MIXER"},
2609 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002610 {"DAC1", NULL, "CP"},
2611
2612 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2613 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2614 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002615
2616 /* Headset (RX MIX1 and RX MIX2) */
2617 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002618 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002619
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002620 {"HPHL", NULL, "HPHL_PA_MIXER"},
2621 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
2622
2623 {"HPHR", NULL, "HPHR_PA_MIXER"},
2624 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002625
2626 {"HPHL DAC", NULL, "CP"},
2627 {"HPHR DAC", NULL, "CP"},
2628
2629 {"ANC", NULL, "ANC1 MUX"},
2630 {"ANC", NULL, "ANC2 MUX"},
2631 {"ANC1 MUX", "ADC1", "ADC1"},
2632 {"ANC1 MUX", "ADC2", "ADC2"},
2633 {"ANC1 MUX", "ADC3", "ADC3"},
2634 {"ANC1 MUX", "ADC4", "ADC4"},
2635 {"ANC2 MUX", "ADC1", "ADC1"},
2636 {"ANC2 MUX", "ADC2", "ADC2"},
2637 {"ANC2 MUX", "ADC3", "ADC3"},
2638 {"ANC2 MUX", "ADC4", "ADC4"},
2639
Bradley Rubine1d08622011-07-20 18:01:35 -07002640 {"ANC", NULL, "CDC_CONN"},
2641
Bradley Rubin229c6a52011-07-12 16:18:48 -07002642 {"DAC1", "Switch", "RX1 CHAIN"},
2643 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002644 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002645
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002646 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2647 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2648 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2649 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2650 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002651
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002652 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2653 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
2654 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2655 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2656 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
2657 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
2658 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
2659 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
2660 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
2661 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002662
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002663 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2664 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2665
Bradley Rubin229c6a52011-07-12 16:18:48 -07002666 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2667 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2668 {"RX1 CHAIN", NULL, "ANC"},
2669 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002670
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002671 {"CP", NULL, "RX_BIAS"},
2672 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2673 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2674 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2675 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002676 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002677
Kuirong Wang0f8ade32012-02-27 16:29:45 -08002678 {"RX1 MIX1", NULL, "COMP1_CLK"},
2679 {"RX2 MIX1", NULL, "COMP1_CLK"},
2680 {"RX3 MIX1", NULL, "COMP2_CLK"},
2681 {"RX5 MIX1", NULL, "COMP2_CLK"},
2682
2683
Bradley Rubin229c6a52011-07-12 16:18:48 -07002684 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2685 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2686 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2687 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002688 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2689 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2690 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2691 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2692 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2693 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2694 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2695 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002696 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2697 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002698
Bradley Rubin229c6a52011-07-12 16:18:48 -07002699 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2700 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302701 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2702 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002703 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
2704 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002705 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2706 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2707 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302708 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2709 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002710 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
2711 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002712 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2713 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2714 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302715 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2716 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002717 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
2718 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002719 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002720 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2721 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302722 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2723 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002724 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
2725 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002726 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002727 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2728 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302729 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2730 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002731 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
2732 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002733 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002734 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2735 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302736 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2737 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002738 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
2739 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002740 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002741 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2742 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302743 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2744 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002745 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
2746 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002747 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002748 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2749 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302750 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2751 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002752 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
2753 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002754 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002755 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2756 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302757 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2758 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002759 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
2760 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002761 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002762 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2763 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302764 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2765 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002766 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
2767 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002768 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002769 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2770 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302771 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2772 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002773 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
2774 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002775 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002776 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2777 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302778 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2779 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002780 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
2781 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002782 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002783 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2784 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302785 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2786 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002787 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
2788 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002789 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002790 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2791 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302792 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2793 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002794 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
2795 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002796 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002797
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002798 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002799 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002800 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002801 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002802 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002803 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002804 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002805 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002806 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002807 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002808 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002809 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002810 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002811 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002813 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002814 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002815 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002816 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002817 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002818 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002819 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002820 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002821 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002822 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002823 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002824 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002825 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002826
2827 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002828 {"ADC1", NULL, "AMIC1"},
2829 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002830 {"ADC3", NULL, "AMIC3"},
2831 {"ADC4", NULL, "AMIC4"},
2832 {"ADC5", NULL, "AMIC5"},
2833 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002834
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002835 /* AUX PGA Connections */
2836 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2837 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2838 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2839 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2840 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2841 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2842 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2843 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2844 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2845 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2846 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2847 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2848 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2849 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2850 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2851 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2852 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2853 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2854 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2855 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2856 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2857 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2858 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2859 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2860 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2861 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2862 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2863 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2864 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2865 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2866 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2867 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2868 {"AUX_PGA_Left", NULL, "AMIC5"},
2869 {"AUX_PGA_Right", NULL, "AMIC6"},
2870
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002871 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002872 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2873 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2874 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2875 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2876 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002877 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002878 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
2879 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
2880 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
2881 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002882
2883 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2884 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2885 {"MIC BIAS1 External", NULL, "LDO_H"},
2886 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2887 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2888 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2889 {"MIC BIAS2 External", NULL, "LDO_H"},
2890 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2891 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2892 {"MIC BIAS3 External", NULL, "LDO_H"},
2893 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002894};
2895
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002896static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
2897
2898 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2899 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2900
2901 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
2902
2903 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
2904 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
2905 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
2906
2907 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2908 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2909
2910 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2911 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
2912 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
2913};
2914
Kiran Kandi7a9fd902011-11-14 13:51:45 -08002915
2916static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
2917
2918 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2919 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2920
2921 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
2922
2923 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
2924
2925 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2926 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2927
2928 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2929};
2930
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002931static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
2932{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002933 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302934 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002935
2936 if (TABLA_IS_1_X(tabla_core->version)) {
2937 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
2938 if (tabla_1_reg_readable[i] == reg)
2939 return 1;
2940 }
2941 } else {
2942 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
2943 if (tabla_2_reg_readable[i] == reg)
2944 return 1;
2945 }
2946 }
2947
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002948 return tabla_reg_readable[reg];
2949}
2950
2951static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2952{
2953 /* Registers lower than 0x100 are top level registers which can be
2954 * written by the Tabla core driver.
2955 */
2956
2957 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2958 return 1;
2959
Ben Romberger1f045a72011-11-04 10:14:57 -07002960 /* IIR Coeff registers are not cacheable */
2961 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
2962 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
2963 return 1;
2964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002965 return 0;
2966}
2967
2968#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2969static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
2970 unsigned int value)
2971{
2972 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002973 BUG_ON(reg > TABLA_MAX_REGISTER);
2974
2975 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002976 ret = snd_soc_cache_write(codec, reg, value);
2977 if (ret != 0)
2978 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2979 reg, ret);
2980 }
2981
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302982 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002983}
2984static unsigned int tabla_read(struct snd_soc_codec *codec,
2985 unsigned int reg)
2986{
2987 unsigned int val;
2988 int ret;
2989
2990 BUG_ON(reg > TABLA_MAX_REGISTER);
2991
2992 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
2993 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002994 ret = snd_soc_cache_read(codec, reg, &val);
2995 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002996 return val;
2997 } else
2998 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2999 reg, ret);
3000 }
3001
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303002 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003 return val;
3004}
3005
Bradley Rubincb1e2732011-06-23 16:49:20 -07003006static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3007{
Joonwoo Parkc0672392012-01-11 11:03:14 -08003008 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08003009 struct tabla_mbhc_btn_detect_cfg *btn_det;
3010 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08003011 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003012
Joonwoo Park0976d012011-12-22 11:48:18 -08003013 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
3014 tabla->mbhc_data.v_ins_hu & 0xFF);
3015 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
3016 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003017
Joonwoo Park0976d012011-12-22 11:48:18 -08003018 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
3019 tabla->mbhc_data.v_b1_hu & 0xFF);
3020 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
3021 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
3022
3023 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
3024 tabla->mbhc_data.v_b1_h & 0xFF);
3025 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
3026 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
3027
3028 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
3029 tabla->mbhc_data.v_brh & 0xFF);
3030 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
3031 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
3032
3033 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
3034 tabla->mbhc_data.v_brl & 0xFF);
3035 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
3036 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
3037
Joonwoo Parkc0672392012-01-11 11:03:14 -08003038 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003039 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08003040 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003041 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
3042 tabla->mbhc_data.npoll);
3043 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
3044 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08003045 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003046 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
3047 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003048}
3049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003050static int tabla_startup(struct snd_pcm_substream *substream,
3051 struct snd_soc_dai *dai)
3052{
Kuirong Wanga545e722012-02-06 19:12:54 -08003053 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003054 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3055 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003056 if ((tabla_core != NULL) &&
3057 (tabla_core->dev != NULL) &&
3058 (tabla_core->dev->parent != NULL))
3059 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003061 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003062}
3063
3064static void tabla_shutdown(struct snd_pcm_substream *substream,
3065 struct snd_soc_dai *dai)
3066{
Kuirong Wanga545e722012-02-06 19:12:54 -08003067 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003068 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3069 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003070 if ((tabla_core != NULL) &&
3071 (tabla_core->dev != NULL) &&
3072 (tabla_core->dev->parent != NULL)) {
3073 pm_runtime_mark_last_busy(tabla_core->dev->parent);
3074 pm_runtime_put(tabla_core->dev->parent);
3075 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003076}
3077
3078int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
3079{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003080 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3081
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003082 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003083
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003084 if (mclk_enable) {
3085 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003086
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003087 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07003088 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003089 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003090 TABLA_BANDGAP_AUDIO_MODE);
3091 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003092 tabla_codec_calibrate_hs_polling(codec);
3093 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303094 } else {
3095 tabla_codec_enable_bandgap(codec,
3096 TABLA_BANDGAP_AUDIO_MODE);
3097 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003098 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003099 } else {
3100
3101 if (!tabla->mclk_enabled) {
3102 pr_err("Error, MCLK already diabled\n");
3103 return -EINVAL;
3104 }
3105 tabla->mclk_enabled = false;
3106
3107 if (tabla->mbhc_polling_active) {
3108 if (!tabla->mclk_enabled) {
3109 tabla_codec_pause_hs_polling(codec);
3110 tabla_codec_enable_bandgap(codec,
3111 TABLA_BANDGAP_MBHC_MODE);
3112 tabla_enable_rx_bias(codec, 1);
3113 tabla_codec_enable_clock_block(codec, 1);
3114 tabla_codec_calibrate_hs_polling(codec);
3115 tabla_codec_start_hs_polling(codec);
3116 }
3117 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
3118 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303119 } else {
3120 tabla_codec_disable_clock_block(codec);
3121 tabla_codec_enable_bandgap(codec,
3122 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003123 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003124 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003125 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003126}
3127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003128static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
3129 int clk_id, unsigned int freq, int dir)
3130{
3131 pr_debug("%s\n", __func__);
3132 return 0;
3133}
3134
3135static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3136{
Santosh Mardie15e2302011-11-15 10:39:23 +05303137 u8 val = 0;
3138 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3139
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003140 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05303141 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3142 case SND_SOC_DAIFMT_CBS_CFS:
3143 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303144 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003145 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303146 snd_soc_update_bits(dai->codec,
3147 TABLA_A_CDC_CLK_TX_I2S_CTL,
3148 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003149 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303150 snd_soc_update_bits(dai->codec,
3151 TABLA_A_CDC_CLK_RX_I2S_CTL,
3152 TABLA_I2S_MASTER_MODE_MASK, 0);
3153 }
3154 break;
3155 case SND_SOC_DAIFMT_CBM_CFM:
3156 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303157 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303158 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003159 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303160 snd_soc_update_bits(dai->codec,
3161 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003162 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303163 snd_soc_update_bits(dai->codec,
3164 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
3165 }
3166 break;
3167 default:
3168 return -EINVAL;
3169 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003170 return 0;
3171}
3172
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003173static int tabla_set_channel_map(struct snd_soc_dai *dai,
3174 unsigned int tx_num, unsigned int *tx_slot,
3175 unsigned int rx_num, unsigned int *rx_slot)
3176
3177{
3178 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3179 u32 i = 0;
3180 if (!tx_slot && !rx_slot) {
3181 pr_err("%s: Invalid\n", __func__);
3182 return -EINVAL;
3183 }
3184 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3185
Neema Shettyd3a89262012-02-16 10:23:50 -08003186 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003187 for (i = 0; i < rx_num; i++) {
3188 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
3189 tabla->dai[dai->id - 1].ch_act = 0;
3190 tabla->dai[dai->id - 1].ch_tot = rx_num;
3191 }
3192 } else if (dai->id == AIF1_CAP) {
3193 for (i = 0; i < tx_num; i++) {
3194 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
3195 tabla->dai[dai->id - 1].ch_act = 0;
3196 tabla->dai[dai->id - 1].ch_tot = tx_num;
3197 }
3198 }
3199 return 0;
3200}
3201
3202static int tabla_get_channel_map(struct snd_soc_dai *dai,
3203 unsigned int *tx_num, unsigned int *tx_slot,
3204 unsigned int *rx_num, unsigned int *rx_slot)
3205
3206{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303207 struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003208
3209 u32 cnt = 0;
3210 u32 tx_ch[SLIM_MAX_TX_PORTS];
3211 u32 rx_ch[SLIM_MAX_RX_PORTS];
3212
3213 if (!rx_slot && !tx_slot) {
3214 pr_err("%s: Invalid\n", __func__);
3215 return -EINVAL;
3216 }
3217 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
3218 /* for virtual port, codec driver needs to do
3219 * housekeeping, for now should be ok
3220 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303221 wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003222 if (dai->id == AIF1_PB) {
3223 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3224 while (cnt < *rx_num) {
3225 rx_slot[cnt] = rx_ch[cnt];
3226 cnt++;
3227 }
3228 } else if (dai->id == AIF1_CAP) {
3229 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3230 while (cnt < *tx_num) {
3231 tx_slot[cnt] = tx_ch[6 + cnt];
3232 cnt++;
3233 }
Neema Shettyd3a89262012-02-16 10:23:50 -08003234 } else if (dai->id == AIF2_PB) {
3235 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3236 while (cnt < *rx_num) {
3237 rx_slot[cnt] = rx_ch[5 + cnt];
3238 cnt++;
3239 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003240 }
3241 return 0;
3242}
3243
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003244static int tabla_hw_params(struct snd_pcm_substream *substream,
3245 struct snd_pcm_hw_params *params,
3246 struct snd_soc_dai *dai)
3247{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003248 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05303249 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07003250 u8 path, shift;
3251 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003252 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003253 u32 compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003254
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003255 pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
3256 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003257
3258 switch (params_rate(params)) {
3259 case 8000:
3260 tx_fs_rate = 0x00;
3261 rx_fs_rate = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003262 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003263 break;
3264 case 16000:
3265 tx_fs_rate = 0x01;
3266 rx_fs_rate = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003267 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003268 break;
3269 case 32000:
3270 tx_fs_rate = 0x02;
3271 rx_fs_rate = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003272 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003273 break;
3274 case 48000:
3275 tx_fs_rate = 0x03;
3276 rx_fs_rate = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003277 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003278 break;
3279 default:
3280 pr_err("%s: Invalid sampling rate %d\n", __func__,
3281 params_rate(params));
3282 return -EINVAL;
3283 }
3284
3285
3286 /**
3287 * If current dai is a tx dai, set sample rate to
3288 * all the txfe paths that are currently not active
3289 */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003290 if (dai->id == AIF1_CAP) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003291
3292 tx_state = snd_soc_read(codec,
3293 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3294
3295 for (path = 1, shift = 0;
3296 path <= NUM_DECIMATORS; path++, shift++) {
3297
3298 if (path == BITS_PER_REG + 1) {
3299 shift = 0;
3300 tx_state = snd_soc_read(codec,
3301 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
3302 }
3303
3304 if (!(tx_state & (1 << shift))) {
3305 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
3306 + (BITS_PER_REG*(path-1));
3307 snd_soc_update_bits(codec, tx_fs_reg,
3308 0x03, tx_fs_rate);
3309 }
3310 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303311 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303312 switch (params_format(params)) {
3313 case SNDRV_PCM_FORMAT_S16_LE:
3314 snd_soc_update_bits(codec,
3315 TABLA_A_CDC_CLK_TX_I2S_CTL,
3316 0x20, 0x20);
3317 break;
3318 case SNDRV_PCM_FORMAT_S32_LE:
3319 snd_soc_update_bits(codec,
3320 TABLA_A_CDC_CLK_TX_I2S_CTL,
3321 0x20, 0x00);
3322 break;
3323 default:
3324 pr_err("invalid format\n");
3325 break;
3326 }
3327 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
3328 0x03, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003329 } else {
3330 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303331 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003332 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003333 /**
3334 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3335 * with varying sample rates
3336 */
3337
3338 /**
3339 * If current dai is a rx dai, set sample rate to
3340 * all the rx paths that are currently not active
3341 */
Neema Shettyd3a89262012-02-16 10:23:50 -08003342 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003343
3344 rx_state = snd_soc_read(codec,
3345 TABLA_A_CDC_CLK_RX_B1_CTL);
3346
3347 for (path = 1, shift = 0;
3348 path <= NUM_INTERPOLATORS; path++, shift++) {
3349
3350 if (!(rx_state & (1 << shift))) {
3351 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
3352 + (BITS_PER_REG*(path-1));
3353 snd_soc_update_bits(codec, rx_fs_reg,
3354 0xE0, rx_fs_rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003355 if (comp_rx_path[shift] < COMPANDER_MAX)
3356 tabla->comp_fs[comp_rx_path[shift]]
3357 = compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003358 }
3359 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303360 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303361 switch (params_format(params)) {
3362 case SNDRV_PCM_FORMAT_S16_LE:
3363 snd_soc_update_bits(codec,
3364 TABLA_A_CDC_CLK_RX_I2S_CTL,
3365 0x20, 0x20);
3366 break;
3367 case SNDRV_PCM_FORMAT_S32_LE:
3368 snd_soc_update_bits(codec,
3369 TABLA_A_CDC_CLK_RX_I2S_CTL,
3370 0x20, 0x00);
3371 break;
3372 default:
3373 pr_err("invalid format\n");
3374 break;
3375 }
3376 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
3377 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003378 } else {
3379 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303380 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003381 }
3382
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003383 return 0;
3384}
3385
3386static struct snd_soc_dai_ops tabla_dai_ops = {
3387 .startup = tabla_startup,
3388 .shutdown = tabla_shutdown,
3389 .hw_params = tabla_hw_params,
3390 .set_sysclk = tabla_set_dai_sysclk,
3391 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003392 .set_channel_map = tabla_set_channel_map,
3393 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003394};
3395
3396static struct snd_soc_dai_driver tabla_dai[] = {
3397 {
3398 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003399 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 .playback = {
3401 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003402 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403 .formats = TABLA_FORMATS,
3404 .rate_max = 48000,
3405 .rate_min = 8000,
3406 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003407 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003408 },
3409 .ops = &tabla_dai_ops,
3410 },
3411 {
3412 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003413 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003414 .capture = {
3415 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003416 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003417 .formats = TABLA_FORMATS,
3418 .rate_max = 48000,
3419 .rate_min = 8000,
3420 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003421 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003422 },
3423 .ops = &tabla_dai_ops,
3424 },
Neema Shettyd3a89262012-02-16 10:23:50 -08003425 {
3426 .name = "tabla_rx2",
3427 .id = AIF2_PB,
3428 .playback = {
3429 .stream_name = "AIF2 Playback",
3430 .rates = WCD9310_RATES,
3431 .formats = TABLA_FORMATS,
3432 .rate_min = 8000,
3433 .rate_max = 48000,
3434 .channels_min = 1,
3435 .channels_max = 2,
3436 },
3437 .ops = &tabla_dai_ops,
3438 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003439};
Santosh Mardie15e2302011-11-15 10:39:23 +05303440
3441static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3442 {
3443 .name = "tabla_i2s_rx1",
3444 .id = 1,
3445 .playback = {
3446 .stream_name = "AIF1 Playback",
3447 .rates = WCD9310_RATES,
3448 .formats = TABLA_FORMATS,
3449 .rate_max = 48000,
3450 .rate_min = 8000,
3451 .channels_min = 1,
3452 .channels_max = 4,
3453 },
3454 .ops = &tabla_dai_ops,
3455 },
3456 {
3457 .name = "tabla_i2s_tx1",
3458 .id = 2,
3459 .capture = {
3460 .stream_name = "AIF1 Capture",
3461 .rates = WCD9310_RATES,
3462 .formats = TABLA_FORMATS,
3463 .rate_max = 48000,
3464 .rate_min = 8000,
3465 .channels_min = 1,
3466 .channels_max = 4,
3467 },
3468 .ops = &tabla_dai_ops,
3469 },
3470};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003471
3472static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3473 struct snd_kcontrol *kcontrol, int event)
3474{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303475 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003476 struct snd_soc_codec *codec = w->codec;
3477 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3478 u32 j = 0;
3479 u32 ret = 0;
3480 codec->control_data = dev_get_drvdata(codec->dev->parent);
3481 tabla = codec->control_data;
3482 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303483 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003484 return 0;
3485 switch (event) {
3486 case SND_SOC_DAPM_POST_PMU:
3487 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3488 if (tabla_dai[j].id == AIF1_CAP)
3489 continue;
3490 if (!strncmp(w->sname,
3491 tabla_dai[j].playback.stream_name, 13)) {
3492 ++tabla_p->dai[j].ch_act;
3493 break;
3494 }
3495 }
3496 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303497 ret = wcd9xxx_cfg_slim_sch_rx(tabla,
3498 tabla_p->dai[j].ch_num,
3499 tabla_p->dai[j].ch_tot,
3500 tabla_p->dai[j].rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003501 break;
3502 case SND_SOC_DAPM_POST_PMD:
3503 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3504 if (tabla_dai[j].id == AIF1_CAP)
3505 continue;
3506 if (!strncmp(w->sname,
3507 tabla_dai[j].playback.stream_name, 13)) {
3508 --tabla_p->dai[j].ch_act;
3509 break;
3510 }
3511 }
3512 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303513 ret = wcd9xxx_close_slim_sch_rx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003514 tabla_p->dai[j].ch_num,
3515 tabla_p->dai[j].ch_tot);
3516 tabla_p->dai[j].rate = 0;
3517 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303518 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003519 tabla_p->dai[j].ch_tot = 0;
3520 }
3521 }
3522 return ret;
3523}
3524
3525static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3526 struct snd_kcontrol *kcontrol, int event)
3527{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303528 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003529 struct snd_soc_codec *codec = w->codec;
3530 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3531 /* index to the DAI ID, for now hardcoding */
3532 u32 j = 0;
3533 u32 ret = 0;
3534
3535 codec->control_data = dev_get_drvdata(codec->dev->parent);
3536 tabla = codec->control_data;
3537
3538 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303539 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003540 return 0;
3541 switch (event) {
3542 case SND_SOC_DAPM_POST_PMU:
3543 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003544 if (tabla_dai[j].id == AIF1_PB ||
3545 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003546 continue;
3547 if (!strncmp(w->sname,
3548 tabla_dai[j].capture.stream_name, 13)) {
3549 ++tabla_p->dai[j].ch_act;
3550 break;
3551 }
3552 }
3553 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303554 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003555 tabla_p->dai[j].ch_num,
3556 tabla_p->dai[j].ch_tot,
3557 tabla_p->dai[j].rate);
3558 break;
3559 case SND_SOC_DAPM_POST_PMD:
3560 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003561 if (tabla_dai[j].id == AIF1_PB ||
3562 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003563 continue;
3564 if (!strncmp(w->sname,
3565 tabla_dai[j].capture.stream_name, 13)) {
3566 --tabla_p->dai[j].ch_act;
3567 break;
3568 }
3569 }
3570 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303571 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003572 tabla_p->dai[j].ch_num,
3573 tabla_p->dai[j].ch_tot);
3574 tabla_p->dai[j].rate = 0;
3575 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303576 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003577 tabla_p->dai[j].ch_tot = 0;
3578 }
3579 }
3580 return ret;
3581}
3582
3583/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3584 * Might Need to have callbacks registered only for slimbus
3585 */
3586static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
3587 /*RX stuff */
3588 SND_SOC_DAPM_OUTPUT("EAR"),
3589
3590 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
3591
3592 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
3593 ARRAY_SIZE(dac1_switch)),
3594
3595 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3596 0, tabla_codec_enable_slimrx,
3597 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3598 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3599 0, tabla_codec_enable_slimrx,
3600 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3601
3602 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3603 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3604
Neema Shettyd3a89262012-02-16 10:23:50 -08003605 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3606 0, tabla_codec_enable_slimrx,
3607 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3608 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3609 0, tabla_codec_enable_slimrx,
3610 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3611
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003612 /* Headphone */
3613 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3614 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3615 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3616 SND_SOC_DAPM_POST_PMD),
3617 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
3618 hphl_switch, ARRAY_SIZE(hphl_switch)),
3619
3620 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
3621 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3622 SND_SOC_DAPM_POST_PMD),
3623
3624 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
3625 tabla_hphr_dac_event,
3626 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3627
3628 /* Speaker */
3629 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
3630 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
3631 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
3632 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
3633 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
3634
3635 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
3636 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3637 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3638 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
3639 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3640 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3641 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
3642 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3643 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3644 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
3645 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3646 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3647 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
3648 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3649 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3650
3651 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
3652 , tabla_lineout_dac_event,
3653 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3654 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
3655 , tabla_lineout_dac_event,
3656 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3657 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
3658 , tabla_lineout_dac_event,
3659 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3660 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
3661 &lineout3_ground_switch),
3662 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
3663 , tabla_lineout_dac_event,
3664 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3665 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
3666 &lineout4_ground_switch),
3667 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
3668 , tabla_lineout_dac_event,
3669 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3670
3671 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
3672 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3673 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
3674 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3675 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
3676 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3677 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
3678 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3679 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
3680 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3681 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
3682 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3683 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
3684 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3685
3686 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
3687 &rx4_dsm_mux, tabla_codec_reset_interpolator,
3688 SND_SOC_DAPM_PRE_PMU),
3689
3690 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
3691 &rx6_dsm_mux, tabla_codec_reset_interpolator,
3692 SND_SOC_DAPM_PRE_PMU),
3693
3694 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
3695 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
3696
3697 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3698 &rx_mix1_inp1_mux),
3699 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3700 &rx_mix1_inp2_mux),
3701 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3702 &rx2_mix1_inp1_mux),
3703 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3704 &rx2_mix1_inp2_mux),
3705 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3706 &rx3_mix1_inp1_mux),
3707 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3708 &rx3_mix1_inp2_mux),
3709 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3710 &rx4_mix1_inp1_mux),
3711 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3712 &rx4_mix1_inp2_mux),
3713 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3714 &rx5_mix1_inp1_mux),
3715 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3716 &rx5_mix1_inp2_mux),
3717 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3718 &rx6_mix1_inp1_mux),
3719 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3720 &rx6_mix1_inp2_mux),
3721 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3722 &rx7_mix1_inp1_mux),
3723 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3724 &rx7_mix1_inp2_mux),
3725
3726 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
3727 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
3728 SND_SOC_DAPM_PRE_PMD),
3729
3730 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
3731 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
3732 SND_SOC_DAPM_POST_PMD),
3733
3734 /* TX */
3735
3736 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
3737 0),
3738
3739 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
3740 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
3741
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003742 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
3743 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3744 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3745 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
3746 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3747 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3748
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003749 SND_SOC_DAPM_INPUT("AMIC1"),
3750 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
3751 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3752 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3753 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
3754 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3755 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3756 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
3757 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3758 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3759 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
3760 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3761 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3762
3763 SND_SOC_DAPM_INPUT("AMIC3"),
3764 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
3765 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3766 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3767
3768 SND_SOC_DAPM_INPUT("AMIC4"),
3769 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
3770 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3771 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3772
3773 SND_SOC_DAPM_INPUT("AMIC5"),
3774 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
3775 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3776
3777 SND_SOC_DAPM_INPUT("AMIC6"),
3778 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
3779 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3780
3781 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
3782 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3783
3784 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
3785 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3786
3787 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
3788 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3789
3790 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
3791 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3792
3793 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
3794 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3795
3796 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
3797 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3798
3799 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
3800 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3801
3802 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
3803 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3804
3805 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
3806 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3807
3808 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
3809 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3810
3811 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
3812 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
3813
3814 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
3815 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
3816 SND_SOC_DAPM_POST_PMD),
3817
3818 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
3819
3820 SND_SOC_DAPM_INPUT("AMIC2"),
3821 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
3822 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3823 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3824 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
3825 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3826 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3827 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
3828 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3829 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3830 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
3831 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3832 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3833 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
3834 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3835 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3836 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
3837 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3838 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3839 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
3840 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3841 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3842 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
3843 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3844 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3845
3846 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
3847 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
3848 0, 0),
3849
3850 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
3851 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
3852 4, 0),
3853
3854 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
3855 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
3856 5, 0),
3857
3858 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
3859 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3860 0, tabla_codec_enable_slimtx,
3861 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3862
3863 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
3864 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3865 0, tabla_codec_enable_slimtx,
3866 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3867
3868 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
3869 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
3870 0, 0, tabla_codec_enable_slimtx,
3871 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3872
3873 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
3874 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
3875 0, 0, tabla_codec_enable_slimtx,
3876 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3877
3878 /* Digital Mic Inputs */
3879 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
3880 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3881 SND_SOC_DAPM_POST_PMD),
3882
3883 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
3884 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3885 SND_SOC_DAPM_POST_PMD),
3886
3887 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
3888 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3889 SND_SOC_DAPM_POST_PMD),
3890
3891 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
3892 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3893 SND_SOC_DAPM_POST_PMD),
3894
3895 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
3896 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3897 SND_SOC_DAPM_POST_PMD),
3898 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
3899 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3900 SND_SOC_DAPM_POST_PMD),
3901
3902 /* Sidetone */
3903 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
3904 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003905
3906 /* AUX PGA */
3907 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
3908 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3909 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
3910 SND_SOC_DAPM_POST_PMD),
3911
3912 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
3913 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3914 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
3915 SND_SOC_DAPM_POST_PMD),
3916
3917 /* Lineout, ear and HPH PA Mixers */
3918 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
3919 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
3920
3921 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
3922 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
3923
3924 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
3925 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
3926
3927 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
3928 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
3929
3930 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
3931 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
3932
3933 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
3934 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
3935
3936 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
3937 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
3938
3939 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
3940 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003941};
3942
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003943static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07003944{
3945 u8 bias_msb, bias_lsb;
3946 short bias_value;
3947
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003948 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
3949 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
3950 bias_value = (bias_msb << 8) | bias_lsb;
3951 return bias_value;
3952}
3953
3954static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
3955{
3956 u8 bias_msb, bias_lsb;
3957 short bias_value;
3958
3959 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
3960 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
3961 bias_value = (bias_msb << 8) | bias_lsb;
3962 return bias_value;
3963}
3964
Joonwoo Park0976d012011-12-22 11:48:18 -08003965static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003966{
Joonwoo Park0976d012011-12-22 11:48:18 -08003967 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003968 short bias_value;
3969
Joonwoo Park925914c2012-01-05 13:35:18 -08003970 /* Turn on the override */
3971 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003972 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003973 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3974 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
3975 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003976 usleep_range(tabla->mbhc_data.t_sta_dce,
3977 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003978 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08003979 usleep_range(tabla->mbhc_data.t_dce,
3980 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003981 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003982 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003983 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003984 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3985 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08003986 usleep_range(tabla->mbhc_data.t_sta_dce,
3987 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08003988 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
3989 usleep_range(tabla->mbhc_data.t_sta,
3990 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07003991 bias_value = tabla_codec_read_sta_result(codec);
3992 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
3993 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003994 }
Joonwoo Park925914c2012-01-05 13:35:18 -08003995 /* Turn off the override after measuring mic voltage */
3996 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003997
Bradley Rubincb1e2732011-06-23 16:49:20 -07003998 return bias_value;
3999}
4000
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004001static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004002{
4003 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004004 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004005 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004006
Joonwoo Park0976d012011-12-22 11:48:18 -08004007 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004008 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004009 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004010 }
4011
4012 tabla->mbhc_polling_active = true;
4013
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004014 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004015 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004016 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004017 tabla_codec_enable_clock_block(codec, 1);
4018 }
4019
4020 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004022 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
4023
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004024 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004025 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4026 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004027
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004028 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004029
4030 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004031 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004032
4033 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4034 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4035 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4036
4037 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004038 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4039 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004040
Joonwoo Park925914c2012-01-05 13:35:18 -08004041 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004042 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4043
Bradley Rubincb1e2732011-06-23 16:49:20 -07004044 tabla_codec_calibrate_hs_polling(codec);
4045
Joonwoo Park0976d012011-12-22 11:48:18 -08004046 bias_value = tabla_codec_sta_dce(codec, 0);
4047 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4048 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004049 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004050
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004051 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004052}
4053
4054static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
4055 int insertion)
4056{
4057 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004058 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08004059 const struct tabla_mbhc_general_cfg *generic =
4060 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
4061 const struct tabla_mbhc_plug_detect_cfg *plug_det =
4062 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004063 u8 wg_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004064
Joonwoo Park0976d012011-12-22 11:48:18 -08004065 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004066 pr_err("Error, no tabla calibration\n");
4067 return -EINVAL;
4068 }
4069
4070 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
4071
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004072 if (insertion) {
4073 /* Make sure mic bias and Mic line schmitt trigger
4074 * are turned OFF
4075 */
4076 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
4077 0x81, 0x01);
4078 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4079 0x90, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004080 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4081 wg_time += 1;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004082
4083 /* Enable HPH Schmitt Trigger */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004084 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11, 0x11);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004085 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
Joonwoo Park0976d012011-12-22 11:48:18 -08004086 plug_det->hph_current << 2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004087
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004088 /* Turn off HPH PAs and DAC's during insertion detection to
4089 * avoid false insertion interrupts
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004090 */
4091 if (tabla->mbhc_micbias_switched)
4092 tabla_codec_switch_micbias(codec, 0);
4093 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004094 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08004095 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004096 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
Joonwoo Park0976d012011-12-22 11:48:18 -08004097 0xC0, 0x00);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004098 usleep_range(wg_time * 1000, wg_time * 1000);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004099
4100 /* setup for insetion detection */
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004101 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02, 0x02);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004102 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004103 } else {
4104 /* Make sure the HPH schmitt trigger is OFF */
4105 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
4106
4107 /* enable the mic line schmitt trigger */
4108 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08004109 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004110 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4111 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004112 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004113 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4114 0x10, 0x10);
4115
4116 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004117 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004118 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004119
4120 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
4121 if (!(tabla->clock_active)) {
4122 tabla_codec_enable_config_mode(codec, 1);
4123 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004124 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004125 usleep_range(generic->t_shutdown_plug_rem,
4126 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004127 tabla_codec_enable_config_mode(codec, 0);
4128 } else
4129 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004130 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004131 }
4132
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004133 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004134
4135 /* If central bandgap disabled */
4136 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
4137 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004138 usleep_range(generic->t_bg_fast_settle,
4139 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 central_bias_enabled = 1;
4141 }
4142
4143 /* If LDO_H disabled */
4144 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
4145 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
4146 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004147 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004148 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
4149
4150 if (central_bias_enabled)
4151 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
4152 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004153
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004154 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
4155 tabla->micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004156
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304157 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004158 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4159 return 0;
4160}
4161
Joonwoo Park0976d012011-12-22 11:48:18 -08004162static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4163 s16 vin_mv)
4164{
4165 short diff, zero;
4166 struct tabla_priv *tabla;
4167 u32 mb_mv, in;
4168
4169 tabla = snd_soc_codec_get_drvdata(codec);
4170 mb_mv = tabla->mbhc_data.micb_mv;
4171
4172 if (mb_mv == 0) {
4173 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4174 return -EINVAL;
4175 }
4176
4177 if (dce) {
4178 diff = tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z;
4179 zero = tabla->mbhc_data.dce_z;
4180 } else {
4181 diff = tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z;
4182 zero = tabla->mbhc_data.sta_z;
4183 }
4184 in = (u32) diff * vin_mv;
4185
4186 return (u16) (in / mb_mv) + zero;
4187}
4188
4189static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4190 u16 bias_value)
4191{
4192 struct tabla_priv *tabla;
4193 s32 mv;
4194
4195 tabla = snd_soc_codec_get_drvdata(codec);
4196
4197 if (dce) {
4198 mv = ((s32)bias_value - (s32)tabla->mbhc_data.dce_z) *
4199 (s32)tabla->mbhc_data.micb_mv /
4200 (s32)(tabla->mbhc_data.dce_mb - tabla->mbhc_data.dce_z);
4201 } else {
4202 mv = ((s32)bias_value - (s32)tabla->mbhc_data.sta_z) *
4203 (s32)tabla->mbhc_data.micb_mv /
4204 (s32)(tabla->mbhc_data.sta_mb - tabla->mbhc_data.sta_z);
4205 }
4206
4207 return mv;
4208}
4209
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004210static void btn0_lpress_fn(struct work_struct *work)
4211{
4212 struct delayed_work *delayed_work;
4213 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08004214 short bias_value;
4215 int dce_mv, sta_mv;
Joonwoo Park816b8e62012-01-23 16:03:21 -08004216 struct tabla *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004217
4218 pr_debug("%s:\n", __func__);
4219
4220 delayed_work = to_delayed_work(work);
4221 tabla = container_of(delayed_work, struct tabla_priv, btn0_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004222 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004223
4224 if (tabla) {
4225 if (tabla->button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004226 bias_value = tabla_codec_read_sta_result(tabla->codec);
4227 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304228 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004229 bias_value = tabla_codec_read_dce_result(tabla->codec);
4230 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304231 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004232 pr_debug("%s: Reporting long button press event"
4233 " STA: %d, DCE: %d\n", __func__,
4234 sta_mv, dce_mv);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004235 tabla_snd_soc_jack_report(tabla, tabla->button_jack,
4236 SND_JACK_BTN_0,
4237 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004238 }
4239 } else {
4240 pr_err("%s: Bad tabla private data\n", __func__);
4241 }
4242
4243}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004244
Joonwoo Park0976d012011-12-22 11:48:18 -08004245void tabla_mbhc_cal(struct snd_soc_codec *codec)
4246{
4247 struct tabla_priv *tabla;
4248 struct tabla_mbhc_btn_detect_cfg *btn_det;
4249 u8 cfilt_mode, bg_mode;
4250 u8 ncic, nmeas, navg;
4251 u32 mclk_rate;
4252 u32 dce_wait, sta_wait;
4253 u8 *n_cic;
4254
4255 tabla = snd_soc_codec_get_drvdata(codec);
4256
4257 /* First compute the DCE / STA wait times
4258 * depending on tunable parameters.
4259 * The value is computed in microseconds
4260 */
4261 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
4262 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08004263 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Park0976d012011-12-22 11:48:18 -08004264 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
4265 navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
4266 mclk_rate = tabla->mclk_freq;
Joonwoo Park433149a2012-01-11 09:53:54 -08004267 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
4268 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08004269
4270 tabla->mbhc_data.t_dce = dce_wait;
4271 tabla->mbhc_data.t_sta = sta_wait;
4272
4273 /* LDOH and CFILT are already configured during pdata handling.
4274 * Only need to make sure CFILT and bandgap are in Fast mode.
4275 * Need to restore defaults once calculation is done.
4276 */
4277 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4278 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
4279 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
4280 0x02);
4281
4282 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
4283 * to perform ADC calibration
4284 */
4285 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
4286 tabla->micbias << 5);
4287 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
4288 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
4289 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
4290 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
4291
4292 /* DCE measurement for 0 volts */
4293 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4294 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4295 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004296 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4297 usleep_range(100, 100);
4298 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4299 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4300 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
4301
4302 /* DCE measurment for MB voltage */
4303 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4304 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
4305 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4306 usleep_range(100, 100);
4307 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4308 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4309 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
4310
4311 /* Sta measuremnt for 0 volts */
4312 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4313 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4314 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004315 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4316 usleep_range(100, 100);
4317 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4318 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4319 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
4320
4321 /* STA Measurement for MB Voltage */
4322 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4323 usleep_range(100, 100);
4324 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4325 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4326 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
4327
4328 /* Restore default settings. */
4329 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4330 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4331 cfilt_mode);
4332 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
4333
4334 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
4335 usleep_range(100, 100);
4336}
4337
4338void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
4339 const enum tabla_mbhc_btn_det_mem mem)
4340{
4341 void *ret = &btn_det->_v_btn_low;
4342
4343 switch (mem) {
4344 case TABLA_BTN_DET_GAIN:
4345 ret += sizeof(btn_det->_n_cic);
4346 case TABLA_BTN_DET_N_CIC:
4347 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08004348 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08004349 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
4350 case TABLA_BTN_DET_V_BTN_HIGH:
4351 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
4352 case TABLA_BTN_DET_V_BTN_LOW:
4353 /* do nothing */
4354 break;
4355 default:
4356 ret = NULL;
4357 }
4358
4359 return ret;
4360}
4361
4362static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
4363{
4364 struct tabla_priv *tabla;
4365 s16 btn_mv = 0, btn_delta_mv;
4366 struct tabla_mbhc_btn_detect_cfg *btn_det;
4367 struct tabla_mbhc_plug_type_cfg *plug_type;
4368 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004369 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08004370 int i;
4371
4372 tabla = snd_soc_codec_get_drvdata(codec);
4373 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
4374 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
4375
Joonwoo Parkc0672392012-01-11 11:03:14 -08004376 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08004377 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004378 tabla->mbhc_data.npoll = 9;
4379 tabla->mbhc_data.nbounce_wait = 30;
4380 } else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004381 tabla->mbhc_data.npoll = 7;
4382 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004383 }
Joonwoo Park0976d012011-12-22 11:48:18 -08004384
Joonwoo Park433149a2012-01-11 09:53:54 -08004385 tabla->mbhc_data.t_sta_dce = ((1000 * 256) / (tabla->mclk_freq / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08004386 n_ready[tabla_codec_mclk_index(tabla)]) +
4387 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08004388 tabla->mbhc_data.v_ins_hu =
4389 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
4390 tabla->mbhc_data.v_ins_h =
4391 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
4392
4393 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
4394 for (i = 0; i < btn_det->num_btn; i++)
4395 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
4396
4397 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
4398 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
4399
4400 tabla->mbhc_data.v_b1_hu =
4401 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
4402
4403 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
4404
4405 tabla->mbhc_data.v_b1_huc =
4406 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
4407
4408 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
4409 tabla->mbhc_data.v_brl = 0xFA55;
4410
4411 tabla->mbhc_data.v_no_mic =
4412 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
4413}
4414
4415void tabla_mbhc_init(struct snd_soc_codec *codec)
4416{
4417 struct tabla_priv *tabla;
4418 struct tabla_mbhc_general_cfg *generic;
4419 struct tabla_mbhc_btn_detect_cfg *btn_det;
4420 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08004421 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304422 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08004423
4424 tabla = snd_soc_codec_get_drvdata(codec);
4425 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
4426 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
4427
Joonwoo Park0976d012011-12-22 11:48:18 -08004428 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08004429 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004430 snd_soc_update_bits(codec,
4431 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
4432 0x07, n);
4433 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
4434 btn_det->c[n]);
4435 }
4436 }
4437 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
4438 btn_det->nc);
4439
4440 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
4441 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08004442 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08004443
4444 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08004445 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
4446 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004447
4448 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
4449 generic->mbhc_nsa << 4);
4450
4451 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
4452 btn_det->n_meas);
4453
4454 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
4455
4456 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
4457
4458 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
4459 btn_det->mbhc_nsc << 3);
4460
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004461 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
4462 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08004463
4464 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
4465}
4466
Patrick Lai64b43262011-12-06 17:29:15 -08004467static bool tabla_mbhc_fw_validate(const struct firmware *fw)
4468{
4469 u32 cfg_offset;
4470 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
4471 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
4472
4473 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
4474 return false;
4475
4476 /* previous check guarantees that there is enough fw data up
4477 * to num_btn
4478 */
4479 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
4480 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
4481 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
4482 return false;
4483
4484 /* previous check guarantees that there is enough fw data up
4485 * to start of impedance detection configuration
4486 */
4487 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
4488 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
4489
4490 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
4491 return false;
4492
4493 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
4494 return false;
4495
4496 return true;
4497}
4498static void mbhc_fw_read(struct work_struct *work)
4499{
4500 struct delayed_work *dwork;
4501 struct tabla_priv *tabla;
4502 struct snd_soc_codec *codec;
4503 const struct firmware *fw;
4504 int ret = -1, retry = 0, rc;
4505
4506 dwork = to_delayed_work(work);
4507 tabla = container_of(dwork, struct tabla_priv,
4508 mbhc_firmware_dwork);
4509 codec = tabla->codec;
4510
4511 while (retry < MBHC_FW_READ_ATTEMPTS) {
4512 retry++;
4513 pr_info("%s:Attempt %d to request MBHC firmware\n",
4514 __func__, retry);
4515 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
4516 codec->dev);
4517
4518 if (ret != 0) {
4519 usleep_range(MBHC_FW_READ_TIMEOUT,
4520 MBHC_FW_READ_TIMEOUT);
4521 } else {
4522 pr_info("%s: MBHC Firmware read succesful\n", __func__);
4523 break;
4524 }
4525 }
4526
4527 if (ret != 0) {
4528 pr_err("%s: Cannot load MBHC firmware use default cal\n",
4529 __func__);
4530 } else if (tabla_mbhc_fw_validate(fw) == false) {
4531 pr_err("%s: Invalid MBHC cal data size use default cal\n",
4532 __func__);
4533 release_firmware(fw);
4534 } else {
4535 tabla->calibration = (void *)fw->data;
4536 tabla->mbhc_fw = fw;
4537 }
4538
4539 tabla->mclk_cb(codec, 1);
4540 tabla_mbhc_init(codec);
4541 tabla_mbhc_cal(codec);
4542 tabla_mbhc_calc_thres(codec);
4543 tabla->mclk_cb(codec, 0);
4544 tabla_codec_calibrate_hs_polling(codec);
4545 rc = tabla_codec_enable_hs_detect(codec, 1);
4546
4547 if (IS_ERR_VALUE(rc))
4548 pr_err("%s: Failed to setup MBHC detection\n", __func__);
4549
4550}
4551
Bradley Rubincb1e2732011-06-23 16:49:20 -07004552int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park0976d012011-12-22 11:48:18 -08004553 struct snd_soc_jack *headset_jack,
4554 struct snd_soc_jack *button_jack,
4555 void *calibration, enum tabla_micbias_num micbias,
4556 int (*mclk_cb_fn) (struct snd_soc_codec*, int),
4557 int read_fw_bin, u32 mclk_rate)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004558{
4559 struct tabla_priv *tabla;
Patrick Lai64b43262011-12-06 17:29:15 -08004560 int rc = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07004561
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004562 if (!codec || !calibration) {
4563 pr_err("Error: no codec or calibration\n");
4564 return -EINVAL;
4565 }
Joonwoo Park107edf02012-01-11 11:42:24 -08004566
4567 if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
4568 if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
4569 pr_err("Error: clock rate %dHz is not yet supported\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304570 mclk_rate);
Joonwoo Park107edf02012-01-11 11:42:24 -08004571 else
4572 pr_err("Error: unsupported clock rate %d\n", mclk_rate);
4573 return -EINVAL;
4574 }
4575
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004576 tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004577 tabla->headset_jack = headset_jack;
4578 tabla->button_jack = button_jack;
Joonwoo Park0976d012011-12-22 11:48:18 -08004579 tabla->micbias = micbias;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004580 tabla->calibration = calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08004581 tabla->mclk_cb = mclk_cb_fn;
4582 tabla->mclk_freq = mclk_rate;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004583 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004584
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004585 /* Put CFILT in fast mode by default */
4586 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
4587 0x40, TABLA_CFILT_FAST_MODE);
Patrick Lai64b43262011-12-06 17:29:15 -08004588 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004589 INIT_DELAYED_WORK(&tabla->btn0_dwork, btn0_lpress_fn);
Patrick Lai49efeac2011-11-03 11:01:12 -07004590 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
4591 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
Joonwoo Park0976d012011-12-22 11:48:18 -08004592
4593 if (!read_fw_bin) {
4594 tabla->mclk_cb(codec, 1);
4595 tabla_mbhc_init(codec);
4596 tabla_mbhc_cal(codec);
4597 tabla_mbhc_calc_thres(codec);
4598 tabla->mclk_cb(codec, 0);
4599 tabla_codec_calibrate_hs_polling(codec);
4600 rc = tabla_codec_enable_hs_detect(codec, 1);
4601 } else {
Patrick Lai64b43262011-12-06 17:29:15 -08004602 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
4603 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Joonwoo Park0976d012011-12-22 11:48:18 -08004604 }
Patrick Lai49efeac2011-11-03 11:01:12 -07004605
4606 if (!IS_ERR_VALUE(rc)) {
4607 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4608 0x10);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304609 wcd9xxx_enable_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07004610 TABLA_IRQ_HPH_PA_OCPL_FAULT);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304611 wcd9xxx_enable_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07004612 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4613 }
4614
4615 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004616}
4617EXPORT_SYMBOL_GPL(tabla_hs_detect);
4618
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004619static int tabla_determine_button(const struct tabla_priv *priv,
4620 const s32 bias_mv)
4621{
4622 s16 *v_btn_low, *v_btn_high;
4623 struct tabla_mbhc_btn_detect_cfg *btn_det;
4624 int i, btn = -1;
4625
4626 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
4627 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
4628 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304629 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004630 for (i = 0; i < btn_det->num_btn; i++) {
4631 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
4632 btn = i;
4633 break;
4634 }
4635 }
4636
4637 if (btn == -1)
4638 pr_debug("%s: couldn't find button number for mic mv %d\n",
4639 __func__, bias_mv);
4640
4641 return btn;
4642}
4643
4644static int tabla_get_button_mask(const int btn)
4645{
4646 int mask = 0;
4647 switch (btn) {
4648 case 0:
4649 mask = SND_JACK_BTN_0;
4650 break;
4651 case 1:
4652 mask = SND_JACK_BTN_1;
4653 break;
4654 case 2:
4655 mask = SND_JACK_BTN_2;
4656 break;
4657 case 3:
4658 mask = SND_JACK_BTN_3;
4659 break;
4660 case 4:
4661 mask = SND_JACK_BTN_4;
4662 break;
4663 case 5:
4664 mask = SND_JACK_BTN_5;
4665 break;
4666 case 6:
4667 mask = SND_JACK_BTN_6;
4668 break;
4669 case 7:
4670 mask = SND_JACK_BTN_7;
4671 break;
4672 }
4673 return mask;
4674}
4675
Bradley Rubincb1e2732011-06-23 16:49:20 -07004676static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004677{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004678 int i, mask;
4679 short bias_value_dce;
4680 s32 bias_mv_dce;
4681 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004682 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004683 const struct tabla_mbhc_btn_detect_cfg *d =
4684 TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
4685 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004686 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304687 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004688
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304689 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4690 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004691
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004692 bias_value_dce = tabla_codec_read_dce_result(codec);
4693 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004694
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004695 /* determine pressed button */
4696 btnmeas[meas++] = tabla_determine_button(priv, bias_mv_dce);
4697 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
4698 meas - 1, bias_value_dce, bias_mv_dce, btnmeas[meas - 1]);
4699 if (d->n_btn_meas == 0)
4700 btn = btnmeas[0];
4701 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
4702 bias_value_dce = tabla_codec_sta_dce(codec, 1);
4703 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
4704 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
4705 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
4706 __func__, meas, bias_value_dce, bias_mv_dce,
4707 btnmeas[meas]);
4708 /* if large enough measurements are collected,
4709 * start to check if last all n_btn_con measurements were
4710 * in same button low/high range */
4711 if (meas + 1 >= d->n_btn_con) {
4712 for (i = 0; i < d->n_btn_con; i++)
4713 if ((btnmeas[meas] < 0) ||
4714 (btnmeas[meas] != btnmeas[meas - i]))
4715 break;
4716 if (i == d->n_btn_con) {
4717 /* button pressed */
4718 btn = btnmeas[meas];
4719 break;
4720 }
4721 }
4722 /* if left measurements are less than n_btn_con,
4723 * it's impossible to find button number */
4724 if ((d->n_btn_meas - meas) < d->n_btn_con)
4725 break;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004726 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004727
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004728 if (btn >= 0) {
4729 mask = tabla_get_button_mask(btn);
4730 priv->buttons_pressed |= mask;
4731
4732 msleep(100);
4733
4734 /* XXX: assuming button 0 has the lowest micbias voltage */
4735 if (btn == 0) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304736 wcd9xxx_lock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004737 if (schedule_delayed_work(&priv->btn0_dwork,
4738 msecs_to_jiffies(400)) == 0) {
4739 WARN(1, "Button pressed twice without release"
4740 "event\n");
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304741 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004742 }
4743 } else {
4744 pr_debug("%s: Reporting short button %d(0x%x) press\n",
4745 __func__, btn, mask);
4746 tabla_snd_soc_jack_report(priv, priv->button_jack, mask,
4747 mask);
4748 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08004749 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004750 pr_debug("%s: bogus button press, too short press?\n",
4751 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004752 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004754 return IRQ_HANDLED;
4755}
4756
Bradley Rubincb1e2732011-06-23 16:49:20 -07004757static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004758{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08004759 int ret;
4760 short mb_v;
Joonwoo Park816b8e62012-01-23 16:03:21 -08004761 struct tabla_priv *priv = data;
4762 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304763 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004764
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004765 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304766 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004767
Bradley Rubincb1e2732011-06-23 16:49:20 -07004768 if (priv->buttons_pressed & SND_JACK_BTN_0) {
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004769 ret = cancel_delayed_work(&priv->btn0_dwork);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004770 if (ret == 0) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004771 pr_debug("%s: Reporting long button 0 release event\n",
4772 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08004773 if (priv->button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004774 tabla_snd_soc_jack_report(priv,
4775 priv->button_jack, 0,
4776 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004777 } else {
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004778 /* if scheduled btn0_dwork is canceled from here,
4779 * we have to unlock from here instead btn0_work */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304780 wcd9xxx_unlock_sleep(core);
Joonwoo Park0976d012011-12-22 11:48:18 -08004781 mb_v = tabla_codec_sta_dce(codec, 0);
4782 pr_debug("%s: Mic Voltage on release STA: %d,%d\n",
4783 __func__, mb_v,
4784 tabla_codec_sta_dce_v(codec, 0, mb_v));
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004785
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08004786 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
4787 mb_v > (short)priv->mbhc_data.v_ins_hu)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004788 pr_debug("%s: Fake buttton press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004789 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08004790 else if (priv->button_jack) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004791 pr_debug("%s: Reporting short button 0 "
Joonwoo Park0976d012011-12-22 11:48:18 -08004792 "press and release\n", __func__);
4793 tabla_snd_soc_jack_report(priv,
4794 priv->button_jack,
4795 SND_JACK_BTN_0,
4796 SND_JACK_BTN_0);
4797 tabla_snd_soc_jack_report(priv,
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004798 priv->button_jack, 0,
4799 SND_JACK_BTN_0);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004800 }
4801 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004802
Bradley Rubincb1e2732011-06-23 16:49:20 -07004803 priv->buttons_pressed &= ~SND_JACK_BTN_0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004804 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004805
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004806 if (priv->buttons_pressed) {
4807 pr_debug("%s:reporting button release mask 0x%x\n", __func__,
4808 priv->buttons_pressed);
4809 tabla_snd_soc_jack_report(priv, priv->button_jack, 0,
4810 priv->buttons_pressed);
4811 /* hardware doesn't detect another button press until
4812 * already pressed button is released.
4813 * therefore buttons_pressed has only one button's mask. */
4814 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
4815 }
4816
Bradley Rubin688c66a2011-08-16 12:25:13 -07004817 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004818 return IRQ_HANDLED;
4819}
4820
Bradley Rubincb1e2732011-06-23 16:49:20 -07004821static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
4822{
4823 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08004824 const struct tabla_mbhc_general_cfg *generic =
4825 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004826
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004827 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004828 tabla_codec_enable_config_mode(codec, 1);
4829
4830 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
4831 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004832
Joonwoo Park0976d012011-12-22 11:48:18 -08004833 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
4834
4835 usleep_range(generic->t_shutdown_plug_rem,
4836 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004837
4838 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004839 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004840 tabla_codec_enable_config_mode(codec, 0);
4841
4842 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
4843}
4844
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004845static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
4846{
4847 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004848
4849 tabla_codec_shutdown_hs_removal_detect(codec);
4850
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004851 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004852 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05304853 tabla_codec_disable_clock_block(codec);
4854 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004855 }
4856
4857 tabla->mbhc_polling_active = false;
4858}
4859
Patrick Lai49efeac2011-11-03 11:01:12 -07004860static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
4861{
4862 struct tabla_priv *tabla = data;
4863 struct snd_soc_codec *codec;
4864
4865 pr_info("%s: received HPHL OCP irq\n", __func__);
4866
4867 if (tabla) {
4868 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004869 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
4870 pr_info("%s: retry\n", __func__);
4871 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4872 0x00);
4873 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4874 0x10);
4875 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304876 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08004877 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4878 tabla->hphlocp_cnt = 0;
4879 tabla->hph_status |= SND_JACK_OC_HPHL;
4880 if (tabla->headset_jack)
4881 tabla_snd_soc_jack_report(tabla,
4882 tabla->headset_jack,
4883 tabla->hph_status,
4884 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07004885 }
4886 } else {
4887 pr_err("%s: Bad tabla private data\n", __func__);
4888 }
4889
4890 return IRQ_HANDLED;
4891}
4892
4893static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
4894{
4895 struct tabla_priv *tabla = data;
4896 struct snd_soc_codec *codec;
4897
4898 pr_info("%s: received HPHR OCP irq\n", __func__);
4899
4900 if (tabla) {
4901 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004902 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
4903 pr_info("%s: retry\n", __func__);
4904 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4905 0x00);
4906 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4907 0x10);
4908 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304909 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08004910 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4911 tabla->hphrocp_cnt = 0;
4912 tabla->hph_status |= SND_JACK_OC_HPHR;
4913 if (tabla->headset_jack)
4914 tabla_snd_soc_jack_report(tabla,
4915 tabla->headset_jack,
4916 tabla->hph_status,
4917 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07004918 }
4919 } else {
4920 pr_err("%s: Bad tabla private data\n", __func__);
4921 }
4922
4923 return IRQ_HANDLED;
4924}
4925
Joonwoo Parka9444452011-12-08 18:48:27 -08004926static void tabla_sync_hph_state(struct tabla_priv *tabla)
4927{
4928 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304929 &tabla->hph_pa_dac_state)) {
Joonwoo Parka9444452011-12-08 18:48:27 -08004930 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4931 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4932 1 << 4);
4933 }
4934 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304935 &tabla->hph_pa_dac_state)) {
Joonwoo Parka9444452011-12-08 18:48:27 -08004936 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4937 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4938 1 << 5);
4939 }
4940
4941 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304942 &tabla->hph_pa_dac_state)) {
Joonwoo Parka9444452011-12-08 18:48:27 -08004943 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4944 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4945 0xC0, 0xC0);
4946 }
4947 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304948 &tabla->hph_pa_dac_state)) {
Joonwoo Parka9444452011-12-08 18:48:27 -08004949 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4950 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4951 0xC0, 0xC0);
4952 }
4953}
4954
Bradley Rubincb1e2732011-06-23 16:49:20 -07004955static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
4956{
4957 struct tabla_priv *priv = data;
4958 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08004959 const struct tabla_mbhc_plug_detect_cfg *plug_det =
4960 TABLA_MBHC_CAL_PLUG_DET_PTR(priv->calibration);
Bradley Rubin355611a2011-08-24 14:01:18 -07004961 int ldo_h_on, micb_cfilt_on;
Joonwoo Park0976d012011-12-22 11:48:18 -08004962 short mb_v;
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004963 u8 is_removal;
Joonwoo Park0976d012011-12-22 11:48:18 -08004964 int mic_mv;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004965
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004966 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304967 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004968
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004969 is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
4970 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
4971
4972 /* Turn off both HPH and MIC line schmitt triggers */
Joonwoo Park0976d012011-12-22 11:48:18 -08004973 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004974 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004975
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004976 if (priv->mbhc_fake_ins_start &&
4977 time_after(jiffies, priv->mbhc_fake_ins_start +
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304978 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004979 pr_debug("%s: fake context interrupt, reset insertion\n",
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004980 __func__);
4981 priv->mbhc_fake_ins_start = 0;
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08004982 tabla_codec_shutdown_hs_polling(codec);
4983 tabla_codec_enable_hs_detect(codec, 1);
4984 return IRQ_HANDLED;
4985 }
4986
Bradley Rubin355611a2011-08-24 14:01:18 -07004987 ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
Joonwoo Park0976d012011-12-22 11:48:18 -08004988 micb_cfilt_on = snd_soc_read(codec, priv->mbhc_bias_regs.cfilt_ctl)
4989 & 0x80;
Bradley Rubin355611a2011-08-24 14:01:18 -07004990
4991 if (!ldo_h_on)
4992 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x80);
4993 if (!micb_cfilt_on)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004994 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08004995 0x80, 0x80);
4996 if (plug_det->t_ins_complete > 20)
4997 msleep(plug_det->t_ins_complete);
4998 else
4999 usleep_range(plug_det->t_ins_complete * 1000,
5000 plug_det->t_ins_complete * 1000);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005001
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005002 if (!ldo_h_on)
5003 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x80, 0x0);
5004 if (!micb_cfilt_on)
5005 snd_soc_update_bits(codec, priv->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park0976d012011-12-22 11:48:18 -08005006 0x80, 0x0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005007
5008 if (is_removal) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005009 /*
5010 * If headphone is removed while playback is in progress,
5011 * it is possible that micbias will be switched to VDDIO.
5012 */
5013 if (priv->mbhc_micbias_switched)
5014 tabla_codec_switch_micbias(codec, 0);
Patrick Lai72aa4da2011-12-08 12:38:18 -08005015 priv->hph_status &= ~SND_JACK_HEADPHONE;
Joonwoo Parka9444452011-12-08 18:48:27 -08005016
5017 /* If headphone PA is on, check if userspace receives
5018 * removal event to sync-up PA's state */
5019 if (tabla_is_hph_pa_on(codec)) {
5020 set_bit(TABLA_HPHL_PA_OFF_ACK, &priv->hph_pa_dac_state);
5021 set_bit(TABLA_HPHR_PA_OFF_ACK, &priv->hph_pa_dac_state);
5022 }
5023
5024 if (tabla_is_hph_dac_on(codec, 1))
5025 set_bit(TABLA_HPHL_DAC_OFF_ACK,
5026 &priv->hph_pa_dac_state);
5027 if (tabla_is_hph_dac_on(codec, 0))
5028 set_bit(TABLA_HPHR_DAC_OFF_ACK,
5029 &priv->hph_pa_dac_state);
5030
Bradley Rubincb1e2732011-06-23 16:49:20 -07005031 if (priv->headset_jack) {
5032 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005033 tabla_snd_soc_jack_report(priv, priv->headset_jack,
5034 priv->hph_status,
5035 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005036 }
5037 tabla_codec_shutdown_hs_removal_detect(codec);
5038 tabla_codec_enable_hs_detect(codec, 1);
5039 return IRQ_HANDLED;
5040 }
5041
Joonwoo Park0976d012011-12-22 11:48:18 -08005042 mb_v = tabla_codec_setup_hs_polling(codec);
5043 mic_mv = tabla_codec_sta_dce_v(codec, 0, mb_v);
Bradley Rubin355611a2011-08-24 14:01:18 -07005044
Joonwoo Park0976d012011-12-22 11:48:18 -08005045 if (mb_v > (short) priv->mbhc_data.v_ins_hu) {
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005046 pr_debug("%s: Fake insertion interrupt since %dmsec ago, "
5047 "STA : %d,%d\n", __func__,
5048 (priv->mbhc_fake_ins_start ?
5049 jiffies_to_msecs(jiffies -
5050 priv->mbhc_fake_ins_start) :
5051 0),
5052 mb_v, mic_mv);
5053 if (time_after(jiffies,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305054 priv->mbhc_fake_ins_start +
5055 msecs_to_jiffies(TABLA_FAKE_INS_THRESHOLD_MS))) {
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005056 /* Disable HPH trigger and enable MIC line trigger */
5057 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12,
5058 0x00);
5059 snd_soc_update_bits(codec,
5060 priv->mbhc_bias_regs.mbhc_reg, 0x60,
5061 plug_det->mic_current << 5);
5062 snd_soc_update_bits(codec,
5063 priv->mbhc_bias_regs.mbhc_reg,
5064 0x80, 0x80);
5065 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
5066 snd_soc_update_bits(codec,
5067 priv->mbhc_bias_regs.mbhc_reg,
5068 0x10, 0x10);
5069 } else {
5070 if (priv->mbhc_fake_ins_start == 0)
5071 priv->mbhc_fake_ins_start = jiffies;
5072 /* Setup normal insert detection
5073 * Enable HPH Schmitt Trigger
5074 */
5075 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH,
5076 0x13 | 0x0C,
5077 0x13 | plug_det->hph_current << 2);
5078 }
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08005079 /* Setup for insertion detection */
5080 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305081 wcd9xxx_enable_irq(codec->control_data,
5082 TABLA_IRQ_MBHC_INSERTION);
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08005083 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
5084
Joonwoo Park0976d012011-12-22 11:48:18 -08005085 } else if (mb_v < (short) priv->mbhc_data.v_no_mic) {
5086 pr_debug("%s: Headphone Detected, mb_v: %d,%d\n",
5087 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005088 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07005089 priv->hph_status |= SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005090 if (priv->headset_jack) {
5091 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08005092 SND_JACK_HEADPHONE);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005093 tabla_snd_soc_jack_report(priv, priv->headset_jack,
5094 priv->hph_status,
5095 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005096 }
5097 tabla_codec_shutdown_hs_polling(codec);
5098 tabla_codec_enable_hs_detect(codec, 0);
Joonwoo Parka9444452011-12-08 18:48:27 -08005099 tabla_sync_hph_state(priv);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07005100 } else {
Joonwoo Park0976d012011-12-22 11:48:18 -08005101 pr_debug("%s: Headset detected, mb_v: %d,%d\n",
5102 __func__, mb_v, mic_mv);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005103 priv->mbhc_fake_ins_start = 0;
Patrick Lai49efeac2011-11-03 11:01:12 -07005104 priv->hph_status |= SND_JACK_HEADSET;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005105 if (priv->headset_jack) {
5106 pr_debug("%s: Reporting insertion %d\n", __func__,
Joonwoo Park0976d012011-12-22 11:48:18 -08005107 SND_JACK_HEADSET);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005108 tabla_snd_soc_jack_report(priv, priv->headset_jack,
5109 priv->hph_status,
5110 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005111 }
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005112 /* avoid false button press detect */
5113 msleep(50);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005114 tabla_codec_start_hs_polling(codec);
Joonwoo Parka9444452011-12-08 18:48:27 -08005115 tabla_sync_hph_state(priv);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005116 }
5117
5118 return IRQ_HANDLED;
5119}
5120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005121static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
5122{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005123 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005124 struct tabla_priv *priv = data;
5125 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08005126 const struct tabla_mbhc_general_cfg *generic =
5127 TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005128 int fake_removal = 0;
5129 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005130
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005131 pr_debug("%s: enter, removal interrupt\n", __func__);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305132 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
5133 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
5134 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005135
Joonwoo Park0976d012011-12-22 11:48:18 -08005136 usleep_range(generic->t_shutdown_plug_rem,
5137 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005138
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005139 do {
5140 bias_value = tabla_codec_sta_dce(codec, 1);
5141 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
5142 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
5143 if (bias_value < (short)priv->mbhc_data.v_ins_h) {
5144 fake_removal = 1;
5145 break;
5146 }
5147 min_us -= priv->mbhc_data.t_dce;
5148 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005149
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005150 if (fake_removal) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005151 pr_debug("False alarm, headset not actually removed\n");
5152 tabla_codec_start_hs_polling(codec);
5153 } else {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005154 /*
5155 * If this removal is not false, first check the micbias
5156 * switch status and switch it to LDOH if it is already
5157 * switched to VDDIO.
5158 */
5159 if (priv->mbhc_micbias_switched)
5160 tabla_codec_switch_micbias(codec, 0);
Patrick Lai49efeac2011-11-03 11:01:12 -07005161 priv->hph_status &= ~SND_JACK_HEADSET;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005162 if (priv->headset_jack) {
5163 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005164 tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
5165 TABLA_JACK_MASK);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005166 }
5167 tabla_codec_shutdown_hs_polling(codec);
5168
5169 tabla_codec_enable_hs_detect(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005170 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005172 return IRQ_HANDLED;
5173}
5174
5175static unsigned long slimbus_value;
5176
5177static irqreturn_t tabla_slimbus_irq(int irq, void *data)
5178{
5179 struct tabla_priv *priv = data;
5180 struct snd_soc_codec *codec = priv->codec;
5181 int i, j;
5182 u8 val;
5183
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305184 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
5185 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005186 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
5187 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305188 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005189 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
5190 if (val & 0x1)
5191 pr_err_ratelimited("overflow error on port %x,"
5192 " value %x\n", i*8 + j, val);
5193 if (val & 0x2)
5194 pr_err_ratelimited("underflow error on port %x,"
5195 " value %x\n", i*8 + j, val);
5196 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305197 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005198 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
5199 }
5200
5201 return IRQ_HANDLED;
5202}
5203
Patrick Lai3043fba2011-08-01 14:15:57 -07005204
5205static int tabla_handle_pdata(struct tabla_priv *tabla)
5206{
5207 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305208 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07005209 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05305210 u8 leg_mode = pdata->amic_settings.legacy_mode;
5211 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
5212 u8 txfe_buff = pdata->amic_settings.txfe_buff;
5213 u8 flag = pdata->amic_settings.use_pdata;
5214 u8 i = 0, j = 0;
5215 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07005216
5217 if (!pdata) {
5218 rc = -ENODEV;
5219 goto done;
5220 }
5221
5222 /* Make sure settings are correct */
5223 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
5224 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
5225 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
5226 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
5227 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
5228 rc = -EINVAL;
5229 goto done;
5230 }
5231
5232 /* figure out k value */
5233 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
5234 pdata->micbias.cfilt1_mv);
5235 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
5236 pdata->micbias.cfilt2_mv);
5237 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
5238 pdata->micbias.cfilt3_mv);
5239
5240 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
5241 rc = -EINVAL;
5242 goto done;
5243 }
5244
5245 /* Set voltage level and always use LDO */
5246 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
5247 (pdata->micbias.ldoh_v << 2));
5248
5249 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
5250 (k1 << 2));
5251 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
5252 (k2 << 2));
5253 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
5254 (k3 << 2));
5255
5256 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
5257 (pdata->micbias.bias1_cfilt_sel << 5));
5258 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
5259 (pdata->micbias.bias2_cfilt_sel << 5));
5260 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
5261 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005262 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
5263 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07005264
Santosh Mardi22920282011-10-26 02:38:40 +05305265 for (i = 0; i < 6; j++, i += 2) {
5266 if (flag & (0x01 << i)) {
5267 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
5268 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
5269 val_txfe = val_txfe |
5270 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
5271 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
5272 0x10, value);
5273 snd_soc_update_bits(codec,
5274 TABLA_A_TX_1_2_TEST_EN + j * 10,
5275 0x30, val_txfe);
5276 }
5277 if (flag & (0x01 << (i + 1))) {
5278 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
5279 val_txfe = (txfe_bypass &
5280 (0x01 << (i + 1))) ? 0x02 : 0x00;
5281 val_txfe |= (txfe_buff &
5282 (0x01 << (i + 1))) ? 0x01 : 0x00;
5283 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
5284 0x01, value);
5285 snd_soc_update_bits(codec,
5286 TABLA_A_TX_1_2_TEST_EN + j * 10,
5287 0x03, val_txfe);
5288 }
5289 }
5290 if (flag & 0x40) {
5291 value = (leg_mode & 0x40) ? 0x10 : 0x00;
5292 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
5293 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
5294 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
5295 0x13, value);
5296 }
Patrick Lai49efeac2011-11-03 11:01:12 -07005297
5298 if (pdata->ocp.use_pdata) {
5299 /* not defined in CODEC specification */
5300 if (pdata->ocp.hph_ocp_limit == 1 ||
5301 pdata->ocp.hph_ocp_limit == 5) {
5302 rc = -EINVAL;
5303 goto done;
5304 }
5305 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
5306 0x0F, pdata->ocp.num_attempts);
5307 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
5308 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
5309 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
5310 0xE0, (pdata->ocp.hph_ocp_limit << 5));
5311 }
Patrick Lai3043fba2011-08-01 14:15:57 -07005312done:
5313 return rc;
5314}
5315
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005316static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
5317
5318 /* Tabla 1.1 MICBIAS changes */
5319 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
5320 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
5321 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005322
5323 /* Tabla 1.1 HPH changes */
5324 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
5325 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
5326
5327 /* Tabla 1.1 EAR PA changes */
5328 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
5329 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
5330 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
5331
5332 /* Tabla 1.1 Lineout_5 Changes */
5333 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
5334
5335 /* Tabla 1.1 RX Changes */
5336 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
5337 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
5338 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
5339 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
5340 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
5341 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
5342 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
5343
5344 /* Tabla 1.1 RX1 and RX2 Changes */
5345 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
5346 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
5347
5348 /* Tabla 1.1 RX3 to RX7 Changes */
5349 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
5350 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
5351 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
5352 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
5353 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
5354
5355 /* Tabla 1.1 CLASSG Changes */
5356 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
5357};
5358
5359static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005360 /* Tabla 2.0 MICBIAS changes */
5361 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
5362};
5363
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005364static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
5365 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
5366};
5367
5368static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
5369 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
5370};
5371
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005372static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
5373{
5374 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305375 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005376
5377 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
5378 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
5379 tabla_1_1_reg_defaults[i].val);
5380
5381 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
5382 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
5383 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005384
5385 if (TABLA_IS_1_X(tabla_core->version)) {
5386 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
5387 i++)
5388 snd_soc_write(codec,
5389 tabla_1_x_only_reg_2_0_defaults[i].reg,
5390 tabla_1_x_only_reg_2_0_defaults[i].val);
5391 } else {
5392 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
5393 snd_soc_write(codec,
5394 tabla_2_only_reg_2_0_defaults[i].reg,
5395 tabla_2_only_reg_2_0_defaults[i].val);
5396 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005397}
5398
5399static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08005400 /* Initialize current threshold to 350MA
5401 * number of wait and run cycles to 4096
5402 */
Patrick Lai49efeac2011-11-03 11:01:12 -07005403 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08005404 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005405
Santosh Mardi32171012011-10-28 23:32:06 +05305406 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
5407
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005408 /* Initialize gain registers to use register gain */
5409 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
5410 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
5411 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
5412 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
5413 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
5414 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
5415
5416 /* Initialize mic biases to differential mode */
5417 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
5418 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
5419 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005420
5421 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
5422
5423 /* Use 16 bit sample size for TX1 to TX6 */
5424 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
5425 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
5426 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
5427 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
5428 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
5429 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
5430
5431 /* Use 16 bit sample size for TX7 to TX10 */
5432 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
5433 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
5434 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
5435 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
5436
5437 /* Use 16 bit sample size for RX */
5438 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
5439 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
5440
5441 /*enable HPF filter for TX paths */
5442 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
5443 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
5444 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
5445 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
5446 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
5447 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
5448 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
5449 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
5450 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
5451 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
5452};
5453
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005454static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
5455 /* Initialize mic biases to differential mode */
5456 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
5457};
5458
5459static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
5460 /* Initialize mic biases to differential mode */
5461 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
5462};
5463
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005464static void tabla_codec_init_reg(struct snd_soc_codec *codec)
5465{
5466 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305467 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005468
5469 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
5470 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
5471 tabla_codec_reg_init_val[i].mask,
5472 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005473 if (TABLA_IS_1_X(tabla_core->version)) {
5474 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
5475 snd_soc_update_bits(codec,
5476 tabla_1_x_codec_reg_init_val[i].reg,
5477 tabla_1_x_codec_reg_init_val[i].mask,
5478 tabla_1_x_codec_reg_init_val[i].val);
5479 } else {
5480 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
5481 i++)
5482 snd_soc_update_bits(codec,
5483 tabla_2_higher_codec_reg_init_val[i].reg,
5484 tabla_2_higher_codec_reg_init_val[i].mask,
5485 tabla_2_higher_codec_reg_init_val[i].val);
5486 }
5487}
5488
5489static void tabla_update_reg_address(struct tabla_priv *priv)
5490{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305491 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005492 struct tabla_reg_address *reg_addr = &priv->reg_addr;
5493
5494 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08005495 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
5496 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005497 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005498 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08005499 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
5500 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005501 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005502 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005503}
5504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005505static int tabla_codec_probe(struct snd_soc_codec *codec)
5506{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305507 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005508 struct tabla_priv *tabla;
5509 struct snd_soc_dapm_context *dapm = &codec->dapm;
5510 int ret = 0;
5511 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005512 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005513
5514 codec->control_data = dev_get_drvdata(codec->dev->parent);
5515 control = codec->control_data;
5516
5517 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
5518 if (!tabla) {
5519 dev_err(codec->dev, "Failed to allocate private data\n");
5520 return -ENOMEM;
5521 }
5522
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07005523 /* Make sure mbhc micbias register addresses are zeroed out */
5524 memset(&tabla->mbhc_bias_regs, 0,
5525 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005526 tabla->cfilt_k_value = 0;
5527 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07005528
Joonwoo Park0976d012011-12-22 11:48:18 -08005529 /* Make sure mbhc intenal calibration data is zeroed out */
5530 memset(&tabla->mbhc_data, 0,
5531 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08005532 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08005533 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
5534 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005535 snd_soc_codec_set_drvdata(codec, tabla);
5536
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005537 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005538 tabla->bandgap_type = TABLA_BANDGAP_OFF;
5539 tabla->clock_active = false;
5540 tabla->config_mode_active = false;
5541 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005542 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07005543 tabla->no_mic_headset_override = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005544 tabla->codec = codec;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08005545 for (i = 0; i < COMPANDER_MAX; i++) {
5546 tabla->comp_enabled[i] = 0;
5547 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
5548 }
Patrick Lai3043fba2011-08-01 14:15:57 -07005549 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305550 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08005551 tabla->aux_pga_cnt = 0;
5552 tabla->aux_l_gain = 0x1F;
5553 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005554 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05305555 tabla_update_reg_defaults(codec);
5556 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05305557 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07005558 if (IS_ERR_VALUE(ret)) {
5559 pr_err("%s: bad pdata\n", __func__);
5560 goto err_pdata;
5561 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005562
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005563 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005564 ARRAY_SIZE(tabla_snd_controls));
5565 if (TABLA_IS_1_X(control->version))
5566 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
5567 ARRAY_SIZE(tabla_1_x_snd_controls));
5568 else
5569 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
5570 ARRAY_SIZE(tabla_2_higher_snd_controls));
5571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005572 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005573 ARRAY_SIZE(tabla_dapm_widgets));
5574 if (TABLA_IS_1_X(control->version))
5575 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
5576 ARRAY_SIZE(tabla_1_x_dapm_widgets));
5577 else
5578 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
5579 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
5580
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305581 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05305582 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
5583 ARRAY_SIZE(tabla_dapm_i2s_widgets));
5584 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
5585 ARRAY_SIZE(audio_i2s_map));
5586 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005587 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07005588
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005589 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08005590 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005591 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
5592 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08005593 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005594 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08005595 } else {
5596 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305597 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08005598 goto err_pdata;
5599 }
5600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005601 snd_soc_dapm_sync(dapm);
5602
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305603 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005604 tabla_hs_insert_irq, "Headset insert detect", tabla);
5605 if (ret) {
5606 pr_err("%s: Failed to request irq %d\n", __func__,
5607 TABLA_IRQ_MBHC_INSERTION);
5608 goto err_insert_irq;
5609 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305610 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005611
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305612 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005613 tabla_hs_remove_irq, "Headset remove detect", tabla);
5614 if (ret) {
5615 pr_err("%s: Failed to request irq %d\n", __func__,
5616 TABLA_IRQ_MBHC_REMOVAL);
5617 goto err_remove_irq;
5618 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305619 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005620
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305621 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07005622 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005623 if (ret) {
5624 pr_err("%s: Failed to request irq %d\n", __func__,
5625 TABLA_IRQ_MBHC_POTENTIAL);
5626 goto err_potential_irq;
5627 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305628 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005629
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305630 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07005631 tabla_release_handler, "Button Release detect", tabla);
5632 if (ret) {
5633 pr_err("%s: Failed to request irq %d\n", __func__,
5634 TABLA_IRQ_MBHC_RELEASE);
5635 goto err_release_irq;
5636 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305637 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005638
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305639 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005640 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
5641 if (ret) {
5642 pr_err("%s: Failed to request irq %d\n", __func__,
5643 TABLA_IRQ_SLIMBUS);
5644 goto err_slimbus_irq;
5645 }
5646
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305647 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
5648 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005649 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
5650
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305651 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07005652 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
5653 "HPH_L OCP detect", tabla);
5654 if (ret) {
5655 pr_err("%s: Failed to request irq %d\n", __func__,
5656 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5657 goto err_hphl_ocp_irq;
5658 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305659 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07005660
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305661 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07005662 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
5663 "HPH_R OCP detect", tabla);
5664 if (ret) {
5665 pr_err("%s: Failed to request irq %d\n", __func__,
5666 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5667 goto err_hphr_ocp_irq;
5668 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305669 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005670 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
5671 switch (tabla_dai[i].id) {
5672 case AIF1_PB:
5673 ch_cnt = tabla_dai[i].playback.channels_max;
5674 break;
5675 case AIF1_CAP:
5676 ch_cnt = tabla_dai[i].capture.channels_max;
5677 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08005678 case AIF2_PB:
5679 ch_cnt = tabla_dai[i].playback.channels_max;
5680 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005681 default:
5682 continue;
5683 }
5684 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
5685 ch_cnt), GFP_KERNEL);
5686 }
Patrick Lai49efeac2011-11-03 11:01:12 -07005687
Bradley Rubincb3950a2011-08-18 13:07:26 -07005688#ifdef CONFIG_DEBUG_FS
5689 debug_tabla_priv = tabla;
5690#endif
5691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005692 return ret;
5693
Patrick Lai49efeac2011-11-03 11:01:12 -07005694err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305695 wcd9xxx_free_irq(codec->control_data,
5696 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07005697err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305698 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005699err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305700 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005701err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305702 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005703err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305704 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005705err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305706 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005707err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07005708err_pdata:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005709 kfree(tabla);
5710 return ret;
5711}
5712static int tabla_codec_remove(struct snd_soc_codec *codec)
5713{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005714 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005715 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305716 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
5717 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
5718 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
5719 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
5720 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005721 tabla_codec_disable_clock_block(codec);
5722 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08005723 if (tabla->mbhc_fw)
5724 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005725 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
5726 kfree(tabla->dai[i].ch_num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005727 kfree(tabla);
5728 return 0;
5729}
5730static struct snd_soc_codec_driver soc_codec_dev_tabla = {
5731 .probe = tabla_codec_probe,
5732 .remove = tabla_codec_remove,
5733 .read = tabla_read,
5734 .write = tabla_write,
5735
5736 .readable_register = tabla_readable,
5737 .volatile_register = tabla_volatile,
5738
5739 .reg_cache_size = TABLA_CACHE_SIZE,
5740 .reg_cache_default = tabla_reg_defaults,
5741 .reg_word_size = 1,
5742};
Bradley Rubincb3950a2011-08-18 13:07:26 -07005743
5744#ifdef CONFIG_DEBUG_FS
5745static struct dentry *debugfs_poke;
5746
5747static int codec_debug_open(struct inode *inode, struct file *file)
5748{
5749 file->private_data = inode->i_private;
5750 return 0;
5751}
5752
5753static ssize_t codec_debug_write(struct file *filp,
5754 const char __user *ubuf, size_t cnt, loff_t *ppos)
5755{
5756 char lbuf[32];
5757 char *buf;
5758 int rc;
5759
5760 if (cnt > sizeof(lbuf) - 1)
5761 return -EINVAL;
5762
5763 rc = copy_from_user(lbuf, ubuf, cnt);
5764 if (rc)
5765 return -EFAULT;
5766
5767 lbuf[cnt] = '\0';
5768 buf = (char *)lbuf;
5769 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
5770 ? false : true;
Bradley Rubincb3950a2011-08-18 13:07:26 -07005771 return rc;
5772}
5773
5774static const struct file_operations codec_debug_ops = {
5775 .open = codec_debug_open,
5776 .write = codec_debug_write,
5777};
5778#endif
5779
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005780#ifdef CONFIG_PM
5781static int tabla_suspend(struct device *dev)
5782{
Joonwoo Park816b8e62012-01-23 16:03:21 -08005783 dev_dbg(dev, "%s: system suspend\n", __func__);
5784 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005785}
5786
5787static int tabla_resume(struct device *dev)
5788{
Joonwoo Park816b8e62012-01-23 16:03:21 -08005789 dev_dbg(dev, "%s: system resume\n", __func__);
5790 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005791}
5792
5793static const struct dev_pm_ops tabla_pm_ops = {
5794 .suspend = tabla_suspend,
5795 .resume = tabla_resume,
5796};
5797#endif
5798
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005799static int __devinit tabla_probe(struct platform_device *pdev)
5800{
Santosh Mardie15e2302011-11-15 10:39:23 +05305801 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07005802#ifdef CONFIG_DEBUG_FS
5803 debugfs_poke = debugfs_create_file("TRRS",
5804 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
5805
5806#endif
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305807 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05305808 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
5809 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305810 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05305811 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
5812 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
5813 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005814}
5815static int __devexit tabla_remove(struct platform_device *pdev)
5816{
5817 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07005818
5819#ifdef CONFIG_DEBUG_FS
5820 debugfs_remove(debugfs_poke);
5821#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005822 return 0;
5823}
5824static struct platform_driver tabla_codec_driver = {
5825 .probe = tabla_probe,
5826 .remove = tabla_remove,
5827 .driver = {
5828 .name = "tabla_codec",
5829 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005830#ifdef CONFIG_PM
5831 .pm = &tabla_pm_ops,
5832#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005833 },
5834};
5835
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005836static struct platform_driver tabla1x_codec_driver = {
5837 .probe = tabla_probe,
5838 .remove = tabla_remove,
5839 .driver = {
5840 .name = "tabla1x_codec",
5841 .owner = THIS_MODULE,
5842#ifdef CONFIG_PM
5843 .pm = &tabla_pm_ops,
5844#endif
5845 },
5846};
5847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005848static int __init tabla_codec_init(void)
5849{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005850 int rtn = platform_driver_register(&tabla_codec_driver);
5851 if (rtn == 0) {
5852 rtn = platform_driver_register(&tabla1x_codec_driver);
5853 if (rtn != 0)
5854 platform_driver_unregister(&tabla_codec_driver);
5855 }
5856 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005857}
5858
5859static void __exit tabla_codec_exit(void)
5860{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005861 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005862 platform_driver_unregister(&tabla_codec_driver);
5863}
5864
5865module_init(tabla_codec_init);
5866module_exit(tabla_codec_exit);
5867
5868MODULE_DESCRIPTION("Tabla codec driver");
5869MODULE_VERSION("1.0");
5870MODULE_LICENSE("GPL v2");