blob: 74e2dc0aaa5993e3b8afe067fdec8a5061cbe4bf [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>
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070033#include <linux/kernel.h>
34#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#include "wcd9310.h"
36
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070037#define WCD9310_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
38 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
39
40#define NUM_DECIMATORS 10
41#define NUM_INTERPOLATORS 7
42#define BITS_PER_REG 8
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080043#define TABLA_CFILT_FAST_MODE 0x00
44#define TABLA_CFILT_SLOW_MODE 0x40
Patrick Lai64b43262011-12-06 17:29:15 -080045#define MBHC_FW_READ_ATTEMPTS 15
46#define MBHC_FW_READ_TIMEOUT 2000000
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070047
Joonwoo Park03324832012-03-19 19:36:16 -070048enum {
49 MBHC_USE_HPHL_TRIGGER = 1,
50 MBHC_USE_MB_TRIGGER = 2
51};
52
53#define MBHC_NUM_DCE_PLUG_DETECT 3
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070054#define NUM_ATTEMPTS_INSERT_DETECT 25
55#define NUM_ATTEMPTS_TO_REPORT 5
Joonwoo Park03324832012-03-19 19:36:16 -070056
Patrick Lai49efeac2011-11-03 11:01:12 -070057#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
58
Santosh Mardie15e2302011-11-15 10:39:23 +053059#define TABLA_I2S_MASTER_MODE_MASK 0x08
60
Patrick Laic7cae882011-11-18 11:52:49 -080061#define TABLA_OCP_ATTEMPT 1
62
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080063#define AIF1_PB 1
64#define AIF1_CAP 2
Neema Shettyd3a89262012-02-16 10:23:50 -080065#define AIF2_PB 3
66#define NUM_CODEC_DAIS 3
Kuirong Wang0f8ade32012-02-27 16:29:45 -080067#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080068
69struct tabla_codec_dai_data {
70 u32 rate;
71 u32 *ch_num;
72 u32 ch_act;
73 u32 ch_tot;
74};
75
Joonwoo Park0976d012011-12-22 11:48:18 -080076#define TABLA_MCLK_RATE_12288KHZ 12288000
77#define TABLA_MCLK_RATE_9600KHZ 9600000
78
Joonwoo Parkf4267c22012-01-10 13:25:24 -080079#define TABLA_FAKE_INS_THRESHOLD_MS 2500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -080080#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
Joonwoo Parkf4267c22012-01-10 13:25:24 -080081
Joonwoo Park03324832012-03-19 19:36:16 -070082#define TABLA_MBHC_BUTTON_MIN 0x8000
83
Joonwoo Park03324832012-03-19 19:36:16 -070084#define TABLA_MBHC_FAKE_INSERT_LOW 10
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070085#define TABLA_MBHC_FAKE_INSERT_HIGH 80
86#define TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO 150
Joonwoo Park03324832012-03-19 19:36:16 -070087
88#define TABLA_MBHC_STATUS_REL_DETECTION 0x0C
89
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070090#define TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
91
92#define TABLA_MBHC_FAKE_INSERT_VOLT_DELTA_MV 200
93
94#define TABLA_HS_DETECT_PLUG_TIME_MS (5 * 1000)
95#define TABLA_HS_DETECT_PLUG_INERVAL_MS 100
96
97#define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
98
99#define TABLA_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
100#define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
101
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700102static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
103static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
104static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800105static struct snd_soc_dai_driver tabla_dai[];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800106static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107
108enum tabla_bandgap_type {
109 TABLA_BANDGAP_OFF = 0,
110 TABLA_BANDGAP_AUDIO_MODE,
111 TABLA_BANDGAP_MBHC_MODE,
112};
113
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700114struct mbhc_micbias_regs {
115 u16 cfilt_val;
116 u16 cfilt_ctl;
117 u16 mbhc_reg;
118 u16 int_rbias;
119 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -0800120 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700121};
122
Ben Romberger1f045a72011-11-04 10:14:57 -0700123/* Codec supports 2 IIR filters */
124enum {
125 IIR1 = 0,
126 IIR2,
127 IIR_MAX,
128};
129/* Codec supports 5 bands */
130enum {
131 BAND1 = 0,
132 BAND2,
133 BAND3,
134 BAND4,
135 BAND5,
136 BAND_MAX,
137};
138
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800139enum {
140 COMPANDER_1 = 0,
141 COMPANDER_2,
142 COMPANDER_MAX,
143};
144
145enum {
146 COMPANDER_FS_8KHZ = 0,
147 COMPANDER_FS_16KHZ,
148 COMPANDER_FS_32KHZ,
149 COMPANDER_FS_48KHZ,
150 COMPANDER_FS_MAX,
151};
152
Joonwoo Parka9444452011-12-08 18:48:27 -0800153/* Flags to track of PA and DAC state.
154 * PA and DAC should be tracked separately as AUXPGA loopback requires
155 * only PA to be turned on without DAC being on. */
156enum tabla_priv_ack_flags {
157 TABLA_HPHL_PA_OFF_ACK = 0,
158 TABLA_HPHR_PA_OFF_ACK,
159 TABLA_HPHL_DAC_OFF_ACK,
160 TABLA_HPHR_DAC_OFF_ACK
161};
162
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800163
164struct comp_sample_dependent_params {
165 u32 peak_det_timeout;
166 u32 rms_meter_div_fact;
167 u32 rms_meter_resamp_fact;
168};
169
Joonwoo Park0976d012011-12-22 11:48:18 -0800170/* Data used by MBHC */
171struct mbhc_internal_cal_data {
172 u16 dce_z;
173 u16 dce_mb;
174 u16 sta_z;
175 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800176 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800177 u32 t_dce;
178 u32 t_sta;
179 u32 micb_mv;
180 u16 v_ins_hu;
181 u16 v_ins_h;
182 u16 v_b1_hu;
183 u16 v_b1_h;
184 u16 v_b1_huc;
185 u16 v_brh;
186 u16 v_brl;
187 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800188 u8 npoll;
189 u8 nbounce_wait;
190};
191
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800192struct tabla_reg_address {
193 u16 micb_4_ctl;
194 u16 micb_4_int_rbias;
195 u16 micb_4_mbhc;
196};
197
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700198enum tabla_mbhc_plug_type {
199 PLUG_TYPE_NONE = 0,
200 PLUG_TYPE_HEADSET,
201 PLUG_TYPE_HEADPHONE,
202 PLUG_TYPE_HIGH_HPH,
203};
204
205enum tabla_mbhc_state {
206 MBHC_STATE_NONE = -1,
207 MBHC_STATE_POTENTIAL,
208 MBHC_STATE_POTENTIAL_RECOVERY,
209 MBHC_STATE_RELEASE,
210};
211
Bradley Rubin229c6a52011-07-12 16:18:48 -0700212struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800214 struct tabla_reg_address reg_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700216 u32 cfilt1_cnt;
217 u32 cfilt2_cnt;
218 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700219 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700221 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222 bool clock_active;
223 bool config_mode_active;
224 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800225 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700226 int buttons_pressed;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700227 enum tabla_mbhc_state mbhc_state;
228 struct tabla_mbhc_config mbhc_cfg;
Joonwoo Park0976d012011-12-22 11:48:18 -0800229 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530231 struct wcd9xxx_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700232 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700233
234 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700235 /* Delayed work to report long button press */
Joonwoo Park03324832012-03-19 19:36:16 -0700236 struct delayed_work mbhc_btn_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700237
238 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700239 u8 cfilt_k_value;
240 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700241
Joonwoo Parka9444452011-12-08 18:48:27 -0800242 /* track PA/DAC state */
243 unsigned long hph_pa_dac_state;
244
Santosh Mardie15e2302011-11-15 10:39:23 +0530245 /*track tabla interface type*/
246 u8 intf_type;
247
Patrick Lai49efeac2011-11-03 11:01:12 -0700248 u32 hph_status; /* track headhpone status */
249 /* define separate work for left and right headphone OCP to avoid
250 * additional checking on which OCP event to report so no locking
251 * to ensure synchronization is required
252 */
253 struct work_struct hphlocp_work; /* reporting left hph ocp off */
254 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800255
Patrick Laic7cae882011-11-18 11:52:49 -0800256 u8 hphlocp_cnt; /* headphone left ocp retry */
257 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800258
Patrick Lai64b43262011-12-06 17:29:15 -0800259 /* Work to perform MBHC Firmware Read */
260 struct delayed_work mbhc_firmware_dwork;
261 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800262
263 /* num of slim ports required */
264 struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800265
266 /*compander*/
267 int comp_enabled[COMPANDER_MAX];
268 u32 comp_fs[COMPANDER_MAX];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800269
270 /* Maintain the status of AUX PGA */
271 int aux_pga_cnt;
272 u8 aux_l_gain;
273 u8 aux_r_gain;
Joonwoo Park03324832012-03-19 19:36:16 -0700274
Joonwoo Park03324832012-03-19 19:36:16 -0700275 struct delayed_work mbhc_insert_dwork;
276 unsigned long mbhc_last_resume; /* in jiffies */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700277
278 u8 current_plug;
279 struct work_struct hs_correct_plug_work;
280 bool hs_detect_work_stop;
281 bool hs_polling_irq_prepared;
282 bool lpi_enabled; /* low power insertion detection */
283 bool in_gpio_handler;
284 /* Currently, only used for mbhc purpose, to protect
285 * concurrent execution of mbhc threaded irq handlers and
286 * kill race between DAPM and MBHC.But can serve as a
287 * general lock to protect codec resource
288 */
289 struct mutex codec_resource_lock;
290
291 /* Used to override the rule "invalid headset
292 * when microphone voltage is too high"
293 */
294 bool mbhc_inval_hs_range_override;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295};
296
Bradley Rubincb3950a2011-08-18 13:07:26 -0700297#ifdef CONFIG_DEBUG_FS
298struct tabla_priv *debug_tabla_priv;
299#endif
300
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800301static const u32 comp_shift[] = {
302 0,
303 2,
304};
305
306static const int comp_rx_path[] = {
307 COMPANDER_1,
308 COMPANDER_1,
309 COMPANDER_2,
310 COMPANDER_2,
311 COMPANDER_2,
312 COMPANDER_2,
313 COMPANDER_MAX,
314};
315
316static const struct comp_sample_dependent_params comp_samp_params[] = {
317 {
318 .peak_det_timeout = 0x2,
319 .rms_meter_div_fact = 0x8 << 4,
320 .rms_meter_resamp_fact = 0x21,
321 },
322 {
323 .peak_det_timeout = 0x3,
324 .rms_meter_div_fact = 0x9 << 4,
325 .rms_meter_resamp_fact = 0x28,
326 },
327
328 {
329 .peak_det_timeout = 0x5,
330 .rms_meter_div_fact = 0xB << 4,
331 .rms_meter_resamp_fact = 0x28,
332 },
333
334 {
335 .peak_det_timeout = 0x5,
336 .rms_meter_div_fact = 0xB << 4,
337 .rms_meter_resamp_fact = 0x28,
338 },
339};
340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700341static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
342 struct snd_kcontrol *kcontrol, int event)
343{
344 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345
346 pr_debug("%s %d\n", __func__, event);
347 switch (event) {
348 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700349 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
350 0x01);
351 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
352 usleep_range(200, 200);
353 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
354 break;
355 case SND_SOC_DAPM_PRE_PMD:
356 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
357 0x10);
358 usleep_range(20, 20);
359 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
360 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
361 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
362 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
363 0x00);
364 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365 break;
366 }
367 return 0;
368}
369
Bradley Rubina7096d02011-08-03 18:29:02 -0700370static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
371 struct snd_ctl_elem_value *ucontrol)
372{
373 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
374 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
375 ucontrol->value.integer.value[0] = tabla->anc_slot;
376 return 0;
377}
378
379static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
380 struct snd_ctl_elem_value *ucontrol)
381{
382 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
383 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
384 tabla->anc_slot = ucontrol->value.integer.value[0];
385 return 0;
386}
387
Kiran Kandid2d86b52011-09-09 17:44:28 -0700388static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
389 struct snd_ctl_elem_value *ucontrol)
390{
391 u8 ear_pa_gain;
392 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
393
394 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
395
396 ear_pa_gain = ear_pa_gain >> 5;
397
398 if (ear_pa_gain == 0x00) {
399 ucontrol->value.integer.value[0] = 0;
400 } else if (ear_pa_gain == 0x04) {
401 ucontrol->value.integer.value[0] = 1;
402 } else {
403 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
404 __func__, ear_pa_gain);
405 return -EINVAL;
406 }
407
408 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
409
410 return 0;
411}
412
413static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
414 struct snd_ctl_elem_value *ucontrol)
415{
416 u8 ear_pa_gain;
417 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
418
419 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
420 ucontrol->value.integer.value[0]);
421
422 switch (ucontrol->value.integer.value[0]) {
423 case 0:
424 ear_pa_gain = 0x00;
425 break;
426 case 1:
427 ear_pa_gain = 0x80;
428 break;
429 default:
430 return -EINVAL;
431 }
432
433 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
434 return 0;
435}
436
Ben Romberger1f045a72011-11-04 10:14:57 -0700437static int tabla_get_iir_enable_audio_mixer(
438 struct snd_kcontrol *kcontrol,
439 struct snd_ctl_elem_value *ucontrol)
440{
441 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
442 int iir_idx = ((struct soc_multi_mixer_control *)
443 kcontrol->private_value)->reg;
444 int band_idx = ((struct soc_multi_mixer_control *)
445 kcontrol->private_value)->shift;
446
447 ucontrol->value.integer.value[0] =
448 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
449 (1 << band_idx);
450
451 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
452 iir_idx, band_idx,
453 (uint32_t)ucontrol->value.integer.value[0]);
454 return 0;
455}
456
457static int tabla_put_iir_enable_audio_mixer(
458 struct snd_kcontrol *kcontrol,
459 struct snd_ctl_elem_value *ucontrol)
460{
461 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
462 int iir_idx = ((struct soc_multi_mixer_control *)
463 kcontrol->private_value)->reg;
464 int band_idx = ((struct soc_multi_mixer_control *)
465 kcontrol->private_value)->shift;
466 int value = ucontrol->value.integer.value[0];
467
468 /* Mask first 5 bits, 6-8 are reserved */
469 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
470 (1 << band_idx), (value << band_idx));
471
472 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
473 iir_idx, band_idx, value);
474 return 0;
475}
476static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
477 int iir_idx, int band_idx,
478 int coeff_idx)
479{
480 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800481 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700482 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800483 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700484
485 /* Mask bits top 2 bits since they are reserved */
486 return ((snd_soc_read(codec,
487 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
488 (snd_soc_read(codec,
489 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
490 (snd_soc_read(codec,
491 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
492 (snd_soc_read(codec,
493 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
494 0x3FFFFFFF;
495}
496
497static int tabla_get_iir_band_audio_mixer(
498 struct snd_kcontrol *kcontrol,
499 struct snd_ctl_elem_value *ucontrol)
500{
501 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
502 int iir_idx = ((struct soc_multi_mixer_control *)
503 kcontrol->private_value)->reg;
504 int band_idx = ((struct soc_multi_mixer_control *)
505 kcontrol->private_value)->shift;
506
507 ucontrol->value.integer.value[0] =
508 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
509 ucontrol->value.integer.value[1] =
510 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
511 ucontrol->value.integer.value[2] =
512 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
513 ucontrol->value.integer.value[3] =
514 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
515 ucontrol->value.integer.value[4] =
516 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
517
518 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
519 "%s: IIR #%d band #%d b1 = 0x%x\n"
520 "%s: IIR #%d band #%d b2 = 0x%x\n"
521 "%s: IIR #%d band #%d a1 = 0x%x\n"
522 "%s: IIR #%d band #%d a2 = 0x%x\n",
523 __func__, iir_idx, band_idx,
524 (uint32_t)ucontrol->value.integer.value[0],
525 __func__, iir_idx, band_idx,
526 (uint32_t)ucontrol->value.integer.value[1],
527 __func__, iir_idx, band_idx,
528 (uint32_t)ucontrol->value.integer.value[2],
529 __func__, iir_idx, band_idx,
530 (uint32_t)ucontrol->value.integer.value[3],
531 __func__, iir_idx, band_idx,
532 (uint32_t)ucontrol->value.integer.value[4]);
533 return 0;
534}
535
536static void set_iir_band_coeff(struct snd_soc_codec *codec,
537 int iir_idx, int band_idx,
538 int coeff_idx, uint32_t value)
539{
540 /* Mask top 3 bits, 6-8 are reserved */
541 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800542 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700543 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800544 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700545
546 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800547 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700548 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800549 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700550
551 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800552 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700553 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800554 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700555
Ben Romberger0915aae2012-02-06 23:32:43 -0800556 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700557 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800558 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700559
Ben Romberger0915aae2012-02-06 23:32:43 -0800560 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700561 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800562 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700563}
564
565static int tabla_put_iir_band_audio_mixer(
566 struct snd_kcontrol *kcontrol,
567 struct snd_ctl_elem_value *ucontrol)
568{
569 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
570 int iir_idx = ((struct soc_multi_mixer_control *)
571 kcontrol->private_value)->reg;
572 int band_idx = ((struct soc_multi_mixer_control *)
573 kcontrol->private_value)->shift;
574
575 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
576 ucontrol->value.integer.value[0]);
577 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
578 ucontrol->value.integer.value[1]);
579 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
580 ucontrol->value.integer.value[2]);
581 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
582 ucontrol->value.integer.value[3]);
583 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
584 ucontrol->value.integer.value[4]);
585
586 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
587 "%s: IIR #%d band #%d b1 = 0x%x\n"
588 "%s: IIR #%d band #%d b2 = 0x%x\n"
589 "%s: IIR #%d band #%d a1 = 0x%x\n"
590 "%s: IIR #%d band #%d a2 = 0x%x\n",
591 __func__, iir_idx, band_idx,
592 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
593 __func__, iir_idx, band_idx,
594 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
595 __func__, iir_idx, band_idx,
596 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
597 __func__, iir_idx, band_idx,
598 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
599 __func__, iir_idx, band_idx,
600 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
601 return 0;
602}
603
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800604static int tabla_compander_gain_offset(
605 struct snd_soc_codec *codec, u32 enable,
606 unsigned int reg, int mask, int event)
607{
608 int pa_mode = snd_soc_read(codec, reg) & mask;
609 int gain_offset = 0;
610 /* if PMU && enable is 1-> offset is 3
611 * if PMU && enable is 0-> offset is 0
612 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
613 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
614 */
615
616 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
617 gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
618 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
619 gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
620 return gain_offset;
621}
622
623
624static int tabla_config_gain_compander(
625 struct snd_soc_codec *codec,
626 u32 compander, u32 enable, int event)
627{
628 int value = 0;
629 int mask = 1 << 4;
630 int gain = 0;
631 int gain_offset;
632 if (compander >= COMPANDER_MAX) {
633 pr_err("%s: Error, invalid compander channel\n", __func__);
634 return -EINVAL;
635 }
636
637 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
638 value = 1 << 4;
639
640 if (compander == COMPANDER_1) {
641 gain_offset = tabla_compander_gain_offset(codec, enable,
642 TABLA_A_RX_HPH_L_GAIN, mask, event);
643 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
644 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
645 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
646 0xFF, gain - gain_offset);
647 gain_offset = tabla_compander_gain_offset(codec, enable,
648 TABLA_A_RX_HPH_R_GAIN, mask, event);
649 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
650 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
651 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
652 0xFF, gain - gain_offset);
653 } else if (compander == COMPANDER_2) {
654 gain_offset = tabla_compander_gain_offset(codec, enable,
655 TABLA_A_RX_LINE_1_GAIN, mask, event);
656 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
657 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
658 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
659 0xFF, gain - gain_offset);
660 gain_offset = tabla_compander_gain_offset(codec, enable,
661 TABLA_A_RX_LINE_3_GAIN, mask, event);
662 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
663 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
664 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
665 0xFF, gain - gain_offset);
666 gain_offset = tabla_compander_gain_offset(codec, enable,
667 TABLA_A_RX_LINE_2_GAIN, mask, event);
668 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
669 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
670 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
671 0xFF, gain - gain_offset);
672 gain_offset = tabla_compander_gain_offset(codec, enable,
673 TABLA_A_RX_LINE_4_GAIN, mask, event);
674 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
675 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
676 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
677 0xFF, gain - gain_offset);
678 }
679 return 0;
680}
681static int tabla_get_compander(struct snd_kcontrol *kcontrol,
682 struct snd_ctl_elem_value *ucontrol)
683{
684
685 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
686 int comp = ((struct soc_multi_mixer_control *)
687 kcontrol->private_value)->max;
688 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
689
690 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
691
692 return 0;
693}
694
695static int tabla_set_compander(struct snd_kcontrol *kcontrol,
696 struct snd_ctl_elem_value *ucontrol)
697{
698 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
699 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
700 int comp = ((struct soc_multi_mixer_control *)
701 kcontrol->private_value)->max;
702 int value = ucontrol->value.integer.value[0];
703
704 if (value == tabla->comp_enabled[comp]) {
705 pr_debug("%s: compander #%d enable %d no change\n",
706 __func__, comp, value);
707 return 0;
708 }
709 tabla->comp_enabled[comp] = value;
710 return 0;
711}
712
713
714static int tabla_config_compander(struct snd_soc_dapm_widget *w,
715 struct snd_kcontrol *kcontrol,
716 int event)
717{
718 struct snd_soc_codec *codec = w->codec;
719 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
720 u32 rate = tabla->comp_fs[w->shift];
721
722 switch (event) {
723 case SND_SOC_DAPM_PRE_PMU:
724 if (tabla->comp_enabled[w->shift] != 0) {
725 /* Enable both L/R compander clocks */
726 snd_soc_update_bits(codec,
727 TABLA_A_CDC_CLK_RX_B2_CTL,
728 0x03 << comp_shift[w->shift],
729 0x03 << comp_shift[w->shift]);
730 /* Clar the HALT for the compander*/
731 snd_soc_update_bits(codec,
732 TABLA_A_CDC_COMP1_B1_CTL +
733 w->shift * 8, 1 << 2, 0);
734 /* Toggle compander reset bits*/
735 snd_soc_update_bits(codec,
736 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
737 0x03 << comp_shift[w->shift],
738 0x03 << comp_shift[w->shift]);
739 snd_soc_update_bits(codec,
740 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
741 0x03 << comp_shift[w->shift], 0);
742 tabla_config_gain_compander(codec, w->shift, 1, event);
743 /* Update the RMS meter resampling*/
744 snd_soc_update_bits(codec,
745 TABLA_A_CDC_COMP1_B3_CTL +
746 w->shift * 8, 0xFF, 0x01);
747 /* Wait for 1ms*/
748 usleep_range(1000, 1000);
749 }
750 break;
751 case SND_SOC_DAPM_POST_PMU:
752 /* Set sample rate dependent paramater*/
753 if (tabla->comp_enabled[w->shift] != 0) {
754 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
755 w->shift * 8, 0x03, rate);
756 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
757 w->shift * 8, 0x0F,
758 comp_samp_params[rate].peak_det_timeout);
759 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
760 w->shift * 8, 0xF0,
761 comp_samp_params[rate].rms_meter_div_fact);
762 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
763 w->shift * 8, 0xFF,
764 comp_samp_params[rate].rms_meter_resamp_fact);
765 /* Compander enable -> 0x370/0x378*/
766 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
767 w->shift * 8, 0x03, 0x03);
768 }
769 break;
770 case SND_SOC_DAPM_PRE_PMD:
771 /* Halt the compander*/
772 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
773 w->shift * 8, 1 << 2, 1 << 2);
774 break;
775 case SND_SOC_DAPM_POST_PMD:
776 /* Restore the gain */
777 tabla_config_gain_compander(codec, w->shift,
778 tabla->comp_enabled[w->shift], event);
779 /* Disable the compander*/
780 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
781 w->shift * 8, 0x03, 0x00);
782 /* Turn off the clock for compander in pair*/
783 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
784 0x03 << comp_shift[w->shift], 0);
785 break;
786 }
787 return 0;
788}
789
Kiran Kandid2d86b52011-09-09 17:44:28 -0700790static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
791static const struct soc_enum tabla_ear_pa_gain_enum[] = {
792 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
793};
794
Santosh Mardi024010f2011-10-18 06:27:21 +0530795/*cut of frequency for high pass filter*/
796static const char *cf_text[] = {
797 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
798};
799
800static const struct soc_enum cf_dec1_enum =
801 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
802
803static const struct soc_enum cf_dec2_enum =
804 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
805
806static const struct soc_enum cf_dec3_enum =
807 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
808
809static const struct soc_enum cf_dec4_enum =
810 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
811
812static const struct soc_enum cf_dec5_enum =
813 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
814
815static const struct soc_enum cf_dec6_enum =
816 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
817
818static const struct soc_enum cf_dec7_enum =
819 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
820
821static const struct soc_enum cf_dec8_enum =
822 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
823
824static const struct soc_enum cf_dec9_enum =
825 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
826
827static const struct soc_enum cf_dec10_enum =
828 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
829
830static const struct soc_enum cf_rxmix1_enum =
831 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
832
833static const struct soc_enum cf_rxmix2_enum =
834 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
835
836static const struct soc_enum cf_rxmix3_enum =
837 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
838
839static const struct soc_enum cf_rxmix4_enum =
840 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
841
842static const struct soc_enum cf_rxmix5_enum =
843 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
844;
845static const struct soc_enum cf_rxmix6_enum =
846 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
847
848static const struct soc_enum cf_rxmix7_enum =
849 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
850
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700852
853 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
854 tabla_pa_gain_get, tabla_pa_gain_put),
855
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
857 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700858 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
859 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
861 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700862 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
863 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700864 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
865 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
868 line_gain),
869 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
870 line_gain),
871
Bradley Rubin410383f2011-07-22 13:44:23 -0700872 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
873 -84, 40, digital_gain),
874 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
875 -84, 40, digital_gain),
876 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
877 -84, 40, digital_gain),
878 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
879 -84, 40, digital_gain),
880 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
881 -84, 40, digital_gain),
882 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
883 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -0800884 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
885 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886
Bradley Rubin410383f2011-07-22 13:44:23 -0700887 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700888 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700889 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700891 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
892 digital_gain),
893 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
894 digital_gain),
895 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
896 digital_gain),
897 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
898 digital_gain),
899 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
900 digital_gain),
901 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
902 digital_gain),
903 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
904 digital_gain),
905 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
906 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700907 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
908 40, digital_gain),
909 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
910 40, digital_gain),
911 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
912 40, digital_gain),
913 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
914 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700915 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
916 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700917 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
918 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700919 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
920 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700921
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800922 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
923 aux_pga_gain),
924 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
925 aux_pga_gain),
926
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800928 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700929 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700930
931 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
932 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530933 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
934 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
935 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
936 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
937 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
938 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
939 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
940 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
941 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
942 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
943
944 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
945 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
946 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
947 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
948 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
949 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
950 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
951 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
952 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
953 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
954
955 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
956 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
957 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
958 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
959 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
960 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
961 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
962
963 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
964 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
965 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
966 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
967 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
968 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
969 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700970
971 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
972 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
973 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
974 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
975 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
976 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
977 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
978 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
979 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
980 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
981 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
982 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
983 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
984 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
985 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
986 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
987 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
988 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
989 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
990 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
991
992 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
993 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
994 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
995 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
996 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
997 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
998 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
999 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1000 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1001 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1002 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1003 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1004 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1005 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1006 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1007 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1008 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1009 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1010 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1011 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001012 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
1013 tabla_get_compander, tabla_set_compander),
1014 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
1015 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016};
1017
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001018static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
1019 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
1020};
1021
1022static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
1023 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
1024};
1025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026static const char *rx_mix1_text[] = {
1027 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1028 "RX5", "RX6", "RX7"
1029};
1030
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001031static const char *rx_dsm_text[] = {
1032 "CIC_OUT", "DSM_INV"
1033};
1034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035static const char *sb_tx1_mux_text[] = {
1036 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1037 "DEC1"
1038};
1039
1040static const char *sb_tx5_mux_text[] = {
1041 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1042 "DEC5"
1043};
1044
1045static const char *sb_tx6_mux_text[] = {
1046 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1047 "DEC6"
1048};
1049
1050static const char const *sb_tx7_to_tx10_mux_text[] = {
1051 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1052 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1053 "DEC9", "DEC10"
1054};
1055
1056static const char *dec1_mux_text[] = {
1057 "ZERO", "DMIC1", "ADC6",
1058};
1059
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001060static const char *dec2_mux_text[] = {
1061 "ZERO", "DMIC2", "ADC5",
1062};
1063
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001064static const char *dec3_mux_text[] = {
1065 "ZERO", "DMIC3", "ADC4",
1066};
1067
1068static const char *dec4_mux_text[] = {
1069 "ZERO", "DMIC4", "ADC3",
1070};
1071
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072static const char *dec5_mux_text[] = {
1073 "ZERO", "DMIC5", "ADC2",
1074};
1075
1076static const char *dec6_mux_text[] = {
1077 "ZERO", "DMIC6", "ADC1",
1078};
1079
1080static const char const *dec7_mux_text[] = {
1081 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1082};
1083
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001084static const char *dec8_mux_text[] = {
1085 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1086};
1087
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001088static const char *dec9_mux_text[] = {
1089 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1090};
1091
1092static const char *dec10_mux_text[] = {
1093 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1094};
1095
Bradley Rubin229c6a52011-07-12 16:18:48 -07001096static const char const *anc_mux_text[] = {
1097 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1098 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1099};
1100
1101static const char const *anc1_fb_mux_text[] = {
1102 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1103};
1104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105static const char *iir1_inp1_text[] = {
1106 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1107 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1108};
1109
1110static const struct soc_enum rx_mix1_inp1_chain_enum =
1111 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1112
Bradley Rubin229c6a52011-07-12 16:18:48 -07001113static const struct soc_enum rx_mix1_inp2_chain_enum =
1114 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116static const struct soc_enum rx2_mix1_inp1_chain_enum =
1117 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1118
Bradley Rubin229c6a52011-07-12 16:18:48 -07001119static const struct soc_enum rx2_mix1_inp2_chain_enum =
1120 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001122static const struct soc_enum rx3_mix1_inp1_chain_enum =
1123 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1124
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001125static const struct soc_enum rx3_mix1_inp2_chain_enum =
1126 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001128static const struct soc_enum rx4_mix1_inp1_chain_enum =
1129 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1130
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001131static const struct soc_enum rx4_mix1_inp2_chain_enum =
1132 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001134static const struct soc_enum rx5_mix1_inp1_chain_enum =
1135 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1136
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001137static const struct soc_enum rx5_mix1_inp2_chain_enum =
1138 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1139
1140static const struct soc_enum rx6_mix1_inp1_chain_enum =
1141 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1142
1143static const struct soc_enum rx6_mix1_inp2_chain_enum =
1144 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1145
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001146static const struct soc_enum rx7_mix1_inp1_chain_enum =
1147 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1148
1149static const struct soc_enum rx7_mix1_inp2_chain_enum =
1150 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1151
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001152static const struct soc_enum rx4_dsm_enum =
1153 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1154
1155static const struct soc_enum rx6_dsm_enum =
1156 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1157
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158static const struct soc_enum sb_tx5_mux_enum =
1159 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1160
1161static const struct soc_enum sb_tx6_mux_enum =
1162 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1163
1164static const struct soc_enum sb_tx7_mux_enum =
1165 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1166 sb_tx7_to_tx10_mux_text);
1167
1168static const struct soc_enum sb_tx8_mux_enum =
1169 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1170 sb_tx7_to_tx10_mux_text);
1171
Kiran Kandi3426e512011-09-13 22:50:10 -07001172static const struct soc_enum sb_tx9_mux_enum =
1173 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1174 sb_tx7_to_tx10_mux_text);
1175
1176static const struct soc_enum sb_tx10_mux_enum =
1177 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1178 sb_tx7_to_tx10_mux_text);
1179
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180static const struct soc_enum sb_tx1_mux_enum =
1181 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1182
1183static const struct soc_enum dec1_mux_enum =
1184 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1185
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001186static const struct soc_enum dec2_mux_enum =
1187 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1188
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001189static const struct soc_enum dec3_mux_enum =
1190 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1191
1192static const struct soc_enum dec4_mux_enum =
1193 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1194
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195static const struct soc_enum dec5_mux_enum =
1196 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1197
1198static const struct soc_enum dec6_mux_enum =
1199 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1200
1201static const struct soc_enum dec7_mux_enum =
1202 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1203
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001204static const struct soc_enum dec8_mux_enum =
1205 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1206
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001207static const struct soc_enum dec9_mux_enum =
1208 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1209
1210static const struct soc_enum dec10_mux_enum =
1211 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1212
Bradley Rubin229c6a52011-07-12 16:18:48 -07001213static const struct soc_enum anc1_mux_enum =
1214 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1215
1216static const struct soc_enum anc2_mux_enum =
1217 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1218
1219static const struct soc_enum anc1_fb_mux_enum =
1220 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1221
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222static const struct soc_enum iir1_inp1_mux_enum =
1223 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
1224
1225static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1226 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1227
Bradley Rubin229c6a52011-07-12 16:18:48 -07001228static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1229 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1232 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1233
Bradley Rubin229c6a52011-07-12 16:18:48 -07001234static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1235 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1236
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1238 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1239
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001240static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1241 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1242
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1244 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1245
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001246static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1247 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1248
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1250 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1251
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001252static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1253 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1254
1255static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1256 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1257
1258static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1259 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1260
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001261static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1262 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1263
1264static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1265 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1266
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001267static const struct snd_kcontrol_new rx4_dsm_mux =
1268 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1269
1270static const struct snd_kcontrol_new rx6_dsm_mux =
1271 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273static const struct snd_kcontrol_new sb_tx5_mux =
1274 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1275
1276static const struct snd_kcontrol_new sb_tx6_mux =
1277 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1278
1279static const struct snd_kcontrol_new sb_tx7_mux =
1280 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1281
1282static const struct snd_kcontrol_new sb_tx8_mux =
1283 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1284
Kiran Kandi3426e512011-09-13 22:50:10 -07001285static const struct snd_kcontrol_new sb_tx9_mux =
1286 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1287
1288static const struct snd_kcontrol_new sb_tx10_mux =
1289 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291static const struct snd_kcontrol_new sb_tx1_mux =
1292 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1293
1294static const struct snd_kcontrol_new dec1_mux =
1295 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1296
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001297static const struct snd_kcontrol_new dec2_mux =
1298 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1299
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001300static const struct snd_kcontrol_new dec3_mux =
1301 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1302
1303static const struct snd_kcontrol_new dec4_mux =
1304 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1305
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306static const struct snd_kcontrol_new dec5_mux =
1307 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
1308
1309static const struct snd_kcontrol_new dec6_mux =
1310 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
1311
1312static const struct snd_kcontrol_new dec7_mux =
1313 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
1314
Bradley Rubin229c6a52011-07-12 16:18:48 -07001315static const struct snd_kcontrol_new anc1_mux =
1316 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001317static const struct snd_kcontrol_new dec8_mux =
1318 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
1319
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001320static const struct snd_kcontrol_new dec9_mux =
1321 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
1322
1323static const struct snd_kcontrol_new dec10_mux =
1324 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
1325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326static const struct snd_kcontrol_new iir1_inp1_mux =
1327 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1328
Bradley Rubin229c6a52011-07-12 16:18:48 -07001329static const struct snd_kcontrol_new anc2_mux =
1330 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331
Bradley Rubin229c6a52011-07-12 16:18:48 -07001332static const struct snd_kcontrol_new anc1_fb_mux =
1333 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334
Bradley Rubin229c6a52011-07-12 16:18:48 -07001335static const struct snd_kcontrol_new dac1_switch[] = {
1336 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1337};
1338static const struct snd_kcontrol_new hphl_switch[] = {
1339 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1340};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001341
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001342static const struct snd_kcontrol_new hphl_pa_mix[] = {
1343 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1344 7, 1, 0),
1345 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1346 7, 1, 0),
1347 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1348 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1349 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1350 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1351};
1352
1353static const struct snd_kcontrol_new hphr_pa_mix[] = {
1354 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1355 6, 1, 0),
1356 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1357 6, 1, 0),
1358 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1359 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1360 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1361 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1362};
1363
1364static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1365 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1366 5, 1, 0),
1367 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1368 5, 1, 0),
1369 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1370 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1371 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1372 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1373};
1374
1375static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1376 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1377 4, 1, 0),
1378 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1379 4, 1, 0),
1380 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1381 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1382 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1383 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1384};
1385
1386static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1387 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1388 3, 1, 0),
1389 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1390 3, 1, 0),
1391 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1392 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1393 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1394 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1395};
1396
1397static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1398 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1399 2, 1, 0),
1400 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1401 2, 1, 0),
1402 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1403 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1404 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1405 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1406};
1407
1408static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1409 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1410 1, 1, 0),
1411 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1412 1, 1, 0),
1413 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1414 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1415 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1416 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1417};
1418
1419static const struct snd_kcontrol_new ear_pa_mix[] = {
1420 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1421 0, 1, 0),
1422 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1423 0, 1, 0),
1424 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1425 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1426 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1427 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1428};
1429
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001430static const struct snd_kcontrol_new lineout3_ground_switch =
1431 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1432
1433static const struct snd_kcontrol_new lineout4_ground_switch =
1434 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001437 int enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438{
1439 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1440
1441 pr_debug("%s %d\n", __func__, enable);
1442
1443 if (enable) {
1444 tabla->adc_count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1446 } else {
1447 tabla->adc_count--;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001448 if (!tabla->adc_count)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
Joonwoo Park03324832012-03-19 19:36:16 -07001450 0x2, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 }
1452}
1453
1454static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1455 struct snd_kcontrol *kcontrol, int event)
1456{
1457 struct snd_soc_codec *codec = w->codec;
1458 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001459 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460
1461 pr_debug("%s %d\n", __func__, event);
1462
1463 if (w->reg == TABLA_A_TX_1_2_EN)
1464 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1465 else if (w->reg == TABLA_A_TX_3_4_EN)
1466 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1467 else if (w->reg == TABLA_A_TX_5_6_EN)
1468 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1469 else {
1470 pr_err("%s: Error, invalid adc register\n", __func__);
1471 return -EINVAL;
1472 }
1473
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001474 if (w->shift == 3)
1475 init_bit_shift = 6;
1476 else if (w->shift == 7)
1477 init_bit_shift = 7;
1478 else {
1479 pr_err("%s: Error, invalid init bit postion adc register\n",
1480 __func__);
1481 return -EINVAL;
1482 }
1483
1484
1485
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001486 switch (event) {
1487 case SND_SOC_DAPM_PRE_PMU:
1488 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001489 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1490 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 break;
1492 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001493
1494 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496 break;
1497 case SND_SOC_DAPM_POST_PMD:
1498 tabla_codec_enable_adc_block(codec, 0);
1499 break;
1500 }
1501 return 0;
1502}
1503
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001504static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1505{
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001506 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1507 0x80);
1508 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1509 0x04);
1510 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1511 0x01);
1512 usleep_range(1000, 1000);
1513 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1514 0x00);
1515}
1516
1517static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1518 enum tabla_bandgap_type choice)
1519{
1520 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1521
1522 /* TODO lock resources accessed by audio streams and threaded
1523 * interrupt handlers
1524 */
1525
1526 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1527 tabla->bandgap_type);
1528
1529 if (tabla->bandgap_type == choice)
1530 return;
1531
1532 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1533 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1534 tabla_codec_enable_audio_mode_bandgap(codec);
1535 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
1536 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1537 0x2);
1538 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1539 0x80);
1540 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1541 0x4);
1542 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1543 0x01);
1544 usleep_range(1000, 1000);
1545 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1546 0x00);
1547 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1548 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1549 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1550 usleep_range(100, 100);
1551 tabla_codec_enable_audio_mode_bandgap(codec);
1552 } else if (choice == TABLA_BANDGAP_OFF) {
1553 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1554 } else {
1555 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1556 }
1557 tabla->bandgap_type = choice;
1558}
1559
1560static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1561{
1562 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1563 pr_debug("%s\n", __func__);
1564 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1565 ndelay(160);
1566 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1567 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1568 tabla->clock_active = false;
1569}
1570
1571static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
1572{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001573 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001574 return 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001575 else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001576 return 1;
1577 else {
1578 BUG_ON(1);
1579 return -EINVAL;
1580 }
1581}
1582
1583static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1584{
1585 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1586
1587 if (enable) {
1588 tabla->rx_bias_count++;
1589 if (tabla->rx_bias_count == 1)
1590 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1591 0x80, 0x80);
1592 } else {
1593 tabla->rx_bias_count--;
1594 if (!tabla->rx_bias_count)
1595 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1596 0x80, 0x00);
1597 }
1598}
1599
1600static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1601 int enable)
1602{
1603 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1604
1605 pr_debug("%s: enable = %d\n", __func__, enable);
1606 if (enable) {
1607 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1608 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1609 usleep_range(5, 5);
1610 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1611 0x80);
1612 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1613 0x80);
1614 usleep_range(10, 10);
1615 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1616 usleep_range(20, 20);
1617 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1618 } else {
1619 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1620 0);
1621 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1622 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1623 }
1624 tabla->config_mode_active = enable ? true : false;
1625
1626 return 0;
1627}
1628
1629static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1630 int config_mode)
1631{
1632 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1633
1634 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
1635
1636 if (config_mode) {
1637 tabla_codec_enable_config_mode(codec, 1);
1638 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1639 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1640 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1641 usleep_range(1000, 1000);
1642 } else
1643 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1644
1645 if (!config_mode && tabla->mbhc_polling_active) {
1646 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1647 tabla_codec_enable_config_mode(codec, 0);
1648
1649 }
1650
1651 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1652 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1653 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1654 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1655 usleep_range(50, 50);
1656 tabla->clock_active = true;
1657 return 0;
1658}
1659
1660static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1661 struct snd_kcontrol *kcontrol, int event)
1662{
1663 struct snd_soc_codec *codec = w->codec;
1664 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1665
1666 pr_debug("%s: %d\n", __func__, event);
1667
1668 switch (event) {
1669 case SND_SOC_DAPM_PRE_PMU:
1670 tabla_codec_enable_bandgap(codec,
1671 TABLA_BANDGAP_AUDIO_MODE);
1672 tabla_enable_rx_bias(codec, 1);
1673
1674 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1675 0x08, 0x08);
1676 /* Enable Zero Cross detect for AUX PGA channel
1677 * and set the initial AUX PGA gain to NEG_0P0_DB
1678 * to avoid glitches.
1679 */
1680 if (w->reg == TABLA_A_AUX_L_EN) {
1681 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1682 0x20, 0x20);
1683 tabla->aux_l_gain = snd_soc_read(codec,
1684 TABLA_A_AUX_L_GAIN);
1685 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1686 } else {
1687 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1688 0x20, 0x20);
1689 tabla->aux_r_gain = snd_soc_read(codec,
1690 TABLA_A_AUX_R_GAIN);
1691 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1692 }
1693 if (tabla->aux_pga_cnt++ == 1
1694 && !tabla->mclk_enabled) {
1695 tabla_codec_enable_clock_block(codec, 1);
1696 pr_debug("AUX PGA enabled RC osc\n");
1697 }
1698 break;
1699
1700 case SND_SOC_DAPM_POST_PMU:
1701 if (w->reg == TABLA_A_AUX_L_EN)
1702 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1703 tabla->aux_l_gain);
1704 else
1705 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1706 tabla->aux_r_gain);
1707 break;
1708
1709 case SND_SOC_DAPM_PRE_PMD:
1710 /* Mute AUX PGA channel in use before disabling AUX PGA */
1711 if (w->reg == TABLA_A_AUX_L_EN) {
1712 tabla->aux_l_gain = snd_soc_read(codec,
1713 TABLA_A_AUX_L_GAIN);
1714 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1715 } else {
1716 tabla->aux_r_gain = snd_soc_read(codec,
1717 TABLA_A_AUX_R_GAIN);
1718 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1719 }
1720 break;
1721
1722 case SND_SOC_DAPM_POST_PMD:
1723 tabla_enable_rx_bias(codec, 0);
1724
1725 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1726 0x08, 0x00);
1727 if (w->reg == TABLA_A_AUX_L_EN) {
1728 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1729 tabla->aux_l_gain);
1730 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1731 0x20, 0x00);
1732 } else {
1733 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1734 tabla->aux_r_gain);
1735 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1736 0x20, 0x00);
1737 }
1738
1739 if (tabla->aux_pga_cnt-- == 0) {
1740 if (tabla->mbhc_polling_active)
1741 tabla_codec_enable_bandgap(codec,
1742 TABLA_BANDGAP_MBHC_MODE);
1743 else
1744 tabla_codec_enable_bandgap(codec,
1745 TABLA_BANDGAP_OFF);
1746
1747 if (!tabla->mclk_enabled &&
1748 !tabla->mbhc_polling_active) {
1749 tabla_codec_enable_clock_block(codec, 0);
1750 }
1751 }
1752 break;
1753 }
1754 return 0;
1755}
1756
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001757static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1758 struct snd_kcontrol *kcontrol, int event)
1759{
1760 struct snd_soc_codec *codec = w->codec;
1761 u16 lineout_gain_reg;
1762
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001763 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001764
1765 switch (w->shift) {
1766 case 0:
1767 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1768 break;
1769 case 1:
1770 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1771 break;
1772 case 2:
1773 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1774 break;
1775 case 3:
1776 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1777 break;
1778 case 4:
1779 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1780 break;
1781 default:
1782 pr_err("%s: Error, incorrect lineout register value\n",
1783 __func__);
1784 return -EINVAL;
1785 }
1786
1787 switch (event) {
1788 case SND_SOC_DAPM_PRE_PMU:
1789 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1790 break;
1791 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001792 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001793 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001794 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001795 break;
1796 case SND_SOC_DAPM_POST_PMD:
1797 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1798 break;
1799 }
1800 return 0;
1801}
1802
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001803
1804static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001805 struct snd_kcontrol *kcontrol, int event)
1806{
1807 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001808 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1809 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001810 unsigned int dmic;
1811 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001812
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001813 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1814 if (ret < 0) {
1815 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001816 return -EINVAL;
1817 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001818
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001819 switch (dmic) {
1820 case 1:
1821 case 2:
1822 dmic_clk_sel = 0x02;
1823 dmic_clk_en = 0x01;
1824 break;
1825
1826 case 3:
1827 case 4:
1828 dmic_clk_sel = 0x08;
1829 dmic_clk_en = 0x04;
1830 break;
1831
1832 case 5:
1833 case 6:
1834 dmic_clk_sel = 0x20;
1835 dmic_clk_en = 0x10;
1836 break;
1837
1838 default:
1839 pr_err("%s: Invalid DMIC Selection\n", __func__);
1840 return -EINVAL;
1841 }
1842
1843 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1844 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1845
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001846 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001847
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001848 switch (event) {
1849 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001850 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1851
1852 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1853 dmic_clk_sel, dmic_clk_sel);
1854
1855 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1856
1857 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1858 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001859 break;
1860 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001861 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1862 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001863 break;
1864 }
1865 return 0;
1866}
1867
Bradley Rubin229c6a52011-07-12 16:18:48 -07001868static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1869 struct snd_kcontrol *kcontrol, int event)
1870{
1871 struct snd_soc_codec *codec = w->codec;
1872 const char *filename;
1873 const struct firmware *fw;
1874 int i;
1875 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001876 int num_anc_slots;
1877 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001878 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001879 u32 anc_writes_size = 0;
1880 int anc_size_remaining;
1881 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001882 u16 reg;
1883 u8 mask, val, old_val;
1884
1885 pr_debug("%s %d\n", __func__, event);
1886 switch (event) {
1887 case SND_SOC_DAPM_PRE_PMU:
1888
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001889 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001890
1891 ret = request_firmware(&fw, filename, codec->dev);
1892 if (ret != 0) {
1893 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1894 ret);
1895 return -ENODEV;
1896 }
1897
Bradley Rubina7096d02011-08-03 18:29:02 -07001898 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001899 dev_err(codec->dev, "Not enough data\n");
1900 release_firmware(fw);
1901 return -ENOMEM;
1902 }
1903
1904 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001905 anc_head = (struct anc_header *)(fw->data);
1906 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1907 anc_size_remaining = fw->size - sizeof(struct anc_header);
1908 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001909
Bradley Rubina7096d02011-08-03 18:29:02 -07001910 if (tabla->anc_slot >= num_anc_slots) {
1911 dev_err(codec->dev, "Invalid ANC slot selected\n");
1912 release_firmware(fw);
1913 return -EINVAL;
1914 }
1915
1916 for (i = 0; i < num_anc_slots; i++) {
1917
1918 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1919 dev_err(codec->dev, "Invalid register format\n");
1920 release_firmware(fw);
1921 return -EINVAL;
1922 }
1923 anc_writes_size = (u32)(*anc_ptr);
1924 anc_size_remaining -= sizeof(u32);
1925 anc_ptr += 1;
1926
1927 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1928 > anc_size_remaining) {
1929 dev_err(codec->dev, "Invalid register format\n");
1930 release_firmware(fw);
1931 return -ENOMEM;
1932 }
1933
1934 if (tabla->anc_slot == i)
1935 break;
1936
1937 anc_size_remaining -= (anc_writes_size *
1938 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001939 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001940 }
1941 if (i == num_anc_slots) {
1942 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001943 release_firmware(fw);
1944 return -ENOMEM;
1945 }
1946
Bradley Rubina7096d02011-08-03 18:29:02 -07001947 for (i = 0; i < anc_writes_size; i++) {
1948 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001949 mask, val);
1950 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001951 snd_soc_write(codec, reg, (old_val & ~mask) |
1952 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001953 }
1954 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001955
1956 break;
1957 case SND_SOC_DAPM_POST_PMD:
1958 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1959 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1960 break;
1961 }
1962 return 0;
1963}
1964
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001965/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001966static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1967{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001968 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07001969 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
1970 int mbhc_state = tabla->mbhc_state;
Bradley Rubincb3950a2011-08-18 13:07:26 -07001971
Joonwoo Park03324832012-03-19 19:36:16 -07001972 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001973 if (!tabla->mbhc_polling_active) {
1974 pr_debug("Polling is not active, do not start polling\n");
1975 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07001976 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001977 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Joonwoo Park03324832012-03-19 19:36:16 -07001978
1979 if (!tabla->no_mic_headset_override) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001980 if (mbhc_state == MBHC_STATE_POTENTIAL) {
1981 pr_debug("%s recovering MBHC state macine\n", __func__);
1982 tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
Joonwoo Park03324832012-03-19 19:36:16 -07001983 /* set to max button press threshold */
1984 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
1985 0x7F);
1986 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
1987 0xFF);
1988 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1989 (TABLA_IS_1_X(tabla_core->version) ?
1990 0x07 : 0x7F));
1991 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
1992 0xFF);
1993 /* set to max */
1994 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
1995 0x7F);
1996 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
1997 0xFF);
1998 }
1999 }
2000
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002001 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
2002 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2003 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
Joonwoo Park03324832012-03-19 19:36:16 -07002004 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002005}
2006
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002007/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002008static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
2009{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002010 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2011
Joonwoo Park03324832012-03-19 19:36:16 -07002012 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002013 if (!tabla->mbhc_polling_active) {
2014 pr_debug("polling not active, nothing to pause\n");
2015 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002016 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002017
2018 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Joonwoo Park03324832012-03-19 19:36:16 -07002019 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002020}
2021
Joonwoo Park03324832012-03-19 19:36:16 -07002022static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002023{
2024 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2025 u8 reg_mode_val, cur_mode_val;
2026 bool mbhc_was_polling = false;
2027
2028 if (mode)
2029 reg_mode_val = TABLA_CFILT_FAST_MODE;
2030 else
2031 reg_mode_val = TABLA_CFILT_SLOW_MODE;
2032
2033 cur_mode_val = snd_soc_read(codec,
2034 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
2035
2036 if (cur_mode_val != reg_mode_val) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002037 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002038 if (tabla->mbhc_polling_active) {
2039 tabla_codec_pause_hs_polling(codec);
2040 mbhc_was_polling = true;
2041 }
2042 snd_soc_update_bits(codec,
2043 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
2044 if (mbhc_was_polling)
2045 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002046 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002047 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
2048 cur_mode_val, reg_mode_val);
2049 } else {
2050 pr_debug("%s: CFILT Value is already %x\n",
2051 __func__, cur_mode_val);
2052 }
2053}
2054
2055static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
2056 u8 cfilt_sel, int inc)
2057{
2058 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2059 u32 *cfilt_cnt_ptr = NULL;
2060 u16 micb_cfilt_reg;
2061
2062 switch (cfilt_sel) {
2063 case TABLA_CFILT1_SEL:
2064 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2065 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2066 break;
2067 case TABLA_CFILT2_SEL:
2068 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2069 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2070 break;
2071 case TABLA_CFILT3_SEL:
2072 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2073 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2074 break;
2075 default:
2076 return; /* should not happen */
2077 }
2078
2079 if (inc) {
2080 if (!(*cfilt_cnt_ptr)++) {
2081 /* Switch CFILT to slow mode if MBHC CFILT being used */
2082 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2083 tabla_codec_switch_cfilt_mode(codec, 0);
2084
2085 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2086 }
2087 } else {
2088 /* check if count not zero, decrement
2089 * then check if zero, go ahead disable cfilter
2090 */
2091 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2092 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2093
2094 /* Switch CFILT to fast mode if MBHC CFILT being used */
2095 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2096 tabla_codec_switch_cfilt_mode(codec, 1);
2097 }
2098 }
2099}
2100
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002101static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2102{
2103 int rc = -EINVAL;
2104 unsigned min_mv, max_mv;
2105
2106 switch (ldoh_v) {
2107 case TABLA_LDOH_1P95_V:
2108 min_mv = 160;
2109 max_mv = 1800;
2110 break;
2111 case TABLA_LDOH_2P35_V:
2112 min_mv = 200;
2113 max_mv = 2200;
2114 break;
2115 case TABLA_LDOH_2P75_V:
2116 min_mv = 240;
2117 max_mv = 2600;
2118 break;
2119 case TABLA_LDOH_2P85_V:
2120 min_mv = 250;
2121 max_mv = 2700;
2122 break;
2123 default:
2124 goto done;
2125 }
2126
2127 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2128 goto done;
2129
2130 for (rc = 4; rc <= 44; rc++) {
2131 min_mv = max_mv * (rc) / 44;
2132 if (min_mv >= cfilt_mv) {
2133 rc -= 4;
2134 break;
2135 }
2136 }
2137done:
2138 return rc;
2139}
2140
2141static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2142{
2143 u8 hph_reg_val = 0;
2144 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2145
2146 return (hph_reg_val & 0x30) ? true : false;
2147}
2148
Joonwoo Parka9444452011-12-08 18:48:27 -08002149static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2150{
2151 u8 hph_reg_val = 0;
2152 if (left)
2153 hph_reg_val = snd_soc_read(codec,
2154 TABLA_A_RX_HPH_L_DAC_CTL);
2155 else
2156 hph_reg_val = snd_soc_read(codec,
2157 TABLA_A_RX_HPH_R_DAC_CTL);
2158
2159 return (hph_reg_val & 0xC0) ? true : false;
2160}
2161
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002162/* called under codec_resource_lock acquisition */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002163static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002164 int vddio_switch)
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002165{
2166 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2167 int cfilt_k_val;
Joonwoo Park03324832012-03-19 19:36:16 -07002168 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002169
2170 switch (vddio_switch) {
2171 case 1:
Joonwoo Park03324832012-03-19 19:36:16 -07002172 if (tabla->mbhc_micbias_switched == 0 &&
2173 tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002174 tabla_codec_pause_hs_polling(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08002175 /* VDDIO switch enabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002176 tabla->cfilt_k_value = snd_soc_read(codec,
2177 tabla->mbhc_bias_regs.cfilt_val);
2178 cfilt_k_val = tabla_find_k_value(
2179 tabla->pdata->micbias.ldoh_v, 1800);
2180 snd_soc_update_bits(codec,
2181 tabla->mbhc_bias_regs.cfilt_val,
2182 0xFC, (cfilt_k_val << 2));
2183
2184 snd_soc_update_bits(codec,
2185 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
2186 snd_soc_update_bits(codec,
2187 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002188 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002189
2190 tabla->mbhc_micbias_switched = true;
Joonwoo Park0976d012011-12-22 11:48:18 -08002191 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002192 }
2193 break;
2194
2195 case 0:
2196 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002197 if (tabla->mbhc_polling_active) {
2198 tabla_codec_pause_hs_polling(codec);
2199 mbhc_was_polling = true;
2200 }
Joonwoo Park0976d012011-12-22 11:48:18 -08002201 /* VDDIO switch disabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002202 if (tabla->cfilt_k_value != 0)
2203 snd_soc_update_bits(codec,
2204 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
2205 tabla->cfilt_k_value);
2206 snd_soc_update_bits(codec,
2207 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
2208 snd_soc_update_bits(codec,
2209 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
2210
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002211 if (mbhc_was_polling)
2212 tabla_codec_start_hs_polling(codec);
2213
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002214 tabla->mbhc_micbias_switched = false;
Joonwoo Park0976d012011-12-22 11:48:18 -08002215 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002216 }
2217 break;
2218 }
2219}
2220
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002221static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2222 struct snd_kcontrol *kcontrol, int event)
2223{
2224 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002225 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2226 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002227 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002228 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002229 char *internal1_text = "Internal1";
2230 char *internal2_text = "Internal2";
2231 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232
2233 pr_debug("%s %d\n", __func__, event);
2234 switch (w->reg) {
2235 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002236 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002237 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002238 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002239 break;
2240 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002242 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002243 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244 break;
2245 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002246 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002247 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002248 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002249 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002250 case TABLA_1_A_MICB_4_CTL:
2251 case TABLA_2_A_MICB_4_CTL:
2252 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002253 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002254 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002255 break;
2256 default:
2257 pr_err("%s: Error, invalid micbias register\n", __func__);
2258 return -EINVAL;
2259 }
2260
2261 switch (event) {
2262 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002263 /* Decide whether to switch the micbias for MBHC */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002264 if (w->reg == tabla->mbhc_bias_regs.ctl_reg) {
2265 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002266 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002267 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2268 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002269
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002270 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002271 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002272
2273 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002274 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002275 else if (strnstr(w->name, internal2_text, 30))
2276 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2277 else if (strnstr(w->name, internal3_text, 30))
2278 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002281 case SND_SOC_DAPM_POST_PMU:
2282 if (tabla->mbhc_polling_active &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002283 tabla->mbhc_cfg.micbias == micb_line) {
2284 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002285 tabla_codec_pause_hs_polling(codec);
2286 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002287 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002288 }
2289 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002290
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002291 case SND_SOC_DAPM_POST_PMD:
Joonwoo Park03324832012-03-19 19:36:16 -07002292 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg) &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002293 tabla_is_hph_pa_on(codec)) {
2294 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002295 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002296 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2297 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002298
Bradley Rubin229c6a52011-07-12 16:18:48 -07002299 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002300 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002301 else if (strnstr(w->name, internal2_text, 30))
2302 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2303 else if (strnstr(w->name, internal3_text, 30))
2304 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2305
Patrick Lai3043fba2011-08-01 14:15:57 -07002306 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002307 break;
2308 }
2309
2310 return 0;
2311}
2312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002313static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
2314 struct snd_kcontrol *kcontrol, int event)
2315{
2316 struct snd_soc_codec *codec = w->codec;
2317 u16 dec_reset_reg;
2318
2319 pr_debug("%s %d\n", __func__, event);
2320
2321 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
2322 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
2323 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
2324 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
2325 else {
2326 pr_err("%s: Error, incorrect dec\n", __func__);
2327 return -EINVAL;
2328 }
2329
2330 switch (event) {
2331 case SND_SOC_DAPM_PRE_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002332 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2333 1 << w->shift);
2334 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
2335 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002336 }
2337 return 0;
2338}
2339
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002340static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341 struct snd_kcontrol *kcontrol, int event)
2342{
2343 struct snd_soc_codec *codec = w->codec;
2344
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002345 pr_debug("%s %d %s\n", __func__, event, w->name);
2346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002347 switch (event) {
2348 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002349 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2350 1 << w->shift, 1 << w->shift);
2351 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2352 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002353 break;
2354 }
2355 return 0;
2356}
2357
Bradley Rubin229c6a52011-07-12 16:18:48 -07002358static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2359 struct snd_kcontrol *kcontrol, int event)
2360{
2361 switch (event) {
2362 case SND_SOC_DAPM_POST_PMU:
2363 case SND_SOC_DAPM_POST_PMD:
2364 usleep_range(1000, 1000);
2365 break;
2366 }
2367 return 0;
2368}
2369
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002370static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2371 struct snd_kcontrol *kcontrol, int event)
2372{
2373 struct snd_soc_codec *codec = w->codec;
2374
2375 pr_debug("%s %d\n", __func__, event);
2376
2377 switch (event) {
2378 case SND_SOC_DAPM_PRE_PMU:
2379 tabla_enable_rx_bias(codec, 1);
2380 break;
2381 case SND_SOC_DAPM_POST_PMD:
2382 tabla_enable_rx_bias(codec, 0);
2383 break;
2384 }
2385 return 0;
2386}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002387static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
2388 struct snd_kcontrol *kcontrol, int event)
2389{
2390 struct snd_soc_codec *codec = w->codec;
2391
2392 pr_debug("%s %s %d\n", __func__, w->name, event);
2393
2394 switch (event) {
2395 case SND_SOC_DAPM_PRE_PMU:
2396 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2397 break;
2398 case SND_SOC_DAPM_POST_PMD:
2399 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2400 break;
2401 }
2402 return 0;
2403}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002404
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002405static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
2406 struct snd_soc_jack *jack, int status,
2407 int mask)
2408{
2409 /* XXX: wake_lock_timeout()? */
Joonwoo Park03324832012-03-19 19:36:16 -07002410 snd_soc_jack_report_no_dapm(jack, status, mask);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002411}
2412
Patrick Lai49efeac2011-11-03 11:01:12 -07002413static void hphocp_off_report(struct tabla_priv *tabla,
2414 u32 jack_status, int irq)
2415{
2416 struct snd_soc_codec *codec;
Joonwoo Park03324832012-03-19 19:36:16 -07002417 if (!tabla) {
2418 pr_err("%s: Bad tabla private data\n", __func__);
2419 return;
2420 }
Patrick Lai49efeac2011-11-03 11:01:12 -07002421
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002422 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
Joonwoo Park03324832012-03-19 19:36:16 -07002423 codec = tabla->codec;
2424 if (tabla->hph_status & jack_status) {
Patrick Lai49efeac2011-11-03 11:01:12 -07002425 tabla->hph_status &= ~jack_status;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002426 if (tabla->mbhc_cfg.headset_jack)
2427 tabla_snd_soc_jack_report(tabla,
2428 tabla->mbhc_cfg.headset_jack,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002429 tabla->hph_status,
2430 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08002431 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2432 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08002433 /* reset retry counter as PA is turned off signifying
2434 * start of new OCP detection session
2435 */
2436 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
2437 tabla->hphlocp_cnt = 0;
2438 else
2439 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302440 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07002441 }
2442}
2443
2444static void hphlocp_off_report(struct work_struct *work)
2445{
2446 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2447 hphlocp_work);
2448 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
2449}
2450
2451static void hphrocp_off_report(struct work_struct *work)
2452{
2453 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2454 hphrocp_work);
2455 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
2456}
2457
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002458static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
2459 struct snd_kcontrol *kcontrol, int event)
2460{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002461 struct snd_soc_codec *codec = w->codec;
2462 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2463 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002464 pr_debug("%s: event = %d\n", __func__, event);
2465
2466 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002467 case SND_SOC_DAPM_PRE_PMU:
2468 mbhc_micb_ctl_val = snd_soc_read(codec,
2469 tabla->mbhc_bias_regs.ctl_reg);
2470
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002471 if (!(mbhc_micb_ctl_val & 0x80)) {
2472 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002473 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002474 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2475 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002476 break;
2477
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002478 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07002479 /* schedule work is required because at the time HPH PA DAPM
2480 * event callback is called by DAPM framework, CODEC dapm mutex
2481 * would have been locked while snd_soc_jack_report also
2482 * attempts to acquire same lock.
2483 */
Joonwoo Parka9444452011-12-08 18:48:27 -08002484 if (w->shift == 5) {
2485 clear_bit(TABLA_HPHL_PA_OFF_ACK,
2486 &tabla->hph_pa_dac_state);
2487 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
2488 &tabla->hph_pa_dac_state);
2489 if (tabla->hph_status & SND_JACK_OC_HPHL)
2490 schedule_work(&tabla->hphlocp_work);
2491 } else if (w->shift == 4) {
2492 clear_bit(TABLA_HPHR_PA_OFF_ACK,
2493 &tabla->hph_pa_dac_state);
2494 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
2495 &tabla->hph_pa_dac_state);
2496 if (tabla->hph_status & SND_JACK_OC_HPHR)
2497 schedule_work(&tabla->hphrocp_work);
2498 }
2499
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002500 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park03324832012-03-19 19:36:16 -07002501 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002502 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002503
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002504 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
2505 w->name);
2506 usleep_range(10000, 10000);
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002507 break;
2508 }
2509 return 0;
2510}
2511
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002512static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002513 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002514{
2515 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002516 unsigned int cfilt;
2517
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002518 switch (tabla->mbhc_cfg.micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002519 case TABLA_MICBIAS1:
2520 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
2521 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
2522 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
2523 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
2524 break;
2525 case TABLA_MICBIAS2:
2526 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
2527 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
2528 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
2529 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
2530 break;
2531 case TABLA_MICBIAS3:
2532 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
2533 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
2534 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
2535 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
2536 break;
2537 case TABLA_MICBIAS4:
2538 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002539 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
2540 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
2541 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002542 break;
2543 default:
2544 /* Should never reach here */
2545 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07002546 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002547 }
2548
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002549 micbias_regs->cfilt_sel = cfilt;
2550
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002551 switch (cfilt) {
2552 case TABLA_CFILT1_SEL:
2553 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
2554 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002555 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002556 break;
2557 case TABLA_CFILT2_SEL:
2558 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
2559 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002560 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002561 break;
2562 case TABLA_CFILT3_SEL:
2563 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
2564 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002565 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002566 break;
2567 }
2568}
Santosh Mardie15e2302011-11-15 10:39:23 +05302569static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
2570 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
2571 4, 0, NULL, 0),
2572 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
2573 0, NULL, 0),
2574};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002575
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002576static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
2577 struct snd_kcontrol *kcontrol, int event)
2578{
2579 struct snd_soc_codec *codec = w->codec;
2580
2581 pr_debug("%s %s %d\n", __func__, w->name, event);
2582
2583 switch (event) {
2584 case SND_SOC_DAPM_PRE_PMU:
2585 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2586 break;
2587
2588 case SND_SOC_DAPM_POST_PMD:
2589 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2590 break;
2591 }
2592 return 0;
2593}
2594
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002595static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
2596 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302597 0, tabla_codec_enable_micbias,
2598 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2599 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002600};
2601
2602static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
2603 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302604 0, tabla_codec_enable_micbias,
2605 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2606 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002607};
2608
Santosh Mardie15e2302011-11-15 10:39:23 +05302609static const struct snd_soc_dapm_route audio_i2s_map[] = {
2610 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2611 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2612 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2613 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2614 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2615
2616 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2617 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2618 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2619 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2620};
2621
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002622static const struct snd_soc_dapm_route audio_map[] = {
2623 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002624
2625 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2626 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2627
2628 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2629 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2630
2631 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2632 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2633
2634 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2635 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002636 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002637 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2638 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002639 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2640 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002641 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2642 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002643 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2644 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002645
2646 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002647 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2648 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2649 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002650 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2652 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2653
Kiran Kandi3426e512011-09-13 22:50:10 -07002654 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
2655 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
2656 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
2657 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
2658 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
2659 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
2660 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
2661 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
2662 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
2663 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
2664 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
2665
2666 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
2667 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
2668 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
2669 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
2670 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
2671 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
2672 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
2673 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
2674 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
2675 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
2676 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
2677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002678 /* Earpiece (RX MIX1) */
2679 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002680 {"EAR PA", NULL, "EAR_PA_MIXER"},
2681 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002682 {"DAC1", NULL, "CP"},
2683
2684 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2685 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2686 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687
2688 /* Headset (RX MIX1 and RX MIX2) */
2689 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002691
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002692 {"HPHL", NULL, "HPHL_PA_MIXER"},
2693 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
2694
2695 {"HPHR", NULL, "HPHR_PA_MIXER"},
2696 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002697
2698 {"HPHL DAC", NULL, "CP"},
2699 {"HPHR DAC", NULL, "CP"},
2700
2701 {"ANC", NULL, "ANC1 MUX"},
2702 {"ANC", NULL, "ANC2 MUX"},
2703 {"ANC1 MUX", "ADC1", "ADC1"},
2704 {"ANC1 MUX", "ADC2", "ADC2"},
2705 {"ANC1 MUX", "ADC3", "ADC3"},
2706 {"ANC1 MUX", "ADC4", "ADC4"},
2707 {"ANC2 MUX", "ADC1", "ADC1"},
2708 {"ANC2 MUX", "ADC2", "ADC2"},
2709 {"ANC2 MUX", "ADC3", "ADC3"},
2710 {"ANC2 MUX", "ADC4", "ADC4"},
2711
Bradley Rubine1d08622011-07-20 18:01:35 -07002712 {"ANC", NULL, "CDC_CONN"},
2713
Bradley Rubin229c6a52011-07-12 16:18:48 -07002714 {"DAC1", "Switch", "RX1 CHAIN"},
2715 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002716 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002717
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002718 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2719 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2720 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2721 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2722 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002723
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002724 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2725 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
2726 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2727 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2728 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
2729 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
2730 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
2731 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
2732 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
2733 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002734
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002735 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2736 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2737
Bradley Rubin229c6a52011-07-12 16:18:48 -07002738 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2739 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2740 {"RX1 CHAIN", NULL, "ANC"},
2741 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002742
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002743 {"CP", NULL, "RX_BIAS"},
2744 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2745 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2746 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2747 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002748 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002749
Kuirong Wang0f8ade32012-02-27 16:29:45 -08002750 {"RX1 MIX1", NULL, "COMP1_CLK"},
2751 {"RX2 MIX1", NULL, "COMP1_CLK"},
2752 {"RX3 MIX1", NULL, "COMP2_CLK"},
2753 {"RX5 MIX1", NULL, "COMP2_CLK"},
2754
2755
Bradley Rubin229c6a52011-07-12 16:18:48 -07002756 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2757 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2758 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2759 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002760 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2761 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2762 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2763 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2764 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2765 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2766 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2767 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002768 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2769 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002770
Bradley Rubin229c6a52011-07-12 16:18:48 -07002771 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2772 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302773 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2774 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002775 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
2776 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002777 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2778 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2779 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302780 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2781 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002782 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
2783 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002784 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2785 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2786 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302787 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2788 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002789 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
2790 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002791 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002792 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2793 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302794 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2795 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002796 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
2797 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002798 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002799 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2800 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302801 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2802 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002803 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
2804 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002805 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002806 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2807 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302808 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2809 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002810 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
2811 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002812 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002813 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2814 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302815 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2816 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002817 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
2818 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002819 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002820 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2821 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302822 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2823 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002824 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
2825 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002826 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002827 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2828 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302829 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2830 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002831 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
2832 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002833 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002834 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2835 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302836 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2837 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002838 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
2839 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002840 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002841 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2842 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302843 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2844 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002845 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
2846 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002847 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002848 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2849 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302850 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2851 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002852 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
2853 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002854 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002855 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2856 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302857 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2858 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002859 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
2860 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002861 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002862 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2863 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302864 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2865 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002866 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
2867 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002868 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002869
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002870 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002871 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002872 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002873 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002874 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002875 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002876 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002877 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002878 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002879 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002880 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002881 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002882 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002883 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002884 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002885 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002886 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002887 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002888 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002889 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002890 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002891 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002892 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002893 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002894 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002895 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002896 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002897 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002898
2899 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002900 {"ADC1", NULL, "AMIC1"},
2901 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002902 {"ADC3", NULL, "AMIC3"},
2903 {"ADC4", NULL, "AMIC4"},
2904 {"ADC5", NULL, "AMIC5"},
2905 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002906
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002907 /* AUX PGA Connections */
2908 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2909 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2910 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2911 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2912 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2913 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2914 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2915 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2916 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2917 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2918 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2919 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2920 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2921 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2922 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2923 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2924 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2925 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2926 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2927 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2928 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2929 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2930 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2931 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2932 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2933 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2934 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2935 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2936 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2937 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2938 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
2939 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
2940 {"AUX_PGA_Left", NULL, "AMIC5"},
2941 {"AUX_PGA_Right", NULL, "AMIC6"},
2942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002943 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002944 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2945 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2946 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2947 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2948 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002949 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07002950 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
2951 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
2952 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
2953 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002954
2955 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2956 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2957 {"MIC BIAS1 External", NULL, "LDO_H"},
2958 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2959 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2960 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2961 {"MIC BIAS2 External", NULL, "LDO_H"},
2962 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2963 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2964 {"MIC BIAS3 External", NULL, "LDO_H"},
2965 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002966};
2967
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002968static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
2969
2970 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2971 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2972
2973 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
2974
2975 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
2976 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
2977 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
2978
2979 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2980 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2981
2982 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
2983 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
2984 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
2985};
2986
Kiran Kandi7a9fd902011-11-14 13:51:45 -08002987
2988static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
2989
2990 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
2991 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
2992
2993 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
2994
2995 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
2996
2997 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
2998 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
2999
3000 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3001};
3002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003003static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
3004{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003005 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303006 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003007
3008 if (TABLA_IS_1_X(tabla_core->version)) {
3009 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
3010 if (tabla_1_reg_readable[i] == reg)
3011 return 1;
3012 }
3013 } else {
3014 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
3015 if (tabla_2_reg_readable[i] == reg)
3016 return 1;
3017 }
3018 }
3019
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003020 return tabla_reg_readable[reg];
3021}
3022
3023static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3024{
3025 /* Registers lower than 0x100 are top level registers which can be
3026 * written by the Tabla core driver.
3027 */
3028
3029 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3030 return 1;
3031
Ben Romberger1f045a72011-11-04 10:14:57 -07003032 /* IIR Coeff registers are not cacheable */
3033 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
3034 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
3035 return 1;
3036
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003037 return 0;
3038}
3039
3040#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3041static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
3042 unsigned int value)
3043{
3044 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003045 BUG_ON(reg > TABLA_MAX_REGISTER);
3046
3047 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003048 ret = snd_soc_cache_write(codec, reg, value);
3049 if (ret != 0)
3050 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3051 reg, ret);
3052 }
3053
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303054 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003055}
3056static unsigned int tabla_read(struct snd_soc_codec *codec,
3057 unsigned int reg)
3058{
3059 unsigned int val;
3060 int ret;
3061
3062 BUG_ON(reg > TABLA_MAX_REGISTER);
3063
3064 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
3065 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066 ret = snd_soc_cache_read(codec, reg, &val);
3067 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003068 return val;
3069 } else
3070 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3071 reg, ret);
3072 }
3073
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303074 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003075 return val;
3076}
3077
Bradley Rubincb1e2732011-06-23 16:49:20 -07003078static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3079{
Joonwoo Parkc0672392012-01-11 11:03:14 -08003080 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08003081 struct tabla_mbhc_btn_detect_cfg *btn_det;
3082 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003083 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003084
Joonwoo Park0976d012011-12-22 11:48:18 -08003085 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
3086 tabla->mbhc_data.v_ins_hu & 0xFF);
3087 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
3088 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003089
Joonwoo Park0976d012011-12-22 11:48:18 -08003090 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
3091 tabla->mbhc_data.v_b1_hu & 0xFF);
3092 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
3093 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
3094
3095 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
3096 tabla->mbhc_data.v_b1_h & 0xFF);
3097 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
3098 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
3099
3100 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
3101 tabla->mbhc_data.v_brh & 0xFF);
3102 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
3103 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
3104
3105 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
3106 tabla->mbhc_data.v_brl & 0xFF);
3107 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
3108 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
3109
Joonwoo Parkc0672392012-01-11 11:03:14 -08003110 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003111 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08003112 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003113 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
3114 tabla->mbhc_data.npoll);
3115 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
3116 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08003117 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003118 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
3119 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003120}
3121
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003122static int tabla_startup(struct snd_pcm_substream *substream,
3123 struct snd_soc_dai *dai)
3124{
Kuirong Wanga545e722012-02-06 19:12:54 -08003125 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003126 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3127 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003128 if ((tabla_core != NULL) &&
3129 (tabla_core->dev != NULL) &&
3130 (tabla_core->dev->parent != NULL))
3131 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003132
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003133 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003134}
3135
3136static void tabla_shutdown(struct snd_pcm_substream *substream,
3137 struct snd_soc_dai *dai)
3138{
Kuirong Wanga545e722012-02-06 19:12:54 -08003139 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003140 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3141 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003142 if ((tabla_core != NULL) &&
3143 (tabla_core->dev != NULL) &&
3144 (tabla_core->dev->parent != NULL)) {
3145 pm_runtime_mark_last_busy(tabla_core->dev->parent);
3146 pm_runtime_put(tabla_core->dev->parent);
3147 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003148}
3149
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003150int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003151{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003152 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3153
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003154 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003155
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003156 if (dapm)
3157 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003158 if (mclk_enable) {
3159 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003160
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003161 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07003162 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003164 TABLA_BANDGAP_AUDIO_MODE);
3165 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003166 tabla_codec_calibrate_hs_polling(codec);
3167 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303168 } else {
3169 tabla_codec_enable_bandgap(codec,
3170 TABLA_BANDGAP_AUDIO_MODE);
3171 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003172 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003173 } else {
3174
3175 if (!tabla->mclk_enabled) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003176 if (dapm)
3177 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003178 pr_err("Error, MCLK already diabled\n");
3179 return -EINVAL;
3180 }
3181 tabla->mclk_enabled = false;
3182
3183 if (tabla->mbhc_polling_active) {
3184 if (!tabla->mclk_enabled) {
3185 tabla_codec_pause_hs_polling(codec);
3186 tabla_codec_enable_bandgap(codec,
3187 TABLA_BANDGAP_MBHC_MODE);
3188 tabla_enable_rx_bias(codec, 1);
3189 tabla_codec_enable_clock_block(codec, 1);
3190 tabla_codec_calibrate_hs_polling(codec);
3191 tabla_codec_start_hs_polling(codec);
3192 }
3193 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
3194 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303195 } else {
3196 tabla_codec_disable_clock_block(codec);
3197 tabla_codec_enable_bandgap(codec,
3198 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003199 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003201 if (dapm)
3202 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003203 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003204}
3205
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003206static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
3207 int clk_id, unsigned int freq, int dir)
3208{
3209 pr_debug("%s\n", __func__);
3210 return 0;
3211}
3212
3213static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3214{
Santosh Mardie15e2302011-11-15 10:39:23 +05303215 u8 val = 0;
3216 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3217
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003218 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05303219 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3220 case SND_SOC_DAIFMT_CBS_CFS:
3221 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303222 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003223 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303224 snd_soc_update_bits(dai->codec,
3225 TABLA_A_CDC_CLK_TX_I2S_CTL,
3226 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003227 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303228 snd_soc_update_bits(dai->codec,
3229 TABLA_A_CDC_CLK_RX_I2S_CTL,
3230 TABLA_I2S_MASTER_MODE_MASK, 0);
3231 }
3232 break;
3233 case SND_SOC_DAIFMT_CBM_CFM:
3234 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303235 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303236 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003237 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303238 snd_soc_update_bits(dai->codec,
3239 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003240 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303241 snd_soc_update_bits(dai->codec,
3242 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
3243 }
3244 break;
3245 default:
3246 return -EINVAL;
3247 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003248 return 0;
3249}
3250
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003251static int tabla_set_channel_map(struct snd_soc_dai *dai,
3252 unsigned int tx_num, unsigned int *tx_slot,
3253 unsigned int rx_num, unsigned int *rx_slot)
3254
3255{
3256 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3257 u32 i = 0;
3258 if (!tx_slot && !rx_slot) {
3259 pr_err("%s: Invalid\n", __func__);
3260 return -EINVAL;
3261 }
3262 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3263
Neema Shettyd3a89262012-02-16 10:23:50 -08003264 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003265 for (i = 0; i < rx_num; i++) {
3266 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
3267 tabla->dai[dai->id - 1].ch_act = 0;
3268 tabla->dai[dai->id - 1].ch_tot = rx_num;
3269 }
3270 } else if (dai->id == AIF1_CAP) {
3271 for (i = 0; i < tx_num; i++) {
3272 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
3273 tabla->dai[dai->id - 1].ch_act = 0;
3274 tabla->dai[dai->id - 1].ch_tot = tx_num;
3275 }
3276 }
3277 return 0;
3278}
3279
3280static int tabla_get_channel_map(struct snd_soc_dai *dai,
3281 unsigned int *tx_num, unsigned int *tx_slot,
3282 unsigned int *rx_num, unsigned int *rx_slot)
3283
3284{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303285 struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003286
3287 u32 cnt = 0;
3288 u32 tx_ch[SLIM_MAX_TX_PORTS];
3289 u32 rx_ch[SLIM_MAX_RX_PORTS];
3290
3291 if (!rx_slot && !tx_slot) {
3292 pr_err("%s: Invalid\n", __func__);
3293 return -EINVAL;
3294 }
3295 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
3296 /* for virtual port, codec driver needs to do
3297 * housekeeping, for now should be ok
3298 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303299 wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003300 if (dai->id == AIF1_PB) {
3301 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3302 while (cnt < *rx_num) {
3303 rx_slot[cnt] = rx_ch[cnt];
3304 cnt++;
3305 }
3306 } else if (dai->id == AIF1_CAP) {
3307 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3308 while (cnt < *tx_num) {
3309 tx_slot[cnt] = tx_ch[6 + cnt];
3310 cnt++;
3311 }
Neema Shettyd3a89262012-02-16 10:23:50 -08003312 } else if (dai->id == AIF2_PB) {
3313 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3314 while (cnt < *rx_num) {
3315 rx_slot[cnt] = rx_ch[5 + cnt];
3316 cnt++;
3317 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003318 }
3319 return 0;
3320}
3321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003322static int tabla_hw_params(struct snd_pcm_substream *substream,
3323 struct snd_pcm_hw_params *params,
3324 struct snd_soc_dai *dai)
3325{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003326 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05303327 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07003328 u8 path, shift;
3329 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003330 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003331 u32 compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003332
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003333 pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
3334 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003335
3336 switch (params_rate(params)) {
3337 case 8000:
3338 tx_fs_rate = 0x00;
3339 rx_fs_rate = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003340 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003341 break;
3342 case 16000:
3343 tx_fs_rate = 0x01;
3344 rx_fs_rate = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003345 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003346 break;
3347 case 32000:
3348 tx_fs_rate = 0x02;
3349 rx_fs_rate = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003350 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003351 break;
3352 case 48000:
3353 tx_fs_rate = 0x03;
3354 rx_fs_rate = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003355 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003356 break;
3357 default:
3358 pr_err("%s: Invalid sampling rate %d\n", __func__,
3359 params_rate(params));
3360 return -EINVAL;
3361 }
3362
3363
3364 /**
3365 * If current dai is a tx dai, set sample rate to
3366 * all the txfe paths that are currently not active
3367 */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003368 if (dai->id == AIF1_CAP) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003369
3370 tx_state = snd_soc_read(codec,
3371 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3372
3373 for (path = 1, shift = 0;
3374 path <= NUM_DECIMATORS; path++, shift++) {
3375
3376 if (path == BITS_PER_REG + 1) {
3377 shift = 0;
3378 tx_state = snd_soc_read(codec,
3379 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
3380 }
3381
3382 if (!(tx_state & (1 << shift))) {
3383 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
3384 + (BITS_PER_REG*(path-1));
3385 snd_soc_update_bits(codec, tx_fs_reg,
3386 0x03, tx_fs_rate);
3387 }
3388 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303389 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303390 switch (params_format(params)) {
3391 case SNDRV_PCM_FORMAT_S16_LE:
3392 snd_soc_update_bits(codec,
3393 TABLA_A_CDC_CLK_TX_I2S_CTL,
3394 0x20, 0x20);
3395 break;
3396 case SNDRV_PCM_FORMAT_S32_LE:
3397 snd_soc_update_bits(codec,
3398 TABLA_A_CDC_CLK_TX_I2S_CTL,
3399 0x20, 0x00);
3400 break;
3401 default:
3402 pr_err("invalid format\n");
3403 break;
3404 }
3405 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
3406 0x03, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003407 } else {
3408 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303409 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003410 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003411 /**
3412 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3413 * with varying sample rates
3414 */
3415
3416 /**
3417 * If current dai is a rx dai, set sample rate to
3418 * all the rx paths that are currently not active
3419 */
Neema Shettyd3a89262012-02-16 10:23:50 -08003420 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003421
3422 rx_state = snd_soc_read(codec,
3423 TABLA_A_CDC_CLK_RX_B1_CTL);
3424
3425 for (path = 1, shift = 0;
3426 path <= NUM_INTERPOLATORS; path++, shift++) {
3427
3428 if (!(rx_state & (1 << shift))) {
3429 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
3430 + (BITS_PER_REG*(path-1));
3431 snd_soc_update_bits(codec, rx_fs_reg,
3432 0xE0, rx_fs_rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003433 if (comp_rx_path[shift] < COMPANDER_MAX)
3434 tabla->comp_fs[comp_rx_path[shift]]
3435 = compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003436 }
3437 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303438 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303439 switch (params_format(params)) {
3440 case SNDRV_PCM_FORMAT_S16_LE:
3441 snd_soc_update_bits(codec,
3442 TABLA_A_CDC_CLK_RX_I2S_CTL,
3443 0x20, 0x20);
3444 break;
3445 case SNDRV_PCM_FORMAT_S32_LE:
3446 snd_soc_update_bits(codec,
3447 TABLA_A_CDC_CLK_RX_I2S_CTL,
3448 0x20, 0x00);
3449 break;
3450 default:
3451 pr_err("invalid format\n");
3452 break;
3453 }
3454 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
3455 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003456 } else {
3457 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303458 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003459 }
3460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003461 return 0;
3462}
3463
3464static struct snd_soc_dai_ops tabla_dai_ops = {
3465 .startup = tabla_startup,
3466 .shutdown = tabla_shutdown,
3467 .hw_params = tabla_hw_params,
3468 .set_sysclk = tabla_set_dai_sysclk,
3469 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003470 .set_channel_map = tabla_set_channel_map,
3471 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003472};
3473
3474static struct snd_soc_dai_driver tabla_dai[] = {
3475 {
3476 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003477 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003478 .playback = {
3479 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003480 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003481 .formats = TABLA_FORMATS,
3482 .rate_max = 48000,
3483 .rate_min = 8000,
3484 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003485 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003486 },
3487 .ops = &tabla_dai_ops,
3488 },
3489 {
3490 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003491 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003492 .capture = {
3493 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003494 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003495 .formats = TABLA_FORMATS,
3496 .rate_max = 48000,
3497 .rate_min = 8000,
3498 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003499 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003500 },
3501 .ops = &tabla_dai_ops,
3502 },
Neema Shettyd3a89262012-02-16 10:23:50 -08003503 {
3504 .name = "tabla_rx2",
3505 .id = AIF2_PB,
3506 .playback = {
3507 .stream_name = "AIF2 Playback",
3508 .rates = WCD9310_RATES,
3509 .formats = TABLA_FORMATS,
3510 .rate_min = 8000,
3511 .rate_max = 48000,
3512 .channels_min = 1,
3513 .channels_max = 2,
3514 },
3515 .ops = &tabla_dai_ops,
3516 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003517};
Santosh Mardie15e2302011-11-15 10:39:23 +05303518
3519static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3520 {
3521 .name = "tabla_i2s_rx1",
3522 .id = 1,
3523 .playback = {
3524 .stream_name = "AIF1 Playback",
3525 .rates = WCD9310_RATES,
3526 .formats = TABLA_FORMATS,
3527 .rate_max = 48000,
3528 .rate_min = 8000,
3529 .channels_min = 1,
3530 .channels_max = 4,
3531 },
3532 .ops = &tabla_dai_ops,
3533 },
3534 {
3535 .name = "tabla_i2s_tx1",
3536 .id = 2,
3537 .capture = {
3538 .stream_name = "AIF1 Capture",
3539 .rates = WCD9310_RATES,
3540 .formats = TABLA_FORMATS,
3541 .rate_max = 48000,
3542 .rate_min = 8000,
3543 .channels_min = 1,
3544 .channels_max = 4,
3545 },
3546 .ops = &tabla_dai_ops,
3547 },
3548};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003549
3550static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3551 struct snd_kcontrol *kcontrol, int event)
3552{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303553 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003554 struct snd_soc_codec *codec = w->codec;
3555 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3556 u32 j = 0;
3557 u32 ret = 0;
3558 codec->control_data = dev_get_drvdata(codec->dev->parent);
3559 tabla = codec->control_data;
3560 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303561 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003562 return 0;
3563 switch (event) {
3564 case SND_SOC_DAPM_POST_PMU:
3565 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3566 if (tabla_dai[j].id == AIF1_CAP)
3567 continue;
3568 if (!strncmp(w->sname,
3569 tabla_dai[j].playback.stream_name, 13)) {
3570 ++tabla_p->dai[j].ch_act;
3571 break;
3572 }
3573 }
3574 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303575 ret = wcd9xxx_cfg_slim_sch_rx(tabla,
3576 tabla_p->dai[j].ch_num,
3577 tabla_p->dai[j].ch_tot,
3578 tabla_p->dai[j].rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003579 break;
3580 case SND_SOC_DAPM_POST_PMD:
3581 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3582 if (tabla_dai[j].id == AIF1_CAP)
3583 continue;
3584 if (!strncmp(w->sname,
3585 tabla_dai[j].playback.stream_name, 13)) {
3586 --tabla_p->dai[j].ch_act;
3587 break;
3588 }
3589 }
3590 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303591 ret = wcd9xxx_close_slim_sch_rx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003592 tabla_p->dai[j].ch_num,
3593 tabla_p->dai[j].ch_tot);
Bharath Ramachandramurthyda6fa7a2012-03-30 14:35:32 -07003594 usleep_range(5000, 5000);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003595 tabla_p->dai[j].rate = 0;
3596 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303597 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003598 tabla_p->dai[j].ch_tot = 0;
3599 }
3600 }
3601 return ret;
3602}
3603
3604static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3605 struct snd_kcontrol *kcontrol, int event)
3606{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303607 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003608 struct snd_soc_codec *codec = w->codec;
3609 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3610 /* index to the DAI ID, for now hardcoding */
3611 u32 j = 0;
3612 u32 ret = 0;
3613
3614 codec->control_data = dev_get_drvdata(codec->dev->parent);
3615 tabla = codec->control_data;
3616
3617 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303618 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003619 return 0;
3620 switch (event) {
3621 case SND_SOC_DAPM_POST_PMU:
3622 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003623 if (tabla_dai[j].id == AIF1_PB ||
3624 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003625 continue;
3626 if (!strncmp(w->sname,
3627 tabla_dai[j].capture.stream_name, 13)) {
3628 ++tabla_p->dai[j].ch_act;
3629 break;
3630 }
3631 }
3632 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303633 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003634 tabla_p->dai[j].ch_num,
3635 tabla_p->dai[j].ch_tot,
3636 tabla_p->dai[j].rate);
3637 break;
3638 case SND_SOC_DAPM_POST_PMD:
3639 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003640 if (tabla_dai[j].id == AIF1_PB ||
3641 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003642 continue;
3643 if (!strncmp(w->sname,
3644 tabla_dai[j].capture.stream_name, 13)) {
3645 --tabla_p->dai[j].ch_act;
3646 break;
3647 }
3648 }
3649 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303650 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003651 tabla_p->dai[j].ch_num,
3652 tabla_p->dai[j].ch_tot);
3653 tabla_p->dai[j].rate = 0;
3654 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303655 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003656 tabla_p->dai[j].ch_tot = 0;
3657 }
3658 }
3659 return ret;
3660}
3661
3662/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3663 * Might Need to have callbacks registered only for slimbus
3664 */
3665static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
3666 /*RX stuff */
3667 SND_SOC_DAPM_OUTPUT("EAR"),
3668
3669 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
3670
3671 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
3672 ARRAY_SIZE(dac1_switch)),
3673
3674 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3675 0, tabla_codec_enable_slimrx,
3676 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3677 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3678 0, tabla_codec_enable_slimrx,
3679 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3680
3681 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3682 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3683
Neema Shettyd3a89262012-02-16 10:23:50 -08003684 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3685 0, tabla_codec_enable_slimrx,
3686 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3687 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3688 0, tabla_codec_enable_slimrx,
3689 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3690
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003691 /* Headphone */
3692 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3693 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3694 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3695 SND_SOC_DAPM_POST_PMD),
3696 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
3697 hphl_switch, ARRAY_SIZE(hphl_switch)),
3698
3699 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
3700 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3701 SND_SOC_DAPM_POST_PMD),
3702
3703 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
3704 tabla_hphr_dac_event,
3705 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3706
3707 /* Speaker */
3708 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
3709 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
3710 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
3711 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
3712 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
3713
3714 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
3715 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3716 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3717 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
3718 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3719 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3720 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
3721 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3722 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3723 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
3724 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3725 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3726 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
3727 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3728 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3729
3730 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
3731 , tabla_lineout_dac_event,
3732 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3733 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
3734 , tabla_lineout_dac_event,
3735 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3736 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
3737 , tabla_lineout_dac_event,
3738 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3739 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
3740 &lineout3_ground_switch),
3741 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
3742 , tabla_lineout_dac_event,
3743 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3744 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
3745 &lineout4_ground_switch),
3746 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
3747 , tabla_lineout_dac_event,
3748 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3749
3750 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
3751 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3752 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
3753 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3754 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
3755 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3756 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
3757 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3758 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
3759 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3760 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
3761 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3762 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
3763 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3764
3765 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
3766 &rx4_dsm_mux, tabla_codec_reset_interpolator,
3767 SND_SOC_DAPM_PRE_PMU),
3768
3769 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
3770 &rx6_dsm_mux, tabla_codec_reset_interpolator,
3771 SND_SOC_DAPM_PRE_PMU),
3772
3773 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
3774 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
3775
3776 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3777 &rx_mix1_inp1_mux),
3778 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3779 &rx_mix1_inp2_mux),
3780 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3781 &rx2_mix1_inp1_mux),
3782 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3783 &rx2_mix1_inp2_mux),
3784 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3785 &rx3_mix1_inp1_mux),
3786 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3787 &rx3_mix1_inp2_mux),
3788 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3789 &rx4_mix1_inp1_mux),
3790 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3791 &rx4_mix1_inp2_mux),
3792 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3793 &rx5_mix1_inp1_mux),
3794 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3795 &rx5_mix1_inp2_mux),
3796 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3797 &rx6_mix1_inp1_mux),
3798 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3799 &rx6_mix1_inp2_mux),
3800 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3801 &rx7_mix1_inp1_mux),
3802 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3803 &rx7_mix1_inp2_mux),
3804
3805 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
3806 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
3807 SND_SOC_DAPM_PRE_PMD),
3808
3809 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
3810 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
3811 SND_SOC_DAPM_POST_PMD),
3812
3813 /* TX */
3814
3815 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
3816 0),
3817
3818 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
3819 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
3820
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003821 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
3822 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3823 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3824 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
3825 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3826 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3827
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003828 SND_SOC_DAPM_INPUT("AMIC1"),
3829 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
3830 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3831 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3832 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
3833 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3834 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3835 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
3836 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3837 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3838 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
3839 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3840 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3841
3842 SND_SOC_DAPM_INPUT("AMIC3"),
3843 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
3844 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3845 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3846
3847 SND_SOC_DAPM_INPUT("AMIC4"),
3848 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
3849 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3850 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3851
3852 SND_SOC_DAPM_INPUT("AMIC5"),
3853 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
3854 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3855
3856 SND_SOC_DAPM_INPUT("AMIC6"),
3857 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
3858 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3859
3860 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
3861 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3862
3863 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
3864 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3865
3866 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
3867 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3868
3869 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
3870 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3871
3872 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
3873 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3874
3875 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
3876 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3877
3878 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
3879 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3880
3881 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
3882 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3883
3884 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
3885 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3886
3887 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
3888 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3889
3890 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
3891 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
3892
3893 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
3894 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
3895 SND_SOC_DAPM_POST_PMD),
3896
3897 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
3898
3899 SND_SOC_DAPM_INPUT("AMIC2"),
3900 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
3901 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3902 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3903 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
3904 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3905 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3906 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
3907 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3908 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3909 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
3910 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3911 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3912 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
3913 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3914 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3915 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
3916 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3917 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3918 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
3919 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3920 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3921 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
3922 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3923 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3924
3925 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
3926 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
3927 0, 0),
3928
3929 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
3930 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
3931 4, 0),
3932
3933 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
3934 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
3935 5, 0),
3936
3937 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
3938 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3939 0, tabla_codec_enable_slimtx,
3940 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3941
3942 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
3943 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3944 0, tabla_codec_enable_slimtx,
3945 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3946
3947 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
3948 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
3949 0, 0, tabla_codec_enable_slimtx,
3950 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3951
3952 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
3953 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
3954 0, 0, tabla_codec_enable_slimtx,
3955 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3956
3957 /* Digital Mic Inputs */
3958 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
3959 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3960 SND_SOC_DAPM_POST_PMD),
3961
3962 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
3963 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3964 SND_SOC_DAPM_POST_PMD),
3965
3966 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
3967 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3968 SND_SOC_DAPM_POST_PMD),
3969
3970 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
3971 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3972 SND_SOC_DAPM_POST_PMD),
3973
3974 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
3975 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3976 SND_SOC_DAPM_POST_PMD),
3977 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
3978 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3979 SND_SOC_DAPM_POST_PMD),
3980
3981 /* Sidetone */
3982 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
3983 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003984
3985 /* AUX PGA */
3986 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
3987 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3988 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
3989 SND_SOC_DAPM_POST_PMD),
3990
3991 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
3992 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3993 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
3994 SND_SOC_DAPM_POST_PMD),
3995
3996 /* Lineout, ear and HPH PA Mixers */
3997 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
3998 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
3999
4000 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4001 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4002
4003 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4004 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4005
4006 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4007 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
4008
4009 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
4010 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
4011
4012 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
4013 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
4014
4015 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
4016 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
4017
4018 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4019 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004020};
4021
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004022static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004023{
4024 u8 bias_msb, bias_lsb;
4025 short bias_value;
4026
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004027 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
4028 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
4029 bias_value = (bias_msb << 8) | bias_lsb;
4030 return bias_value;
4031}
4032
4033static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
4034{
4035 u8 bias_msb, bias_lsb;
4036 short bias_value;
4037
4038 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
4039 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
4040 bias_value = (bias_msb << 8) | bias_lsb;
4041 return bias_value;
4042}
4043
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004044static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004045{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004046 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
4047}
4048
4049static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4050 bool override_bypass, bool noreldetection)
4051{
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004052 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004053 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4054
4055 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4056 if (noreldetection)
4057 tabla_turn_onoff_rel_detection(codec, false);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004058
Joonwoo Park925914c2012-01-05 13:35:18 -08004059 /* Turn on the override */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004060 if (!override_bypass)
4061 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004062 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004063 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4064 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
4065 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004066 usleep_range(tabla->mbhc_data.t_sta_dce,
4067 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004068 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08004069 usleep_range(tabla->mbhc_data.t_dce,
4070 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004071 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004072 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004073 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004074 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4075 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004076 usleep_range(tabla->mbhc_data.t_sta_dce,
4077 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08004078 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4079 usleep_range(tabla->mbhc_data.t_sta,
4080 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004081 bias_value = tabla_codec_read_sta_result(codec);
4082 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4083 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004084 }
Joonwoo Park925914c2012-01-05 13:35:18 -08004085 /* Turn off the override after measuring mic voltage */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004086 if (!override_bypass)
4087 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4088
4089 if (noreldetection)
4090 tabla_turn_onoff_rel_detection(codec, true);
4091 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004092
Bradley Rubincb1e2732011-06-23 16:49:20 -07004093 return bias_value;
4094}
4095
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004096static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4097 bool norel)
4098{
4099 return __tabla_codec_sta_dce(codec, dce, false, norel);
4100}
4101
4102/* called only from interrupt which is under codec_resource_lock acquisition */
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004103static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004104{
4105 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004106 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004107 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004109 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004110 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004111 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004112 }
4113
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004114 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004115 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004116 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004117 tabla_codec_enable_clock_block(codec, 1);
4118 }
4119
4120 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4121
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004122 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004123 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4124 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004125
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004126 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004127
4128 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004129 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004130
4131 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4132 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4133 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4134
4135 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004136 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4137 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004138
Joonwoo Park925914c2012-01-05 13:35:18 -08004139 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004140 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4141
Bradley Rubincb1e2732011-06-23 16:49:20 -07004142 tabla_codec_calibrate_hs_polling(codec);
4143
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004144 /* don't flip override */
4145 bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004146 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4147 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004148 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004149
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004150 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004151}
4152
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004153static int tabla_cancel_btn_work(struct tabla_priv *tabla)
4154{
4155 int r = 0;
4156 struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
4157
4158 if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
4159 /* if scheduled mbhc_btn_dwork is canceled from here,
4160 * we have to unlock from here instead btn_work */
4161 wcd9xxx_unlock_sleep(core);
4162 r = 1;
4163 }
4164 return r;
4165}
4166
4167/* called under codec_resource_lock acquisition */
4168void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
Joonwoo Park03324832012-03-19 19:36:16 -07004169{
4170 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004171 u8 wg_time;
4172
4173 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4174 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07004175
4176 /* If headphone PA is on, check if userspace receives
4177 * removal event to sync-up PA's state */
4178 if (tabla_is_hph_pa_on(codec)) {
4179 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4180 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4181 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4182 } else {
4183 pr_debug("%s PA is off\n", __func__);
4184 }
4185
4186 if (tabla_is_hph_dac_on(codec, 1))
4187 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4188 if (tabla_is_hph_dac_on(codec, 0))
4189 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004190
4191 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
4192 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
4193 0xC0, 0x00);
4194 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
4195 0xC0, 0x00);
4196 usleep_range(wg_time * 1000, wg_time * 1000);
4197}
4198
4199static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
4200{
4201 bool pa_turned_on = false;
4202 struct snd_soc_codec *codec = tabla->codec;
4203 u8 wg_time;
4204
4205 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4206 wg_time += 1;
4207
4208 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4209 &tabla->hph_pa_dac_state)) {
4210 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4211 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4212 0xC0, 0xC0);
4213 }
4214 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4215 &tabla->hph_pa_dac_state)) {
4216 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4217 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4218 0xC0, 0xC0);
4219 }
4220
4221 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4222 &tabla->hph_pa_dac_state)) {
4223 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4224 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4225 1 << 4);
4226 pa_turned_on = true;
4227 }
4228 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4229 &tabla->hph_pa_dac_state)) {
4230 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4231 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4232 1 << 5);
4233 pa_turned_on = true;
4234 }
4235
4236 if (pa_turned_on) {
4237 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4238 __func__);
4239 usleep_range(wg_time * 1000, wg_time * 1000);
4240 }
4241}
4242
4243/* called under codec_resource_lock acquisition */
4244static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4245 enum snd_jack_types jack_type)
4246{
4247 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4248
4249 if (!insertion) {
4250 /* Report removal */
4251 tabla->hph_status &= ~jack_type;
4252 if (tabla->mbhc_cfg.headset_jack) {
4253 /* cancel possibly scheduled btn work and
4254 * report release if we reported button press */
4255 if (tabla_cancel_btn_work(tabla)) {
4256 pr_debug("%s: button press is canceled\n",
4257 __func__);
4258 } else if (tabla->buttons_pressed) {
4259 pr_debug("%s: Reporting release for reported "
4260 "button press %d\n", __func__,
4261 jack_type);
4262 tabla_snd_soc_jack_report(tabla,
4263 tabla->mbhc_cfg.button_jack, 0,
4264 tabla->buttons_pressed);
4265 tabla->buttons_pressed &=
4266 ~TABLA_JACK_BUTTON_MASK;
4267 }
4268 pr_debug("%s: Reporting removal %d\n", __func__,
4269 jack_type);
4270 tabla_snd_soc_jack_report(tabla,
4271 tabla->mbhc_cfg.headset_jack,
4272 tabla->hph_status,
4273 TABLA_JACK_MASK);
4274 }
4275 tabla_set_and_turnoff_hph_padac(codec);
4276 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
4277 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4278 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
4279 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4280 tabla->current_plug = PLUG_TYPE_NONE;
4281 tabla->mbhc_polling_active = false;
4282 } else {
4283 /* Report insertion */
4284 tabla->hph_status |= jack_type;
4285
4286 if (jack_type == SND_JACK_HEADPHONE)
4287 tabla->current_plug = PLUG_TYPE_HEADPHONE;
4288 else if (jack_type == SND_JACK_HEADSET) {
4289 tabla->mbhc_polling_active = true;
4290 tabla->current_plug = PLUG_TYPE_HEADSET;
4291 }
4292 if (tabla->mbhc_cfg.headset_jack) {
4293 pr_debug("%s: Reporting insertion %d\n", __func__,
4294 jack_type);
4295 tabla_snd_soc_jack_report(tabla,
4296 tabla->mbhc_cfg.headset_jack,
4297 tabla->hph_status,
4298 TABLA_JACK_MASK);
4299 }
4300 tabla_clr_and_turnon_hph_padac(tabla);
4301 }
Joonwoo Park03324832012-03-19 19:36:16 -07004302}
4303
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004304static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07004305 int insertion, int trigger,
4306 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004307{
4308 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004309 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08004310 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004311 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004312 const struct tabla_mbhc_plug_detect_cfg *plug_det =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004313 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004314
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004315 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004316 pr_err("Error, no tabla calibration\n");
4317 return -EINVAL;
4318 }
4319
4320 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
4321
Joonwoo Park03324832012-03-19 19:36:16 -07004322 /* Make sure mic bias and Mic line schmitt trigger
4323 * are turned OFF
4324 */
4325 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
4326 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
4327
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004328 if (insertion) {
Joonwoo Park03324832012-03-19 19:36:16 -07004329 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004330
Joonwoo Park03324832012-03-19 19:36:16 -07004331 /* DAPM can manipulate PA/DAC bits concurrently */
4332 if (padac_off == true) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004333 tabla_set_and_turnoff_hph_padac(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004334 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004335
Joonwoo Park03324832012-03-19 19:36:16 -07004336 if (trigger == MBHC_USE_HPHL_TRIGGER) {
4337 /* Enable HPH Schmitt Trigger */
4338 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
4339 0x11);
4340 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
4341 plug_det->hph_current << 2);
4342 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
4343 0x02);
4344 } else if (trigger == MBHC_USE_MB_TRIGGER) {
4345 /* enable the mic line schmitt trigger */
4346 snd_soc_update_bits(codec,
4347 tabla->mbhc_bias_regs.mbhc_reg,
4348 0x60, plug_det->mic_current << 5);
4349 snd_soc_update_bits(codec,
4350 tabla->mbhc_bias_regs.mbhc_reg,
4351 0x80, 0x80);
4352 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4353 snd_soc_update_bits(codec,
4354 tabla->mbhc_bias_regs.ctl_reg, 0x01,
4355 0x00);
4356 snd_soc_update_bits(codec,
4357 tabla->mbhc_bias_regs.mbhc_reg,
4358 0x10, 0x10);
4359 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004360
4361 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004362 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07004363
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004364 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004365 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004366 /* Make sure the HPH schmitt trigger is OFF */
4367 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
4368
4369 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07004370 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
4371 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004372 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08004373 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004374 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4375 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004376 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004377 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4378 0x10, 0x10);
4379
4380 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004381 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004382 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004383
4384 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004385 /* called called by interrupt */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004386 if (!(tabla->clock_active)) {
4387 tabla_codec_enable_config_mode(codec, 1);
4388 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004389 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004390 usleep_range(generic->t_shutdown_plug_rem,
4391 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004392 tabla_codec_enable_config_mode(codec, 0);
4393 } else
4394 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004395 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004396 }
4397
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004398 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004399
4400 /* If central bandgap disabled */
4401 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
4402 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004403 usleep_range(generic->t_bg_fast_settle,
4404 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004405 central_bias_enabled = 1;
4406 }
4407
4408 /* If LDO_H disabled */
4409 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
4410 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
4411 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004412 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004413 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
4414
4415 if (central_bias_enabled)
4416 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
4417 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004418
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004419 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004420 tabla->mbhc_cfg.micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004421
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304422 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004423 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4424 return 0;
4425}
4426
Joonwoo Park0976d012011-12-22 11:48:18 -08004427static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4428 s16 vin_mv)
4429{
Joonwoo Park0976d012011-12-22 11:48:18 -08004430 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004431 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08004432 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07004433 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004434
4435 tabla = snd_soc_codec_get_drvdata(codec);
4436 mb_mv = tabla->mbhc_data.micb_mv;
4437
4438 if (mb_mv == 0) {
4439 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4440 return -EINVAL;
4441 }
4442
4443 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004444 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
4445 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004446 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004447 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
4448 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004449 }
4450 in = (u32) diff * vin_mv;
4451
Joonwoo Park03324832012-03-19 19:36:16 -07004452 value = (u16) (in / mb_mv) + zero;
4453 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004454}
4455
4456static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4457 u16 bias_value)
4458{
4459 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004460 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08004461 s32 mv;
4462
4463 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004464 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004465 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004466 z = (tabla->mbhc_data.dce_z);
4467 mb = (tabla->mbhc_data.dce_mb);
4468 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004469 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004470 z = (tabla->mbhc_data.sta_z);
4471 mb = (tabla->mbhc_data.sta_mb);
4472 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004473 }
4474
4475 return mv;
4476}
4477
Joonwoo Park03324832012-03-19 19:36:16 -07004478static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004479{
4480 struct delayed_work *delayed_work;
4481 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08004482 short bias_value;
4483 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07004484 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004485
4486 pr_debug("%s:\n", __func__);
4487
4488 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07004489 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004490 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004491
4492 if (tabla) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004493 if (tabla->mbhc_cfg.button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004494 bias_value = tabla_codec_read_sta_result(tabla->codec);
4495 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304496 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004497 bias_value = tabla_codec_read_dce_result(tabla->codec);
4498 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304499 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004500 pr_debug("%s: Reporting long button press event"
4501 " STA: %d, DCE: %d\n", __func__,
4502 sta_mv, dce_mv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004503 tabla_snd_soc_jack_report(tabla,
4504 tabla->mbhc_cfg.button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07004505 tabla->buttons_pressed,
4506 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004507 }
4508 } else {
4509 pr_err("%s: Bad tabla private data\n", __func__);
4510 }
4511
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004512 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07004513 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004514}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004515
Joonwoo Park0976d012011-12-22 11:48:18 -08004516void tabla_mbhc_cal(struct snd_soc_codec *codec)
4517{
4518 struct tabla_priv *tabla;
4519 struct tabla_mbhc_btn_detect_cfg *btn_det;
4520 u8 cfilt_mode, bg_mode;
4521 u8 ncic, nmeas, navg;
4522 u32 mclk_rate;
4523 u32 dce_wait, sta_wait;
4524 u8 *n_cic;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004525 void *calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08004526
4527 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004528 calibration = tabla->mbhc_cfg.calibration;
4529
4530 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4531 tabla_turn_onoff_rel_detection(codec, false);
Joonwoo Park0976d012011-12-22 11:48:18 -08004532
4533 /* First compute the DCE / STA wait times
4534 * depending on tunable parameters.
4535 * The value is computed in microseconds
4536 */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004537 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004538 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08004539 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004540 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
4541 navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
4542 mclk_rate = tabla->mbhc_cfg.mclk_rate;
Joonwoo Park433149a2012-01-11 09:53:54 -08004543 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
4544 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08004545
4546 tabla->mbhc_data.t_dce = dce_wait;
4547 tabla->mbhc_data.t_sta = sta_wait;
4548
4549 /* LDOH and CFILT are already configured during pdata handling.
4550 * Only need to make sure CFILT and bandgap are in Fast mode.
4551 * Need to restore defaults once calculation is done.
4552 */
4553 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4554 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
4555 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
4556 0x02);
4557
4558 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
4559 * to perform ADC calibration
4560 */
4561 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004562 tabla->mbhc_cfg.micbias << 5);
Joonwoo Park0976d012011-12-22 11:48:18 -08004563 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
4564 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
4565 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
4566 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
4567
4568 /* DCE measurement for 0 volts */
4569 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4570 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4571 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004572 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4573 usleep_range(100, 100);
4574 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4575 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4576 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
4577
4578 /* DCE measurment for MB voltage */
4579 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4580 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
4581 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4582 usleep_range(100, 100);
4583 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4584 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4585 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
4586
4587 /* Sta measuremnt for 0 volts */
4588 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4589 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4590 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004591 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4592 usleep_range(100, 100);
4593 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4594 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4595 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
4596
4597 /* STA Measurement for MB Voltage */
4598 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4599 usleep_range(100, 100);
4600 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4601 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4602 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
4603
4604 /* Restore default settings. */
4605 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4606 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4607 cfilt_mode);
4608 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
4609
4610 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
4611 usleep_range(100, 100);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004612
4613 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4614 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004615}
4616
4617void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
4618 const enum tabla_mbhc_btn_det_mem mem)
4619{
4620 void *ret = &btn_det->_v_btn_low;
4621
4622 switch (mem) {
4623 case TABLA_BTN_DET_GAIN:
4624 ret += sizeof(btn_det->_n_cic);
4625 case TABLA_BTN_DET_N_CIC:
4626 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08004627 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08004628 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
4629 case TABLA_BTN_DET_V_BTN_HIGH:
4630 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
4631 case TABLA_BTN_DET_V_BTN_LOW:
4632 /* do nothing */
4633 break;
4634 default:
4635 ret = NULL;
4636 }
4637
4638 return ret;
4639}
4640
4641static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
4642{
4643 struct tabla_priv *tabla;
4644 s16 btn_mv = 0, btn_delta_mv;
4645 struct tabla_mbhc_btn_detect_cfg *btn_det;
4646 struct tabla_mbhc_plug_type_cfg *plug_type;
4647 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004648 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08004649 int i;
4650
4651 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004652 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
4653 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004654
Joonwoo Parkc0672392012-01-11 11:03:14 -08004655 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004656 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07004657 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08004658 tabla->mbhc_data.nbounce_wait = 30;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004659 } else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004660 tabla->mbhc_data.npoll = 7;
4661 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004662 }
Joonwoo Park0976d012011-12-22 11:48:18 -08004663
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004664 tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
4665 (tabla->mbhc_cfg.mclk_rate / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08004666 n_ready[tabla_codec_mclk_index(tabla)]) +
4667 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08004668 tabla->mbhc_data.v_ins_hu =
4669 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
4670 tabla->mbhc_data.v_ins_h =
4671 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
4672
4673 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
4674 for (i = 0; i < btn_det->num_btn; i++)
4675 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
4676
4677 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
4678 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
4679
4680 tabla->mbhc_data.v_b1_hu =
4681 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
4682
4683 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
4684
4685 tabla->mbhc_data.v_b1_huc =
4686 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
4687
4688 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
Joonwoo Park03324832012-03-19 19:36:16 -07004689 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
Joonwoo Park0976d012011-12-22 11:48:18 -08004690
4691 tabla->mbhc_data.v_no_mic =
4692 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
4693}
4694
4695void tabla_mbhc_init(struct snd_soc_codec *codec)
4696{
4697 struct tabla_priv *tabla;
4698 struct tabla_mbhc_general_cfg *generic;
4699 struct tabla_mbhc_btn_detect_cfg *btn_det;
4700 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08004701 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304702 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08004703
4704 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004705 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
4706 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004707
Joonwoo Park0976d012011-12-22 11:48:18 -08004708 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08004709 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004710 snd_soc_update_bits(codec,
4711 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
4712 0x07, n);
4713 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
4714 btn_det->c[n]);
4715 }
4716 }
4717 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
4718 btn_det->nc);
4719
4720 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
4721 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08004722 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08004723
4724 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08004725 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
4726 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004727
4728 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
4729 generic->mbhc_nsa << 4);
4730
4731 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
4732 btn_det->n_meas);
4733
4734 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
4735
4736 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
4737
4738 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
4739 btn_det->mbhc_nsc << 3);
4740
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004741 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
4742 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08004743
4744 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07004745
4746 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004747}
4748
Patrick Lai64b43262011-12-06 17:29:15 -08004749static bool tabla_mbhc_fw_validate(const struct firmware *fw)
4750{
4751 u32 cfg_offset;
4752 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
4753 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
4754
4755 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
4756 return false;
4757
4758 /* previous check guarantees that there is enough fw data up
4759 * to num_btn
4760 */
4761 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
4762 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
4763 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
4764 return false;
4765
4766 /* previous check guarantees that there is enough fw data up
4767 * to start of impedance detection configuration
4768 */
4769 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
4770 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
4771
4772 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
4773 return false;
4774
4775 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
4776 return false;
4777
4778 return true;
4779}
Joonwoo Park03324832012-03-19 19:36:16 -07004780
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004781static int tabla_determine_button(const struct tabla_priv *priv,
4782 const s32 bias_mv)
4783{
4784 s16 *v_btn_low, *v_btn_high;
4785 struct tabla_mbhc_btn_detect_cfg *btn_det;
4786 int i, btn = -1;
4787
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004788 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004789 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
4790 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304791 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004792 for (i = 0; i < btn_det->num_btn; i++) {
4793 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
4794 btn = i;
4795 break;
4796 }
4797 }
4798
4799 if (btn == -1)
4800 pr_debug("%s: couldn't find button number for mic mv %d\n",
4801 __func__, bias_mv);
4802
4803 return btn;
4804}
4805
4806static int tabla_get_button_mask(const int btn)
4807{
4808 int mask = 0;
4809 switch (btn) {
4810 case 0:
4811 mask = SND_JACK_BTN_0;
4812 break;
4813 case 1:
4814 mask = SND_JACK_BTN_1;
4815 break;
4816 case 2:
4817 mask = SND_JACK_BTN_2;
4818 break;
4819 case 3:
4820 mask = SND_JACK_BTN_3;
4821 break;
4822 case 4:
4823 mask = SND_JACK_BTN_4;
4824 break;
4825 case 5:
4826 mask = SND_JACK_BTN_5;
4827 break;
4828 case 6:
4829 mask = SND_JACK_BTN_6;
4830 break;
4831 case 7:
4832 mask = SND_JACK_BTN_7;
4833 break;
4834 }
4835 return mask;
4836}
4837
Bradley Rubincb1e2732011-06-23 16:49:20 -07004838static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004839{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004840 int i, mask;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004841 short dce, sta, bias_value_dce;
4842 s32 mv, stamv, bias_mv_dce;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004843 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004844 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004845 const struct tabla_mbhc_btn_detect_cfg *d =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004846 TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004847 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004848 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304849 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07004850 int n_btn_meas = d->n_btn_meas;
4851 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004852
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004853 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004854
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004855 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
4856 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
4857 pr_debug("%s: mbhc is being recovered, skip button press\n",
4858 __func__);
4859 goto done;
4860 }
4861
4862 priv->mbhc_state = MBHC_STATE_POTENTIAL;
4863
4864 if (!priv->mbhc_polling_active) {
4865 pr_warn("%s: mbhc polling is not active, skip button press\n",
4866 __func__);
4867 goto done;
4868 }
Joonwoo Park03324832012-03-19 19:36:16 -07004869
4870 dce = tabla_codec_read_dce_result(codec);
4871 mv = tabla_codec_sta_dce_v(codec, 1, dce);
4872
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004873 /* If GPIO interrupt already kicked in, ignore button press */
4874 if (priv->in_gpio_handler) {
4875 pr_debug("%s: GPIO State Changed, ignore button press\n",
4876 __func__);
4877 btn = -1;
4878 goto done;
4879 }
4880
Joonwoo Park03324832012-03-19 19:36:16 -07004881 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
4882 if (priv->mbhc_last_resume &&
4883 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
4884 pr_debug("%s: Button is already released shortly after "
4885 "resume\n", __func__);
4886 n_btn_meas = 0;
4887 } else {
4888 pr_debug("%s: Button is already released without "
4889 "resume", __func__);
4890 sta = tabla_codec_read_sta_result(codec);
4891 stamv = tabla_codec_sta_dce_v(codec, 0, sta);
4892 btn = tabla_determine_button(priv, mv);
4893 if (btn != tabla_determine_button(priv, stamv))
4894 btn = -1;
4895 goto done;
4896 }
4897 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004898
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004899 /* determine pressed button */
Joonwoo Park03324832012-03-19 19:36:16 -07004900 btnmeas[meas++] = tabla_determine_button(priv, mv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004901 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Joonwoo Park03324832012-03-19 19:36:16 -07004902 meas - 1, dce, mv, btnmeas[meas - 1]);
4903 if (n_btn_meas == 0)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004904 btn = btnmeas[0];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004905 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
4906 bias_value_dce = tabla_codec_sta_dce(codec, 1, false);
4907 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
4908 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004909 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004910 __func__, meas, bias_value_dce, bias_mv_dce,
4911 btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004912 /* if large enough measurements are collected,
4913 * start to check if last all n_btn_con measurements were
4914 * in same button low/high range */
4915 if (meas + 1 >= d->n_btn_con) {
4916 for (i = 0; i < d->n_btn_con; i++)
4917 if ((btnmeas[meas] < 0) ||
4918 (btnmeas[meas] != btnmeas[meas - i]))
4919 break;
4920 if (i == d->n_btn_con) {
4921 /* button pressed */
4922 btn = btnmeas[meas];
4923 break;
Joonwoo Park03324832012-03-19 19:36:16 -07004924 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
4925 /* if left measurements are less than n_btn_con,
4926 * it's impossible to find button number */
4927 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004928 }
4929 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004930 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004931
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004932 if (btn >= 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004933 if (priv->in_gpio_handler) {
4934 pr_debug("%s: GPIO already triggered, ignore button "
4935 "press\n", __func__);
4936 goto done;
4937 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004938 mask = tabla_get_button_mask(btn);
4939 priv->buttons_pressed |= mask;
Joonwoo Park03324832012-03-19 19:36:16 -07004940 wcd9xxx_lock_sleep(core);
4941 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
4942 msecs_to_jiffies(400)) == 0) {
4943 WARN(1, "Button pressed twice without release"
4944 "event\n");
4945 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004946 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08004947 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004948 pr_debug("%s: bogus button press, too short press?\n",
4949 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004950 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004951
Joonwoo Park03324832012-03-19 19:36:16 -07004952 done:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004953 pr_debug("%s: leave\n", __func__);
4954 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004955 return IRQ_HANDLED;
4956}
4957
Joonwoo Park03324832012-03-19 19:36:16 -07004958static int tabla_is_fake_press(struct tabla_priv *priv)
4959{
4960 int i;
4961 int r = 0;
4962 struct snd_soc_codec *codec = priv->codec;
4963 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
4964 short mb_v;
4965
4966 for (i = 0; i < dces; i++) {
4967 usleep_range(10000, 10000);
4968 if (i == 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004969 mb_v = tabla_codec_sta_dce(codec, 0, true);
Joonwoo Park03324832012-03-19 19:36:16 -07004970 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
4971 tabla_codec_sta_dce_v(codec, 0, mb_v));
4972 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
4973 mb_v > (short)priv->mbhc_data.v_ins_hu) {
4974 r = 1;
4975 break;
4976 }
4977 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004978 mb_v = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park03324832012-03-19 19:36:16 -07004979 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
4980 tabla_codec_sta_dce_v(codec, 1, mb_v));
4981 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
4982 mb_v > (short)priv->mbhc_data.v_ins_h) {
4983 r = 1;
4984 break;
4985 }
4986 }
4987 }
4988
4989 return r;
4990}
4991
Bradley Rubincb1e2732011-06-23 16:49:20 -07004992static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004993{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08004994 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08004995 struct tabla_priv *priv = data;
4996 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004997
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004998 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07004999
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005000 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5001 priv->mbhc_state = MBHC_STATE_RELEASE;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005002
Joonwoo Park03324832012-03-19 19:36:16 -07005003 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005004 ret = tabla_cancel_btn_work(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005005 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07005006 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005007 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005008 if (priv->mbhc_cfg.button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005009 tabla_snd_soc_jack_report(priv,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005010 priv->mbhc_cfg.button_jack, 0,
5011 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005012 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005013 if (tabla_is_fake_press(priv)) {
5014 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005015 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005016 } else if (priv->mbhc_cfg.button_jack) {
5017 if (priv->in_gpio_handler) {
5018 pr_debug("%s: GPIO kicked in, ignore\n",
5019 __func__);
5020 } else {
5021 pr_debug("%s: Reporting short button 0 "
5022 "press and release\n",
5023 __func__);
5024 tabla_snd_soc_jack_report(priv,
5025 priv->mbhc_cfg.button_jack,
5026 priv->buttons_pressed,
5027 priv->buttons_pressed);
5028 tabla_snd_soc_jack_report(priv,
5029 priv->mbhc_cfg.button_jack, 0,
5030 priv->buttons_pressed);
5031 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005032 }
5033 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005034
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005035 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
5036 }
5037
Joonwoo Park03324832012-03-19 19:36:16 -07005038 tabla_codec_calibrate_hs_polling(codec);
5039
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005040 if (priv->mbhc_cfg.gpio)
5041 msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
Joonwoo Park03324832012-03-19 19:36:16 -07005042
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005043 tabla_codec_start_hs_polling(codec);
5044
5045 pr_debug("%s: leave\n", __func__);
5046 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005047 return IRQ_HANDLED;
5048}
5049
Bradley Rubincb1e2732011-06-23 16:49:20 -07005050static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
5051{
5052 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08005053 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005054 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005055
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005056 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005057 tabla_codec_enable_config_mode(codec, 1);
5058
5059 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
5060 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005061
Joonwoo Park0976d012011-12-22 11:48:18 -08005062 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
5063
5064 usleep_range(generic->t_shutdown_plug_rem,
5065 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005066
5067 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005068 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005069 tabla_codec_enable_config_mode(codec, 0);
5070
5071 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
5072}
5073
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005074static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005075{
5076 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005077
5078 tabla_codec_shutdown_hs_removal_detect(codec);
5079
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005080 if (!tabla->mclk_enabled) {
Asish Bhattacharya486745a2012-01-20 06:41:53 +05305081 tabla_codec_disable_clock_block(codec);
5082 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005083 }
5084
5085 tabla->mbhc_polling_active = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005086 tabla->mbhc_state = MBHC_STATE_NONE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005087}
5088
Patrick Lai49efeac2011-11-03 11:01:12 -07005089static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
5090{
5091 struct tabla_priv *tabla = data;
5092 struct snd_soc_codec *codec;
5093
5094 pr_info("%s: received HPHL OCP irq\n", __func__);
5095
5096 if (tabla) {
5097 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005098 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
5099 pr_info("%s: retry\n", __func__);
5100 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5101 0x00);
5102 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5103 0x10);
5104 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305105 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005106 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5107 tabla->hphlocp_cnt = 0;
5108 tabla->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005109 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005110 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005111 tabla->mbhc_cfg.headset_jack,
5112 tabla->hph_status,
5113 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005114 }
5115 } else {
5116 pr_err("%s: Bad tabla private data\n", __func__);
5117 }
5118
5119 return IRQ_HANDLED;
5120}
5121
5122static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
5123{
5124 struct tabla_priv *tabla = data;
5125 struct snd_soc_codec *codec;
5126
5127 pr_info("%s: received HPHR OCP irq\n", __func__);
5128
5129 if (tabla) {
5130 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005131 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
5132 pr_info("%s: retry\n", __func__);
5133 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5134 0x00);
5135 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5136 0x10);
5137 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305138 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005139 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5140 tabla->hphrocp_cnt = 0;
5141 tabla->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005142 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005143 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005144 tabla->mbhc_cfg.headset_jack,
5145 tabla->hph_status,
5146 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005147 }
5148 } else {
5149 pr_err("%s: Bad tabla private data\n", __func__);
5150 }
5151
5152 return IRQ_HANDLED;
5153}
5154
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005155static bool tabla_is_invalid_insertion_range(struct snd_soc_codec *codec,
5156 s32 mic_volt)
Joonwoo Park03324832012-03-19 19:36:16 -07005157{
5158 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5159 struct tabla_mbhc_plug_type_cfg *plug_type =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005160 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5161 int fake_insert_high;
5162 bool invalid = false;
Joonwoo Park03324832012-03-19 19:36:16 -07005163
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005164 if (tabla->mbhc_cfg.gpio)
5165 fake_insert_high = TABLA_MBHC_FAKE_INSERT_HIGH;
5166 else
5167 fake_insert_high = TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
5168
5169 /* Perform this check only when the high voltage headphone
5170 * needs to be considered as invalid
5171 */
5172 if (!tabla->mbhc_inval_hs_range_override
5173 && (mic_volt > plug_type->v_hs_max)) {
5174 invalid = true;
5175 } else if (mic_volt < fake_insert_high
5176 && (mic_volt > TABLA_MBHC_FAKE_INSERT_LOW)) {
5177 invalid = true;
5178 }
5179
5180 return invalid;
5181}
5182
5183static bool tabla_is_invalid_insert_delta(struct snd_soc_codec *codec,
5184 int mic_volt, int mic_volt_prev)
5185{
5186 int delta = abs(mic_volt - mic_volt_prev);
5187 if (delta > TABLA_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
5188 pr_debug("%s: volt delta %dmv\n", __func__, delta);
Joonwoo Park03324832012-03-19 19:36:16 -07005189 return true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005190 }
Joonwoo Park03324832012-03-19 19:36:16 -07005191 return false;
5192}
5193
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005194static bool tabla_codec_is_invalid_plug(struct snd_soc_codec *codec,
5195 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
5196 enum tabla_mbhc_plug_type
5197 plug_type[MBHC_NUM_DCE_PLUG_DETECT])
5198{
5199 int i;
5200 bool r = false;
5201 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5202 struct tabla_mbhc_plug_type_cfg *plug_type_ptr =
5203 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5204
5205 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
5206 if (mic_mv[i] < plug_type_ptr->v_no_mic)
5207 plug_type[i] = PLUG_TYPE_HEADPHONE;
5208 else if (mic_mv[i] < plug_type_ptr->v_hs_max)
5209 plug_type[i] = PLUG_TYPE_HEADSET;
5210 else if (mic_mv[i] > plug_type_ptr->v_hs_max)
5211 plug_type[i] = PLUG_TYPE_HIGH_HPH;
5212
5213 r = tabla_is_invalid_insertion_range(codec, mic_mv[i]);
5214 if (!r && i > 0) {
5215 if (plug_type[i-1] != plug_type[i])
5216 r = true;
5217 else
5218 r = tabla_is_invalid_insert_delta(codec,
5219 mic_mv[i],
5220 mic_mv[i - 1]);
5221 }
5222 }
5223
5224 return r;
5225}
5226
5227/* called under codec_resource_lock acquisition */
5228void tabla_find_plug_and_report(struct snd_soc_codec *codec,
5229 enum tabla_mbhc_plug_type plug_type)
Joonwoo Park03324832012-03-19 19:36:16 -07005230{
5231 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005232
5233 if (plug_type == PLUG_TYPE_HEADPHONE
5234 && tabla->current_plug == PLUG_TYPE_NONE) {
5235 /* Nothing was reported previously
5236 * reporte a headphone
5237 */
5238 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5239 tabla_codec_cleanup_hs_polling(codec);
5240 } else if (plug_type == PLUG_TYPE_HEADSET) {
5241 /* If Headphone was reported previously, this will
5242 * only report the mic line
5243 */
5244 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5245 msleep(100);
5246 tabla_codec_start_hs_polling(codec);
5247 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
5248 if (tabla->current_plug == PLUG_TYPE_NONE)
5249 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5250 tabla_codec_cleanup_hs_polling(codec);
5251 pr_debug("setup mic trigger for further detection\n");
5252 tabla->lpi_enabled = true;
5253 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5254 false);
5255 }
5256}
5257
5258/* should be called under interrupt context that hold suspend */
5259static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla)
5260{
5261 pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
5262 tabla->hs_detect_work_stop = false;
5263 wcd9xxx_lock_sleep(tabla->codec->control_data);
5264 schedule_work(&tabla->hs_correct_plug_work);
5265}
5266
5267/* called under codec_resource_lock acquisition */
5268static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla)
5269{
5270 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
5271 tabla->hs_detect_work_stop = true;
5272 wmb();
5273 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5274 if (cancel_work_sync(&tabla->hs_correct_plug_work)) {
5275 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
5276 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5277 }
5278 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5279}
5280
5281static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
5282{
5283 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
5284}
5285
5286static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
5287{
5288 return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
5289 tabla->mbhc_cfg.gpio_level_insert);
5290}
5291
5292static void tabla_hs_correct_gpio_plug(struct work_struct *work)
5293{
5294 struct tabla_priv *tabla;
5295 struct snd_soc_codec *codec;
5296 int retry = 0, i;
5297 bool correction = false;
5298 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5299 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5300 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5301 unsigned long timeout;
5302
5303 tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
5304 codec = tabla->codec;
5305
5306 pr_debug("%s: enter\n", __func__);
5307 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
5308
5309 /* Keep override on during entire plug type correction work.
5310 *
5311 * This is okay under the assumption that any GPIO irqs which use
5312 * MBHC block cancel and sync this work so override is off again
5313 * prior to GPIO interrupt handler's MBHC block usage.
5314 * Also while this correction work is running, we can guarantee
5315 * DAPM doesn't use any MBHC block as this work only runs with
5316 * headphone detection.
5317 */
5318 tabla_turn_onoff_override(codec, true);
5319
5320 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5321 while (!time_after(jiffies, timeout)) {
5322 ++retry;
5323 rmb();
5324 if (tabla->hs_detect_work_stop) {
5325 pr_debug("%s: stop requested\n", __func__);
5326 break;
5327 }
5328
5329 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
5330 if (tabla_hs_gpio_level_remove(tabla)) {
5331 pr_debug("%s: GPIO value is low\n", __func__);
5332 break;
5333 }
5334
5335 /* can race with removal interrupt */
5336 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5337 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5338 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5339 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5340 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
5341 __func__, retry, mic_mv[i], mb_v[i]);
5342 }
5343 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5344
5345 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5346 pr_debug("Invalid plug in attempt # %d\n", retry);
5347 if (retry == NUM_ATTEMPTS_TO_REPORT &&
5348 tabla->current_plug == PLUG_TYPE_NONE) {
5349 tabla_codec_report_plug(codec, 1,
5350 SND_JACK_HEADPHONE);
5351 }
5352 } else if (!tabla_codec_is_invalid_plug(codec, mic_mv,
5353 plug_type) &&
5354 plug_type[0] == PLUG_TYPE_HEADPHONE) {
5355 pr_debug("Good headphone detected, continue polling mic\n");
5356 if (tabla->current_plug == PLUG_TYPE_NONE) {
5357 tabla_codec_report_plug(codec, 1,
5358 SND_JACK_HEADPHONE);
5359 }
5360 } else {
5361 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5362 /* Turn off override */
5363 tabla_turn_onoff_override(codec, false);
5364 tabla_find_plug_and_report(codec, plug_type[0]);
5365 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5366 pr_debug("Attempt %d found correct plug %d\n", retry,
5367 plug_type[0]);
5368 correction = true;
5369 break;
5370 }
5371 }
5372
5373 /* Turn off override */
5374 if (!correction)
5375 tabla_turn_onoff_override(codec, false);
5376
5377 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
5378 pr_debug("%s: leave\n", __func__);
5379 /* unlock sleep */
5380 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5381}
5382
5383/* called under codec_resource_lock acquisition */
5384static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
5385{
5386 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005387 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5388 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005389 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5390 int i;
5391
5392 pr_debug("%s: enter\n", __func__);
5393
5394 tabla_turn_onoff_override(codec, true);
5395 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5396 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
5397 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
5398
5399 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5400 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5401 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5402 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
5403 mic_mv[i]);
5404 }
5405 tabla_turn_onoff_override(codec, false);
5406
5407 if (tabla_hs_gpio_level_remove(tabla)) {
5408 pr_debug("%s: GPIO value is low when determining plug\n",
5409 __func__);
5410 return;
5411 }
5412
5413 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5414 tabla_schedule_hs_detect_plug(tabla);
5415 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5416 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5417
5418 tabla_schedule_hs_detect_plug(tabla);
5419 } else {
5420 pr_debug("%s: Valid plug found, determine plug type\n",
5421 __func__);
5422 tabla_find_plug_and_report(codec, plug_type[0]);
5423 }
5424}
5425
5426/* called under codec_resource_lock acquisition */
5427static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
5428{
5429 int i;
5430 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5431 const struct tabla_mbhc_plug_detect_cfg *plug_det =
5432 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
5433 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5434 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5435 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
Joonwoo Park03324832012-03-19 19:36:16 -07005436 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
5437
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005438 /* Turn on the override,
5439 * tabla_codec_setup_hs_polling requires override on */
5440 tabla_turn_onoff_override(codec, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005441
5442 if (plug_det->t_ins_complete > 20)
5443 msleep(plug_det->t_ins_complete);
5444 else
5445 usleep_range(plug_det->t_ins_complete * 1000,
5446 plug_det->t_ins_complete * 1000);
5447
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005448 if (tabla->mbhc_cfg.gpio) {
5449 /* Turn off the override */
5450 tabla_turn_onoff_override(codec, false);
5451 if (tabla_hs_gpio_level_remove(tabla))
5452 pr_debug("%s: GPIO value is low when determining "
5453 "plug\n", __func__);
5454 else
5455 tabla_codec_decide_gpio_plug(codec);
5456 return;
5457 }
5458
Joonwoo Park03324832012-03-19 19:36:16 -07005459 /*
5460 * First DCE measurement,
5461 * IF this is fake, discontinue detection
5462 * and restart insertion detection
5463 */
5464 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5465 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005466 if (tabla_is_invalid_insertion_range(codec, mic_mv[0])) {
Joonwoo Park03324832012-03-19 19:36:16 -07005467 pr_debug("%s: Detect attempt 1, detected Fake\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005468 tabla_turn_onoff_override(codec, false);
5469 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005470 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5471 false);
5472 return;
5473 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005474 pr_debug("%s: DCE run 1, %x, mic_mv = %d\n", __func__, mb_v[0],
Joonwoo Park03324832012-03-19 19:36:16 -07005475 mic_mv[0]);
5476
5477 /*
5478 * Perform two more DCE measurements,
5479 * IF any of them is fake, discontinue detection
5480 * and restart insertion detection
5481 */
Joonwoo Park03324832012-03-19 19:36:16 -07005482 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005483 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005484 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005485 pr_debug("%s: DCE run %d, %x, mic_mv = %d\n", __func__, i + 1,
Joonwoo Park03324832012-03-19 19:36:16 -07005486 mb_v[1], mic_mv[i]);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005487 if (tabla_is_invalid_insertion_range(codec, mic_mv[i])
5488 || tabla_is_invalid_insert_delta(codec, mic_mv[i],
5489 mic_mv[i - 1])) {
Joonwoo Park03324832012-03-19 19:36:16 -07005490 pr_debug("%s: Detect attempt %d, detected Fake\n",
5491 __func__, i + 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005492 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005493 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
5494 0x02, 0x02);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005495 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005496 tabla_codec_enable_hs_detect(codec, 1,
5497 MBHC_USE_MB_TRIGGER,
5498 false);
5499 return;
5500 }
5501 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005502 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005503
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005504 plug_type_ptr =
5505 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07005506
5507 /*
5508 * If we are here, means none of the three
5509 * measurements are fake, continue plug type detection.
5510 * If all three measurements do not produce same
5511 * plug type, restart insertion detection
5512 */
5513 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5514 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
5515 plug_type[i] = PLUG_TYPE_HEADPHONE;
5516 pr_debug("%s: Detect attempt %d, detected Headphone\n",
5517 __func__, i);
5518 } else {
5519 plug_type[i] = PLUG_TYPE_HEADSET;
5520 pr_debug("%s: Detect attempt %d, detected Headset\n",
5521 __func__, i);
5522 }
5523
5524 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
5525 pr_err("%s: Detect attempt %d and %d are not same",
5526 __func__, i - 1, i);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005527 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005528 tabla_codec_enable_hs_detect(codec, 1,
5529 MBHC_USE_MB_TRIGGER,
5530 false);
5531 return;
5532 }
5533 }
5534
5535 if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5536 pr_debug("%s: Headphone Detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005537 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5538 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005539 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005540 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
5541 pr_debug("%s: Headset detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005542 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5543
Joonwoo Park03324832012-03-19 19:36:16 -07005544 /* avoid false button press detect */
5545 msleep(50);
Joonwoo Park03324832012-03-19 19:36:16 -07005546 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005547 }
5548}
5549
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005550/* called only from interrupt which is under codec_resource_lock acquisition */
5551static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005552{
Bradley Rubincb1e2732011-06-23 16:49:20 -07005553 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005554
5555 if (!is_removal) {
5556 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
5557
5558 rmb();
5559 if (priv->lpi_enabled)
5560 msleep(100);
5561
5562 rmb();
5563 if (!priv->lpi_enabled) {
5564 pr_debug("%s: lpi is disabled\n", __func__);
5565 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
5566 priv->mbhc_cfg.gpio_level_insert) {
5567 pr_debug("%s: Valid insertion, "
5568 "detect plug type\n", __func__);
5569 tabla_codec_decide_gpio_plug(codec);
5570 } else {
5571 pr_debug("%s: Invalid insertion, "
5572 "stop plug detection\n", __func__);
5573 }
5574 } else {
5575 pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
5576 }
5577}
5578
5579/* called only from interrupt which is under codec_resource_lock acquisition */
5580static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
5581 bool is_mb_trigger)
5582{
Joonwoo Park03324832012-03-19 19:36:16 -07005583 int ret;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005584 struct snd_soc_codec *codec = priv->codec;
5585 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005586
5587 if (is_removal) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005588 /* cancel possiblely running hs detect work */
5589 tabla_cancel_hs_detect_plug(priv);
5590
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005591 /*
5592 * If headphone is removed while playback is in progress,
5593 * it is possible that micbias will be switched to VDDIO.
5594 */
Joonwoo Park03324832012-03-19 19:36:16 -07005595 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005596 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005597 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005598 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5599 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005600 } else if (is_mb_trigger && !is_removal) {
Joonwoo Park03324832012-03-19 19:36:16 -07005601 pr_debug("%s: Waiting for Headphone left trigger\n",
5602 __func__);
5603 wcd9xxx_lock_sleep(core);
5604 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
5605 usecs_to_jiffies(1000000)) == 0) {
5606 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
5607 __func__);
5608 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005609 }
Joonwoo Park03324832012-03-19 19:36:16 -07005610 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
5611 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005612 } else {
5613 wcd9xxx_lock_sleep(core);
5614 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
5615 if (ret != 0) {
5616 pr_debug("%s: Complete plug insertion, Detecting plug "
5617 "type\n", __func__);
5618 tabla_codec_detect_plug_type(codec);
5619 wcd9xxx_unlock_sleep(core);
5620 } else {
5621 wcd9xxx_enable_irq(codec->control_data,
5622 TABLA_IRQ_MBHC_INSERTION);
5623 pr_err("%s: Error detecting plug insertion\n",
5624 __func__);
5625 }
Joonwoo Park03324832012-03-19 19:36:16 -07005626 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005627}
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08005628
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005629static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
5630{
5631 bool is_mb_trigger, is_removal;
5632 struct tabla_priv *priv = data;
5633 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005634
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005635 pr_debug("%s: enter\n", __func__);
5636 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5637 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
5638
5639 is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
5640 0x10);
5641 is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
5642 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
5643
5644 /* Turn off both HPH and MIC line schmitt triggers */
5645 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5646 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
5647 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5648
5649 if (priv->mbhc_cfg.gpio)
5650 tabla_hs_insert_irq_gpio(priv, is_removal);
5651 else
5652 tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
5653
5654 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005655 return IRQ_HANDLED;
5656}
5657
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005658static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
5659{
5660 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5661 struct tabla_mbhc_plug_type_cfg *plug_type =
5662 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5663
5664 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
5665 && (mic_mv < plug_type->v_hs_max)) ? true : false;
5666}
5667
5668/* called under codec_resource_lock acquisition
5669 * returns true if mic voltage range is back to normal insertion
5670 * returns false either if timedout or removed */
5671static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
5672{
5673 int i;
5674 bool timedout, settled = false;
5675 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5676 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5677 unsigned long retry = 0, timeout;
5678 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5679 struct tabla_mbhc_plug_type_cfg *plug_type =
5680 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5681
5682 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5683 while (!(timedout = time_after(jiffies, timeout))) {
5684 retry++;
5685 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5686 pr_debug("%s: GPIO indicates removal\n", __func__);
5687 break;
5688 }
5689
5690 if (tabla->mbhc_cfg.gpio) {
5691 if (retry > 1)
5692 msleep(250);
5693 else
5694 msleep(50);
5695 }
5696
5697 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5698 pr_debug("%s: GPIO indicates removal\n", __func__);
5699 break;
5700 }
5701
5702 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5703 mb_v[i] = tabla_codec_sta_dce(codec, 1, true);
5704 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5705 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
5706 __func__, retry, mic_mv[i], mb_v[i]);
5707 }
5708
5709 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5710 pr_debug("%s: GPIO indicates removal\n", __func__);
5711 break;
5712 }
5713
5714 if (tabla->current_plug == PLUG_TYPE_NONE) {
5715 pr_debug("%s : headset/headphone is removed\n",
5716 __func__);
5717 break;
5718 }
5719
5720 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5721 if (!is_valid_mic_voltage(codec, mic_mv[i]))
5722 break;
5723
5724 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5725 pr_debug("%s: MIC voltage settled\n", __func__);
5726 settled = true;
5727 msleep(200);
5728 break;
5729 }
5730
5731 /* only for non-GPIO remove irq */
5732 if (!tabla->mbhc_cfg.gpio) {
5733 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5734 if (mic_mv[i] < plug_type->v_hs_max)
5735 break;
5736 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5737 pr_debug("%s: Headset is removed\n", __func__);
5738 break;
5739 }
5740 }
5741 }
5742
5743 if (timedout)
5744 pr_debug("%s: Microphone did not settle in %d seconds\n",
5745 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
5746 return settled;
5747}
5748
5749/* called only from interrupt which is under codec_resource_lock acquisition */
5750static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
5751{
5752 struct snd_soc_codec *codec = priv->codec;
5753
5754 if (tabla_hs_remove_settle(codec))
5755 tabla_codec_start_hs_polling(codec);
5756 pr_debug("%s: remove settle done\n", __func__);
5757}
5758
5759/* called only from interrupt which is under codec_resource_lock acquisition */
5760static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005761{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005762 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005763 bool removed = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005764 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08005765 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005766 TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005767 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005768
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005769 if (priv->current_plug != PLUG_TYPE_HEADSET) {
5770 pr_debug("%s(): Headset is not inserted, ignore removal\n",
5771 __func__);
5772 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
5773 0x08, 0x08);
5774 return;
5775 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005776
Joonwoo Park0976d012011-12-22 11:48:18 -08005777 usleep_range(generic->t_shutdown_plug_rem,
5778 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005779
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005780 do {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005781 bias_value = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005782 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
5783 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
5784 if (bias_value < (short)priv->mbhc_data.v_ins_h) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005785 pr_debug("%s: checking false removal\n", __func__);
5786 msleep(500);
5787 removed = !tabla_hs_remove_settle(codec);
5788 pr_debug("%s: headset %sactually removed\n", __func__,
5789 removed ? "" : "not ");
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005790 break;
5791 }
5792 min_us -= priv->mbhc_data.t_dce;
5793 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005794
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005795 if (removed) {
5796 /* cancel possiblely running hs detect work */
5797 tabla_cancel_hs_detect_plug(priv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005798 /*
5799 * If this removal is not false, first check the micbias
5800 * switch status and switch it to LDOH if it is already
5801 * switched to VDDIO.
5802 */
Joonwoo Park03324832012-03-19 19:36:16 -07005803 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07005804
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005805 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
5806 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005807 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5808 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005809 } else {
5810 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005811 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005812}
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005813
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005814static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
5815{
5816 struct tabla_priv *priv = data;
5817 pr_debug("%s: enter, removal interrupt\n", __func__);
5818
5819 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5820 if (priv->mbhc_cfg.gpio)
5821 tabla_hs_remove_irq_gpio(priv);
5822 else
5823 tabla_hs_remove_irq_nogpio(priv);
5824
5825 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005826 return IRQ_HANDLED;
5827}
5828
Joonwoo Park03324832012-03-19 19:36:16 -07005829void mbhc_insert_work(struct work_struct *work)
5830{
5831 struct delayed_work *dwork;
5832 struct tabla_priv *tabla;
5833 struct snd_soc_codec *codec;
5834 struct wcd9xxx *tabla_core;
5835
5836 dwork = to_delayed_work(work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005837 tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
Joonwoo Park03324832012-03-19 19:36:16 -07005838 codec = tabla->codec;
5839 tabla_core = dev_get_drvdata(codec->dev->parent);
5840
5841 pr_debug("%s:\n", __func__);
5842
5843 /* Turn off both HPH and MIC line schmitt triggers */
5844 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5845 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
5846 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5847 wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
5848 tabla_codec_detect_plug_type(codec);
5849 wcd9xxx_unlock_sleep(tabla_core);
5850}
5851
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005852static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
5853{
5854 bool insert;
5855 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5856 bool is_removed = false;
5857
5858 pr_debug("%s: enter\n", __func__);
5859
5860 tabla->in_gpio_handler = true;
5861 /* Wait here for debounce time */
5862 usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
5863 TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
5864
5865 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5866
5867 /* cancel pending button press */
5868 if (tabla_cancel_btn_work(tabla))
5869 pr_debug("%s: button press is canceled\n", __func__);
5870
5871 insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
5872 tabla->mbhc_cfg.gpio_level_insert);
5873 if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
5874 tabla->lpi_enabled = false;
5875 wmb();
5876
5877 /* cancel detect plug */
5878 tabla_cancel_hs_detect_plug(tabla);
5879
5880 /* Disable Mic Bias pull down and HPH Switch to GND */
5881 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
5882 0x00);
5883 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
5884 tabla_codec_detect_plug_type(codec);
5885 } else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
5886 tabla->lpi_enabled = false;
5887 wmb();
5888
5889 /* cancel detect plug */
5890 tabla_cancel_hs_detect_plug(tabla);
5891
5892 if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
5893 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
5894 is_removed = true;
5895 } else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
5896 tabla_codec_pause_hs_polling(codec);
5897 tabla_codec_cleanup_hs_polling(codec);
5898 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
5899 is_removed = true;
5900 }
5901
5902 if (is_removed) {
5903 /* Enable Mic Bias pull down and HPH Switch to GND */
5904 snd_soc_update_bits(codec,
5905 tabla->mbhc_bias_regs.ctl_reg, 0x01,
5906 0x01);
5907 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
5908 0x01);
5909 /* Make sure mic trigger is turned off */
5910 snd_soc_update_bits(codec,
5911 tabla->mbhc_bias_regs.ctl_reg,
5912 0x01, 0x01);
5913 snd_soc_update_bits(codec,
5914 tabla->mbhc_bias_regs.mbhc_reg,
5915 0x90, 0x00);
5916 /* Reset MBHC State Machine */
5917 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
5918 0x08, 0x08);
5919 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
5920 0x08, 0x00);
5921 /* Turn off override */
5922 tabla_turn_onoff_override(codec, false);
5923 }
5924 }
5925
5926 tabla->in_gpio_handler = false;
5927 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5928 pr_debug("%s: leave\n", __func__);
5929}
5930
5931static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
5932{
5933 int r = IRQ_HANDLED;
5934 struct snd_soc_codec *codec = data;
5935
5936 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
5937 pr_warn("%s: failed to hold suspend\n", __func__);
5938 r = IRQ_NONE;
5939 } else {
5940 tabla_hs_gpio_handler(codec);
5941 wcd9xxx_unlock_sleep(codec->control_data);
5942 }
5943
5944 return r;
5945}
5946
5947static void mbhc_fw_read(struct work_struct *work)
5948{
5949 struct delayed_work *dwork;
5950 struct tabla_priv *tabla;
5951 struct snd_soc_codec *codec;
5952 const struct firmware *fw;
5953 int ret = -1, retry = 0, rc;
5954
5955 dwork = to_delayed_work(work);
5956 tabla = container_of(dwork, struct tabla_priv,
5957 mbhc_firmware_dwork);
5958 codec = tabla->codec;
5959
5960 while (retry < MBHC_FW_READ_ATTEMPTS) {
5961 retry++;
5962 pr_info("%s:Attempt %d to request MBHC firmware\n",
5963 __func__, retry);
5964 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
5965 codec->dev);
5966
5967 if (ret != 0) {
5968 usleep_range(MBHC_FW_READ_TIMEOUT,
5969 MBHC_FW_READ_TIMEOUT);
5970 } else {
5971 pr_info("%s: MBHC Firmware read succesful\n", __func__);
5972 break;
5973 }
5974 }
5975
5976 if (ret != 0) {
5977 pr_err("%s: Cannot load MBHC firmware use default cal\n",
5978 __func__);
5979 } else if (tabla_mbhc_fw_validate(fw) == false) {
5980 pr_err("%s: Invalid MBHC cal data size use default cal\n",
5981 __func__);
5982 release_firmware(fw);
5983 } else {
5984 tabla->mbhc_cfg.calibration = (void *)fw->data;
5985 tabla->mbhc_fw = fw;
5986 }
5987
5988 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
5989 tabla_mbhc_init(codec);
5990 tabla_mbhc_cal(codec);
5991 tabla_mbhc_calc_thres(codec);
5992 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
5993 tabla_codec_calibrate_hs_polling(codec);
5994 if (!tabla->mbhc_cfg.gpio) {
5995 tabla->mbhc_inval_hs_range_override = false;
5996 rc = tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5997 false);
5998
5999 if (IS_ERR_VALUE(rc))
6000 pr_err("%s: Failed to setup MBHC detection\n",
6001 __func__);
6002 } else {
6003 tabla->mbhc_inval_hs_range_override = true;
6004 /* Enable Mic Bias pull down and HPH Switch to GND */
6005 snd_soc_update_bits(codec,
6006 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6007 0x01);
6008 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6009 0x01);
6010 INIT_WORK(&tabla->hs_correct_plug_work,
6011 tabla_hs_correct_gpio_plug);
6012 }
6013
6014}
6015
Joonwoo Park03324832012-03-19 19:36:16 -07006016int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006017 const struct tabla_mbhc_config *cfg)
Joonwoo Park03324832012-03-19 19:36:16 -07006018{
6019 struct tabla_priv *tabla;
6020 int rc = 0;
6021
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006022 if (!codec || !cfg->calibration) {
Joonwoo Park03324832012-03-19 19:36:16 -07006023 pr_err("Error: no codec or calibration\n");
6024 return -EINVAL;
6025 }
6026
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006027 if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
6028 if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Joonwoo Park03324832012-03-19 19:36:16 -07006029 pr_err("Error: clock rate %dHz is not yet supported\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006030 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006031 else
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006032 pr_err("Error: unsupported clock rate %d\n",
6033 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006034 return -EINVAL;
6035 }
6036
6037 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006038 tabla->mbhc_cfg = *cfg;
6039 tabla->in_gpio_handler = false;
6040 tabla->current_plug = PLUG_TYPE_NONE;
6041 tabla->lpi_enabled = false;
Joonwoo Park03324832012-03-19 19:36:16 -07006042 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
6043
6044 /* Put CFILT in fast mode by default */
6045 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
6046 0x40, TABLA_CFILT_FAST_MODE);
6047 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
6048 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
6049 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
6050 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
6051 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
6052
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006053 if (!tabla->mbhc_cfg.read_fw_bin) {
6054 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006055 tabla_mbhc_init(codec);
6056 tabla_mbhc_cal(codec);
6057 tabla_mbhc_calc_thres(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006058 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006059 tabla_codec_calibrate_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006060 if (!tabla->mbhc_cfg.gpio) {
6061 tabla->mbhc_inval_hs_range_override = false;
6062 rc = tabla_codec_enable_hs_detect(codec, 1,
6063 MBHC_USE_MB_TRIGGER,
6064 false);
6065 } else {
6066 tabla->mbhc_inval_hs_range_override = true;
6067 /* Enable Mic Bias pull down and HPH Switch to GND */
6068 snd_soc_update_bits(codec,
6069 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6070 0x01);
6071 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6072 0x01);
6073 INIT_WORK(&tabla->hs_correct_plug_work,
6074 tabla_hs_correct_gpio_plug);
6075 }
Joonwoo Park03324832012-03-19 19:36:16 -07006076 } else {
6077 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
6078 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
6079 }
6080
6081 if (!IS_ERR_VALUE(rc)) {
6082 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
6083 wcd9xxx_enable_irq(codec->control_data,
6084 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6085 wcd9xxx_enable_irq(codec->control_data,
6086 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6087 }
6088
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006089 if (!IS_ERR_VALUE(rc) && tabla->mbhc_cfg.gpio) {
6090 rc = request_threaded_irq(tabla->mbhc_cfg.gpio_irq, NULL,
6091 tabla_mechanical_plug_detect_irq,
6092 (IRQF_TRIGGER_RISING |
6093 IRQF_TRIGGER_FALLING),
6094 "tabla-gpio", codec);
6095 if (!IS_ERR_VALUE(rc)) {
6096 rc = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
6097 /* Bootup time detection */
6098 tabla_hs_gpio_handler(codec);
6099 }
6100 }
6101
Joonwoo Park03324832012-03-19 19:36:16 -07006102 return rc;
6103}
6104EXPORT_SYMBOL_GPL(tabla_hs_detect);
6105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006106static unsigned long slimbus_value;
6107
6108static irqreturn_t tabla_slimbus_irq(int irq, void *data)
6109{
6110 struct tabla_priv *priv = data;
6111 struct snd_soc_codec *codec = priv->codec;
6112 int i, j;
6113 u8 val;
6114
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306115 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
6116 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006117 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
6118 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306119 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006120 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
6121 if (val & 0x1)
6122 pr_err_ratelimited("overflow error on port %x,"
6123 " value %x\n", i*8 + j, val);
6124 if (val & 0x2)
6125 pr_err_ratelimited("underflow error on port %x,"
6126 " value %x\n", i*8 + j, val);
6127 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306128 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006129 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
6130 }
6131
6132 return IRQ_HANDLED;
6133}
6134
Patrick Lai3043fba2011-08-01 14:15:57 -07006135
6136static int tabla_handle_pdata(struct tabla_priv *tabla)
6137{
6138 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306139 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07006140 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05306141 u8 leg_mode = pdata->amic_settings.legacy_mode;
6142 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
6143 u8 txfe_buff = pdata->amic_settings.txfe_buff;
6144 u8 flag = pdata->amic_settings.use_pdata;
6145 u8 i = 0, j = 0;
6146 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07006147
6148 if (!pdata) {
6149 rc = -ENODEV;
6150 goto done;
6151 }
6152
6153 /* Make sure settings are correct */
6154 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
6155 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
6156 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
6157 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
6158 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
6159 rc = -EINVAL;
6160 goto done;
6161 }
6162
6163 /* figure out k value */
6164 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
6165 pdata->micbias.cfilt1_mv);
6166 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
6167 pdata->micbias.cfilt2_mv);
6168 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
6169 pdata->micbias.cfilt3_mv);
6170
6171 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
6172 rc = -EINVAL;
6173 goto done;
6174 }
6175
6176 /* Set voltage level and always use LDO */
6177 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
6178 (pdata->micbias.ldoh_v << 2));
6179
6180 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
6181 (k1 << 2));
6182 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
6183 (k2 << 2));
6184 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
6185 (k3 << 2));
6186
6187 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
6188 (pdata->micbias.bias1_cfilt_sel << 5));
6189 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
6190 (pdata->micbias.bias2_cfilt_sel << 5));
6191 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
6192 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006193 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
6194 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07006195
Santosh Mardi22920282011-10-26 02:38:40 +05306196 for (i = 0; i < 6; j++, i += 2) {
6197 if (flag & (0x01 << i)) {
6198 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
6199 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
6200 val_txfe = val_txfe |
6201 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
6202 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6203 0x10, value);
6204 snd_soc_update_bits(codec,
6205 TABLA_A_TX_1_2_TEST_EN + j * 10,
6206 0x30, val_txfe);
6207 }
6208 if (flag & (0x01 << (i + 1))) {
6209 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
6210 val_txfe = (txfe_bypass &
6211 (0x01 << (i + 1))) ? 0x02 : 0x00;
6212 val_txfe |= (txfe_buff &
6213 (0x01 << (i + 1))) ? 0x01 : 0x00;
6214 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6215 0x01, value);
6216 snd_soc_update_bits(codec,
6217 TABLA_A_TX_1_2_TEST_EN + j * 10,
6218 0x03, val_txfe);
6219 }
6220 }
6221 if (flag & 0x40) {
6222 value = (leg_mode & 0x40) ? 0x10 : 0x00;
6223 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
6224 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
6225 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
6226 0x13, value);
6227 }
Patrick Lai49efeac2011-11-03 11:01:12 -07006228
6229 if (pdata->ocp.use_pdata) {
6230 /* not defined in CODEC specification */
6231 if (pdata->ocp.hph_ocp_limit == 1 ||
6232 pdata->ocp.hph_ocp_limit == 5) {
6233 rc = -EINVAL;
6234 goto done;
6235 }
6236 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
6237 0x0F, pdata->ocp.num_attempts);
6238 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
6239 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
6240 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
6241 0xE0, (pdata->ocp.hph_ocp_limit << 5));
6242 }
Joonwoo Park03324832012-03-19 19:36:16 -07006243
6244 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
6245 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
6246 if (pdata->regulator[i].min_uV == 1800000 &&
6247 pdata->regulator[i].max_uV == 1800000) {
6248 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6249 0x1C);
6250 } else if (pdata->regulator[i].min_uV == 2200000 &&
6251 pdata->regulator[i].max_uV == 2200000) {
6252 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6253 0x1E);
6254 } else {
6255 pr_err("%s: unsupported CDC_VDDA_RX voltage "
6256 "min %d, max %d\n", __func__,
6257 pdata->regulator[i].min_uV,
6258 pdata->regulator[i].max_uV);
6259 rc = -EINVAL;
6260 }
6261 break;
6262 }
6263 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006264done:
6265 return rc;
6266}
6267
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006268static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
6269
6270 /* Tabla 1.1 MICBIAS changes */
6271 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
6272 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
6273 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006274
6275 /* Tabla 1.1 HPH changes */
6276 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
6277 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
6278
6279 /* Tabla 1.1 EAR PA changes */
6280 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
6281 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
6282 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
6283
6284 /* Tabla 1.1 Lineout_5 Changes */
6285 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
6286
6287 /* Tabla 1.1 RX Changes */
6288 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
6289 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
6290 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
6291 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
6292 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
6293 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
6294 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
6295
6296 /* Tabla 1.1 RX1 and RX2 Changes */
6297 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
6298 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
6299
6300 /* Tabla 1.1 RX3 to RX7 Changes */
6301 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
6302 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
6303 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
6304 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
6305 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
6306
6307 /* Tabla 1.1 CLASSG Changes */
6308 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
6309};
6310
6311static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006312 /* Tabla 2.0 MICBIAS changes */
6313 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
6314};
6315
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006316static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
6317 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
6318};
6319
6320static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
6321 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
6322};
6323
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006324static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
6325{
6326 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306327 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006328
6329 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
6330 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
6331 tabla_1_1_reg_defaults[i].val);
6332
6333 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
6334 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
6335 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006336
6337 if (TABLA_IS_1_X(tabla_core->version)) {
6338 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
6339 i++)
6340 snd_soc_write(codec,
6341 tabla_1_x_only_reg_2_0_defaults[i].reg,
6342 tabla_1_x_only_reg_2_0_defaults[i].val);
6343 } else {
6344 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
6345 snd_soc_write(codec,
6346 tabla_2_only_reg_2_0_defaults[i].reg,
6347 tabla_2_only_reg_2_0_defaults[i].val);
6348 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006349}
6350
6351static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08006352 /* Initialize current threshold to 350MA
6353 * number of wait and run cycles to 4096
6354 */
Patrick Lai49efeac2011-11-03 11:01:12 -07006355 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08006356 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006357
Santosh Mardi32171012011-10-28 23:32:06 +05306358 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
6359
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006360 /* Initialize gain registers to use register gain */
6361 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
6362 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
6363 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
6364 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
6365 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
6366 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
6367
6368 /* Initialize mic biases to differential mode */
6369 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
6370 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
6371 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006372
6373 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
6374
6375 /* Use 16 bit sample size for TX1 to TX6 */
6376 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
6377 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
6378 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
6379 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
6380 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
6381 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
6382
6383 /* Use 16 bit sample size for TX7 to TX10 */
6384 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
6385 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
6386 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
6387 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
6388
6389 /* Use 16 bit sample size for RX */
6390 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
6391 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
6392
6393 /*enable HPF filter for TX paths */
6394 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
6395 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
6396 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
6397 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
6398 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
6399 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
6400 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
6401 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
6402 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
6403 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
6404};
6405
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006406static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
6407 /* Initialize mic biases to differential mode */
6408 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6409};
6410
6411static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
6412 /* Initialize mic biases to differential mode */
6413 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6414};
6415
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006416static void tabla_codec_init_reg(struct snd_soc_codec *codec)
6417{
6418 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306419 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006420
6421 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
6422 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
6423 tabla_codec_reg_init_val[i].mask,
6424 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006425 if (TABLA_IS_1_X(tabla_core->version)) {
6426 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
6427 snd_soc_update_bits(codec,
6428 tabla_1_x_codec_reg_init_val[i].reg,
6429 tabla_1_x_codec_reg_init_val[i].mask,
6430 tabla_1_x_codec_reg_init_val[i].val);
6431 } else {
6432 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
6433 i++)
6434 snd_soc_update_bits(codec,
6435 tabla_2_higher_codec_reg_init_val[i].reg,
6436 tabla_2_higher_codec_reg_init_val[i].mask,
6437 tabla_2_higher_codec_reg_init_val[i].val);
6438 }
6439}
6440
6441static void tabla_update_reg_address(struct tabla_priv *priv)
6442{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306443 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006444 struct tabla_reg_address *reg_addr = &priv->reg_addr;
6445
6446 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006447 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
6448 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006449 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006450 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006451 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
6452 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006453 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006454 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006455}
6456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006457static int tabla_codec_probe(struct snd_soc_codec *codec)
6458{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306459 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006460 struct tabla_priv *tabla;
6461 struct snd_soc_dapm_context *dapm = &codec->dapm;
6462 int ret = 0;
6463 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006464 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006465
6466 codec->control_data = dev_get_drvdata(codec->dev->parent);
6467 control = codec->control_data;
6468
6469 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
6470 if (!tabla) {
6471 dev_err(codec->dev, "Failed to allocate private data\n");
6472 return -ENOMEM;
6473 }
6474
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006475 /* Make sure mbhc micbias register addresses are zeroed out */
6476 memset(&tabla->mbhc_bias_regs, 0,
6477 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006478 tabla->cfilt_k_value = 0;
6479 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006480
Joonwoo Park0976d012011-12-22 11:48:18 -08006481 /* Make sure mbhc intenal calibration data is zeroed out */
6482 memset(&tabla->mbhc_data, 0,
6483 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08006484 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08006485 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
6486 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006487 snd_soc_codec_set_drvdata(codec, tabla);
6488
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07006489 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006490 tabla->bandgap_type = TABLA_BANDGAP_OFF;
6491 tabla->clock_active = false;
6492 tabla->config_mode_active = false;
6493 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08006494 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006495 tabla->no_mic_headset_override = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006496 tabla->hs_polling_irq_prepared = false;
6497 mutex_init(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006498 tabla->codec = codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006499 tabla->mbhc_state = MBHC_STATE_NONE;
Joonwoo Park03324832012-03-19 19:36:16 -07006500 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08006501 for (i = 0; i < COMPANDER_MAX; i++) {
6502 tabla->comp_enabled[i] = 0;
6503 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
6504 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006505 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306506 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08006507 tabla->aux_pga_cnt = 0;
6508 tabla->aux_l_gain = 0x1F;
6509 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006510 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05306511 tabla_update_reg_defaults(codec);
6512 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05306513 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07006514 if (IS_ERR_VALUE(ret)) {
6515 pr_err("%s: bad pdata\n", __func__);
6516 goto err_pdata;
6517 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006519 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006520 ARRAY_SIZE(tabla_snd_controls));
6521 if (TABLA_IS_1_X(control->version))
6522 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
6523 ARRAY_SIZE(tabla_1_x_snd_controls));
6524 else
6525 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
6526 ARRAY_SIZE(tabla_2_higher_snd_controls));
6527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006528 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006529 ARRAY_SIZE(tabla_dapm_widgets));
6530 if (TABLA_IS_1_X(control->version))
6531 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
6532 ARRAY_SIZE(tabla_1_x_dapm_widgets));
6533 else
6534 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
6535 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
6536
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306537 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05306538 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
6539 ARRAY_SIZE(tabla_dapm_i2s_widgets));
6540 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
6541 ARRAY_SIZE(audio_i2s_map));
6542 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006543 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07006544
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006545 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006546 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006547 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
6548 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006549 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006550 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006551 } else {
6552 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306553 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006554 goto err_pdata;
6555 }
6556
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006557 snd_soc_dapm_sync(dapm);
6558
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306559 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006560 tabla_hs_insert_irq, "Headset insert detect", tabla);
6561 if (ret) {
6562 pr_err("%s: Failed to request irq %d\n", __func__,
6563 TABLA_IRQ_MBHC_INSERTION);
6564 goto err_insert_irq;
6565 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306566 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006567
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306568 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006569 tabla_hs_remove_irq, "Headset remove detect", tabla);
6570 if (ret) {
6571 pr_err("%s: Failed to request irq %d\n", __func__,
6572 TABLA_IRQ_MBHC_REMOVAL);
6573 goto err_remove_irq;
6574 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006575
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306576 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07006577 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006578 if (ret) {
6579 pr_err("%s: Failed to request irq %d\n", __func__,
6580 TABLA_IRQ_MBHC_POTENTIAL);
6581 goto err_potential_irq;
6582 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006583
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306584 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07006585 tabla_release_handler, "Button Release detect", tabla);
6586 if (ret) {
6587 pr_err("%s: Failed to request irq %d\n", __func__,
6588 TABLA_IRQ_MBHC_RELEASE);
6589 goto err_release_irq;
6590 }
6591
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306592 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006593 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
6594 if (ret) {
6595 pr_err("%s: Failed to request irq %d\n", __func__,
6596 TABLA_IRQ_SLIMBUS);
6597 goto err_slimbus_irq;
6598 }
6599
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306600 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
6601 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006602 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
6603
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306604 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07006605 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
6606 "HPH_L OCP detect", tabla);
6607 if (ret) {
6608 pr_err("%s: Failed to request irq %d\n", __func__,
6609 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6610 goto err_hphl_ocp_irq;
6611 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306612 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07006613
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306614 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07006615 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
6616 "HPH_R OCP detect", tabla);
6617 if (ret) {
6618 pr_err("%s: Failed to request irq %d\n", __func__,
6619 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6620 goto err_hphr_ocp_irq;
6621 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306622 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006623 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
6624 switch (tabla_dai[i].id) {
6625 case AIF1_PB:
6626 ch_cnt = tabla_dai[i].playback.channels_max;
6627 break;
6628 case AIF1_CAP:
6629 ch_cnt = tabla_dai[i].capture.channels_max;
6630 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08006631 case AIF2_PB:
6632 ch_cnt = tabla_dai[i].playback.channels_max;
6633 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006634 default:
6635 continue;
6636 }
6637 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
6638 ch_cnt), GFP_KERNEL);
6639 }
Patrick Lai49efeac2011-11-03 11:01:12 -07006640
Bradley Rubincb3950a2011-08-18 13:07:26 -07006641#ifdef CONFIG_DEBUG_FS
6642 debug_tabla_priv = tabla;
6643#endif
6644
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006645 return ret;
6646
Patrick Lai49efeac2011-11-03 11:01:12 -07006647err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306648 wcd9xxx_free_irq(codec->control_data,
6649 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07006650err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306651 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006652err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306653 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006654err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306655 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006656err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306657 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006658err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306659 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006660err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07006661err_pdata:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006662 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006663 kfree(tabla);
6664 return ret;
6665}
6666static int tabla_codec_remove(struct snd_soc_codec *codec)
6667{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006668 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006669 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306670 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
6671 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
6672 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
6673 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
6674 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006675 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006676 tabla_codec_disable_clock_block(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006677 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006678 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08006679 if (tabla->mbhc_fw)
6680 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006681 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
6682 kfree(tabla->dai[i].ch_num);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006683 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006684 kfree(tabla);
6685 return 0;
6686}
6687static struct snd_soc_codec_driver soc_codec_dev_tabla = {
6688 .probe = tabla_codec_probe,
6689 .remove = tabla_codec_remove,
6690 .read = tabla_read,
6691 .write = tabla_write,
6692
6693 .readable_register = tabla_readable,
6694 .volatile_register = tabla_volatile,
6695
6696 .reg_cache_size = TABLA_CACHE_SIZE,
6697 .reg_cache_default = tabla_reg_defaults,
6698 .reg_word_size = 1,
6699};
Bradley Rubincb3950a2011-08-18 13:07:26 -07006700
6701#ifdef CONFIG_DEBUG_FS
6702static struct dentry *debugfs_poke;
6703
6704static int codec_debug_open(struct inode *inode, struct file *file)
6705{
6706 file->private_data = inode->i_private;
6707 return 0;
6708}
6709
6710static ssize_t codec_debug_write(struct file *filp,
6711 const char __user *ubuf, size_t cnt, loff_t *ppos)
6712{
6713 char lbuf[32];
6714 char *buf;
6715 int rc;
6716
6717 if (cnt > sizeof(lbuf) - 1)
6718 return -EINVAL;
6719
6720 rc = copy_from_user(lbuf, ubuf, cnt);
6721 if (rc)
6722 return -EFAULT;
6723
6724 lbuf[cnt] = '\0';
6725 buf = (char *)lbuf;
6726 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
6727 ? false : true;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006728 return rc;
6729}
6730
6731static const struct file_operations codec_debug_ops = {
6732 .open = codec_debug_open,
6733 .write = codec_debug_write,
6734};
6735#endif
6736
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006737#ifdef CONFIG_PM
6738static int tabla_suspend(struct device *dev)
6739{
Joonwoo Park816b8e62012-01-23 16:03:21 -08006740 dev_dbg(dev, "%s: system suspend\n", __func__);
6741 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006742}
6743
6744static int tabla_resume(struct device *dev)
6745{
Joonwoo Park03324832012-03-19 19:36:16 -07006746 struct platform_device *pdev = to_platform_device(dev);
6747 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Park816b8e62012-01-23 16:03:21 -08006748 dev_dbg(dev, "%s: system resume\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07006749 tabla->mbhc_last_resume = jiffies;
Joonwoo Park816b8e62012-01-23 16:03:21 -08006750 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006751}
6752
6753static const struct dev_pm_ops tabla_pm_ops = {
6754 .suspend = tabla_suspend,
6755 .resume = tabla_resume,
6756};
6757#endif
6758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006759static int __devinit tabla_probe(struct platform_device *pdev)
6760{
Santosh Mardie15e2302011-11-15 10:39:23 +05306761 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006762#ifdef CONFIG_DEBUG_FS
6763 debugfs_poke = debugfs_create_file("TRRS",
6764 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
6765
6766#endif
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306767 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05306768 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
6769 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306770 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05306771 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
6772 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
6773 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006774}
6775static int __devexit tabla_remove(struct platform_device *pdev)
6776{
6777 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07006778
6779#ifdef CONFIG_DEBUG_FS
6780 debugfs_remove(debugfs_poke);
6781#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006782 return 0;
6783}
6784static struct platform_driver tabla_codec_driver = {
6785 .probe = tabla_probe,
6786 .remove = tabla_remove,
6787 .driver = {
6788 .name = "tabla_codec",
6789 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006790#ifdef CONFIG_PM
6791 .pm = &tabla_pm_ops,
6792#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006793 },
6794};
6795
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006796static struct platform_driver tabla1x_codec_driver = {
6797 .probe = tabla_probe,
6798 .remove = tabla_remove,
6799 .driver = {
6800 .name = "tabla1x_codec",
6801 .owner = THIS_MODULE,
6802#ifdef CONFIG_PM
6803 .pm = &tabla_pm_ops,
6804#endif
6805 },
6806};
6807
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006808static int __init tabla_codec_init(void)
6809{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006810 int rtn = platform_driver_register(&tabla_codec_driver);
6811 if (rtn == 0) {
6812 rtn = platform_driver_register(&tabla1x_codec_driver);
6813 if (rtn != 0)
6814 platform_driver_unregister(&tabla_codec_driver);
6815 }
6816 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006817}
6818
6819static void __exit tabla_codec_exit(void)
6820{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006821 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006822 platform_driver_unregister(&tabla_codec_driver);
6823}
6824
6825module_init(tabla_codec_init);
6826module_exit(tabla_codec_exit);
6827
6828MODULE_DESCRIPTION("Tabla codec driver");
6829MODULE_VERSION("1.0");
6830MODULE_LICENSE("GPL v2");