blob: 851722ae5b1bbfa37671f097cf05e34d36a3c863 [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
Joonwoo Park03324832012-03-19 19:36:16 -070046enum {
47 MBHC_USE_HPHL_TRIGGER = 1,
48 MBHC_USE_MB_TRIGGER = 2
49};
50
51#define MBHC_NUM_DCE_PLUG_DETECT 3
52
Patrick Lai49efeac2011-11-03 11:01:12 -070053#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
54
Santosh Mardie15e2302011-11-15 10:39:23 +053055#define TABLA_I2S_MASTER_MODE_MASK 0x08
56
Patrick Laic7cae882011-11-18 11:52:49 -080057#define TABLA_OCP_ATTEMPT 1
58
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080059#define AIF1_PB 1
60#define AIF1_CAP 2
Neema Shettyd3a89262012-02-16 10:23:50 -080061#define AIF2_PB 3
62#define NUM_CODEC_DAIS 3
Kuirong Wang0f8ade32012-02-27 16:29:45 -080063#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080064
65struct tabla_codec_dai_data {
66 u32 rate;
67 u32 *ch_num;
68 u32 ch_act;
69 u32 ch_tot;
70};
71
Joonwoo Park0976d012011-12-22 11:48:18 -080072#define TABLA_MCLK_RATE_12288KHZ 12288000
73#define TABLA_MCLK_RATE_9600KHZ 9600000
74
Joonwoo Parkf4267c22012-01-10 13:25:24 -080075#define TABLA_FAKE_INS_THRESHOLD_MS 2500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -080076#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
Joonwoo Parkf4267c22012-01-10 13:25:24 -080077
Joonwoo Park03324832012-03-19 19:36:16 -070078#define TABLA_MBHC_BUTTON_MIN 0x8000
79
80#define PLUG_TYPE_HEADPHONE (1 << 0)
81#define PLUG_TYPE_HEADSET (1 << 1)
82
83#define TABLA_MBHC_FAKE_INSERT_LOW 10
84#define TABLA_MBHC_FAKE_INSERT_HIGH 150
85
86#define TABLA_MBHC_STATUS_REL_DETECTION 0x0C
87
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
89static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
90static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080091static struct snd_soc_dai_driver tabla_dai[];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -080092static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093
94enum tabla_bandgap_type {
95 TABLA_BANDGAP_OFF = 0,
96 TABLA_BANDGAP_AUDIO_MODE,
97 TABLA_BANDGAP_MBHC_MODE,
98};
99
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700100struct mbhc_micbias_regs {
101 u16 cfilt_val;
102 u16 cfilt_ctl;
103 u16 mbhc_reg;
104 u16 int_rbias;
105 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -0800106 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700107};
108
Ben Romberger1f045a72011-11-04 10:14:57 -0700109/* Codec supports 2 IIR filters */
110enum {
111 IIR1 = 0,
112 IIR2,
113 IIR_MAX,
114};
115/* Codec supports 5 bands */
116enum {
117 BAND1 = 0,
118 BAND2,
119 BAND3,
120 BAND4,
121 BAND5,
122 BAND_MAX,
123};
124
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800125enum {
126 COMPANDER_1 = 0,
127 COMPANDER_2,
128 COMPANDER_MAX,
129};
130
131enum {
132 COMPANDER_FS_8KHZ = 0,
133 COMPANDER_FS_16KHZ,
134 COMPANDER_FS_32KHZ,
135 COMPANDER_FS_48KHZ,
136 COMPANDER_FS_MAX,
137};
138
Joonwoo Parka9444452011-12-08 18:48:27 -0800139/* Flags to track of PA and DAC state.
140 * PA and DAC should be tracked separately as AUXPGA loopback requires
141 * only PA to be turned on without DAC being on. */
142enum tabla_priv_ack_flags {
143 TABLA_HPHL_PA_OFF_ACK = 0,
144 TABLA_HPHR_PA_OFF_ACK,
145 TABLA_HPHL_DAC_OFF_ACK,
146 TABLA_HPHR_DAC_OFF_ACK
147};
148
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800149
150struct comp_sample_dependent_params {
151 u32 peak_det_timeout;
152 u32 rms_meter_div_fact;
153 u32 rms_meter_resamp_fact;
154};
155
Joonwoo Park0976d012011-12-22 11:48:18 -0800156/* Data used by MBHC */
157struct mbhc_internal_cal_data {
158 u16 dce_z;
159 u16 dce_mb;
160 u16 sta_z;
161 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800162 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800163 u32 t_dce;
164 u32 t_sta;
165 u32 micb_mv;
166 u16 v_ins_hu;
167 u16 v_ins_h;
168 u16 v_b1_hu;
169 u16 v_b1_h;
170 u16 v_b1_huc;
171 u16 v_brh;
172 u16 v_brl;
173 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800174 u8 npoll;
175 u8 nbounce_wait;
176};
177
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800178struct tabla_reg_address {
179 u16 micb_4_ctl;
180 u16 micb_4_int_rbias;
181 u16 micb_4_mbhc;
182};
183
Bradley Rubin229c6a52011-07-12 16:18:48 -0700184struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800186 struct tabla_reg_address reg_addr;
Joonwoo Park0976d012011-12-22 11:48:18 -0800187 u32 mclk_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700188 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700189 u32 cfilt1_cnt;
190 u32 cfilt2_cnt;
191 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700192 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700193 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700194 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700195 bool clock_active;
196 bool config_mode_active;
197 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800198 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700199 int buttons_pressed;
Joonwoo Park03324832012-03-19 19:36:16 -0700200 int mbhc_state;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700201
Joonwoo Park0976d012011-12-22 11:48:18 -0800202 enum tabla_micbias_num micbias;
203 /* void* calibration contains:
204 * struct tabla_mbhc_general_cfg generic;
205 * struct tabla_mbhc_plug_detect_cfg plug_det;
206 * struct tabla_mbhc_plug_type_cfg plug_type;
207 * struct tabla_mbhc_btn_detect_cfg btn_det;
208 * struct tabla_mbhc_imped_detect_cfg imped_det;
209 * Note: various size depends on btn_det->num_btn
210 */
211 void *calibration;
212 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213
Bradley Rubincb1e2732011-06-23 16:49:20 -0700214 struct snd_soc_jack *headset_jack;
215 struct snd_soc_jack *button_jack;
Bradley Rubin229c6a52011-07-12 16:18:48 -0700216
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530217 struct wcd9xxx_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700218 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700219
220 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700221 /* Delayed work to report long button press */
Joonwoo Park03324832012-03-19 19:36:16 -0700222 struct delayed_work mbhc_btn_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700223
224 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700225 u8 cfilt_k_value;
226 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700227
Joonwoo Parka9444452011-12-08 18:48:27 -0800228 /* track PA/DAC state */
229 unsigned long hph_pa_dac_state;
230
Santosh Mardie15e2302011-11-15 10:39:23 +0530231 /*track tabla interface type*/
232 u8 intf_type;
233
Patrick Lai49efeac2011-11-03 11:01:12 -0700234 u32 hph_status; /* track headhpone status */
235 /* define separate work for left and right headphone OCP to avoid
236 * additional checking on which OCP event to report so no locking
237 * to ensure synchronization is required
238 */
239 struct work_struct hphlocp_work; /* reporting left hph ocp off */
240 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800241
Patrick Laic7cae882011-11-18 11:52:49 -0800242 u8 hphlocp_cnt; /* headphone left ocp retry */
243 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800244
245 /* Callback function to enable MCLK */
246 int (*mclk_cb) (struct snd_soc_codec*, int);
Patrick Lai64b43262011-12-06 17:29:15 -0800247
248 /* Work to perform MBHC Firmware Read */
249 struct delayed_work mbhc_firmware_dwork;
250 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800251
252 /* num of slim ports required */
253 struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800254
255 /*compander*/
256 int comp_enabled[COMPANDER_MAX];
257 u32 comp_fs[COMPANDER_MAX];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800258
259 /* Maintain the status of AUX PGA */
260 int aux_pga_cnt;
261 u8 aux_l_gain;
262 u8 aux_r_gain;
Joonwoo Park03324832012-03-19 19:36:16 -0700263
264 struct mutex mbhc_mutex;
265 struct delayed_work mbhc_insert_dwork;
266 unsigned long mbhc_last_resume; /* in jiffies */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700267};
268
Bradley Rubincb3950a2011-08-18 13:07:26 -0700269#ifdef CONFIG_DEBUG_FS
270struct tabla_priv *debug_tabla_priv;
271#endif
272
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800273static const u32 comp_shift[] = {
274 0,
275 2,
276};
277
278static const int comp_rx_path[] = {
279 COMPANDER_1,
280 COMPANDER_1,
281 COMPANDER_2,
282 COMPANDER_2,
283 COMPANDER_2,
284 COMPANDER_2,
285 COMPANDER_MAX,
286};
287
288static const struct comp_sample_dependent_params comp_samp_params[] = {
289 {
290 .peak_det_timeout = 0x2,
291 .rms_meter_div_fact = 0x8 << 4,
292 .rms_meter_resamp_fact = 0x21,
293 },
294 {
295 .peak_det_timeout = 0x3,
296 .rms_meter_div_fact = 0x9 << 4,
297 .rms_meter_resamp_fact = 0x28,
298 },
299
300 {
301 .peak_det_timeout = 0x5,
302 .rms_meter_div_fact = 0xB << 4,
303 .rms_meter_resamp_fact = 0x28,
304 },
305
306 {
307 .peak_det_timeout = 0x5,
308 .rms_meter_div_fact = 0xB << 4,
309 .rms_meter_resamp_fact = 0x28,
310 },
311};
312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700313static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
314 struct snd_kcontrol *kcontrol, int event)
315{
316 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700317
318 pr_debug("%s %d\n", __func__, event);
319 switch (event) {
320 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
322 0x01);
323 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
324 usleep_range(200, 200);
325 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
326 break;
327 case SND_SOC_DAPM_PRE_PMD:
328 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
329 0x10);
330 usleep_range(20, 20);
331 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
332 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
333 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
334 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
335 0x00);
336 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700337 break;
338 }
339 return 0;
340}
341
Bradley Rubina7096d02011-08-03 18:29:02 -0700342static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
343 struct snd_ctl_elem_value *ucontrol)
344{
345 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
346 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
347 ucontrol->value.integer.value[0] = tabla->anc_slot;
348 return 0;
349}
350
351static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
352 struct snd_ctl_elem_value *ucontrol)
353{
354 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
355 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
356 tabla->anc_slot = ucontrol->value.integer.value[0];
357 return 0;
358}
359
Kiran Kandid2d86b52011-09-09 17:44:28 -0700360static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
361 struct snd_ctl_elem_value *ucontrol)
362{
363 u8 ear_pa_gain;
364 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
365
366 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
367
368 ear_pa_gain = ear_pa_gain >> 5;
369
370 if (ear_pa_gain == 0x00) {
371 ucontrol->value.integer.value[0] = 0;
372 } else if (ear_pa_gain == 0x04) {
373 ucontrol->value.integer.value[0] = 1;
374 } else {
375 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
376 __func__, ear_pa_gain);
377 return -EINVAL;
378 }
379
380 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
381
382 return 0;
383}
384
385static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
386 struct snd_ctl_elem_value *ucontrol)
387{
388 u8 ear_pa_gain;
389 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
390
391 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
392 ucontrol->value.integer.value[0]);
393
394 switch (ucontrol->value.integer.value[0]) {
395 case 0:
396 ear_pa_gain = 0x00;
397 break;
398 case 1:
399 ear_pa_gain = 0x80;
400 break;
401 default:
402 return -EINVAL;
403 }
404
405 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
406 return 0;
407}
408
Ben Romberger1f045a72011-11-04 10:14:57 -0700409static int tabla_get_iir_enable_audio_mixer(
410 struct snd_kcontrol *kcontrol,
411 struct snd_ctl_elem_value *ucontrol)
412{
413 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
414 int iir_idx = ((struct soc_multi_mixer_control *)
415 kcontrol->private_value)->reg;
416 int band_idx = ((struct soc_multi_mixer_control *)
417 kcontrol->private_value)->shift;
418
419 ucontrol->value.integer.value[0] =
420 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
421 (1 << band_idx);
422
423 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
424 iir_idx, band_idx,
425 (uint32_t)ucontrol->value.integer.value[0]);
426 return 0;
427}
428
429static int tabla_put_iir_enable_audio_mixer(
430 struct snd_kcontrol *kcontrol,
431 struct snd_ctl_elem_value *ucontrol)
432{
433 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
434 int iir_idx = ((struct soc_multi_mixer_control *)
435 kcontrol->private_value)->reg;
436 int band_idx = ((struct soc_multi_mixer_control *)
437 kcontrol->private_value)->shift;
438 int value = ucontrol->value.integer.value[0];
439
440 /* Mask first 5 bits, 6-8 are reserved */
441 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
442 (1 << band_idx), (value << band_idx));
443
444 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
445 iir_idx, band_idx, value);
446 return 0;
447}
448static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
449 int iir_idx, int band_idx,
450 int coeff_idx)
451{
452 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800453 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700454 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800455 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700456
457 /* Mask bits top 2 bits since they are reserved */
458 return ((snd_soc_read(codec,
459 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
460 (snd_soc_read(codec,
461 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
462 (snd_soc_read(codec,
463 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
464 (snd_soc_read(codec,
465 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
466 0x3FFFFFFF;
467}
468
469static int tabla_get_iir_band_audio_mixer(
470 struct snd_kcontrol *kcontrol,
471 struct snd_ctl_elem_value *ucontrol)
472{
473 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
474 int iir_idx = ((struct soc_multi_mixer_control *)
475 kcontrol->private_value)->reg;
476 int band_idx = ((struct soc_multi_mixer_control *)
477 kcontrol->private_value)->shift;
478
479 ucontrol->value.integer.value[0] =
480 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
481 ucontrol->value.integer.value[1] =
482 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
483 ucontrol->value.integer.value[2] =
484 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
485 ucontrol->value.integer.value[3] =
486 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
487 ucontrol->value.integer.value[4] =
488 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
489
490 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
491 "%s: IIR #%d band #%d b1 = 0x%x\n"
492 "%s: IIR #%d band #%d b2 = 0x%x\n"
493 "%s: IIR #%d band #%d a1 = 0x%x\n"
494 "%s: IIR #%d band #%d a2 = 0x%x\n",
495 __func__, iir_idx, band_idx,
496 (uint32_t)ucontrol->value.integer.value[0],
497 __func__, iir_idx, band_idx,
498 (uint32_t)ucontrol->value.integer.value[1],
499 __func__, iir_idx, band_idx,
500 (uint32_t)ucontrol->value.integer.value[2],
501 __func__, iir_idx, band_idx,
502 (uint32_t)ucontrol->value.integer.value[3],
503 __func__, iir_idx, band_idx,
504 (uint32_t)ucontrol->value.integer.value[4]);
505 return 0;
506}
507
508static void set_iir_band_coeff(struct snd_soc_codec *codec,
509 int iir_idx, int band_idx,
510 int coeff_idx, uint32_t value)
511{
512 /* Mask top 3 bits, 6-8 are reserved */
513 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800514 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700515 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800516 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700517
518 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800519 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700520 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800521 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700522
523 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800524 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700525 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800526 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700527
Ben Romberger0915aae2012-02-06 23:32:43 -0800528 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700529 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800530 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700531
Ben Romberger0915aae2012-02-06 23:32:43 -0800532 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700533 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800534 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700535}
536
537static int tabla_put_iir_band_audio_mixer(
538 struct snd_kcontrol *kcontrol,
539 struct snd_ctl_elem_value *ucontrol)
540{
541 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
542 int iir_idx = ((struct soc_multi_mixer_control *)
543 kcontrol->private_value)->reg;
544 int band_idx = ((struct soc_multi_mixer_control *)
545 kcontrol->private_value)->shift;
546
547 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
548 ucontrol->value.integer.value[0]);
549 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
550 ucontrol->value.integer.value[1]);
551 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
552 ucontrol->value.integer.value[2]);
553 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
554 ucontrol->value.integer.value[3]);
555 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
556 ucontrol->value.integer.value[4]);
557
558 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
559 "%s: IIR #%d band #%d b1 = 0x%x\n"
560 "%s: IIR #%d band #%d b2 = 0x%x\n"
561 "%s: IIR #%d band #%d a1 = 0x%x\n"
562 "%s: IIR #%d band #%d a2 = 0x%x\n",
563 __func__, iir_idx, band_idx,
564 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
565 __func__, iir_idx, band_idx,
566 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
567 __func__, iir_idx, band_idx,
568 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
569 __func__, iir_idx, band_idx,
570 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
571 __func__, iir_idx, band_idx,
572 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
573 return 0;
574}
575
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800576static int tabla_compander_gain_offset(
577 struct snd_soc_codec *codec, u32 enable,
578 unsigned int reg, int mask, int event)
579{
580 int pa_mode = snd_soc_read(codec, reg) & mask;
581 int gain_offset = 0;
582 /* if PMU && enable is 1-> offset is 3
583 * if PMU && enable is 0-> offset is 0
584 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
585 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
586 */
587
588 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
589 gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
590 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
591 gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
592 return gain_offset;
593}
594
595
596static int tabla_config_gain_compander(
597 struct snd_soc_codec *codec,
598 u32 compander, u32 enable, int event)
599{
600 int value = 0;
601 int mask = 1 << 4;
602 int gain = 0;
603 int gain_offset;
604 if (compander >= COMPANDER_MAX) {
605 pr_err("%s: Error, invalid compander channel\n", __func__);
606 return -EINVAL;
607 }
608
609 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
610 value = 1 << 4;
611
612 if (compander == COMPANDER_1) {
613 gain_offset = tabla_compander_gain_offset(codec, enable,
614 TABLA_A_RX_HPH_L_GAIN, mask, event);
615 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
616 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
617 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
618 0xFF, gain - gain_offset);
619 gain_offset = tabla_compander_gain_offset(codec, enable,
620 TABLA_A_RX_HPH_R_GAIN, mask, event);
621 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
622 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
623 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
624 0xFF, gain - gain_offset);
625 } else if (compander == COMPANDER_2) {
626 gain_offset = tabla_compander_gain_offset(codec, enable,
627 TABLA_A_RX_LINE_1_GAIN, mask, event);
628 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
629 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
630 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
631 0xFF, gain - gain_offset);
632 gain_offset = tabla_compander_gain_offset(codec, enable,
633 TABLA_A_RX_LINE_3_GAIN, mask, event);
634 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
635 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
636 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
637 0xFF, gain - gain_offset);
638 gain_offset = tabla_compander_gain_offset(codec, enable,
639 TABLA_A_RX_LINE_2_GAIN, mask, event);
640 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
641 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
642 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
643 0xFF, gain - gain_offset);
644 gain_offset = tabla_compander_gain_offset(codec, enable,
645 TABLA_A_RX_LINE_4_GAIN, mask, event);
646 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
647 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
648 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
649 0xFF, gain - gain_offset);
650 }
651 return 0;
652}
653static int tabla_get_compander(struct snd_kcontrol *kcontrol,
654 struct snd_ctl_elem_value *ucontrol)
655{
656
657 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
658 int comp = ((struct soc_multi_mixer_control *)
659 kcontrol->private_value)->max;
660 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
661
662 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
663
664 return 0;
665}
666
667static int tabla_set_compander(struct snd_kcontrol *kcontrol,
668 struct snd_ctl_elem_value *ucontrol)
669{
670 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
671 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
672 int comp = ((struct soc_multi_mixer_control *)
673 kcontrol->private_value)->max;
674 int value = ucontrol->value.integer.value[0];
675
676 if (value == tabla->comp_enabled[comp]) {
677 pr_debug("%s: compander #%d enable %d no change\n",
678 __func__, comp, value);
679 return 0;
680 }
681 tabla->comp_enabled[comp] = value;
682 return 0;
683}
684
685
686static int tabla_config_compander(struct snd_soc_dapm_widget *w,
687 struct snd_kcontrol *kcontrol,
688 int event)
689{
690 struct snd_soc_codec *codec = w->codec;
691 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
692 u32 rate = tabla->comp_fs[w->shift];
693
694 switch (event) {
695 case SND_SOC_DAPM_PRE_PMU:
696 if (tabla->comp_enabled[w->shift] != 0) {
697 /* Enable both L/R compander clocks */
698 snd_soc_update_bits(codec,
699 TABLA_A_CDC_CLK_RX_B2_CTL,
700 0x03 << comp_shift[w->shift],
701 0x03 << comp_shift[w->shift]);
702 /* Clar the HALT for the compander*/
703 snd_soc_update_bits(codec,
704 TABLA_A_CDC_COMP1_B1_CTL +
705 w->shift * 8, 1 << 2, 0);
706 /* Toggle compander reset bits*/
707 snd_soc_update_bits(codec,
708 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
709 0x03 << comp_shift[w->shift],
710 0x03 << comp_shift[w->shift]);
711 snd_soc_update_bits(codec,
712 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
713 0x03 << comp_shift[w->shift], 0);
714 tabla_config_gain_compander(codec, w->shift, 1, event);
715 /* Update the RMS meter resampling*/
716 snd_soc_update_bits(codec,
717 TABLA_A_CDC_COMP1_B3_CTL +
718 w->shift * 8, 0xFF, 0x01);
719 /* Wait for 1ms*/
720 usleep_range(1000, 1000);
721 }
722 break;
723 case SND_SOC_DAPM_POST_PMU:
724 /* Set sample rate dependent paramater*/
725 if (tabla->comp_enabled[w->shift] != 0) {
726 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
727 w->shift * 8, 0x03, rate);
728 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
729 w->shift * 8, 0x0F,
730 comp_samp_params[rate].peak_det_timeout);
731 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
732 w->shift * 8, 0xF0,
733 comp_samp_params[rate].rms_meter_div_fact);
734 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
735 w->shift * 8, 0xFF,
736 comp_samp_params[rate].rms_meter_resamp_fact);
737 /* Compander enable -> 0x370/0x378*/
738 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
739 w->shift * 8, 0x03, 0x03);
740 }
741 break;
742 case SND_SOC_DAPM_PRE_PMD:
743 /* Halt the compander*/
744 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
745 w->shift * 8, 1 << 2, 1 << 2);
746 break;
747 case SND_SOC_DAPM_POST_PMD:
748 /* Restore the gain */
749 tabla_config_gain_compander(codec, w->shift,
750 tabla->comp_enabled[w->shift], event);
751 /* Disable the compander*/
752 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
753 w->shift * 8, 0x03, 0x00);
754 /* Turn off the clock for compander in pair*/
755 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
756 0x03 << comp_shift[w->shift], 0);
757 break;
758 }
759 return 0;
760}
761
Kiran Kandid2d86b52011-09-09 17:44:28 -0700762static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
763static const struct soc_enum tabla_ear_pa_gain_enum[] = {
764 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
765};
766
Santosh Mardi024010f2011-10-18 06:27:21 +0530767/*cut of frequency for high pass filter*/
768static const char *cf_text[] = {
769 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
770};
771
772static const struct soc_enum cf_dec1_enum =
773 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
774
775static const struct soc_enum cf_dec2_enum =
776 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
777
778static const struct soc_enum cf_dec3_enum =
779 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
780
781static const struct soc_enum cf_dec4_enum =
782 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
783
784static const struct soc_enum cf_dec5_enum =
785 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
786
787static const struct soc_enum cf_dec6_enum =
788 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
789
790static const struct soc_enum cf_dec7_enum =
791 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
792
793static const struct soc_enum cf_dec8_enum =
794 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
795
796static const struct soc_enum cf_dec9_enum =
797 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
798
799static const struct soc_enum cf_dec10_enum =
800 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
801
802static const struct soc_enum cf_rxmix1_enum =
803 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
804
805static const struct soc_enum cf_rxmix2_enum =
806 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
807
808static const struct soc_enum cf_rxmix3_enum =
809 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
810
811static const struct soc_enum cf_rxmix4_enum =
812 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
813
814static const struct soc_enum cf_rxmix5_enum =
815 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
816;
817static const struct soc_enum cf_rxmix6_enum =
818 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
819
820static const struct soc_enum cf_rxmix7_enum =
821 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
822
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700824
825 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
826 tabla_pa_gain_get, tabla_pa_gain_put),
827
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
829 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700830 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
831 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
833 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700834 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
835 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700836 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
837 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
840 line_gain),
841 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
842 line_gain),
843
Bradley Rubin410383f2011-07-22 13:44:23 -0700844 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
845 -84, 40, digital_gain),
846 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
847 -84, 40, digital_gain),
848 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
849 -84, 40, digital_gain),
850 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
851 -84, 40, digital_gain),
852 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
853 -84, 40, digital_gain),
854 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
855 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -0800856 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
857 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700858
Bradley Rubin410383f2011-07-22 13:44:23 -0700859 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700861 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700863 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
864 digital_gain),
865 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
866 digital_gain),
867 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
868 digital_gain),
869 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
870 digital_gain),
871 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
872 digital_gain),
873 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
874 digital_gain),
875 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
876 digital_gain),
877 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
878 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700879 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
880 40, digital_gain),
881 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
882 40, digital_gain),
883 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
884 40, digital_gain),
885 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
886 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700887 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
888 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700889 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
890 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700891 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
892 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700893
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800894 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
895 aux_pga_gain),
896 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
897 aux_pga_gain),
898
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800900 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700901 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700902
903 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
904 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530905 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
906 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
907 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
908 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
909 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
910 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
911 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
912 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
913 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
914 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
915
916 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
917 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
918 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
919 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
920 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
921 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
922 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
923 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
924 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
925 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
926
927 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
928 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
929 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
930 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
931 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
932 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
933 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
934
935 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
936 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
937 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
938 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
939 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
940 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
941 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700942
943 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
944 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
945 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
946 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
947 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
948 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
949 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
950 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
951 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
952 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
953 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
954 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
955 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
956 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
957 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
958 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
959 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
960 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
961 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
962 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
963
964 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
965 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
966 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
967 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
968 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
969 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
970 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
971 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
972 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
973 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
974 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
975 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
976 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
977 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
978 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
979 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
980 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
981 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
982 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
983 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800984 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
985 tabla_get_compander, tabla_set_compander),
986 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
987 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988};
989
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800990static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
991 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
992};
993
994static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
995 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
996};
997
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998static const char *rx_mix1_text[] = {
999 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1000 "RX5", "RX6", "RX7"
1001};
1002
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001003static const char *rx_dsm_text[] = {
1004 "CIC_OUT", "DSM_INV"
1005};
1006
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001007static const char *sb_tx1_mux_text[] = {
1008 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1009 "DEC1"
1010};
1011
1012static const char *sb_tx5_mux_text[] = {
1013 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1014 "DEC5"
1015};
1016
1017static const char *sb_tx6_mux_text[] = {
1018 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1019 "DEC6"
1020};
1021
1022static const char const *sb_tx7_to_tx10_mux_text[] = {
1023 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1024 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1025 "DEC9", "DEC10"
1026};
1027
1028static const char *dec1_mux_text[] = {
1029 "ZERO", "DMIC1", "ADC6",
1030};
1031
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001032static const char *dec2_mux_text[] = {
1033 "ZERO", "DMIC2", "ADC5",
1034};
1035
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001036static const char *dec3_mux_text[] = {
1037 "ZERO", "DMIC3", "ADC4",
1038};
1039
1040static const char *dec4_mux_text[] = {
1041 "ZERO", "DMIC4", "ADC3",
1042};
1043
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044static const char *dec5_mux_text[] = {
1045 "ZERO", "DMIC5", "ADC2",
1046};
1047
1048static const char *dec6_mux_text[] = {
1049 "ZERO", "DMIC6", "ADC1",
1050};
1051
1052static const char const *dec7_mux_text[] = {
1053 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1054};
1055
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001056static const char *dec8_mux_text[] = {
1057 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1058};
1059
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001060static const char *dec9_mux_text[] = {
1061 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1062};
1063
1064static const char *dec10_mux_text[] = {
1065 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1066};
1067
Bradley Rubin229c6a52011-07-12 16:18:48 -07001068static const char const *anc_mux_text[] = {
1069 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1070 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1071};
1072
1073static const char const *anc1_fb_mux_text[] = {
1074 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1075};
1076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001077static const char *iir1_inp1_text[] = {
1078 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1079 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1080};
1081
1082static const struct soc_enum rx_mix1_inp1_chain_enum =
1083 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1084
Bradley Rubin229c6a52011-07-12 16:18:48 -07001085static const struct soc_enum rx_mix1_inp2_chain_enum =
1086 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088static const struct soc_enum rx2_mix1_inp1_chain_enum =
1089 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1090
Bradley Rubin229c6a52011-07-12 16:18:48 -07001091static const struct soc_enum rx2_mix1_inp2_chain_enum =
1092 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1093
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094static const struct soc_enum rx3_mix1_inp1_chain_enum =
1095 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1096
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001097static const struct soc_enum rx3_mix1_inp2_chain_enum =
1098 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100static const struct soc_enum rx4_mix1_inp1_chain_enum =
1101 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1102
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001103static const struct soc_enum rx4_mix1_inp2_chain_enum =
1104 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106static const struct soc_enum rx5_mix1_inp1_chain_enum =
1107 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1108
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001109static const struct soc_enum rx5_mix1_inp2_chain_enum =
1110 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1111
1112static const struct soc_enum rx6_mix1_inp1_chain_enum =
1113 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1114
1115static const struct soc_enum rx6_mix1_inp2_chain_enum =
1116 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1117
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001118static const struct soc_enum rx7_mix1_inp1_chain_enum =
1119 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1120
1121static const struct soc_enum rx7_mix1_inp2_chain_enum =
1122 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1123
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001124static const struct soc_enum rx4_dsm_enum =
1125 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1126
1127static const struct soc_enum rx6_dsm_enum =
1128 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001130static const struct soc_enum sb_tx5_mux_enum =
1131 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1132
1133static const struct soc_enum sb_tx6_mux_enum =
1134 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1135
1136static const struct soc_enum sb_tx7_mux_enum =
1137 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1138 sb_tx7_to_tx10_mux_text);
1139
1140static const struct soc_enum sb_tx8_mux_enum =
1141 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1142 sb_tx7_to_tx10_mux_text);
1143
Kiran Kandi3426e512011-09-13 22:50:10 -07001144static const struct soc_enum sb_tx9_mux_enum =
1145 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1146 sb_tx7_to_tx10_mux_text);
1147
1148static const struct soc_enum sb_tx10_mux_enum =
1149 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1150 sb_tx7_to_tx10_mux_text);
1151
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001152static const struct soc_enum sb_tx1_mux_enum =
1153 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1154
1155static const struct soc_enum dec1_mux_enum =
1156 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1157
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001158static const struct soc_enum dec2_mux_enum =
1159 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1160
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001161static const struct soc_enum dec3_mux_enum =
1162 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1163
1164static const struct soc_enum dec4_mux_enum =
1165 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167static const struct soc_enum dec5_mux_enum =
1168 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1169
1170static const struct soc_enum dec6_mux_enum =
1171 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1172
1173static const struct soc_enum dec7_mux_enum =
1174 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1175
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001176static const struct soc_enum dec8_mux_enum =
1177 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1178
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001179static const struct soc_enum dec9_mux_enum =
1180 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1181
1182static const struct soc_enum dec10_mux_enum =
1183 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1184
Bradley Rubin229c6a52011-07-12 16:18:48 -07001185static const struct soc_enum anc1_mux_enum =
1186 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1187
1188static const struct soc_enum anc2_mux_enum =
1189 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1190
1191static const struct soc_enum anc1_fb_mux_enum =
1192 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1193
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001194static const struct soc_enum iir1_inp1_mux_enum =
1195 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
1196
1197static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1198 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1199
Bradley Rubin229c6a52011-07-12 16:18:48 -07001200static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1201 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1202
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001203static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1204 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1205
Bradley Rubin229c6a52011-07-12 16:18:48 -07001206static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1207 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1208
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1210 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1211
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001212static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1213 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001215static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1216 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1217
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001218static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1219 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1222 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1223
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001224static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1225 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1226
1227static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1228 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1229
1230static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1231 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1232
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001233static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1234 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1235
1236static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1237 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1238
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001239static const struct snd_kcontrol_new rx4_dsm_mux =
1240 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1241
1242static const struct snd_kcontrol_new rx6_dsm_mux =
1243 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1244
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001245static const struct snd_kcontrol_new sb_tx5_mux =
1246 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1247
1248static const struct snd_kcontrol_new sb_tx6_mux =
1249 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1250
1251static const struct snd_kcontrol_new sb_tx7_mux =
1252 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1253
1254static const struct snd_kcontrol_new sb_tx8_mux =
1255 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1256
Kiran Kandi3426e512011-09-13 22:50:10 -07001257static const struct snd_kcontrol_new sb_tx9_mux =
1258 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1259
1260static const struct snd_kcontrol_new sb_tx10_mux =
1261 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1262
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001263static const struct snd_kcontrol_new sb_tx1_mux =
1264 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1265
1266static const struct snd_kcontrol_new dec1_mux =
1267 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1268
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001269static const struct snd_kcontrol_new dec2_mux =
1270 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1271
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001272static const struct snd_kcontrol_new dec3_mux =
1273 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1274
1275static const struct snd_kcontrol_new dec4_mux =
1276 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278static const struct snd_kcontrol_new dec5_mux =
1279 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
1280
1281static const struct snd_kcontrol_new dec6_mux =
1282 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
1283
1284static const struct snd_kcontrol_new dec7_mux =
1285 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
1286
Bradley Rubin229c6a52011-07-12 16:18:48 -07001287static const struct snd_kcontrol_new anc1_mux =
1288 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001289static const struct snd_kcontrol_new dec8_mux =
1290 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
1291
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001292static const struct snd_kcontrol_new dec9_mux =
1293 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
1294
1295static const struct snd_kcontrol_new dec10_mux =
1296 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
1297
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298static const struct snd_kcontrol_new iir1_inp1_mux =
1299 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1300
Bradley Rubin229c6a52011-07-12 16:18:48 -07001301static const struct snd_kcontrol_new anc2_mux =
1302 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303
Bradley Rubin229c6a52011-07-12 16:18:48 -07001304static const struct snd_kcontrol_new anc1_fb_mux =
1305 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306
Bradley Rubin229c6a52011-07-12 16:18:48 -07001307static const struct snd_kcontrol_new dac1_switch[] = {
1308 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1309};
1310static const struct snd_kcontrol_new hphl_switch[] = {
1311 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1312};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001313
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001314static const struct snd_kcontrol_new hphl_pa_mix[] = {
1315 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1316 7, 1, 0),
1317 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1318 7, 1, 0),
1319 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1320 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1321 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1322 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1323};
1324
1325static const struct snd_kcontrol_new hphr_pa_mix[] = {
1326 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1327 6, 1, 0),
1328 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1329 6, 1, 0),
1330 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1331 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1332 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1333 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1334};
1335
1336static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1337 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1338 5, 1, 0),
1339 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1340 5, 1, 0),
1341 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1342 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1343 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1344 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1345};
1346
1347static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1348 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1349 4, 1, 0),
1350 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1351 4, 1, 0),
1352 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1353 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1354 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1355 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1356};
1357
1358static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1359 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1360 3, 1, 0),
1361 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1362 3, 1, 0),
1363 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1364 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1365 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1366 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1367};
1368
1369static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1370 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1371 2, 1, 0),
1372 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1373 2, 1, 0),
1374 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1375 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1376 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1377 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1378};
1379
1380static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1381 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1382 1, 1, 0),
1383 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1384 1, 1, 0),
1385 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1386 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1387 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1388 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1389};
1390
1391static const struct snd_kcontrol_new ear_pa_mix[] = {
1392 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1393 0, 1, 0),
1394 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1395 0, 1, 0),
1396 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1397 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1398 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1399 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1400};
1401
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001402static const struct snd_kcontrol_new lineout3_ground_switch =
1403 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1404
1405static const struct snd_kcontrol_new lineout4_ground_switch =
1406 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001407
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
1409 int enable)
1410{
1411 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1412
1413 pr_debug("%s %d\n", __func__, enable);
1414
1415 if (enable) {
1416 tabla->adc_count++;
1417 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
1418 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1419 } else {
1420 tabla->adc_count--;
1421 if (!tabla->adc_count) {
1422 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
Joonwoo Park03324832012-03-19 19:36:16 -07001423 0x2, 0x0);
1424 mutex_lock(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425 if (!tabla->mbhc_polling_active)
1426 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS,
Joonwoo Park03324832012-03-19 19:36:16 -07001427 0xE0, 0x0);
1428 mutex_unlock(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 }
1430 }
1431}
1432
1433static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1434 struct snd_kcontrol *kcontrol, int event)
1435{
1436 struct snd_soc_codec *codec = w->codec;
1437 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001438 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439
1440 pr_debug("%s %d\n", __func__, event);
1441
1442 if (w->reg == TABLA_A_TX_1_2_EN)
1443 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1444 else if (w->reg == TABLA_A_TX_3_4_EN)
1445 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1446 else if (w->reg == TABLA_A_TX_5_6_EN)
1447 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1448 else {
1449 pr_err("%s: Error, invalid adc register\n", __func__);
1450 return -EINVAL;
1451 }
1452
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001453 if (w->shift == 3)
1454 init_bit_shift = 6;
1455 else if (w->shift == 7)
1456 init_bit_shift = 7;
1457 else {
1458 pr_err("%s: Error, invalid init bit postion adc register\n",
1459 __func__);
1460 return -EINVAL;
1461 }
1462
1463
1464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 switch (event) {
1466 case SND_SOC_DAPM_PRE_PMU:
1467 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001468 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1469 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 break;
1471 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001472
1473 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 break;
1476 case SND_SOC_DAPM_POST_PMD:
1477 tabla_codec_enable_adc_block(codec, 0);
1478 break;
1479 }
1480 return 0;
1481}
1482
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001483static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1484{
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001485 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1486 0x80);
1487 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1488 0x04);
1489 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1490 0x01);
1491 usleep_range(1000, 1000);
1492 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1493 0x00);
1494}
1495
1496static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1497 enum tabla_bandgap_type choice)
1498{
1499 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1500
1501 /* TODO lock resources accessed by audio streams and threaded
1502 * interrupt handlers
1503 */
1504
1505 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1506 tabla->bandgap_type);
1507
1508 if (tabla->bandgap_type == choice)
1509 return;
1510
1511 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1512 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1513 tabla_codec_enable_audio_mode_bandgap(codec);
1514 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
1515 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1516 0x2);
1517 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1518 0x80);
1519 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1520 0x4);
1521 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1522 0x01);
1523 usleep_range(1000, 1000);
1524 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1525 0x00);
1526 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1527 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1528 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1529 usleep_range(100, 100);
1530 tabla_codec_enable_audio_mode_bandgap(codec);
1531 } else if (choice == TABLA_BANDGAP_OFF) {
1532 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1533 } else {
1534 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1535 }
1536 tabla->bandgap_type = choice;
1537}
1538
1539static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1540{
1541 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1542 pr_debug("%s\n", __func__);
1543 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1544 ndelay(160);
1545 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1546 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1547 tabla->clock_active = false;
1548}
1549
1550static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
1551{
1552 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ)
1553 return 0;
1554 else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ)
1555 return 1;
1556 else {
1557 BUG_ON(1);
1558 return -EINVAL;
1559 }
1560}
1561
1562static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1563{
1564 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1565
1566 if (enable) {
1567 tabla->rx_bias_count++;
1568 if (tabla->rx_bias_count == 1)
1569 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1570 0x80, 0x80);
1571 } else {
1572 tabla->rx_bias_count--;
1573 if (!tabla->rx_bias_count)
1574 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1575 0x80, 0x00);
1576 }
1577}
1578
1579static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1580 int enable)
1581{
1582 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1583
1584 pr_debug("%s: enable = %d\n", __func__, enable);
1585 if (enable) {
1586 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1587 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1588 usleep_range(5, 5);
1589 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1590 0x80);
1591 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1592 0x80);
1593 usleep_range(10, 10);
1594 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1595 usleep_range(20, 20);
1596 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1597 } else {
1598 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1599 0);
1600 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1601 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1602 }
1603 tabla->config_mode_active = enable ? true : false;
1604
1605 return 0;
1606}
1607
1608static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1609 int config_mode)
1610{
1611 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1612
1613 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
1614
1615 if (config_mode) {
1616 tabla_codec_enable_config_mode(codec, 1);
1617 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1618 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1619 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1620 usleep_range(1000, 1000);
1621 } else
1622 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1623
1624 if (!config_mode && tabla->mbhc_polling_active) {
1625 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1626 tabla_codec_enable_config_mode(codec, 0);
1627
1628 }
1629
1630 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1631 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1632 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1633 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1634 usleep_range(50, 50);
1635 tabla->clock_active = true;
1636 return 0;
1637}
1638
1639static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1640 struct snd_kcontrol *kcontrol, int event)
1641{
1642 struct snd_soc_codec *codec = w->codec;
1643 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1644
1645 pr_debug("%s: %d\n", __func__, event);
1646
1647 switch (event) {
1648 case SND_SOC_DAPM_PRE_PMU:
1649 tabla_codec_enable_bandgap(codec,
1650 TABLA_BANDGAP_AUDIO_MODE);
1651 tabla_enable_rx_bias(codec, 1);
1652
1653 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1654 0x08, 0x08);
1655 /* Enable Zero Cross detect for AUX PGA channel
1656 * and set the initial AUX PGA gain to NEG_0P0_DB
1657 * to avoid glitches.
1658 */
1659 if (w->reg == TABLA_A_AUX_L_EN) {
1660 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1661 0x20, 0x20);
1662 tabla->aux_l_gain = snd_soc_read(codec,
1663 TABLA_A_AUX_L_GAIN);
1664 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1665 } else {
1666 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1667 0x20, 0x20);
1668 tabla->aux_r_gain = snd_soc_read(codec,
1669 TABLA_A_AUX_R_GAIN);
1670 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1671 }
1672 if (tabla->aux_pga_cnt++ == 1
1673 && !tabla->mclk_enabled) {
1674 tabla_codec_enable_clock_block(codec, 1);
1675 pr_debug("AUX PGA enabled RC osc\n");
1676 }
1677 break;
1678
1679 case SND_SOC_DAPM_POST_PMU:
1680 if (w->reg == TABLA_A_AUX_L_EN)
1681 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1682 tabla->aux_l_gain);
1683 else
1684 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1685 tabla->aux_r_gain);
1686 break;
1687
1688 case SND_SOC_DAPM_PRE_PMD:
1689 /* Mute AUX PGA channel in use before disabling AUX PGA */
1690 if (w->reg == TABLA_A_AUX_L_EN) {
1691 tabla->aux_l_gain = snd_soc_read(codec,
1692 TABLA_A_AUX_L_GAIN);
1693 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1694 } else {
1695 tabla->aux_r_gain = snd_soc_read(codec,
1696 TABLA_A_AUX_R_GAIN);
1697 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1698 }
1699 break;
1700
1701 case SND_SOC_DAPM_POST_PMD:
1702 tabla_enable_rx_bias(codec, 0);
1703
1704 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1705 0x08, 0x00);
1706 if (w->reg == TABLA_A_AUX_L_EN) {
1707 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1708 tabla->aux_l_gain);
1709 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1710 0x20, 0x00);
1711 } else {
1712 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1713 tabla->aux_r_gain);
1714 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1715 0x20, 0x00);
1716 }
1717
1718 if (tabla->aux_pga_cnt-- == 0) {
1719 if (tabla->mbhc_polling_active)
1720 tabla_codec_enable_bandgap(codec,
1721 TABLA_BANDGAP_MBHC_MODE);
1722 else
1723 tabla_codec_enable_bandgap(codec,
1724 TABLA_BANDGAP_OFF);
1725
1726 if (!tabla->mclk_enabled &&
1727 !tabla->mbhc_polling_active) {
1728 tabla_codec_enable_clock_block(codec, 0);
1729 }
1730 }
1731 break;
1732 }
1733 return 0;
1734}
1735
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1737 struct snd_kcontrol *kcontrol, int event)
1738{
1739 struct snd_soc_codec *codec = w->codec;
1740 u16 lineout_gain_reg;
1741
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001742 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743
1744 switch (w->shift) {
1745 case 0:
1746 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1747 break;
1748 case 1:
1749 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1750 break;
1751 case 2:
1752 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1753 break;
1754 case 3:
1755 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1756 break;
1757 case 4:
1758 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1759 break;
1760 default:
1761 pr_err("%s: Error, incorrect lineout register value\n",
1762 __func__);
1763 return -EINVAL;
1764 }
1765
1766 switch (event) {
1767 case SND_SOC_DAPM_PRE_PMU:
1768 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1769 break;
1770 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001771 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001772 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001773 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001774 break;
1775 case SND_SOC_DAPM_POST_PMD:
1776 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1777 break;
1778 }
1779 return 0;
1780}
1781
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001782
1783static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001784 struct snd_kcontrol *kcontrol, int event)
1785{
1786 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001787 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1788 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001789 unsigned int dmic;
1790 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001791
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001792 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1793 if (ret < 0) {
1794 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001795 return -EINVAL;
1796 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001798 switch (dmic) {
1799 case 1:
1800 case 2:
1801 dmic_clk_sel = 0x02;
1802 dmic_clk_en = 0x01;
1803 break;
1804
1805 case 3:
1806 case 4:
1807 dmic_clk_sel = 0x08;
1808 dmic_clk_en = 0x04;
1809 break;
1810
1811 case 5:
1812 case 6:
1813 dmic_clk_sel = 0x20;
1814 dmic_clk_en = 0x10;
1815 break;
1816
1817 default:
1818 pr_err("%s: Invalid DMIC Selection\n", __func__);
1819 return -EINVAL;
1820 }
1821
1822 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1823 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1824
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001825 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001826
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001827 switch (event) {
1828 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001829 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1830
1831 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1832 dmic_clk_sel, dmic_clk_sel);
1833
1834 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1835
1836 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1837 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001838 break;
1839 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001840 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1841 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001842 break;
1843 }
1844 return 0;
1845}
1846
Bradley Rubin229c6a52011-07-12 16:18:48 -07001847static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1848 struct snd_kcontrol *kcontrol, int event)
1849{
1850 struct snd_soc_codec *codec = w->codec;
1851 const char *filename;
1852 const struct firmware *fw;
1853 int i;
1854 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001855 int num_anc_slots;
1856 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001857 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001858 u32 anc_writes_size = 0;
1859 int anc_size_remaining;
1860 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001861 u16 reg;
1862 u8 mask, val, old_val;
1863
1864 pr_debug("%s %d\n", __func__, event);
1865 switch (event) {
1866 case SND_SOC_DAPM_PRE_PMU:
1867
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001868 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001869
1870 ret = request_firmware(&fw, filename, codec->dev);
1871 if (ret != 0) {
1872 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1873 ret);
1874 return -ENODEV;
1875 }
1876
Bradley Rubina7096d02011-08-03 18:29:02 -07001877 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001878 dev_err(codec->dev, "Not enough data\n");
1879 release_firmware(fw);
1880 return -ENOMEM;
1881 }
1882
1883 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001884 anc_head = (struct anc_header *)(fw->data);
1885 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1886 anc_size_remaining = fw->size - sizeof(struct anc_header);
1887 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001888
Bradley Rubina7096d02011-08-03 18:29:02 -07001889 if (tabla->anc_slot >= num_anc_slots) {
1890 dev_err(codec->dev, "Invalid ANC slot selected\n");
1891 release_firmware(fw);
1892 return -EINVAL;
1893 }
1894
1895 for (i = 0; i < num_anc_slots; i++) {
1896
1897 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1898 dev_err(codec->dev, "Invalid register format\n");
1899 release_firmware(fw);
1900 return -EINVAL;
1901 }
1902 anc_writes_size = (u32)(*anc_ptr);
1903 anc_size_remaining -= sizeof(u32);
1904 anc_ptr += 1;
1905
1906 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1907 > anc_size_remaining) {
1908 dev_err(codec->dev, "Invalid register format\n");
1909 release_firmware(fw);
1910 return -ENOMEM;
1911 }
1912
1913 if (tabla->anc_slot == i)
1914 break;
1915
1916 anc_size_remaining -= (anc_writes_size *
1917 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001918 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001919 }
1920 if (i == num_anc_slots) {
1921 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001922 release_firmware(fw);
1923 return -ENOMEM;
1924 }
1925
Bradley Rubina7096d02011-08-03 18:29:02 -07001926 for (i = 0; i < anc_writes_size; i++) {
1927 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001928 mask, val);
1929 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001930 snd_soc_write(codec, reg, (old_val & ~mask) |
1931 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001932 }
1933 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001934
1935 break;
1936 case SND_SOC_DAPM_POST_PMD:
1937 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1938 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1939 break;
1940 }
1941 return 0;
1942}
1943
1944
Bradley Rubincb3950a2011-08-18 13:07:26 -07001945static void tabla_codec_disable_button_presses(struct snd_soc_codec *codec)
1946{
1947 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
1948 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
1949}
1950
Joonwoo Park03324832012-03-19 19:36:16 -07001951/* called after acquiring mbhc_mutex */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001952static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1953{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001954 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07001955 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
1956 int mbhc_state = tabla->mbhc_state;
Bradley Rubincb3950a2011-08-18 13:07:26 -07001957
Joonwoo Park03324832012-03-19 19:36:16 -07001958 pr_debug("%s: enter\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001959 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05301960 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001961 if (!tabla->no_mic_headset_override) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05301962 wcd9xxx_enable_irq(codec->control_data,
1963 TABLA_IRQ_MBHC_POTENTIAL);
1964 wcd9xxx_enable_irq(codec->control_data,
1965 TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb3950a2011-08-18 13:07:26 -07001966 } else {
1967 tabla_codec_disable_button_presses(codec);
1968 }
Joonwoo Park03324832012-03-19 19:36:16 -07001969
1970 if (!tabla->no_mic_headset_override) {
1971 if (mbhc_state == TABLA_IRQ_MBHC_POTENTIAL) {
1972 pr_debug("%s:%d recovering MBHC state macine\n",
1973 __func__, __LINE__);
1974 /* set to max button press threshold */
1975 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
1976 0x7F);
1977 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
1978 0xFF);
1979 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1980 (TABLA_IS_1_X(tabla_core->version) ?
1981 0x07 : 0x7F));
1982 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
1983 0xFF);
1984 /* set to max */
1985 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
1986 0x7F);
1987 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
1988 0xFF);
1989 }
1990 }
1991
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001992 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
1993 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
1994 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
Joonwoo Park03324832012-03-19 19:36:16 -07001995 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001996}
1997
Joonwoo Park03324832012-03-19 19:36:16 -07001998/* called after acquiring mbhc_mutex */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001999static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
2000{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002001 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2002
Joonwoo Park03324832012-03-19 19:36:16 -07002003 pr_debug("%s: enter\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002004 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302005 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bradley Rubincb3950a2011-08-18 13:07:26 -07002006 if (!tabla->no_mic_headset_override) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302007 wcd9xxx_disable_irq(codec->control_data,
Bradley Rubincb3950a2011-08-18 13:07:26 -07002008 TABLA_IRQ_MBHC_POTENTIAL);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302009 wcd9xxx_disable_irq(codec->control_data,
2010 TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb3950a2011-08-18 13:07:26 -07002011 }
Joonwoo Park03324832012-03-19 19:36:16 -07002012 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002013}
2014
Joonwoo Park03324832012-03-19 19:36:16 -07002015static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002016{
2017 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2018 u8 reg_mode_val, cur_mode_val;
2019 bool mbhc_was_polling = false;
2020
2021 if (mode)
2022 reg_mode_val = TABLA_CFILT_FAST_MODE;
2023 else
2024 reg_mode_val = TABLA_CFILT_SLOW_MODE;
2025
2026 cur_mode_val = snd_soc_read(codec,
2027 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
2028
2029 if (cur_mode_val != reg_mode_val) {
Joonwoo Park03324832012-03-19 19:36:16 -07002030 mutex_lock(&tabla->mbhc_mutex);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002031 if (tabla->mbhc_polling_active) {
2032 tabla_codec_pause_hs_polling(codec);
2033 mbhc_was_polling = true;
2034 }
2035 snd_soc_update_bits(codec,
2036 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
2037 if (mbhc_was_polling)
2038 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07002039 mutex_unlock(&tabla->mbhc_mutex);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002040 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
2041 cur_mode_val, reg_mode_val);
2042 } else {
2043 pr_debug("%s: CFILT Value is already %x\n",
2044 __func__, cur_mode_val);
2045 }
2046}
2047
2048static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
2049 u8 cfilt_sel, int inc)
2050{
2051 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2052 u32 *cfilt_cnt_ptr = NULL;
2053 u16 micb_cfilt_reg;
2054
2055 switch (cfilt_sel) {
2056 case TABLA_CFILT1_SEL:
2057 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2058 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2059 break;
2060 case TABLA_CFILT2_SEL:
2061 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2062 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2063 break;
2064 case TABLA_CFILT3_SEL:
2065 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2066 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2067 break;
2068 default:
2069 return; /* should not happen */
2070 }
2071
2072 if (inc) {
2073 if (!(*cfilt_cnt_ptr)++) {
2074 /* Switch CFILT to slow mode if MBHC CFILT being used */
2075 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2076 tabla_codec_switch_cfilt_mode(codec, 0);
2077
2078 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2079 }
2080 } else {
2081 /* check if count not zero, decrement
2082 * then check if zero, go ahead disable cfilter
2083 */
2084 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2085 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2086
2087 /* Switch CFILT to fast mode if MBHC CFILT being used */
2088 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2089 tabla_codec_switch_cfilt_mode(codec, 1);
2090 }
2091 }
2092}
2093
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002094static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2095{
2096 int rc = -EINVAL;
2097 unsigned min_mv, max_mv;
2098
2099 switch (ldoh_v) {
2100 case TABLA_LDOH_1P95_V:
2101 min_mv = 160;
2102 max_mv = 1800;
2103 break;
2104 case TABLA_LDOH_2P35_V:
2105 min_mv = 200;
2106 max_mv = 2200;
2107 break;
2108 case TABLA_LDOH_2P75_V:
2109 min_mv = 240;
2110 max_mv = 2600;
2111 break;
2112 case TABLA_LDOH_2P85_V:
2113 min_mv = 250;
2114 max_mv = 2700;
2115 break;
2116 default:
2117 goto done;
2118 }
2119
2120 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2121 goto done;
2122
2123 for (rc = 4; rc <= 44; rc++) {
2124 min_mv = max_mv * (rc) / 44;
2125 if (min_mv >= cfilt_mv) {
2126 rc -= 4;
2127 break;
2128 }
2129 }
2130done:
2131 return rc;
2132}
2133
2134static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2135{
2136 u8 hph_reg_val = 0;
2137 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2138
2139 return (hph_reg_val & 0x30) ? true : false;
2140}
2141
Joonwoo Parka9444452011-12-08 18:48:27 -08002142static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2143{
2144 u8 hph_reg_val = 0;
2145 if (left)
2146 hph_reg_val = snd_soc_read(codec,
2147 TABLA_A_RX_HPH_L_DAC_CTL);
2148 else
2149 hph_reg_val = snd_soc_read(codec,
2150 TABLA_A_RX_HPH_R_DAC_CTL);
2151
2152 return (hph_reg_val & 0xC0) ? true : false;
2153}
2154
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002155static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2156 int vddio_switch)
2157{
2158 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2159 int cfilt_k_val;
Joonwoo Park03324832012-03-19 19:36:16 -07002160 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002161
Joonwoo Park03324832012-03-19 19:36:16 -07002162 mutex_lock(&tabla->mbhc_mutex);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002163 switch (vddio_switch) {
2164 case 1:
Joonwoo Park03324832012-03-19 19:36:16 -07002165 if (tabla->mbhc_micbias_switched == 0 &&
2166 tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002167 tabla_codec_pause_hs_polling(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08002168 /* VDDIO switch enabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002169 tabla->cfilt_k_value = snd_soc_read(codec,
2170 tabla->mbhc_bias_regs.cfilt_val);
2171 cfilt_k_val = tabla_find_k_value(
2172 tabla->pdata->micbias.ldoh_v, 1800);
2173 snd_soc_update_bits(codec,
2174 tabla->mbhc_bias_regs.cfilt_val,
2175 0xFC, (cfilt_k_val << 2));
2176
2177 snd_soc_update_bits(codec,
2178 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
2179 snd_soc_update_bits(codec,
2180 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002181 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002182
2183 tabla->mbhc_micbias_switched = true;
Joonwoo Park0976d012011-12-22 11:48:18 -08002184 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002185 }
2186 break;
2187
2188 case 0:
2189 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002190 if (tabla->mbhc_polling_active) {
2191 tabla_codec_pause_hs_polling(codec);
2192 mbhc_was_polling = true;
2193 }
Joonwoo Park0976d012011-12-22 11:48:18 -08002194 /* VDDIO switch disabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002195 if (tabla->cfilt_k_value != 0)
2196 snd_soc_update_bits(codec,
2197 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
2198 tabla->cfilt_k_value);
2199 snd_soc_update_bits(codec,
2200 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
2201 snd_soc_update_bits(codec,
2202 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
2203
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002204 if (mbhc_was_polling)
2205 tabla_codec_start_hs_polling(codec);
2206
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002207 tabla->mbhc_micbias_switched = false;
Joonwoo Park0976d012011-12-22 11:48:18 -08002208 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002209 }
2210 break;
2211 }
Joonwoo Park03324832012-03-19 19:36:16 -07002212 mutex_unlock(&tabla->mbhc_mutex);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002213}
2214
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002215static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2216 struct snd_kcontrol *kcontrol, int event)
2217{
2218 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002219 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2220 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002221 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002222 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002223 char *internal1_text = "Internal1";
2224 char *internal2_text = "Internal2";
2225 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226
2227 pr_debug("%s %d\n", __func__, event);
2228 switch (w->reg) {
2229 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002231 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002232 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002233 break;
2234 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002235 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002236 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002237 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002238 break;
2239 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002240 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002241 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002242 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002243 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002244 case TABLA_1_A_MICB_4_CTL:
2245 case TABLA_2_A_MICB_4_CTL:
2246 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002247 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002248 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002249 break;
2250 default:
2251 pr_err("%s: Error, invalid micbias register\n", __func__);
2252 return -EINVAL;
2253 }
2254
2255 switch (event) {
2256 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002257 /* Decide whether to switch the micbias for MBHC */
Joonwoo Park03324832012-03-19 19:36:16 -07002258 if (w->reg == tabla->mbhc_bias_regs.ctl_reg)
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002259 tabla_codec_switch_micbias(codec, 0);
2260
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002261 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002262 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002263
2264 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002266 else if (strnstr(w->name, internal2_text, 30))
2267 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2268 else if (strnstr(w->name, internal3_text, 30))
2269 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002271 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002272 case SND_SOC_DAPM_POST_PMU:
2273 if (tabla->mbhc_polling_active &&
Joonwoo Park0976d012011-12-22 11:48:18 -08002274 tabla->micbias == micb_line) {
Joonwoo Park03324832012-03-19 19:36:16 -07002275 mutex_lock(&tabla->mbhc_mutex);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002276 tabla_codec_pause_hs_polling(codec);
2277 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07002278 mutex_unlock(&tabla->mbhc_mutex);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002279 }
2280 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002282 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002283
Joonwoo Park03324832012-03-19 19:36:16 -07002284 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg) &&
2285 tabla_is_hph_pa_on(codec))
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002286 tabla_codec_switch_micbias(codec, 1);
2287
Bradley Rubin229c6a52011-07-12 16:18:48 -07002288 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002290 else if (strnstr(w->name, internal2_text, 30))
2291 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2292 else if (strnstr(w->name, internal3_text, 30))
2293 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2294
Patrick Lai3043fba2011-08-01 14:15:57 -07002295 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002296 break;
2297 }
2298
2299 return 0;
2300}
2301
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002302static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
2303 struct snd_kcontrol *kcontrol, int event)
2304{
2305 struct snd_soc_codec *codec = w->codec;
2306 u16 dec_reset_reg;
2307
2308 pr_debug("%s %d\n", __func__, event);
2309
2310 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
2311 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
2312 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
2313 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
2314 else {
2315 pr_err("%s: Error, incorrect dec\n", __func__);
2316 return -EINVAL;
2317 }
2318
2319 switch (event) {
2320 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002321 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2322 1 << w->shift);
2323 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
2324 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002325 }
2326 return 0;
2327}
2328
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002329static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002330 struct snd_kcontrol *kcontrol, int event)
2331{
2332 struct snd_soc_codec *codec = w->codec;
2333
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002334 pr_debug("%s %d %s\n", __func__, event, w->name);
2335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336 switch (event) {
2337 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002338 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2339 1 << w->shift, 1 << w->shift);
2340 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2341 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002342 break;
2343 }
2344 return 0;
2345}
2346
Bradley Rubin229c6a52011-07-12 16:18:48 -07002347static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2348 struct snd_kcontrol *kcontrol, int event)
2349{
2350 switch (event) {
2351 case SND_SOC_DAPM_POST_PMU:
2352 case SND_SOC_DAPM_POST_PMD:
2353 usleep_range(1000, 1000);
2354 break;
2355 }
2356 return 0;
2357}
2358
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002359static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2360 struct snd_kcontrol *kcontrol, int event)
2361{
2362 struct snd_soc_codec *codec = w->codec;
2363
2364 pr_debug("%s %d\n", __func__, event);
2365
2366 switch (event) {
2367 case SND_SOC_DAPM_PRE_PMU:
2368 tabla_enable_rx_bias(codec, 1);
2369 break;
2370 case SND_SOC_DAPM_POST_PMD:
2371 tabla_enable_rx_bias(codec, 0);
2372 break;
2373 }
2374 return 0;
2375}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002376static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
2377 struct snd_kcontrol *kcontrol, int event)
2378{
2379 struct snd_soc_codec *codec = w->codec;
2380
2381 pr_debug("%s %s %d\n", __func__, w->name, event);
2382
2383 switch (event) {
2384 case SND_SOC_DAPM_PRE_PMU:
2385 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2386 break;
2387 case SND_SOC_DAPM_POST_PMD:
2388 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2389 break;
2390 }
2391 return 0;
2392}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002393
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002394static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
2395 struct snd_soc_jack *jack, int status,
2396 int mask)
2397{
2398 /* XXX: wake_lock_timeout()? */
Joonwoo Park03324832012-03-19 19:36:16 -07002399 snd_soc_jack_report_no_dapm(jack, status, mask);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002400}
2401
Patrick Lai49efeac2011-11-03 11:01:12 -07002402static void hphocp_off_report(struct tabla_priv *tabla,
2403 u32 jack_status, int irq)
2404{
2405 struct snd_soc_codec *codec;
Joonwoo Park03324832012-03-19 19:36:16 -07002406 if (!tabla) {
2407 pr_err("%s: Bad tabla private data\n", __func__);
2408 return;
2409 }
Patrick Lai49efeac2011-11-03 11:01:12 -07002410
Joonwoo Park03324832012-03-19 19:36:16 -07002411 pr_info("%s: clear ocp status %x\n", __func__, jack_status);
2412 codec = tabla->codec;
2413 if (tabla->hph_status & jack_status) {
Patrick Lai49efeac2011-11-03 11:01:12 -07002414 tabla->hph_status &= ~jack_status;
2415 if (tabla->headset_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002416 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
2417 tabla->hph_status,
2418 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08002419 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2420 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08002421 /* reset retry counter as PA is turned off signifying
2422 * start of new OCP detection session
2423 */
2424 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
2425 tabla->hphlocp_cnt = 0;
2426 else
2427 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302428 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07002429 }
2430}
2431
2432static void hphlocp_off_report(struct work_struct *work)
2433{
2434 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2435 hphlocp_work);
2436 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
2437}
2438
2439static void hphrocp_off_report(struct work_struct *work)
2440{
2441 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2442 hphrocp_work);
2443 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
2444}
2445
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002446static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
2447 struct snd_kcontrol *kcontrol, int event)
2448{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002449 struct snd_soc_codec *codec = w->codec;
2450 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2451 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002452 pr_debug("%s: event = %d\n", __func__, event);
2453
2454 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002455 case SND_SOC_DAPM_PRE_PMU:
2456 mbhc_micb_ctl_val = snd_soc_read(codec,
2457 tabla->mbhc_bias_regs.ctl_reg);
2458
Joonwoo Park03324832012-03-19 19:36:16 -07002459 if (!(mbhc_micb_ctl_val & 0x80))
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002460 tabla_codec_switch_micbias(codec, 1);
2461
2462 break;
2463
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002464 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07002465 /* schedule work is required because at the time HPH PA DAPM
2466 * event callback is called by DAPM framework, CODEC dapm mutex
2467 * would have been locked while snd_soc_jack_report also
2468 * attempts to acquire same lock.
2469 */
Joonwoo Parka9444452011-12-08 18:48:27 -08002470 if (w->shift == 5) {
2471 clear_bit(TABLA_HPHL_PA_OFF_ACK,
2472 &tabla->hph_pa_dac_state);
2473 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
2474 &tabla->hph_pa_dac_state);
2475 if (tabla->hph_status & SND_JACK_OC_HPHL)
2476 schedule_work(&tabla->hphlocp_work);
2477 } else if (w->shift == 4) {
2478 clear_bit(TABLA_HPHR_PA_OFF_ACK,
2479 &tabla->hph_pa_dac_state);
2480 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
2481 &tabla->hph_pa_dac_state);
2482 if (tabla->hph_status & SND_JACK_OC_HPHR)
2483 schedule_work(&tabla->hphrocp_work);
2484 }
2485
Joonwoo Park03324832012-03-19 19:36:16 -07002486 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002487
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002488 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
2489 w->name);
2490 usleep_range(10000, 10000);
2491
2492 break;
2493 }
2494 return 0;
2495}
2496
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002497static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002498 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002499{
2500 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002501 unsigned int cfilt;
2502
Joonwoo Park0976d012011-12-22 11:48:18 -08002503 switch (tabla->micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002504 case TABLA_MICBIAS1:
2505 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
2506 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
2507 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
2508 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
2509 break;
2510 case TABLA_MICBIAS2:
2511 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
2512 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
2513 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
2514 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
2515 break;
2516 case TABLA_MICBIAS3:
2517 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
2518 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
2519 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
2520 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
2521 break;
2522 case TABLA_MICBIAS4:
2523 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002524 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
2525 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
2526 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002527 break;
2528 default:
2529 /* Should never reach here */
2530 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07002531 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002532 }
2533
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002534 micbias_regs->cfilt_sel = cfilt;
2535
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002536 switch (cfilt) {
2537 case TABLA_CFILT1_SEL:
2538 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
2539 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002540 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002541 break;
2542 case TABLA_CFILT2_SEL:
2543 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
2544 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002545 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002546 break;
2547 case TABLA_CFILT3_SEL:
2548 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
2549 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002550 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002551 break;
2552 }
2553}
Santosh Mardie15e2302011-11-15 10:39:23 +05302554static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
2555 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
2556 4, 0, NULL, 0),
2557 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
2558 0, NULL, 0),
2559};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002560
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002561static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
2562 struct snd_kcontrol *kcontrol, int event)
2563{
2564 struct snd_soc_codec *codec = w->codec;
2565
2566 pr_debug("%s %s %d\n", __func__, w->name, event);
2567
2568 switch (event) {
2569 case SND_SOC_DAPM_PRE_PMU:
2570 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2571 break;
2572
2573 case SND_SOC_DAPM_POST_PMD:
2574 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2575 break;
2576 }
2577 return 0;
2578}
2579
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002580static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
2581 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302582 0, tabla_codec_enable_micbias,
2583 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2584 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002585};
2586
2587static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
2588 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302589 0, tabla_codec_enable_micbias,
2590 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2591 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002592};
2593
Santosh Mardie15e2302011-11-15 10:39:23 +05302594static const struct snd_soc_dapm_route audio_i2s_map[] = {
2595 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2596 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2597 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2598 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2599 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2600
2601 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2602 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2603 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2604 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2605};
2606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002607static const struct snd_soc_dapm_route audio_map[] = {
2608 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002609
2610 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2611 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2612
2613 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2614 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2615
2616 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2617 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2618
2619 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2620 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002621 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002622 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2623 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002624 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2625 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002626 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2627 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002628 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2629 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630
2631 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002632 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2633 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2634 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002635 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002636 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2637 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2638
Kiran Kandi3426e512011-09-13 22:50:10 -07002639 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
2640 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
2641 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
2642 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
2643 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
2644 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
2645 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
2646 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
2647 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
2648 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
2649 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
2650
2651 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
2652 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
2653 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
2654 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
2655 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
2656 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
2657 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
2658 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
2659 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
2660 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
2661 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
2662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002663 /* Earpiece (RX MIX1) */
2664 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002665 {"EAR PA", NULL, "EAR_PA_MIXER"},
2666 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002667 {"DAC1", NULL, "CP"},
2668
2669 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2670 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2671 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002672
2673 /* Headset (RX MIX1 and RX MIX2) */
2674 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002675 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002676
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002677 {"HPHL", NULL, "HPHL_PA_MIXER"},
2678 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
2679
2680 {"HPHR", NULL, "HPHR_PA_MIXER"},
2681 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002682
2683 {"HPHL DAC", NULL, "CP"},
2684 {"HPHR DAC", NULL, "CP"},
2685
2686 {"ANC", NULL, "ANC1 MUX"},
2687 {"ANC", NULL, "ANC2 MUX"},
2688 {"ANC1 MUX", "ADC1", "ADC1"},
2689 {"ANC1 MUX", "ADC2", "ADC2"},
2690 {"ANC1 MUX", "ADC3", "ADC3"},
2691 {"ANC1 MUX", "ADC4", "ADC4"},
2692 {"ANC2 MUX", "ADC1", "ADC1"},
2693 {"ANC2 MUX", "ADC2", "ADC2"},
2694 {"ANC2 MUX", "ADC3", "ADC3"},
2695 {"ANC2 MUX", "ADC4", "ADC4"},
2696
Bradley Rubine1d08622011-07-20 18:01:35 -07002697 {"ANC", NULL, "CDC_CONN"},
2698
Bradley Rubin229c6a52011-07-12 16:18:48 -07002699 {"DAC1", "Switch", "RX1 CHAIN"},
2700 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002701 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002702
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002703 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2704 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2705 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2706 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2707 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002708
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002709 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2710 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
2711 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2712 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2713 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
2714 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
2715 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
2716 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
2717 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
2718 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002719
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002720 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2721 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2722
Bradley Rubin229c6a52011-07-12 16:18:48 -07002723 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2724 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2725 {"RX1 CHAIN", NULL, "ANC"},
2726 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002727
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002728 {"CP", NULL, "RX_BIAS"},
2729 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2730 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2731 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2732 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002733 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002734
Kuirong Wang0f8ade32012-02-27 16:29:45 -08002735 {"RX1 MIX1", NULL, "COMP1_CLK"},
2736 {"RX2 MIX1", NULL, "COMP1_CLK"},
2737 {"RX3 MIX1", NULL, "COMP2_CLK"},
2738 {"RX5 MIX1", NULL, "COMP2_CLK"},
2739
2740
Bradley Rubin229c6a52011-07-12 16:18:48 -07002741 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2742 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2743 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2744 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002745 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2746 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2747 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2748 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2749 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2750 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2751 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2752 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002753 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2754 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002755
Bradley Rubin229c6a52011-07-12 16:18:48 -07002756 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2757 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302758 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2759 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002760 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
2761 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002762 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2763 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2764 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302765 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2766 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002767 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
2768 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002769 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2770 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2771 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302772 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2773 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002774 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
2775 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002776 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002777 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2778 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302779 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2780 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002781 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
2782 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002783 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002784 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2785 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302786 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2787 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002788 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
2789 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002790 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002791 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2792 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302793 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2794 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002795 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
2796 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002797 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002798 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2799 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302800 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2801 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002802 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
2803 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002804 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002805 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2806 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302807 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2808 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002809 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
2810 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002811 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002812 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2813 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302814 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2815 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002816 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
2817 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002818 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002819 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2820 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302821 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2822 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002823 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
2824 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002825 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002826 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2827 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302828 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2829 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002830 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
2831 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002832 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002833 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2834 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302835 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2836 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002837 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
2838 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002839 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002840 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2841 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302842 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2843 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002844 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
2845 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002846 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002847 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2848 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302849 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2850 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002851 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
2852 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002853 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002854
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002855 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002856 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002857 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002858 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002859 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002860 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002861 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002862 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002863 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002864 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002865 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002866 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002867 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002868 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002870 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002871 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002872 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002873 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002874 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002875 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002876 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002877 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002878 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002879 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002880 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002881 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002882 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002883
2884 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002885 {"ADC1", NULL, "AMIC1"},
2886 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002887 {"ADC3", NULL, "AMIC3"},
2888 {"ADC4", NULL, "AMIC4"},
2889 {"ADC5", NULL, "AMIC5"},
2890 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002891
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002892 /* AUX PGA Connections */
2893 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2894 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2895 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2896 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2897 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2898 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2899 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2900 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2901 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2902 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2903 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2904 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2905 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2906 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2907 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2908 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2909 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2910 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2911 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2912 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2913 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2914 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2915 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2916 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2917 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2918 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2919 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2920 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2921 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2922 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2923 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2924 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2925 {"AUX_PGA_Left", NULL, "AMIC5"},
2926 {"AUX_PGA_Right", NULL, "AMIC6"},
2927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002928 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002929 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2930 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2931 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2932 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2933 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002934 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002935 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
2936 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
2937 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
2938 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002939
2940 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2941 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2942 {"MIC BIAS1 External", NULL, "LDO_H"},
2943 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2944 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2945 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2946 {"MIC BIAS2 External", NULL, "LDO_H"},
2947 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2948 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2949 {"MIC BIAS3 External", NULL, "LDO_H"},
2950 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002951};
2952
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002953static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
2954
2955 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2956 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2957
2958 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
2959
2960 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
2961 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
2962 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
2963
2964 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2965 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2966
2967 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2968 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
2969 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
2970};
2971
Kiran Kandi7a9fd902011-11-14 13:51:45 -08002972
2973static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
2974
2975 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2976 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2977
2978 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
2979
2980 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
2981
2982 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2983 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2984
2985 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2986};
2987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002988static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
2989{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002990 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302991 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002992
2993 if (TABLA_IS_1_X(tabla_core->version)) {
2994 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
2995 if (tabla_1_reg_readable[i] == reg)
2996 return 1;
2997 }
2998 } else {
2999 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
3000 if (tabla_2_reg_readable[i] == reg)
3001 return 1;
3002 }
3003 }
3004
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003005 return tabla_reg_readable[reg];
3006}
3007
3008static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3009{
3010 /* Registers lower than 0x100 are top level registers which can be
3011 * written by the Tabla core driver.
3012 */
3013
3014 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3015 return 1;
3016
Ben Romberger1f045a72011-11-04 10:14:57 -07003017 /* IIR Coeff registers are not cacheable */
3018 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
3019 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
3020 return 1;
3021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003022 return 0;
3023}
3024
3025#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3026static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
3027 unsigned int value)
3028{
3029 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003030 BUG_ON(reg > TABLA_MAX_REGISTER);
3031
3032 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003033 ret = snd_soc_cache_write(codec, reg, value);
3034 if (ret != 0)
3035 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3036 reg, ret);
3037 }
3038
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303039 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003040}
3041static unsigned int tabla_read(struct snd_soc_codec *codec,
3042 unsigned int reg)
3043{
3044 unsigned int val;
3045 int ret;
3046
3047 BUG_ON(reg > TABLA_MAX_REGISTER);
3048
3049 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
3050 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003051 ret = snd_soc_cache_read(codec, reg, &val);
3052 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003053 return val;
3054 } else
3055 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3056 reg, ret);
3057 }
3058
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303059 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003060 return val;
3061}
3062
Bradley Rubincb1e2732011-06-23 16:49:20 -07003063static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3064{
Joonwoo Parkc0672392012-01-11 11:03:14 -08003065 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08003066 struct tabla_mbhc_btn_detect_cfg *btn_det;
3067 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08003068 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003069
Joonwoo Park0976d012011-12-22 11:48:18 -08003070 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
3071 tabla->mbhc_data.v_ins_hu & 0xFF);
3072 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
3073 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003074
Joonwoo Park0976d012011-12-22 11:48:18 -08003075 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
3076 tabla->mbhc_data.v_b1_hu & 0xFF);
3077 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
3078 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
3079
3080 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
3081 tabla->mbhc_data.v_b1_h & 0xFF);
3082 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
3083 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
3084
3085 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
3086 tabla->mbhc_data.v_brh & 0xFF);
3087 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
3088 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
3089
3090 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
3091 tabla->mbhc_data.v_brl & 0xFF);
3092 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
3093 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
3094
Joonwoo Parkc0672392012-01-11 11:03:14 -08003095 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003096 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08003097 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003098 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
3099 tabla->mbhc_data.npoll);
3100 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
3101 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08003102 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003103 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
3104 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003105}
3106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003107static int tabla_startup(struct snd_pcm_substream *substream,
3108 struct snd_soc_dai *dai)
3109{
Kuirong Wanga545e722012-02-06 19:12:54 -08003110 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003111 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3112 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003113 if ((tabla_core != NULL) &&
3114 (tabla_core->dev != NULL) &&
3115 (tabla_core->dev->parent != NULL))
3116 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003117
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003118 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003119}
3120
3121static void tabla_shutdown(struct snd_pcm_substream *substream,
3122 struct snd_soc_dai *dai)
3123{
Kuirong Wanga545e722012-02-06 19:12:54 -08003124 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003125 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3126 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003127 if ((tabla_core != NULL) &&
3128 (tabla_core->dev != NULL) &&
3129 (tabla_core->dev->parent != NULL)) {
3130 pm_runtime_mark_last_busy(tabla_core->dev->parent);
3131 pm_runtime_put(tabla_core->dev->parent);
3132 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003133}
3134
3135int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable)
3136{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3138
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003139 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003140
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003141 if (mclk_enable) {
3142 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003143
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003144 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07003145 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003146 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003147 TABLA_BANDGAP_AUDIO_MODE);
3148 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003149 tabla_codec_calibrate_hs_polling(codec);
3150 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303151 } else {
3152 tabla_codec_enable_bandgap(codec,
3153 TABLA_BANDGAP_AUDIO_MODE);
3154 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003155 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003156 } else {
3157
3158 if (!tabla->mclk_enabled) {
3159 pr_err("Error, MCLK already diabled\n");
3160 return -EINVAL;
3161 }
3162 tabla->mclk_enabled = false;
3163
3164 if (tabla->mbhc_polling_active) {
3165 if (!tabla->mclk_enabled) {
3166 tabla_codec_pause_hs_polling(codec);
3167 tabla_codec_enable_bandgap(codec,
3168 TABLA_BANDGAP_MBHC_MODE);
3169 tabla_enable_rx_bias(codec, 1);
3170 tabla_codec_enable_clock_block(codec, 1);
3171 tabla_codec_calibrate_hs_polling(codec);
3172 tabla_codec_start_hs_polling(codec);
3173 }
3174 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
3175 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303176 } else {
3177 tabla_codec_disable_clock_block(codec);
3178 tabla_codec_enable_bandgap(codec,
3179 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003180 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003181 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003182 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003183}
3184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003185static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
3186 int clk_id, unsigned int freq, int dir)
3187{
3188 pr_debug("%s\n", __func__);
3189 return 0;
3190}
3191
3192static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3193{
Santosh Mardie15e2302011-11-15 10:39:23 +05303194 u8 val = 0;
3195 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003197 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05303198 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3199 case SND_SOC_DAIFMT_CBS_CFS:
3200 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303201 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003202 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303203 snd_soc_update_bits(dai->codec,
3204 TABLA_A_CDC_CLK_TX_I2S_CTL,
3205 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003206 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303207 snd_soc_update_bits(dai->codec,
3208 TABLA_A_CDC_CLK_RX_I2S_CTL,
3209 TABLA_I2S_MASTER_MODE_MASK, 0);
3210 }
3211 break;
3212 case SND_SOC_DAIFMT_CBM_CFM:
3213 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303214 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303215 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003216 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303217 snd_soc_update_bits(dai->codec,
3218 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003219 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303220 snd_soc_update_bits(dai->codec,
3221 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
3222 }
3223 break;
3224 default:
3225 return -EINVAL;
3226 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003227 return 0;
3228}
3229
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003230static int tabla_set_channel_map(struct snd_soc_dai *dai,
3231 unsigned int tx_num, unsigned int *tx_slot,
3232 unsigned int rx_num, unsigned int *rx_slot)
3233
3234{
3235 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3236 u32 i = 0;
3237 if (!tx_slot && !rx_slot) {
3238 pr_err("%s: Invalid\n", __func__);
3239 return -EINVAL;
3240 }
3241 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3242
Neema Shettyd3a89262012-02-16 10:23:50 -08003243 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003244 for (i = 0; i < rx_num; i++) {
3245 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
3246 tabla->dai[dai->id - 1].ch_act = 0;
3247 tabla->dai[dai->id - 1].ch_tot = rx_num;
3248 }
3249 } else if (dai->id == AIF1_CAP) {
3250 for (i = 0; i < tx_num; i++) {
3251 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
3252 tabla->dai[dai->id - 1].ch_act = 0;
3253 tabla->dai[dai->id - 1].ch_tot = tx_num;
3254 }
3255 }
3256 return 0;
3257}
3258
3259static int tabla_get_channel_map(struct snd_soc_dai *dai,
3260 unsigned int *tx_num, unsigned int *tx_slot,
3261 unsigned int *rx_num, unsigned int *rx_slot)
3262
3263{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303264 struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003265
3266 u32 cnt = 0;
3267 u32 tx_ch[SLIM_MAX_TX_PORTS];
3268 u32 rx_ch[SLIM_MAX_RX_PORTS];
3269
3270 if (!rx_slot && !tx_slot) {
3271 pr_err("%s: Invalid\n", __func__);
3272 return -EINVAL;
3273 }
3274 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
3275 /* for virtual port, codec driver needs to do
3276 * housekeeping, for now should be ok
3277 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303278 wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003279 if (dai->id == AIF1_PB) {
3280 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3281 while (cnt < *rx_num) {
3282 rx_slot[cnt] = rx_ch[cnt];
3283 cnt++;
3284 }
3285 } else if (dai->id == AIF1_CAP) {
3286 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3287 while (cnt < *tx_num) {
3288 tx_slot[cnt] = tx_ch[6 + cnt];
3289 cnt++;
3290 }
Neema Shettyd3a89262012-02-16 10:23:50 -08003291 } else if (dai->id == AIF2_PB) {
3292 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3293 while (cnt < *rx_num) {
3294 rx_slot[cnt] = rx_ch[5 + cnt];
3295 cnt++;
3296 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003297 }
3298 return 0;
3299}
3300
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003301static int tabla_hw_params(struct snd_pcm_substream *substream,
3302 struct snd_pcm_hw_params *params,
3303 struct snd_soc_dai *dai)
3304{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003305 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05303306 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07003307 u8 path, shift;
3308 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003309 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003310 u32 compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003311
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003312 pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
3313 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003314
3315 switch (params_rate(params)) {
3316 case 8000:
3317 tx_fs_rate = 0x00;
3318 rx_fs_rate = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003319 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003320 break;
3321 case 16000:
3322 tx_fs_rate = 0x01;
3323 rx_fs_rate = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003324 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003325 break;
3326 case 32000:
3327 tx_fs_rate = 0x02;
3328 rx_fs_rate = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003329 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003330 break;
3331 case 48000:
3332 tx_fs_rate = 0x03;
3333 rx_fs_rate = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003334 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003335 break;
3336 default:
3337 pr_err("%s: Invalid sampling rate %d\n", __func__,
3338 params_rate(params));
3339 return -EINVAL;
3340 }
3341
3342
3343 /**
3344 * If current dai is a tx dai, set sample rate to
3345 * all the txfe paths that are currently not active
3346 */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003347 if (dai->id == AIF1_CAP) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003348
3349 tx_state = snd_soc_read(codec,
3350 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3351
3352 for (path = 1, shift = 0;
3353 path <= NUM_DECIMATORS; path++, shift++) {
3354
3355 if (path == BITS_PER_REG + 1) {
3356 shift = 0;
3357 tx_state = snd_soc_read(codec,
3358 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
3359 }
3360
3361 if (!(tx_state & (1 << shift))) {
3362 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
3363 + (BITS_PER_REG*(path-1));
3364 snd_soc_update_bits(codec, tx_fs_reg,
3365 0x03, tx_fs_rate);
3366 }
3367 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303368 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303369 switch (params_format(params)) {
3370 case SNDRV_PCM_FORMAT_S16_LE:
3371 snd_soc_update_bits(codec,
3372 TABLA_A_CDC_CLK_TX_I2S_CTL,
3373 0x20, 0x20);
3374 break;
3375 case SNDRV_PCM_FORMAT_S32_LE:
3376 snd_soc_update_bits(codec,
3377 TABLA_A_CDC_CLK_TX_I2S_CTL,
3378 0x20, 0x00);
3379 break;
3380 default:
3381 pr_err("invalid format\n");
3382 break;
3383 }
3384 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
3385 0x03, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003386 } else {
3387 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303388 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003389 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003390 /**
3391 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3392 * with varying sample rates
3393 */
3394
3395 /**
3396 * If current dai is a rx dai, set sample rate to
3397 * all the rx paths that are currently not active
3398 */
Neema Shettyd3a89262012-02-16 10:23:50 -08003399 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003400
3401 rx_state = snd_soc_read(codec,
3402 TABLA_A_CDC_CLK_RX_B1_CTL);
3403
3404 for (path = 1, shift = 0;
3405 path <= NUM_INTERPOLATORS; path++, shift++) {
3406
3407 if (!(rx_state & (1 << shift))) {
3408 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
3409 + (BITS_PER_REG*(path-1));
3410 snd_soc_update_bits(codec, rx_fs_reg,
3411 0xE0, rx_fs_rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003412 if (comp_rx_path[shift] < COMPANDER_MAX)
3413 tabla->comp_fs[comp_rx_path[shift]]
3414 = compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003415 }
3416 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303417 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303418 switch (params_format(params)) {
3419 case SNDRV_PCM_FORMAT_S16_LE:
3420 snd_soc_update_bits(codec,
3421 TABLA_A_CDC_CLK_RX_I2S_CTL,
3422 0x20, 0x20);
3423 break;
3424 case SNDRV_PCM_FORMAT_S32_LE:
3425 snd_soc_update_bits(codec,
3426 TABLA_A_CDC_CLK_RX_I2S_CTL,
3427 0x20, 0x00);
3428 break;
3429 default:
3430 pr_err("invalid format\n");
3431 break;
3432 }
3433 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
3434 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003435 } else {
3436 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303437 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003438 }
3439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003440 return 0;
3441}
3442
3443static struct snd_soc_dai_ops tabla_dai_ops = {
3444 .startup = tabla_startup,
3445 .shutdown = tabla_shutdown,
3446 .hw_params = tabla_hw_params,
3447 .set_sysclk = tabla_set_dai_sysclk,
3448 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003449 .set_channel_map = tabla_set_channel_map,
3450 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003451};
3452
3453static struct snd_soc_dai_driver tabla_dai[] = {
3454 {
3455 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003456 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003457 .playback = {
3458 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003459 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003460 .formats = TABLA_FORMATS,
3461 .rate_max = 48000,
3462 .rate_min = 8000,
3463 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003464 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003465 },
3466 .ops = &tabla_dai_ops,
3467 },
3468 {
3469 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003470 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 .capture = {
3472 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003473 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003474 .formats = TABLA_FORMATS,
3475 .rate_max = 48000,
3476 .rate_min = 8000,
3477 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003478 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003479 },
3480 .ops = &tabla_dai_ops,
3481 },
Neema Shettyd3a89262012-02-16 10:23:50 -08003482 {
3483 .name = "tabla_rx2",
3484 .id = AIF2_PB,
3485 .playback = {
3486 .stream_name = "AIF2 Playback",
3487 .rates = WCD9310_RATES,
3488 .formats = TABLA_FORMATS,
3489 .rate_min = 8000,
3490 .rate_max = 48000,
3491 .channels_min = 1,
3492 .channels_max = 2,
3493 },
3494 .ops = &tabla_dai_ops,
3495 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003496};
Santosh Mardie15e2302011-11-15 10:39:23 +05303497
3498static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3499 {
3500 .name = "tabla_i2s_rx1",
3501 .id = 1,
3502 .playback = {
3503 .stream_name = "AIF1 Playback",
3504 .rates = WCD9310_RATES,
3505 .formats = TABLA_FORMATS,
3506 .rate_max = 48000,
3507 .rate_min = 8000,
3508 .channels_min = 1,
3509 .channels_max = 4,
3510 },
3511 .ops = &tabla_dai_ops,
3512 },
3513 {
3514 .name = "tabla_i2s_tx1",
3515 .id = 2,
3516 .capture = {
3517 .stream_name = "AIF1 Capture",
3518 .rates = WCD9310_RATES,
3519 .formats = TABLA_FORMATS,
3520 .rate_max = 48000,
3521 .rate_min = 8000,
3522 .channels_min = 1,
3523 .channels_max = 4,
3524 },
3525 .ops = &tabla_dai_ops,
3526 },
3527};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003528
3529static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3530 struct snd_kcontrol *kcontrol, int event)
3531{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303532 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003533 struct snd_soc_codec *codec = w->codec;
3534 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3535 u32 j = 0;
3536 u32 ret = 0;
3537 codec->control_data = dev_get_drvdata(codec->dev->parent);
3538 tabla = codec->control_data;
3539 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303540 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003541 return 0;
3542 switch (event) {
3543 case SND_SOC_DAPM_POST_PMU:
3544 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3545 if (tabla_dai[j].id == AIF1_CAP)
3546 continue;
3547 if (!strncmp(w->sname,
3548 tabla_dai[j].playback.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_rx(tabla,
3555 tabla_p->dai[j].ch_num,
3556 tabla_p->dai[j].ch_tot,
3557 tabla_p->dai[j].rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003558 break;
3559 case SND_SOC_DAPM_POST_PMD:
3560 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3561 if (tabla_dai[j].id == AIF1_CAP)
3562 continue;
3563 if (!strncmp(w->sname,
3564 tabla_dai[j].playback.stream_name, 13)) {
3565 --tabla_p->dai[j].ch_act;
3566 break;
3567 }
3568 }
3569 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303570 ret = wcd9xxx_close_slim_sch_rx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003571 tabla_p->dai[j].ch_num,
3572 tabla_p->dai[j].ch_tot);
3573 tabla_p->dai[j].rate = 0;
3574 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303575 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003576 tabla_p->dai[j].ch_tot = 0;
3577 }
3578 }
3579 return ret;
3580}
3581
3582static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3583 struct snd_kcontrol *kcontrol, int event)
3584{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303585 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003586 struct snd_soc_codec *codec = w->codec;
3587 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3588 /* index to the DAI ID, for now hardcoding */
3589 u32 j = 0;
3590 u32 ret = 0;
3591
3592 codec->control_data = dev_get_drvdata(codec->dev->parent);
3593 tabla = codec->control_data;
3594
3595 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303596 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003597 return 0;
3598 switch (event) {
3599 case SND_SOC_DAPM_POST_PMU:
3600 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003601 if (tabla_dai[j].id == AIF1_PB ||
3602 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003603 continue;
3604 if (!strncmp(w->sname,
3605 tabla_dai[j].capture.stream_name, 13)) {
3606 ++tabla_p->dai[j].ch_act;
3607 break;
3608 }
3609 }
3610 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303611 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003612 tabla_p->dai[j].ch_num,
3613 tabla_p->dai[j].ch_tot,
3614 tabla_p->dai[j].rate);
3615 break;
3616 case SND_SOC_DAPM_POST_PMD:
3617 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003618 if (tabla_dai[j].id == AIF1_PB ||
3619 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003620 continue;
3621 if (!strncmp(w->sname,
3622 tabla_dai[j].capture.stream_name, 13)) {
3623 --tabla_p->dai[j].ch_act;
3624 break;
3625 }
3626 }
3627 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303628 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003629 tabla_p->dai[j].ch_num,
3630 tabla_p->dai[j].ch_tot);
3631 tabla_p->dai[j].rate = 0;
3632 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303633 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003634 tabla_p->dai[j].ch_tot = 0;
3635 }
3636 }
3637 return ret;
3638}
3639
3640/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3641 * Might Need to have callbacks registered only for slimbus
3642 */
3643static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
3644 /*RX stuff */
3645 SND_SOC_DAPM_OUTPUT("EAR"),
3646
3647 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
3648
3649 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
3650 ARRAY_SIZE(dac1_switch)),
3651
3652 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3653 0, tabla_codec_enable_slimrx,
3654 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3655 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3656 0, tabla_codec_enable_slimrx,
3657 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3658
3659 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3660 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3661
Neema Shettyd3a89262012-02-16 10:23:50 -08003662 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3663 0, tabla_codec_enable_slimrx,
3664 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3665 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3666 0, tabla_codec_enable_slimrx,
3667 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3668
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003669 /* Headphone */
3670 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3671 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3672 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3673 SND_SOC_DAPM_POST_PMD),
3674 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
3675 hphl_switch, ARRAY_SIZE(hphl_switch)),
3676
3677 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
3678 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3679 SND_SOC_DAPM_POST_PMD),
3680
3681 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
3682 tabla_hphr_dac_event,
3683 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3684
3685 /* Speaker */
3686 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
3687 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
3688 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
3689 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
3690 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
3691
3692 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
3693 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3694 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3695 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
3696 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3697 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3698 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
3699 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3700 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3701 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
3702 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3703 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3704 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
3705 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3706 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3707
3708 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
3709 , tabla_lineout_dac_event,
3710 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3711 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
3712 , tabla_lineout_dac_event,
3713 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3714 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
3715 , tabla_lineout_dac_event,
3716 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3717 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
3718 &lineout3_ground_switch),
3719 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
3720 , tabla_lineout_dac_event,
3721 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3722 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
3723 &lineout4_ground_switch),
3724 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
3725 , tabla_lineout_dac_event,
3726 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3727
3728 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
3729 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3730 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
3731 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3732 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
3733 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3734 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
3735 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3736 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
3737 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3738 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
3739 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3740 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
3741 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3742
3743 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
3744 &rx4_dsm_mux, tabla_codec_reset_interpolator,
3745 SND_SOC_DAPM_PRE_PMU),
3746
3747 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
3748 &rx6_dsm_mux, tabla_codec_reset_interpolator,
3749 SND_SOC_DAPM_PRE_PMU),
3750
3751 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
3752 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
3753
3754 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3755 &rx_mix1_inp1_mux),
3756 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3757 &rx_mix1_inp2_mux),
3758 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3759 &rx2_mix1_inp1_mux),
3760 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3761 &rx2_mix1_inp2_mux),
3762 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3763 &rx3_mix1_inp1_mux),
3764 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3765 &rx3_mix1_inp2_mux),
3766 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3767 &rx4_mix1_inp1_mux),
3768 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3769 &rx4_mix1_inp2_mux),
3770 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3771 &rx5_mix1_inp1_mux),
3772 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3773 &rx5_mix1_inp2_mux),
3774 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3775 &rx6_mix1_inp1_mux),
3776 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3777 &rx6_mix1_inp2_mux),
3778 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3779 &rx7_mix1_inp1_mux),
3780 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3781 &rx7_mix1_inp2_mux),
3782
3783 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
3784 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
3785 SND_SOC_DAPM_PRE_PMD),
3786
3787 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
3788 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
3789 SND_SOC_DAPM_POST_PMD),
3790
3791 /* TX */
3792
3793 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
3794 0),
3795
3796 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
3797 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
3798
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003799 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
3800 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3801 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3802 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
3803 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3804 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3805
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003806 SND_SOC_DAPM_INPUT("AMIC1"),
3807 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
3808 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3809 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3810 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
3811 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3812 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3813 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
3814 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3815 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3816 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
3817 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3818 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3819
3820 SND_SOC_DAPM_INPUT("AMIC3"),
3821 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
3822 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3823 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3824
3825 SND_SOC_DAPM_INPUT("AMIC4"),
3826 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
3827 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3828 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3829
3830 SND_SOC_DAPM_INPUT("AMIC5"),
3831 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
3832 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3833
3834 SND_SOC_DAPM_INPUT("AMIC6"),
3835 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
3836 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3837
3838 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
3839 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3840
3841 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
3842 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3843
3844 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
3845 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3846
3847 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
3848 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3849
3850 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
3851 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3852
3853 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
3854 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3855
3856 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
3857 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3858
3859 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
3860 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3861
3862 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
3863 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3864
3865 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
3866 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3867
3868 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
3869 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
3870
3871 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
3872 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
3873 SND_SOC_DAPM_POST_PMD),
3874
3875 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
3876
3877 SND_SOC_DAPM_INPUT("AMIC2"),
3878 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
3879 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3880 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3881 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
3882 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3883 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3884 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
3885 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3886 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3887 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
3888 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3889 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3890 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
3891 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3892 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3893 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
3894 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3895 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3896 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
3897 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3898 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3899 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
3900 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3901 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3902
3903 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
3904 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
3905 0, 0),
3906
3907 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
3908 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
3909 4, 0),
3910
3911 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
3912 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
3913 5, 0),
3914
3915 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
3916 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3917 0, tabla_codec_enable_slimtx,
3918 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3919
3920 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
3921 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3922 0, tabla_codec_enable_slimtx,
3923 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3924
3925 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
3926 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
3927 0, 0, tabla_codec_enable_slimtx,
3928 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3929
3930 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
3931 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
3932 0, 0, tabla_codec_enable_slimtx,
3933 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3934
3935 /* Digital Mic Inputs */
3936 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
3937 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3938 SND_SOC_DAPM_POST_PMD),
3939
3940 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
3941 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3942 SND_SOC_DAPM_POST_PMD),
3943
3944 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
3945 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3946 SND_SOC_DAPM_POST_PMD),
3947
3948 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
3949 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3950 SND_SOC_DAPM_POST_PMD),
3951
3952 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
3953 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3954 SND_SOC_DAPM_POST_PMD),
3955 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
3956 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3957 SND_SOC_DAPM_POST_PMD),
3958
3959 /* Sidetone */
3960 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
3961 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003962
3963 /* AUX PGA */
3964 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
3965 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3966 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
3967 SND_SOC_DAPM_POST_PMD),
3968
3969 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
3970 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3971 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
3972 SND_SOC_DAPM_POST_PMD),
3973
3974 /* Lineout, ear and HPH PA Mixers */
3975 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
3976 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
3977
3978 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
3979 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
3980
3981 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
3982 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
3983
3984 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
3985 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
3986
3987 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
3988 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
3989
3990 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
3991 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
3992
3993 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
3994 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
3995
3996 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
3997 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003998};
3999
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004000static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004001{
4002 u8 bias_msb, bias_lsb;
4003 short bias_value;
4004
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004005 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
4006 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
4007 bias_value = (bias_msb << 8) | bias_lsb;
4008 return bias_value;
4009}
4010
4011static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
4012{
4013 u8 bias_msb, bias_lsb;
4014 short bias_value;
4015
4016 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
4017 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
4018 bias_value = (bias_msb << 8) | bias_lsb;
4019 return bias_value;
4020}
4021
Joonwoo Park0976d012011-12-22 11:48:18 -08004022static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004023{
Joonwoo Park0976d012011-12-22 11:48:18 -08004024 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004025 short bias_value;
4026
Joonwoo Park925914c2012-01-05 13:35:18 -08004027 /* Turn on the override */
4028 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004029 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004030 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4031 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
4032 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004033 usleep_range(tabla->mbhc_data.t_sta_dce,
4034 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004035 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08004036 usleep_range(tabla->mbhc_data.t_dce,
4037 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004038 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004039 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004040 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004041 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4042 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004043 usleep_range(tabla->mbhc_data.t_sta_dce,
4044 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08004045 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4046 usleep_range(tabla->mbhc_data.t_sta,
4047 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004048 bias_value = tabla_codec_read_sta_result(codec);
4049 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4050 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004051 }
Joonwoo Park925914c2012-01-05 13:35:18 -08004052 /* Turn off the override after measuring mic voltage */
4053 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004054
Bradley Rubincb1e2732011-06-23 16:49:20 -07004055 return bias_value;
4056}
4057
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004058static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004059{
4060 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004061 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004062 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063
Joonwoo Park0976d012011-12-22 11:48:18 -08004064 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004065 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004066 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004067 }
4068
Joonwoo Park03324832012-03-19 19:36:16 -07004069 mutex_lock(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004070 tabla->mbhc_polling_active = true;
4071
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004072 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004073 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004074 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004075 tabla_codec_enable_clock_block(codec, 1);
4076 }
Joonwoo Park03324832012-03-19 19:36:16 -07004077 mutex_unlock(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004078
4079 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004081 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0xE0);
4082
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004083 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004084 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4085 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004086
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004087 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004088
4089 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004090 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004091
4092 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4093 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4094 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4095
4096 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004097 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4098 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004099
Joonwoo Park925914c2012-01-05 13:35:18 -08004100 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004101 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4102
Bradley Rubincb1e2732011-06-23 16:49:20 -07004103 tabla_codec_calibrate_hs_polling(codec);
4104
Joonwoo Park03324832012-03-19 19:36:16 -07004105 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x00);
4106 bias_value = tabla_codec_sta_dce(codec, 1);
4107 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004108 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4109 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004110 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004111
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004112 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004113}
4114
Joonwoo Park03324832012-03-19 19:36:16 -07004115/* called after acquiring codec mutex */
4116static void tabla_set_pa_dac_state(struct snd_soc_codec *codec)
4117{
4118 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4119
4120 /* If headphone PA is on, check if userspace receives
4121 * removal event to sync-up PA's state */
4122 if (tabla_is_hph_pa_on(codec)) {
4123 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4124 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4125 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4126 } else {
4127 pr_debug("%s PA is off\n", __func__);
4128 }
4129
4130 if (tabla_is_hph_dac_on(codec, 1))
4131 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4132 if (tabla_is_hph_dac_on(codec, 0))
4133 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4134}
4135
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004136static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07004137 int insertion, int trigger,
4138 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004139{
4140 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004141 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08004142 const struct tabla_mbhc_general_cfg *generic =
4143 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
4144 const struct tabla_mbhc_plug_detect_cfg *plug_det =
4145 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004146 u8 wg_time;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004147
Joonwoo Park0976d012011-12-22 11:48:18 -08004148 if (!tabla->calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004149 pr_err("Error, no tabla calibration\n");
4150 return -EINVAL;
4151 }
4152
4153 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
4154
Joonwoo Park03324832012-03-19 19:36:16 -07004155 /* Make sure mic bias and Mic line schmitt trigger
4156 * are turned OFF
4157 */
4158 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
4159 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
4160
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004161 if (insertion) {
Joonwoo Park03324832012-03-19 19:36:16 -07004162
Bhalchandra Gajare5ea376d2011-11-30 14:21:20 -08004163 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4164 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07004165 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004166
Joonwoo Park03324832012-03-19 19:36:16 -07004167 /* DAPM can manipulate PA/DAC bits concurrently */
4168 if (padac_off == true) {
4169 mutex_lock(&codec->mutex);
4170 tabla_set_pa_dac_state(codec);
4171 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30,
4172 0x00);
4173 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
4174 0xC0, 0x00);
4175 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
4176 0xC0, 0x00);
4177 usleep_range(wg_time * 1000, wg_time * 1000);
4178 mutex_unlock(&codec->mutex);
4179 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004180
Joonwoo Park03324832012-03-19 19:36:16 -07004181 if (trigger == MBHC_USE_HPHL_TRIGGER) {
4182 /* Enable HPH Schmitt Trigger */
4183 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
4184 0x11);
4185 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
4186 plug_det->hph_current << 2);
4187 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
4188 0x02);
4189 } else if (trigger == MBHC_USE_MB_TRIGGER) {
4190 /* enable the mic line schmitt trigger */
4191 snd_soc_update_bits(codec,
4192 tabla->mbhc_bias_regs.mbhc_reg,
4193 0x60, plug_det->mic_current << 5);
4194 snd_soc_update_bits(codec,
4195 tabla->mbhc_bias_regs.mbhc_reg,
4196 0x80, 0x80);
4197 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4198 snd_soc_update_bits(codec,
4199 tabla->mbhc_bias_regs.ctl_reg, 0x01,
4200 0x00);
4201 snd_soc_update_bits(codec,
4202 tabla->mbhc_bias_regs.mbhc_reg,
4203 0x10, 0x10);
4204 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004205
4206 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004207 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07004208
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004209 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004210 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004211 /* Make sure the HPH schmitt trigger is OFF */
4212 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
4213
4214 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07004215 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
4216 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004217 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08004218 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004219 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4220 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004221 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004222 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4223 0x10, 0x10);
4224
4225 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004226 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004227 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004228
4229 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Park03324832012-03-19 19:36:16 -07004230 mutex_lock(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004231 if (!(tabla->clock_active)) {
4232 tabla_codec_enable_config_mode(codec, 1);
4233 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004234 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004235 usleep_range(generic->t_shutdown_plug_rem,
4236 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004237 tabla_codec_enable_config_mode(codec, 0);
4238 } else
4239 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004240 0x06, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07004241 mutex_unlock(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004242 }
4243
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004244 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004245
4246 /* If central bandgap disabled */
4247 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
4248 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004249 usleep_range(generic->t_bg_fast_settle,
4250 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004251 central_bias_enabled = 1;
4252 }
4253
4254 /* If LDO_H disabled */
4255 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
4256 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
4257 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004258 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004259 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
4260
4261 if (central_bias_enabled)
4262 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
4263 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004264
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004265 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
4266 tabla->micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004267
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304268 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004269 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4270 return 0;
4271}
4272
Joonwoo Park0976d012011-12-22 11:48:18 -08004273static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4274 s16 vin_mv)
4275{
Joonwoo Park0976d012011-12-22 11:48:18 -08004276 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004277 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08004278 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07004279 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004280
4281 tabla = snd_soc_codec_get_drvdata(codec);
4282 mb_mv = tabla->mbhc_data.micb_mv;
4283
4284 if (mb_mv == 0) {
4285 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4286 return -EINVAL;
4287 }
4288
4289 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004290 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
4291 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004292 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004293 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
4294 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004295 }
4296 in = (u32) diff * vin_mv;
4297
Joonwoo Park03324832012-03-19 19:36:16 -07004298 value = (u16) (in / mb_mv) + zero;
4299 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004300}
4301
4302static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4303 u16 bias_value)
4304{
4305 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004306 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08004307 s32 mv;
4308
4309 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004310 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004311 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004312 z = (tabla->mbhc_data.dce_z);
4313 mb = (tabla->mbhc_data.dce_mb);
4314 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004315 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004316 z = (tabla->mbhc_data.sta_z);
4317 mb = (tabla->mbhc_data.sta_mb);
4318 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004319 }
4320
4321 return mv;
4322}
4323
Joonwoo Park03324832012-03-19 19:36:16 -07004324static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004325{
4326 struct delayed_work *delayed_work;
4327 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08004328 short bias_value;
4329 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07004330 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004331
4332 pr_debug("%s:\n", __func__);
4333
4334 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07004335 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004336 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004337
4338 if (tabla) {
4339 if (tabla->button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004340 bias_value = tabla_codec_read_sta_result(tabla->codec);
4341 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304342 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004343 bias_value = tabla_codec_read_dce_result(tabla->codec);
4344 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304345 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004346 pr_debug("%s: Reporting long button press event"
4347 " STA: %d, DCE: %d\n", __func__,
4348 sta_mv, dce_mv);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004349 tabla_snd_soc_jack_report(tabla, tabla->button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07004350 tabla->buttons_pressed,
4351 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004352 }
4353 } else {
4354 pr_err("%s: Bad tabla private data\n", __func__);
4355 }
4356
Joonwoo Park03324832012-03-19 19:36:16 -07004357 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004358}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004359
Joonwoo Park0976d012011-12-22 11:48:18 -08004360void tabla_mbhc_cal(struct snd_soc_codec *codec)
4361{
4362 struct tabla_priv *tabla;
4363 struct tabla_mbhc_btn_detect_cfg *btn_det;
4364 u8 cfilt_mode, bg_mode;
4365 u8 ncic, nmeas, navg;
4366 u32 mclk_rate;
4367 u32 dce_wait, sta_wait;
4368 u8 *n_cic;
4369
4370 tabla = snd_soc_codec_get_drvdata(codec);
4371
4372 /* First compute the DCE / STA wait times
4373 * depending on tunable parameters.
4374 * The value is computed in microseconds
4375 */
4376 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
4377 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08004378 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Park0976d012011-12-22 11:48:18 -08004379 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration)->n_meas;
4380 navg = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration)->mbhc_navg;
4381 mclk_rate = tabla->mclk_freq;
Joonwoo Park433149a2012-01-11 09:53:54 -08004382 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
4383 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08004384
4385 tabla->mbhc_data.t_dce = dce_wait;
4386 tabla->mbhc_data.t_sta = sta_wait;
4387
4388 /* LDOH and CFILT are already configured during pdata handling.
4389 * Only need to make sure CFILT and bandgap are in Fast mode.
4390 * Need to restore defaults once calculation is done.
4391 */
4392 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4393 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
4394 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
4395 0x02);
4396
4397 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
4398 * to perform ADC calibration
4399 */
4400 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
4401 tabla->micbias << 5);
4402 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
4403 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
4404 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
4405 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
4406
4407 /* DCE measurement for 0 volts */
4408 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4409 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4410 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004411 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4412 usleep_range(100, 100);
4413 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4414 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4415 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
4416
4417 /* DCE measurment for MB voltage */
4418 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4419 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
4420 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4421 usleep_range(100, 100);
4422 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4423 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4424 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
4425
4426 /* Sta measuremnt for 0 volts */
4427 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4428 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4429 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004430 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4431 usleep_range(100, 100);
4432 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4433 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4434 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
4435
4436 /* STA Measurement for MB Voltage */
4437 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4438 usleep_range(100, 100);
4439 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4440 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4441 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
4442
4443 /* Restore default settings. */
4444 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4445 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4446 cfilt_mode);
4447 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
4448
4449 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
4450 usleep_range(100, 100);
4451}
4452
4453void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
4454 const enum tabla_mbhc_btn_det_mem mem)
4455{
4456 void *ret = &btn_det->_v_btn_low;
4457
4458 switch (mem) {
4459 case TABLA_BTN_DET_GAIN:
4460 ret += sizeof(btn_det->_n_cic);
4461 case TABLA_BTN_DET_N_CIC:
4462 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08004463 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08004464 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
4465 case TABLA_BTN_DET_V_BTN_HIGH:
4466 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
4467 case TABLA_BTN_DET_V_BTN_LOW:
4468 /* do nothing */
4469 break;
4470 default:
4471 ret = NULL;
4472 }
4473
4474 return ret;
4475}
4476
4477static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
4478{
4479 struct tabla_priv *tabla;
4480 s16 btn_mv = 0, btn_delta_mv;
4481 struct tabla_mbhc_btn_detect_cfg *btn_det;
4482 struct tabla_mbhc_plug_type_cfg *plug_type;
4483 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004484 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08004485 int i;
4486
4487 tabla = snd_soc_codec_get_drvdata(codec);
4488 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
4489 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
4490
Joonwoo Parkc0672392012-01-11 11:03:14 -08004491 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08004492 if (tabla->mclk_freq == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07004493 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08004494 tabla->mbhc_data.nbounce_wait = 30;
4495 } else if (tabla->mclk_freq == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004496 tabla->mbhc_data.npoll = 7;
4497 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004498 }
Joonwoo Park0976d012011-12-22 11:48:18 -08004499
Joonwoo Park433149a2012-01-11 09:53:54 -08004500 tabla->mbhc_data.t_sta_dce = ((1000 * 256) / (tabla->mclk_freq / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08004501 n_ready[tabla_codec_mclk_index(tabla)]) +
4502 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08004503 tabla->mbhc_data.v_ins_hu =
4504 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
4505 tabla->mbhc_data.v_ins_h =
4506 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
4507
4508 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
4509 for (i = 0; i < btn_det->num_btn; i++)
4510 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
4511
4512 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
4513 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
4514
4515 tabla->mbhc_data.v_b1_hu =
4516 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
4517
4518 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
4519
4520 tabla->mbhc_data.v_b1_huc =
4521 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
4522
4523 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
Joonwoo Park03324832012-03-19 19:36:16 -07004524 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
Joonwoo Park0976d012011-12-22 11:48:18 -08004525
4526 tabla->mbhc_data.v_no_mic =
4527 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
4528}
4529
4530void tabla_mbhc_init(struct snd_soc_codec *codec)
4531{
4532 struct tabla_priv *tabla;
4533 struct tabla_mbhc_general_cfg *generic;
4534 struct tabla_mbhc_btn_detect_cfg *btn_det;
4535 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08004536 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304537 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08004538
4539 tabla = snd_soc_codec_get_drvdata(codec);
4540 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
4541 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->calibration);
4542
Joonwoo Park0976d012011-12-22 11:48:18 -08004543 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08004544 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004545 snd_soc_update_bits(codec,
4546 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
4547 0x07, n);
4548 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
4549 btn_det->c[n]);
4550 }
4551 }
4552 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
4553 btn_det->nc);
4554
4555 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
4556 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08004557 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08004558
4559 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08004560 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
4561 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004562
4563 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
4564 generic->mbhc_nsa << 4);
4565
4566 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
4567 btn_det->n_meas);
4568
4569 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
4570
4571 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
4572
4573 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
4574 btn_det->mbhc_nsc << 3);
4575
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004576 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
4577 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08004578
4579 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07004580
4581 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004582}
4583
Patrick Lai64b43262011-12-06 17:29:15 -08004584static bool tabla_mbhc_fw_validate(const struct firmware *fw)
4585{
4586 u32 cfg_offset;
4587 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
4588 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
4589
4590 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
4591 return false;
4592
4593 /* previous check guarantees that there is enough fw data up
4594 * to num_btn
4595 */
4596 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
4597 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
4598 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
4599 return false;
4600
4601 /* previous check guarantees that there is enough fw data up
4602 * to start of impedance detection configuration
4603 */
4604 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
4605 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
4606
4607 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
4608 return false;
4609
4610 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
4611 return false;
4612
4613 return true;
4614}
Joonwoo Park03324832012-03-19 19:36:16 -07004615
Patrick Lai64b43262011-12-06 17:29:15 -08004616static void mbhc_fw_read(struct work_struct *work)
4617{
4618 struct delayed_work *dwork;
4619 struct tabla_priv *tabla;
4620 struct snd_soc_codec *codec;
4621 const struct firmware *fw;
4622 int ret = -1, retry = 0, rc;
4623
4624 dwork = to_delayed_work(work);
4625 tabla = container_of(dwork, struct tabla_priv,
4626 mbhc_firmware_dwork);
4627 codec = tabla->codec;
4628
4629 while (retry < MBHC_FW_READ_ATTEMPTS) {
4630 retry++;
4631 pr_info("%s:Attempt %d to request MBHC firmware\n",
4632 __func__, retry);
4633 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
4634 codec->dev);
4635
4636 if (ret != 0) {
4637 usleep_range(MBHC_FW_READ_TIMEOUT,
4638 MBHC_FW_READ_TIMEOUT);
4639 } else {
4640 pr_info("%s: MBHC Firmware read succesful\n", __func__);
4641 break;
4642 }
4643 }
4644
4645 if (ret != 0) {
4646 pr_err("%s: Cannot load MBHC firmware use default cal\n",
4647 __func__);
4648 } else if (tabla_mbhc_fw_validate(fw) == false) {
4649 pr_err("%s: Invalid MBHC cal data size use default cal\n",
4650 __func__);
4651 release_firmware(fw);
4652 } else {
4653 tabla->calibration = (void *)fw->data;
4654 tabla->mbhc_fw = fw;
4655 }
4656
4657 tabla->mclk_cb(codec, 1);
4658 tabla_mbhc_init(codec);
4659 tabla_mbhc_cal(codec);
4660 tabla_mbhc_calc_thres(codec);
4661 tabla->mclk_cb(codec, 0);
4662 tabla_codec_calibrate_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004663 rc = tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER, false);
Patrick Lai64b43262011-12-06 17:29:15 -08004664
4665 if (IS_ERR_VALUE(rc))
4666 pr_err("%s: Failed to setup MBHC detection\n", __func__);
4667
4668}
4669
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004670static int tabla_determine_button(const struct tabla_priv *priv,
4671 const s32 bias_mv)
4672{
4673 s16 *v_btn_low, *v_btn_high;
4674 struct tabla_mbhc_btn_detect_cfg *btn_det;
4675 int i, btn = -1;
4676
4677 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
4678 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
4679 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304680 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004681 for (i = 0; i < btn_det->num_btn; i++) {
4682 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
4683 btn = i;
4684 break;
4685 }
4686 }
4687
4688 if (btn == -1)
4689 pr_debug("%s: couldn't find button number for mic mv %d\n",
4690 __func__, bias_mv);
4691
4692 return btn;
4693}
4694
4695static int tabla_get_button_mask(const int btn)
4696{
4697 int mask = 0;
4698 switch (btn) {
4699 case 0:
4700 mask = SND_JACK_BTN_0;
4701 break;
4702 case 1:
4703 mask = SND_JACK_BTN_1;
4704 break;
4705 case 2:
4706 mask = SND_JACK_BTN_2;
4707 break;
4708 case 3:
4709 mask = SND_JACK_BTN_3;
4710 break;
4711 case 4:
4712 mask = SND_JACK_BTN_4;
4713 break;
4714 case 5:
4715 mask = SND_JACK_BTN_5;
4716 break;
4717 case 6:
4718 mask = SND_JACK_BTN_6;
4719 break;
4720 case 7:
4721 mask = SND_JACK_BTN_7;
4722 break;
4723 }
4724 return mask;
4725}
4726
Bradley Rubincb1e2732011-06-23 16:49:20 -07004727static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004728{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004729 int i, mask;
Joonwoo Park03324832012-03-19 19:36:16 -07004730 short dce, sta;
4731 s32 mv, stamv;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004732 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004733 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004734 const struct tabla_mbhc_btn_detect_cfg *d =
4735 TABLA_MBHC_CAL_BTN_DET_PTR(priv->calibration);
4736 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004737 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304738 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07004739 int n_btn_meas = d->n_btn_meas;
4740 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004741
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304742 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
4743 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004744
Joonwoo Park03324832012-03-19 19:36:16 -07004745 mutex_lock(&priv->mbhc_mutex);
4746 priv->mbhc_state = TABLA_IRQ_MBHC_POTENTIAL;
4747 mutex_unlock(&priv->mbhc_mutex);
4748
4749 dce = tabla_codec_read_dce_result(codec);
4750 mv = tabla_codec_sta_dce_v(codec, 1, dce);
4751
4752 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
4753 if (priv->mbhc_last_resume &&
4754 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
4755 pr_debug("%s: Button is already released shortly after "
4756 "resume\n", __func__);
4757 n_btn_meas = 0;
4758 } else {
4759 pr_debug("%s: Button is already released without "
4760 "resume", __func__);
4761 sta = tabla_codec_read_sta_result(codec);
4762 stamv = tabla_codec_sta_dce_v(codec, 0, sta);
4763 btn = tabla_determine_button(priv, mv);
4764 if (btn != tabla_determine_button(priv, stamv))
4765 btn = -1;
4766 goto done;
4767 }
4768 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004769
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004770 /* determine pressed button */
Joonwoo Park03324832012-03-19 19:36:16 -07004771 btnmeas[meas++] = tabla_determine_button(priv, mv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004772 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Joonwoo Park03324832012-03-19 19:36:16 -07004773 meas - 1, dce, mv, btnmeas[meas - 1]);
4774 if (n_btn_meas == 0)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004775 btn = btnmeas[0];
Joonwoo Park03324832012-03-19 19:36:16 -07004776 for (; ((n_btn_meas) && (meas < (n_btn_meas + 1))); meas++) {
4777 dce = tabla_codec_sta_dce(codec, 1);
4778 mv = tabla_codec_sta_dce_v(codec, 1, dce);
4779 btnmeas[meas] = tabla_determine_button(priv, mv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004780 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
Joonwoo Park03324832012-03-19 19:36:16 -07004781 __func__, meas, dce, mv, btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004782 /* if large enough measurements are collected,
4783 * start to check if last all n_btn_con measurements were
4784 * in same button low/high range */
4785 if (meas + 1 >= d->n_btn_con) {
4786 for (i = 0; i < d->n_btn_con; i++)
4787 if ((btnmeas[meas] < 0) ||
4788 (btnmeas[meas] != btnmeas[meas - i]))
4789 break;
4790 if (i == d->n_btn_con) {
4791 /* button pressed */
4792 btn = btnmeas[meas];
4793 break;
Joonwoo Park03324832012-03-19 19:36:16 -07004794 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
4795 /* if left measurements are less than n_btn_con,
4796 * it's impossible to find button number */
4797 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004798 }
4799 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004800 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004801
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004802 if (btn >= 0) {
4803 mask = tabla_get_button_mask(btn);
4804 priv->buttons_pressed |= mask;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004805 msleep(100);
Joonwoo Park03324832012-03-19 19:36:16 -07004806 wcd9xxx_lock_sleep(core);
4807 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
4808 msecs_to_jiffies(400)) == 0) {
4809 WARN(1, "Button pressed twice without release"
4810 "event\n");
4811 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004812 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08004813 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004814 pr_debug("%s: bogus button press, too short press?\n",
4815 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004816 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004817
Joonwoo Park03324832012-03-19 19:36:16 -07004818 done:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004819 return IRQ_HANDLED;
4820}
4821
Joonwoo Park03324832012-03-19 19:36:16 -07004822static int tabla_is_fake_press(struct tabla_priv *priv)
4823{
4824 int i;
4825 int r = 0;
4826 struct snd_soc_codec *codec = priv->codec;
4827 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
4828 short mb_v;
4829
4830 for (i = 0; i < dces; i++) {
4831 usleep_range(10000, 10000);
4832 if (i == 0) {
4833 mb_v = tabla_codec_sta_dce(codec, 0);
4834 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
4835 tabla_codec_sta_dce_v(codec, 0, mb_v));
4836 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
4837 mb_v > (short)priv->mbhc_data.v_ins_hu) {
4838 r = 1;
4839 break;
4840 }
4841 } else {
4842 mb_v = tabla_codec_sta_dce(codec, 1);
4843 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
4844 tabla_codec_sta_dce_v(codec, 1, mb_v));
4845 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
4846 mb_v > (short)priv->mbhc_data.v_ins_h) {
4847 r = 1;
4848 break;
4849 }
4850 }
4851 }
4852
4853 return r;
4854}
4855
Bradley Rubincb1e2732011-06-23 16:49:20 -07004856static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004857{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08004858 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08004859 struct tabla_priv *priv = data;
4860 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304861 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004862
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004863 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07004864
4865 mutex_lock(&priv->mbhc_mutex);
4866 priv->mbhc_state = TABLA_IRQ_MBHC_RELEASE;
4867 mutex_unlock(&priv->mbhc_mutex);
4868
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304869 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004870
Joonwoo Park03324832012-03-19 19:36:16 -07004871 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
4872 ret = cancel_delayed_work(&priv->mbhc_btn_dwork);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004873 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07004874 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004875 __func__);
Joonwoo Park0976d012011-12-22 11:48:18 -08004876 if (priv->button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004877 tabla_snd_soc_jack_report(priv,
Joonwoo Park03324832012-03-19 19:36:16 -07004878 priv->button_jack, 0,
4879 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004880 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004881 /* if scheduled mbhc_btn_dwork is canceled from here,
4882 * we have to unlock from here instead btn_work */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304883 wcd9xxx_unlock_sleep(core);
Joonwoo Park03324832012-03-19 19:36:16 -07004884 if (tabla_is_fake_press(priv)) {
4885 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004886 __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07004887 } else if (priv->button_jack) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004888 pr_debug("%s: Reporting short button 0 "
Joonwoo Park0976d012011-12-22 11:48:18 -08004889 "press and release\n", __func__);
4890 tabla_snd_soc_jack_report(priv,
Joonwoo Park03324832012-03-19 19:36:16 -07004891 priv->button_jack,
4892 priv->buttons_pressed,
4893 priv->buttons_pressed);
Joonwoo Park0976d012011-12-22 11:48:18 -08004894 tabla_snd_soc_jack_report(priv,
Joonwoo Park03324832012-03-19 19:36:16 -07004895 priv->button_jack, 0,
4896 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004897 }
4898 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004899
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004900 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
4901 }
4902
Joonwoo Park03324832012-03-19 19:36:16 -07004903 tabla_codec_calibrate_hs_polling(codec);
4904
4905 mutex_lock(&priv->mbhc_mutex);
Bradley Rubin688c66a2011-08-16 12:25:13 -07004906 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004907 mutex_unlock(&priv->mbhc_mutex);
4908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004909 return IRQ_HANDLED;
4910}
4911
Bradley Rubincb1e2732011-06-23 16:49:20 -07004912static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
4913{
4914 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08004915 const struct tabla_mbhc_general_cfg *generic =
4916 TABLA_MBHC_CAL_GENERAL_PTR(tabla->calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004917
Joonwoo Park03324832012-03-19 19:36:16 -07004918 mutex_lock(&tabla->mbhc_mutex);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004919 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004920 tabla_codec_enable_config_mode(codec, 1);
4921
4922 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
4923 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004924
Joonwoo Park0976d012011-12-22 11:48:18 -08004925 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
4926
4927 usleep_range(generic->t_shutdown_plug_rem,
4928 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004929
4930 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004931 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004932 tabla_codec_enable_config_mode(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07004933 mutex_unlock(&tabla->mbhc_mutex);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004934
4935 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
4936}
4937
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004938static void tabla_codec_shutdown_hs_polling(struct snd_soc_codec *codec)
4939{
4940 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004941
4942 tabla_codec_shutdown_hs_removal_detect(codec);
4943
Joonwoo Park03324832012-03-19 19:36:16 -07004944 mutex_lock(&tabla->mbhc_mutex);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004945 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004946 snd_soc_update_bits(codec, TABLA_A_TX_COM_BIAS, 0xE0, 0x00);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05304947 tabla_codec_disable_clock_block(codec);
4948 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004949 }
4950
4951 tabla->mbhc_polling_active = false;
Joonwoo Park03324832012-03-19 19:36:16 -07004952 mutex_unlock(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004953}
4954
Patrick Lai49efeac2011-11-03 11:01:12 -07004955static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
4956{
4957 struct tabla_priv *tabla = data;
4958 struct snd_soc_codec *codec;
4959
4960 pr_info("%s: received HPHL OCP irq\n", __func__);
4961
4962 if (tabla) {
4963 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004964 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
4965 pr_info("%s: retry\n", __func__);
4966 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4967 0x00);
4968 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
4969 0x10);
4970 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304971 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08004972 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4973 tabla->hphlocp_cnt = 0;
4974 tabla->hph_status |= SND_JACK_OC_HPHL;
4975 if (tabla->headset_jack)
4976 tabla_snd_soc_jack_report(tabla,
4977 tabla->headset_jack,
4978 tabla->hph_status,
4979 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07004980 }
4981 } else {
4982 pr_err("%s: Bad tabla private data\n", __func__);
4983 }
4984
4985 return IRQ_HANDLED;
4986}
4987
4988static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
4989{
4990 struct tabla_priv *tabla = data;
4991 struct snd_soc_codec *codec;
4992
4993 pr_info("%s: received HPHR OCP irq\n", __func__);
4994
4995 if (tabla) {
4996 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08004997 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
4998 pr_info("%s: retry\n", __func__);
4999 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5000 0x00);
5001 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5002 0x10);
5003 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305004 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005005 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5006 tabla->hphrocp_cnt = 0;
5007 tabla->hph_status |= SND_JACK_OC_HPHR;
5008 if (tabla->headset_jack)
5009 tabla_snd_soc_jack_report(tabla,
5010 tabla->headset_jack,
5011 tabla->hph_status,
5012 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005013 }
5014 } else {
5015 pr_err("%s: Bad tabla private data\n", __func__);
5016 }
5017
5018 return IRQ_HANDLED;
5019}
5020
Joonwoo Parka9444452011-12-08 18:48:27 -08005021static void tabla_sync_hph_state(struct tabla_priv *tabla)
5022{
5023 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305024 &tabla->hph_pa_dac_state)) {
Joonwoo Parka9444452011-12-08 18:48:27 -08005025 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
5026 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
5027 1 << 4);
5028 }
5029 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305030 &tabla->hph_pa_dac_state)) {
Joonwoo Parka9444452011-12-08 18:48:27 -08005031 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
5032 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
5033 1 << 5);
5034 }
5035
5036 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305037 &tabla->hph_pa_dac_state)) {
Joonwoo Parka9444452011-12-08 18:48:27 -08005038 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
5039 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
5040 0xC0, 0xC0);
5041 }
5042 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305043 &tabla->hph_pa_dac_state)) {
Joonwoo Parka9444452011-12-08 18:48:27 -08005044 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
5045 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
5046 0xC0, 0xC0);
5047 }
5048}
5049
Joonwoo Park03324832012-03-19 19:36:16 -07005050static bool mbhc_is_fake_insertion(struct snd_soc_codec *codec, s32 mic_volt)
5051{
5052 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5053 struct tabla_mbhc_plug_type_cfg *plug_type =
5054 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
5055
5056 if (mic_volt > plug_type->v_hs_max ||
5057 (mic_volt < TABLA_MBHC_FAKE_INSERT_HIGH &&
5058 mic_volt > TABLA_MBHC_FAKE_INSERT_LOW))
5059 return true;
5060
5061 return false;
5062}
5063
5064static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
5065{
5066 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5067 const struct tabla_mbhc_plug_detect_cfg *plug_det =
5068 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->calibration);
5069 int ldo_h_on, micb_cfilt_on, i;
5070 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5071 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5072 u8 plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5073 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
5074
5075 ldo_h_on = snd_soc_read(codec, TABLA_A_LDO_H_MODE_1) & 0x80;
5076 micb_cfilt_on = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl) &
5077 0x80;
5078
5079 /* Turn on the override */
5080 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
5081
5082 if (plug_det->t_ins_complete > 20)
5083 msleep(plug_det->t_ins_complete);
5084 else
5085 usleep_range(plug_det->t_ins_complete * 1000,
5086 plug_det->t_ins_complete * 1000);
5087
5088 /*
5089 * First DCE measurement,
5090 * IF this is fake, discontinue detection
5091 * and restart insertion detection
5092 */
5093 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5094 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
5095 if (mbhc_is_fake_insertion(codec, mic_mv[0])) {
5096 pr_debug("%s: Detect attempt 1, detected Fake\n", __func__);
5097 tabla_codec_shutdown_hs_polling(codec);
5098 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5099 false);
5100 return;
5101 }
5102 pr_debug("%s: Run 1, DCE %x, mic_mv = %d\n", __func__, mb_v[0],
5103 mic_mv[0]);
5104
5105 /*
5106 * Perform two more DCE measurements,
5107 * IF any of them is fake, discontinue detection
5108 * and restart insertion detection
5109 */
5110 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x00);
5111 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5112 mb_v[i] = tabla_codec_sta_dce(codec, 1);
5113 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5114 pr_debug("%s: Run %d, DCE %x, mic_mv = %d\n", __func__, i + 1,
5115 mb_v[1], mic_mv[i]);
5116 if (mbhc_is_fake_insertion(codec, mic_mv[i])) {
5117 pr_debug("%s: Detect attempt %d, detected Fake\n",
5118 __func__, i + 1);
5119 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
5120 0x02, 0x02);
5121 tabla_codec_shutdown_hs_polling(codec);
5122 tabla_codec_enable_hs_detect(codec, 1,
5123 MBHC_USE_MB_TRIGGER,
5124 false);
5125 return;
5126 }
5127 }
5128 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
5129
5130 plug_type_ptr = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->calibration);
5131
5132 /*
5133 * If we are here, means none of the three
5134 * measurements are fake, continue plug type detection.
5135 * If all three measurements do not produce same
5136 * plug type, restart insertion detection
5137 */
5138 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5139 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
5140 plug_type[i] = PLUG_TYPE_HEADPHONE;
5141 pr_debug("%s: Detect attempt %d, detected Headphone\n",
5142 __func__, i);
5143 } else {
5144 plug_type[i] = PLUG_TYPE_HEADSET;
5145 pr_debug("%s: Detect attempt %d, detected Headset\n",
5146 __func__, i);
5147 }
5148
5149 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
5150 pr_err("%s: Detect attempt %d and %d are not same",
5151 __func__, i - 1, i);
5152 tabla_codec_shutdown_hs_polling(codec);
5153 tabla_codec_enable_hs_detect(codec, 1,
5154 MBHC_USE_MB_TRIGGER,
5155 false);
5156 return;
5157 }
5158 }
5159
5160 if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5161 pr_debug("%s: Headphone Detected\n", __func__);
5162 tabla->hph_status |= SND_JACK_HEADPHONE;
5163 if (tabla->headset_jack) {
5164 pr_debug("%s: Reporting insertion %d\n", __func__,
5165 SND_JACK_HEADPHONE);
5166 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
5167 tabla->hph_status,
5168 TABLA_JACK_MASK);
5169 }
5170 tabla_codec_shutdown_hs_polling(codec);
5171 tabla_codec_enable_hs_detect(codec, 0, 0, false);
5172 tabla_sync_hph_state(tabla);
5173 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
5174 pr_debug("%s: Headset detected\n", __func__);
5175 tabla->hph_status |= SND_JACK_HEADSET;
5176 if (tabla->headset_jack) {
5177 pr_err("%s: Reporting insertion %d\n", __func__,
5178 SND_JACK_HEADSET);
5179 tabla_snd_soc_jack_report(tabla, tabla->headset_jack,
5180 tabla->hph_status,
5181 TABLA_JACK_MASK);
5182 }
5183 /* avoid false button press detect */
5184 msleep(50);
5185 mutex_lock(&tabla->mbhc_mutex);
5186 tabla_codec_start_hs_polling(codec);
5187 mutex_unlock(&tabla->mbhc_mutex);
5188 tabla_sync_hph_state(tabla);
5189 }
5190}
5191
Bradley Rubincb1e2732011-06-23 16:49:20 -07005192static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
5193{
5194 struct tabla_priv *priv = data;
5195 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park03324832012-03-19 19:36:16 -07005196 u8 is_removal, is_mb_trigger;
5197 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
5198 int ret;
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07005199
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005200 pr_debug("%s: enter\n", __func__);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305201 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005202
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005203 is_removal = snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02;
5204 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
5205
Joonwoo Park03324832012-03-19 19:36:16 -07005206 is_mb_trigger = snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
5207 0x10;
5208
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005209 /* Turn off both HPH and MIC line schmitt triggers */
Joonwoo Park0976d012011-12-22 11:48:18 -08005210 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005211 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Joonwoo Park03324832012-03-19 19:36:16 -07005212 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005213
5214 if (is_removal) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005215 /*
5216 * If headphone is removed while playback is in progress,
5217 * it is possible that micbias will be switched to VDDIO.
5218 */
Joonwoo Park03324832012-03-19 19:36:16 -07005219 tabla_codec_switch_micbias(codec, 0);
Patrick Lai72aa4da2011-12-08 12:38:18 -08005220 priv->hph_status &= ~SND_JACK_HEADPHONE;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005221 if (priv->headset_jack) {
5222 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005223 tabla_snd_soc_jack_report(priv, priv->headset_jack,
5224 priv->hph_status,
5225 TABLA_JACK_MASK);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005226 }
Joonwoo Park03324832012-03-19 19:36:16 -07005227
5228 hphocp_off_report(priv, SND_JACK_OC_HPHR,
5229 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5230 hphocp_off_report(priv, SND_JACK_OC_HPHL,
5231 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5232
Bradley Rubincb1e2732011-06-23 16:49:20 -07005233 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005234 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5235 true);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005236 return IRQ_HANDLED;
5237 }
5238
Joonwoo Park03324832012-03-19 19:36:16 -07005239 if (is_mb_trigger && !is_removal) {
5240 pr_debug("%s: Waiting for Headphone left trigger\n",
5241 __func__);
5242 wcd9xxx_lock_sleep(core);
5243 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
5244 usecs_to_jiffies(1000000)) == 0) {
5245 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
5246 __func__);
5247 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005248 }
Joonwoo Park03324832012-03-19 19:36:16 -07005249 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
5250 false);
5251 return IRQ_HANDLED;
5252 }
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08005253
Joonwoo Park03324832012-03-19 19:36:16 -07005254 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
5255 if (ret != 0) {
5256 pr_debug("%s: Complete plug insertion, Detecting plug type\n",
5257 __func__);
5258 tabla_codec_detect_plug_type(codec);
5259 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07005260 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005261 wcd9xxx_enable_irq(codec->control_data,
5262 TABLA_IRQ_MBHC_INSERTION);
5263 pr_err("%s: Error detecting plug insertion\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005264 }
5265
5266 return IRQ_HANDLED;
5267}
5268
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005269static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
5270{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005271 short bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005272 struct tabla_priv *priv = data;
5273 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08005274 const struct tabla_mbhc_general_cfg *generic =
5275 TABLA_MBHC_CAL_GENERAL_PTR(priv->calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005276 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Joonwoo Park03324832012-03-19 19:36:16 -07005277 int fake_removal = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005278
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005279 pr_debug("%s: enter, removal interrupt\n", __func__);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305280 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
5281 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
5282 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005283
Joonwoo Park0976d012011-12-22 11:48:18 -08005284 usleep_range(generic->t_shutdown_plug_rem,
5285 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005286
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005287 do {
Joonwoo Park03324832012-03-19 19:36:16 -07005288 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x00);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005289 bias_value = tabla_codec_sta_dce(codec, 1);
Joonwoo Park03324832012-03-19 19:36:16 -07005290 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005291 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
5292 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
5293 if (bias_value < (short)priv->mbhc_data.v_ins_h) {
5294 fake_removal = 1;
5295 break;
5296 }
5297 min_us -= priv->mbhc_data.t_dce;
5298 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005299
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005300 if (fake_removal) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005301 pr_debug("False alarm, headset not actually removed\n");
Joonwoo Park03324832012-03-19 19:36:16 -07005302 mutex_lock(&priv->mbhc_mutex);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005303 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005304 mutex_unlock(&priv->mbhc_mutex);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005305 } else {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005306 /*
5307 * If this removal is not false, first check the micbias
5308 * switch status and switch it to LDOH if it is already
5309 * switched to VDDIO.
5310 */
Joonwoo Park03324832012-03-19 19:36:16 -07005311 tabla_codec_switch_micbias(codec, 0);
Patrick Lai49efeac2011-11-03 11:01:12 -07005312 priv->hph_status &= ~SND_JACK_HEADSET;
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005313 if (priv->headset_jack) {
5314 pr_debug("%s: Reporting removal\n", __func__);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005315 tabla_snd_soc_jack_report(priv, priv->headset_jack, 0,
5316 TABLA_JACK_MASK);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005317 }
Joonwoo Park03324832012-03-19 19:36:16 -07005318
5319 hphocp_off_report(priv, SND_JACK_OC_HPHR,
5320 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5321 hphocp_off_report(priv, SND_JACK_OC_HPHL,
5322 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5323
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005324 tabla_codec_shutdown_hs_polling(codec);
5325
Joonwoo Park03324832012-03-19 19:36:16 -07005326 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5327 true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005328 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005330 return IRQ_HANDLED;
5331}
5332
Joonwoo Park03324832012-03-19 19:36:16 -07005333void mbhc_insert_work(struct work_struct *work)
5334{
5335 struct delayed_work *dwork;
5336 struct tabla_priv *tabla;
5337 struct snd_soc_codec *codec;
5338 struct wcd9xxx *tabla_core;
5339
5340 dwork = to_delayed_work(work);
5341 tabla = container_of(dwork, struct tabla_priv,
5342 mbhc_insert_dwork);
5343 codec = tabla->codec;
5344 tabla_core = dev_get_drvdata(codec->dev->parent);
5345
5346 pr_debug("%s:\n", __func__);
5347
5348 /* Turn off both HPH and MIC line schmitt triggers */
5349 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5350 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
5351 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5352 wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
5353 tabla_codec_detect_plug_type(codec);
5354 wcd9xxx_unlock_sleep(tabla_core);
5355}
5356
5357int tabla_hs_detect(struct snd_soc_codec *codec,
5358 struct snd_soc_jack *headset_jack,
5359 struct snd_soc_jack *button_jack,
5360 void *calibration, enum tabla_micbias_num micbias,
5361 int (*mclk_cb_fn) (struct snd_soc_codec*, int),
5362 int read_fw_bin, u32 mclk_rate)
5363{
5364 struct tabla_priv *tabla;
5365 int rc = 0;
5366
5367 if (!codec || !calibration) {
5368 pr_err("Error: no codec or calibration\n");
5369 return -EINVAL;
5370 }
5371
5372 if (mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
5373 if (mclk_rate == TABLA_MCLK_RATE_9600KHZ)
5374 pr_err("Error: clock rate %dHz is not yet supported\n",
5375 mclk_rate);
5376 else
5377 pr_err("Error: unsupported clock rate %d\n", mclk_rate);
5378 return -EINVAL;
5379 }
5380
5381 tabla = snd_soc_codec_get_drvdata(codec);
5382 tabla->headset_jack = headset_jack;
5383 tabla->button_jack = button_jack;
5384 tabla->micbias = micbias;
5385 tabla->calibration = calibration;
5386 tabla->mclk_cb = mclk_cb_fn;
5387 tabla->mclk_freq = mclk_rate;
5388 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
5389
5390 /* Put CFILT in fast mode by default */
5391 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
5392 0x40, TABLA_CFILT_FAST_MODE);
5393 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
5394 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
5395 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
5396 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
5397 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
5398
5399 if (!read_fw_bin) {
5400 tabla->mclk_cb(codec, 1);
5401 tabla_mbhc_init(codec);
5402 tabla_mbhc_cal(codec);
5403 tabla_mbhc_calc_thres(codec);
5404 tabla->mclk_cb(codec, 0);
5405 tabla_codec_calibrate_hs_polling(codec);
5406 rc = tabla_codec_enable_hs_detect(codec, 1,
5407 MBHC_USE_MB_TRIGGER, false);
5408 } else {
5409 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
5410 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
5411 }
5412
5413 if (!IS_ERR_VALUE(rc)) {
5414 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
5415 wcd9xxx_enable_irq(codec->control_data,
5416 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5417 wcd9xxx_enable_irq(codec->control_data,
5418 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5419 }
5420
5421 return rc;
5422}
5423EXPORT_SYMBOL_GPL(tabla_hs_detect);
5424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005425static unsigned long slimbus_value;
5426
5427static irqreturn_t tabla_slimbus_irq(int irq, void *data)
5428{
5429 struct tabla_priv *priv = data;
5430 struct snd_soc_codec *codec = priv->codec;
5431 int i, j;
5432 u8 val;
5433
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305434 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
5435 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005436 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
5437 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305438 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005439 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
5440 if (val & 0x1)
5441 pr_err_ratelimited("overflow error on port %x,"
5442 " value %x\n", i*8 + j, val);
5443 if (val & 0x2)
5444 pr_err_ratelimited("underflow error on port %x,"
5445 " value %x\n", i*8 + j, val);
5446 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305447 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005448 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
5449 }
5450
5451 return IRQ_HANDLED;
5452}
5453
Patrick Lai3043fba2011-08-01 14:15:57 -07005454
5455static int tabla_handle_pdata(struct tabla_priv *tabla)
5456{
5457 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305458 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07005459 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05305460 u8 leg_mode = pdata->amic_settings.legacy_mode;
5461 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
5462 u8 txfe_buff = pdata->amic_settings.txfe_buff;
5463 u8 flag = pdata->amic_settings.use_pdata;
5464 u8 i = 0, j = 0;
5465 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07005466
5467 if (!pdata) {
5468 rc = -ENODEV;
5469 goto done;
5470 }
5471
5472 /* Make sure settings are correct */
5473 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
5474 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
5475 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
5476 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
5477 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
5478 rc = -EINVAL;
5479 goto done;
5480 }
5481
5482 /* figure out k value */
5483 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
5484 pdata->micbias.cfilt1_mv);
5485 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
5486 pdata->micbias.cfilt2_mv);
5487 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
5488 pdata->micbias.cfilt3_mv);
5489
5490 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
5491 rc = -EINVAL;
5492 goto done;
5493 }
5494
5495 /* Set voltage level and always use LDO */
5496 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
5497 (pdata->micbias.ldoh_v << 2));
5498
5499 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
5500 (k1 << 2));
5501 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
5502 (k2 << 2));
5503 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
5504 (k3 << 2));
5505
5506 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
5507 (pdata->micbias.bias1_cfilt_sel << 5));
5508 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
5509 (pdata->micbias.bias2_cfilt_sel << 5));
5510 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
5511 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005512 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
5513 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07005514
Santosh Mardi22920282011-10-26 02:38:40 +05305515 for (i = 0; i < 6; j++, i += 2) {
5516 if (flag & (0x01 << i)) {
5517 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
5518 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
5519 val_txfe = val_txfe |
5520 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
5521 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
5522 0x10, value);
5523 snd_soc_update_bits(codec,
5524 TABLA_A_TX_1_2_TEST_EN + j * 10,
5525 0x30, val_txfe);
5526 }
5527 if (flag & (0x01 << (i + 1))) {
5528 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
5529 val_txfe = (txfe_bypass &
5530 (0x01 << (i + 1))) ? 0x02 : 0x00;
5531 val_txfe |= (txfe_buff &
5532 (0x01 << (i + 1))) ? 0x01 : 0x00;
5533 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
5534 0x01, value);
5535 snd_soc_update_bits(codec,
5536 TABLA_A_TX_1_2_TEST_EN + j * 10,
5537 0x03, val_txfe);
5538 }
5539 }
5540 if (flag & 0x40) {
5541 value = (leg_mode & 0x40) ? 0x10 : 0x00;
5542 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
5543 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
5544 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
5545 0x13, value);
5546 }
Patrick Lai49efeac2011-11-03 11:01:12 -07005547
5548 if (pdata->ocp.use_pdata) {
5549 /* not defined in CODEC specification */
5550 if (pdata->ocp.hph_ocp_limit == 1 ||
5551 pdata->ocp.hph_ocp_limit == 5) {
5552 rc = -EINVAL;
5553 goto done;
5554 }
5555 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
5556 0x0F, pdata->ocp.num_attempts);
5557 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
5558 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
5559 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
5560 0xE0, (pdata->ocp.hph_ocp_limit << 5));
5561 }
Joonwoo Park03324832012-03-19 19:36:16 -07005562
5563 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
5564 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
5565 if (pdata->regulator[i].min_uV == 1800000 &&
5566 pdata->regulator[i].max_uV == 1800000) {
5567 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
5568 0x1C);
5569 } else if (pdata->regulator[i].min_uV == 2200000 &&
5570 pdata->regulator[i].max_uV == 2200000) {
5571 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
5572 0x1E);
5573 } else {
5574 pr_err("%s: unsupported CDC_VDDA_RX voltage "
5575 "min %d, max %d\n", __func__,
5576 pdata->regulator[i].min_uV,
5577 pdata->regulator[i].max_uV);
5578 rc = -EINVAL;
5579 }
5580 break;
5581 }
5582 }
Patrick Lai3043fba2011-08-01 14:15:57 -07005583done:
5584 return rc;
5585}
5586
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005587static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
5588
5589 /* Tabla 1.1 MICBIAS changes */
5590 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
5591 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
5592 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005593
5594 /* Tabla 1.1 HPH changes */
5595 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
5596 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
5597
5598 /* Tabla 1.1 EAR PA changes */
5599 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
5600 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
5601 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
5602
5603 /* Tabla 1.1 Lineout_5 Changes */
5604 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
5605
5606 /* Tabla 1.1 RX Changes */
5607 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
5608 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
5609 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
5610 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
5611 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
5612 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
5613 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
5614
5615 /* Tabla 1.1 RX1 and RX2 Changes */
5616 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
5617 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
5618
5619 /* Tabla 1.1 RX3 to RX7 Changes */
5620 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
5621 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
5622 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
5623 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
5624 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
5625
5626 /* Tabla 1.1 CLASSG Changes */
5627 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
5628};
5629
5630static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005631 /* Tabla 2.0 MICBIAS changes */
5632 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
5633};
5634
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005635static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
5636 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
5637};
5638
5639static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
5640 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
5641};
5642
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005643static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
5644{
5645 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305646 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005647
5648 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
5649 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
5650 tabla_1_1_reg_defaults[i].val);
5651
5652 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
5653 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
5654 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005655
5656 if (TABLA_IS_1_X(tabla_core->version)) {
5657 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
5658 i++)
5659 snd_soc_write(codec,
5660 tabla_1_x_only_reg_2_0_defaults[i].reg,
5661 tabla_1_x_only_reg_2_0_defaults[i].val);
5662 } else {
5663 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
5664 snd_soc_write(codec,
5665 tabla_2_only_reg_2_0_defaults[i].reg,
5666 tabla_2_only_reg_2_0_defaults[i].val);
5667 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005668}
5669
5670static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08005671 /* Initialize current threshold to 350MA
5672 * number of wait and run cycles to 4096
5673 */
Patrick Lai49efeac2011-11-03 11:01:12 -07005674 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08005675 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005676
Santosh Mardi32171012011-10-28 23:32:06 +05305677 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
5678
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005679 /* Initialize gain registers to use register gain */
5680 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
5681 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
5682 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
5683 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
5684 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
5685 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
5686
5687 /* Initialize mic biases to differential mode */
5688 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
5689 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
5690 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005691
5692 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
5693
5694 /* Use 16 bit sample size for TX1 to TX6 */
5695 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
5696 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
5697 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
5698 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
5699 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
5700 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
5701
5702 /* Use 16 bit sample size for TX7 to TX10 */
5703 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
5704 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
5705 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
5706 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
5707
5708 /* Use 16 bit sample size for RX */
5709 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
5710 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
5711
5712 /*enable HPF filter for TX paths */
5713 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
5714 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
5715 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
5716 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
5717 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
5718 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
5719 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
5720 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
5721 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
5722 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
5723};
5724
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005725static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
5726 /* Initialize mic biases to differential mode */
5727 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
5728};
5729
5730static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
5731 /* Initialize mic biases to differential mode */
5732 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
5733};
5734
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005735static void tabla_codec_init_reg(struct snd_soc_codec *codec)
5736{
5737 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305738 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005739
5740 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
5741 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
5742 tabla_codec_reg_init_val[i].mask,
5743 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005744 if (TABLA_IS_1_X(tabla_core->version)) {
5745 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
5746 snd_soc_update_bits(codec,
5747 tabla_1_x_codec_reg_init_val[i].reg,
5748 tabla_1_x_codec_reg_init_val[i].mask,
5749 tabla_1_x_codec_reg_init_val[i].val);
5750 } else {
5751 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
5752 i++)
5753 snd_soc_update_bits(codec,
5754 tabla_2_higher_codec_reg_init_val[i].reg,
5755 tabla_2_higher_codec_reg_init_val[i].mask,
5756 tabla_2_higher_codec_reg_init_val[i].val);
5757 }
5758}
5759
5760static void tabla_update_reg_address(struct tabla_priv *priv)
5761{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305762 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005763 struct tabla_reg_address *reg_addr = &priv->reg_addr;
5764
5765 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08005766 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
5767 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005768 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005769 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08005770 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
5771 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005772 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005773 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07005774}
5775
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005776static int tabla_codec_probe(struct snd_soc_codec *codec)
5777{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305778 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005779 struct tabla_priv *tabla;
5780 struct snd_soc_dapm_context *dapm = &codec->dapm;
5781 int ret = 0;
5782 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005783 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005784
5785 codec->control_data = dev_get_drvdata(codec->dev->parent);
5786 control = codec->control_data;
5787
5788 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
5789 if (!tabla) {
5790 dev_err(codec->dev, "Failed to allocate private data\n");
5791 return -ENOMEM;
5792 }
5793
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07005794 /* Make sure mbhc micbias register addresses are zeroed out */
5795 memset(&tabla->mbhc_bias_regs, 0,
5796 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005797 tabla->cfilt_k_value = 0;
5798 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07005799
Joonwoo Park0976d012011-12-22 11:48:18 -08005800 /* Make sure mbhc intenal calibration data is zeroed out */
5801 memset(&tabla->mbhc_data, 0,
5802 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08005803 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08005804 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
5805 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005806 snd_soc_codec_set_drvdata(codec, tabla);
5807
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005808 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005809 tabla->bandgap_type = TABLA_BANDGAP_OFF;
5810 tabla->clock_active = false;
5811 tabla->config_mode_active = false;
5812 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005813 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07005814 tabla->no_mic_headset_override = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005815 tabla->codec = codec;
Joonwoo Park03324832012-03-19 19:36:16 -07005816 mutex_init(&tabla->mbhc_mutex);
5817 tabla->mbhc_state = -1;
5818 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08005819 for (i = 0; i < COMPANDER_MAX; i++) {
5820 tabla->comp_enabled[i] = 0;
5821 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
5822 }
Patrick Lai3043fba2011-08-01 14:15:57 -07005823 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305824 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08005825 tabla->aux_pga_cnt = 0;
5826 tabla->aux_l_gain = 0x1F;
5827 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005828 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05305829 tabla_update_reg_defaults(codec);
5830 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05305831 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07005832 if (IS_ERR_VALUE(ret)) {
5833 pr_err("%s: bad pdata\n", __func__);
5834 goto err_pdata;
5835 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005836
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005837 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005838 ARRAY_SIZE(tabla_snd_controls));
5839 if (TABLA_IS_1_X(control->version))
5840 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
5841 ARRAY_SIZE(tabla_1_x_snd_controls));
5842 else
5843 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
5844 ARRAY_SIZE(tabla_2_higher_snd_controls));
5845
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005846 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005847 ARRAY_SIZE(tabla_dapm_widgets));
5848 if (TABLA_IS_1_X(control->version))
5849 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
5850 ARRAY_SIZE(tabla_1_x_dapm_widgets));
5851 else
5852 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
5853 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
5854
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305855 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05305856 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
5857 ARRAY_SIZE(tabla_dapm_i2s_widgets));
5858 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
5859 ARRAY_SIZE(audio_i2s_map));
5860 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005861 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07005862
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005863 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08005864 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005865 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
5866 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08005867 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005868 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08005869 } else {
5870 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305871 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08005872 goto err_pdata;
5873 }
5874
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005875 snd_soc_dapm_sync(dapm);
5876
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305877 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005878 tabla_hs_insert_irq, "Headset insert detect", tabla);
5879 if (ret) {
5880 pr_err("%s: Failed to request irq %d\n", __func__,
5881 TABLA_IRQ_MBHC_INSERTION);
5882 goto err_insert_irq;
5883 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305884 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005885
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305886 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005887 tabla_hs_remove_irq, "Headset remove detect", tabla);
5888 if (ret) {
5889 pr_err("%s: Failed to request irq %d\n", __func__,
5890 TABLA_IRQ_MBHC_REMOVAL);
5891 goto err_remove_irq;
5892 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305893 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005894
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305895 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07005896 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005897 if (ret) {
5898 pr_err("%s: Failed to request irq %d\n", __func__,
5899 TABLA_IRQ_MBHC_POTENTIAL);
5900 goto err_potential_irq;
5901 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305902 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005903
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305904 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07005905 tabla_release_handler, "Button Release detect", tabla);
5906 if (ret) {
5907 pr_err("%s: Failed to request irq %d\n", __func__,
5908 TABLA_IRQ_MBHC_RELEASE);
5909 goto err_release_irq;
5910 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305911 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005912
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305913 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005914 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
5915 if (ret) {
5916 pr_err("%s: Failed to request irq %d\n", __func__,
5917 TABLA_IRQ_SLIMBUS);
5918 goto err_slimbus_irq;
5919 }
5920
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305921 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
5922 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005923 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
5924
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305925 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07005926 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
5927 "HPH_L OCP detect", tabla);
5928 if (ret) {
5929 pr_err("%s: Failed to request irq %d\n", __func__,
5930 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5931 goto err_hphl_ocp_irq;
5932 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305933 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07005934
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305935 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07005936 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
5937 "HPH_R OCP detect", tabla);
5938 if (ret) {
5939 pr_err("%s: Failed to request irq %d\n", __func__,
5940 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5941 goto err_hphr_ocp_irq;
5942 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305943 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005944 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
5945 switch (tabla_dai[i].id) {
5946 case AIF1_PB:
5947 ch_cnt = tabla_dai[i].playback.channels_max;
5948 break;
5949 case AIF1_CAP:
5950 ch_cnt = tabla_dai[i].capture.channels_max;
5951 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08005952 case AIF2_PB:
5953 ch_cnt = tabla_dai[i].playback.channels_max;
5954 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005955 default:
5956 continue;
5957 }
5958 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
5959 ch_cnt), GFP_KERNEL);
5960 }
Patrick Lai49efeac2011-11-03 11:01:12 -07005961
Bradley Rubincb3950a2011-08-18 13:07:26 -07005962#ifdef CONFIG_DEBUG_FS
5963 debug_tabla_priv = tabla;
5964#endif
5965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005966 return ret;
5967
Patrick Lai49efeac2011-11-03 11:01:12 -07005968err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305969 wcd9xxx_free_irq(codec->control_data,
5970 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07005971err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305972 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005973err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305974 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005975err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305976 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005977err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305978 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005979err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305980 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005981err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07005982err_pdata:
Joonwoo Park03324832012-03-19 19:36:16 -07005983 mutex_destroy(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005984 kfree(tabla);
5985 return ret;
5986}
5987static int tabla_codec_remove(struct snd_soc_codec *codec)
5988{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005989 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005990 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305991 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
5992 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
5993 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
5994 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
5995 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Joonwoo Park03324832012-03-19 19:36:16 -07005996 mutex_lock(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005997 tabla_codec_disable_clock_block(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005998 mutex_unlock(&tabla->mbhc_mutex);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005999 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08006000 if (tabla->mbhc_fw)
6001 release_firmware(tabla->mbhc_fw);
Joonwoo Park03324832012-03-19 19:36:16 -07006002 mutex_destroy(&tabla->mbhc_mutex);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006003 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
6004 kfree(tabla->dai[i].ch_num);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006005 kfree(tabla);
6006 return 0;
6007}
6008static struct snd_soc_codec_driver soc_codec_dev_tabla = {
6009 .probe = tabla_codec_probe,
6010 .remove = tabla_codec_remove,
6011 .read = tabla_read,
6012 .write = tabla_write,
6013
6014 .readable_register = tabla_readable,
6015 .volatile_register = tabla_volatile,
6016
6017 .reg_cache_size = TABLA_CACHE_SIZE,
6018 .reg_cache_default = tabla_reg_defaults,
6019 .reg_word_size = 1,
6020};
Bradley Rubincb3950a2011-08-18 13:07:26 -07006021
6022#ifdef CONFIG_DEBUG_FS
6023static struct dentry *debugfs_poke;
6024
6025static int codec_debug_open(struct inode *inode, struct file *file)
6026{
6027 file->private_data = inode->i_private;
6028 return 0;
6029}
6030
6031static ssize_t codec_debug_write(struct file *filp,
6032 const char __user *ubuf, size_t cnt, loff_t *ppos)
6033{
6034 char lbuf[32];
6035 char *buf;
6036 int rc;
6037
6038 if (cnt > sizeof(lbuf) - 1)
6039 return -EINVAL;
6040
6041 rc = copy_from_user(lbuf, ubuf, cnt);
6042 if (rc)
6043 return -EFAULT;
6044
6045 lbuf[cnt] = '\0';
6046 buf = (char *)lbuf;
6047 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
6048 ? false : true;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006049 return rc;
6050}
6051
6052static const struct file_operations codec_debug_ops = {
6053 .open = codec_debug_open,
6054 .write = codec_debug_write,
6055};
6056#endif
6057
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006058#ifdef CONFIG_PM
6059static int tabla_suspend(struct device *dev)
6060{
Joonwoo Park816b8e62012-01-23 16:03:21 -08006061 dev_dbg(dev, "%s: system suspend\n", __func__);
6062 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006063}
6064
6065static int tabla_resume(struct device *dev)
6066{
Joonwoo Park03324832012-03-19 19:36:16 -07006067 struct platform_device *pdev = to_platform_device(dev);
6068 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Park816b8e62012-01-23 16:03:21 -08006069 dev_dbg(dev, "%s: system resume\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07006070 tabla->mbhc_last_resume = jiffies;
Joonwoo Park816b8e62012-01-23 16:03:21 -08006071 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006072}
6073
6074static const struct dev_pm_ops tabla_pm_ops = {
6075 .suspend = tabla_suspend,
6076 .resume = tabla_resume,
6077};
6078#endif
6079
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006080static int __devinit tabla_probe(struct platform_device *pdev)
6081{
Santosh Mardie15e2302011-11-15 10:39:23 +05306082 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006083#ifdef CONFIG_DEBUG_FS
6084 debugfs_poke = debugfs_create_file("TRRS",
6085 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
6086
6087#endif
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306088 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05306089 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
6090 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306091 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05306092 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
6093 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
6094 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006095}
6096static int __devexit tabla_remove(struct platform_device *pdev)
6097{
6098 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07006099
6100#ifdef CONFIG_DEBUG_FS
6101 debugfs_remove(debugfs_poke);
6102#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006103 return 0;
6104}
6105static struct platform_driver tabla_codec_driver = {
6106 .probe = tabla_probe,
6107 .remove = tabla_remove,
6108 .driver = {
6109 .name = "tabla_codec",
6110 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006111#ifdef CONFIG_PM
6112 .pm = &tabla_pm_ops,
6113#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006114 },
6115};
6116
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006117static struct platform_driver tabla1x_codec_driver = {
6118 .probe = tabla_probe,
6119 .remove = tabla_remove,
6120 .driver = {
6121 .name = "tabla1x_codec",
6122 .owner = THIS_MODULE,
6123#ifdef CONFIG_PM
6124 .pm = &tabla_pm_ops,
6125#endif
6126 },
6127};
6128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006129static int __init tabla_codec_init(void)
6130{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006131 int rtn = platform_driver_register(&tabla_codec_driver);
6132 if (rtn == 0) {
6133 rtn = platform_driver_register(&tabla1x_codec_driver);
6134 if (rtn != 0)
6135 platform_driver_unregister(&tabla_codec_driver);
6136 }
6137 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006138}
6139
6140static void __exit tabla_codec_exit(void)
6141{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006142 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006143 platform_driver_unregister(&tabla_codec_driver);
6144}
6145
6146module_init(tabla_codec_init);
6147module_exit(tabla_codec_exit);
6148
6149MODULE_DESCRIPTION("Tabla codec driver");
6150MODULE_VERSION("1.0");
6151MODULE_LICENSE("GPL v2");