blob: 2c437927576fd95e270d52e2d3a459cc83e695bc [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);
3594 tabla_p->dai[j].rate = 0;
3595 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303596 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003597 tabla_p->dai[j].ch_tot = 0;
3598 }
3599 }
3600 return ret;
3601}
3602
3603static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3604 struct snd_kcontrol *kcontrol, int event)
3605{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303606 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003607 struct snd_soc_codec *codec = w->codec;
3608 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3609 /* index to the DAI ID, for now hardcoding */
3610 u32 j = 0;
3611 u32 ret = 0;
3612
3613 codec->control_data = dev_get_drvdata(codec->dev->parent);
3614 tabla = codec->control_data;
3615
3616 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303617 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003618 return 0;
3619 switch (event) {
3620 case SND_SOC_DAPM_POST_PMU:
3621 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003622 if (tabla_dai[j].id == AIF1_PB ||
3623 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003624 continue;
3625 if (!strncmp(w->sname,
3626 tabla_dai[j].capture.stream_name, 13)) {
3627 ++tabla_p->dai[j].ch_act;
3628 break;
3629 }
3630 }
3631 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303632 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003633 tabla_p->dai[j].ch_num,
3634 tabla_p->dai[j].ch_tot,
3635 tabla_p->dai[j].rate);
3636 break;
3637 case SND_SOC_DAPM_POST_PMD:
3638 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003639 if (tabla_dai[j].id == AIF1_PB ||
3640 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003641 continue;
3642 if (!strncmp(w->sname,
3643 tabla_dai[j].capture.stream_name, 13)) {
3644 --tabla_p->dai[j].ch_act;
3645 break;
3646 }
3647 }
3648 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303649 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003650 tabla_p->dai[j].ch_num,
3651 tabla_p->dai[j].ch_tot);
3652 tabla_p->dai[j].rate = 0;
3653 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303654 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003655 tabla_p->dai[j].ch_tot = 0;
3656 }
3657 }
3658 return ret;
3659}
3660
3661/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3662 * Might Need to have callbacks registered only for slimbus
3663 */
3664static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
3665 /*RX stuff */
3666 SND_SOC_DAPM_OUTPUT("EAR"),
3667
3668 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
3669
3670 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
3671 ARRAY_SIZE(dac1_switch)),
3672
3673 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3674 0, tabla_codec_enable_slimrx,
3675 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3676 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3677 0, tabla_codec_enable_slimrx,
3678 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3679
3680 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3681 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3682
Neema Shettyd3a89262012-02-16 10:23:50 -08003683 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3684 0, tabla_codec_enable_slimrx,
3685 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3686 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3687 0, tabla_codec_enable_slimrx,
3688 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3689
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003690 /* Headphone */
3691 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3692 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3693 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3694 SND_SOC_DAPM_POST_PMD),
3695 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
3696 hphl_switch, ARRAY_SIZE(hphl_switch)),
3697
3698 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
3699 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3700 SND_SOC_DAPM_POST_PMD),
3701
3702 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
3703 tabla_hphr_dac_event,
3704 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3705
3706 /* Speaker */
3707 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
3708 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
3709 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
3710 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
3711 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
3712
3713 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
3714 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3715 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3716 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
3717 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3718 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3719 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
3720 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3721 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3722 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
3723 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3724 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3725 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
3726 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3727 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3728
3729 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
3730 , tabla_lineout_dac_event,
3731 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3732 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
3733 , tabla_lineout_dac_event,
3734 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3735 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
3736 , tabla_lineout_dac_event,
3737 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3738 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
3739 &lineout3_ground_switch),
3740 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
3741 , tabla_lineout_dac_event,
3742 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3743 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
3744 &lineout4_ground_switch),
3745 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
3746 , tabla_lineout_dac_event,
3747 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3748
3749 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
3750 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3751 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
3752 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3753 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
3754 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3755 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
3756 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3757 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
3758 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3759 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
3760 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3761 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
3762 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3763
3764 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
3765 &rx4_dsm_mux, tabla_codec_reset_interpolator,
3766 SND_SOC_DAPM_PRE_PMU),
3767
3768 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
3769 &rx6_dsm_mux, tabla_codec_reset_interpolator,
3770 SND_SOC_DAPM_PRE_PMU),
3771
3772 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
3773 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
3774
3775 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3776 &rx_mix1_inp1_mux),
3777 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3778 &rx_mix1_inp2_mux),
3779 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3780 &rx2_mix1_inp1_mux),
3781 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3782 &rx2_mix1_inp2_mux),
3783 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3784 &rx3_mix1_inp1_mux),
3785 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3786 &rx3_mix1_inp2_mux),
3787 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3788 &rx4_mix1_inp1_mux),
3789 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3790 &rx4_mix1_inp2_mux),
3791 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3792 &rx5_mix1_inp1_mux),
3793 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3794 &rx5_mix1_inp2_mux),
3795 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3796 &rx6_mix1_inp1_mux),
3797 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3798 &rx6_mix1_inp2_mux),
3799 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3800 &rx7_mix1_inp1_mux),
3801 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3802 &rx7_mix1_inp2_mux),
3803
3804 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
3805 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
3806 SND_SOC_DAPM_PRE_PMD),
3807
3808 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
3809 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
3810 SND_SOC_DAPM_POST_PMD),
3811
3812 /* TX */
3813
3814 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
3815 0),
3816
3817 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
3818 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
3819
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003820 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
3821 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3822 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3823 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
3824 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3825 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3826
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003827 SND_SOC_DAPM_INPUT("AMIC1"),
3828 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
3829 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3830 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3831 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
3832 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3833 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3834 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
3835 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3836 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3837 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
3838 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3839 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3840
3841 SND_SOC_DAPM_INPUT("AMIC3"),
3842 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
3843 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3844 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3845
3846 SND_SOC_DAPM_INPUT("AMIC4"),
3847 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
3848 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3849 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3850
3851 SND_SOC_DAPM_INPUT("AMIC5"),
3852 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
3853 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3854
3855 SND_SOC_DAPM_INPUT("AMIC6"),
3856 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
3857 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3858
3859 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
3860 &dec1_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3861
3862 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
3863 &dec2_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3864
3865 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
3866 &dec3_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3867
3868 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
3869 &dec4_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3870
3871 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
3872 &dec5_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3873
3874 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
3875 &dec6_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3876
3877 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
3878 &dec7_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3879
3880 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
3881 &dec8_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3882
3883 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
3884 &dec9_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3885
3886 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
3887 &dec10_mux, tabla_codec_enable_dec, SND_SOC_DAPM_PRE_PMU),
3888
3889 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
3890 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
3891
3892 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
3893 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
3894 SND_SOC_DAPM_POST_PMD),
3895
3896 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
3897
3898 SND_SOC_DAPM_INPUT("AMIC2"),
3899 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
3900 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3901 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3902 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
3903 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3904 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3905 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
3906 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3907 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3908 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
3909 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3910 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3911 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
3912 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3913 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3914 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
3915 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3916 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3917 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
3918 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3919 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3920 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
3921 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3922 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3923
3924 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
3925 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
3926 0, 0),
3927
3928 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
3929 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
3930 4, 0),
3931
3932 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
3933 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
3934 5, 0),
3935
3936 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
3937 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3938 0, tabla_codec_enable_slimtx,
3939 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3940
3941 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
3942 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
3943 0, tabla_codec_enable_slimtx,
3944 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3945
3946 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
3947 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
3948 0, 0, tabla_codec_enable_slimtx,
3949 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3950
3951 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
3952 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
3953 0, 0, tabla_codec_enable_slimtx,
3954 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3955
3956 /* Digital Mic Inputs */
3957 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
3958 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3959 SND_SOC_DAPM_POST_PMD),
3960
3961 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
3962 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3963 SND_SOC_DAPM_POST_PMD),
3964
3965 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
3966 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3967 SND_SOC_DAPM_POST_PMD),
3968
3969 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
3970 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3971 SND_SOC_DAPM_POST_PMD),
3972
3973 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
3974 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3975 SND_SOC_DAPM_POST_PMD),
3976 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
3977 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3978 SND_SOC_DAPM_POST_PMD),
3979
3980 /* Sidetone */
3981 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
3982 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003983
3984 /* AUX PGA */
3985 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
3986 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3987 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
3988 SND_SOC_DAPM_POST_PMD),
3989
3990 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
3991 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3992 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
3993 SND_SOC_DAPM_POST_PMD),
3994
3995 /* Lineout, ear and HPH PA Mixers */
3996 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
3997 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
3998
3999 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4000 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4001
4002 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4003 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4004
4005 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4006 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
4007
4008 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
4009 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
4010
4011 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
4012 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
4013
4014 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
4015 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
4016
4017 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4018 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004019};
4020
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004021static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004022{
4023 u8 bias_msb, bias_lsb;
4024 short bias_value;
4025
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004026 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
4027 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
4028 bias_value = (bias_msb << 8) | bias_lsb;
4029 return bias_value;
4030}
4031
4032static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
4033{
4034 u8 bias_msb, bias_lsb;
4035 short bias_value;
4036
4037 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
4038 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
4039 bias_value = (bias_msb << 8) | bias_lsb;
4040 return bias_value;
4041}
4042
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004043static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004044{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004045 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
4046}
4047
4048static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4049 bool override_bypass, bool noreldetection)
4050{
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004051 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004052 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4053
4054 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4055 if (noreldetection)
4056 tabla_turn_onoff_rel_detection(codec, false);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004057
Joonwoo Park925914c2012-01-05 13:35:18 -08004058 /* Turn on the override */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004059 if (!override_bypass)
4060 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004061 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004062 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4063 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
4064 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004065 usleep_range(tabla->mbhc_data.t_sta_dce,
4066 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004067 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08004068 usleep_range(tabla->mbhc_data.t_dce,
4069 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004070 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004071 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004072 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004073 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4074 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004075 usleep_range(tabla->mbhc_data.t_sta_dce,
4076 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08004077 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4078 usleep_range(tabla->mbhc_data.t_sta,
4079 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004080 bias_value = tabla_codec_read_sta_result(codec);
4081 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4082 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004083 }
Joonwoo Park925914c2012-01-05 13:35:18 -08004084 /* Turn off the override after measuring mic voltage */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004085 if (!override_bypass)
4086 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4087
4088 if (noreldetection)
4089 tabla_turn_onoff_rel_detection(codec, true);
4090 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004091
Bradley Rubincb1e2732011-06-23 16:49:20 -07004092 return bias_value;
4093}
4094
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004095static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4096 bool norel)
4097{
4098 return __tabla_codec_sta_dce(codec, dce, false, norel);
4099}
4100
4101/* called only from interrupt which is under codec_resource_lock acquisition */
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004102static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004103{
4104 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004105 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004106 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004107
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004108 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004109 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004110 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004111 }
4112
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004113 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004114 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004115 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004116 tabla_codec_enable_clock_block(codec, 1);
4117 }
4118
4119 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4120
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004121 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004122 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4123 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004124
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004125 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004126
4127 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004128 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004129
4130 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4131 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4132 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4133
4134 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004135 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4136 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004137
Joonwoo Park925914c2012-01-05 13:35:18 -08004138 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004139 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4140
Bradley Rubincb1e2732011-06-23 16:49:20 -07004141 tabla_codec_calibrate_hs_polling(codec);
4142
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004143 /* don't flip override */
4144 bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004145 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4146 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004147 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004148
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004149 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004150}
4151
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004152static int tabla_cancel_btn_work(struct tabla_priv *tabla)
4153{
4154 int r = 0;
4155 struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
4156
4157 if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
4158 /* if scheduled mbhc_btn_dwork is canceled from here,
4159 * we have to unlock from here instead btn_work */
4160 wcd9xxx_unlock_sleep(core);
4161 r = 1;
4162 }
4163 return r;
4164}
4165
4166/* called under codec_resource_lock acquisition */
4167void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
Joonwoo Park03324832012-03-19 19:36:16 -07004168{
4169 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004170 u8 wg_time;
4171
4172 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4173 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07004174
4175 /* If headphone PA is on, check if userspace receives
4176 * removal event to sync-up PA's state */
4177 if (tabla_is_hph_pa_on(codec)) {
4178 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4179 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4180 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4181 } else {
4182 pr_debug("%s PA is off\n", __func__);
4183 }
4184
4185 if (tabla_is_hph_dac_on(codec, 1))
4186 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4187 if (tabla_is_hph_dac_on(codec, 0))
4188 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004189
4190 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
4191 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
4192 0xC0, 0x00);
4193 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
4194 0xC0, 0x00);
4195 usleep_range(wg_time * 1000, wg_time * 1000);
4196}
4197
4198static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
4199{
4200 bool pa_turned_on = false;
4201 struct snd_soc_codec *codec = tabla->codec;
4202 u8 wg_time;
4203
4204 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4205 wg_time += 1;
4206
4207 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4208 &tabla->hph_pa_dac_state)) {
4209 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4210 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4211 0xC0, 0xC0);
4212 }
4213 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4214 &tabla->hph_pa_dac_state)) {
4215 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4216 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4217 0xC0, 0xC0);
4218 }
4219
4220 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4221 &tabla->hph_pa_dac_state)) {
4222 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4223 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4224 1 << 4);
4225 pa_turned_on = true;
4226 }
4227 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4228 &tabla->hph_pa_dac_state)) {
4229 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4230 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4231 1 << 5);
4232 pa_turned_on = true;
4233 }
4234
4235 if (pa_turned_on) {
4236 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4237 __func__);
4238 usleep_range(wg_time * 1000, wg_time * 1000);
4239 }
4240}
4241
4242/* called under codec_resource_lock acquisition */
4243static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4244 enum snd_jack_types jack_type)
4245{
4246 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4247
4248 if (!insertion) {
4249 /* Report removal */
4250 tabla->hph_status &= ~jack_type;
4251 if (tabla->mbhc_cfg.headset_jack) {
4252 /* cancel possibly scheduled btn work and
4253 * report release if we reported button press */
4254 if (tabla_cancel_btn_work(tabla)) {
4255 pr_debug("%s: button press is canceled\n",
4256 __func__);
4257 } else if (tabla->buttons_pressed) {
4258 pr_debug("%s: Reporting release for reported "
4259 "button press %d\n", __func__,
4260 jack_type);
4261 tabla_snd_soc_jack_report(tabla,
4262 tabla->mbhc_cfg.button_jack, 0,
4263 tabla->buttons_pressed);
4264 tabla->buttons_pressed &=
4265 ~TABLA_JACK_BUTTON_MASK;
4266 }
4267 pr_debug("%s: Reporting removal %d\n", __func__,
4268 jack_type);
4269 tabla_snd_soc_jack_report(tabla,
4270 tabla->mbhc_cfg.headset_jack,
4271 tabla->hph_status,
4272 TABLA_JACK_MASK);
4273 }
4274 tabla_set_and_turnoff_hph_padac(codec);
4275 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
4276 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4277 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
4278 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4279 tabla->current_plug = PLUG_TYPE_NONE;
4280 tabla->mbhc_polling_active = false;
4281 } else {
4282 /* Report insertion */
4283 tabla->hph_status |= jack_type;
4284
4285 if (jack_type == SND_JACK_HEADPHONE)
4286 tabla->current_plug = PLUG_TYPE_HEADPHONE;
4287 else if (jack_type == SND_JACK_HEADSET) {
4288 tabla->mbhc_polling_active = true;
4289 tabla->current_plug = PLUG_TYPE_HEADSET;
4290 }
4291 if (tabla->mbhc_cfg.headset_jack) {
4292 pr_debug("%s: Reporting insertion %d\n", __func__,
4293 jack_type);
4294 tabla_snd_soc_jack_report(tabla,
4295 tabla->mbhc_cfg.headset_jack,
4296 tabla->hph_status,
4297 TABLA_JACK_MASK);
4298 }
4299 tabla_clr_and_turnon_hph_padac(tabla);
4300 }
Joonwoo Park03324832012-03-19 19:36:16 -07004301}
4302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004303static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07004304 int insertion, int trigger,
4305 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004306{
4307 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004308 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08004309 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004310 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004311 const struct tabla_mbhc_plug_detect_cfg *plug_det =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004312 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004313
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004314 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004315 pr_err("Error, no tabla calibration\n");
4316 return -EINVAL;
4317 }
4318
4319 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
4320
Joonwoo Park03324832012-03-19 19:36:16 -07004321 /* Make sure mic bias and Mic line schmitt trigger
4322 * are turned OFF
4323 */
4324 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
4325 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
4326
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004327 if (insertion) {
Joonwoo Park03324832012-03-19 19:36:16 -07004328 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004329
Joonwoo Park03324832012-03-19 19:36:16 -07004330 /* DAPM can manipulate PA/DAC bits concurrently */
4331 if (padac_off == true) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004332 tabla_set_and_turnoff_hph_padac(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004333 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004334
Joonwoo Park03324832012-03-19 19:36:16 -07004335 if (trigger == MBHC_USE_HPHL_TRIGGER) {
4336 /* Enable HPH Schmitt Trigger */
4337 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
4338 0x11);
4339 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
4340 plug_det->hph_current << 2);
4341 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
4342 0x02);
4343 } else if (trigger == MBHC_USE_MB_TRIGGER) {
4344 /* enable the mic line schmitt trigger */
4345 snd_soc_update_bits(codec,
4346 tabla->mbhc_bias_regs.mbhc_reg,
4347 0x60, plug_det->mic_current << 5);
4348 snd_soc_update_bits(codec,
4349 tabla->mbhc_bias_regs.mbhc_reg,
4350 0x80, 0x80);
4351 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4352 snd_soc_update_bits(codec,
4353 tabla->mbhc_bias_regs.ctl_reg, 0x01,
4354 0x00);
4355 snd_soc_update_bits(codec,
4356 tabla->mbhc_bias_regs.mbhc_reg,
4357 0x10, 0x10);
4358 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004359
4360 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004361 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07004362
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004363 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004364 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004365 /* Make sure the HPH schmitt trigger is OFF */
4366 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
4367
4368 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07004369 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
4370 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004371 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08004372 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004373 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4374 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004375 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004376 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4377 0x10, 0x10);
4378
4379 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004380 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004381 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004382
4383 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004384 /* called called by interrupt */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004385 if (!(tabla->clock_active)) {
4386 tabla_codec_enable_config_mode(codec, 1);
4387 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004388 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004389 usleep_range(generic->t_shutdown_plug_rem,
4390 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004391 tabla_codec_enable_config_mode(codec, 0);
4392 } else
4393 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004394 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004395 }
4396
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004397 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004398
4399 /* If central bandgap disabled */
4400 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
4401 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004402 usleep_range(generic->t_bg_fast_settle,
4403 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004404 central_bias_enabled = 1;
4405 }
4406
4407 /* If LDO_H disabled */
4408 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
4409 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
4410 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004411 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004412 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
4413
4414 if (central_bias_enabled)
4415 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
4416 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004417
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004418 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004419 tabla->mbhc_cfg.micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004420
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304421 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004422 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4423 return 0;
4424}
4425
Joonwoo Park0976d012011-12-22 11:48:18 -08004426static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4427 s16 vin_mv)
4428{
Joonwoo Park0976d012011-12-22 11:48:18 -08004429 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004430 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08004431 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07004432 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004433
4434 tabla = snd_soc_codec_get_drvdata(codec);
4435 mb_mv = tabla->mbhc_data.micb_mv;
4436
4437 if (mb_mv == 0) {
4438 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4439 return -EINVAL;
4440 }
4441
4442 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004443 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
4444 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004445 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004446 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
4447 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004448 }
4449 in = (u32) diff * vin_mv;
4450
Joonwoo Park03324832012-03-19 19:36:16 -07004451 value = (u16) (in / mb_mv) + zero;
4452 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004453}
4454
4455static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4456 u16 bias_value)
4457{
4458 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004459 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08004460 s32 mv;
4461
4462 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004463 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004464 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004465 z = (tabla->mbhc_data.dce_z);
4466 mb = (tabla->mbhc_data.dce_mb);
4467 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004468 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004469 z = (tabla->mbhc_data.sta_z);
4470 mb = (tabla->mbhc_data.sta_mb);
4471 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004472 }
4473
4474 return mv;
4475}
4476
Joonwoo Park03324832012-03-19 19:36:16 -07004477static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004478{
4479 struct delayed_work *delayed_work;
4480 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08004481 short bias_value;
4482 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07004483 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004484
4485 pr_debug("%s:\n", __func__);
4486
4487 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07004488 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004489 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004490
4491 if (tabla) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004492 if (tabla->mbhc_cfg.button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004493 bias_value = tabla_codec_read_sta_result(tabla->codec);
4494 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304495 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004496 bias_value = tabla_codec_read_dce_result(tabla->codec);
4497 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304498 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004499 pr_debug("%s: Reporting long button press event"
4500 " STA: %d, DCE: %d\n", __func__,
4501 sta_mv, dce_mv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004502 tabla_snd_soc_jack_report(tabla,
4503 tabla->mbhc_cfg.button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07004504 tabla->buttons_pressed,
4505 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004506 }
4507 } else {
4508 pr_err("%s: Bad tabla private data\n", __func__);
4509 }
4510
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004511 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07004512 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004513}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004514
Joonwoo Park0976d012011-12-22 11:48:18 -08004515void tabla_mbhc_cal(struct snd_soc_codec *codec)
4516{
4517 struct tabla_priv *tabla;
4518 struct tabla_mbhc_btn_detect_cfg *btn_det;
4519 u8 cfilt_mode, bg_mode;
4520 u8 ncic, nmeas, navg;
4521 u32 mclk_rate;
4522 u32 dce_wait, sta_wait;
4523 u8 *n_cic;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004524 void *calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08004525
4526 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004527 calibration = tabla->mbhc_cfg.calibration;
4528
4529 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4530 tabla_turn_onoff_rel_detection(codec, false);
Joonwoo Park0976d012011-12-22 11:48:18 -08004531
4532 /* First compute the DCE / STA wait times
4533 * depending on tunable parameters.
4534 * The value is computed in microseconds
4535 */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004536 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004537 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08004538 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004539 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
4540 navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
4541 mclk_rate = tabla->mbhc_cfg.mclk_rate;
Joonwoo Park433149a2012-01-11 09:53:54 -08004542 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
4543 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08004544
4545 tabla->mbhc_data.t_dce = dce_wait;
4546 tabla->mbhc_data.t_sta = sta_wait;
4547
4548 /* LDOH and CFILT are already configured during pdata handling.
4549 * Only need to make sure CFILT and bandgap are in Fast mode.
4550 * Need to restore defaults once calculation is done.
4551 */
4552 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4553 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
4554 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
4555 0x02);
4556
4557 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
4558 * to perform ADC calibration
4559 */
4560 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004561 tabla->mbhc_cfg.micbias << 5);
Joonwoo Park0976d012011-12-22 11:48:18 -08004562 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
4563 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
4564 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
4565 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
4566
4567 /* DCE measurement for 0 volts */
4568 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4569 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4570 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004571 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4572 usleep_range(100, 100);
4573 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4574 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4575 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
4576
4577 /* DCE measurment for MB voltage */
4578 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4579 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
4580 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4581 usleep_range(100, 100);
4582 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4583 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4584 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
4585
4586 /* Sta measuremnt for 0 volts */
4587 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4588 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4589 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004590 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4591 usleep_range(100, 100);
4592 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4593 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4594 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
4595
4596 /* STA Measurement for MB Voltage */
4597 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4598 usleep_range(100, 100);
4599 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4600 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4601 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
4602
4603 /* Restore default settings. */
4604 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4605 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4606 cfilt_mode);
4607 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
4608
4609 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
4610 usleep_range(100, 100);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004611
4612 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4613 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004614}
4615
4616void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
4617 const enum tabla_mbhc_btn_det_mem mem)
4618{
4619 void *ret = &btn_det->_v_btn_low;
4620
4621 switch (mem) {
4622 case TABLA_BTN_DET_GAIN:
4623 ret += sizeof(btn_det->_n_cic);
4624 case TABLA_BTN_DET_N_CIC:
4625 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08004626 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08004627 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
4628 case TABLA_BTN_DET_V_BTN_HIGH:
4629 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
4630 case TABLA_BTN_DET_V_BTN_LOW:
4631 /* do nothing */
4632 break;
4633 default:
4634 ret = NULL;
4635 }
4636
4637 return ret;
4638}
4639
4640static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
4641{
4642 struct tabla_priv *tabla;
4643 s16 btn_mv = 0, btn_delta_mv;
4644 struct tabla_mbhc_btn_detect_cfg *btn_det;
4645 struct tabla_mbhc_plug_type_cfg *plug_type;
4646 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004647 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08004648 int i;
4649
4650 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004651 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
4652 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004653
Joonwoo Parkc0672392012-01-11 11:03:14 -08004654 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004655 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07004656 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08004657 tabla->mbhc_data.nbounce_wait = 30;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004658 } else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004659 tabla->mbhc_data.npoll = 7;
4660 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004661 }
Joonwoo Park0976d012011-12-22 11:48:18 -08004662
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004663 tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
4664 (tabla->mbhc_cfg.mclk_rate / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08004665 n_ready[tabla_codec_mclk_index(tabla)]) +
4666 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08004667 tabla->mbhc_data.v_ins_hu =
4668 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
4669 tabla->mbhc_data.v_ins_h =
4670 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
4671
4672 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
4673 for (i = 0; i < btn_det->num_btn; i++)
4674 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
4675
4676 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
4677 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
4678
4679 tabla->mbhc_data.v_b1_hu =
4680 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
4681
4682 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
4683
4684 tabla->mbhc_data.v_b1_huc =
4685 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
4686
4687 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
Joonwoo Park03324832012-03-19 19:36:16 -07004688 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
Joonwoo Park0976d012011-12-22 11:48:18 -08004689
4690 tabla->mbhc_data.v_no_mic =
4691 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
4692}
4693
4694void tabla_mbhc_init(struct snd_soc_codec *codec)
4695{
4696 struct tabla_priv *tabla;
4697 struct tabla_mbhc_general_cfg *generic;
4698 struct tabla_mbhc_btn_detect_cfg *btn_det;
4699 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08004700 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304701 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08004702
4703 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004704 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
4705 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004706
Joonwoo Park0976d012011-12-22 11:48:18 -08004707 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08004708 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004709 snd_soc_update_bits(codec,
4710 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
4711 0x07, n);
4712 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
4713 btn_det->c[n]);
4714 }
4715 }
4716 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
4717 btn_det->nc);
4718
4719 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
4720 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08004721 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08004722
4723 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08004724 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
4725 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004726
4727 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
4728 generic->mbhc_nsa << 4);
4729
4730 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
4731 btn_det->n_meas);
4732
4733 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
4734
4735 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
4736
4737 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
4738 btn_det->mbhc_nsc << 3);
4739
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004740 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
4741 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08004742
4743 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07004744
4745 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004746}
4747
Patrick Lai64b43262011-12-06 17:29:15 -08004748static bool tabla_mbhc_fw_validate(const struct firmware *fw)
4749{
4750 u32 cfg_offset;
4751 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
4752 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
4753
4754 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
4755 return false;
4756
4757 /* previous check guarantees that there is enough fw data up
4758 * to num_btn
4759 */
4760 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
4761 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
4762 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
4763 return false;
4764
4765 /* previous check guarantees that there is enough fw data up
4766 * to start of impedance detection configuration
4767 */
4768 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
4769 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
4770
4771 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
4772 return false;
4773
4774 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
4775 return false;
4776
4777 return true;
4778}
Joonwoo Park03324832012-03-19 19:36:16 -07004779
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004780static int tabla_determine_button(const struct tabla_priv *priv,
4781 const s32 bias_mv)
4782{
4783 s16 *v_btn_low, *v_btn_high;
4784 struct tabla_mbhc_btn_detect_cfg *btn_det;
4785 int i, btn = -1;
4786
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004787 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004788 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
4789 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304790 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004791 for (i = 0; i < btn_det->num_btn; i++) {
4792 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
4793 btn = i;
4794 break;
4795 }
4796 }
4797
4798 if (btn == -1)
4799 pr_debug("%s: couldn't find button number for mic mv %d\n",
4800 __func__, bias_mv);
4801
4802 return btn;
4803}
4804
4805static int tabla_get_button_mask(const int btn)
4806{
4807 int mask = 0;
4808 switch (btn) {
4809 case 0:
4810 mask = SND_JACK_BTN_0;
4811 break;
4812 case 1:
4813 mask = SND_JACK_BTN_1;
4814 break;
4815 case 2:
4816 mask = SND_JACK_BTN_2;
4817 break;
4818 case 3:
4819 mask = SND_JACK_BTN_3;
4820 break;
4821 case 4:
4822 mask = SND_JACK_BTN_4;
4823 break;
4824 case 5:
4825 mask = SND_JACK_BTN_5;
4826 break;
4827 case 6:
4828 mask = SND_JACK_BTN_6;
4829 break;
4830 case 7:
4831 mask = SND_JACK_BTN_7;
4832 break;
4833 }
4834 return mask;
4835}
4836
Bradley Rubincb1e2732011-06-23 16:49:20 -07004837static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004838{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004839 int i, mask;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004840 short dce, sta, bias_value_dce;
4841 s32 mv, stamv, bias_mv_dce;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004842 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004843 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004844 const struct tabla_mbhc_btn_detect_cfg *d =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004845 TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004846 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004847 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304848 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07004849 int n_btn_meas = d->n_btn_meas;
4850 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004851
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004852 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004853
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004854 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
4855 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
4856 pr_debug("%s: mbhc is being recovered, skip button press\n",
4857 __func__);
4858 goto done;
4859 }
4860
4861 priv->mbhc_state = MBHC_STATE_POTENTIAL;
4862
4863 if (!priv->mbhc_polling_active) {
4864 pr_warn("%s: mbhc polling is not active, skip button press\n",
4865 __func__);
4866 goto done;
4867 }
Joonwoo Park03324832012-03-19 19:36:16 -07004868
4869 dce = tabla_codec_read_dce_result(codec);
4870 mv = tabla_codec_sta_dce_v(codec, 1, dce);
4871
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004872 /* If GPIO interrupt already kicked in, ignore button press */
4873 if (priv->in_gpio_handler) {
4874 pr_debug("%s: GPIO State Changed, ignore button press\n",
4875 __func__);
4876 btn = -1;
4877 goto done;
4878 }
4879
Joonwoo Park03324832012-03-19 19:36:16 -07004880 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
4881 if (priv->mbhc_last_resume &&
4882 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
4883 pr_debug("%s: Button is already released shortly after "
4884 "resume\n", __func__);
4885 n_btn_meas = 0;
4886 } else {
4887 pr_debug("%s: Button is already released without "
4888 "resume", __func__);
4889 sta = tabla_codec_read_sta_result(codec);
4890 stamv = tabla_codec_sta_dce_v(codec, 0, sta);
4891 btn = tabla_determine_button(priv, mv);
4892 if (btn != tabla_determine_button(priv, stamv))
4893 btn = -1;
4894 goto done;
4895 }
4896 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004897
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004898 /* determine pressed button */
Joonwoo Park03324832012-03-19 19:36:16 -07004899 btnmeas[meas++] = tabla_determine_button(priv, mv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004900 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Joonwoo Park03324832012-03-19 19:36:16 -07004901 meas - 1, dce, mv, btnmeas[meas - 1]);
4902 if (n_btn_meas == 0)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004903 btn = btnmeas[0];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004904 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
4905 bias_value_dce = tabla_codec_sta_dce(codec, 1, false);
4906 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
4907 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004908 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004909 __func__, meas, bias_value_dce, bias_mv_dce,
4910 btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004911 /* if large enough measurements are collected,
4912 * start to check if last all n_btn_con measurements were
4913 * in same button low/high range */
4914 if (meas + 1 >= d->n_btn_con) {
4915 for (i = 0; i < d->n_btn_con; i++)
4916 if ((btnmeas[meas] < 0) ||
4917 (btnmeas[meas] != btnmeas[meas - i]))
4918 break;
4919 if (i == d->n_btn_con) {
4920 /* button pressed */
4921 btn = btnmeas[meas];
4922 break;
Joonwoo Park03324832012-03-19 19:36:16 -07004923 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
4924 /* if left measurements are less than n_btn_con,
4925 * it's impossible to find button number */
4926 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004927 }
4928 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08004929 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004930
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004931 if (btn >= 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004932 if (priv->in_gpio_handler) {
4933 pr_debug("%s: GPIO already triggered, ignore button "
4934 "press\n", __func__);
4935 goto done;
4936 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004937 mask = tabla_get_button_mask(btn);
4938 priv->buttons_pressed |= mask;
Joonwoo Park03324832012-03-19 19:36:16 -07004939 wcd9xxx_lock_sleep(core);
4940 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
4941 msecs_to_jiffies(400)) == 0) {
4942 WARN(1, "Button pressed twice without release"
4943 "event\n");
4944 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004945 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08004946 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004947 pr_debug("%s: bogus button press, too short press?\n",
4948 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004949 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004950
Joonwoo Park03324832012-03-19 19:36:16 -07004951 done:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004952 pr_debug("%s: leave\n", __func__);
4953 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004954 return IRQ_HANDLED;
4955}
4956
Joonwoo Park03324832012-03-19 19:36:16 -07004957static int tabla_is_fake_press(struct tabla_priv *priv)
4958{
4959 int i;
4960 int r = 0;
4961 struct snd_soc_codec *codec = priv->codec;
4962 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
4963 short mb_v;
4964
4965 for (i = 0; i < dces; i++) {
4966 usleep_range(10000, 10000);
4967 if (i == 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004968 mb_v = tabla_codec_sta_dce(codec, 0, true);
Joonwoo Park03324832012-03-19 19:36:16 -07004969 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
4970 tabla_codec_sta_dce_v(codec, 0, mb_v));
4971 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
4972 mb_v > (short)priv->mbhc_data.v_ins_hu) {
4973 r = 1;
4974 break;
4975 }
4976 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004977 mb_v = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park03324832012-03-19 19:36:16 -07004978 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
4979 tabla_codec_sta_dce_v(codec, 1, mb_v));
4980 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
4981 mb_v > (short)priv->mbhc_data.v_ins_h) {
4982 r = 1;
4983 break;
4984 }
4985 }
4986 }
4987
4988 return r;
4989}
4990
Bradley Rubincb1e2732011-06-23 16:49:20 -07004991static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08004993 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08004994 struct tabla_priv *priv = data;
4995 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004996
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004997 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07004998
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004999 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5000 priv->mbhc_state = MBHC_STATE_RELEASE;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005001
Joonwoo Park03324832012-03-19 19:36:16 -07005002 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005003 ret = tabla_cancel_btn_work(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005004 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07005005 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005006 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005007 if (priv->mbhc_cfg.button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005008 tabla_snd_soc_jack_report(priv,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005009 priv->mbhc_cfg.button_jack, 0,
5010 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005011 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005012 if (tabla_is_fake_press(priv)) {
5013 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005014 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005015 } else if (priv->mbhc_cfg.button_jack) {
5016 if (priv->in_gpio_handler) {
5017 pr_debug("%s: GPIO kicked in, ignore\n",
5018 __func__);
5019 } else {
5020 pr_debug("%s: Reporting short button 0 "
5021 "press and release\n",
5022 __func__);
5023 tabla_snd_soc_jack_report(priv,
5024 priv->mbhc_cfg.button_jack,
5025 priv->buttons_pressed,
5026 priv->buttons_pressed);
5027 tabla_snd_soc_jack_report(priv,
5028 priv->mbhc_cfg.button_jack, 0,
5029 priv->buttons_pressed);
5030 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005031 }
5032 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005033
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005034 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
5035 }
5036
Joonwoo Park03324832012-03-19 19:36:16 -07005037 tabla_codec_calibrate_hs_polling(codec);
5038
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005039 if (priv->mbhc_cfg.gpio)
5040 msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
Joonwoo Park03324832012-03-19 19:36:16 -07005041
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005042 tabla_codec_start_hs_polling(codec);
5043
5044 pr_debug("%s: leave\n", __func__);
5045 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005046 return IRQ_HANDLED;
5047}
5048
Bradley Rubincb1e2732011-06-23 16:49:20 -07005049static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
5050{
5051 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08005052 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005053 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005054
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005055 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005056 tabla_codec_enable_config_mode(codec, 1);
5057
5058 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
5059 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005060
Joonwoo Park0976d012011-12-22 11:48:18 -08005061 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
5062
5063 usleep_range(generic->t_shutdown_plug_rem,
5064 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005065
5066 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005067 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005068 tabla_codec_enable_config_mode(codec, 0);
5069
5070 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
5071}
5072
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005073static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005074{
5075 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005076
5077 tabla_codec_shutdown_hs_removal_detect(codec);
5078
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005079 if (!tabla->mclk_enabled) {
Asish Bhattacharya486745a2012-01-20 06:41:53 +05305080 tabla_codec_disable_clock_block(codec);
5081 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005082 }
5083
5084 tabla->mbhc_polling_active = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005085 tabla->mbhc_state = MBHC_STATE_NONE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005086}
5087
Patrick Lai49efeac2011-11-03 11:01:12 -07005088static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
5089{
5090 struct tabla_priv *tabla = data;
5091 struct snd_soc_codec *codec;
5092
5093 pr_info("%s: received HPHL OCP irq\n", __func__);
5094
5095 if (tabla) {
5096 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005097 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
5098 pr_info("%s: retry\n", __func__);
5099 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5100 0x00);
5101 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5102 0x10);
5103 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305104 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005105 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5106 tabla->hphlocp_cnt = 0;
5107 tabla->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005108 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005109 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005110 tabla->mbhc_cfg.headset_jack,
5111 tabla->hph_status,
5112 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005113 }
5114 } else {
5115 pr_err("%s: Bad tabla private data\n", __func__);
5116 }
5117
5118 return IRQ_HANDLED;
5119}
5120
5121static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
5122{
5123 struct tabla_priv *tabla = data;
5124 struct snd_soc_codec *codec;
5125
5126 pr_info("%s: received HPHR OCP irq\n", __func__);
5127
5128 if (tabla) {
5129 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005130 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
5131 pr_info("%s: retry\n", __func__);
5132 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5133 0x00);
5134 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5135 0x10);
5136 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305137 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005138 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5139 tabla->hphrocp_cnt = 0;
5140 tabla->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005141 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005142 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005143 tabla->mbhc_cfg.headset_jack,
5144 tabla->hph_status,
5145 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005146 }
5147 } else {
5148 pr_err("%s: Bad tabla private data\n", __func__);
5149 }
5150
5151 return IRQ_HANDLED;
5152}
5153
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005154static bool tabla_is_invalid_insertion_range(struct snd_soc_codec *codec,
5155 s32 mic_volt)
Joonwoo Park03324832012-03-19 19:36:16 -07005156{
5157 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5158 struct tabla_mbhc_plug_type_cfg *plug_type =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005159 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5160 int fake_insert_high;
5161 bool invalid = false;
Joonwoo Park03324832012-03-19 19:36:16 -07005162
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005163 if (tabla->mbhc_cfg.gpio)
5164 fake_insert_high = TABLA_MBHC_FAKE_INSERT_HIGH;
5165 else
5166 fake_insert_high = TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
5167
5168 /* Perform this check only when the high voltage headphone
5169 * needs to be considered as invalid
5170 */
5171 if (!tabla->mbhc_inval_hs_range_override
5172 && (mic_volt > plug_type->v_hs_max)) {
5173 invalid = true;
5174 } else if (mic_volt < fake_insert_high
5175 && (mic_volt > TABLA_MBHC_FAKE_INSERT_LOW)) {
5176 invalid = true;
5177 }
5178
5179 return invalid;
5180}
5181
5182static bool tabla_is_invalid_insert_delta(struct snd_soc_codec *codec,
5183 int mic_volt, int mic_volt_prev)
5184{
5185 int delta = abs(mic_volt - mic_volt_prev);
5186 if (delta > TABLA_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
5187 pr_debug("%s: volt delta %dmv\n", __func__, delta);
Joonwoo Park03324832012-03-19 19:36:16 -07005188 return true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005189 }
Joonwoo Park03324832012-03-19 19:36:16 -07005190 return false;
5191}
5192
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005193static bool tabla_codec_is_invalid_plug(struct snd_soc_codec *codec,
5194 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
5195 enum tabla_mbhc_plug_type
5196 plug_type[MBHC_NUM_DCE_PLUG_DETECT])
5197{
5198 int i;
5199 bool r = false;
5200 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5201 struct tabla_mbhc_plug_type_cfg *plug_type_ptr =
5202 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5203
5204 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
5205 if (mic_mv[i] < plug_type_ptr->v_no_mic)
5206 plug_type[i] = PLUG_TYPE_HEADPHONE;
5207 else if (mic_mv[i] < plug_type_ptr->v_hs_max)
5208 plug_type[i] = PLUG_TYPE_HEADSET;
5209 else if (mic_mv[i] > plug_type_ptr->v_hs_max)
5210 plug_type[i] = PLUG_TYPE_HIGH_HPH;
5211
5212 r = tabla_is_invalid_insertion_range(codec, mic_mv[i]);
5213 if (!r && i > 0) {
5214 if (plug_type[i-1] != plug_type[i])
5215 r = true;
5216 else
5217 r = tabla_is_invalid_insert_delta(codec,
5218 mic_mv[i],
5219 mic_mv[i - 1]);
5220 }
5221 }
5222
5223 return r;
5224}
5225
5226/* called under codec_resource_lock acquisition */
5227void tabla_find_plug_and_report(struct snd_soc_codec *codec,
5228 enum tabla_mbhc_plug_type plug_type)
Joonwoo Park03324832012-03-19 19:36:16 -07005229{
5230 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005231
5232 if (plug_type == PLUG_TYPE_HEADPHONE
5233 && tabla->current_plug == PLUG_TYPE_NONE) {
5234 /* Nothing was reported previously
5235 * reporte a headphone
5236 */
5237 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5238 tabla_codec_cleanup_hs_polling(codec);
5239 } else if (plug_type == PLUG_TYPE_HEADSET) {
5240 /* If Headphone was reported previously, this will
5241 * only report the mic line
5242 */
5243 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5244 msleep(100);
5245 tabla_codec_start_hs_polling(codec);
5246 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
5247 if (tabla->current_plug == PLUG_TYPE_NONE)
5248 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5249 tabla_codec_cleanup_hs_polling(codec);
5250 pr_debug("setup mic trigger for further detection\n");
5251 tabla->lpi_enabled = true;
5252 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5253 false);
5254 }
5255}
5256
5257/* should be called under interrupt context that hold suspend */
5258static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla)
5259{
5260 pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
5261 tabla->hs_detect_work_stop = false;
5262 wcd9xxx_lock_sleep(tabla->codec->control_data);
5263 schedule_work(&tabla->hs_correct_plug_work);
5264}
5265
5266/* called under codec_resource_lock acquisition */
5267static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla)
5268{
5269 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
5270 tabla->hs_detect_work_stop = true;
5271 wmb();
5272 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5273 if (cancel_work_sync(&tabla->hs_correct_plug_work)) {
5274 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
5275 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5276 }
5277 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5278}
5279
5280static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
5281{
5282 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
5283}
5284
5285static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
5286{
5287 return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
5288 tabla->mbhc_cfg.gpio_level_insert);
5289}
5290
5291static void tabla_hs_correct_gpio_plug(struct work_struct *work)
5292{
5293 struct tabla_priv *tabla;
5294 struct snd_soc_codec *codec;
5295 int retry = 0, i;
5296 bool correction = false;
5297 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5298 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5299 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5300 unsigned long timeout;
5301
5302 tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
5303 codec = tabla->codec;
5304
5305 pr_debug("%s: enter\n", __func__);
5306 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
5307
5308 /* Keep override on during entire plug type correction work.
5309 *
5310 * This is okay under the assumption that any GPIO irqs which use
5311 * MBHC block cancel and sync this work so override is off again
5312 * prior to GPIO interrupt handler's MBHC block usage.
5313 * Also while this correction work is running, we can guarantee
5314 * DAPM doesn't use any MBHC block as this work only runs with
5315 * headphone detection.
5316 */
5317 tabla_turn_onoff_override(codec, true);
5318
5319 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5320 while (!time_after(jiffies, timeout)) {
5321 ++retry;
5322 rmb();
5323 if (tabla->hs_detect_work_stop) {
5324 pr_debug("%s: stop requested\n", __func__);
5325 break;
5326 }
5327
5328 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
5329 if (tabla_hs_gpio_level_remove(tabla)) {
5330 pr_debug("%s: GPIO value is low\n", __func__);
5331 break;
5332 }
5333
5334 /* can race with removal interrupt */
5335 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5336 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5337 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5338 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5339 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
5340 __func__, retry, mic_mv[i], mb_v[i]);
5341 }
5342 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5343
5344 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5345 pr_debug("Invalid plug in attempt # %d\n", retry);
5346 if (retry == NUM_ATTEMPTS_TO_REPORT &&
5347 tabla->current_plug == PLUG_TYPE_NONE) {
5348 tabla_codec_report_plug(codec, 1,
5349 SND_JACK_HEADPHONE);
5350 }
5351 } else if (!tabla_codec_is_invalid_plug(codec, mic_mv,
5352 plug_type) &&
5353 plug_type[0] == PLUG_TYPE_HEADPHONE) {
5354 pr_debug("Good headphone detected, continue polling mic\n");
5355 if (tabla->current_plug == PLUG_TYPE_NONE) {
5356 tabla_codec_report_plug(codec, 1,
5357 SND_JACK_HEADPHONE);
5358 }
5359 } else {
5360 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5361 /* Turn off override */
5362 tabla_turn_onoff_override(codec, false);
5363 tabla_find_plug_and_report(codec, plug_type[0]);
5364 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5365 pr_debug("Attempt %d found correct plug %d\n", retry,
5366 plug_type[0]);
5367 correction = true;
5368 break;
5369 }
5370 }
5371
5372 /* Turn off override */
5373 if (!correction)
5374 tabla_turn_onoff_override(codec, false);
5375
5376 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
5377 pr_debug("%s: leave\n", __func__);
5378 /* unlock sleep */
5379 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5380}
5381
5382/* called under codec_resource_lock acquisition */
5383static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
5384{
5385 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005386 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5387 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005388 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5389 int i;
5390
5391 pr_debug("%s: enter\n", __func__);
5392
5393 tabla_turn_onoff_override(codec, true);
5394 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5395 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
5396 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
5397
5398 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5399 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5400 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5401 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
5402 mic_mv[i]);
5403 }
5404 tabla_turn_onoff_override(codec, false);
5405
5406 if (tabla_hs_gpio_level_remove(tabla)) {
5407 pr_debug("%s: GPIO value is low when determining plug\n",
5408 __func__);
5409 return;
5410 }
5411
5412 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5413 tabla_schedule_hs_detect_plug(tabla);
5414 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5415 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5416
5417 tabla_schedule_hs_detect_plug(tabla);
5418 } else {
5419 pr_debug("%s: Valid plug found, determine plug type\n",
5420 __func__);
5421 tabla_find_plug_and_report(codec, plug_type[0]);
5422 }
5423}
5424
5425/* called under codec_resource_lock acquisition */
5426static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
5427{
5428 int i;
5429 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5430 const struct tabla_mbhc_plug_detect_cfg *plug_det =
5431 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
5432 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5433 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5434 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
Joonwoo Park03324832012-03-19 19:36:16 -07005435 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
5436
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005437 /* Turn on the override,
5438 * tabla_codec_setup_hs_polling requires override on */
5439 tabla_turn_onoff_override(codec, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005440
5441 if (plug_det->t_ins_complete > 20)
5442 msleep(plug_det->t_ins_complete);
5443 else
5444 usleep_range(plug_det->t_ins_complete * 1000,
5445 plug_det->t_ins_complete * 1000);
5446
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005447 if (tabla->mbhc_cfg.gpio) {
5448 /* Turn off the override */
5449 tabla_turn_onoff_override(codec, false);
5450 if (tabla_hs_gpio_level_remove(tabla))
5451 pr_debug("%s: GPIO value is low when determining "
5452 "plug\n", __func__);
5453 else
5454 tabla_codec_decide_gpio_plug(codec);
5455 return;
5456 }
5457
Joonwoo Park03324832012-03-19 19:36:16 -07005458 /*
5459 * First DCE measurement,
5460 * IF this is fake, discontinue detection
5461 * and restart insertion detection
5462 */
5463 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5464 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005465 if (tabla_is_invalid_insertion_range(codec, mic_mv[0])) {
Joonwoo Park03324832012-03-19 19:36:16 -07005466 pr_debug("%s: Detect attempt 1, detected Fake\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005467 tabla_turn_onoff_override(codec, false);
5468 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005469 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5470 false);
5471 return;
5472 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005473 pr_debug("%s: DCE run 1, %x, mic_mv = %d\n", __func__, mb_v[0],
Joonwoo Park03324832012-03-19 19:36:16 -07005474 mic_mv[0]);
5475
5476 /*
5477 * Perform two more DCE measurements,
5478 * IF any of them is fake, discontinue detection
5479 * and restart insertion detection
5480 */
Joonwoo Park03324832012-03-19 19:36:16 -07005481 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005482 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005483 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005484 pr_debug("%s: DCE run %d, %x, mic_mv = %d\n", __func__, i + 1,
Joonwoo Park03324832012-03-19 19:36:16 -07005485 mb_v[1], mic_mv[i]);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005486 if (tabla_is_invalid_insertion_range(codec, mic_mv[i])
5487 || tabla_is_invalid_insert_delta(codec, mic_mv[i],
5488 mic_mv[i - 1])) {
Joonwoo Park03324832012-03-19 19:36:16 -07005489 pr_debug("%s: Detect attempt %d, detected Fake\n",
5490 __func__, i + 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005491 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005492 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
5493 0x02, 0x02);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005494 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005495 tabla_codec_enable_hs_detect(codec, 1,
5496 MBHC_USE_MB_TRIGGER,
5497 false);
5498 return;
5499 }
5500 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005501 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005502
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005503 plug_type_ptr =
5504 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07005505
5506 /*
5507 * If we are here, means none of the three
5508 * measurements are fake, continue plug type detection.
5509 * If all three measurements do not produce same
5510 * plug type, restart insertion detection
5511 */
5512 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5513 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
5514 plug_type[i] = PLUG_TYPE_HEADPHONE;
5515 pr_debug("%s: Detect attempt %d, detected Headphone\n",
5516 __func__, i);
5517 } else {
5518 plug_type[i] = PLUG_TYPE_HEADSET;
5519 pr_debug("%s: Detect attempt %d, detected Headset\n",
5520 __func__, i);
5521 }
5522
5523 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
5524 pr_err("%s: Detect attempt %d and %d are not same",
5525 __func__, i - 1, i);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005526 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005527 tabla_codec_enable_hs_detect(codec, 1,
5528 MBHC_USE_MB_TRIGGER,
5529 false);
5530 return;
5531 }
5532 }
5533
5534 if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5535 pr_debug("%s: Headphone Detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005536 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5537 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005538 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005539 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
5540 pr_debug("%s: Headset detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005541 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5542
Joonwoo Park03324832012-03-19 19:36:16 -07005543 /* avoid false button press detect */
5544 msleep(50);
Joonwoo Park03324832012-03-19 19:36:16 -07005545 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005546 }
5547}
5548
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005549/* called only from interrupt which is under codec_resource_lock acquisition */
5550static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005551{
Bradley Rubincb1e2732011-06-23 16:49:20 -07005552 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005553
5554 if (!is_removal) {
5555 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
5556
5557 rmb();
5558 if (priv->lpi_enabled)
5559 msleep(100);
5560
5561 rmb();
5562 if (!priv->lpi_enabled) {
5563 pr_debug("%s: lpi is disabled\n", __func__);
5564 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
5565 priv->mbhc_cfg.gpio_level_insert) {
5566 pr_debug("%s: Valid insertion, "
5567 "detect plug type\n", __func__);
5568 tabla_codec_decide_gpio_plug(codec);
5569 } else {
5570 pr_debug("%s: Invalid insertion, "
5571 "stop plug detection\n", __func__);
5572 }
5573 } else {
5574 pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
5575 }
5576}
5577
5578/* called only from interrupt which is under codec_resource_lock acquisition */
5579static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
5580 bool is_mb_trigger)
5581{
Joonwoo Park03324832012-03-19 19:36:16 -07005582 int ret;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005583 struct snd_soc_codec *codec = priv->codec;
5584 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005585
5586 if (is_removal) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005587 /* cancel possiblely running hs detect work */
5588 tabla_cancel_hs_detect_plug(priv);
5589
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005590 /*
5591 * If headphone is removed while playback is in progress,
5592 * it is possible that micbias will be switched to VDDIO.
5593 */
Joonwoo Park03324832012-03-19 19:36:16 -07005594 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005595 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005596 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005597 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5598 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005599 } else if (is_mb_trigger && !is_removal) {
Joonwoo Park03324832012-03-19 19:36:16 -07005600 pr_debug("%s: Waiting for Headphone left trigger\n",
5601 __func__);
5602 wcd9xxx_lock_sleep(core);
5603 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
5604 usecs_to_jiffies(1000000)) == 0) {
5605 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
5606 __func__);
5607 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005608 }
Joonwoo Park03324832012-03-19 19:36:16 -07005609 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
5610 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005611 } else {
5612 wcd9xxx_lock_sleep(core);
5613 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
5614 if (ret != 0) {
5615 pr_debug("%s: Complete plug insertion, Detecting plug "
5616 "type\n", __func__);
5617 tabla_codec_detect_plug_type(codec);
5618 wcd9xxx_unlock_sleep(core);
5619 } else {
5620 wcd9xxx_enable_irq(codec->control_data,
5621 TABLA_IRQ_MBHC_INSERTION);
5622 pr_err("%s: Error detecting plug insertion\n",
5623 __func__);
5624 }
Joonwoo Park03324832012-03-19 19:36:16 -07005625 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005626}
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08005627
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005628static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
5629{
5630 bool is_mb_trigger, is_removal;
5631 struct tabla_priv *priv = data;
5632 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005633
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005634 pr_debug("%s: enter\n", __func__);
5635 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5636 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
5637
5638 is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
5639 0x10);
5640 is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
5641 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
5642
5643 /* Turn off both HPH and MIC line schmitt triggers */
5644 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5645 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
5646 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5647
5648 if (priv->mbhc_cfg.gpio)
5649 tabla_hs_insert_irq_gpio(priv, is_removal);
5650 else
5651 tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
5652
5653 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005654 return IRQ_HANDLED;
5655}
5656
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005657static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
5658{
5659 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5660 struct tabla_mbhc_plug_type_cfg *plug_type =
5661 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5662
5663 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
5664 && (mic_mv < plug_type->v_hs_max)) ? true : false;
5665}
5666
5667/* called under codec_resource_lock acquisition
5668 * returns true if mic voltage range is back to normal insertion
5669 * returns false either if timedout or removed */
5670static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
5671{
5672 int i;
5673 bool timedout, settled = false;
5674 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5675 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5676 unsigned long retry = 0, timeout;
5677 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5678 struct tabla_mbhc_plug_type_cfg *plug_type =
5679 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5680
5681 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5682 while (!(timedout = time_after(jiffies, timeout))) {
5683 retry++;
5684 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5685 pr_debug("%s: GPIO indicates removal\n", __func__);
5686 break;
5687 }
5688
5689 if (tabla->mbhc_cfg.gpio) {
5690 if (retry > 1)
5691 msleep(250);
5692 else
5693 msleep(50);
5694 }
5695
5696 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5697 pr_debug("%s: GPIO indicates removal\n", __func__);
5698 break;
5699 }
5700
5701 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5702 mb_v[i] = tabla_codec_sta_dce(codec, 1, true);
5703 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5704 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
5705 __func__, retry, mic_mv[i], mb_v[i]);
5706 }
5707
5708 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5709 pr_debug("%s: GPIO indicates removal\n", __func__);
5710 break;
5711 }
5712
5713 if (tabla->current_plug == PLUG_TYPE_NONE) {
5714 pr_debug("%s : headset/headphone is removed\n",
5715 __func__);
5716 break;
5717 }
5718
5719 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5720 if (!is_valid_mic_voltage(codec, mic_mv[i]))
5721 break;
5722
5723 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5724 pr_debug("%s: MIC voltage settled\n", __func__);
5725 settled = true;
5726 msleep(200);
5727 break;
5728 }
5729
5730 /* only for non-GPIO remove irq */
5731 if (!tabla->mbhc_cfg.gpio) {
5732 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5733 if (mic_mv[i] < plug_type->v_hs_max)
5734 break;
5735 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5736 pr_debug("%s: Headset is removed\n", __func__);
5737 break;
5738 }
5739 }
5740 }
5741
5742 if (timedout)
5743 pr_debug("%s: Microphone did not settle in %d seconds\n",
5744 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
5745 return settled;
5746}
5747
5748/* called only from interrupt which is under codec_resource_lock acquisition */
5749static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
5750{
5751 struct snd_soc_codec *codec = priv->codec;
5752
5753 if (tabla_hs_remove_settle(codec))
5754 tabla_codec_start_hs_polling(codec);
5755 pr_debug("%s: remove settle done\n", __func__);
5756}
5757
5758/* called only from interrupt which is under codec_resource_lock acquisition */
5759static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005760{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005761 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005762 bool removed = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005763 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08005764 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005765 TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005766 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005767
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005768 if (priv->current_plug != PLUG_TYPE_HEADSET) {
5769 pr_debug("%s(): Headset is not inserted, ignore removal\n",
5770 __func__);
5771 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
5772 0x08, 0x08);
5773 return;
5774 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005775
Joonwoo Park0976d012011-12-22 11:48:18 -08005776 usleep_range(generic->t_shutdown_plug_rem,
5777 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005778
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005779 do {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005780 bias_value = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005781 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
5782 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
5783 if (bias_value < (short)priv->mbhc_data.v_ins_h) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005784 pr_debug("%s: checking false removal\n", __func__);
5785 msleep(500);
5786 removed = !tabla_hs_remove_settle(codec);
5787 pr_debug("%s: headset %sactually removed\n", __func__,
5788 removed ? "" : "not ");
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005789 break;
5790 }
5791 min_us -= priv->mbhc_data.t_dce;
5792 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005793
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005794 if (removed) {
5795 /* cancel possiblely running hs detect work */
5796 tabla_cancel_hs_detect_plug(priv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005797 /*
5798 * If this removal is not false, first check the micbias
5799 * switch status and switch it to LDOH if it is already
5800 * switched to VDDIO.
5801 */
Joonwoo Park03324832012-03-19 19:36:16 -07005802 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07005803
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005804 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
5805 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005806 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5807 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005808 } else {
5809 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005810 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005811}
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005812
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005813static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
5814{
5815 struct tabla_priv *priv = data;
5816 pr_debug("%s: enter, removal interrupt\n", __func__);
5817
5818 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5819 if (priv->mbhc_cfg.gpio)
5820 tabla_hs_remove_irq_gpio(priv);
5821 else
5822 tabla_hs_remove_irq_nogpio(priv);
5823
5824 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005825 return IRQ_HANDLED;
5826}
5827
Joonwoo Park03324832012-03-19 19:36:16 -07005828void mbhc_insert_work(struct work_struct *work)
5829{
5830 struct delayed_work *dwork;
5831 struct tabla_priv *tabla;
5832 struct snd_soc_codec *codec;
5833 struct wcd9xxx *tabla_core;
5834
5835 dwork = to_delayed_work(work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005836 tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
Joonwoo Park03324832012-03-19 19:36:16 -07005837 codec = tabla->codec;
5838 tabla_core = dev_get_drvdata(codec->dev->parent);
5839
5840 pr_debug("%s:\n", __func__);
5841
5842 /* Turn off both HPH and MIC line schmitt triggers */
5843 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5844 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
5845 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5846 wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
5847 tabla_codec_detect_plug_type(codec);
5848 wcd9xxx_unlock_sleep(tabla_core);
5849}
5850
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005851static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
5852{
5853 bool insert;
5854 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5855 bool is_removed = false;
5856
5857 pr_debug("%s: enter\n", __func__);
5858
5859 tabla->in_gpio_handler = true;
5860 /* Wait here for debounce time */
5861 usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
5862 TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
5863
5864 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5865
5866 /* cancel pending button press */
5867 if (tabla_cancel_btn_work(tabla))
5868 pr_debug("%s: button press is canceled\n", __func__);
5869
5870 insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
5871 tabla->mbhc_cfg.gpio_level_insert);
5872 if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
5873 tabla->lpi_enabled = false;
5874 wmb();
5875
5876 /* cancel detect plug */
5877 tabla_cancel_hs_detect_plug(tabla);
5878
5879 /* Disable Mic Bias pull down and HPH Switch to GND */
5880 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
5881 0x00);
5882 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
5883 tabla_codec_detect_plug_type(codec);
5884 } else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
5885 tabla->lpi_enabled = false;
5886 wmb();
5887
5888 /* cancel detect plug */
5889 tabla_cancel_hs_detect_plug(tabla);
5890
5891 if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
5892 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
5893 is_removed = true;
5894 } else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
5895 tabla_codec_pause_hs_polling(codec);
5896 tabla_codec_cleanup_hs_polling(codec);
5897 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
5898 is_removed = true;
5899 }
5900
5901 if (is_removed) {
5902 /* Enable Mic Bias pull down and HPH Switch to GND */
5903 snd_soc_update_bits(codec,
5904 tabla->mbhc_bias_regs.ctl_reg, 0x01,
5905 0x01);
5906 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
5907 0x01);
5908 /* Make sure mic trigger is turned off */
5909 snd_soc_update_bits(codec,
5910 tabla->mbhc_bias_regs.ctl_reg,
5911 0x01, 0x01);
5912 snd_soc_update_bits(codec,
5913 tabla->mbhc_bias_regs.mbhc_reg,
5914 0x90, 0x00);
5915 /* Reset MBHC State Machine */
5916 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
5917 0x08, 0x08);
5918 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
5919 0x08, 0x00);
5920 /* Turn off override */
5921 tabla_turn_onoff_override(codec, false);
5922 }
5923 }
5924
5925 tabla->in_gpio_handler = false;
5926 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5927 pr_debug("%s: leave\n", __func__);
5928}
5929
5930static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
5931{
5932 int r = IRQ_HANDLED;
5933 struct snd_soc_codec *codec = data;
5934
5935 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
5936 pr_warn("%s: failed to hold suspend\n", __func__);
5937 r = IRQ_NONE;
5938 } else {
5939 tabla_hs_gpio_handler(codec);
5940 wcd9xxx_unlock_sleep(codec->control_data);
5941 }
5942
5943 return r;
5944}
5945
5946static void mbhc_fw_read(struct work_struct *work)
5947{
5948 struct delayed_work *dwork;
5949 struct tabla_priv *tabla;
5950 struct snd_soc_codec *codec;
5951 const struct firmware *fw;
5952 int ret = -1, retry = 0, rc;
5953
5954 dwork = to_delayed_work(work);
5955 tabla = container_of(dwork, struct tabla_priv,
5956 mbhc_firmware_dwork);
5957 codec = tabla->codec;
5958
5959 while (retry < MBHC_FW_READ_ATTEMPTS) {
5960 retry++;
5961 pr_info("%s:Attempt %d to request MBHC firmware\n",
5962 __func__, retry);
5963 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
5964 codec->dev);
5965
5966 if (ret != 0) {
5967 usleep_range(MBHC_FW_READ_TIMEOUT,
5968 MBHC_FW_READ_TIMEOUT);
5969 } else {
5970 pr_info("%s: MBHC Firmware read succesful\n", __func__);
5971 break;
5972 }
5973 }
5974
5975 if (ret != 0) {
5976 pr_err("%s: Cannot load MBHC firmware use default cal\n",
5977 __func__);
5978 } else if (tabla_mbhc_fw_validate(fw) == false) {
5979 pr_err("%s: Invalid MBHC cal data size use default cal\n",
5980 __func__);
5981 release_firmware(fw);
5982 } else {
5983 tabla->mbhc_cfg.calibration = (void *)fw->data;
5984 tabla->mbhc_fw = fw;
5985 }
5986
5987 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
5988 tabla_mbhc_init(codec);
5989 tabla_mbhc_cal(codec);
5990 tabla_mbhc_calc_thres(codec);
5991 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
5992 tabla_codec_calibrate_hs_polling(codec);
5993 if (!tabla->mbhc_cfg.gpio) {
5994 tabla->mbhc_inval_hs_range_override = false;
5995 rc = tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5996 false);
5997
5998 if (IS_ERR_VALUE(rc))
5999 pr_err("%s: Failed to setup MBHC detection\n",
6000 __func__);
6001 } else {
6002 tabla->mbhc_inval_hs_range_override = true;
6003 /* Enable Mic Bias pull down and HPH Switch to GND */
6004 snd_soc_update_bits(codec,
6005 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6006 0x01);
6007 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6008 0x01);
6009 INIT_WORK(&tabla->hs_correct_plug_work,
6010 tabla_hs_correct_gpio_plug);
6011 }
6012
6013}
6014
Joonwoo Park03324832012-03-19 19:36:16 -07006015int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006016 const struct tabla_mbhc_config *cfg)
Joonwoo Park03324832012-03-19 19:36:16 -07006017{
6018 struct tabla_priv *tabla;
6019 int rc = 0;
6020
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006021 if (!codec || !cfg->calibration) {
Joonwoo Park03324832012-03-19 19:36:16 -07006022 pr_err("Error: no codec or calibration\n");
6023 return -EINVAL;
6024 }
6025
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006026 if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
6027 if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Joonwoo Park03324832012-03-19 19:36:16 -07006028 pr_err("Error: clock rate %dHz is not yet supported\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006029 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006030 else
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006031 pr_err("Error: unsupported clock rate %d\n",
6032 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006033 return -EINVAL;
6034 }
6035
6036 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006037 tabla->mbhc_cfg = *cfg;
6038 tabla->in_gpio_handler = false;
6039 tabla->current_plug = PLUG_TYPE_NONE;
6040 tabla->lpi_enabled = false;
Joonwoo Park03324832012-03-19 19:36:16 -07006041 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
6042
6043 /* Put CFILT in fast mode by default */
6044 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
6045 0x40, TABLA_CFILT_FAST_MODE);
6046 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
6047 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
6048 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
6049 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
6050 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
6051
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006052 if (!tabla->mbhc_cfg.read_fw_bin) {
6053 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006054 tabla_mbhc_init(codec);
6055 tabla_mbhc_cal(codec);
6056 tabla_mbhc_calc_thres(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006057 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006058 tabla_codec_calibrate_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006059 if (!tabla->mbhc_cfg.gpio) {
6060 tabla->mbhc_inval_hs_range_override = false;
6061 rc = tabla_codec_enable_hs_detect(codec, 1,
6062 MBHC_USE_MB_TRIGGER,
6063 false);
6064 } else {
6065 tabla->mbhc_inval_hs_range_override = true;
6066 /* Enable Mic Bias pull down and HPH Switch to GND */
6067 snd_soc_update_bits(codec,
6068 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6069 0x01);
6070 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6071 0x01);
6072 INIT_WORK(&tabla->hs_correct_plug_work,
6073 tabla_hs_correct_gpio_plug);
6074 }
Joonwoo Park03324832012-03-19 19:36:16 -07006075 } else {
6076 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
6077 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
6078 }
6079
6080 if (!IS_ERR_VALUE(rc)) {
6081 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
6082 wcd9xxx_enable_irq(codec->control_data,
6083 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6084 wcd9xxx_enable_irq(codec->control_data,
6085 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6086 }
6087
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006088 if (!IS_ERR_VALUE(rc) && tabla->mbhc_cfg.gpio) {
6089 rc = request_threaded_irq(tabla->mbhc_cfg.gpio_irq, NULL,
6090 tabla_mechanical_plug_detect_irq,
6091 (IRQF_TRIGGER_RISING |
6092 IRQF_TRIGGER_FALLING),
6093 "tabla-gpio", codec);
6094 if (!IS_ERR_VALUE(rc)) {
6095 rc = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
6096 /* Bootup time detection */
6097 tabla_hs_gpio_handler(codec);
6098 }
6099 }
6100
Joonwoo Park03324832012-03-19 19:36:16 -07006101 return rc;
6102}
6103EXPORT_SYMBOL_GPL(tabla_hs_detect);
6104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006105static unsigned long slimbus_value;
6106
6107static irqreturn_t tabla_slimbus_irq(int irq, void *data)
6108{
6109 struct tabla_priv *priv = data;
6110 struct snd_soc_codec *codec = priv->codec;
6111 int i, j;
6112 u8 val;
6113
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306114 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
6115 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006116 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
6117 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306118 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006119 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
6120 if (val & 0x1)
6121 pr_err_ratelimited("overflow error on port %x,"
6122 " value %x\n", i*8 + j, val);
6123 if (val & 0x2)
6124 pr_err_ratelimited("underflow error on port %x,"
6125 " value %x\n", i*8 + j, val);
6126 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306127 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006128 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
6129 }
6130
6131 return IRQ_HANDLED;
6132}
6133
Patrick Lai3043fba2011-08-01 14:15:57 -07006134
6135static int tabla_handle_pdata(struct tabla_priv *tabla)
6136{
6137 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306138 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07006139 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05306140 u8 leg_mode = pdata->amic_settings.legacy_mode;
6141 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
6142 u8 txfe_buff = pdata->amic_settings.txfe_buff;
6143 u8 flag = pdata->amic_settings.use_pdata;
6144 u8 i = 0, j = 0;
6145 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07006146
6147 if (!pdata) {
6148 rc = -ENODEV;
6149 goto done;
6150 }
6151
6152 /* Make sure settings are correct */
6153 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
6154 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
6155 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
6156 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
6157 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
6158 rc = -EINVAL;
6159 goto done;
6160 }
6161
6162 /* figure out k value */
6163 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
6164 pdata->micbias.cfilt1_mv);
6165 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
6166 pdata->micbias.cfilt2_mv);
6167 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
6168 pdata->micbias.cfilt3_mv);
6169
6170 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
6171 rc = -EINVAL;
6172 goto done;
6173 }
6174
6175 /* Set voltage level and always use LDO */
6176 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
6177 (pdata->micbias.ldoh_v << 2));
6178
6179 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
6180 (k1 << 2));
6181 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
6182 (k2 << 2));
6183 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
6184 (k3 << 2));
6185
6186 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
6187 (pdata->micbias.bias1_cfilt_sel << 5));
6188 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
6189 (pdata->micbias.bias2_cfilt_sel << 5));
6190 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
6191 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006192 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
6193 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07006194
Santosh Mardi22920282011-10-26 02:38:40 +05306195 for (i = 0; i < 6; j++, i += 2) {
6196 if (flag & (0x01 << i)) {
6197 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
6198 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
6199 val_txfe = val_txfe |
6200 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
6201 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6202 0x10, value);
6203 snd_soc_update_bits(codec,
6204 TABLA_A_TX_1_2_TEST_EN + j * 10,
6205 0x30, val_txfe);
6206 }
6207 if (flag & (0x01 << (i + 1))) {
6208 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
6209 val_txfe = (txfe_bypass &
6210 (0x01 << (i + 1))) ? 0x02 : 0x00;
6211 val_txfe |= (txfe_buff &
6212 (0x01 << (i + 1))) ? 0x01 : 0x00;
6213 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6214 0x01, value);
6215 snd_soc_update_bits(codec,
6216 TABLA_A_TX_1_2_TEST_EN + j * 10,
6217 0x03, val_txfe);
6218 }
6219 }
6220 if (flag & 0x40) {
6221 value = (leg_mode & 0x40) ? 0x10 : 0x00;
6222 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
6223 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
6224 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
6225 0x13, value);
6226 }
Patrick Lai49efeac2011-11-03 11:01:12 -07006227
6228 if (pdata->ocp.use_pdata) {
6229 /* not defined in CODEC specification */
6230 if (pdata->ocp.hph_ocp_limit == 1 ||
6231 pdata->ocp.hph_ocp_limit == 5) {
6232 rc = -EINVAL;
6233 goto done;
6234 }
6235 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
6236 0x0F, pdata->ocp.num_attempts);
6237 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
6238 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
6239 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
6240 0xE0, (pdata->ocp.hph_ocp_limit << 5));
6241 }
Joonwoo Park03324832012-03-19 19:36:16 -07006242
6243 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
6244 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
6245 if (pdata->regulator[i].min_uV == 1800000 &&
6246 pdata->regulator[i].max_uV == 1800000) {
6247 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6248 0x1C);
6249 } else if (pdata->regulator[i].min_uV == 2200000 &&
6250 pdata->regulator[i].max_uV == 2200000) {
6251 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6252 0x1E);
6253 } else {
6254 pr_err("%s: unsupported CDC_VDDA_RX voltage "
6255 "min %d, max %d\n", __func__,
6256 pdata->regulator[i].min_uV,
6257 pdata->regulator[i].max_uV);
6258 rc = -EINVAL;
6259 }
6260 break;
6261 }
6262 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006263done:
6264 return rc;
6265}
6266
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006267static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
6268
6269 /* Tabla 1.1 MICBIAS changes */
6270 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
6271 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
6272 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006273
6274 /* Tabla 1.1 HPH changes */
6275 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
6276 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
6277
6278 /* Tabla 1.1 EAR PA changes */
6279 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
6280 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
6281 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
6282
6283 /* Tabla 1.1 Lineout_5 Changes */
6284 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
6285
6286 /* Tabla 1.1 RX Changes */
6287 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
6288 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
6289 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
6290 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
6291 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
6292 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
6293 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
6294
6295 /* Tabla 1.1 RX1 and RX2 Changes */
6296 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
6297 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
6298
6299 /* Tabla 1.1 RX3 to RX7 Changes */
6300 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
6301 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
6302 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
6303 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
6304 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
6305
6306 /* Tabla 1.1 CLASSG Changes */
6307 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
6308};
6309
6310static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006311 /* Tabla 2.0 MICBIAS changes */
6312 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
6313};
6314
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006315static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
6316 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
6317};
6318
6319static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
6320 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
6321};
6322
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006323static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
6324{
6325 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306326 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006327
6328 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
6329 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
6330 tabla_1_1_reg_defaults[i].val);
6331
6332 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
6333 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
6334 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006335
6336 if (TABLA_IS_1_X(tabla_core->version)) {
6337 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
6338 i++)
6339 snd_soc_write(codec,
6340 tabla_1_x_only_reg_2_0_defaults[i].reg,
6341 tabla_1_x_only_reg_2_0_defaults[i].val);
6342 } else {
6343 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
6344 snd_soc_write(codec,
6345 tabla_2_only_reg_2_0_defaults[i].reg,
6346 tabla_2_only_reg_2_0_defaults[i].val);
6347 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006348}
6349
6350static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08006351 /* Initialize current threshold to 350MA
6352 * number of wait and run cycles to 4096
6353 */
Patrick Lai49efeac2011-11-03 11:01:12 -07006354 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08006355 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006356
Santosh Mardi32171012011-10-28 23:32:06 +05306357 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
6358
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006359 /* Initialize gain registers to use register gain */
6360 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
6361 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
6362 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
6363 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
6364 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
6365 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
6366
6367 /* Initialize mic biases to differential mode */
6368 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
6369 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
6370 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006371
6372 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
6373
6374 /* Use 16 bit sample size for TX1 to TX6 */
6375 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
6376 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
6377 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
6378 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
6379 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
6380 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
6381
6382 /* Use 16 bit sample size for TX7 to TX10 */
6383 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
6384 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
6385 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
6386 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
6387
6388 /* Use 16 bit sample size for RX */
6389 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
6390 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
6391
6392 /*enable HPF filter for TX paths */
6393 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
6394 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
6395 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
6396 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
6397 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
6398 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
6399 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
6400 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
6401 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
6402 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
6403};
6404
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006405static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
6406 /* Initialize mic biases to differential mode */
6407 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6408};
6409
6410static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
6411 /* Initialize mic biases to differential mode */
6412 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6413};
6414
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006415static void tabla_codec_init_reg(struct snd_soc_codec *codec)
6416{
6417 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306418 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006419
6420 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
6421 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
6422 tabla_codec_reg_init_val[i].mask,
6423 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006424 if (TABLA_IS_1_X(tabla_core->version)) {
6425 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
6426 snd_soc_update_bits(codec,
6427 tabla_1_x_codec_reg_init_val[i].reg,
6428 tabla_1_x_codec_reg_init_val[i].mask,
6429 tabla_1_x_codec_reg_init_val[i].val);
6430 } else {
6431 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
6432 i++)
6433 snd_soc_update_bits(codec,
6434 tabla_2_higher_codec_reg_init_val[i].reg,
6435 tabla_2_higher_codec_reg_init_val[i].mask,
6436 tabla_2_higher_codec_reg_init_val[i].val);
6437 }
6438}
6439
6440static void tabla_update_reg_address(struct tabla_priv *priv)
6441{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306442 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006443 struct tabla_reg_address *reg_addr = &priv->reg_addr;
6444
6445 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006446 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
6447 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006448 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006449 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006450 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
6451 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006452 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006453 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006454}
6455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006456static int tabla_codec_probe(struct snd_soc_codec *codec)
6457{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306458 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006459 struct tabla_priv *tabla;
6460 struct snd_soc_dapm_context *dapm = &codec->dapm;
6461 int ret = 0;
6462 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006463 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006464
6465 codec->control_data = dev_get_drvdata(codec->dev->parent);
6466 control = codec->control_data;
6467
6468 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
6469 if (!tabla) {
6470 dev_err(codec->dev, "Failed to allocate private data\n");
6471 return -ENOMEM;
6472 }
6473
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006474 /* Make sure mbhc micbias register addresses are zeroed out */
6475 memset(&tabla->mbhc_bias_regs, 0,
6476 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006477 tabla->cfilt_k_value = 0;
6478 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006479
Joonwoo Park0976d012011-12-22 11:48:18 -08006480 /* Make sure mbhc intenal calibration data is zeroed out */
6481 memset(&tabla->mbhc_data, 0,
6482 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08006483 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08006484 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
6485 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006486 snd_soc_codec_set_drvdata(codec, tabla);
6487
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07006488 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006489 tabla->bandgap_type = TABLA_BANDGAP_OFF;
6490 tabla->clock_active = false;
6491 tabla->config_mode_active = false;
6492 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08006493 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006494 tabla->no_mic_headset_override = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006495 tabla->hs_polling_irq_prepared = false;
6496 mutex_init(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006497 tabla->codec = codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006498 tabla->mbhc_state = MBHC_STATE_NONE;
Joonwoo Park03324832012-03-19 19:36:16 -07006499 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08006500 for (i = 0; i < COMPANDER_MAX; i++) {
6501 tabla->comp_enabled[i] = 0;
6502 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
6503 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006504 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306505 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08006506 tabla->aux_pga_cnt = 0;
6507 tabla->aux_l_gain = 0x1F;
6508 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006509 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05306510 tabla_update_reg_defaults(codec);
6511 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05306512 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07006513 if (IS_ERR_VALUE(ret)) {
6514 pr_err("%s: bad pdata\n", __func__);
6515 goto err_pdata;
6516 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006518 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006519 ARRAY_SIZE(tabla_snd_controls));
6520 if (TABLA_IS_1_X(control->version))
6521 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
6522 ARRAY_SIZE(tabla_1_x_snd_controls));
6523 else
6524 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
6525 ARRAY_SIZE(tabla_2_higher_snd_controls));
6526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006527 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006528 ARRAY_SIZE(tabla_dapm_widgets));
6529 if (TABLA_IS_1_X(control->version))
6530 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
6531 ARRAY_SIZE(tabla_1_x_dapm_widgets));
6532 else
6533 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
6534 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
6535
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306536 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05306537 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
6538 ARRAY_SIZE(tabla_dapm_i2s_widgets));
6539 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
6540 ARRAY_SIZE(audio_i2s_map));
6541 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006542 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07006543
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006544 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006545 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006546 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
6547 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006548 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006549 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006550 } else {
6551 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306552 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006553 goto err_pdata;
6554 }
6555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006556 snd_soc_dapm_sync(dapm);
6557
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306558 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006559 tabla_hs_insert_irq, "Headset insert detect", tabla);
6560 if (ret) {
6561 pr_err("%s: Failed to request irq %d\n", __func__,
6562 TABLA_IRQ_MBHC_INSERTION);
6563 goto err_insert_irq;
6564 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306565 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006566
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306567 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006568 tabla_hs_remove_irq, "Headset remove detect", tabla);
6569 if (ret) {
6570 pr_err("%s: Failed to request irq %d\n", __func__,
6571 TABLA_IRQ_MBHC_REMOVAL);
6572 goto err_remove_irq;
6573 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006574
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306575 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07006576 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006577 if (ret) {
6578 pr_err("%s: Failed to request irq %d\n", __func__,
6579 TABLA_IRQ_MBHC_POTENTIAL);
6580 goto err_potential_irq;
6581 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006582
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306583 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07006584 tabla_release_handler, "Button Release detect", tabla);
6585 if (ret) {
6586 pr_err("%s: Failed to request irq %d\n", __func__,
6587 TABLA_IRQ_MBHC_RELEASE);
6588 goto err_release_irq;
6589 }
6590
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306591 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006592 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
6593 if (ret) {
6594 pr_err("%s: Failed to request irq %d\n", __func__,
6595 TABLA_IRQ_SLIMBUS);
6596 goto err_slimbus_irq;
6597 }
6598
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306599 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
6600 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006601 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
6602
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306603 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07006604 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
6605 "HPH_L OCP detect", tabla);
6606 if (ret) {
6607 pr_err("%s: Failed to request irq %d\n", __func__,
6608 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6609 goto err_hphl_ocp_irq;
6610 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306611 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07006612
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306613 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07006614 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
6615 "HPH_R OCP detect", tabla);
6616 if (ret) {
6617 pr_err("%s: Failed to request irq %d\n", __func__,
6618 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6619 goto err_hphr_ocp_irq;
6620 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306621 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006622 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
6623 switch (tabla_dai[i].id) {
6624 case AIF1_PB:
6625 ch_cnt = tabla_dai[i].playback.channels_max;
6626 break;
6627 case AIF1_CAP:
6628 ch_cnt = tabla_dai[i].capture.channels_max;
6629 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08006630 case AIF2_PB:
6631 ch_cnt = tabla_dai[i].playback.channels_max;
6632 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006633 default:
6634 continue;
6635 }
6636 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
6637 ch_cnt), GFP_KERNEL);
6638 }
Patrick Lai49efeac2011-11-03 11:01:12 -07006639
Bradley Rubincb3950a2011-08-18 13:07:26 -07006640#ifdef CONFIG_DEBUG_FS
6641 debug_tabla_priv = tabla;
6642#endif
6643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006644 return ret;
6645
Patrick Lai49efeac2011-11-03 11:01:12 -07006646err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306647 wcd9xxx_free_irq(codec->control_data,
6648 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07006649err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306650 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006651err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306652 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006653err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306654 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006655err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306656 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006657err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306658 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006659err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07006660err_pdata:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006661 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006662 kfree(tabla);
6663 return ret;
6664}
6665static int tabla_codec_remove(struct snd_soc_codec *codec)
6666{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006667 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006668 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306669 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
6670 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
6671 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
6672 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
6673 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006674 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006675 tabla_codec_disable_clock_block(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006676 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006677 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08006678 if (tabla->mbhc_fw)
6679 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006680 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
6681 kfree(tabla->dai[i].ch_num);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006682 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006683 kfree(tabla);
6684 return 0;
6685}
6686static struct snd_soc_codec_driver soc_codec_dev_tabla = {
6687 .probe = tabla_codec_probe,
6688 .remove = tabla_codec_remove,
6689 .read = tabla_read,
6690 .write = tabla_write,
6691
6692 .readable_register = tabla_readable,
6693 .volatile_register = tabla_volatile,
6694
6695 .reg_cache_size = TABLA_CACHE_SIZE,
6696 .reg_cache_default = tabla_reg_defaults,
6697 .reg_word_size = 1,
6698};
Bradley Rubincb3950a2011-08-18 13:07:26 -07006699
6700#ifdef CONFIG_DEBUG_FS
6701static struct dentry *debugfs_poke;
6702
6703static int codec_debug_open(struct inode *inode, struct file *file)
6704{
6705 file->private_data = inode->i_private;
6706 return 0;
6707}
6708
6709static ssize_t codec_debug_write(struct file *filp,
6710 const char __user *ubuf, size_t cnt, loff_t *ppos)
6711{
6712 char lbuf[32];
6713 char *buf;
6714 int rc;
6715
6716 if (cnt > sizeof(lbuf) - 1)
6717 return -EINVAL;
6718
6719 rc = copy_from_user(lbuf, ubuf, cnt);
6720 if (rc)
6721 return -EFAULT;
6722
6723 lbuf[cnt] = '\0';
6724 buf = (char *)lbuf;
6725 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
6726 ? false : true;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006727 return rc;
6728}
6729
6730static const struct file_operations codec_debug_ops = {
6731 .open = codec_debug_open,
6732 .write = codec_debug_write,
6733};
6734#endif
6735
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006736#ifdef CONFIG_PM
6737static int tabla_suspend(struct device *dev)
6738{
Joonwoo Park816b8e62012-01-23 16:03:21 -08006739 dev_dbg(dev, "%s: system suspend\n", __func__);
6740 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006741}
6742
6743static int tabla_resume(struct device *dev)
6744{
Joonwoo Park03324832012-03-19 19:36:16 -07006745 struct platform_device *pdev = to_platform_device(dev);
6746 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Park816b8e62012-01-23 16:03:21 -08006747 dev_dbg(dev, "%s: system resume\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07006748 tabla->mbhc_last_resume = jiffies;
Joonwoo Park816b8e62012-01-23 16:03:21 -08006749 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006750}
6751
6752static const struct dev_pm_ops tabla_pm_ops = {
6753 .suspend = tabla_suspend,
6754 .resume = tabla_resume,
6755};
6756#endif
6757
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006758static int __devinit tabla_probe(struct platform_device *pdev)
6759{
Santosh Mardie15e2302011-11-15 10:39:23 +05306760 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006761#ifdef CONFIG_DEBUG_FS
6762 debugfs_poke = debugfs_create_file("TRRS",
6763 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
6764
6765#endif
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306766 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05306767 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
6768 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306769 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05306770 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
6771 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
6772 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006773}
6774static int __devexit tabla_remove(struct platform_device *pdev)
6775{
6776 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07006777
6778#ifdef CONFIG_DEBUG_FS
6779 debugfs_remove(debugfs_poke);
6780#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006781 return 0;
6782}
6783static struct platform_driver tabla_codec_driver = {
6784 .probe = tabla_probe,
6785 .remove = tabla_remove,
6786 .driver = {
6787 .name = "tabla_codec",
6788 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006789#ifdef CONFIG_PM
6790 .pm = &tabla_pm_ops,
6791#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006792 },
6793};
6794
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006795static struct platform_driver tabla1x_codec_driver = {
6796 .probe = tabla_probe,
6797 .remove = tabla_remove,
6798 .driver = {
6799 .name = "tabla1x_codec",
6800 .owner = THIS_MODULE,
6801#ifdef CONFIG_PM
6802 .pm = &tabla_pm_ops,
6803#endif
6804 },
6805};
6806
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006807static int __init tabla_codec_init(void)
6808{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006809 int rtn = platform_driver_register(&tabla_codec_driver);
6810 if (rtn == 0) {
6811 rtn = platform_driver_register(&tabla1x_codec_driver);
6812 if (rtn != 0)
6813 platform_driver_unregister(&tabla_codec_driver);
6814 }
6815 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006816}
6817
6818static void __exit tabla_codec_exit(void)
6819{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006820 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006821 platform_driver_unregister(&tabla_codec_driver);
6822}
6823
6824module_init(tabla_codec_init);
6825module_exit(tabla_codec_exit);
6826
6827MODULE_DESCRIPTION("Tabla codec driver");
6828MODULE_VERSION("1.0");
6829MODULE_LICENSE("GPL v2");