blob: d49e2152ad5d62237560fb11d2018d0f497493dd [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
Kiran Kandid8cf5212012-03-02 15:34:53 -0800212struct hpf_work {
213 struct tabla_priv *tabla;
214 u32 decimator;
215 u8 tx_hpf_cut_of_freq;
216 struct delayed_work dwork;
217};
218
219static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
220
Bradley Rubin229c6a52011-07-12 16:18:48 -0700221struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800223 struct tabla_reg_address reg_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700224 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700225 u32 cfilt1_cnt;
226 u32 cfilt2_cnt;
227 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700228 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700230 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231 bool clock_active;
232 bool config_mode_active;
233 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800234 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700235 int buttons_pressed;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700236 enum tabla_mbhc_state mbhc_state;
237 struct tabla_mbhc_config mbhc_cfg;
Joonwoo Park0976d012011-12-22 11:48:18 -0800238 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700239
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530240 struct wcd9xxx_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700241 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700242
243 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700244 /* Delayed work to report long button press */
Joonwoo Park03324832012-03-19 19:36:16 -0700245 struct delayed_work mbhc_btn_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700246
247 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700248 u8 cfilt_k_value;
249 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700250
Joonwoo Parka9444452011-12-08 18:48:27 -0800251 /* track PA/DAC state */
252 unsigned long hph_pa_dac_state;
253
Santosh Mardie15e2302011-11-15 10:39:23 +0530254 /*track tabla interface type*/
255 u8 intf_type;
256
Patrick Lai49efeac2011-11-03 11:01:12 -0700257 u32 hph_status; /* track headhpone status */
258 /* define separate work for left and right headphone OCP to avoid
259 * additional checking on which OCP event to report so no locking
260 * to ensure synchronization is required
261 */
262 struct work_struct hphlocp_work; /* reporting left hph ocp off */
263 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800264
Patrick Laic7cae882011-11-18 11:52:49 -0800265 u8 hphlocp_cnt; /* headphone left ocp retry */
266 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800267
Patrick Lai64b43262011-12-06 17:29:15 -0800268 /* Work to perform MBHC Firmware Read */
269 struct delayed_work mbhc_firmware_dwork;
270 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800271
272 /* num of slim ports required */
273 struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800274
275 /*compander*/
276 int comp_enabled[COMPANDER_MAX];
277 u32 comp_fs[COMPANDER_MAX];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800278
279 /* Maintain the status of AUX PGA */
280 int aux_pga_cnt;
281 u8 aux_l_gain;
282 u8 aux_r_gain;
Joonwoo Park03324832012-03-19 19:36:16 -0700283
Joonwoo Park03324832012-03-19 19:36:16 -0700284 struct delayed_work mbhc_insert_dwork;
285 unsigned long mbhc_last_resume; /* in jiffies */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700286
287 u8 current_plug;
288 struct work_struct hs_correct_plug_work;
289 bool hs_detect_work_stop;
290 bool hs_polling_irq_prepared;
291 bool lpi_enabled; /* low power insertion detection */
292 bool in_gpio_handler;
293 /* Currently, only used for mbhc purpose, to protect
294 * concurrent execution of mbhc threaded irq handlers and
295 * kill race between DAPM and MBHC.But can serve as a
296 * general lock to protect codec resource
297 */
298 struct mutex codec_resource_lock;
299
300 /* Used to override the rule "invalid headset
301 * when microphone voltage is too high"
302 */
303 bool mbhc_inval_hs_range_override;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304};
305
Bradley Rubincb3950a2011-08-18 13:07:26 -0700306#ifdef CONFIG_DEBUG_FS
307struct tabla_priv *debug_tabla_priv;
308#endif
309
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800310static const u32 comp_shift[] = {
311 0,
312 2,
313};
314
315static const int comp_rx_path[] = {
316 COMPANDER_1,
317 COMPANDER_1,
318 COMPANDER_2,
319 COMPANDER_2,
320 COMPANDER_2,
321 COMPANDER_2,
322 COMPANDER_MAX,
323};
324
325static const struct comp_sample_dependent_params comp_samp_params[] = {
326 {
327 .peak_det_timeout = 0x2,
328 .rms_meter_div_fact = 0x8 << 4,
329 .rms_meter_resamp_fact = 0x21,
330 },
331 {
332 .peak_det_timeout = 0x3,
333 .rms_meter_div_fact = 0x9 << 4,
334 .rms_meter_resamp_fact = 0x28,
335 },
336
337 {
338 .peak_det_timeout = 0x5,
339 .rms_meter_div_fact = 0xB << 4,
340 .rms_meter_resamp_fact = 0x28,
341 },
342
343 {
344 .peak_det_timeout = 0x5,
345 .rms_meter_div_fact = 0xB << 4,
346 .rms_meter_resamp_fact = 0x28,
347 },
348};
349
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
351 struct snd_kcontrol *kcontrol, int event)
352{
353 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700354
355 pr_debug("%s %d\n", __func__, event);
356 switch (event) {
357 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
359 0x01);
360 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
361 usleep_range(200, 200);
362 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
363 break;
364 case SND_SOC_DAPM_PRE_PMD:
365 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
366 0x10);
367 usleep_range(20, 20);
368 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
369 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
370 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
371 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
372 0x00);
373 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700374 break;
375 }
376 return 0;
377}
378
Bradley Rubina7096d02011-08-03 18:29:02 -0700379static int tabla_get_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 ucontrol->value.integer.value[0] = tabla->anc_slot;
385 return 0;
386}
387
388static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
389 struct snd_ctl_elem_value *ucontrol)
390{
391 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
392 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
393 tabla->anc_slot = ucontrol->value.integer.value[0];
394 return 0;
395}
396
Kiran Kandid2d86b52011-09-09 17:44:28 -0700397static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
398 struct snd_ctl_elem_value *ucontrol)
399{
400 u8 ear_pa_gain;
401 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
402
403 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
404
405 ear_pa_gain = ear_pa_gain >> 5;
406
407 if (ear_pa_gain == 0x00) {
408 ucontrol->value.integer.value[0] = 0;
409 } else if (ear_pa_gain == 0x04) {
410 ucontrol->value.integer.value[0] = 1;
411 } else {
412 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
413 __func__, ear_pa_gain);
414 return -EINVAL;
415 }
416
417 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
418
419 return 0;
420}
421
422static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
423 struct snd_ctl_elem_value *ucontrol)
424{
425 u8 ear_pa_gain;
426 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
427
428 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
429 ucontrol->value.integer.value[0]);
430
431 switch (ucontrol->value.integer.value[0]) {
432 case 0:
433 ear_pa_gain = 0x00;
434 break;
435 case 1:
436 ear_pa_gain = 0x80;
437 break;
438 default:
439 return -EINVAL;
440 }
441
442 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
443 return 0;
444}
445
Ben Romberger1f045a72011-11-04 10:14:57 -0700446static int tabla_get_iir_enable_audio_mixer(
447 struct snd_kcontrol *kcontrol,
448 struct snd_ctl_elem_value *ucontrol)
449{
450 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
451 int iir_idx = ((struct soc_multi_mixer_control *)
452 kcontrol->private_value)->reg;
453 int band_idx = ((struct soc_multi_mixer_control *)
454 kcontrol->private_value)->shift;
455
456 ucontrol->value.integer.value[0] =
457 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
458 (1 << band_idx);
459
460 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
461 iir_idx, band_idx,
462 (uint32_t)ucontrol->value.integer.value[0]);
463 return 0;
464}
465
466static int tabla_put_iir_enable_audio_mixer(
467 struct snd_kcontrol *kcontrol,
468 struct snd_ctl_elem_value *ucontrol)
469{
470 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
471 int iir_idx = ((struct soc_multi_mixer_control *)
472 kcontrol->private_value)->reg;
473 int band_idx = ((struct soc_multi_mixer_control *)
474 kcontrol->private_value)->shift;
475 int value = ucontrol->value.integer.value[0];
476
477 /* Mask first 5 bits, 6-8 are reserved */
478 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
479 (1 << band_idx), (value << band_idx));
480
481 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
482 iir_idx, band_idx, value);
483 return 0;
484}
485static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
486 int iir_idx, int band_idx,
487 int coeff_idx)
488{
489 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800490 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700491 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800492 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700493
494 /* Mask bits top 2 bits since they are reserved */
495 return ((snd_soc_read(codec,
496 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
497 (snd_soc_read(codec,
498 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
499 (snd_soc_read(codec,
500 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
501 (snd_soc_read(codec,
502 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
503 0x3FFFFFFF;
504}
505
506static int tabla_get_iir_band_audio_mixer(
507 struct snd_kcontrol *kcontrol,
508 struct snd_ctl_elem_value *ucontrol)
509{
510 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
511 int iir_idx = ((struct soc_multi_mixer_control *)
512 kcontrol->private_value)->reg;
513 int band_idx = ((struct soc_multi_mixer_control *)
514 kcontrol->private_value)->shift;
515
516 ucontrol->value.integer.value[0] =
517 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
518 ucontrol->value.integer.value[1] =
519 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
520 ucontrol->value.integer.value[2] =
521 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
522 ucontrol->value.integer.value[3] =
523 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
524 ucontrol->value.integer.value[4] =
525 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
526
527 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
528 "%s: IIR #%d band #%d b1 = 0x%x\n"
529 "%s: IIR #%d band #%d b2 = 0x%x\n"
530 "%s: IIR #%d band #%d a1 = 0x%x\n"
531 "%s: IIR #%d band #%d a2 = 0x%x\n",
532 __func__, iir_idx, band_idx,
533 (uint32_t)ucontrol->value.integer.value[0],
534 __func__, iir_idx, band_idx,
535 (uint32_t)ucontrol->value.integer.value[1],
536 __func__, iir_idx, band_idx,
537 (uint32_t)ucontrol->value.integer.value[2],
538 __func__, iir_idx, band_idx,
539 (uint32_t)ucontrol->value.integer.value[3],
540 __func__, iir_idx, band_idx,
541 (uint32_t)ucontrol->value.integer.value[4]);
542 return 0;
543}
544
545static void set_iir_band_coeff(struct snd_soc_codec *codec,
546 int iir_idx, int band_idx,
547 int coeff_idx, uint32_t value)
548{
549 /* Mask top 3 bits, 6-8 are reserved */
550 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800551 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700552 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800553 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700554
555 /* Mask top 2 bits, 7-8 are reserved */
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_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800558 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700559
560 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800561 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700562 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800563 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700564
Ben Romberger0915aae2012-02-06 23:32:43 -0800565 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700566 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800567 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700568
Ben Romberger0915aae2012-02-06 23:32:43 -0800569 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700570 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800571 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700572}
573
574static int tabla_put_iir_band_audio_mixer(
575 struct snd_kcontrol *kcontrol,
576 struct snd_ctl_elem_value *ucontrol)
577{
578 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
579 int iir_idx = ((struct soc_multi_mixer_control *)
580 kcontrol->private_value)->reg;
581 int band_idx = ((struct soc_multi_mixer_control *)
582 kcontrol->private_value)->shift;
583
584 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
585 ucontrol->value.integer.value[0]);
586 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
587 ucontrol->value.integer.value[1]);
588 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
589 ucontrol->value.integer.value[2]);
590 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
591 ucontrol->value.integer.value[3]);
592 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
593 ucontrol->value.integer.value[4]);
594
595 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
596 "%s: IIR #%d band #%d b1 = 0x%x\n"
597 "%s: IIR #%d band #%d b2 = 0x%x\n"
598 "%s: IIR #%d band #%d a1 = 0x%x\n"
599 "%s: IIR #%d band #%d a2 = 0x%x\n",
600 __func__, iir_idx, band_idx,
601 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
602 __func__, iir_idx, band_idx,
603 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
604 __func__, iir_idx, band_idx,
605 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
606 __func__, iir_idx, band_idx,
607 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
608 __func__, iir_idx, band_idx,
609 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
610 return 0;
611}
612
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800613static int tabla_compander_gain_offset(
614 struct snd_soc_codec *codec, u32 enable,
615 unsigned int reg, int mask, int event)
616{
617 int pa_mode = snd_soc_read(codec, reg) & mask;
618 int gain_offset = 0;
619 /* if PMU && enable is 1-> offset is 3
620 * if PMU && enable is 0-> offset is 0
621 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
622 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
623 */
624
625 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
626 gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
627 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
628 gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
629 return gain_offset;
630}
631
632
633static int tabla_config_gain_compander(
634 struct snd_soc_codec *codec,
635 u32 compander, u32 enable, int event)
636{
637 int value = 0;
638 int mask = 1 << 4;
639 int gain = 0;
640 int gain_offset;
641 if (compander >= COMPANDER_MAX) {
642 pr_err("%s: Error, invalid compander channel\n", __func__);
643 return -EINVAL;
644 }
645
646 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
647 value = 1 << 4;
648
649 if (compander == COMPANDER_1) {
650 gain_offset = tabla_compander_gain_offset(codec, enable,
651 TABLA_A_RX_HPH_L_GAIN, mask, event);
652 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
653 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
654 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
655 0xFF, gain - gain_offset);
656 gain_offset = tabla_compander_gain_offset(codec, enable,
657 TABLA_A_RX_HPH_R_GAIN, mask, event);
658 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
659 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
660 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
661 0xFF, gain - gain_offset);
662 } else if (compander == COMPANDER_2) {
663 gain_offset = tabla_compander_gain_offset(codec, enable,
664 TABLA_A_RX_LINE_1_GAIN, mask, event);
665 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
666 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
667 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
668 0xFF, gain - gain_offset);
669 gain_offset = tabla_compander_gain_offset(codec, enable,
670 TABLA_A_RX_LINE_3_GAIN, mask, event);
671 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
672 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
673 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
674 0xFF, gain - gain_offset);
675 gain_offset = tabla_compander_gain_offset(codec, enable,
676 TABLA_A_RX_LINE_2_GAIN, mask, event);
677 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
678 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
679 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
680 0xFF, gain - gain_offset);
681 gain_offset = tabla_compander_gain_offset(codec, enable,
682 TABLA_A_RX_LINE_4_GAIN, mask, event);
683 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
684 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
685 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
686 0xFF, gain - gain_offset);
687 }
688 return 0;
689}
690static int tabla_get_compander(struct snd_kcontrol *kcontrol,
691 struct snd_ctl_elem_value *ucontrol)
692{
693
694 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
695 int comp = ((struct soc_multi_mixer_control *)
696 kcontrol->private_value)->max;
697 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
698
699 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
700
701 return 0;
702}
703
704static int tabla_set_compander(struct snd_kcontrol *kcontrol,
705 struct snd_ctl_elem_value *ucontrol)
706{
707 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
708 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
709 int comp = ((struct soc_multi_mixer_control *)
710 kcontrol->private_value)->max;
711 int value = ucontrol->value.integer.value[0];
712
713 if (value == tabla->comp_enabled[comp]) {
714 pr_debug("%s: compander #%d enable %d no change\n",
715 __func__, comp, value);
716 return 0;
717 }
718 tabla->comp_enabled[comp] = value;
719 return 0;
720}
721
722
723static int tabla_config_compander(struct snd_soc_dapm_widget *w,
724 struct snd_kcontrol *kcontrol,
725 int event)
726{
727 struct snd_soc_codec *codec = w->codec;
728 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
729 u32 rate = tabla->comp_fs[w->shift];
730
731 switch (event) {
732 case SND_SOC_DAPM_PRE_PMU:
733 if (tabla->comp_enabled[w->shift] != 0) {
734 /* Enable both L/R compander clocks */
735 snd_soc_update_bits(codec,
736 TABLA_A_CDC_CLK_RX_B2_CTL,
737 0x03 << comp_shift[w->shift],
738 0x03 << comp_shift[w->shift]);
739 /* Clar the HALT for the compander*/
740 snd_soc_update_bits(codec,
741 TABLA_A_CDC_COMP1_B1_CTL +
742 w->shift * 8, 1 << 2, 0);
743 /* Toggle compander reset bits*/
744 snd_soc_update_bits(codec,
745 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
746 0x03 << comp_shift[w->shift],
747 0x03 << comp_shift[w->shift]);
748 snd_soc_update_bits(codec,
749 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
750 0x03 << comp_shift[w->shift], 0);
751 tabla_config_gain_compander(codec, w->shift, 1, event);
752 /* Update the RMS meter resampling*/
753 snd_soc_update_bits(codec,
754 TABLA_A_CDC_COMP1_B3_CTL +
755 w->shift * 8, 0xFF, 0x01);
756 /* Wait for 1ms*/
757 usleep_range(1000, 1000);
758 }
759 break;
760 case SND_SOC_DAPM_POST_PMU:
761 /* Set sample rate dependent paramater*/
762 if (tabla->comp_enabled[w->shift] != 0) {
763 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
764 w->shift * 8, 0x03, rate);
765 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
766 w->shift * 8, 0x0F,
767 comp_samp_params[rate].peak_det_timeout);
768 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
769 w->shift * 8, 0xF0,
770 comp_samp_params[rate].rms_meter_div_fact);
771 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
772 w->shift * 8, 0xFF,
773 comp_samp_params[rate].rms_meter_resamp_fact);
774 /* Compander enable -> 0x370/0x378*/
775 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
776 w->shift * 8, 0x03, 0x03);
777 }
778 break;
779 case SND_SOC_DAPM_PRE_PMD:
780 /* Halt the compander*/
781 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
782 w->shift * 8, 1 << 2, 1 << 2);
783 break;
784 case SND_SOC_DAPM_POST_PMD:
785 /* Restore the gain */
786 tabla_config_gain_compander(codec, w->shift,
787 tabla->comp_enabled[w->shift], event);
788 /* Disable the compander*/
789 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
790 w->shift * 8, 0x03, 0x00);
791 /* Turn off the clock for compander in pair*/
792 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
793 0x03 << comp_shift[w->shift], 0);
794 break;
795 }
796 return 0;
797}
798
Kiran Kandid2d86b52011-09-09 17:44:28 -0700799static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
800static const struct soc_enum tabla_ear_pa_gain_enum[] = {
801 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
802};
803
Santosh Mardi024010f2011-10-18 06:27:21 +0530804/*cut of frequency for high pass filter*/
805static const char *cf_text[] = {
806 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
807};
808
809static const struct soc_enum cf_dec1_enum =
810 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
811
812static const struct soc_enum cf_dec2_enum =
813 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
814
815static const struct soc_enum cf_dec3_enum =
816 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
817
818static const struct soc_enum cf_dec4_enum =
819 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
820
821static const struct soc_enum cf_dec5_enum =
822 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
823
824static const struct soc_enum cf_dec6_enum =
825 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
826
827static const struct soc_enum cf_dec7_enum =
828 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
829
830static const struct soc_enum cf_dec8_enum =
831 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
832
833static const struct soc_enum cf_dec9_enum =
834 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
835
836static const struct soc_enum cf_dec10_enum =
837 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
838
839static const struct soc_enum cf_rxmix1_enum =
840 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
841
842static const struct soc_enum cf_rxmix2_enum =
843 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
844
845static const struct soc_enum cf_rxmix3_enum =
846 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
847
848static const struct soc_enum cf_rxmix4_enum =
849 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
850
851static const struct soc_enum cf_rxmix5_enum =
852 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
853;
854static const struct soc_enum cf_rxmix6_enum =
855 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
856
857static const struct soc_enum cf_rxmix7_enum =
858 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700861
862 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
863 tabla_pa_gain_get, tabla_pa_gain_put),
864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
866 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700867 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
868 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
870 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700871 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
872 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700873 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
874 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700875
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700876 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
877 line_gain),
878 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
879 line_gain),
880
Bradley Rubin410383f2011-07-22 13:44:23 -0700881 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
882 -84, 40, digital_gain),
883 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
884 -84, 40, digital_gain),
885 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
886 -84, 40, digital_gain),
887 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
888 -84, 40, digital_gain),
889 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
890 -84, 40, digital_gain),
891 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
892 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -0800893 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
894 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895
Bradley Rubin410383f2011-07-22 13:44:23 -0700896 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700898 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700900 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
901 digital_gain),
902 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
903 digital_gain),
904 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
905 digital_gain),
906 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
907 digital_gain),
908 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
909 digital_gain),
910 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
911 digital_gain),
912 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
913 digital_gain),
914 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
915 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700916 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
917 40, digital_gain),
918 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
919 40, digital_gain),
920 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
921 40, digital_gain),
922 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
923 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700924 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
925 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700926 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
927 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700928 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
929 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800931 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
932 aux_pga_gain),
933 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
934 aux_pga_gain),
935
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800937 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700938 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700939
940 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
941 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530942 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
943 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
944 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
945 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
946 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
947 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
948 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
949 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
950 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
951 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
952
953 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
954 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
955 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
956 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
957 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
958 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
959 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
960 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
961 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
962 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
963
964 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
965 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
966 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
967 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
968 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
969 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
970 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
971
972 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
973 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
974 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
975 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
976 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
977 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
978 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700979
980 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
981 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
982 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
983 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
984 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
985 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
986 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
987 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
988 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
989 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
990 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
991 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
992 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
993 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
994 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
995 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
996 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
997 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
998 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
999 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1000
1001 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1002 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1003 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1004 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1005 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1006 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1007 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1008 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1009 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1010 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1011 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1012 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1013 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1014 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1015 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1016 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1017 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1018 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1019 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1020 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001021 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
1022 tabla_get_compander, tabla_set_compander),
1023 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
1024 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025};
1026
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001027static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
1028 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
1029};
1030
1031static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
1032 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
1033};
1034
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035static const char *rx_mix1_text[] = {
1036 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1037 "RX5", "RX6", "RX7"
1038};
1039
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001040static const char *rx_dsm_text[] = {
1041 "CIC_OUT", "DSM_INV"
1042};
1043
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044static const char *sb_tx1_mux_text[] = {
1045 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1046 "DEC1"
1047};
1048
1049static const char *sb_tx5_mux_text[] = {
1050 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1051 "DEC5"
1052};
1053
1054static const char *sb_tx6_mux_text[] = {
1055 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1056 "DEC6"
1057};
1058
1059static const char const *sb_tx7_to_tx10_mux_text[] = {
1060 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1061 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1062 "DEC9", "DEC10"
1063};
1064
1065static const char *dec1_mux_text[] = {
1066 "ZERO", "DMIC1", "ADC6",
1067};
1068
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001069static const char *dec2_mux_text[] = {
1070 "ZERO", "DMIC2", "ADC5",
1071};
1072
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001073static const char *dec3_mux_text[] = {
1074 "ZERO", "DMIC3", "ADC4",
1075};
1076
1077static const char *dec4_mux_text[] = {
1078 "ZERO", "DMIC4", "ADC3",
1079};
1080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081static const char *dec5_mux_text[] = {
1082 "ZERO", "DMIC5", "ADC2",
1083};
1084
1085static const char *dec6_mux_text[] = {
1086 "ZERO", "DMIC6", "ADC1",
1087};
1088
1089static const char const *dec7_mux_text[] = {
1090 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1091};
1092
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001093static const char *dec8_mux_text[] = {
1094 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1095};
1096
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001097static const char *dec9_mux_text[] = {
1098 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1099};
1100
1101static const char *dec10_mux_text[] = {
1102 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1103};
1104
Bradley Rubin229c6a52011-07-12 16:18:48 -07001105static const char const *anc_mux_text[] = {
1106 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1107 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1108};
1109
1110static const char const *anc1_fb_mux_text[] = {
1111 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1112};
1113
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001114static const char *iir1_inp1_text[] = {
1115 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1116 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1117};
1118
1119static const struct soc_enum rx_mix1_inp1_chain_enum =
1120 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1121
Bradley Rubin229c6a52011-07-12 16:18:48 -07001122static const struct soc_enum rx_mix1_inp2_chain_enum =
1123 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1124
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125static const struct soc_enum rx2_mix1_inp1_chain_enum =
1126 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1127
Bradley Rubin229c6a52011-07-12 16:18:48 -07001128static const struct soc_enum rx2_mix1_inp2_chain_enum =
1129 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001131static const struct soc_enum rx3_mix1_inp1_chain_enum =
1132 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1133
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001134static const struct soc_enum rx3_mix1_inp2_chain_enum =
1135 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137static const struct soc_enum rx4_mix1_inp1_chain_enum =
1138 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1139
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001140static const struct soc_enum rx4_mix1_inp2_chain_enum =
1141 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143static const struct soc_enum rx5_mix1_inp1_chain_enum =
1144 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1145
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001146static const struct soc_enum rx5_mix1_inp2_chain_enum =
1147 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1148
1149static const struct soc_enum rx6_mix1_inp1_chain_enum =
1150 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1151
1152static const struct soc_enum rx6_mix1_inp2_chain_enum =
1153 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1154
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001155static const struct soc_enum rx7_mix1_inp1_chain_enum =
1156 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1157
1158static const struct soc_enum rx7_mix1_inp2_chain_enum =
1159 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1160
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001161static const struct soc_enum rx4_dsm_enum =
1162 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1163
1164static const struct soc_enum rx6_dsm_enum =
1165 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1166
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167static const struct soc_enum sb_tx5_mux_enum =
1168 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1169
1170static const struct soc_enum sb_tx6_mux_enum =
1171 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1172
1173static const struct soc_enum sb_tx7_mux_enum =
1174 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1175 sb_tx7_to_tx10_mux_text);
1176
1177static const struct soc_enum sb_tx8_mux_enum =
1178 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1179 sb_tx7_to_tx10_mux_text);
1180
Kiran Kandi3426e512011-09-13 22:50:10 -07001181static const struct soc_enum sb_tx9_mux_enum =
1182 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1183 sb_tx7_to_tx10_mux_text);
1184
1185static const struct soc_enum sb_tx10_mux_enum =
1186 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1187 sb_tx7_to_tx10_mux_text);
1188
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189static const struct soc_enum sb_tx1_mux_enum =
1190 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1191
1192static const struct soc_enum dec1_mux_enum =
1193 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1194
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001195static const struct soc_enum dec2_mux_enum =
1196 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1197
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001198static const struct soc_enum dec3_mux_enum =
1199 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1200
1201static const struct soc_enum dec4_mux_enum =
1202 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204static const struct soc_enum dec5_mux_enum =
1205 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1206
1207static const struct soc_enum dec6_mux_enum =
1208 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1209
1210static const struct soc_enum dec7_mux_enum =
1211 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1212
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001213static const struct soc_enum dec8_mux_enum =
1214 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1215
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001216static const struct soc_enum dec9_mux_enum =
1217 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1218
1219static const struct soc_enum dec10_mux_enum =
1220 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1221
Bradley Rubin229c6a52011-07-12 16:18:48 -07001222static const struct soc_enum anc1_mux_enum =
1223 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1224
1225static const struct soc_enum anc2_mux_enum =
1226 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1227
1228static const struct soc_enum anc1_fb_mux_enum =
1229 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231static const struct soc_enum iir1_inp1_mux_enum =
1232 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
1233
1234static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1235 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1236
Bradley Rubin229c6a52011-07-12 16:18:48 -07001237static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1238 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1239
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001240static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1241 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1242
Bradley Rubin229c6a52011-07-12 16:18:48 -07001243static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1244 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1245
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001246static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1247 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1248
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001249static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1250 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001252static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1253 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1254
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001255static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1256 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1259 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1260
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001261static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1262 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1263
1264static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1265 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1266
1267static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1268 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1269
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001270static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1271 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1272
1273static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1274 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1275
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001276static const struct snd_kcontrol_new rx4_dsm_mux =
1277 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1278
1279static const struct snd_kcontrol_new rx6_dsm_mux =
1280 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1281
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001282static const struct snd_kcontrol_new sb_tx5_mux =
1283 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1284
1285static const struct snd_kcontrol_new sb_tx6_mux =
1286 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1287
1288static const struct snd_kcontrol_new sb_tx7_mux =
1289 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1290
1291static const struct snd_kcontrol_new sb_tx8_mux =
1292 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1293
Kiran Kandi3426e512011-09-13 22:50:10 -07001294static const struct snd_kcontrol_new sb_tx9_mux =
1295 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1296
1297static const struct snd_kcontrol_new sb_tx10_mux =
1298 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001300static const struct snd_kcontrol_new sb_tx1_mux =
1301 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1302
1303static const struct snd_kcontrol_new dec1_mux =
1304 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1305
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001306static const struct snd_kcontrol_new dec2_mux =
1307 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1308
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001309static const struct snd_kcontrol_new dec3_mux =
1310 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1311
1312static const struct snd_kcontrol_new dec4_mux =
1313 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1314
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001315static const struct snd_kcontrol_new dec5_mux =
1316 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
1317
1318static const struct snd_kcontrol_new dec6_mux =
1319 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
1320
1321static const struct snd_kcontrol_new dec7_mux =
1322 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
1323
Bradley Rubin229c6a52011-07-12 16:18:48 -07001324static const struct snd_kcontrol_new anc1_mux =
1325 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001326static const struct snd_kcontrol_new dec8_mux =
1327 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
1328
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001329static const struct snd_kcontrol_new dec9_mux =
1330 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
1331
1332static const struct snd_kcontrol_new dec10_mux =
1333 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
1334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335static const struct snd_kcontrol_new iir1_inp1_mux =
1336 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1337
Bradley Rubin229c6a52011-07-12 16:18:48 -07001338static const struct snd_kcontrol_new anc2_mux =
1339 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340
Bradley Rubin229c6a52011-07-12 16:18:48 -07001341static const struct snd_kcontrol_new anc1_fb_mux =
1342 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001343
Bradley Rubin229c6a52011-07-12 16:18:48 -07001344static const struct snd_kcontrol_new dac1_switch[] = {
1345 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1346};
1347static const struct snd_kcontrol_new hphl_switch[] = {
1348 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1349};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001350
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001351static const struct snd_kcontrol_new hphl_pa_mix[] = {
1352 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1353 7, 1, 0),
1354 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1355 7, 1, 0),
1356 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1357 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1358 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1359 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1360};
1361
1362static const struct snd_kcontrol_new hphr_pa_mix[] = {
1363 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1364 6, 1, 0),
1365 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1366 6, 1, 0),
1367 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1368 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1369 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1370 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1371};
1372
1373static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1374 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1375 5, 1, 0),
1376 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1377 5, 1, 0),
1378 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1379 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1380 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1381 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1382};
1383
1384static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1385 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1386 4, 1, 0),
1387 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1388 4, 1, 0),
1389 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1390 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1391 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1392 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1393};
1394
1395static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1396 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1397 3, 1, 0),
1398 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1399 3, 1, 0),
1400 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1401 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1402 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1403 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1404};
1405
1406static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1407 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1408 2, 1, 0),
1409 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1410 2, 1, 0),
1411 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1412 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1413 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1414 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1415};
1416
1417static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1418 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1419 1, 1, 0),
1420 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1421 1, 1, 0),
1422 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1423 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1424 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1425 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1426};
1427
1428static const struct snd_kcontrol_new ear_pa_mix[] = {
1429 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1430 0, 1, 0),
1431 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1432 0, 1, 0),
1433 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1434 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1435 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1436 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1437};
1438
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001439static const struct snd_kcontrol_new lineout3_ground_switch =
1440 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1441
1442static const struct snd_kcontrol_new lineout4_ground_switch =
1443 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001446 int enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447{
1448 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1449
1450 pr_debug("%s %d\n", __func__, enable);
1451
1452 if (enable) {
1453 tabla->adc_count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1455 } else {
1456 tabla->adc_count--;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001457 if (!tabla->adc_count)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
Joonwoo Park03324832012-03-19 19:36:16 -07001459 0x2, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 }
1461}
1462
1463static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1464 struct snd_kcontrol *kcontrol, int event)
1465{
1466 struct snd_soc_codec *codec = w->codec;
1467 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001468 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469
1470 pr_debug("%s %d\n", __func__, event);
1471
1472 if (w->reg == TABLA_A_TX_1_2_EN)
1473 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1474 else if (w->reg == TABLA_A_TX_3_4_EN)
1475 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1476 else if (w->reg == TABLA_A_TX_5_6_EN)
1477 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1478 else {
1479 pr_err("%s: Error, invalid adc register\n", __func__);
1480 return -EINVAL;
1481 }
1482
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001483 if (w->shift == 3)
1484 init_bit_shift = 6;
1485 else if (w->shift == 7)
1486 init_bit_shift = 7;
1487 else {
1488 pr_err("%s: Error, invalid init bit postion adc register\n",
1489 __func__);
1490 return -EINVAL;
1491 }
1492
1493
1494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001495 switch (event) {
1496 case SND_SOC_DAPM_PRE_PMU:
1497 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001498 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1499 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 break;
1501 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001502
1503 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1504
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001505 break;
1506 case SND_SOC_DAPM_POST_PMD:
1507 tabla_codec_enable_adc_block(codec, 0);
1508 break;
1509 }
1510 return 0;
1511}
1512
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001513static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1514{
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001515 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1516 0x80);
1517 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1518 0x04);
1519 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1520 0x01);
1521 usleep_range(1000, 1000);
1522 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1523 0x00);
1524}
1525
1526static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1527 enum tabla_bandgap_type choice)
1528{
1529 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1530
1531 /* TODO lock resources accessed by audio streams and threaded
1532 * interrupt handlers
1533 */
1534
1535 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1536 tabla->bandgap_type);
1537
1538 if (tabla->bandgap_type == choice)
1539 return;
1540
1541 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1542 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1543 tabla_codec_enable_audio_mode_bandgap(codec);
1544 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
1545 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1546 0x2);
1547 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1548 0x80);
1549 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1550 0x4);
1551 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1552 0x01);
1553 usleep_range(1000, 1000);
1554 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1555 0x00);
1556 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1557 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1558 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1559 usleep_range(100, 100);
1560 tabla_codec_enable_audio_mode_bandgap(codec);
1561 } else if (choice == TABLA_BANDGAP_OFF) {
1562 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1563 } else {
1564 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1565 }
1566 tabla->bandgap_type = choice;
1567}
1568
1569static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1570{
1571 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1572 pr_debug("%s\n", __func__);
1573 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1574 ndelay(160);
1575 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1576 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1577 tabla->clock_active = false;
1578}
1579
1580static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
1581{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001582 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001583 return 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001584 else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001585 return 1;
1586 else {
1587 BUG_ON(1);
1588 return -EINVAL;
1589 }
1590}
1591
1592static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1593{
1594 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1595
1596 if (enable) {
1597 tabla->rx_bias_count++;
1598 if (tabla->rx_bias_count == 1)
1599 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1600 0x80, 0x80);
1601 } else {
1602 tabla->rx_bias_count--;
1603 if (!tabla->rx_bias_count)
1604 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1605 0x80, 0x00);
1606 }
1607}
1608
1609static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1610 int enable)
1611{
1612 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1613
1614 pr_debug("%s: enable = %d\n", __func__, enable);
1615 if (enable) {
1616 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1617 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1618 usleep_range(5, 5);
1619 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1620 0x80);
1621 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1622 0x80);
1623 usleep_range(10, 10);
1624 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1625 usleep_range(20, 20);
1626 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1627 } else {
1628 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1629 0);
1630 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1631 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1632 }
1633 tabla->config_mode_active = enable ? true : false;
1634
1635 return 0;
1636}
1637
1638static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1639 int config_mode)
1640{
1641 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1642
1643 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
1644
1645 if (config_mode) {
1646 tabla_codec_enable_config_mode(codec, 1);
1647 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1648 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1649 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1650 usleep_range(1000, 1000);
1651 } else
1652 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1653
1654 if (!config_mode && tabla->mbhc_polling_active) {
1655 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1656 tabla_codec_enable_config_mode(codec, 0);
1657
1658 }
1659
1660 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1661 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1662 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1663 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1664 usleep_range(50, 50);
1665 tabla->clock_active = true;
1666 return 0;
1667}
1668
1669static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1670 struct snd_kcontrol *kcontrol, int event)
1671{
1672 struct snd_soc_codec *codec = w->codec;
1673 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1674
1675 pr_debug("%s: %d\n", __func__, event);
1676
1677 switch (event) {
1678 case SND_SOC_DAPM_PRE_PMU:
1679 tabla_codec_enable_bandgap(codec,
1680 TABLA_BANDGAP_AUDIO_MODE);
1681 tabla_enable_rx_bias(codec, 1);
1682
1683 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1684 0x08, 0x08);
1685 /* Enable Zero Cross detect for AUX PGA channel
1686 * and set the initial AUX PGA gain to NEG_0P0_DB
1687 * to avoid glitches.
1688 */
1689 if (w->reg == TABLA_A_AUX_L_EN) {
1690 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1691 0x20, 0x20);
1692 tabla->aux_l_gain = snd_soc_read(codec,
1693 TABLA_A_AUX_L_GAIN);
1694 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1695 } else {
1696 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1697 0x20, 0x20);
1698 tabla->aux_r_gain = snd_soc_read(codec,
1699 TABLA_A_AUX_R_GAIN);
1700 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1701 }
1702 if (tabla->aux_pga_cnt++ == 1
1703 && !tabla->mclk_enabled) {
1704 tabla_codec_enable_clock_block(codec, 1);
1705 pr_debug("AUX PGA enabled RC osc\n");
1706 }
1707 break;
1708
1709 case SND_SOC_DAPM_POST_PMU:
1710 if (w->reg == TABLA_A_AUX_L_EN)
1711 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1712 tabla->aux_l_gain);
1713 else
1714 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1715 tabla->aux_r_gain);
1716 break;
1717
1718 case SND_SOC_DAPM_PRE_PMD:
1719 /* Mute AUX PGA channel in use before disabling AUX PGA */
1720 if (w->reg == TABLA_A_AUX_L_EN) {
1721 tabla->aux_l_gain = snd_soc_read(codec,
1722 TABLA_A_AUX_L_GAIN);
1723 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1724 } else {
1725 tabla->aux_r_gain = snd_soc_read(codec,
1726 TABLA_A_AUX_R_GAIN);
1727 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1728 }
1729 break;
1730
1731 case SND_SOC_DAPM_POST_PMD:
1732 tabla_enable_rx_bias(codec, 0);
1733
1734 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1735 0x08, 0x00);
1736 if (w->reg == TABLA_A_AUX_L_EN) {
1737 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1738 tabla->aux_l_gain);
1739 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1740 0x20, 0x00);
1741 } else {
1742 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1743 tabla->aux_r_gain);
1744 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1745 0x20, 0x00);
1746 }
1747
1748 if (tabla->aux_pga_cnt-- == 0) {
1749 if (tabla->mbhc_polling_active)
1750 tabla_codec_enable_bandgap(codec,
1751 TABLA_BANDGAP_MBHC_MODE);
1752 else
1753 tabla_codec_enable_bandgap(codec,
1754 TABLA_BANDGAP_OFF);
1755
1756 if (!tabla->mclk_enabled &&
1757 !tabla->mbhc_polling_active) {
1758 tabla_codec_enable_clock_block(codec, 0);
1759 }
1760 }
1761 break;
1762 }
1763 return 0;
1764}
1765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001766static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1767 struct snd_kcontrol *kcontrol, int event)
1768{
1769 struct snd_soc_codec *codec = w->codec;
1770 u16 lineout_gain_reg;
1771
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001772 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773
1774 switch (w->shift) {
1775 case 0:
1776 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1777 break;
1778 case 1:
1779 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1780 break;
1781 case 2:
1782 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1783 break;
1784 case 3:
1785 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1786 break;
1787 case 4:
1788 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1789 break;
1790 default:
1791 pr_err("%s: Error, incorrect lineout register value\n",
1792 __func__);
1793 return -EINVAL;
1794 }
1795
1796 switch (event) {
1797 case SND_SOC_DAPM_PRE_PMU:
1798 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1799 break;
1800 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001801 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001802 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001803 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804 break;
1805 case SND_SOC_DAPM_POST_PMD:
1806 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1807 break;
1808 }
1809 return 0;
1810}
1811
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001812
1813static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001814 struct snd_kcontrol *kcontrol, int event)
1815{
1816 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001817 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1818 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001819 unsigned int dmic;
1820 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001821
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001822 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1823 if (ret < 0) {
1824 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001825 return -EINVAL;
1826 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001827
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001828 switch (dmic) {
1829 case 1:
1830 case 2:
1831 dmic_clk_sel = 0x02;
1832 dmic_clk_en = 0x01;
1833 break;
1834
1835 case 3:
1836 case 4:
1837 dmic_clk_sel = 0x08;
1838 dmic_clk_en = 0x04;
1839 break;
1840
1841 case 5:
1842 case 6:
1843 dmic_clk_sel = 0x20;
1844 dmic_clk_en = 0x10;
1845 break;
1846
1847 default:
1848 pr_err("%s: Invalid DMIC Selection\n", __func__);
1849 return -EINVAL;
1850 }
1851
1852 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1853 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1854
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001855 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001856
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 switch (event) {
1858 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001859 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1860
1861 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1862 dmic_clk_sel, dmic_clk_sel);
1863
1864 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1865
1866 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1867 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001868 break;
1869 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001870 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1871 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001872 break;
1873 }
1874 return 0;
1875}
1876
Bradley Rubin229c6a52011-07-12 16:18:48 -07001877static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1878 struct snd_kcontrol *kcontrol, int event)
1879{
1880 struct snd_soc_codec *codec = w->codec;
1881 const char *filename;
1882 const struct firmware *fw;
1883 int i;
1884 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001885 int num_anc_slots;
1886 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001887 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001888 u32 anc_writes_size = 0;
1889 int anc_size_remaining;
1890 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001891 u16 reg;
1892 u8 mask, val, old_val;
1893
1894 pr_debug("%s %d\n", __func__, event);
1895 switch (event) {
1896 case SND_SOC_DAPM_PRE_PMU:
1897
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001898 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001899
1900 ret = request_firmware(&fw, filename, codec->dev);
1901 if (ret != 0) {
1902 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1903 ret);
1904 return -ENODEV;
1905 }
1906
Bradley Rubina7096d02011-08-03 18:29:02 -07001907 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001908 dev_err(codec->dev, "Not enough data\n");
1909 release_firmware(fw);
1910 return -ENOMEM;
1911 }
1912
1913 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001914 anc_head = (struct anc_header *)(fw->data);
1915 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1916 anc_size_remaining = fw->size - sizeof(struct anc_header);
1917 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001918
Bradley Rubina7096d02011-08-03 18:29:02 -07001919 if (tabla->anc_slot >= num_anc_slots) {
1920 dev_err(codec->dev, "Invalid ANC slot selected\n");
1921 release_firmware(fw);
1922 return -EINVAL;
1923 }
1924
1925 for (i = 0; i < num_anc_slots; i++) {
1926
1927 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1928 dev_err(codec->dev, "Invalid register format\n");
1929 release_firmware(fw);
1930 return -EINVAL;
1931 }
1932 anc_writes_size = (u32)(*anc_ptr);
1933 anc_size_remaining -= sizeof(u32);
1934 anc_ptr += 1;
1935
1936 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1937 > anc_size_remaining) {
1938 dev_err(codec->dev, "Invalid register format\n");
1939 release_firmware(fw);
1940 return -ENOMEM;
1941 }
1942
1943 if (tabla->anc_slot == i)
1944 break;
1945
1946 anc_size_remaining -= (anc_writes_size *
1947 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001948 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001949 }
1950 if (i == num_anc_slots) {
1951 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001952 release_firmware(fw);
1953 return -ENOMEM;
1954 }
1955
Bradley Rubina7096d02011-08-03 18:29:02 -07001956 for (i = 0; i < anc_writes_size; i++) {
1957 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001958 mask, val);
1959 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001960 snd_soc_write(codec, reg, (old_val & ~mask) |
1961 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001962 }
1963 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001964
1965 break;
1966 case SND_SOC_DAPM_POST_PMD:
1967 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1968 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1969 break;
1970 }
1971 return 0;
1972}
1973
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001974/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001975static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1976{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001977 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07001978 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
1979 int mbhc_state = tabla->mbhc_state;
Bradley Rubincb3950a2011-08-18 13:07:26 -07001980
Joonwoo Park03324832012-03-19 19:36:16 -07001981 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001982 if (!tabla->mbhc_polling_active) {
1983 pr_debug("Polling is not active, do not start polling\n");
1984 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07001985 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001986 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Joonwoo Park03324832012-03-19 19:36:16 -07001987
1988 if (!tabla->no_mic_headset_override) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001989 if (mbhc_state == MBHC_STATE_POTENTIAL) {
1990 pr_debug("%s recovering MBHC state macine\n", __func__);
1991 tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
Joonwoo Park03324832012-03-19 19:36:16 -07001992 /* set to max button press threshold */
1993 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
1994 0x7F);
1995 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
1996 0xFF);
1997 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
1998 (TABLA_IS_1_X(tabla_core->version) ?
1999 0x07 : 0x7F));
2000 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2001 0xFF);
2002 /* set to max */
2003 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2004 0x7F);
2005 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2006 0xFF);
2007 }
2008 }
2009
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002010 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
2011 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2012 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
Joonwoo Park03324832012-03-19 19:36:16 -07002013 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002014}
2015
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002016/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002017static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
2018{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002019 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2020
Joonwoo Park03324832012-03-19 19:36:16 -07002021 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002022 if (!tabla->mbhc_polling_active) {
2023 pr_debug("polling not active, nothing to pause\n");
2024 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002025 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002026
2027 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Joonwoo Park03324832012-03-19 19:36:16 -07002028 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002029}
2030
Joonwoo Park03324832012-03-19 19:36:16 -07002031static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002032{
2033 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2034 u8 reg_mode_val, cur_mode_val;
2035 bool mbhc_was_polling = false;
2036
2037 if (mode)
2038 reg_mode_val = TABLA_CFILT_FAST_MODE;
2039 else
2040 reg_mode_val = TABLA_CFILT_SLOW_MODE;
2041
2042 cur_mode_val = snd_soc_read(codec,
2043 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
2044
2045 if (cur_mode_val != reg_mode_val) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002046 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002047 if (tabla->mbhc_polling_active) {
2048 tabla_codec_pause_hs_polling(codec);
2049 mbhc_was_polling = true;
2050 }
2051 snd_soc_update_bits(codec,
2052 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
2053 if (mbhc_was_polling)
2054 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002055 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002056 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
2057 cur_mode_val, reg_mode_val);
2058 } else {
2059 pr_debug("%s: CFILT Value is already %x\n",
2060 __func__, cur_mode_val);
2061 }
2062}
2063
2064static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
2065 u8 cfilt_sel, int inc)
2066{
2067 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2068 u32 *cfilt_cnt_ptr = NULL;
2069 u16 micb_cfilt_reg;
2070
2071 switch (cfilt_sel) {
2072 case TABLA_CFILT1_SEL:
2073 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2074 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2075 break;
2076 case TABLA_CFILT2_SEL:
2077 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2078 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2079 break;
2080 case TABLA_CFILT3_SEL:
2081 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2082 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2083 break;
2084 default:
2085 return; /* should not happen */
2086 }
2087
2088 if (inc) {
2089 if (!(*cfilt_cnt_ptr)++) {
2090 /* Switch CFILT to slow mode if MBHC CFILT being used */
2091 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2092 tabla_codec_switch_cfilt_mode(codec, 0);
2093
2094 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2095 }
2096 } else {
2097 /* check if count not zero, decrement
2098 * then check if zero, go ahead disable cfilter
2099 */
2100 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2101 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2102
2103 /* Switch CFILT to fast mode if MBHC CFILT being used */
2104 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2105 tabla_codec_switch_cfilt_mode(codec, 1);
2106 }
2107 }
2108}
2109
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002110static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2111{
2112 int rc = -EINVAL;
2113 unsigned min_mv, max_mv;
2114
2115 switch (ldoh_v) {
2116 case TABLA_LDOH_1P95_V:
2117 min_mv = 160;
2118 max_mv = 1800;
2119 break;
2120 case TABLA_LDOH_2P35_V:
2121 min_mv = 200;
2122 max_mv = 2200;
2123 break;
2124 case TABLA_LDOH_2P75_V:
2125 min_mv = 240;
2126 max_mv = 2600;
2127 break;
2128 case TABLA_LDOH_2P85_V:
2129 min_mv = 250;
2130 max_mv = 2700;
2131 break;
2132 default:
2133 goto done;
2134 }
2135
2136 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2137 goto done;
2138
2139 for (rc = 4; rc <= 44; rc++) {
2140 min_mv = max_mv * (rc) / 44;
2141 if (min_mv >= cfilt_mv) {
2142 rc -= 4;
2143 break;
2144 }
2145 }
2146done:
2147 return rc;
2148}
2149
2150static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2151{
2152 u8 hph_reg_val = 0;
2153 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2154
2155 return (hph_reg_val & 0x30) ? true : false;
2156}
2157
Joonwoo Parka9444452011-12-08 18:48:27 -08002158static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2159{
2160 u8 hph_reg_val = 0;
2161 if (left)
2162 hph_reg_val = snd_soc_read(codec,
2163 TABLA_A_RX_HPH_L_DAC_CTL);
2164 else
2165 hph_reg_val = snd_soc_read(codec,
2166 TABLA_A_RX_HPH_R_DAC_CTL);
2167
2168 return (hph_reg_val & 0xC0) ? true : false;
2169}
2170
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002171/* called under codec_resource_lock acquisition */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002172static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002173 int vddio_switch)
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002174{
2175 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2176 int cfilt_k_val;
Joonwoo Park03324832012-03-19 19:36:16 -07002177 bool mbhc_was_polling = false;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002178
2179 switch (vddio_switch) {
2180 case 1:
Joonwoo Park03324832012-03-19 19:36:16 -07002181 if (tabla->mbhc_micbias_switched == 0 &&
2182 tabla->mbhc_polling_active) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002183 tabla_codec_pause_hs_polling(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08002184 /* VDDIO switch enabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002185 tabla->cfilt_k_value = snd_soc_read(codec,
2186 tabla->mbhc_bias_regs.cfilt_val);
2187 cfilt_k_val = tabla_find_k_value(
2188 tabla->pdata->micbias.ldoh_v, 1800);
2189 snd_soc_update_bits(codec,
2190 tabla->mbhc_bias_regs.cfilt_val,
2191 0xFC, (cfilt_k_val << 2));
2192
2193 snd_soc_update_bits(codec,
2194 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x80);
2195 snd_soc_update_bits(codec,
2196 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002197 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002198
2199 tabla->mbhc_micbias_switched = true;
Joonwoo Park0976d012011-12-22 11:48:18 -08002200 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002201 }
2202 break;
2203
2204 case 0:
2205 if (tabla->mbhc_micbias_switched) {
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002206 if (tabla->mbhc_polling_active) {
2207 tabla_codec_pause_hs_polling(codec);
2208 mbhc_was_polling = true;
2209 }
Joonwoo Park0976d012011-12-22 11:48:18 -08002210 /* VDDIO switch disabled */
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002211 if (tabla->cfilt_k_value != 0)
2212 snd_soc_update_bits(codec,
2213 tabla->mbhc_bias_regs.cfilt_val, 0XFC,
2214 tabla->cfilt_k_value);
2215 snd_soc_update_bits(codec,
2216 tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
2217 snd_soc_update_bits(codec,
2218 tabla->mbhc_bias_regs.mbhc_reg, 0x10, 0x00);
2219
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002220 if (mbhc_was_polling)
2221 tabla_codec_start_hs_polling(codec);
2222
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002223 tabla->mbhc_micbias_switched = false;
Joonwoo Park0976d012011-12-22 11:48:18 -08002224 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002225 }
2226 break;
2227 }
2228}
2229
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002230static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2231 struct snd_kcontrol *kcontrol, int event)
2232{
2233 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002234 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2235 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002236 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002237 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002238 char *internal1_text = "Internal1";
2239 char *internal2_text = "Internal2";
2240 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002241
2242 pr_debug("%s %d\n", __func__, event);
2243 switch (w->reg) {
2244 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002245 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002246 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002247 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002248 break;
2249 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002250 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002251 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002252 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002253 break;
2254 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002255 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002256 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002257 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002258 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002259 case TABLA_1_A_MICB_4_CTL:
2260 case TABLA_2_A_MICB_4_CTL:
2261 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002262 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002263 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002264 break;
2265 default:
2266 pr_err("%s: Error, invalid micbias register\n", __func__);
2267 return -EINVAL;
2268 }
2269
2270 switch (event) {
2271 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002272 /* Decide whether to switch the micbias for MBHC */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002273 if (w->reg == tabla->mbhc_bias_regs.ctl_reg) {
2274 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002275 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002276 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2277 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002278
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002279 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002280 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002281
2282 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002283 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002284 else if (strnstr(w->name, internal2_text, 30))
2285 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2286 else if (strnstr(w->name, internal3_text, 30))
2287 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002290 case SND_SOC_DAPM_POST_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002291
2292 usleep_range(20000, 20000);
2293
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002294 if (tabla->mbhc_polling_active &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002295 tabla->mbhc_cfg.micbias == micb_line) {
2296 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002297 tabla_codec_pause_hs_polling(codec);
2298 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002299 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002300 }
2301 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002303 case SND_SOC_DAPM_POST_PMD:
Joonwoo Park03324832012-03-19 19:36:16 -07002304 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg) &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002305 tabla_is_hph_pa_on(codec)) {
2306 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002307 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002308 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2309 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002310
Bradley Rubin229c6a52011-07-12 16:18:48 -07002311 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002312 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002313 else if (strnstr(w->name, internal2_text, 30))
2314 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2315 else if (strnstr(w->name, internal3_text, 30))
2316 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2317
Patrick Lai3043fba2011-08-01 14:15:57 -07002318 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 break;
2320 }
2321
2322 return 0;
2323}
2324
Kiran Kandid8cf5212012-03-02 15:34:53 -08002325
2326static void tx_hpf_corner_freq_callback(struct work_struct *work)
2327{
2328 struct delayed_work *hpf_delayed_work;
2329 struct hpf_work *hpf_work;
2330 struct tabla_priv *tabla;
2331 struct snd_soc_codec *codec;
2332 u16 tx_mux_ctl_reg;
2333 u8 hpf_cut_of_freq;
2334
2335 hpf_delayed_work = to_delayed_work(work);
2336 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2337 tabla = hpf_work->tabla;
2338 codec = hpf_work->tabla->codec;
2339 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2340
2341 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL +
2342 (hpf_work->decimator - 1) * 8;
2343
2344 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
2345 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2346
2347 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
2348}
2349
2350#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
2351#define CF_MIN_3DB_4HZ 0x0
2352#define CF_MIN_3DB_75HZ 0x1
2353#define CF_MIN_3DB_150HZ 0x2
2354
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002355static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
2356 struct snd_kcontrol *kcontrol, int event)
2357{
2358 struct snd_soc_codec *codec = w->codec;
Kiran Kandid8cf5212012-03-02 15:34:53 -08002359 unsigned int decimator;
2360 char *dec_name = NULL;
2361 char *widget_name = NULL;
2362 char *temp;
2363 int ret = 0;
2364 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2365 u8 dec_hpf_cut_of_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002366
2367 pr_debug("%s %d\n", __func__, event);
2368
Kiran Kandid8cf5212012-03-02 15:34:53 -08002369 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2370 if (!widget_name)
2371 return -ENOMEM;
2372 temp = widget_name;
2373
2374 dec_name = strsep(&widget_name, " ");
2375 widget_name = temp;
2376 if (!dec_name) {
2377 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2378 ret = -EINVAL;
2379 goto out;
2380 }
2381
2382 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
2383 if (ret < 0) {
2384 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2385 ret = -EINVAL;
2386 goto out;
2387 }
2388
2389 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
2390 w->name, dec_name, decimator);
2391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002392 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
2393 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
2394 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
2395 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
2396 else {
2397 pr_err("%s: Error, incorrect dec\n", __func__);
2398 return -EINVAL;
2399 }
2400
Kiran Kandid8cf5212012-03-02 15:34:53 -08002401 tx_vol_ctl_reg = TABLA_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator -1);
2402 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2403
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002404 switch (event) {
2405 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002406
2407 // Enableable TX digital mute */
2408 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2409
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002410 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2411 1 << w->shift);
2412 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Kiran Kandid8cf5212012-03-02 15:34:53 -08002413
2414 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2415
2416 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
2417
2418 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2419 dec_hpf_cut_of_freq;
2420
2421 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2422
2423 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
2424 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2425 CF_MIN_3DB_150HZ << 4);
2426 }
2427
2428 /* enable HPF */
2429 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
2430
2431 break;
2432
2433 case SND_SOC_DAPM_POST_PMU:
2434
2435 /* Disable TX digital mute */
2436 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2437
2438 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2439 CF_MIN_3DB_150HZ) {
2440
2441 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2442 msecs_to_jiffies(300));
2443 }
2444 break;
2445
2446 case SND_SOC_DAPM_PRE_PMD:
2447
2448 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2449 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2450 break;
2451
2452 case SND_SOC_DAPM_POST_PMD:
2453
2454 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2455 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2456 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2457
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002458 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002459 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08002460out:
2461 kfree(widget_name);
2462 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463}
2464
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002465static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 struct snd_kcontrol *kcontrol, int event)
2467{
2468 struct snd_soc_codec *codec = w->codec;
2469
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002470 pr_debug("%s %d %s\n", __func__, event, w->name);
2471
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 switch (event) {
2473 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002474 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2475 1 << w->shift, 1 << w->shift);
2476 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2477 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002478 break;
2479 }
2480 return 0;
2481}
2482
Bradley Rubin229c6a52011-07-12 16:18:48 -07002483static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2484 struct snd_kcontrol *kcontrol, int event)
2485{
2486 switch (event) {
2487 case SND_SOC_DAPM_POST_PMU:
2488 case SND_SOC_DAPM_POST_PMD:
2489 usleep_range(1000, 1000);
2490 break;
2491 }
2492 return 0;
2493}
2494
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002495static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2496 struct snd_kcontrol *kcontrol, int event)
2497{
2498 struct snd_soc_codec *codec = w->codec;
2499
2500 pr_debug("%s %d\n", __func__, event);
2501
2502 switch (event) {
2503 case SND_SOC_DAPM_PRE_PMU:
2504 tabla_enable_rx_bias(codec, 1);
2505 break;
2506 case SND_SOC_DAPM_POST_PMD:
2507 tabla_enable_rx_bias(codec, 0);
2508 break;
2509 }
2510 return 0;
2511}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002512static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
2513 struct snd_kcontrol *kcontrol, int event)
2514{
2515 struct snd_soc_codec *codec = w->codec;
2516
2517 pr_debug("%s %s %d\n", __func__, w->name, event);
2518
2519 switch (event) {
2520 case SND_SOC_DAPM_PRE_PMU:
2521 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2522 break;
2523 case SND_SOC_DAPM_POST_PMD:
2524 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2525 break;
2526 }
2527 return 0;
2528}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002529
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002530static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
2531 struct snd_soc_jack *jack, int status,
2532 int mask)
2533{
2534 /* XXX: wake_lock_timeout()? */
Joonwoo Park03324832012-03-19 19:36:16 -07002535 snd_soc_jack_report_no_dapm(jack, status, mask);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002536}
2537
Patrick Lai49efeac2011-11-03 11:01:12 -07002538static void hphocp_off_report(struct tabla_priv *tabla,
2539 u32 jack_status, int irq)
2540{
2541 struct snd_soc_codec *codec;
Joonwoo Park03324832012-03-19 19:36:16 -07002542 if (!tabla) {
2543 pr_err("%s: Bad tabla private data\n", __func__);
2544 return;
2545 }
Patrick Lai49efeac2011-11-03 11:01:12 -07002546
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002547 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
Joonwoo Park03324832012-03-19 19:36:16 -07002548 codec = tabla->codec;
2549 if (tabla->hph_status & jack_status) {
Patrick Lai49efeac2011-11-03 11:01:12 -07002550 tabla->hph_status &= ~jack_status;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002551 if (tabla->mbhc_cfg.headset_jack)
2552 tabla_snd_soc_jack_report(tabla,
2553 tabla->mbhc_cfg.headset_jack,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002554 tabla->hph_status,
2555 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08002556 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2557 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08002558 /* reset retry counter as PA is turned off signifying
2559 * start of new OCP detection session
2560 */
2561 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
2562 tabla->hphlocp_cnt = 0;
2563 else
2564 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302565 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07002566 }
2567}
2568
2569static void hphlocp_off_report(struct work_struct *work)
2570{
2571 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2572 hphlocp_work);
2573 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
2574}
2575
2576static void hphrocp_off_report(struct work_struct *work)
2577{
2578 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2579 hphrocp_work);
2580 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
2581}
2582
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002583static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
2584 struct snd_kcontrol *kcontrol, int event)
2585{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002586 struct snd_soc_codec *codec = w->codec;
2587 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2588 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002589 pr_debug("%s: event = %d\n", __func__, event);
2590
2591 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002592 case SND_SOC_DAPM_PRE_PMU:
2593 mbhc_micb_ctl_val = snd_soc_read(codec,
2594 tabla->mbhc_bias_regs.ctl_reg);
2595
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002596 if (!(mbhc_micb_ctl_val & 0x80)) {
2597 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002598 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002599 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2600 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002601 break;
2602
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002603 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07002604 /* schedule work is required because at the time HPH PA DAPM
2605 * event callback is called by DAPM framework, CODEC dapm mutex
2606 * would have been locked while snd_soc_jack_report also
2607 * attempts to acquire same lock.
2608 */
Joonwoo Parka9444452011-12-08 18:48:27 -08002609 if (w->shift == 5) {
2610 clear_bit(TABLA_HPHL_PA_OFF_ACK,
2611 &tabla->hph_pa_dac_state);
2612 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
2613 &tabla->hph_pa_dac_state);
2614 if (tabla->hph_status & SND_JACK_OC_HPHL)
2615 schedule_work(&tabla->hphlocp_work);
2616 } else if (w->shift == 4) {
2617 clear_bit(TABLA_HPHR_PA_OFF_ACK,
2618 &tabla->hph_pa_dac_state);
2619 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
2620 &tabla->hph_pa_dac_state);
2621 if (tabla->hph_status & SND_JACK_OC_HPHR)
2622 schedule_work(&tabla->hphrocp_work);
2623 }
2624
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002625 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park03324832012-03-19 19:36:16 -07002626 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002627 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002628
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002629 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
2630 w->name);
2631 usleep_range(10000, 10000);
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002632 break;
2633 }
2634 return 0;
2635}
2636
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002637static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002638 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002639{
2640 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002641 unsigned int cfilt;
2642
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002643 switch (tabla->mbhc_cfg.micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002644 case TABLA_MICBIAS1:
2645 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
2646 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
2647 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
2648 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
2649 break;
2650 case TABLA_MICBIAS2:
2651 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
2652 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
2653 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
2654 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
2655 break;
2656 case TABLA_MICBIAS3:
2657 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
2658 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
2659 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
2660 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
2661 break;
2662 case TABLA_MICBIAS4:
2663 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002664 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
2665 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
2666 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002667 break;
2668 default:
2669 /* Should never reach here */
2670 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07002671 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002672 }
2673
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002674 micbias_regs->cfilt_sel = cfilt;
2675
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002676 switch (cfilt) {
2677 case TABLA_CFILT1_SEL:
2678 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
2679 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002680 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002681 break;
2682 case TABLA_CFILT2_SEL:
2683 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
2684 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002685 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002686 break;
2687 case TABLA_CFILT3_SEL:
2688 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
2689 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002690 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002691 break;
2692 }
2693}
Santosh Mardie15e2302011-11-15 10:39:23 +05302694static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
2695 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
2696 4, 0, NULL, 0),
2697 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
2698 0, NULL, 0),
2699};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002700
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002701static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
2702 struct snd_kcontrol *kcontrol, int event)
2703{
2704 struct snd_soc_codec *codec = w->codec;
2705
2706 pr_debug("%s %s %d\n", __func__, w->name, event);
2707
2708 switch (event) {
2709 case SND_SOC_DAPM_PRE_PMU:
2710 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2711 break;
2712
2713 case SND_SOC_DAPM_POST_PMD:
2714 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2715 break;
2716 }
2717 return 0;
2718}
2719
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002720static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
2721 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302722 0, tabla_codec_enable_micbias,
2723 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2724 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002725};
2726
2727static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
2728 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302729 0, tabla_codec_enable_micbias,
2730 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2731 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002732};
2733
Santosh Mardie15e2302011-11-15 10:39:23 +05302734static const struct snd_soc_dapm_route audio_i2s_map[] = {
2735 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2736 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2737 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2738 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2739 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2740
2741 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2742 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2743 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2744 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2745};
2746
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002747static const struct snd_soc_dapm_route audio_map[] = {
2748 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002749
2750 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2751 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2752
2753 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2754 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2755
2756 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2757 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2758
2759 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2760 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002761 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002762 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2763 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2765 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002766 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2767 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002768 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2769 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002770
2771 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002772 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2773 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2774 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002775 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002776 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2777 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2778
Kiran Kandi3426e512011-09-13 22:50:10 -07002779 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
2780 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
2781 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
2782 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
2783 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
2784 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
2785 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
2786 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
2787 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
2788 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
2789 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
2790
2791 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
2792 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
2793 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
2794 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
2795 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
2796 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
2797 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
2798 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
2799 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
2800 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
2801 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
2802
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002803 /* Earpiece (RX MIX1) */
2804 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002805 {"EAR PA", NULL, "EAR_PA_MIXER"},
2806 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002807 {"DAC1", NULL, "CP"},
2808
2809 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2810 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2811 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002812
2813 /* Headset (RX MIX1 and RX MIX2) */
2814 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002815 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002816
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002817 {"HPHL", NULL, "HPHL_PA_MIXER"},
2818 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
2819
2820 {"HPHR", NULL, "HPHR_PA_MIXER"},
2821 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002822
2823 {"HPHL DAC", NULL, "CP"},
2824 {"HPHR DAC", NULL, "CP"},
2825
2826 {"ANC", NULL, "ANC1 MUX"},
2827 {"ANC", NULL, "ANC2 MUX"},
2828 {"ANC1 MUX", "ADC1", "ADC1"},
2829 {"ANC1 MUX", "ADC2", "ADC2"},
2830 {"ANC1 MUX", "ADC3", "ADC3"},
2831 {"ANC1 MUX", "ADC4", "ADC4"},
2832 {"ANC2 MUX", "ADC1", "ADC1"},
2833 {"ANC2 MUX", "ADC2", "ADC2"},
2834 {"ANC2 MUX", "ADC3", "ADC3"},
2835 {"ANC2 MUX", "ADC4", "ADC4"},
2836
Bradley Rubine1d08622011-07-20 18:01:35 -07002837 {"ANC", NULL, "CDC_CONN"},
2838
Bradley Rubin229c6a52011-07-12 16:18:48 -07002839 {"DAC1", "Switch", "RX1 CHAIN"},
2840 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002841 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002842
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002843 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2844 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2845 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2846 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2847 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002848
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002849 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2850 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
2851 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2852 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2853 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
2854 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
2855 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
2856 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
2857 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
2858 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002859
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002860 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2861 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2862
Bradley Rubin229c6a52011-07-12 16:18:48 -07002863 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2864 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2865 {"RX1 CHAIN", NULL, "ANC"},
2866 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002867
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002868 {"CP", NULL, "RX_BIAS"},
2869 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2870 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2871 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2872 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002873 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002874
Kuirong Wang0f8ade32012-02-27 16:29:45 -08002875 {"RX1 MIX1", NULL, "COMP1_CLK"},
2876 {"RX2 MIX1", NULL, "COMP1_CLK"},
2877 {"RX3 MIX1", NULL, "COMP2_CLK"},
2878 {"RX5 MIX1", NULL, "COMP2_CLK"},
2879
2880
Bradley Rubin229c6a52011-07-12 16:18:48 -07002881 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2882 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2883 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2884 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002885 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2886 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2887 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2888 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2889 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2890 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2891 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2892 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002893 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2894 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002895
Bradley Rubin229c6a52011-07-12 16:18:48 -07002896 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2897 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302898 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2899 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002900 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
2901 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002902 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2903 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2904 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302905 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2906 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002907 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
2908 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002909 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2910 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2911 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302912 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2913 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002914 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
2915 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002916 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002917 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2918 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302919 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2920 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002921 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
2922 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002923 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002924 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2925 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302926 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2927 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002928 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
2929 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002930 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002931 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2932 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302933 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2934 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002935 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
2936 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002937 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002938 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2939 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302940 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2941 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002942 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
2943 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002944 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002945 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2946 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302947 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2948 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002949 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
2950 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002951 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002952 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
2953 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302954 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
2955 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002956 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
2957 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002958 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002959 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
2960 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302961 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
2962 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002963 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
2964 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002965 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002966 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
2967 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302968 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
2969 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002970 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
2971 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002972 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002973 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
2974 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302975 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
2976 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002977 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
2978 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002979 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002980 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
2981 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302982 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
2983 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002984 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
2985 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002986 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002987 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
2988 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302989 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
2990 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002991 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
2992 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002993 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002994
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002995 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002996 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002997 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07002998 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002999 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003000 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003001 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003002 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003003 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003004 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003005 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003006 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003007 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003008 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003009 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003010 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003011 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003012 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003013 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003014 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003015 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003016 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003017 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003018 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003019 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003020 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003021 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003022 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003023
3024 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003025 {"ADC1", NULL, "AMIC1"},
3026 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003027 {"ADC3", NULL, "AMIC3"},
3028 {"ADC4", NULL, "AMIC4"},
3029 {"ADC5", NULL, "AMIC5"},
3030 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003031
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003032 /* AUX PGA Connections */
3033 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3034 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3035 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3036 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3037 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3038 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3039 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3040 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3041 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3042 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3043 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3044 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3045 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3046 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3047 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3048 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3049 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3050 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3051 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3052 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3053 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3054 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3055 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3056 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3057 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3058 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3059 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3060 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3061 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3062 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3063 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3064 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3065 {"AUX_PGA_Left", NULL, "AMIC5"},
3066 {"AUX_PGA_Right", NULL, "AMIC6"},
3067
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003068 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003069 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
3070 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
3071 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
3072 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
3073 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003074 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003075 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
3076 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
3077 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
3078 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003079
3080 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
3081 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
3082 {"MIC BIAS1 External", NULL, "LDO_H"},
3083 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
3084 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
3085 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
3086 {"MIC BIAS2 External", NULL, "LDO_H"},
3087 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
3088 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
3089 {"MIC BIAS3 External", NULL, "LDO_H"},
3090 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003091};
3092
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003093static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
3094
3095 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
3096 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3097
3098 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
3099
3100 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
3101 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
3102 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
3103
3104 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3105 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3106
3107 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3108 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
3109 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
3110};
3111
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003112
3113static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
3114
3115 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
3116 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3117
3118 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
3119
3120 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
3121
3122 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3123 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3124
3125 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3126};
3127
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003128static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
3129{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003130 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303131 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003132
3133 if (TABLA_IS_1_X(tabla_core->version)) {
3134 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
3135 if (tabla_1_reg_readable[i] == reg)
3136 return 1;
3137 }
3138 } else {
3139 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
3140 if (tabla_2_reg_readable[i] == reg)
3141 return 1;
3142 }
3143 }
3144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003145 return tabla_reg_readable[reg];
3146}
3147
3148static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3149{
3150 /* Registers lower than 0x100 are top level registers which can be
3151 * written by the Tabla core driver.
3152 */
3153
3154 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3155 return 1;
3156
Ben Romberger1f045a72011-11-04 10:14:57 -07003157 /* IIR Coeff registers are not cacheable */
3158 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
3159 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
3160 return 1;
3161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003162 return 0;
3163}
3164
3165#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3166static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
3167 unsigned int value)
3168{
3169 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003170 BUG_ON(reg > TABLA_MAX_REGISTER);
3171
3172 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003173 ret = snd_soc_cache_write(codec, reg, value);
3174 if (ret != 0)
3175 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3176 reg, ret);
3177 }
3178
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303179 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003180}
3181static unsigned int tabla_read(struct snd_soc_codec *codec,
3182 unsigned int reg)
3183{
3184 unsigned int val;
3185 int ret;
3186
3187 BUG_ON(reg > TABLA_MAX_REGISTER);
3188
3189 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
3190 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003191 ret = snd_soc_cache_read(codec, reg, &val);
3192 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003193 return val;
3194 } else
3195 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3196 reg, ret);
3197 }
3198
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303199 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003200 return val;
3201}
3202
Bradley Rubincb1e2732011-06-23 16:49:20 -07003203static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3204{
Joonwoo Parkc0672392012-01-11 11:03:14 -08003205 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08003206 struct tabla_mbhc_btn_detect_cfg *btn_det;
3207 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003208 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003209
Joonwoo Park0976d012011-12-22 11:48:18 -08003210 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
3211 tabla->mbhc_data.v_ins_hu & 0xFF);
3212 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
3213 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003214
Joonwoo Park0976d012011-12-22 11:48:18 -08003215 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
3216 tabla->mbhc_data.v_b1_hu & 0xFF);
3217 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
3218 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
3219
3220 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
3221 tabla->mbhc_data.v_b1_h & 0xFF);
3222 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
3223 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
3224
3225 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
3226 tabla->mbhc_data.v_brh & 0xFF);
3227 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
3228 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
3229
3230 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
3231 tabla->mbhc_data.v_brl & 0xFF);
3232 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
3233 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
3234
Joonwoo Parkc0672392012-01-11 11:03:14 -08003235 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003236 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08003237 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003238 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
3239 tabla->mbhc_data.npoll);
3240 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
3241 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08003242 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003243 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
3244 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003245}
3246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003247static int tabla_startup(struct snd_pcm_substream *substream,
3248 struct snd_soc_dai *dai)
3249{
Kuirong Wanga545e722012-02-06 19:12:54 -08003250 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003251 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3252 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003253 if ((tabla_core != NULL) &&
3254 (tabla_core->dev != NULL) &&
3255 (tabla_core->dev->parent != NULL))
3256 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003257
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003258 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259}
3260
3261static void tabla_shutdown(struct snd_pcm_substream *substream,
3262 struct snd_soc_dai *dai)
3263{
Kuirong Wanga545e722012-02-06 19:12:54 -08003264 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003265 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3266 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003267 if ((tabla_core != NULL) &&
3268 (tabla_core->dev != NULL) &&
3269 (tabla_core->dev->parent != NULL)) {
3270 pm_runtime_mark_last_busy(tabla_core->dev->parent);
3271 pm_runtime_put(tabla_core->dev->parent);
3272 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003273}
3274
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003275int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003276{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003277 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3278
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003279 pr_debug("%s() mclk_enable = %u\n", __func__, mclk_enable);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003280
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003281 if (dapm)
3282 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003283 if (mclk_enable) {
3284 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003285
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003286 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07003287 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003288 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003289 TABLA_BANDGAP_AUDIO_MODE);
3290 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003291 tabla_codec_calibrate_hs_polling(codec);
3292 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303293 } else {
3294 tabla_codec_enable_bandgap(codec,
3295 TABLA_BANDGAP_AUDIO_MODE);
3296 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003297 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003298 } else {
3299
3300 if (!tabla->mclk_enabled) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003301 if (dapm)
3302 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003303 pr_err("Error, MCLK already diabled\n");
3304 return -EINVAL;
3305 }
3306 tabla->mclk_enabled = false;
3307
3308 if (tabla->mbhc_polling_active) {
3309 if (!tabla->mclk_enabled) {
3310 tabla_codec_pause_hs_polling(codec);
3311 tabla_codec_enable_bandgap(codec,
3312 TABLA_BANDGAP_MBHC_MODE);
3313 tabla_enable_rx_bias(codec, 1);
3314 tabla_codec_enable_clock_block(codec, 1);
3315 tabla_codec_calibrate_hs_polling(codec);
3316 tabla_codec_start_hs_polling(codec);
3317 }
3318 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
3319 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303320 } else {
3321 tabla_codec_disable_clock_block(codec);
3322 tabla_codec_enable_bandgap(codec,
3323 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003324 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003325 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003326 if (dapm)
3327 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003328 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003329}
3330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003331static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
3332 int clk_id, unsigned int freq, int dir)
3333{
3334 pr_debug("%s\n", __func__);
3335 return 0;
3336}
3337
3338static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3339{
Santosh Mardie15e2302011-11-15 10:39:23 +05303340 u8 val = 0;
3341 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3342
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003343 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05303344 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3345 case SND_SOC_DAIFMT_CBS_CFS:
3346 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303347 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003348 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303349 snd_soc_update_bits(dai->codec,
3350 TABLA_A_CDC_CLK_TX_I2S_CTL,
3351 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003352 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303353 snd_soc_update_bits(dai->codec,
3354 TABLA_A_CDC_CLK_RX_I2S_CTL,
3355 TABLA_I2S_MASTER_MODE_MASK, 0);
3356 }
3357 break;
3358 case SND_SOC_DAIFMT_CBM_CFM:
3359 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303360 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303361 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003362 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303363 snd_soc_update_bits(dai->codec,
3364 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003365 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303366 snd_soc_update_bits(dai->codec,
3367 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
3368 }
3369 break;
3370 default:
3371 return -EINVAL;
3372 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003373 return 0;
3374}
3375
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003376static int tabla_set_channel_map(struct snd_soc_dai *dai,
3377 unsigned int tx_num, unsigned int *tx_slot,
3378 unsigned int rx_num, unsigned int *rx_slot)
3379
3380{
3381 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3382 u32 i = 0;
3383 if (!tx_slot && !rx_slot) {
3384 pr_err("%s: Invalid\n", __func__);
3385 return -EINVAL;
3386 }
3387 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3388
Neema Shettyd3a89262012-02-16 10:23:50 -08003389 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003390 for (i = 0; i < rx_num; i++) {
3391 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
3392 tabla->dai[dai->id - 1].ch_act = 0;
3393 tabla->dai[dai->id - 1].ch_tot = rx_num;
3394 }
3395 } else if (dai->id == AIF1_CAP) {
3396 for (i = 0; i < tx_num; i++) {
3397 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
3398 tabla->dai[dai->id - 1].ch_act = 0;
3399 tabla->dai[dai->id - 1].ch_tot = tx_num;
3400 }
3401 }
3402 return 0;
3403}
3404
3405static int tabla_get_channel_map(struct snd_soc_dai *dai,
3406 unsigned int *tx_num, unsigned int *tx_slot,
3407 unsigned int *rx_num, unsigned int *rx_slot)
3408
3409{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303410 struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003411
3412 u32 cnt = 0;
3413 u32 tx_ch[SLIM_MAX_TX_PORTS];
3414 u32 rx_ch[SLIM_MAX_RX_PORTS];
3415
3416 if (!rx_slot && !tx_slot) {
3417 pr_err("%s: Invalid\n", __func__);
3418 return -EINVAL;
3419 }
3420 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
3421 /* for virtual port, codec driver needs to do
3422 * housekeeping, for now should be ok
3423 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303424 wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003425 if (dai->id == AIF1_PB) {
3426 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3427 while (cnt < *rx_num) {
3428 rx_slot[cnt] = rx_ch[cnt];
3429 cnt++;
3430 }
3431 } else if (dai->id == AIF1_CAP) {
3432 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3433 while (cnt < *tx_num) {
3434 tx_slot[cnt] = tx_ch[6 + cnt];
3435 cnt++;
3436 }
Neema Shettyd3a89262012-02-16 10:23:50 -08003437 } else if (dai->id == AIF2_PB) {
3438 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3439 while (cnt < *rx_num) {
3440 rx_slot[cnt] = rx_ch[5 + cnt];
3441 cnt++;
3442 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003443 }
3444 return 0;
3445}
3446
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003447static int tabla_hw_params(struct snd_pcm_substream *substream,
3448 struct snd_pcm_hw_params *params,
3449 struct snd_soc_dai *dai)
3450{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003451 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05303452 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07003453 u8 path, shift;
3454 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003455 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003456 u32 compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003457
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003458 pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
3459 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003460
3461 switch (params_rate(params)) {
3462 case 8000:
3463 tx_fs_rate = 0x00;
3464 rx_fs_rate = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003465 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003466 break;
3467 case 16000:
3468 tx_fs_rate = 0x01;
3469 rx_fs_rate = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003470 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003471 break;
3472 case 32000:
3473 tx_fs_rate = 0x02;
3474 rx_fs_rate = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003475 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003476 break;
3477 case 48000:
3478 tx_fs_rate = 0x03;
3479 rx_fs_rate = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003480 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003481 break;
3482 default:
3483 pr_err("%s: Invalid sampling rate %d\n", __func__,
3484 params_rate(params));
3485 return -EINVAL;
3486 }
3487
3488
3489 /**
3490 * If current dai is a tx dai, set sample rate to
3491 * all the txfe paths that are currently not active
3492 */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003493 if (dai->id == AIF1_CAP) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003494
3495 tx_state = snd_soc_read(codec,
3496 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3497
3498 for (path = 1, shift = 0;
3499 path <= NUM_DECIMATORS; path++, shift++) {
3500
3501 if (path == BITS_PER_REG + 1) {
3502 shift = 0;
3503 tx_state = snd_soc_read(codec,
3504 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
3505 }
3506
3507 if (!(tx_state & (1 << shift))) {
3508 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
3509 + (BITS_PER_REG*(path-1));
3510 snd_soc_update_bits(codec, tx_fs_reg,
3511 0x03, tx_fs_rate);
3512 }
3513 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303514 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303515 switch (params_format(params)) {
3516 case SNDRV_PCM_FORMAT_S16_LE:
3517 snd_soc_update_bits(codec,
3518 TABLA_A_CDC_CLK_TX_I2S_CTL,
3519 0x20, 0x20);
3520 break;
3521 case SNDRV_PCM_FORMAT_S32_LE:
3522 snd_soc_update_bits(codec,
3523 TABLA_A_CDC_CLK_TX_I2S_CTL,
3524 0x20, 0x00);
3525 break;
3526 default:
3527 pr_err("invalid format\n");
3528 break;
3529 }
3530 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
3531 0x03, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003532 } else {
3533 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303534 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003535 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003536 /**
3537 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3538 * with varying sample rates
3539 */
3540
3541 /**
3542 * If current dai is a rx dai, set sample rate to
3543 * all the rx paths that are currently not active
3544 */
Neema Shettyd3a89262012-02-16 10:23:50 -08003545 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003546
3547 rx_state = snd_soc_read(codec,
3548 TABLA_A_CDC_CLK_RX_B1_CTL);
3549
3550 for (path = 1, shift = 0;
3551 path <= NUM_INTERPOLATORS; path++, shift++) {
3552
3553 if (!(rx_state & (1 << shift))) {
3554 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
3555 + (BITS_PER_REG*(path-1));
3556 snd_soc_update_bits(codec, rx_fs_reg,
3557 0xE0, rx_fs_rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003558 if (comp_rx_path[shift] < COMPANDER_MAX)
3559 tabla->comp_fs[comp_rx_path[shift]]
3560 = compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003561 }
3562 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303563 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303564 switch (params_format(params)) {
3565 case SNDRV_PCM_FORMAT_S16_LE:
3566 snd_soc_update_bits(codec,
3567 TABLA_A_CDC_CLK_RX_I2S_CTL,
3568 0x20, 0x20);
3569 break;
3570 case SNDRV_PCM_FORMAT_S32_LE:
3571 snd_soc_update_bits(codec,
3572 TABLA_A_CDC_CLK_RX_I2S_CTL,
3573 0x20, 0x00);
3574 break;
3575 default:
3576 pr_err("invalid format\n");
3577 break;
3578 }
3579 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
3580 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003581 } else {
3582 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303583 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003584 }
3585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003586 return 0;
3587}
3588
3589static struct snd_soc_dai_ops tabla_dai_ops = {
3590 .startup = tabla_startup,
3591 .shutdown = tabla_shutdown,
3592 .hw_params = tabla_hw_params,
3593 .set_sysclk = tabla_set_dai_sysclk,
3594 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003595 .set_channel_map = tabla_set_channel_map,
3596 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597};
3598
3599static struct snd_soc_dai_driver tabla_dai[] = {
3600 {
3601 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003602 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003603 .playback = {
3604 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003605 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003606 .formats = TABLA_FORMATS,
3607 .rate_max = 48000,
3608 .rate_min = 8000,
3609 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003610 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003611 },
3612 .ops = &tabla_dai_ops,
3613 },
3614 {
3615 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003616 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003617 .capture = {
3618 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003619 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003620 .formats = TABLA_FORMATS,
3621 .rate_max = 48000,
3622 .rate_min = 8000,
3623 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003624 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003625 },
3626 .ops = &tabla_dai_ops,
3627 },
Neema Shettyd3a89262012-02-16 10:23:50 -08003628 {
3629 .name = "tabla_rx2",
3630 .id = AIF2_PB,
3631 .playback = {
3632 .stream_name = "AIF2 Playback",
3633 .rates = WCD9310_RATES,
3634 .formats = TABLA_FORMATS,
3635 .rate_min = 8000,
3636 .rate_max = 48000,
3637 .channels_min = 1,
3638 .channels_max = 2,
3639 },
3640 .ops = &tabla_dai_ops,
3641 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003642};
Santosh Mardie15e2302011-11-15 10:39:23 +05303643
3644static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3645 {
3646 .name = "tabla_i2s_rx1",
3647 .id = 1,
3648 .playback = {
3649 .stream_name = "AIF1 Playback",
3650 .rates = WCD9310_RATES,
3651 .formats = TABLA_FORMATS,
3652 .rate_max = 48000,
3653 .rate_min = 8000,
3654 .channels_min = 1,
3655 .channels_max = 4,
3656 },
3657 .ops = &tabla_dai_ops,
3658 },
3659 {
3660 .name = "tabla_i2s_tx1",
3661 .id = 2,
3662 .capture = {
3663 .stream_name = "AIF1 Capture",
3664 .rates = WCD9310_RATES,
3665 .formats = TABLA_FORMATS,
3666 .rate_max = 48000,
3667 .rate_min = 8000,
3668 .channels_min = 1,
3669 .channels_max = 4,
3670 },
3671 .ops = &tabla_dai_ops,
3672 },
3673};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003674
3675static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3676 struct snd_kcontrol *kcontrol, int event)
3677{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303678 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003679 struct snd_soc_codec *codec = w->codec;
3680 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3681 u32 j = 0;
3682 u32 ret = 0;
3683 codec->control_data = dev_get_drvdata(codec->dev->parent);
3684 tabla = codec->control_data;
3685 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303686 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003687 return 0;
3688 switch (event) {
3689 case SND_SOC_DAPM_POST_PMU:
3690 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3691 if (tabla_dai[j].id == AIF1_CAP)
3692 continue;
3693 if (!strncmp(w->sname,
3694 tabla_dai[j].playback.stream_name, 13)) {
3695 ++tabla_p->dai[j].ch_act;
3696 break;
3697 }
3698 }
3699 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303700 ret = wcd9xxx_cfg_slim_sch_rx(tabla,
3701 tabla_p->dai[j].ch_num,
3702 tabla_p->dai[j].ch_tot,
3703 tabla_p->dai[j].rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003704 break;
3705 case SND_SOC_DAPM_POST_PMD:
3706 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3707 if (tabla_dai[j].id == AIF1_CAP)
3708 continue;
3709 if (!strncmp(w->sname,
3710 tabla_dai[j].playback.stream_name, 13)) {
3711 --tabla_p->dai[j].ch_act;
3712 break;
3713 }
3714 }
3715 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303716 ret = wcd9xxx_close_slim_sch_rx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003717 tabla_p->dai[j].ch_num,
3718 tabla_p->dai[j].ch_tot);
Bharath Ramachandramurthyda6fa7a2012-03-30 14:35:32 -07003719 usleep_range(5000, 5000);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003720 tabla_p->dai[j].rate = 0;
3721 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303722 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003723 tabla_p->dai[j].ch_tot = 0;
3724 }
3725 }
3726 return ret;
3727}
3728
3729static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3730 struct snd_kcontrol *kcontrol, int event)
3731{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303732 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003733 struct snd_soc_codec *codec = w->codec;
3734 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3735 /* index to the DAI ID, for now hardcoding */
3736 u32 j = 0;
3737 u32 ret = 0;
3738
3739 codec->control_data = dev_get_drvdata(codec->dev->parent);
3740 tabla = codec->control_data;
3741
3742 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303743 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003744 return 0;
3745 switch (event) {
3746 case SND_SOC_DAPM_POST_PMU:
3747 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003748 if (tabla_dai[j].id == AIF1_PB ||
3749 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003750 continue;
3751 if (!strncmp(w->sname,
3752 tabla_dai[j].capture.stream_name, 13)) {
3753 ++tabla_p->dai[j].ch_act;
3754 break;
3755 }
3756 }
3757 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303758 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003759 tabla_p->dai[j].ch_num,
3760 tabla_p->dai[j].ch_tot,
3761 tabla_p->dai[j].rate);
3762 break;
3763 case SND_SOC_DAPM_POST_PMD:
3764 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003765 if (tabla_dai[j].id == AIF1_PB ||
3766 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003767 continue;
3768 if (!strncmp(w->sname,
3769 tabla_dai[j].capture.stream_name, 13)) {
3770 --tabla_p->dai[j].ch_act;
3771 break;
3772 }
3773 }
3774 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303775 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003776 tabla_p->dai[j].ch_num,
3777 tabla_p->dai[j].ch_tot);
3778 tabla_p->dai[j].rate = 0;
3779 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303780 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003781 tabla_p->dai[j].ch_tot = 0;
3782 }
3783 }
3784 return ret;
3785}
3786
3787/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3788 * Might Need to have callbacks registered only for slimbus
3789 */
3790static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
3791 /*RX stuff */
3792 SND_SOC_DAPM_OUTPUT("EAR"),
3793
3794 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
3795
3796 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
3797 ARRAY_SIZE(dac1_switch)),
3798
3799 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3800 0, tabla_codec_enable_slimrx,
3801 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3802 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3803 0, tabla_codec_enable_slimrx,
3804 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3805
3806 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3807 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3808
Neema Shettyd3a89262012-02-16 10:23:50 -08003809 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3810 0, tabla_codec_enable_slimrx,
3811 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3812 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3813 0, tabla_codec_enable_slimrx,
3814 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3815
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003816 /* Headphone */
3817 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3818 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3819 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3820 SND_SOC_DAPM_POST_PMD),
3821 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
3822 hphl_switch, ARRAY_SIZE(hphl_switch)),
3823
3824 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
3825 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3826 SND_SOC_DAPM_POST_PMD),
3827
3828 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
3829 tabla_hphr_dac_event,
3830 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3831
3832 /* Speaker */
3833 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
3834 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
3835 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
3836 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
3837 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
3838
3839 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
3840 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3841 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3842 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
3843 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3844 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3845 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
3846 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3847 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3848 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
3849 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3850 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3851 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
3852 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3853 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3854
3855 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
3856 , tabla_lineout_dac_event,
3857 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3858 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
3859 , tabla_lineout_dac_event,
3860 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3861 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
3862 , tabla_lineout_dac_event,
3863 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3864 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
3865 &lineout3_ground_switch),
3866 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
3867 , tabla_lineout_dac_event,
3868 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3869 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
3870 &lineout4_ground_switch),
3871 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
3872 , tabla_lineout_dac_event,
3873 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3874
3875 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
3876 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3877 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
3878 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3879 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
3880 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3881 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
3882 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3883 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
3884 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3885 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
3886 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3887 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
3888 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3889
3890 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
3891 &rx4_dsm_mux, tabla_codec_reset_interpolator,
3892 SND_SOC_DAPM_PRE_PMU),
3893
3894 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
3895 &rx6_dsm_mux, tabla_codec_reset_interpolator,
3896 SND_SOC_DAPM_PRE_PMU),
3897
3898 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
3899 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
3900
3901 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3902 &rx_mix1_inp1_mux),
3903 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3904 &rx_mix1_inp2_mux),
3905 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3906 &rx2_mix1_inp1_mux),
3907 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3908 &rx2_mix1_inp2_mux),
3909 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3910 &rx3_mix1_inp1_mux),
3911 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3912 &rx3_mix1_inp2_mux),
3913 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3914 &rx4_mix1_inp1_mux),
3915 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3916 &rx4_mix1_inp2_mux),
3917 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3918 &rx5_mix1_inp1_mux),
3919 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3920 &rx5_mix1_inp2_mux),
3921 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3922 &rx6_mix1_inp1_mux),
3923 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3924 &rx6_mix1_inp2_mux),
3925 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3926 &rx7_mix1_inp1_mux),
3927 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3928 &rx7_mix1_inp2_mux),
3929
3930 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
3931 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
3932 SND_SOC_DAPM_PRE_PMD),
3933
3934 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
3935 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
3936 SND_SOC_DAPM_POST_PMD),
3937
3938 /* TX */
3939
3940 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
3941 0),
3942
3943 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
3944 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
3945
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003946 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
3947 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3948 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3949 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
3950 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
3951 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3952
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003953 SND_SOC_DAPM_INPUT("AMIC1"),
3954 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
3955 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3956 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3957 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
3958 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3959 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3960 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
3961 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3962 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3963 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
3964 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3965 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3966
3967 SND_SOC_DAPM_INPUT("AMIC3"),
3968 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
3969 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3970 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3971
3972 SND_SOC_DAPM_INPUT("AMIC4"),
3973 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
3974 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3975 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3976
3977 SND_SOC_DAPM_INPUT("AMIC5"),
3978 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
3979 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3980
3981 SND_SOC_DAPM_INPUT("AMIC6"),
3982 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
3983 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3984
3985 SND_SOC_DAPM_MUX_E("DEC1 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08003986 &dec1_mux, tabla_codec_enable_dec,
3987 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3988 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003989
3990 SND_SOC_DAPM_MUX_E("DEC2 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08003991 &dec2_mux, tabla_codec_enable_dec,
3992 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3993 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003994
3995 SND_SOC_DAPM_MUX_E("DEC3 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08003996 &dec3_mux, tabla_codec_enable_dec,
3997 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3998 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003999
4000 SND_SOC_DAPM_MUX_E("DEC4 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08004001 &dec4_mux, tabla_codec_enable_dec,
4002 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4003 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004004
4005 SND_SOC_DAPM_MUX_E("DEC5 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 4, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08004006 &dec5_mux, tabla_codec_enable_dec,
4007 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4008 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004009
4010 SND_SOC_DAPM_MUX_E("DEC6 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 5, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08004011 &dec6_mux, tabla_codec_enable_dec,
4012 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4013 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004014
4015 SND_SOC_DAPM_MUX_E("DEC7 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 6, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08004016 &dec7_mux, tabla_codec_enable_dec,
4017 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4018 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004019
4020 SND_SOC_DAPM_MUX_E("DEC8 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL, 7, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08004021 &dec8_mux, tabla_codec_enable_dec,
4022 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4023 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004024
4025 SND_SOC_DAPM_MUX_E("DEC9 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 0, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08004026 &dec9_mux, tabla_codec_enable_dec,
4027 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4028 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004029
4030 SND_SOC_DAPM_MUX_E("DEC10 MUX", TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL, 1, 0,
Kiran Kandid8cf5212012-03-02 15:34:53 -08004031 &dec10_mux, tabla_codec_enable_dec,
4032 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4033 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004034
4035 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
4036 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
4037
4038 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
4039 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
4040 SND_SOC_DAPM_POST_PMD),
4041
4042 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
4043
4044 SND_SOC_DAPM_INPUT("AMIC2"),
4045 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
4046 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4047 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4048 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
4049 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4050 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4051 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
4052 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4053 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4054 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
4055 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4056 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4057 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
4058 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4059 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4060 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
4061 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4062 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4063 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
4064 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4065 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4066 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
4067 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4068 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4069
4070 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
4071 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
4072 0, 0),
4073
4074 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
4075 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
4076 4, 0),
4077
4078 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
4079 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
4080 5, 0),
4081
4082 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
4083 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4084 0, tabla_codec_enable_slimtx,
4085 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4086
4087 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
4088 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4089 0, tabla_codec_enable_slimtx,
4090 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4091
4092 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
4093 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
4094 0, 0, tabla_codec_enable_slimtx,
4095 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4096
4097 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
4098 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
4099 0, 0, tabla_codec_enable_slimtx,
4100 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4101
4102 /* Digital Mic Inputs */
4103 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
4104 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4105 SND_SOC_DAPM_POST_PMD),
4106
4107 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
4108 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4109 SND_SOC_DAPM_POST_PMD),
4110
4111 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
4112 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4113 SND_SOC_DAPM_POST_PMD),
4114
4115 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
4116 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4117 SND_SOC_DAPM_POST_PMD),
4118
4119 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
4120 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4121 SND_SOC_DAPM_POST_PMD),
4122 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
4123 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4124 SND_SOC_DAPM_POST_PMD),
4125
4126 /* Sidetone */
4127 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
4128 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08004129
4130 /* AUX PGA */
4131 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
4132 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4133 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4134 SND_SOC_DAPM_POST_PMD),
4135
4136 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
4137 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4138 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4139 SND_SOC_DAPM_POST_PMD),
4140
4141 /* Lineout, ear and HPH PA Mixers */
4142 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
4143 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
4144
4145 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4146 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4147
4148 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4149 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4150
4151 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4152 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
4153
4154 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
4155 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
4156
4157 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
4158 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
4159
4160 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
4161 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
4162
4163 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4164 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004165};
4166
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004167static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004168{
4169 u8 bias_msb, bias_lsb;
4170 short bias_value;
4171
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004172 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
4173 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
4174 bias_value = (bias_msb << 8) | bias_lsb;
4175 return bias_value;
4176}
4177
4178static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
4179{
4180 u8 bias_msb, bias_lsb;
4181 short bias_value;
4182
4183 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
4184 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
4185 bias_value = (bias_msb << 8) | bias_lsb;
4186 return bias_value;
4187}
4188
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004189static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004190{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004191 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
4192}
4193
4194static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4195 bool override_bypass, bool noreldetection)
4196{
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004197 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004198 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4199
4200 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4201 if (noreldetection)
4202 tabla_turn_onoff_rel_detection(codec, false);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004203
Joonwoo Park925914c2012-01-05 13:35:18 -08004204 /* Turn on the override */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004205 if (!override_bypass)
4206 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004207 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004208 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4209 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
4210 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004211 usleep_range(tabla->mbhc_data.t_sta_dce,
4212 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004213 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08004214 usleep_range(tabla->mbhc_data.t_dce,
4215 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004216 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004217 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004218 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004219 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4220 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004221 usleep_range(tabla->mbhc_data.t_sta_dce,
4222 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08004223 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4224 usleep_range(tabla->mbhc_data.t_sta,
4225 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004226 bias_value = tabla_codec_read_sta_result(codec);
4227 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4228 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004229 }
Joonwoo Park925914c2012-01-05 13:35:18 -08004230 /* Turn off the override after measuring mic voltage */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004231 if (!override_bypass)
4232 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4233
4234 if (noreldetection)
4235 tabla_turn_onoff_rel_detection(codec, true);
4236 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004237
Bradley Rubincb1e2732011-06-23 16:49:20 -07004238 return bias_value;
4239}
4240
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004241static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4242 bool norel)
4243{
4244 return __tabla_codec_sta_dce(codec, dce, false, norel);
4245}
4246
4247/* called only from interrupt which is under codec_resource_lock acquisition */
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004248static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004249{
4250 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004251 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004252 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004253
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004254 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004255 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004256 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004257 }
4258
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004259 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004260 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004261 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004262 tabla_codec_enable_clock_block(codec, 1);
4263 }
4264
4265 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4266
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004267 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004268 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4269 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004270
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004271 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004272
4273 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004274 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004275
4276 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4277 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4278 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4279
4280 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004281 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4282 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004283
Joonwoo Park925914c2012-01-05 13:35:18 -08004284 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004285 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4286
Bradley Rubincb1e2732011-06-23 16:49:20 -07004287 tabla_codec_calibrate_hs_polling(codec);
4288
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004289 /* don't flip override */
4290 bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004291 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4292 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004293 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004294
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004295 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004296}
4297
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004298static int tabla_cancel_btn_work(struct tabla_priv *tabla)
4299{
4300 int r = 0;
4301 struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
4302
4303 if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
4304 /* if scheduled mbhc_btn_dwork is canceled from here,
4305 * we have to unlock from here instead btn_work */
4306 wcd9xxx_unlock_sleep(core);
4307 r = 1;
4308 }
4309 return r;
4310}
4311
4312/* called under codec_resource_lock acquisition */
4313void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
Joonwoo Park03324832012-03-19 19:36:16 -07004314{
4315 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004316 u8 wg_time;
4317
4318 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4319 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07004320
4321 /* If headphone PA is on, check if userspace receives
4322 * removal event to sync-up PA's state */
4323 if (tabla_is_hph_pa_on(codec)) {
4324 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4325 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4326 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4327 } else {
4328 pr_debug("%s PA is off\n", __func__);
4329 }
4330
4331 if (tabla_is_hph_dac_on(codec, 1))
4332 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4333 if (tabla_is_hph_dac_on(codec, 0))
4334 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004335
4336 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
4337 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
4338 0xC0, 0x00);
4339 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
4340 0xC0, 0x00);
4341 usleep_range(wg_time * 1000, wg_time * 1000);
4342}
4343
4344static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
4345{
4346 bool pa_turned_on = false;
4347 struct snd_soc_codec *codec = tabla->codec;
4348 u8 wg_time;
4349
4350 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4351 wg_time += 1;
4352
4353 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4354 &tabla->hph_pa_dac_state)) {
4355 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4356 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4357 0xC0, 0xC0);
4358 }
4359 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4360 &tabla->hph_pa_dac_state)) {
4361 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4362 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4363 0xC0, 0xC0);
4364 }
4365
4366 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4367 &tabla->hph_pa_dac_state)) {
4368 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4369 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4370 1 << 4);
4371 pa_turned_on = true;
4372 }
4373 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4374 &tabla->hph_pa_dac_state)) {
4375 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4376 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4377 1 << 5);
4378 pa_turned_on = true;
4379 }
4380
4381 if (pa_turned_on) {
4382 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4383 __func__);
4384 usleep_range(wg_time * 1000, wg_time * 1000);
4385 }
4386}
4387
4388/* called under codec_resource_lock acquisition */
4389static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4390 enum snd_jack_types jack_type)
4391{
4392 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4393
4394 if (!insertion) {
4395 /* Report removal */
4396 tabla->hph_status &= ~jack_type;
4397 if (tabla->mbhc_cfg.headset_jack) {
4398 /* cancel possibly scheduled btn work and
4399 * report release if we reported button press */
4400 if (tabla_cancel_btn_work(tabla)) {
4401 pr_debug("%s: button press is canceled\n",
4402 __func__);
4403 } else if (tabla->buttons_pressed) {
4404 pr_debug("%s: Reporting release for reported "
4405 "button press %d\n", __func__,
4406 jack_type);
4407 tabla_snd_soc_jack_report(tabla,
4408 tabla->mbhc_cfg.button_jack, 0,
4409 tabla->buttons_pressed);
4410 tabla->buttons_pressed &=
4411 ~TABLA_JACK_BUTTON_MASK;
4412 }
4413 pr_debug("%s: Reporting removal %d\n", __func__,
4414 jack_type);
4415 tabla_snd_soc_jack_report(tabla,
4416 tabla->mbhc_cfg.headset_jack,
4417 tabla->hph_status,
4418 TABLA_JACK_MASK);
4419 }
4420 tabla_set_and_turnoff_hph_padac(codec);
4421 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
4422 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4423 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
4424 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4425 tabla->current_plug = PLUG_TYPE_NONE;
4426 tabla->mbhc_polling_active = false;
4427 } else {
4428 /* Report insertion */
4429 tabla->hph_status |= jack_type;
4430
4431 if (jack_type == SND_JACK_HEADPHONE)
4432 tabla->current_plug = PLUG_TYPE_HEADPHONE;
4433 else if (jack_type == SND_JACK_HEADSET) {
4434 tabla->mbhc_polling_active = true;
4435 tabla->current_plug = PLUG_TYPE_HEADSET;
4436 }
4437 if (tabla->mbhc_cfg.headset_jack) {
4438 pr_debug("%s: Reporting insertion %d\n", __func__,
4439 jack_type);
4440 tabla_snd_soc_jack_report(tabla,
4441 tabla->mbhc_cfg.headset_jack,
4442 tabla->hph_status,
4443 TABLA_JACK_MASK);
4444 }
4445 tabla_clr_and_turnon_hph_padac(tabla);
4446 }
Joonwoo Park03324832012-03-19 19:36:16 -07004447}
4448
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004449static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07004450 int insertion, int trigger,
4451 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004452{
4453 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004454 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08004455 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004456 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004457 const struct tabla_mbhc_plug_detect_cfg *plug_det =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004458 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004459
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004460 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004461 pr_err("Error, no tabla calibration\n");
4462 return -EINVAL;
4463 }
4464
4465 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
4466
Joonwoo Park03324832012-03-19 19:36:16 -07004467 /* Make sure mic bias and Mic line schmitt trigger
4468 * are turned OFF
4469 */
4470 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
4471 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
4472
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004473 if (insertion) {
Joonwoo Park03324832012-03-19 19:36:16 -07004474 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004475
Joonwoo Park03324832012-03-19 19:36:16 -07004476 /* DAPM can manipulate PA/DAC bits concurrently */
4477 if (padac_off == true) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004478 tabla_set_and_turnoff_hph_padac(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004479 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004480
Joonwoo Park03324832012-03-19 19:36:16 -07004481 if (trigger == MBHC_USE_HPHL_TRIGGER) {
4482 /* Enable HPH Schmitt Trigger */
4483 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
4484 0x11);
4485 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
4486 plug_det->hph_current << 2);
4487 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
4488 0x02);
4489 } else if (trigger == MBHC_USE_MB_TRIGGER) {
4490 /* enable the mic line schmitt trigger */
4491 snd_soc_update_bits(codec,
4492 tabla->mbhc_bias_regs.mbhc_reg,
4493 0x60, plug_det->mic_current << 5);
4494 snd_soc_update_bits(codec,
4495 tabla->mbhc_bias_regs.mbhc_reg,
4496 0x80, 0x80);
4497 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4498 snd_soc_update_bits(codec,
4499 tabla->mbhc_bias_regs.ctl_reg, 0x01,
4500 0x00);
4501 snd_soc_update_bits(codec,
4502 tabla->mbhc_bias_regs.mbhc_reg,
4503 0x10, 0x10);
4504 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004505
4506 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004507 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07004508
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004509 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004510 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004511 /* Make sure the HPH schmitt trigger is OFF */
4512 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
4513
4514 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07004515 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
4516 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004517 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08004518 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004519 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4520 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004521 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004522 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4523 0x10, 0x10);
4524
4525 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004526 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004527 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528
4529 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004530 /* called called by interrupt */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004531 if (!(tabla->clock_active)) {
4532 tabla_codec_enable_config_mode(codec, 1);
4533 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004534 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004535 usleep_range(generic->t_shutdown_plug_rem,
4536 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004537 tabla_codec_enable_config_mode(codec, 0);
4538 } else
4539 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004540 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004541 }
4542
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004543 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004544
4545 /* If central bandgap disabled */
4546 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
4547 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004548 usleep_range(generic->t_bg_fast_settle,
4549 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004550 central_bias_enabled = 1;
4551 }
4552
4553 /* If LDO_H disabled */
4554 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
4555 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
4556 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004557 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004558 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
4559
4560 if (central_bias_enabled)
4561 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
4562 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004563
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004564 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004565 tabla->mbhc_cfg.micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004566
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304567 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004568 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4569 return 0;
4570}
4571
Joonwoo Park0976d012011-12-22 11:48:18 -08004572static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4573 s16 vin_mv)
4574{
Joonwoo Park0976d012011-12-22 11:48:18 -08004575 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004576 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08004577 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07004578 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004579
4580 tabla = snd_soc_codec_get_drvdata(codec);
4581 mb_mv = tabla->mbhc_data.micb_mv;
4582
4583 if (mb_mv == 0) {
4584 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4585 return -EINVAL;
4586 }
4587
4588 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004589 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
4590 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004591 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004592 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
4593 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004594 }
4595 in = (u32) diff * vin_mv;
4596
Joonwoo Park03324832012-03-19 19:36:16 -07004597 value = (u16) (in / mb_mv) + zero;
4598 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004599}
4600
4601static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4602 u16 bias_value)
4603{
4604 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004605 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08004606 s32 mv;
4607
4608 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004609 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004610 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004611 z = (tabla->mbhc_data.dce_z);
4612 mb = (tabla->mbhc_data.dce_mb);
4613 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004614 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004615 z = (tabla->mbhc_data.sta_z);
4616 mb = (tabla->mbhc_data.sta_mb);
4617 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004618 }
4619
4620 return mv;
4621}
4622
Joonwoo Park03324832012-03-19 19:36:16 -07004623static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004624{
4625 struct delayed_work *delayed_work;
4626 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08004627 short bias_value;
4628 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07004629 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004630
4631 pr_debug("%s:\n", __func__);
4632
4633 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07004634 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004635 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004636
4637 if (tabla) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004638 if (tabla->mbhc_cfg.button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004639 bias_value = tabla_codec_read_sta_result(tabla->codec);
4640 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304641 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004642 bias_value = tabla_codec_read_dce_result(tabla->codec);
4643 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304644 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004645 pr_debug("%s: Reporting long button press event"
4646 " STA: %d, DCE: %d\n", __func__,
4647 sta_mv, dce_mv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004648 tabla_snd_soc_jack_report(tabla,
4649 tabla->mbhc_cfg.button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07004650 tabla->buttons_pressed,
4651 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004652 }
4653 } else {
4654 pr_err("%s: Bad tabla private data\n", __func__);
4655 }
4656
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004657 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07004658 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004659}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004660
Joonwoo Park0976d012011-12-22 11:48:18 -08004661void tabla_mbhc_cal(struct snd_soc_codec *codec)
4662{
4663 struct tabla_priv *tabla;
4664 struct tabla_mbhc_btn_detect_cfg *btn_det;
4665 u8 cfilt_mode, bg_mode;
4666 u8 ncic, nmeas, navg;
4667 u32 mclk_rate;
4668 u32 dce_wait, sta_wait;
4669 u8 *n_cic;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004670 void *calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08004671
4672 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004673 calibration = tabla->mbhc_cfg.calibration;
4674
4675 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4676 tabla_turn_onoff_rel_detection(codec, false);
Joonwoo Park0976d012011-12-22 11:48:18 -08004677
4678 /* First compute the DCE / STA wait times
4679 * depending on tunable parameters.
4680 * The value is computed in microseconds
4681 */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004682 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004683 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08004684 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004685 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
4686 navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
4687 mclk_rate = tabla->mbhc_cfg.mclk_rate;
Joonwoo Park433149a2012-01-11 09:53:54 -08004688 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
4689 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08004690
4691 tabla->mbhc_data.t_dce = dce_wait;
4692 tabla->mbhc_data.t_sta = sta_wait;
4693
4694 /* LDOH and CFILT are already configured during pdata handling.
4695 * Only need to make sure CFILT and bandgap are in Fast mode.
4696 * Need to restore defaults once calculation is done.
4697 */
4698 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4699 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
4700 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
4701 0x02);
4702
4703 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
4704 * to perform ADC calibration
4705 */
4706 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004707 tabla->mbhc_cfg.micbias << 5);
Joonwoo Park0976d012011-12-22 11:48:18 -08004708 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
4709 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
4710 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
4711 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
4712
4713 /* DCE measurement for 0 volts */
4714 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4715 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4716 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004717 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4718 usleep_range(100, 100);
4719 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4720 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4721 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
4722
4723 /* DCE measurment for MB voltage */
4724 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4725 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
4726 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4727 usleep_range(100, 100);
4728 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4729 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4730 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
4731
4732 /* Sta measuremnt for 0 volts */
4733 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4734 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4735 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004736 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4737 usleep_range(100, 100);
4738 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4739 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4740 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
4741
4742 /* STA Measurement for MB Voltage */
4743 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4744 usleep_range(100, 100);
4745 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4746 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4747 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
4748
4749 /* Restore default settings. */
4750 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4751 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4752 cfilt_mode);
4753 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
4754
4755 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
4756 usleep_range(100, 100);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004757
4758 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4759 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004760}
4761
4762void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
4763 const enum tabla_mbhc_btn_det_mem mem)
4764{
4765 void *ret = &btn_det->_v_btn_low;
4766
4767 switch (mem) {
4768 case TABLA_BTN_DET_GAIN:
4769 ret += sizeof(btn_det->_n_cic);
4770 case TABLA_BTN_DET_N_CIC:
4771 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08004772 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08004773 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
4774 case TABLA_BTN_DET_V_BTN_HIGH:
4775 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
4776 case TABLA_BTN_DET_V_BTN_LOW:
4777 /* do nothing */
4778 break;
4779 default:
4780 ret = NULL;
4781 }
4782
4783 return ret;
4784}
4785
4786static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
4787{
4788 struct tabla_priv *tabla;
4789 s16 btn_mv = 0, btn_delta_mv;
4790 struct tabla_mbhc_btn_detect_cfg *btn_det;
4791 struct tabla_mbhc_plug_type_cfg *plug_type;
4792 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004793 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08004794 int i;
4795
4796 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004797 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
4798 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004799
Joonwoo Parkc0672392012-01-11 11:03:14 -08004800 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004801 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07004802 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08004803 tabla->mbhc_data.nbounce_wait = 30;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004804 } else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004805 tabla->mbhc_data.npoll = 7;
4806 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004807 }
Joonwoo Park0976d012011-12-22 11:48:18 -08004808
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004809 tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
4810 (tabla->mbhc_cfg.mclk_rate / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08004811 n_ready[tabla_codec_mclk_index(tabla)]) +
4812 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08004813 tabla->mbhc_data.v_ins_hu =
4814 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
4815 tabla->mbhc_data.v_ins_h =
4816 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
4817
4818 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
4819 for (i = 0; i < btn_det->num_btn; i++)
4820 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
4821
4822 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
4823 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
4824
4825 tabla->mbhc_data.v_b1_hu =
4826 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
4827
4828 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
4829
4830 tabla->mbhc_data.v_b1_huc =
4831 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
4832
4833 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
Joonwoo Park03324832012-03-19 19:36:16 -07004834 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
Joonwoo Park0976d012011-12-22 11:48:18 -08004835
4836 tabla->mbhc_data.v_no_mic =
4837 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
4838}
4839
4840void tabla_mbhc_init(struct snd_soc_codec *codec)
4841{
4842 struct tabla_priv *tabla;
4843 struct tabla_mbhc_general_cfg *generic;
4844 struct tabla_mbhc_btn_detect_cfg *btn_det;
4845 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08004846 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304847 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08004848
4849 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004850 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
4851 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004852
Joonwoo Park0976d012011-12-22 11:48:18 -08004853 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08004854 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004855 snd_soc_update_bits(codec,
4856 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
4857 0x07, n);
4858 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
4859 btn_det->c[n]);
4860 }
4861 }
4862 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
4863 btn_det->nc);
4864
4865 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
4866 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08004867 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08004868
4869 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08004870 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
4871 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004872
4873 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
4874 generic->mbhc_nsa << 4);
4875
4876 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
4877 btn_det->n_meas);
4878
4879 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
4880
4881 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
4882
4883 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
4884 btn_det->mbhc_nsc << 3);
4885
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004886 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
4887 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08004888
4889 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07004890
4891 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004892}
4893
Patrick Lai64b43262011-12-06 17:29:15 -08004894static bool tabla_mbhc_fw_validate(const struct firmware *fw)
4895{
4896 u32 cfg_offset;
4897 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
4898 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
4899
4900 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
4901 return false;
4902
4903 /* previous check guarantees that there is enough fw data up
4904 * to num_btn
4905 */
4906 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
4907 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
4908 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
4909 return false;
4910
4911 /* previous check guarantees that there is enough fw data up
4912 * to start of impedance detection configuration
4913 */
4914 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
4915 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
4916
4917 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
4918 return false;
4919
4920 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
4921 return false;
4922
4923 return true;
4924}
Joonwoo Park03324832012-03-19 19:36:16 -07004925
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004926static int tabla_determine_button(const struct tabla_priv *priv,
4927 const s32 bias_mv)
4928{
4929 s16 *v_btn_low, *v_btn_high;
4930 struct tabla_mbhc_btn_detect_cfg *btn_det;
4931 int i, btn = -1;
4932
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004933 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004934 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
4935 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304936 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004937 for (i = 0; i < btn_det->num_btn; i++) {
4938 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
4939 btn = i;
4940 break;
4941 }
4942 }
4943
4944 if (btn == -1)
4945 pr_debug("%s: couldn't find button number for mic mv %d\n",
4946 __func__, bias_mv);
4947
4948 return btn;
4949}
4950
4951static int tabla_get_button_mask(const int btn)
4952{
4953 int mask = 0;
4954 switch (btn) {
4955 case 0:
4956 mask = SND_JACK_BTN_0;
4957 break;
4958 case 1:
4959 mask = SND_JACK_BTN_1;
4960 break;
4961 case 2:
4962 mask = SND_JACK_BTN_2;
4963 break;
4964 case 3:
4965 mask = SND_JACK_BTN_3;
4966 break;
4967 case 4:
4968 mask = SND_JACK_BTN_4;
4969 break;
4970 case 5:
4971 mask = SND_JACK_BTN_5;
4972 break;
4973 case 6:
4974 mask = SND_JACK_BTN_6;
4975 break;
4976 case 7:
4977 mask = SND_JACK_BTN_7;
4978 break;
4979 }
4980 return mask;
4981}
4982
Bradley Rubincb1e2732011-06-23 16:49:20 -07004983static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004984{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004985 int i, mask;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004986 short dce, sta, bias_value_dce;
4987 s32 mv, stamv, bias_mv_dce;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004988 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004989 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004990 const struct tabla_mbhc_btn_detect_cfg *d =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004991 TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08004992 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004993 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304994 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07004995 int n_btn_meas = d->n_btn_meas;
4996 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07004997
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004998 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004999
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005000 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5001 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
5002 pr_debug("%s: mbhc is being recovered, skip button press\n",
5003 __func__);
5004 goto done;
5005 }
5006
5007 priv->mbhc_state = MBHC_STATE_POTENTIAL;
5008
5009 if (!priv->mbhc_polling_active) {
5010 pr_warn("%s: mbhc polling is not active, skip button press\n",
5011 __func__);
5012 goto done;
5013 }
Joonwoo Park03324832012-03-19 19:36:16 -07005014
5015 dce = tabla_codec_read_dce_result(codec);
5016 mv = tabla_codec_sta_dce_v(codec, 1, dce);
5017
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005018 /* If GPIO interrupt already kicked in, ignore button press */
5019 if (priv->in_gpio_handler) {
5020 pr_debug("%s: GPIO State Changed, ignore button press\n",
5021 __func__);
5022 btn = -1;
5023 goto done;
5024 }
5025
Joonwoo Park03324832012-03-19 19:36:16 -07005026 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
5027 if (priv->mbhc_last_resume &&
5028 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
5029 pr_debug("%s: Button is already released shortly after "
5030 "resume\n", __func__);
5031 n_btn_meas = 0;
5032 } else {
5033 pr_debug("%s: Button is already released without "
5034 "resume", __func__);
5035 sta = tabla_codec_read_sta_result(codec);
5036 stamv = tabla_codec_sta_dce_v(codec, 0, sta);
5037 btn = tabla_determine_button(priv, mv);
5038 if (btn != tabla_determine_button(priv, stamv))
5039 btn = -1;
5040 goto done;
5041 }
5042 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005043
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005044 /* determine pressed button */
Joonwoo Park03324832012-03-19 19:36:16 -07005045 btnmeas[meas++] = tabla_determine_button(priv, mv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005046 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Joonwoo Park03324832012-03-19 19:36:16 -07005047 meas - 1, dce, mv, btnmeas[meas - 1]);
5048 if (n_btn_meas == 0)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005049 btn = btnmeas[0];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005050 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
5051 bias_value_dce = tabla_codec_sta_dce(codec, 1, false);
5052 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
5053 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005054 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005055 __func__, meas, bias_value_dce, bias_mv_dce,
5056 btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005057 /* if large enough measurements are collected,
5058 * start to check if last all n_btn_con measurements were
5059 * in same button low/high range */
5060 if (meas + 1 >= d->n_btn_con) {
5061 for (i = 0; i < d->n_btn_con; i++)
5062 if ((btnmeas[meas] < 0) ||
5063 (btnmeas[meas] != btnmeas[meas - i]))
5064 break;
5065 if (i == d->n_btn_con) {
5066 /* button pressed */
5067 btn = btnmeas[meas];
5068 break;
Joonwoo Park03324832012-03-19 19:36:16 -07005069 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
5070 /* if left measurements are less than n_btn_con,
5071 * it's impossible to find button number */
5072 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005073 }
5074 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005075 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005076
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005077 if (btn >= 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005078 if (priv->in_gpio_handler) {
5079 pr_debug("%s: GPIO already triggered, ignore button "
5080 "press\n", __func__);
5081 goto done;
5082 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005083 mask = tabla_get_button_mask(btn);
5084 priv->buttons_pressed |= mask;
Joonwoo Park03324832012-03-19 19:36:16 -07005085 wcd9xxx_lock_sleep(core);
5086 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
5087 msecs_to_jiffies(400)) == 0) {
5088 WARN(1, "Button pressed twice without release"
5089 "event\n");
5090 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005091 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08005092 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005093 pr_debug("%s: bogus button press, too short press?\n",
5094 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08005095 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005096
Joonwoo Park03324832012-03-19 19:36:16 -07005097 done:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005098 pr_debug("%s: leave\n", __func__);
5099 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005100 return IRQ_HANDLED;
5101}
5102
Joonwoo Park03324832012-03-19 19:36:16 -07005103static int tabla_is_fake_press(struct tabla_priv *priv)
5104{
5105 int i;
5106 int r = 0;
5107 struct snd_soc_codec *codec = priv->codec;
5108 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
5109 short mb_v;
5110
5111 for (i = 0; i < dces; i++) {
5112 usleep_range(10000, 10000);
5113 if (i == 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005114 mb_v = tabla_codec_sta_dce(codec, 0, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005115 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
5116 tabla_codec_sta_dce_v(codec, 0, mb_v));
5117 if (mb_v < (short)priv->mbhc_data.v_b1_hu ||
5118 mb_v > (short)priv->mbhc_data.v_ins_hu) {
5119 r = 1;
5120 break;
5121 }
5122 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005123 mb_v = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005124 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
5125 tabla_codec_sta_dce_v(codec, 1, mb_v));
5126 if (mb_v < (short)priv->mbhc_data.v_b1_h ||
5127 mb_v > (short)priv->mbhc_data.v_ins_h) {
5128 r = 1;
5129 break;
5130 }
5131 }
5132 }
5133
5134 return r;
5135}
5136
Bradley Rubincb1e2732011-06-23 16:49:20 -07005137static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005138{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08005139 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08005140 struct tabla_priv *priv = data;
5141 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005142
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005143 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07005144
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005145 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5146 priv->mbhc_state = MBHC_STATE_RELEASE;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005147
Joonwoo Park03324832012-03-19 19:36:16 -07005148 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005149 ret = tabla_cancel_btn_work(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005150 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07005151 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005152 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005153 if (priv->mbhc_cfg.button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005154 tabla_snd_soc_jack_report(priv,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005155 priv->mbhc_cfg.button_jack, 0,
5156 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005157 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005158 if (tabla_is_fake_press(priv)) {
5159 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005160 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005161 } else if (priv->mbhc_cfg.button_jack) {
5162 if (priv->in_gpio_handler) {
5163 pr_debug("%s: GPIO kicked in, ignore\n",
5164 __func__);
5165 } else {
5166 pr_debug("%s: Reporting short button 0 "
5167 "press and release\n",
5168 __func__);
5169 tabla_snd_soc_jack_report(priv,
5170 priv->mbhc_cfg.button_jack,
5171 priv->buttons_pressed,
5172 priv->buttons_pressed);
5173 tabla_snd_soc_jack_report(priv,
5174 priv->mbhc_cfg.button_jack, 0,
5175 priv->buttons_pressed);
5176 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005177 }
5178 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005179
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005180 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
5181 }
5182
Joonwoo Park03324832012-03-19 19:36:16 -07005183 tabla_codec_calibrate_hs_polling(codec);
5184
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005185 if (priv->mbhc_cfg.gpio)
5186 msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
Joonwoo Park03324832012-03-19 19:36:16 -07005187
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005188 tabla_codec_start_hs_polling(codec);
5189
5190 pr_debug("%s: leave\n", __func__);
5191 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005192 return IRQ_HANDLED;
5193}
5194
Bradley Rubincb1e2732011-06-23 16:49:20 -07005195static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
5196{
5197 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08005198 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005199 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005200
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005201 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005202 tabla_codec_enable_config_mode(codec, 1);
5203
5204 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
5205 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005206
Joonwoo Park0976d012011-12-22 11:48:18 -08005207 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
5208
5209 usleep_range(generic->t_shutdown_plug_rem,
5210 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005211
5212 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005213 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005214 tabla_codec_enable_config_mode(codec, 0);
5215
5216 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
5217}
5218
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005219static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005220{
5221 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005222
5223 tabla_codec_shutdown_hs_removal_detect(codec);
5224
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005225 if (!tabla->mclk_enabled) {
Asish Bhattacharya486745a2012-01-20 06:41:53 +05305226 tabla_codec_disable_clock_block(codec);
5227 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005228 }
5229
5230 tabla->mbhc_polling_active = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005231 tabla->mbhc_state = MBHC_STATE_NONE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005232}
5233
Patrick Lai49efeac2011-11-03 11:01:12 -07005234static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
5235{
5236 struct tabla_priv *tabla = data;
5237 struct snd_soc_codec *codec;
5238
5239 pr_info("%s: received HPHL OCP irq\n", __func__);
5240
5241 if (tabla) {
5242 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005243 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
5244 pr_info("%s: retry\n", __func__);
5245 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5246 0x00);
5247 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5248 0x10);
5249 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305250 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005251 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5252 tabla->hphlocp_cnt = 0;
5253 tabla->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005254 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005255 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005256 tabla->mbhc_cfg.headset_jack,
5257 tabla->hph_status,
5258 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005259 }
5260 } else {
5261 pr_err("%s: Bad tabla private data\n", __func__);
5262 }
5263
5264 return IRQ_HANDLED;
5265}
5266
5267static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
5268{
5269 struct tabla_priv *tabla = data;
5270 struct snd_soc_codec *codec;
5271
5272 pr_info("%s: received HPHR OCP irq\n", __func__);
5273
5274 if (tabla) {
5275 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005276 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
5277 pr_info("%s: retry\n", __func__);
5278 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5279 0x00);
5280 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5281 0x10);
5282 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305283 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005284 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5285 tabla->hphrocp_cnt = 0;
5286 tabla->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005287 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005288 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005289 tabla->mbhc_cfg.headset_jack,
5290 tabla->hph_status,
5291 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005292 }
5293 } else {
5294 pr_err("%s: Bad tabla private data\n", __func__);
5295 }
5296
5297 return IRQ_HANDLED;
5298}
5299
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005300static bool tabla_is_invalid_insertion_range(struct snd_soc_codec *codec,
5301 s32 mic_volt)
Joonwoo Park03324832012-03-19 19:36:16 -07005302{
5303 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5304 struct tabla_mbhc_plug_type_cfg *plug_type =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005305 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5306 int fake_insert_high;
5307 bool invalid = false;
Joonwoo Park03324832012-03-19 19:36:16 -07005308
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005309 if (tabla->mbhc_cfg.gpio)
5310 fake_insert_high = TABLA_MBHC_FAKE_INSERT_HIGH;
5311 else
5312 fake_insert_high = TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
5313
5314 /* Perform this check only when the high voltage headphone
5315 * needs to be considered as invalid
5316 */
5317 if (!tabla->mbhc_inval_hs_range_override
5318 && (mic_volt > plug_type->v_hs_max)) {
5319 invalid = true;
5320 } else if (mic_volt < fake_insert_high
5321 && (mic_volt > TABLA_MBHC_FAKE_INSERT_LOW)) {
5322 invalid = true;
5323 }
5324
5325 return invalid;
5326}
5327
5328static bool tabla_is_invalid_insert_delta(struct snd_soc_codec *codec,
5329 int mic_volt, int mic_volt_prev)
5330{
5331 int delta = abs(mic_volt - mic_volt_prev);
5332 if (delta > TABLA_MBHC_FAKE_INSERT_VOLT_DELTA_MV) {
5333 pr_debug("%s: volt delta %dmv\n", __func__, delta);
Joonwoo Park03324832012-03-19 19:36:16 -07005334 return true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005335 }
Joonwoo Park03324832012-03-19 19:36:16 -07005336 return false;
5337}
5338
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005339static bool tabla_codec_is_invalid_plug(struct snd_soc_codec *codec,
5340 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
5341 enum tabla_mbhc_plug_type
5342 plug_type[MBHC_NUM_DCE_PLUG_DETECT])
5343{
5344 int i;
5345 bool r = false;
5346 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5347 struct tabla_mbhc_plug_type_cfg *plug_type_ptr =
5348 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5349
5350 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
5351 if (mic_mv[i] < plug_type_ptr->v_no_mic)
5352 plug_type[i] = PLUG_TYPE_HEADPHONE;
5353 else if (mic_mv[i] < plug_type_ptr->v_hs_max)
5354 plug_type[i] = PLUG_TYPE_HEADSET;
5355 else if (mic_mv[i] > plug_type_ptr->v_hs_max)
5356 plug_type[i] = PLUG_TYPE_HIGH_HPH;
5357
5358 r = tabla_is_invalid_insertion_range(codec, mic_mv[i]);
5359 if (!r && i > 0) {
5360 if (plug_type[i-1] != plug_type[i])
5361 r = true;
5362 else
5363 r = tabla_is_invalid_insert_delta(codec,
5364 mic_mv[i],
5365 mic_mv[i - 1]);
5366 }
5367 }
5368
5369 return r;
5370}
5371
5372/* called under codec_resource_lock acquisition */
5373void tabla_find_plug_and_report(struct snd_soc_codec *codec,
5374 enum tabla_mbhc_plug_type plug_type)
Joonwoo Park03324832012-03-19 19:36:16 -07005375{
5376 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005377
5378 if (plug_type == PLUG_TYPE_HEADPHONE
5379 && tabla->current_plug == PLUG_TYPE_NONE) {
5380 /* Nothing was reported previously
5381 * reporte a headphone
5382 */
5383 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5384 tabla_codec_cleanup_hs_polling(codec);
5385 } else if (plug_type == PLUG_TYPE_HEADSET) {
5386 /* If Headphone was reported previously, this will
5387 * only report the mic line
5388 */
5389 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5390 msleep(100);
5391 tabla_codec_start_hs_polling(codec);
5392 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
5393 if (tabla->current_plug == PLUG_TYPE_NONE)
5394 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5395 tabla_codec_cleanup_hs_polling(codec);
5396 pr_debug("setup mic trigger for further detection\n");
5397 tabla->lpi_enabled = true;
5398 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5399 false);
5400 }
5401}
5402
5403/* should be called under interrupt context that hold suspend */
5404static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla)
5405{
5406 pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
5407 tabla->hs_detect_work_stop = false;
5408 wcd9xxx_lock_sleep(tabla->codec->control_data);
5409 schedule_work(&tabla->hs_correct_plug_work);
5410}
5411
5412/* called under codec_resource_lock acquisition */
5413static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla)
5414{
5415 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
5416 tabla->hs_detect_work_stop = true;
5417 wmb();
5418 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5419 if (cancel_work_sync(&tabla->hs_correct_plug_work)) {
5420 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
5421 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5422 }
5423 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5424}
5425
5426static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
5427{
5428 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
5429}
5430
5431static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
5432{
5433 return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
5434 tabla->mbhc_cfg.gpio_level_insert);
5435}
5436
5437static void tabla_hs_correct_gpio_plug(struct work_struct *work)
5438{
5439 struct tabla_priv *tabla;
5440 struct snd_soc_codec *codec;
5441 int retry = 0, i;
5442 bool correction = false;
5443 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5444 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5445 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5446 unsigned long timeout;
5447
5448 tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
5449 codec = tabla->codec;
5450
5451 pr_debug("%s: enter\n", __func__);
5452 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
5453
5454 /* Keep override on during entire plug type correction work.
5455 *
5456 * This is okay under the assumption that any GPIO irqs which use
5457 * MBHC block cancel and sync this work so override is off again
5458 * prior to GPIO interrupt handler's MBHC block usage.
5459 * Also while this correction work is running, we can guarantee
5460 * DAPM doesn't use any MBHC block as this work only runs with
5461 * headphone detection.
5462 */
5463 tabla_turn_onoff_override(codec, true);
5464
5465 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5466 while (!time_after(jiffies, timeout)) {
5467 ++retry;
5468 rmb();
5469 if (tabla->hs_detect_work_stop) {
5470 pr_debug("%s: stop requested\n", __func__);
5471 break;
5472 }
5473
5474 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
5475 if (tabla_hs_gpio_level_remove(tabla)) {
5476 pr_debug("%s: GPIO value is low\n", __func__);
5477 break;
5478 }
5479
5480 /* can race with removal interrupt */
5481 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5482 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5483 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5484 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5485 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
5486 __func__, retry, mic_mv[i], mb_v[i]);
5487 }
5488 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5489
5490 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5491 pr_debug("Invalid plug in attempt # %d\n", retry);
5492 if (retry == NUM_ATTEMPTS_TO_REPORT &&
5493 tabla->current_plug == PLUG_TYPE_NONE) {
5494 tabla_codec_report_plug(codec, 1,
5495 SND_JACK_HEADPHONE);
5496 }
5497 } else if (!tabla_codec_is_invalid_plug(codec, mic_mv,
5498 plug_type) &&
5499 plug_type[0] == PLUG_TYPE_HEADPHONE) {
5500 pr_debug("Good headphone detected, continue polling mic\n");
5501 if (tabla->current_plug == PLUG_TYPE_NONE) {
5502 tabla_codec_report_plug(codec, 1,
5503 SND_JACK_HEADPHONE);
5504 }
5505 } else {
5506 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5507 /* Turn off override */
5508 tabla_turn_onoff_override(codec, false);
5509 tabla_find_plug_and_report(codec, plug_type[0]);
5510 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5511 pr_debug("Attempt %d found correct plug %d\n", retry,
5512 plug_type[0]);
5513 correction = true;
5514 break;
5515 }
5516 }
5517
5518 /* Turn off override */
5519 if (!correction)
5520 tabla_turn_onoff_override(codec, false);
5521
5522 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
5523 pr_debug("%s: leave\n", __func__);
5524 /* unlock sleep */
5525 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5526}
5527
5528/* called under codec_resource_lock acquisition */
5529static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
5530{
5531 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005532 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5533 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005534 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5535 int i;
5536
5537 pr_debug("%s: enter\n", __func__);
5538
5539 tabla_turn_onoff_override(codec, true);
5540 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5541 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
5542 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
5543
5544 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5545 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5546 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5547 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
5548 mic_mv[i]);
5549 }
5550 tabla_turn_onoff_override(codec, false);
5551
5552 if (tabla_hs_gpio_level_remove(tabla)) {
5553 pr_debug("%s: GPIO value is low when determining plug\n",
5554 __func__);
5555 return;
5556 }
5557
5558 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5559 tabla_schedule_hs_detect_plug(tabla);
5560 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5561 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5562
5563 tabla_schedule_hs_detect_plug(tabla);
5564 } else {
5565 pr_debug("%s: Valid plug found, determine plug type\n",
5566 __func__);
5567 tabla_find_plug_and_report(codec, plug_type[0]);
5568 }
5569}
5570
5571/* called under codec_resource_lock acquisition */
5572static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
5573{
5574 int i;
5575 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5576 const struct tabla_mbhc_plug_detect_cfg *plug_det =
5577 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
5578 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5579 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5580 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
Joonwoo Park03324832012-03-19 19:36:16 -07005581 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
5582
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005583 /* Turn on the override,
5584 * tabla_codec_setup_hs_polling requires override on */
5585 tabla_turn_onoff_override(codec, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005586
5587 if (plug_det->t_ins_complete > 20)
5588 msleep(plug_det->t_ins_complete);
5589 else
5590 usleep_range(plug_det->t_ins_complete * 1000,
5591 plug_det->t_ins_complete * 1000);
5592
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005593 if (tabla->mbhc_cfg.gpio) {
5594 /* Turn off the override */
5595 tabla_turn_onoff_override(codec, false);
5596 if (tabla_hs_gpio_level_remove(tabla))
5597 pr_debug("%s: GPIO value is low when determining "
5598 "plug\n", __func__);
5599 else
5600 tabla_codec_decide_gpio_plug(codec);
5601 return;
5602 }
5603
Joonwoo Park03324832012-03-19 19:36:16 -07005604 /*
5605 * First DCE measurement,
5606 * IF this is fake, discontinue detection
5607 * and restart insertion detection
5608 */
5609 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5610 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005611 if (tabla_is_invalid_insertion_range(codec, mic_mv[0])) {
Joonwoo Park03324832012-03-19 19:36:16 -07005612 pr_debug("%s: Detect attempt 1, detected Fake\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005613 tabla_turn_onoff_override(codec, false);
5614 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005615 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5616 false);
5617 return;
5618 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005619 pr_debug("%s: DCE run 1, %x, mic_mv = %d\n", __func__, mb_v[0],
Joonwoo Park03324832012-03-19 19:36:16 -07005620 mic_mv[0]);
5621
5622 /*
5623 * Perform two more DCE measurements,
5624 * IF any of them is fake, discontinue detection
5625 * and restart insertion detection
5626 */
Joonwoo Park03324832012-03-19 19:36:16 -07005627 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005628 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005629 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005630 pr_debug("%s: DCE run %d, %x, mic_mv = %d\n", __func__, i + 1,
Joonwoo Park03324832012-03-19 19:36:16 -07005631 mb_v[1], mic_mv[i]);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005632 if (tabla_is_invalid_insertion_range(codec, mic_mv[i])
5633 || tabla_is_invalid_insert_delta(codec, mic_mv[i],
5634 mic_mv[i - 1])) {
Joonwoo Park03324832012-03-19 19:36:16 -07005635 pr_debug("%s: Detect attempt %d, detected Fake\n",
5636 __func__, i + 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005637 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005638 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
5639 0x02, 0x02);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005640 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005641 tabla_codec_enable_hs_detect(codec, 1,
5642 MBHC_USE_MB_TRIGGER,
5643 false);
5644 return;
5645 }
5646 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005647 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005648
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005649 plug_type_ptr =
5650 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07005651
5652 /*
5653 * If we are here, means none of the three
5654 * measurements are fake, continue plug type detection.
5655 * If all three measurements do not produce same
5656 * plug type, restart insertion detection
5657 */
5658 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5659 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
5660 plug_type[i] = PLUG_TYPE_HEADPHONE;
5661 pr_debug("%s: Detect attempt %d, detected Headphone\n",
5662 __func__, i);
5663 } else {
5664 plug_type[i] = PLUG_TYPE_HEADSET;
5665 pr_debug("%s: Detect attempt %d, detected Headset\n",
5666 __func__, i);
5667 }
5668
5669 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
5670 pr_err("%s: Detect attempt %d and %d are not same",
5671 __func__, i - 1, i);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005672 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005673 tabla_codec_enable_hs_detect(codec, 1,
5674 MBHC_USE_MB_TRIGGER,
5675 false);
5676 return;
5677 }
5678 }
5679
5680 if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5681 pr_debug("%s: Headphone Detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005682 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5683 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005684 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005685 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
5686 pr_debug("%s: Headset detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005687 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5688
Joonwoo Park03324832012-03-19 19:36:16 -07005689 /* avoid false button press detect */
5690 msleep(50);
Joonwoo Park03324832012-03-19 19:36:16 -07005691 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005692 }
5693}
5694
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005695/* called only from interrupt which is under codec_resource_lock acquisition */
5696static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005697{
Bradley Rubincb1e2732011-06-23 16:49:20 -07005698 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005699
5700 if (!is_removal) {
5701 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
5702
5703 rmb();
5704 if (priv->lpi_enabled)
5705 msleep(100);
5706
5707 rmb();
5708 if (!priv->lpi_enabled) {
5709 pr_debug("%s: lpi is disabled\n", __func__);
5710 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
5711 priv->mbhc_cfg.gpio_level_insert) {
5712 pr_debug("%s: Valid insertion, "
5713 "detect plug type\n", __func__);
5714 tabla_codec_decide_gpio_plug(codec);
5715 } else {
5716 pr_debug("%s: Invalid insertion, "
5717 "stop plug detection\n", __func__);
5718 }
5719 } else {
5720 pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
5721 }
5722}
5723
5724/* called only from interrupt which is under codec_resource_lock acquisition */
5725static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
5726 bool is_mb_trigger)
5727{
Joonwoo Park03324832012-03-19 19:36:16 -07005728 int ret;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005729 struct snd_soc_codec *codec = priv->codec;
5730 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005731
5732 if (is_removal) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005733 /* cancel possiblely running hs detect work */
5734 tabla_cancel_hs_detect_plug(priv);
5735
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005736 /*
5737 * If headphone is removed while playback is in progress,
5738 * it is possible that micbias will be switched to VDDIO.
5739 */
Joonwoo Park03324832012-03-19 19:36:16 -07005740 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005741 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005742 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005743 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5744 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005745 } else if (is_mb_trigger && !is_removal) {
Joonwoo Park03324832012-03-19 19:36:16 -07005746 pr_debug("%s: Waiting for Headphone left trigger\n",
5747 __func__);
5748 wcd9xxx_lock_sleep(core);
5749 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
5750 usecs_to_jiffies(1000000)) == 0) {
5751 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
5752 __func__);
5753 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005754 }
Joonwoo Park03324832012-03-19 19:36:16 -07005755 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
5756 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005757 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005758 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
5759 if (ret != 0) {
5760 pr_debug("%s: Complete plug insertion, Detecting plug "
5761 "type\n", __func__);
5762 tabla_codec_detect_plug_type(codec);
5763 wcd9xxx_unlock_sleep(core);
5764 } else {
5765 wcd9xxx_enable_irq(codec->control_data,
5766 TABLA_IRQ_MBHC_INSERTION);
5767 pr_err("%s: Error detecting plug insertion\n",
5768 __func__);
5769 }
Joonwoo Park03324832012-03-19 19:36:16 -07005770 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005771}
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08005772
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005773static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
5774{
5775 bool is_mb_trigger, is_removal;
5776 struct tabla_priv *priv = data;
5777 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005778
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005779 pr_debug("%s: enter\n", __func__);
5780 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5781 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
5782
5783 is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
5784 0x10);
5785 is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
5786 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
5787
5788 /* Turn off both HPH and MIC line schmitt triggers */
5789 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5790 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
5791 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5792
5793 if (priv->mbhc_cfg.gpio)
5794 tabla_hs_insert_irq_gpio(priv, is_removal);
5795 else
5796 tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
5797
5798 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005799 return IRQ_HANDLED;
5800}
5801
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005802static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
5803{
5804 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5805 struct tabla_mbhc_plug_type_cfg *plug_type =
5806 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5807
5808 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
5809 && (mic_mv < plug_type->v_hs_max)) ? true : false;
5810}
5811
5812/* called under codec_resource_lock acquisition
5813 * returns true if mic voltage range is back to normal insertion
5814 * returns false either if timedout or removed */
5815static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
5816{
5817 int i;
5818 bool timedout, settled = false;
5819 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5820 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5821 unsigned long retry = 0, timeout;
5822 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5823 struct tabla_mbhc_plug_type_cfg *plug_type =
5824 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5825
5826 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5827 while (!(timedout = time_after(jiffies, timeout))) {
5828 retry++;
5829 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5830 pr_debug("%s: GPIO indicates removal\n", __func__);
5831 break;
5832 }
5833
5834 if (tabla->mbhc_cfg.gpio) {
5835 if (retry > 1)
5836 msleep(250);
5837 else
5838 msleep(50);
5839 }
5840
5841 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5842 pr_debug("%s: GPIO indicates removal\n", __func__);
5843 break;
5844 }
5845
5846 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5847 mb_v[i] = tabla_codec_sta_dce(codec, 1, true);
5848 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5849 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
5850 __func__, retry, mic_mv[i], mb_v[i]);
5851 }
5852
5853 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5854 pr_debug("%s: GPIO indicates removal\n", __func__);
5855 break;
5856 }
5857
5858 if (tabla->current_plug == PLUG_TYPE_NONE) {
5859 pr_debug("%s : headset/headphone is removed\n",
5860 __func__);
5861 break;
5862 }
5863
5864 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5865 if (!is_valid_mic_voltage(codec, mic_mv[i]))
5866 break;
5867
5868 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5869 pr_debug("%s: MIC voltage settled\n", __func__);
5870 settled = true;
5871 msleep(200);
5872 break;
5873 }
5874
5875 /* only for non-GPIO remove irq */
5876 if (!tabla->mbhc_cfg.gpio) {
5877 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
5878 if (mic_mv[i] < plug_type->v_hs_max)
5879 break;
5880 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
5881 pr_debug("%s: Headset is removed\n", __func__);
5882 break;
5883 }
5884 }
5885 }
5886
5887 if (timedout)
5888 pr_debug("%s: Microphone did not settle in %d seconds\n",
5889 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
5890 return settled;
5891}
5892
5893/* called only from interrupt which is under codec_resource_lock acquisition */
5894static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
5895{
5896 struct snd_soc_codec *codec = priv->codec;
5897
5898 if (tabla_hs_remove_settle(codec))
5899 tabla_codec_start_hs_polling(codec);
5900 pr_debug("%s: remove settle done\n", __func__);
5901}
5902
5903/* called only from interrupt which is under codec_resource_lock acquisition */
5904static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005905{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005906 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005907 bool removed = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005908 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08005909 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005910 TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005911 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005912
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005913 if (priv->current_plug != PLUG_TYPE_HEADSET) {
5914 pr_debug("%s(): Headset is not inserted, ignore removal\n",
5915 __func__);
5916 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
5917 0x08, 0x08);
5918 return;
5919 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005920
Joonwoo Park0976d012011-12-22 11:48:18 -08005921 usleep_range(generic->t_shutdown_plug_rem,
5922 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005923
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005924 do {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005925 bias_value = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005926 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
5927 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
5928 if (bias_value < (short)priv->mbhc_data.v_ins_h) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005929 pr_debug("%s: checking false removal\n", __func__);
5930 msleep(500);
5931 removed = !tabla_hs_remove_settle(codec);
5932 pr_debug("%s: headset %sactually removed\n", __func__,
5933 removed ? "" : "not ");
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005934 break;
5935 }
5936 min_us -= priv->mbhc_data.t_dce;
5937 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005938
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005939 if (removed) {
5940 /* cancel possiblely running hs detect work */
5941 tabla_cancel_hs_detect_plug(priv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005942 /*
5943 * If this removal is not false, first check the micbias
5944 * switch status and switch it to LDOH if it is already
5945 * switched to VDDIO.
5946 */
Joonwoo Park03324832012-03-19 19:36:16 -07005947 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07005948
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005949 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
5950 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005951 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
5952 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005953 } else {
5954 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005955 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005956}
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005957
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005958static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
5959{
5960 struct tabla_priv *priv = data;
5961 pr_debug("%s: enter, removal interrupt\n", __func__);
5962
5963 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5964 if (priv->mbhc_cfg.gpio)
5965 tabla_hs_remove_irq_gpio(priv);
5966 else
5967 tabla_hs_remove_irq_nogpio(priv);
5968
5969 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005970 return IRQ_HANDLED;
5971}
5972
Joonwoo Park03324832012-03-19 19:36:16 -07005973void mbhc_insert_work(struct work_struct *work)
5974{
5975 struct delayed_work *dwork;
5976 struct tabla_priv *tabla;
5977 struct snd_soc_codec *codec;
5978 struct wcd9xxx *tabla_core;
5979
5980 dwork = to_delayed_work(work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005981 tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
Joonwoo Park03324832012-03-19 19:36:16 -07005982 codec = tabla->codec;
5983 tabla_core = dev_get_drvdata(codec->dev->parent);
5984
5985 pr_debug("%s:\n", __func__);
5986
5987 /* Turn off both HPH and MIC line schmitt triggers */
5988 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5989 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
5990 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5991 wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
5992 tabla_codec_detect_plug_type(codec);
5993 wcd9xxx_unlock_sleep(tabla_core);
5994}
5995
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005996static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
5997{
5998 bool insert;
5999 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6000 bool is_removed = false;
6001
6002 pr_debug("%s: enter\n", __func__);
6003
6004 tabla->in_gpio_handler = true;
6005 /* Wait here for debounce time */
6006 usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
6007 TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
6008
6009 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
6010
6011 /* cancel pending button press */
6012 if (tabla_cancel_btn_work(tabla))
6013 pr_debug("%s: button press is canceled\n", __func__);
6014
6015 insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
6016 tabla->mbhc_cfg.gpio_level_insert);
6017 if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
6018 tabla->lpi_enabled = false;
6019 wmb();
6020
6021 /* cancel detect plug */
6022 tabla_cancel_hs_detect_plug(tabla);
6023
6024 /* Disable Mic Bias pull down and HPH Switch to GND */
6025 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
6026 0x00);
6027 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
6028 tabla_codec_detect_plug_type(codec);
6029 } else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
6030 tabla->lpi_enabled = false;
6031 wmb();
6032
6033 /* cancel detect plug */
6034 tabla_cancel_hs_detect_plug(tabla);
6035
6036 if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
6037 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
6038 is_removed = true;
6039 } else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
6040 tabla_codec_pause_hs_polling(codec);
6041 tabla_codec_cleanup_hs_polling(codec);
6042 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6043 is_removed = true;
6044 }
6045
6046 if (is_removed) {
6047 /* Enable Mic Bias pull down and HPH Switch to GND */
6048 snd_soc_update_bits(codec,
6049 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6050 0x01);
6051 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6052 0x01);
6053 /* Make sure mic trigger is turned off */
6054 snd_soc_update_bits(codec,
6055 tabla->mbhc_bias_regs.ctl_reg,
6056 0x01, 0x01);
6057 snd_soc_update_bits(codec,
6058 tabla->mbhc_bias_regs.mbhc_reg,
6059 0x90, 0x00);
6060 /* Reset MBHC State Machine */
6061 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6062 0x08, 0x08);
6063 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6064 0x08, 0x00);
6065 /* Turn off override */
6066 tabla_turn_onoff_override(codec, false);
6067 }
6068 }
6069
6070 tabla->in_gpio_handler = false;
6071 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6072 pr_debug("%s: leave\n", __func__);
6073}
6074
6075static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
6076{
6077 int r = IRQ_HANDLED;
6078 struct snd_soc_codec *codec = data;
6079
6080 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
6081 pr_warn("%s: failed to hold suspend\n", __func__);
6082 r = IRQ_NONE;
6083 } else {
6084 tabla_hs_gpio_handler(codec);
6085 wcd9xxx_unlock_sleep(codec->control_data);
6086 }
6087
6088 return r;
6089}
6090
6091static void mbhc_fw_read(struct work_struct *work)
6092{
6093 struct delayed_work *dwork;
6094 struct tabla_priv *tabla;
6095 struct snd_soc_codec *codec;
6096 const struct firmware *fw;
6097 int ret = -1, retry = 0, rc;
6098
6099 dwork = to_delayed_work(work);
6100 tabla = container_of(dwork, struct tabla_priv,
6101 mbhc_firmware_dwork);
6102 codec = tabla->codec;
6103
6104 while (retry < MBHC_FW_READ_ATTEMPTS) {
6105 retry++;
6106 pr_info("%s:Attempt %d to request MBHC firmware\n",
6107 __func__, retry);
6108 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
6109 codec->dev);
6110
6111 if (ret != 0) {
6112 usleep_range(MBHC_FW_READ_TIMEOUT,
6113 MBHC_FW_READ_TIMEOUT);
6114 } else {
6115 pr_info("%s: MBHC Firmware read succesful\n", __func__);
6116 break;
6117 }
6118 }
6119
6120 if (ret != 0) {
6121 pr_err("%s: Cannot load MBHC firmware use default cal\n",
6122 __func__);
6123 } else if (tabla_mbhc_fw_validate(fw) == false) {
6124 pr_err("%s: Invalid MBHC cal data size use default cal\n",
6125 __func__);
6126 release_firmware(fw);
6127 } else {
6128 tabla->mbhc_cfg.calibration = (void *)fw->data;
6129 tabla->mbhc_fw = fw;
6130 }
6131
6132 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
6133 tabla_mbhc_init(codec);
6134 tabla_mbhc_cal(codec);
6135 tabla_mbhc_calc_thres(codec);
6136 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
6137 tabla_codec_calibrate_hs_polling(codec);
6138 if (!tabla->mbhc_cfg.gpio) {
6139 tabla->mbhc_inval_hs_range_override = false;
6140 rc = tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_MB_TRIGGER,
6141 false);
6142
6143 if (IS_ERR_VALUE(rc))
6144 pr_err("%s: Failed to setup MBHC detection\n",
6145 __func__);
6146 } else {
6147 tabla->mbhc_inval_hs_range_override = true;
6148 /* Enable Mic Bias pull down and HPH Switch to GND */
6149 snd_soc_update_bits(codec,
6150 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6151 0x01);
6152 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6153 0x01);
6154 INIT_WORK(&tabla->hs_correct_plug_work,
6155 tabla_hs_correct_gpio_plug);
6156 }
6157
6158}
6159
Joonwoo Park03324832012-03-19 19:36:16 -07006160int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006161 const struct tabla_mbhc_config *cfg)
Joonwoo Park03324832012-03-19 19:36:16 -07006162{
6163 struct tabla_priv *tabla;
6164 int rc = 0;
6165
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006166 if (!codec || !cfg->calibration) {
Joonwoo Park03324832012-03-19 19:36:16 -07006167 pr_err("Error: no codec or calibration\n");
6168 return -EINVAL;
6169 }
6170
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006171 if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
6172 if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Joonwoo Park03324832012-03-19 19:36:16 -07006173 pr_err("Error: clock rate %dHz is not yet supported\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006174 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006175 else
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006176 pr_err("Error: unsupported clock rate %d\n",
6177 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006178 return -EINVAL;
6179 }
6180
6181 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006182 tabla->mbhc_cfg = *cfg;
6183 tabla->in_gpio_handler = false;
6184 tabla->current_plug = PLUG_TYPE_NONE;
6185 tabla->lpi_enabled = false;
Joonwoo Park03324832012-03-19 19:36:16 -07006186 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
6187
6188 /* Put CFILT in fast mode by default */
6189 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
6190 0x40, TABLA_CFILT_FAST_MODE);
6191 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
6192 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
6193 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
6194 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
6195 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
6196
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006197 if (!tabla->mbhc_cfg.read_fw_bin) {
6198 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006199 tabla_mbhc_init(codec);
6200 tabla_mbhc_cal(codec);
6201 tabla_mbhc_calc_thres(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006202 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006203 tabla_codec_calibrate_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006204 if (!tabla->mbhc_cfg.gpio) {
6205 tabla->mbhc_inval_hs_range_override = false;
6206 rc = tabla_codec_enable_hs_detect(codec, 1,
6207 MBHC_USE_MB_TRIGGER,
6208 false);
6209 } else {
6210 tabla->mbhc_inval_hs_range_override = true;
6211 /* Enable Mic Bias pull down and HPH Switch to GND */
6212 snd_soc_update_bits(codec,
6213 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6214 0x01);
6215 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6216 0x01);
6217 INIT_WORK(&tabla->hs_correct_plug_work,
6218 tabla_hs_correct_gpio_plug);
6219 }
Joonwoo Park03324832012-03-19 19:36:16 -07006220 } else {
6221 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
6222 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
6223 }
6224
6225 if (!IS_ERR_VALUE(rc)) {
6226 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
6227 wcd9xxx_enable_irq(codec->control_data,
6228 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6229 wcd9xxx_enable_irq(codec->control_data,
6230 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6231 }
6232
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006233 if (!IS_ERR_VALUE(rc) && tabla->mbhc_cfg.gpio) {
6234 rc = request_threaded_irq(tabla->mbhc_cfg.gpio_irq, NULL,
6235 tabla_mechanical_plug_detect_irq,
6236 (IRQF_TRIGGER_RISING |
6237 IRQF_TRIGGER_FALLING),
6238 "tabla-gpio", codec);
6239 if (!IS_ERR_VALUE(rc)) {
6240 rc = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
6241 /* Bootup time detection */
6242 tabla_hs_gpio_handler(codec);
6243 }
6244 }
6245
Joonwoo Park03324832012-03-19 19:36:16 -07006246 return rc;
6247}
6248EXPORT_SYMBOL_GPL(tabla_hs_detect);
6249
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006250static unsigned long slimbus_value;
6251
6252static irqreturn_t tabla_slimbus_irq(int irq, void *data)
6253{
6254 struct tabla_priv *priv = data;
6255 struct snd_soc_codec *codec = priv->codec;
6256 int i, j;
6257 u8 val;
6258
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306259 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
6260 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006261 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
6262 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306263 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006264 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
6265 if (val & 0x1)
6266 pr_err_ratelimited("overflow error on port %x,"
6267 " value %x\n", i*8 + j, val);
6268 if (val & 0x2)
6269 pr_err_ratelimited("underflow error on port %x,"
6270 " value %x\n", i*8 + j, val);
6271 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306272 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006273 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
6274 }
6275
6276 return IRQ_HANDLED;
6277}
6278
Patrick Lai3043fba2011-08-01 14:15:57 -07006279
6280static int tabla_handle_pdata(struct tabla_priv *tabla)
6281{
6282 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306283 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07006284 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05306285 u8 leg_mode = pdata->amic_settings.legacy_mode;
6286 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
6287 u8 txfe_buff = pdata->amic_settings.txfe_buff;
6288 u8 flag = pdata->amic_settings.use_pdata;
6289 u8 i = 0, j = 0;
6290 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07006291
6292 if (!pdata) {
6293 rc = -ENODEV;
6294 goto done;
6295 }
6296
6297 /* Make sure settings are correct */
6298 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
6299 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
6300 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
6301 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
6302 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
6303 rc = -EINVAL;
6304 goto done;
6305 }
6306
6307 /* figure out k value */
6308 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
6309 pdata->micbias.cfilt1_mv);
6310 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
6311 pdata->micbias.cfilt2_mv);
6312 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
6313 pdata->micbias.cfilt3_mv);
6314
6315 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
6316 rc = -EINVAL;
6317 goto done;
6318 }
6319
6320 /* Set voltage level and always use LDO */
6321 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
6322 (pdata->micbias.ldoh_v << 2));
6323
6324 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
6325 (k1 << 2));
6326 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
6327 (k2 << 2));
6328 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
6329 (k3 << 2));
6330
6331 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
6332 (pdata->micbias.bias1_cfilt_sel << 5));
6333 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
6334 (pdata->micbias.bias2_cfilt_sel << 5));
6335 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
6336 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006337 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
6338 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07006339
Santosh Mardi22920282011-10-26 02:38:40 +05306340 for (i = 0; i < 6; j++, i += 2) {
6341 if (flag & (0x01 << i)) {
6342 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
6343 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
6344 val_txfe = val_txfe |
6345 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
6346 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6347 0x10, value);
6348 snd_soc_update_bits(codec,
6349 TABLA_A_TX_1_2_TEST_EN + j * 10,
6350 0x30, val_txfe);
6351 }
6352 if (flag & (0x01 << (i + 1))) {
6353 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
6354 val_txfe = (txfe_bypass &
6355 (0x01 << (i + 1))) ? 0x02 : 0x00;
6356 val_txfe |= (txfe_buff &
6357 (0x01 << (i + 1))) ? 0x01 : 0x00;
6358 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6359 0x01, value);
6360 snd_soc_update_bits(codec,
6361 TABLA_A_TX_1_2_TEST_EN + j * 10,
6362 0x03, val_txfe);
6363 }
6364 }
6365 if (flag & 0x40) {
6366 value = (leg_mode & 0x40) ? 0x10 : 0x00;
6367 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
6368 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
6369 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
6370 0x13, value);
6371 }
Patrick Lai49efeac2011-11-03 11:01:12 -07006372
6373 if (pdata->ocp.use_pdata) {
6374 /* not defined in CODEC specification */
6375 if (pdata->ocp.hph_ocp_limit == 1 ||
6376 pdata->ocp.hph_ocp_limit == 5) {
6377 rc = -EINVAL;
6378 goto done;
6379 }
6380 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
6381 0x0F, pdata->ocp.num_attempts);
6382 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
6383 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
6384 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
6385 0xE0, (pdata->ocp.hph_ocp_limit << 5));
6386 }
Joonwoo Park03324832012-03-19 19:36:16 -07006387
6388 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
6389 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
6390 if (pdata->regulator[i].min_uV == 1800000 &&
6391 pdata->regulator[i].max_uV == 1800000) {
6392 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6393 0x1C);
6394 } else if (pdata->regulator[i].min_uV == 2200000 &&
6395 pdata->regulator[i].max_uV == 2200000) {
6396 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6397 0x1E);
6398 } else {
6399 pr_err("%s: unsupported CDC_VDDA_RX voltage "
6400 "min %d, max %d\n", __func__,
6401 pdata->regulator[i].min_uV,
6402 pdata->regulator[i].max_uV);
6403 rc = -EINVAL;
6404 }
6405 break;
6406 }
6407 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006408done:
6409 return rc;
6410}
6411
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006412static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
6413
6414 /* Tabla 1.1 MICBIAS changes */
6415 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
6416 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
6417 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006418
6419 /* Tabla 1.1 HPH changes */
6420 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
6421 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
6422
6423 /* Tabla 1.1 EAR PA changes */
6424 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
6425 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
6426 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
6427
6428 /* Tabla 1.1 Lineout_5 Changes */
6429 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
6430
6431 /* Tabla 1.1 RX Changes */
6432 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
6433 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
6434 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
6435 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
6436 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
6437 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
6438 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
6439
6440 /* Tabla 1.1 RX1 and RX2 Changes */
6441 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
6442 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
6443
6444 /* Tabla 1.1 RX3 to RX7 Changes */
6445 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
6446 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
6447 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
6448 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
6449 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
6450
6451 /* Tabla 1.1 CLASSG Changes */
6452 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
6453};
6454
6455static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006456 /* Tabla 2.0 MICBIAS changes */
6457 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
6458};
6459
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006460static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
6461 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
6462};
6463
6464static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
6465 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
6466};
6467
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006468static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
6469{
6470 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306471 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006472
6473 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
6474 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
6475 tabla_1_1_reg_defaults[i].val);
6476
6477 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
6478 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
6479 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006480
6481 if (TABLA_IS_1_X(tabla_core->version)) {
6482 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
6483 i++)
6484 snd_soc_write(codec,
6485 tabla_1_x_only_reg_2_0_defaults[i].reg,
6486 tabla_1_x_only_reg_2_0_defaults[i].val);
6487 } else {
6488 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
6489 snd_soc_write(codec,
6490 tabla_2_only_reg_2_0_defaults[i].reg,
6491 tabla_2_only_reg_2_0_defaults[i].val);
6492 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006493}
6494
6495static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08006496 /* Initialize current threshold to 350MA
6497 * number of wait and run cycles to 4096
6498 */
Patrick Lai49efeac2011-11-03 11:01:12 -07006499 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08006500 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006501
Santosh Mardi32171012011-10-28 23:32:06 +05306502 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
6503
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006504 /* Initialize gain registers to use register gain */
6505 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
6506 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
6507 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
6508 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
6509 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
6510 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
6511
6512 /* Initialize mic biases to differential mode */
6513 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
6514 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
6515 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006516
6517 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
6518
6519 /* Use 16 bit sample size for TX1 to TX6 */
6520 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
6521 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
6522 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
6523 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
6524 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
6525 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
6526
6527 /* Use 16 bit sample size for TX7 to TX10 */
6528 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
6529 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
6530 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
6531 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
6532
6533 /* Use 16 bit sample size for RX */
6534 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
6535 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
6536
6537 /*enable HPF filter for TX paths */
6538 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
6539 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
6540 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
6541 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
6542 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
6543 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
6544 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
6545 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
6546 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
6547 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
6548};
6549
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006550static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
6551 /* Initialize mic biases to differential mode */
6552 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6553};
6554
6555static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
6556 /* Initialize mic biases to differential mode */
6557 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6558};
6559
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006560static void tabla_codec_init_reg(struct snd_soc_codec *codec)
6561{
6562 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306563 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006564
6565 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
6566 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
6567 tabla_codec_reg_init_val[i].mask,
6568 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006569 if (TABLA_IS_1_X(tabla_core->version)) {
6570 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
6571 snd_soc_update_bits(codec,
6572 tabla_1_x_codec_reg_init_val[i].reg,
6573 tabla_1_x_codec_reg_init_val[i].mask,
6574 tabla_1_x_codec_reg_init_val[i].val);
6575 } else {
6576 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
6577 i++)
6578 snd_soc_update_bits(codec,
6579 tabla_2_higher_codec_reg_init_val[i].reg,
6580 tabla_2_higher_codec_reg_init_val[i].mask,
6581 tabla_2_higher_codec_reg_init_val[i].val);
6582 }
6583}
6584
6585static void tabla_update_reg_address(struct tabla_priv *priv)
6586{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306587 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006588 struct tabla_reg_address *reg_addr = &priv->reg_addr;
6589
6590 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006591 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
6592 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006593 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006594 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006595 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
6596 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006597 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006598 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006599}
6600
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006601static int tabla_codec_probe(struct snd_soc_codec *codec)
6602{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306603 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006604 struct tabla_priv *tabla;
6605 struct snd_soc_dapm_context *dapm = &codec->dapm;
6606 int ret = 0;
6607 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006608 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006609
6610 codec->control_data = dev_get_drvdata(codec->dev->parent);
6611 control = codec->control_data;
6612
6613 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
6614 if (!tabla) {
6615 dev_err(codec->dev, "Failed to allocate private data\n");
6616 return -ENOMEM;
6617 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08006618 for (i = 0 ; i < NUM_DECIMATORS; i++) {
6619 tx_hpf_work[i].tabla = tabla;
6620 tx_hpf_work[i].decimator = i + 1;
6621 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
6622 tx_hpf_corner_freq_callback);
6623 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006624
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006625 /* Make sure mbhc micbias register addresses are zeroed out */
6626 memset(&tabla->mbhc_bias_regs, 0,
6627 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006628 tabla->cfilt_k_value = 0;
6629 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006630
Joonwoo Park0976d012011-12-22 11:48:18 -08006631 /* Make sure mbhc intenal calibration data is zeroed out */
6632 memset(&tabla->mbhc_data, 0,
6633 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08006634 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08006635 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
6636 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006637 snd_soc_codec_set_drvdata(codec, tabla);
6638
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07006639 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006640 tabla->bandgap_type = TABLA_BANDGAP_OFF;
6641 tabla->clock_active = false;
6642 tabla->config_mode_active = false;
6643 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08006644 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006645 tabla->no_mic_headset_override = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006646 tabla->hs_polling_irq_prepared = false;
6647 mutex_init(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006648 tabla->codec = codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006649 tabla->mbhc_state = MBHC_STATE_NONE;
Joonwoo Park03324832012-03-19 19:36:16 -07006650 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08006651 for (i = 0; i < COMPANDER_MAX; i++) {
6652 tabla->comp_enabled[i] = 0;
6653 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
6654 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006655 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306656 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08006657 tabla->aux_pga_cnt = 0;
6658 tabla->aux_l_gain = 0x1F;
6659 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006660 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05306661 tabla_update_reg_defaults(codec);
6662 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05306663 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07006664 if (IS_ERR_VALUE(ret)) {
6665 pr_err("%s: bad pdata\n", __func__);
6666 goto err_pdata;
6667 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006669 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006670 ARRAY_SIZE(tabla_snd_controls));
6671 if (TABLA_IS_1_X(control->version))
6672 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
6673 ARRAY_SIZE(tabla_1_x_snd_controls));
6674 else
6675 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
6676 ARRAY_SIZE(tabla_2_higher_snd_controls));
6677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006678 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006679 ARRAY_SIZE(tabla_dapm_widgets));
6680 if (TABLA_IS_1_X(control->version))
6681 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
6682 ARRAY_SIZE(tabla_1_x_dapm_widgets));
6683 else
6684 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
6685 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
6686
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306687 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05306688 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
6689 ARRAY_SIZE(tabla_dapm_i2s_widgets));
6690 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
6691 ARRAY_SIZE(audio_i2s_map));
6692 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006693 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07006694
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006695 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006696 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006697 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
6698 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006699 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006700 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006701 } else {
6702 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306703 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006704 goto err_pdata;
6705 }
6706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006707 snd_soc_dapm_sync(dapm);
6708
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306709 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006710 tabla_hs_insert_irq, "Headset insert detect", tabla);
6711 if (ret) {
6712 pr_err("%s: Failed to request irq %d\n", __func__,
6713 TABLA_IRQ_MBHC_INSERTION);
6714 goto err_insert_irq;
6715 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306716 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006717
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306718 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006719 tabla_hs_remove_irq, "Headset remove detect", tabla);
6720 if (ret) {
6721 pr_err("%s: Failed to request irq %d\n", __func__,
6722 TABLA_IRQ_MBHC_REMOVAL);
6723 goto err_remove_irq;
6724 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006725
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306726 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07006727 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006728 if (ret) {
6729 pr_err("%s: Failed to request irq %d\n", __func__,
6730 TABLA_IRQ_MBHC_POTENTIAL);
6731 goto err_potential_irq;
6732 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006733
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306734 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07006735 tabla_release_handler, "Button Release detect", tabla);
6736 if (ret) {
6737 pr_err("%s: Failed to request irq %d\n", __func__,
6738 TABLA_IRQ_MBHC_RELEASE);
6739 goto err_release_irq;
6740 }
6741
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306742 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006743 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
6744 if (ret) {
6745 pr_err("%s: Failed to request irq %d\n", __func__,
6746 TABLA_IRQ_SLIMBUS);
6747 goto err_slimbus_irq;
6748 }
6749
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306750 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
6751 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006752 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
6753
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306754 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07006755 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
6756 "HPH_L OCP detect", tabla);
6757 if (ret) {
6758 pr_err("%s: Failed to request irq %d\n", __func__,
6759 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6760 goto err_hphl_ocp_irq;
6761 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306762 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07006763
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306764 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07006765 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
6766 "HPH_R OCP detect", tabla);
6767 if (ret) {
6768 pr_err("%s: Failed to request irq %d\n", __func__,
6769 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6770 goto err_hphr_ocp_irq;
6771 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306772 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006773 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
6774 switch (tabla_dai[i].id) {
6775 case AIF1_PB:
6776 ch_cnt = tabla_dai[i].playback.channels_max;
6777 break;
6778 case AIF1_CAP:
6779 ch_cnt = tabla_dai[i].capture.channels_max;
6780 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08006781 case AIF2_PB:
6782 ch_cnt = tabla_dai[i].playback.channels_max;
6783 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006784 default:
6785 continue;
6786 }
6787 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
6788 ch_cnt), GFP_KERNEL);
6789 }
Patrick Lai49efeac2011-11-03 11:01:12 -07006790
Bradley Rubincb3950a2011-08-18 13:07:26 -07006791#ifdef CONFIG_DEBUG_FS
6792 debug_tabla_priv = tabla;
6793#endif
6794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006795 return ret;
6796
Patrick Lai49efeac2011-11-03 11:01:12 -07006797err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306798 wcd9xxx_free_irq(codec->control_data,
6799 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07006800err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306801 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006802err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306803 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006804err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306805 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006806err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306807 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006808err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306809 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006810err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07006811err_pdata:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006812 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006813 kfree(tabla);
6814 return ret;
6815}
6816static int tabla_codec_remove(struct snd_soc_codec *codec)
6817{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006818 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006819 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306820 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
6821 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
6822 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
6823 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
6824 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006825 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006826 tabla_codec_disable_clock_block(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006827 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006828 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08006829 if (tabla->mbhc_fw)
6830 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006831 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
6832 kfree(tabla->dai[i].ch_num);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006833 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006834 kfree(tabla);
6835 return 0;
6836}
6837static struct snd_soc_codec_driver soc_codec_dev_tabla = {
6838 .probe = tabla_codec_probe,
6839 .remove = tabla_codec_remove,
6840 .read = tabla_read,
6841 .write = tabla_write,
6842
6843 .readable_register = tabla_readable,
6844 .volatile_register = tabla_volatile,
6845
6846 .reg_cache_size = TABLA_CACHE_SIZE,
6847 .reg_cache_default = tabla_reg_defaults,
6848 .reg_word_size = 1,
6849};
Bradley Rubincb3950a2011-08-18 13:07:26 -07006850
6851#ifdef CONFIG_DEBUG_FS
6852static struct dentry *debugfs_poke;
6853
6854static int codec_debug_open(struct inode *inode, struct file *file)
6855{
6856 file->private_data = inode->i_private;
6857 return 0;
6858}
6859
6860static ssize_t codec_debug_write(struct file *filp,
6861 const char __user *ubuf, size_t cnt, loff_t *ppos)
6862{
6863 char lbuf[32];
6864 char *buf;
6865 int rc;
6866
6867 if (cnt > sizeof(lbuf) - 1)
6868 return -EINVAL;
6869
6870 rc = copy_from_user(lbuf, ubuf, cnt);
6871 if (rc)
6872 return -EFAULT;
6873
6874 lbuf[cnt] = '\0';
6875 buf = (char *)lbuf;
6876 debug_tabla_priv->no_mic_headset_override = (*strsep(&buf, " ") == '0')
6877 ? false : true;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006878 return rc;
6879}
6880
6881static const struct file_operations codec_debug_ops = {
6882 .open = codec_debug_open,
6883 .write = codec_debug_write,
6884};
6885#endif
6886
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006887#ifdef CONFIG_PM
6888static int tabla_suspend(struct device *dev)
6889{
Joonwoo Park816b8e62012-01-23 16:03:21 -08006890 dev_dbg(dev, "%s: system suspend\n", __func__);
6891 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006892}
6893
6894static int tabla_resume(struct device *dev)
6895{
Joonwoo Park03324832012-03-19 19:36:16 -07006896 struct platform_device *pdev = to_platform_device(dev);
6897 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Park816b8e62012-01-23 16:03:21 -08006898 dev_dbg(dev, "%s: system resume\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07006899 tabla->mbhc_last_resume = jiffies;
Joonwoo Park816b8e62012-01-23 16:03:21 -08006900 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006901}
6902
6903static const struct dev_pm_ops tabla_pm_ops = {
6904 .suspend = tabla_suspend,
6905 .resume = tabla_resume,
6906};
6907#endif
6908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006909static int __devinit tabla_probe(struct platform_device *pdev)
6910{
Santosh Mardie15e2302011-11-15 10:39:23 +05306911 int ret = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006912#ifdef CONFIG_DEBUG_FS
6913 debugfs_poke = debugfs_create_file("TRRS",
6914 S_IFREG | S_IRUGO, NULL, (void *) "TRRS", &codec_debug_ops);
6915
6916#endif
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306917 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05306918 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
6919 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306920 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05306921 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
6922 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
6923 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006924}
6925static int __devexit tabla_remove(struct platform_device *pdev)
6926{
6927 snd_soc_unregister_codec(&pdev->dev);
Bradley Rubincb3950a2011-08-18 13:07:26 -07006928
6929#ifdef CONFIG_DEBUG_FS
6930 debugfs_remove(debugfs_poke);
6931#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006932 return 0;
6933}
6934static struct platform_driver tabla_codec_driver = {
6935 .probe = tabla_probe,
6936 .remove = tabla_remove,
6937 .driver = {
6938 .name = "tabla_codec",
6939 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006940#ifdef CONFIG_PM
6941 .pm = &tabla_pm_ops,
6942#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006943 },
6944};
6945
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006946static struct platform_driver tabla1x_codec_driver = {
6947 .probe = tabla_probe,
6948 .remove = tabla_remove,
6949 .driver = {
6950 .name = "tabla1x_codec",
6951 .owner = THIS_MODULE,
6952#ifdef CONFIG_PM
6953 .pm = &tabla_pm_ops,
6954#endif
6955 },
6956};
6957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006958static int __init tabla_codec_init(void)
6959{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006960 int rtn = platform_driver_register(&tabla_codec_driver);
6961 if (rtn == 0) {
6962 rtn = platform_driver_register(&tabla1x_codec_driver);
6963 if (rtn != 0)
6964 platform_driver_unregister(&tabla_codec_driver);
6965 }
6966 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006967}
6968
6969static void __exit tabla_codec_exit(void)
6970{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006971 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006972 platform_driver_unregister(&tabla_codec_driver);
6973}
6974
6975module_init(tabla_codec_init);
6976module_exit(tabla_codec_exit);
6977
6978MODULE_DESCRIPTION("Tabla codec driver");
6979MODULE_VERSION("1.0");
6980MODULE_LICENSE("GPL v2");