blob: 590f1c5f392ebde99a1657f2984de9d9f3d825fd [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
Joonwoo Parkcf473b42012-03-29 19:48:16 -070092#define TABLA_MBHC_FAKE_INS_DELTA_MV 200
93#define TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV 300
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070094
95#define TABLA_HS_DETECT_PLUG_TIME_MS (5 * 1000)
96#define TABLA_HS_DETECT_PLUG_INERVAL_MS 100
97
98#define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
99
100#define TABLA_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
101#define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
104static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
105static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800106static struct snd_soc_dai_driver tabla_dai[];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800107static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108
109enum tabla_bandgap_type {
110 TABLA_BANDGAP_OFF = 0,
111 TABLA_BANDGAP_AUDIO_MODE,
112 TABLA_BANDGAP_MBHC_MODE,
113};
114
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700115struct mbhc_micbias_regs {
116 u16 cfilt_val;
117 u16 cfilt_ctl;
118 u16 mbhc_reg;
119 u16 int_rbias;
120 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -0800121 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700122};
123
Ben Romberger1f045a72011-11-04 10:14:57 -0700124/* Codec supports 2 IIR filters */
125enum {
126 IIR1 = 0,
127 IIR2,
128 IIR_MAX,
129};
130/* Codec supports 5 bands */
131enum {
132 BAND1 = 0,
133 BAND2,
134 BAND3,
135 BAND4,
136 BAND5,
137 BAND_MAX,
138};
139
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800140enum {
141 COMPANDER_1 = 0,
142 COMPANDER_2,
143 COMPANDER_MAX,
144};
145
146enum {
147 COMPANDER_FS_8KHZ = 0,
148 COMPANDER_FS_16KHZ,
149 COMPANDER_FS_32KHZ,
150 COMPANDER_FS_48KHZ,
151 COMPANDER_FS_MAX,
152};
153
Joonwoo Parka9444452011-12-08 18:48:27 -0800154/* Flags to track of PA and DAC state.
155 * PA and DAC should be tracked separately as AUXPGA loopback requires
156 * only PA to be turned on without DAC being on. */
157enum tabla_priv_ack_flags {
158 TABLA_HPHL_PA_OFF_ACK = 0,
159 TABLA_HPHR_PA_OFF_ACK,
160 TABLA_HPHL_DAC_OFF_ACK,
161 TABLA_HPHR_DAC_OFF_ACK
162};
163
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800164
165struct comp_sample_dependent_params {
166 u32 peak_det_timeout;
167 u32 rms_meter_div_fact;
168 u32 rms_meter_resamp_fact;
169};
170
Joonwoo Park0976d012011-12-22 11:48:18 -0800171/* Data used by MBHC */
172struct mbhc_internal_cal_data {
173 u16 dce_z;
174 u16 dce_mb;
175 u16 sta_z;
176 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800177 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800178 u32 t_dce;
179 u32 t_sta;
180 u32 micb_mv;
181 u16 v_ins_hu;
182 u16 v_ins_h;
183 u16 v_b1_hu;
184 u16 v_b1_h;
185 u16 v_b1_huc;
186 u16 v_brh;
187 u16 v_brl;
188 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800189 u8 npoll;
190 u8 nbounce_wait;
Joonwoo Parkcf473b42012-03-29 19:48:16 -0700191 s16 adj_v_hs_max;
192 u16 adj_v_ins_hu;
193 u16 adj_v_ins_h;
194 s16 v_inval_ins_low;
195 s16 v_inval_ins_high;
Joonwoo Park0976d012011-12-22 11:48:18 -0800196};
197
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800198struct tabla_reg_address {
199 u16 micb_4_ctl;
200 u16 micb_4_int_rbias;
201 u16 micb_4_mbhc;
202};
203
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700204enum tabla_mbhc_plug_type {
205 PLUG_TYPE_NONE = 0,
206 PLUG_TYPE_HEADSET,
207 PLUG_TYPE_HEADPHONE,
208 PLUG_TYPE_HIGH_HPH,
209};
210
211enum tabla_mbhc_state {
212 MBHC_STATE_NONE = -1,
213 MBHC_STATE_POTENTIAL,
214 MBHC_STATE_POTENTIAL_RECOVERY,
215 MBHC_STATE_RELEASE,
216};
217
Kiran Kandid8cf5212012-03-02 15:34:53 -0800218struct hpf_work {
219 struct tabla_priv *tabla;
220 u32 decimator;
221 u8 tx_hpf_cut_of_freq;
222 struct delayed_work dwork;
223};
224
225static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
226
Bradley Rubin229c6a52011-07-12 16:18:48 -0700227struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800229 struct tabla_reg_address reg_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700231 u32 cfilt1_cnt;
232 u32 cfilt2_cnt;
233 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700234 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700236 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 bool clock_active;
238 bool config_mode_active;
239 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800240 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700241 int buttons_pressed;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700242 enum tabla_mbhc_state mbhc_state;
243 struct tabla_mbhc_config mbhc_cfg;
Joonwoo Park0976d012011-12-22 11:48:18 -0800244 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530246 struct wcd9xxx_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700247 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700248
249 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700250 /* Delayed work to report long button press */
Joonwoo Park03324832012-03-19 19:36:16 -0700251 struct delayed_work mbhc_btn_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700252
253 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700254 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700255
Joonwoo Parka9444452011-12-08 18:48:27 -0800256 /* track PA/DAC state */
257 unsigned long hph_pa_dac_state;
258
Santosh Mardie15e2302011-11-15 10:39:23 +0530259 /*track tabla interface type*/
260 u8 intf_type;
261
Patrick Lai49efeac2011-11-03 11:01:12 -0700262 u32 hph_status; /* track headhpone status */
263 /* define separate work for left and right headphone OCP to avoid
264 * additional checking on which OCP event to report so no locking
265 * to ensure synchronization is required
266 */
267 struct work_struct hphlocp_work; /* reporting left hph ocp off */
268 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800269
Patrick Laic7cae882011-11-18 11:52:49 -0800270 u8 hphlocp_cnt; /* headphone left ocp retry */
271 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800272
Patrick Lai64b43262011-12-06 17:29:15 -0800273 /* Work to perform MBHC Firmware Read */
274 struct delayed_work mbhc_firmware_dwork;
275 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800276
277 /* num of slim ports required */
278 struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800279
280 /*compander*/
281 int comp_enabled[COMPANDER_MAX];
282 u32 comp_fs[COMPANDER_MAX];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800283
284 /* Maintain the status of AUX PGA */
285 int aux_pga_cnt;
286 u8 aux_l_gain;
287 u8 aux_r_gain;
Joonwoo Park03324832012-03-19 19:36:16 -0700288
Joonwoo Park03324832012-03-19 19:36:16 -0700289 struct delayed_work mbhc_insert_dwork;
290 unsigned long mbhc_last_resume; /* in jiffies */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700291
292 u8 current_plug;
293 struct work_struct hs_correct_plug_work;
294 bool hs_detect_work_stop;
295 bool hs_polling_irq_prepared;
296 bool lpi_enabled; /* low power insertion detection */
297 bool in_gpio_handler;
298 /* Currently, only used for mbhc purpose, to protect
299 * concurrent execution of mbhc threaded irq handlers and
300 * kill race between DAPM and MBHC.But can serve as a
301 * general lock to protect codec resource
302 */
303 struct mutex codec_resource_lock;
304
305 /* Used to override the rule "invalid headset
306 * when microphone voltage is too high"
307 */
308 bool mbhc_inval_hs_range_override;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309
Bradley Rubincb3950a2011-08-18 13:07:26 -0700310#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700311 struct dentry *debugfs_poke;
312 struct dentry *debugfs_mbhc;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700313#endif
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700314};
315
Bradley Rubincb3950a2011-08-18 13:07:26 -0700316
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800317static const u32 comp_shift[] = {
318 0,
319 2,
320};
321
322static const int comp_rx_path[] = {
323 COMPANDER_1,
324 COMPANDER_1,
325 COMPANDER_2,
326 COMPANDER_2,
327 COMPANDER_2,
328 COMPANDER_2,
329 COMPANDER_MAX,
330};
331
332static const struct comp_sample_dependent_params comp_samp_params[] = {
333 {
334 .peak_det_timeout = 0x2,
335 .rms_meter_div_fact = 0x8 << 4,
336 .rms_meter_resamp_fact = 0x21,
337 },
338 {
339 .peak_det_timeout = 0x3,
340 .rms_meter_div_fact = 0x9 << 4,
341 .rms_meter_resamp_fact = 0x28,
342 },
343
344 {
345 .peak_det_timeout = 0x5,
346 .rms_meter_div_fact = 0xB << 4,
347 .rms_meter_resamp_fact = 0x28,
348 },
349
350 {
351 .peak_det_timeout = 0x5,
352 .rms_meter_div_fact = 0xB << 4,
353 .rms_meter_resamp_fact = 0x28,
354 },
355};
356
Kuirong Wange9c8a222012-03-28 16:24:09 -0700357static unsigned short rx_digital_gain_reg[] = {
358 TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
359 TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
360 TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
361 TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
362 TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
363 TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
364 TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
365};
366
367
368static unsigned short tx_digital_gain_reg[] = {
369 TABLA_A_CDC_TX1_VOL_CTL_GAIN,
370 TABLA_A_CDC_TX2_VOL_CTL_GAIN,
371 TABLA_A_CDC_TX3_VOL_CTL_GAIN,
372 TABLA_A_CDC_TX4_VOL_CTL_GAIN,
373 TABLA_A_CDC_TX5_VOL_CTL_GAIN,
374 TABLA_A_CDC_TX6_VOL_CTL_GAIN,
375 TABLA_A_CDC_TX7_VOL_CTL_GAIN,
376 TABLA_A_CDC_TX8_VOL_CTL_GAIN,
377 TABLA_A_CDC_TX9_VOL_CTL_GAIN,
378 TABLA_A_CDC_TX10_VOL_CTL_GAIN,
379};
380
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
382 struct snd_kcontrol *kcontrol, int event)
383{
384 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
386 pr_debug("%s %d\n", __func__, event);
387 switch (event) {
388 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
390 0x01);
391 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
392 usleep_range(200, 200);
393 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
394 break;
395 case SND_SOC_DAPM_PRE_PMD:
396 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
397 0x10);
398 usleep_range(20, 20);
399 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
400 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
401 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
402 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
403 0x00);
404 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 break;
406 }
407 return 0;
408}
409
Bradley Rubina7096d02011-08-03 18:29:02 -0700410static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
411 struct snd_ctl_elem_value *ucontrol)
412{
413 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
414 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
415 ucontrol->value.integer.value[0] = tabla->anc_slot;
416 return 0;
417}
418
419static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
420 struct snd_ctl_elem_value *ucontrol)
421{
422 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
423 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
424 tabla->anc_slot = ucontrol->value.integer.value[0];
425 return 0;
426}
427
Kiran Kandid2d86b52011-09-09 17:44:28 -0700428static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
429 struct snd_ctl_elem_value *ucontrol)
430{
431 u8 ear_pa_gain;
432 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
433
434 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
435
436 ear_pa_gain = ear_pa_gain >> 5;
437
438 if (ear_pa_gain == 0x00) {
439 ucontrol->value.integer.value[0] = 0;
440 } else if (ear_pa_gain == 0x04) {
441 ucontrol->value.integer.value[0] = 1;
442 } else {
443 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
444 __func__, ear_pa_gain);
445 return -EINVAL;
446 }
447
448 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
449
450 return 0;
451}
452
453static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
454 struct snd_ctl_elem_value *ucontrol)
455{
456 u8 ear_pa_gain;
457 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
458
459 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
460 ucontrol->value.integer.value[0]);
461
462 switch (ucontrol->value.integer.value[0]) {
463 case 0:
464 ear_pa_gain = 0x00;
465 break;
466 case 1:
467 ear_pa_gain = 0x80;
468 break;
469 default:
470 return -EINVAL;
471 }
472
473 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
474 return 0;
475}
476
Ben Romberger1f045a72011-11-04 10:14:57 -0700477static int tabla_get_iir_enable_audio_mixer(
478 struct snd_kcontrol *kcontrol,
479 struct snd_ctl_elem_value *ucontrol)
480{
481 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
482 int iir_idx = ((struct soc_multi_mixer_control *)
483 kcontrol->private_value)->reg;
484 int band_idx = ((struct soc_multi_mixer_control *)
485 kcontrol->private_value)->shift;
486
487 ucontrol->value.integer.value[0] =
488 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
489 (1 << band_idx);
490
491 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
492 iir_idx, band_idx,
493 (uint32_t)ucontrol->value.integer.value[0]);
494 return 0;
495}
496
497static int tabla_put_iir_enable_audio_mixer(
498 struct snd_kcontrol *kcontrol,
499 struct snd_ctl_elem_value *ucontrol)
500{
501 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
502 int iir_idx = ((struct soc_multi_mixer_control *)
503 kcontrol->private_value)->reg;
504 int band_idx = ((struct soc_multi_mixer_control *)
505 kcontrol->private_value)->shift;
506 int value = ucontrol->value.integer.value[0];
507
508 /* Mask first 5 bits, 6-8 are reserved */
509 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
510 (1 << band_idx), (value << band_idx));
511
512 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
513 iir_idx, band_idx, value);
514 return 0;
515}
516static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
517 int iir_idx, int band_idx,
518 int coeff_idx)
519{
520 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800521 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700522 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800523 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700524
525 /* Mask bits top 2 bits since they are reserved */
526 return ((snd_soc_read(codec,
527 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
528 (snd_soc_read(codec,
529 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
530 (snd_soc_read(codec,
531 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
532 (snd_soc_read(codec,
533 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
534 0x3FFFFFFF;
535}
536
537static int tabla_get_iir_band_audio_mixer(
538 struct snd_kcontrol *kcontrol,
539 struct snd_ctl_elem_value *ucontrol)
540{
541 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
542 int iir_idx = ((struct soc_multi_mixer_control *)
543 kcontrol->private_value)->reg;
544 int band_idx = ((struct soc_multi_mixer_control *)
545 kcontrol->private_value)->shift;
546
547 ucontrol->value.integer.value[0] =
548 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
549 ucontrol->value.integer.value[1] =
550 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
551 ucontrol->value.integer.value[2] =
552 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
553 ucontrol->value.integer.value[3] =
554 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
555 ucontrol->value.integer.value[4] =
556 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
557
558 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
559 "%s: IIR #%d band #%d b1 = 0x%x\n"
560 "%s: IIR #%d band #%d b2 = 0x%x\n"
561 "%s: IIR #%d band #%d a1 = 0x%x\n"
562 "%s: IIR #%d band #%d a2 = 0x%x\n",
563 __func__, iir_idx, band_idx,
564 (uint32_t)ucontrol->value.integer.value[0],
565 __func__, iir_idx, band_idx,
566 (uint32_t)ucontrol->value.integer.value[1],
567 __func__, iir_idx, band_idx,
568 (uint32_t)ucontrol->value.integer.value[2],
569 __func__, iir_idx, band_idx,
570 (uint32_t)ucontrol->value.integer.value[3],
571 __func__, iir_idx, band_idx,
572 (uint32_t)ucontrol->value.integer.value[4]);
573 return 0;
574}
575
576static void set_iir_band_coeff(struct snd_soc_codec *codec,
577 int iir_idx, int band_idx,
578 int coeff_idx, uint32_t value)
579{
580 /* Mask top 3 bits, 6-8 are reserved */
581 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800582 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700583 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800584 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700585
586 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800587 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700588 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800589 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700590
591 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800592 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700593 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800594 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700595
Ben Romberger0915aae2012-02-06 23:32:43 -0800596 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700597 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800598 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700599
Ben Romberger0915aae2012-02-06 23:32:43 -0800600 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700601 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800602 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700603}
604
605static int tabla_put_iir_band_audio_mixer(
606 struct snd_kcontrol *kcontrol,
607 struct snd_ctl_elem_value *ucontrol)
608{
609 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
610 int iir_idx = ((struct soc_multi_mixer_control *)
611 kcontrol->private_value)->reg;
612 int band_idx = ((struct soc_multi_mixer_control *)
613 kcontrol->private_value)->shift;
614
615 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
616 ucontrol->value.integer.value[0]);
617 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
618 ucontrol->value.integer.value[1]);
619 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
620 ucontrol->value.integer.value[2]);
621 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
622 ucontrol->value.integer.value[3]);
623 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
624 ucontrol->value.integer.value[4]);
625
626 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
627 "%s: IIR #%d band #%d b1 = 0x%x\n"
628 "%s: IIR #%d band #%d b2 = 0x%x\n"
629 "%s: IIR #%d band #%d a1 = 0x%x\n"
630 "%s: IIR #%d band #%d a2 = 0x%x\n",
631 __func__, iir_idx, band_idx,
632 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
633 __func__, iir_idx, band_idx,
634 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
635 __func__, iir_idx, band_idx,
636 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
637 __func__, iir_idx, band_idx,
638 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
639 __func__, iir_idx, band_idx,
640 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
641 return 0;
642}
643
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800644static int tabla_compander_gain_offset(
645 struct snd_soc_codec *codec, u32 enable,
646 unsigned int reg, int mask, int event)
647{
648 int pa_mode = snd_soc_read(codec, reg) & mask;
649 int gain_offset = 0;
650 /* if PMU && enable is 1-> offset is 3
651 * if PMU && enable is 0-> offset is 0
652 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
653 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
654 */
655
656 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
657 gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
658 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
659 gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
660 return gain_offset;
661}
662
663
664static int tabla_config_gain_compander(
665 struct snd_soc_codec *codec,
666 u32 compander, u32 enable, int event)
667{
668 int value = 0;
669 int mask = 1 << 4;
670 int gain = 0;
671 int gain_offset;
672 if (compander >= COMPANDER_MAX) {
673 pr_err("%s: Error, invalid compander channel\n", __func__);
674 return -EINVAL;
675 }
676
677 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
678 value = 1 << 4;
679
680 if (compander == COMPANDER_1) {
681 gain_offset = tabla_compander_gain_offset(codec, enable,
682 TABLA_A_RX_HPH_L_GAIN, mask, event);
683 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
684 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
685 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
686 0xFF, gain - gain_offset);
687 gain_offset = tabla_compander_gain_offset(codec, enable,
688 TABLA_A_RX_HPH_R_GAIN, mask, event);
689 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
690 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
691 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
692 0xFF, gain - gain_offset);
693 } else if (compander == COMPANDER_2) {
694 gain_offset = tabla_compander_gain_offset(codec, enable,
695 TABLA_A_RX_LINE_1_GAIN, mask, event);
696 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
697 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
698 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
699 0xFF, gain - gain_offset);
700 gain_offset = tabla_compander_gain_offset(codec, enable,
701 TABLA_A_RX_LINE_3_GAIN, mask, event);
702 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
703 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
704 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
705 0xFF, gain - gain_offset);
706 gain_offset = tabla_compander_gain_offset(codec, enable,
707 TABLA_A_RX_LINE_2_GAIN, mask, event);
708 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
709 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
710 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
711 0xFF, gain - gain_offset);
712 gain_offset = tabla_compander_gain_offset(codec, enable,
713 TABLA_A_RX_LINE_4_GAIN, mask, event);
714 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
715 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
716 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
717 0xFF, gain - gain_offset);
718 }
719 return 0;
720}
721static int tabla_get_compander(struct snd_kcontrol *kcontrol,
722 struct snd_ctl_elem_value *ucontrol)
723{
724
725 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
726 int comp = ((struct soc_multi_mixer_control *)
727 kcontrol->private_value)->max;
728 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
729
730 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
731
732 return 0;
733}
734
735static int tabla_set_compander(struct snd_kcontrol *kcontrol,
736 struct snd_ctl_elem_value *ucontrol)
737{
738 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
739 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
740 int comp = ((struct soc_multi_mixer_control *)
741 kcontrol->private_value)->max;
742 int value = ucontrol->value.integer.value[0];
743
744 if (value == tabla->comp_enabled[comp]) {
745 pr_debug("%s: compander #%d enable %d no change\n",
746 __func__, comp, value);
747 return 0;
748 }
749 tabla->comp_enabled[comp] = value;
750 return 0;
751}
752
753
754static int tabla_config_compander(struct snd_soc_dapm_widget *w,
755 struct snd_kcontrol *kcontrol,
756 int event)
757{
758 struct snd_soc_codec *codec = w->codec;
759 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
760 u32 rate = tabla->comp_fs[w->shift];
761
762 switch (event) {
763 case SND_SOC_DAPM_PRE_PMU:
764 if (tabla->comp_enabled[w->shift] != 0) {
765 /* Enable both L/R compander clocks */
766 snd_soc_update_bits(codec,
767 TABLA_A_CDC_CLK_RX_B2_CTL,
768 0x03 << comp_shift[w->shift],
769 0x03 << comp_shift[w->shift]);
770 /* Clar the HALT for the compander*/
771 snd_soc_update_bits(codec,
772 TABLA_A_CDC_COMP1_B1_CTL +
773 w->shift * 8, 1 << 2, 0);
774 /* Toggle compander reset bits*/
775 snd_soc_update_bits(codec,
776 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
777 0x03 << comp_shift[w->shift],
778 0x03 << comp_shift[w->shift]);
779 snd_soc_update_bits(codec,
780 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
781 0x03 << comp_shift[w->shift], 0);
782 tabla_config_gain_compander(codec, w->shift, 1, event);
783 /* Update the RMS meter resampling*/
784 snd_soc_update_bits(codec,
785 TABLA_A_CDC_COMP1_B3_CTL +
786 w->shift * 8, 0xFF, 0x01);
787 /* Wait for 1ms*/
788 usleep_range(1000, 1000);
789 }
790 break;
791 case SND_SOC_DAPM_POST_PMU:
792 /* Set sample rate dependent paramater*/
793 if (tabla->comp_enabled[w->shift] != 0) {
794 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
795 w->shift * 8, 0x03, rate);
796 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
797 w->shift * 8, 0x0F,
798 comp_samp_params[rate].peak_det_timeout);
799 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
800 w->shift * 8, 0xF0,
801 comp_samp_params[rate].rms_meter_div_fact);
802 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
803 w->shift * 8, 0xFF,
804 comp_samp_params[rate].rms_meter_resamp_fact);
805 /* Compander enable -> 0x370/0x378*/
806 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
807 w->shift * 8, 0x03, 0x03);
808 }
809 break;
810 case SND_SOC_DAPM_PRE_PMD:
811 /* Halt the compander*/
812 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
813 w->shift * 8, 1 << 2, 1 << 2);
814 break;
815 case SND_SOC_DAPM_POST_PMD:
816 /* Restore the gain */
817 tabla_config_gain_compander(codec, w->shift,
818 tabla->comp_enabled[w->shift], event);
819 /* Disable the compander*/
820 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
821 w->shift * 8, 0x03, 0x00);
822 /* Turn off the clock for compander in pair*/
823 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
824 0x03 << comp_shift[w->shift], 0);
825 break;
826 }
827 return 0;
828}
829
Kiran Kandid2d86b52011-09-09 17:44:28 -0700830static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
831static const struct soc_enum tabla_ear_pa_gain_enum[] = {
832 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
833};
834
Santosh Mardi024010f2011-10-18 06:27:21 +0530835/*cut of frequency for high pass filter*/
836static const char *cf_text[] = {
837 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
838};
839
840static const struct soc_enum cf_dec1_enum =
841 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
842
843static const struct soc_enum cf_dec2_enum =
844 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
845
846static const struct soc_enum cf_dec3_enum =
847 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
848
849static const struct soc_enum cf_dec4_enum =
850 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
851
852static const struct soc_enum cf_dec5_enum =
853 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
854
855static const struct soc_enum cf_dec6_enum =
856 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
857
858static const struct soc_enum cf_dec7_enum =
859 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
860
861static const struct soc_enum cf_dec8_enum =
862 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
863
864static const struct soc_enum cf_dec9_enum =
865 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
866
867static const struct soc_enum cf_dec10_enum =
868 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
869
870static const struct soc_enum cf_rxmix1_enum =
871 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
872
873static const struct soc_enum cf_rxmix2_enum =
874 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
875
876static const struct soc_enum cf_rxmix3_enum =
877 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
878
879static const struct soc_enum cf_rxmix4_enum =
880 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
881
882static const struct soc_enum cf_rxmix5_enum =
883 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
884;
885static const struct soc_enum cf_rxmix6_enum =
886 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
887
888static const struct soc_enum cf_rxmix7_enum =
889 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700892
893 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
894 tabla_pa_gain_get, tabla_pa_gain_put),
895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
897 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700898 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
899 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
901 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700902 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
903 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700904 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
905 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
908 line_gain),
909 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
910 line_gain),
911
Bradley Rubin410383f2011-07-22 13:44:23 -0700912 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
913 -84, 40, digital_gain),
914 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
915 -84, 40, digital_gain),
916 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
917 -84, 40, digital_gain),
918 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
919 -84, 40, digital_gain),
920 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
921 -84, 40, digital_gain),
922 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
923 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -0800924 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
925 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700926
Bradley Rubin410383f2011-07-22 13:44:23 -0700927 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700929 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700931 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
932 digital_gain),
933 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
934 digital_gain),
935 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
936 digital_gain),
937 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
938 digital_gain),
939 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
940 digital_gain),
941 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
942 digital_gain),
943 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
944 digital_gain),
945 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
946 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700947 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
948 40, digital_gain),
949 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
950 40, digital_gain),
951 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
952 40, digital_gain),
953 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
954 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700955 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
956 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700957 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
958 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700959 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
960 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800962 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
963 aux_pga_gain),
964 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
965 aux_pga_gain),
966
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800968 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700969 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700970
971 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
972 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530973 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
974 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
975 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
976 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
977 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
978 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
979 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
980 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
981 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
982 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
983
984 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
985 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
986 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
987 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
988 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
989 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
990 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
991 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
992 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
993 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
994
995 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
996 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
997 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
998 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
999 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
1000 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
1001 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
1002
1003 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1004 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1005 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
1006 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
1007 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
1008 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
1009 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -07001010
1011 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1012 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1013 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1014 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1015 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1016 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1017 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1018 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1019 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1020 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1021 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1022 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1023 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1024 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1025 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1026 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1027 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1028 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1029 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1030 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1031
1032 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1033 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1034 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1035 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1036 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1037 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1038 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1039 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1040 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1041 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1042 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1043 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1044 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1045 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1046 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1047 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1048 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1049 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1050 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1051 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001052 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
1053 tabla_get_compander, tabla_set_compander),
1054 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
1055 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056};
1057
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001058static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
1059 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
1060};
1061
1062static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
1063 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
1064};
1065
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066static const char *rx_mix1_text[] = {
1067 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1068 "RX5", "RX6", "RX7"
1069};
1070
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001071static const char *rx_mix2_text[] = {
1072 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
1073};
1074
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001075static const char *rx_dsm_text[] = {
1076 "CIC_OUT", "DSM_INV"
1077};
1078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079static const char *sb_tx1_mux_text[] = {
1080 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1081 "DEC1"
1082};
1083
1084static const char *sb_tx5_mux_text[] = {
1085 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1086 "DEC5"
1087};
1088
1089static const char *sb_tx6_mux_text[] = {
1090 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1091 "DEC6"
1092};
1093
1094static const char const *sb_tx7_to_tx10_mux_text[] = {
1095 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1096 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1097 "DEC9", "DEC10"
1098};
1099
1100static const char *dec1_mux_text[] = {
1101 "ZERO", "DMIC1", "ADC6",
1102};
1103
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001104static const char *dec2_mux_text[] = {
1105 "ZERO", "DMIC2", "ADC5",
1106};
1107
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001108static const char *dec3_mux_text[] = {
1109 "ZERO", "DMIC3", "ADC4",
1110};
1111
1112static const char *dec4_mux_text[] = {
1113 "ZERO", "DMIC4", "ADC3",
1114};
1115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116static const char *dec5_mux_text[] = {
1117 "ZERO", "DMIC5", "ADC2",
1118};
1119
1120static const char *dec6_mux_text[] = {
1121 "ZERO", "DMIC6", "ADC1",
1122};
1123
1124static const char const *dec7_mux_text[] = {
1125 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1126};
1127
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001128static const char *dec8_mux_text[] = {
1129 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1130};
1131
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001132static const char *dec9_mux_text[] = {
1133 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1134};
1135
1136static const char *dec10_mux_text[] = {
1137 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1138};
1139
Bradley Rubin229c6a52011-07-12 16:18:48 -07001140static const char const *anc_mux_text[] = {
1141 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1142 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1143};
1144
1145static const char const *anc1_fb_mux_text[] = {
1146 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1147};
1148
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001149static const char *iir1_inp1_text[] = {
1150 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1151 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1152};
1153
1154static const struct soc_enum rx_mix1_inp1_chain_enum =
1155 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1156
Bradley Rubin229c6a52011-07-12 16:18:48 -07001157static const struct soc_enum rx_mix1_inp2_chain_enum =
1158 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160static const struct soc_enum rx2_mix1_inp1_chain_enum =
1161 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1162
Bradley Rubin229c6a52011-07-12 16:18:48 -07001163static const struct soc_enum rx2_mix1_inp2_chain_enum =
1164 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1165
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166static const struct soc_enum rx3_mix1_inp1_chain_enum =
1167 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1168
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001169static const struct soc_enum rx3_mix1_inp2_chain_enum =
1170 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1171
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172static const struct soc_enum rx4_mix1_inp1_chain_enum =
1173 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1174
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001175static const struct soc_enum rx4_mix1_inp2_chain_enum =
1176 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178static const struct soc_enum rx5_mix1_inp1_chain_enum =
1179 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1180
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001181static const struct soc_enum rx5_mix1_inp2_chain_enum =
1182 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1183
1184static const struct soc_enum rx6_mix1_inp1_chain_enum =
1185 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1186
1187static const struct soc_enum rx6_mix1_inp2_chain_enum =
1188 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1189
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001190static const struct soc_enum rx7_mix1_inp1_chain_enum =
1191 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1192
1193static const struct soc_enum rx7_mix1_inp2_chain_enum =
1194 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1195
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001196static const struct soc_enum rx1_mix2_inp1_chain_enum =
1197 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
1198
1199static const struct soc_enum rx1_mix2_inp2_chain_enum =
1200 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
1201
1202static const struct soc_enum rx2_mix2_inp1_chain_enum =
1203 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
1204
1205static const struct soc_enum rx2_mix2_inp2_chain_enum =
1206 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
1207
1208static const struct soc_enum rx3_mix2_inp1_chain_enum =
1209 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B3_CTL, 0, 5, rx_mix2_text);
1210
1211static const struct soc_enum rx3_mix2_inp2_chain_enum =
1212 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B3_CTL, 3, 5, rx_mix2_text);
1213
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001214static const struct soc_enum rx4_dsm_enum =
1215 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1216
1217static const struct soc_enum rx6_dsm_enum =
1218 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220static const struct soc_enum sb_tx5_mux_enum =
1221 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1222
1223static const struct soc_enum sb_tx6_mux_enum =
1224 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1225
1226static const struct soc_enum sb_tx7_mux_enum =
1227 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1228 sb_tx7_to_tx10_mux_text);
1229
1230static const struct soc_enum sb_tx8_mux_enum =
1231 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1232 sb_tx7_to_tx10_mux_text);
1233
Kiran Kandi3426e512011-09-13 22:50:10 -07001234static const struct soc_enum sb_tx9_mux_enum =
1235 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1236 sb_tx7_to_tx10_mux_text);
1237
1238static const struct soc_enum sb_tx10_mux_enum =
1239 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1240 sb_tx7_to_tx10_mux_text);
1241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001242static const struct soc_enum sb_tx1_mux_enum =
1243 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1244
1245static const struct soc_enum dec1_mux_enum =
1246 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1247
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001248static const struct soc_enum dec2_mux_enum =
1249 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1250
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001251static const struct soc_enum dec3_mux_enum =
1252 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1253
1254static const struct soc_enum dec4_mux_enum =
1255 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1256
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257static const struct soc_enum dec5_mux_enum =
1258 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1259
1260static const struct soc_enum dec6_mux_enum =
1261 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1262
1263static const struct soc_enum dec7_mux_enum =
1264 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1265
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001266static const struct soc_enum dec8_mux_enum =
1267 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1268
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001269static const struct soc_enum dec9_mux_enum =
1270 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1271
1272static const struct soc_enum dec10_mux_enum =
1273 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1274
Bradley Rubin229c6a52011-07-12 16:18:48 -07001275static const struct soc_enum anc1_mux_enum =
1276 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1277
1278static const struct soc_enum anc2_mux_enum =
1279 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1280
1281static const struct soc_enum anc1_fb_mux_enum =
1282 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284static const struct soc_enum iir1_inp1_mux_enum =
1285 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
1286
1287static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1288 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1289
Bradley Rubin229c6a52011-07-12 16:18:48 -07001290static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1291 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1292
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1294 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1295
Bradley Rubin229c6a52011-07-12 16:18:48 -07001296static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1297 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1300 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1301
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001302static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1303 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1304
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1306 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1307
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001308static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1309 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1310
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1312 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1313
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001314static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1315 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1316
1317static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1318 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1319
1320static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1321 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1322
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001323static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1324 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1325
1326static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1327 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1328
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001329static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1330 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1331
1332static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
1333 SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
1334
1335static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1336 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1337
1338static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
1339 SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
1340
1341static const struct snd_kcontrol_new rx3_mix2_inp1_mux =
1342 SOC_DAPM_ENUM("RX3 MIX2 INP1 Mux", rx3_mix2_inp1_chain_enum);
1343
1344static const struct snd_kcontrol_new rx3_mix2_inp2_mux =
1345 SOC_DAPM_ENUM("RX3 MIX2 INP2 Mux", rx3_mix2_inp2_chain_enum);
1346
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001347static const struct snd_kcontrol_new rx4_dsm_mux =
1348 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1349
1350static const struct snd_kcontrol_new rx6_dsm_mux =
1351 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353static const struct snd_kcontrol_new sb_tx5_mux =
1354 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1355
1356static const struct snd_kcontrol_new sb_tx6_mux =
1357 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1358
1359static const struct snd_kcontrol_new sb_tx7_mux =
1360 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1361
1362static const struct snd_kcontrol_new sb_tx8_mux =
1363 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1364
Kiran Kandi3426e512011-09-13 22:50:10 -07001365static const struct snd_kcontrol_new sb_tx9_mux =
1366 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1367
1368static const struct snd_kcontrol_new sb_tx10_mux =
1369 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1370
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371static const struct snd_kcontrol_new sb_tx1_mux =
1372 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1373
Kiran Kandi59a96b12012-01-16 02:20:03 -08001374static int wcd9310_put_dec_enum(struct snd_kcontrol *kcontrol,
1375 struct snd_ctl_elem_value *ucontrol)
1376{
1377 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1378 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1379 struct snd_soc_codec *codec = w->codec;
1380 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1381 unsigned int dec_mux, decimator;
1382 char *dec_name = NULL;
1383 char *widget_name = NULL;
1384 char *temp;
1385 u16 tx_mux_ctl_reg;
1386 u8 adc_dmic_sel = 0x0;
1387 int ret = 0;
1388
1389 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1390 return -EINVAL;
1391
1392 dec_mux = ucontrol->value.enumerated.item[0];
1393
1394 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1395 if (!widget_name)
1396 return -ENOMEM;
1397 temp = widget_name;
1398
1399 dec_name = strsep(&widget_name, " ");
1400 widget_name = temp;
1401 if (!dec_name) {
1402 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1403 ret = -EINVAL;
1404 goto out;
1405 }
1406
1407 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
1408 if (ret < 0) {
1409 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1410 ret = -EINVAL;
1411 goto out;
1412 }
1413
1414 dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"
1415 " dec_mux = %u\n", __func__, w->name, dec_name, decimator,
1416 dec_mux);
1417
1418
1419 switch (decimator) {
1420 case 1:
1421 case 2:
1422 case 3:
1423 case 4:
1424 case 5:
1425 case 6:
1426 if (dec_mux == 1)
1427 adc_dmic_sel = 0x1;
1428 else
1429 adc_dmic_sel = 0x0;
1430 break;
1431 case 7:
1432 case 8:
1433 case 9:
1434 case 10:
1435 if ((dec_mux == 1) || (dec_mux == 2))
1436 adc_dmic_sel = 0x1;
1437 else
1438 adc_dmic_sel = 0x0;
1439 break;
1440 default:
1441 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1442 ret = -EINVAL;
1443 goto out;
1444 }
1445
1446 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1447
1448 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1449
1450 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1451
1452out:
1453 kfree(widget_name);
1454 return ret;
1455}
1456
1457#define WCD9310_DEC_ENUM(xname, xenum) \
1458{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1459 .info = snd_soc_info_enum_double, \
1460 .get = snd_soc_dapm_get_enum_double, \
1461 .put = wcd9310_put_dec_enum, \
1462 .private_value = (unsigned long)&xenum }
1463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001464static const struct snd_kcontrol_new dec1_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001465 WCD9310_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001467static const struct snd_kcontrol_new dec2_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001468 WCD9310_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001469
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001470static const struct snd_kcontrol_new dec3_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001471 WCD9310_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001472
1473static const struct snd_kcontrol_new dec4_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001474 WCD9310_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476static const struct snd_kcontrol_new dec5_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001477 WCD9310_DEC_ENUM("DEC5 MUX Mux", dec5_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478
1479static const struct snd_kcontrol_new dec6_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001480 WCD9310_DEC_ENUM("DEC6 MUX Mux", dec6_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481
1482static const struct snd_kcontrol_new dec7_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001483 WCD9310_DEC_ENUM("DEC7 MUX Mux", dec7_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001485static const struct snd_kcontrol_new dec8_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001486 WCD9310_DEC_ENUM("DEC8 MUX Mux", dec8_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001487
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001488static const struct snd_kcontrol_new dec9_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001489 WCD9310_DEC_ENUM("DEC9 MUX Mux", dec9_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001490
1491static const struct snd_kcontrol_new dec10_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001492 WCD9310_DEC_ENUM("DEC10 MUX Mux", dec10_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001493
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494static const struct snd_kcontrol_new iir1_inp1_mux =
1495 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1496
Kiran Kandi59a96b12012-01-16 02:20:03 -08001497static const struct snd_kcontrol_new anc1_mux =
1498 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1499
Bradley Rubin229c6a52011-07-12 16:18:48 -07001500static const struct snd_kcontrol_new anc2_mux =
1501 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502
Bradley Rubin229c6a52011-07-12 16:18:48 -07001503static const struct snd_kcontrol_new anc1_fb_mux =
1504 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001505
Bradley Rubin229c6a52011-07-12 16:18:48 -07001506static const struct snd_kcontrol_new dac1_switch[] = {
1507 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1508};
1509static const struct snd_kcontrol_new hphl_switch[] = {
1510 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1511};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001512
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001513static const struct snd_kcontrol_new hphl_pa_mix[] = {
1514 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1515 7, 1, 0),
1516 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1517 7, 1, 0),
1518 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1519 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1520 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1521 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1522};
1523
1524static const struct snd_kcontrol_new hphr_pa_mix[] = {
1525 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1526 6, 1, 0),
1527 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1528 6, 1, 0),
1529 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1530 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1531 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1532 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1533};
1534
1535static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1536 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1537 5, 1, 0),
1538 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1539 5, 1, 0),
1540 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1541 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1542 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1543 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1544};
1545
1546static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1547 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1548 4, 1, 0),
1549 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1550 4, 1, 0),
1551 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1552 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1553 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1554 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1555};
1556
1557static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1558 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1559 3, 1, 0),
1560 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1561 3, 1, 0),
1562 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1563 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1564 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1565 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1566};
1567
1568static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1569 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1570 2, 1, 0),
1571 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1572 2, 1, 0),
1573 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1574 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1575 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1576 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1577};
1578
1579static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1580 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1581 1, 1, 0),
1582 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1583 1, 1, 0),
1584 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1585 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1586 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1587 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1588};
1589
1590static const struct snd_kcontrol_new ear_pa_mix[] = {
1591 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1592 0, 1, 0),
1593 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1594 0, 1, 0),
1595 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1596 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1597 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1598 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1599};
1600
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001601static const struct snd_kcontrol_new lineout3_ground_switch =
1602 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1603
1604static const struct snd_kcontrol_new lineout4_ground_switch =
1605 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001606
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001608 int enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609{
1610 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1611
1612 pr_debug("%s %d\n", __func__, enable);
1613
1614 if (enable) {
1615 tabla->adc_count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1617 } else {
1618 tabla->adc_count--;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001619 if (!tabla->adc_count)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001620 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
Joonwoo Park03324832012-03-19 19:36:16 -07001621 0x2, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 }
1623}
1624
1625static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1626 struct snd_kcontrol *kcontrol, int event)
1627{
1628 struct snd_soc_codec *codec = w->codec;
1629 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001630 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001631
1632 pr_debug("%s %d\n", __func__, event);
1633
1634 if (w->reg == TABLA_A_TX_1_2_EN)
1635 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1636 else if (w->reg == TABLA_A_TX_3_4_EN)
1637 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1638 else if (w->reg == TABLA_A_TX_5_6_EN)
1639 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1640 else {
1641 pr_err("%s: Error, invalid adc register\n", __func__);
1642 return -EINVAL;
1643 }
1644
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001645 if (w->shift == 3)
1646 init_bit_shift = 6;
1647 else if (w->shift == 7)
1648 init_bit_shift = 7;
1649 else {
1650 pr_err("%s: Error, invalid init bit postion adc register\n",
1651 __func__);
1652 return -EINVAL;
1653 }
1654
1655
1656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657 switch (event) {
1658 case SND_SOC_DAPM_PRE_PMU:
1659 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001660 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1661 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001662 break;
1663 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001664
1665 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1666
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 break;
1668 case SND_SOC_DAPM_POST_PMD:
1669 tabla_codec_enable_adc_block(codec, 0);
1670 break;
1671 }
1672 return 0;
1673}
1674
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001675static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1676{
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001677 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1678 0x80);
1679 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1680 0x04);
1681 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1682 0x01);
1683 usleep_range(1000, 1000);
1684 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1685 0x00);
1686}
1687
1688static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1689 enum tabla_bandgap_type choice)
1690{
1691 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1692
1693 /* TODO lock resources accessed by audio streams and threaded
1694 * interrupt handlers
1695 */
1696
1697 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1698 tabla->bandgap_type);
1699
1700 if (tabla->bandgap_type == choice)
1701 return;
1702
1703 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1704 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1705 tabla_codec_enable_audio_mode_bandgap(codec);
1706 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
1707 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1708 0x2);
1709 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1710 0x80);
1711 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1712 0x4);
1713 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1714 0x01);
1715 usleep_range(1000, 1000);
1716 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1717 0x00);
1718 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1719 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1720 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1721 usleep_range(100, 100);
1722 tabla_codec_enable_audio_mode_bandgap(codec);
1723 } else if (choice == TABLA_BANDGAP_OFF) {
1724 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1725 } else {
1726 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1727 }
1728 tabla->bandgap_type = choice;
1729}
1730
1731static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1732{
1733 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1734 pr_debug("%s\n", __func__);
1735 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1736 ndelay(160);
1737 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1738 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1739 tabla->clock_active = false;
1740}
1741
1742static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
1743{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001744 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001745 return 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001746 else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001747 return 1;
1748 else {
1749 BUG_ON(1);
1750 return -EINVAL;
1751 }
1752}
1753
1754static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1755{
1756 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1757
1758 if (enable) {
1759 tabla->rx_bias_count++;
1760 if (tabla->rx_bias_count == 1)
1761 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1762 0x80, 0x80);
1763 } else {
1764 tabla->rx_bias_count--;
1765 if (!tabla->rx_bias_count)
1766 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1767 0x80, 0x00);
1768 }
1769}
1770
1771static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1772 int enable)
1773{
1774 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1775
1776 pr_debug("%s: enable = %d\n", __func__, enable);
1777 if (enable) {
1778 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1779 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1780 usleep_range(5, 5);
1781 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1782 0x80);
1783 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1784 0x80);
1785 usleep_range(10, 10);
1786 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1787 usleep_range(20, 20);
1788 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1789 } else {
1790 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1791 0);
1792 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1793 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1794 }
1795 tabla->config_mode_active = enable ? true : false;
1796
1797 return 0;
1798}
1799
1800static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1801 int config_mode)
1802{
1803 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1804
1805 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
1806
1807 if (config_mode) {
1808 tabla_codec_enable_config_mode(codec, 1);
1809 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1810 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1811 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1812 usleep_range(1000, 1000);
1813 } else
1814 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1815
1816 if (!config_mode && tabla->mbhc_polling_active) {
1817 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1818 tabla_codec_enable_config_mode(codec, 0);
1819
1820 }
1821
1822 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1823 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1824 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1825 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1826 usleep_range(50, 50);
1827 tabla->clock_active = true;
1828 return 0;
1829}
1830
1831static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1832 struct snd_kcontrol *kcontrol, int event)
1833{
1834 struct snd_soc_codec *codec = w->codec;
1835 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1836
1837 pr_debug("%s: %d\n", __func__, event);
1838
1839 switch (event) {
1840 case SND_SOC_DAPM_PRE_PMU:
1841 tabla_codec_enable_bandgap(codec,
1842 TABLA_BANDGAP_AUDIO_MODE);
1843 tabla_enable_rx_bias(codec, 1);
1844
1845 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1846 0x08, 0x08);
1847 /* Enable Zero Cross detect for AUX PGA channel
1848 * and set the initial AUX PGA gain to NEG_0P0_DB
1849 * to avoid glitches.
1850 */
1851 if (w->reg == TABLA_A_AUX_L_EN) {
1852 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1853 0x20, 0x20);
1854 tabla->aux_l_gain = snd_soc_read(codec,
1855 TABLA_A_AUX_L_GAIN);
1856 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1857 } else {
1858 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1859 0x20, 0x20);
1860 tabla->aux_r_gain = snd_soc_read(codec,
1861 TABLA_A_AUX_R_GAIN);
1862 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1863 }
1864 if (tabla->aux_pga_cnt++ == 1
1865 && !tabla->mclk_enabled) {
1866 tabla_codec_enable_clock_block(codec, 1);
1867 pr_debug("AUX PGA enabled RC osc\n");
1868 }
1869 break;
1870
1871 case SND_SOC_DAPM_POST_PMU:
1872 if (w->reg == TABLA_A_AUX_L_EN)
1873 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1874 tabla->aux_l_gain);
1875 else
1876 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1877 tabla->aux_r_gain);
1878 break;
1879
1880 case SND_SOC_DAPM_PRE_PMD:
1881 /* Mute AUX PGA channel in use before disabling AUX PGA */
1882 if (w->reg == TABLA_A_AUX_L_EN) {
1883 tabla->aux_l_gain = snd_soc_read(codec,
1884 TABLA_A_AUX_L_GAIN);
1885 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1886 } else {
1887 tabla->aux_r_gain = snd_soc_read(codec,
1888 TABLA_A_AUX_R_GAIN);
1889 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1890 }
1891 break;
1892
1893 case SND_SOC_DAPM_POST_PMD:
1894 tabla_enable_rx_bias(codec, 0);
1895
1896 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1897 0x08, 0x00);
1898 if (w->reg == TABLA_A_AUX_L_EN) {
1899 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1900 tabla->aux_l_gain);
1901 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1902 0x20, 0x00);
1903 } else {
1904 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1905 tabla->aux_r_gain);
1906 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1907 0x20, 0x00);
1908 }
1909
1910 if (tabla->aux_pga_cnt-- == 0) {
1911 if (tabla->mbhc_polling_active)
1912 tabla_codec_enable_bandgap(codec,
1913 TABLA_BANDGAP_MBHC_MODE);
1914 else
1915 tabla_codec_enable_bandgap(codec,
1916 TABLA_BANDGAP_OFF);
1917
1918 if (!tabla->mclk_enabled &&
1919 !tabla->mbhc_polling_active) {
1920 tabla_codec_enable_clock_block(codec, 0);
1921 }
1922 }
1923 break;
1924 }
1925 return 0;
1926}
1927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001928static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1929 struct snd_kcontrol *kcontrol, int event)
1930{
1931 struct snd_soc_codec *codec = w->codec;
1932 u16 lineout_gain_reg;
1933
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001934 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001935
1936 switch (w->shift) {
1937 case 0:
1938 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1939 break;
1940 case 1:
1941 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1942 break;
1943 case 2:
1944 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1945 break;
1946 case 3:
1947 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1948 break;
1949 case 4:
1950 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1951 break;
1952 default:
1953 pr_err("%s: Error, incorrect lineout register value\n",
1954 __func__);
1955 return -EINVAL;
1956 }
1957
1958 switch (event) {
1959 case SND_SOC_DAPM_PRE_PMU:
1960 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1961 break;
1962 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001963 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001964 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001965 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001966 break;
1967 case SND_SOC_DAPM_POST_PMD:
1968 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1969 break;
1970 }
1971 return 0;
1972}
1973
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001974
1975static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001976 struct snd_kcontrol *kcontrol, int event)
1977{
1978 struct snd_soc_codec *codec = w->codec;
Kiran Kandi59a96b12012-01-16 02:20:03 -08001979 u16 tx_dmic_ctl_reg;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001980 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001981 unsigned int dmic;
1982 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001983
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001984 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1985 if (ret < 0) {
1986 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001987 return -EINVAL;
1988 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001989
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001990 switch (dmic) {
1991 case 1:
1992 case 2:
1993 dmic_clk_sel = 0x02;
1994 dmic_clk_en = 0x01;
1995 break;
1996
1997 case 3:
1998 case 4:
1999 dmic_clk_sel = 0x08;
2000 dmic_clk_en = 0x04;
2001 break;
2002
2003 case 5:
2004 case 6:
2005 dmic_clk_sel = 0x20;
2006 dmic_clk_en = 0x10;
2007 break;
2008
2009 default:
2010 pr_err("%s: Invalid DMIC Selection\n", __func__);
2011 return -EINVAL;
2012 }
2013
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002014 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
2015
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002016 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002017
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002018 switch (event) {
2019 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002020
2021 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
2022 dmic_clk_sel, dmic_clk_sel);
2023
2024 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
2025
2026 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
2027 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 break;
2029 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002030 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
2031 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002032 break;
2033 }
2034 return 0;
2035}
2036
Bradley Rubin229c6a52011-07-12 16:18:48 -07002037static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
2038 struct snd_kcontrol *kcontrol, int event)
2039{
2040 struct snd_soc_codec *codec = w->codec;
2041 const char *filename;
2042 const struct firmware *fw;
2043 int i;
2044 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07002045 int num_anc_slots;
2046 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002047 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07002048 u32 anc_writes_size = 0;
2049 int anc_size_remaining;
2050 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002051 u16 reg;
2052 u8 mask, val, old_val;
2053
2054 pr_debug("%s %d\n", __func__, event);
2055 switch (event) {
2056 case SND_SOC_DAPM_PRE_PMU:
2057
Bradley Rubin4283a4c2011-07-29 16:18:54 -07002058 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07002059
2060 ret = request_firmware(&fw, filename, codec->dev);
2061 if (ret != 0) {
2062 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
2063 ret);
2064 return -ENODEV;
2065 }
2066
Bradley Rubina7096d02011-08-03 18:29:02 -07002067 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07002068 dev_err(codec->dev, "Not enough data\n");
2069 release_firmware(fw);
2070 return -ENOMEM;
2071 }
2072
2073 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07002074 anc_head = (struct anc_header *)(fw->data);
2075 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
2076 anc_size_remaining = fw->size - sizeof(struct anc_header);
2077 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002078
Bradley Rubina7096d02011-08-03 18:29:02 -07002079 if (tabla->anc_slot >= num_anc_slots) {
2080 dev_err(codec->dev, "Invalid ANC slot selected\n");
2081 release_firmware(fw);
2082 return -EINVAL;
2083 }
2084
2085 for (i = 0; i < num_anc_slots; i++) {
2086
2087 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
2088 dev_err(codec->dev, "Invalid register format\n");
2089 release_firmware(fw);
2090 return -EINVAL;
2091 }
2092 anc_writes_size = (u32)(*anc_ptr);
2093 anc_size_remaining -= sizeof(u32);
2094 anc_ptr += 1;
2095
2096 if (anc_writes_size * TABLA_PACKED_REG_SIZE
2097 > anc_size_remaining) {
2098 dev_err(codec->dev, "Invalid register format\n");
2099 release_firmware(fw);
2100 return -ENOMEM;
2101 }
2102
2103 if (tabla->anc_slot == i)
2104 break;
2105
2106 anc_size_remaining -= (anc_writes_size *
2107 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07002108 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07002109 }
2110 if (i == num_anc_slots) {
2111 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07002112 release_firmware(fw);
2113 return -ENOMEM;
2114 }
2115
Bradley Rubina7096d02011-08-03 18:29:02 -07002116 for (i = 0; i < anc_writes_size; i++) {
2117 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07002118 mask, val);
2119 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07002120 snd_soc_write(codec, reg, (old_val & ~mask) |
2121 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07002122 }
2123 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002124
2125 break;
2126 case SND_SOC_DAPM_POST_PMD:
2127 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
2128 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
2129 break;
2130 }
2131 return 0;
2132}
2133
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002134/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002135static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
2136{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002137 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07002138 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
2139 int mbhc_state = tabla->mbhc_state;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002140
Joonwoo Park03324832012-03-19 19:36:16 -07002141 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002142 if (!tabla->mbhc_polling_active) {
2143 pr_debug("Polling is not active, do not start polling\n");
2144 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002145 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002146 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Joonwoo Park03324832012-03-19 19:36:16 -07002147
2148 if (!tabla->no_mic_headset_override) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002149 if (mbhc_state == MBHC_STATE_POTENTIAL) {
2150 pr_debug("%s recovering MBHC state macine\n", __func__);
2151 tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
Joonwoo Park03324832012-03-19 19:36:16 -07002152 /* set to max button press threshold */
2153 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2154 0x7F);
2155 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2156 0xFF);
2157 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2158 (TABLA_IS_1_X(tabla_core->version) ?
2159 0x07 : 0x7F));
2160 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2161 0xFF);
2162 /* set to max */
2163 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2164 0x7F);
2165 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2166 0xFF);
2167 }
2168 }
2169
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002170 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
2171 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2172 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
Joonwoo Park03324832012-03-19 19:36:16 -07002173 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002174}
2175
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002176/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002177static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
2178{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002179 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2180
Joonwoo Park03324832012-03-19 19:36:16 -07002181 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002182 if (!tabla->mbhc_polling_active) {
2183 pr_debug("polling not active, nothing to pause\n");
2184 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002185 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002186
2187 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Joonwoo Park03324832012-03-19 19:36:16 -07002188 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002189}
2190
Joonwoo Park03324832012-03-19 19:36:16 -07002191static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002192{
2193 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2194 u8 reg_mode_val, cur_mode_val;
2195 bool mbhc_was_polling = false;
2196
2197 if (mode)
2198 reg_mode_val = TABLA_CFILT_FAST_MODE;
2199 else
2200 reg_mode_val = TABLA_CFILT_SLOW_MODE;
2201
2202 cur_mode_val = snd_soc_read(codec,
2203 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
2204
2205 if (cur_mode_val != reg_mode_val) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002206 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002207 if (tabla->mbhc_polling_active) {
2208 tabla_codec_pause_hs_polling(codec);
2209 mbhc_was_polling = true;
2210 }
2211 snd_soc_update_bits(codec,
2212 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
2213 if (mbhc_was_polling)
2214 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002215 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002216 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
2217 cur_mode_val, reg_mode_val);
2218 } else {
2219 pr_debug("%s: CFILT Value is already %x\n",
2220 __func__, cur_mode_val);
2221 }
2222}
2223
2224static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
2225 u8 cfilt_sel, int inc)
2226{
2227 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2228 u32 *cfilt_cnt_ptr = NULL;
2229 u16 micb_cfilt_reg;
2230
2231 switch (cfilt_sel) {
2232 case TABLA_CFILT1_SEL:
2233 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2234 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2235 break;
2236 case TABLA_CFILT2_SEL:
2237 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2238 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2239 break;
2240 case TABLA_CFILT3_SEL:
2241 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2242 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2243 break;
2244 default:
2245 return; /* should not happen */
2246 }
2247
2248 if (inc) {
2249 if (!(*cfilt_cnt_ptr)++) {
2250 /* Switch CFILT to slow mode if MBHC CFILT being used */
2251 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2252 tabla_codec_switch_cfilt_mode(codec, 0);
2253
2254 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2255 }
2256 } else {
2257 /* check if count not zero, decrement
2258 * then check if zero, go ahead disable cfilter
2259 */
2260 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2261 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2262
2263 /* Switch CFILT to fast mode if MBHC CFILT being used */
2264 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2265 tabla_codec_switch_cfilt_mode(codec, 1);
2266 }
2267 }
2268}
2269
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002270static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2271{
2272 int rc = -EINVAL;
2273 unsigned min_mv, max_mv;
2274
2275 switch (ldoh_v) {
2276 case TABLA_LDOH_1P95_V:
2277 min_mv = 160;
2278 max_mv = 1800;
2279 break;
2280 case TABLA_LDOH_2P35_V:
2281 min_mv = 200;
2282 max_mv = 2200;
2283 break;
2284 case TABLA_LDOH_2P75_V:
2285 min_mv = 240;
2286 max_mv = 2600;
2287 break;
2288 case TABLA_LDOH_2P85_V:
2289 min_mv = 250;
2290 max_mv = 2700;
2291 break;
2292 default:
2293 goto done;
2294 }
2295
2296 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2297 goto done;
2298
2299 for (rc = 4; rc <= 44; rc++) {
2300 min_mv = max_mv * (rc) / 44;
2301 if (min_mv >= cfilt_mv) {
2302 rc -= 4;
2303 break;
2304 }
2305 }
2306done:
2307 return rc;
2308}
2309
2310static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2311{
2312 u8 hph_reg_val = 0;
2313 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2314
2315 return (hph_reg_val & 0x30) ? true : false;
2316}
2317
Joonwoo Parka9444452011-12-08 18:48:27 -08002318static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2319{
2320 u8 hph_reg_val = 0;
2321 if (left)
2322 hph_reg_val = snd_soc_read(codec,
2323 TABLA_A_RX_HPH_L_DAC_CTL);
2324 else
2325 hph_reg_val = snd_soc_read(codec,
2326 TABLA_A_RX_HPH_R_DAC_CTL);
2327
2328 return (hph_reg_val & 0xC0) ? true : false;
2329}
2330
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002331static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
2332{
2333 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
2334}
2335
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002336/* called under codec_resource_lock acquisition */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002337static void tabla_codec_drive_v_to_micbias(struct snd_soc_codec *codec,
2338 int usec)
2339{
2340 int cfilt_k_val;
2341 bool set = true;
2342 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2343
2344 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2345 tabla->mbhc_micbias_switched) {
2346 pr_debug("%s: set mic V to micbias V\n", __func__);
2347 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2348 tabla_turn_onoff_override(codec, true);
2349 while (1) {
2350 cfilt_k_val = tabla_find_k_value(
2351 tabla->pdata->micbias.ldoh_v,
2352 set ? tabla->mbhc_data.micb_mv :
2353 VDDIO_MICBIAS_MV);
2354 snd_soc_update_bits(codec,
2355 tabla->mbhc_bias_regs.cfilt_val,
2356 0xFC, (cfilt_k_val << 2));
2357 if (!set)
2358 break;
2359 usleep_range(usec, usec);
2360 set = false;
2361 }
2362 tabla_turn_onoff_override(codec, false);
2363 }
2364}
2365
2366/* called under codec_resource_lock acquisition */
2367static void __tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2368 int vddio_switch, bool restartpolling,
2369 bool checkpolling)
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002370{
2371 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2372 int cfilt_k_val;
2373
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002374 if (vddio_switch && !tabla->mbhc_micbias_switched &&
2375 (!checkpolling || tabla->mbhc_polling_active)) {
2376 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002377 tabla_codec_pause_hs_polling(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002378 tabla_turn_onoff_override(codec, true);
2379 /* Adjust threshold if Mic Bias voltage changes */
2380 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002381 cfilt_k_val = tabla_find_k_value(
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002382 tabla->pdata->micbias.ldoh_v,
2383 VDDIO_MICBIAS_MV);
2384 usleep_range(10000, 10000);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002385 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002386 tabla->mbhc_bias_regs.cfilt_val,
2387 0xFC, (cfilt_k_val << 2));
2388 usleep_range(10000, 10000);
2389 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2390 tabla->mbhc_data.adj_v_ins_hu & 0xFF);
2391 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2392 (tabla->mbhc_data.adj_v_ins_hu >> 8) &
2393 0xFF);
2394 pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
2395 __func__);
2396 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002397
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002398 /* enable MIC BIAS Switch to VDDIO */
2399 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2400 0x80, 0x80);
2401 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2402 0x10, 0x00);
2403 tabla_turn_onoff_override(codec, false);
2404 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002405 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002406
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002407 tabla->mbhc_micbias_switched = true;
2408 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002409
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002410 } else if (!vddio_switch && tabla->mbhc_micbias_switched) {
2411 if ((!checkpolling || tabla->mbhc_polling_active) &&
2412 restartpolling)
2413 tabla_codec_pause_hs_polling(codec);
2414 /* Reprogram thresholds */
2415 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
2416 cfilt_k_val = tabla_find_k_value(
2417 tabla->pdata->micbias.ldoh_v,
2418 tabla->mbhc_data.micb_mv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002419 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002420 tabla->mbhc_bias_regs.cfilt_val,
2421 0xFC, (cfilt_k_val << 2));
2422 usleep_range(10000, 10000);
2423 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2424 tabla->mbhc_data.v_ins_hu & 0xFF);
2425 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2426 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
2427 pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
2428 __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002429 }
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002430
2431 /* Disable MIC BIAS Switch to VDDIO */
2432 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2433 0x80, 0x00);
2434 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2435 0x10, 0x00);
2436
2437 if ((!checkpolling || tabla->mbhc_polling_active) &&
2438 restartpolling)
2439 tabla_codec_start_hs_polling(codec);
2440
2441 tabla->mbhc_micbias_switched = false;
2442 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002443 }
2444}
2445
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002446static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2447 int vddio_switch)
2448{
2449 return __tabla_codec_switch_micbias(codec, vddio_switch, true, true);
2450}
2451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2453 struct snd_kcontrol *kcontrol, int event)
2454{
2455 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002456 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2457 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002458 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002459 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002460 char *internal1_text = "Internal1";
2461 char *internal2_text = "Internal2";
2462 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002463
2464 pr_debug("%s %d\n", __func__, event);
2465 switch (w->reg) {
2466 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002467 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002468 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002469 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002470 break;
2471 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002472 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002473 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002474 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002475 break;
2476 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002477 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002478 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002479 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002480 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002481 case TABLA_1_A_MICB_4_CTL:
2482 case TABLA_2_A_MICB_4_CTL:
2483 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002484 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002485 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002486 break;
2487 default:
2488 pr_err("%s: Error, invalid micbias register\n", __func__);
2489 return -EINVAL;
2490 }
2491
2492 switch (event) {
2493 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002494 /* Decide whether to switch the micbias for MBHC */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002495 if (w->reg == tabla->mbhc_bias_regs.ctl_reg) {
2496 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002497 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002498 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2499 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002500
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002501 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002502 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002503
2504 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002505 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002506 else if (strnstr(w->name, internal2_text, 30))
2507 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2508 else if (strnstr(w->name, internal3_text, 30))
2509 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2510
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002511 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002512 case SND_SOC_DAPM_POST_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002513
2514 usleep_range(20000, 20000);
2515
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002516 if (tabla->mbhc_polling_active &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002517 tabla->mbhc_cfg.micbias == micb_line) {
2518 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002519 tabla_codec_pause_hs_polling(codec);
2520 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002521 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002522 }
2523 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002524
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 case SND_SOC_DAPM_POST_PMD:
Joonwoo Park03324832012-03-19 19:36:16 -07002526 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg) &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002527 tabla_is_hph_pa_on(codec)) {
2528 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002529 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002530 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2531 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002532
Bradley Rubin229c6a52011-07-12 16:18:48 -07002533 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002534 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002535 else if (strnstr(w->name, internal2_text, 30))
2536 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2537 else if (strnstr(w->name, internal3_text, 30))
2538 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2539
Patrick Lai3043fba2011-08-01 14:15:57 -07002540 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541 break;
2542 }
2543
2544 return 0;
2545}
2546
Kiran Kandid8cf5212012-03-02 15:34:53 -08002547
2548static void tx_hpf_corner_freq_callback(struct work_struct *work)
2549{
2550 struct delayed_work *hpf_delayed_work;
2551 struct hpf_work *hpf_work;
2552 struct tabla_priv *tabla;
2553 struct snd_soc_codec *codec;
2554 u16 tx_mux_ctl_reg;
2555 u8 hpf_cut_of_freq;
2556
2557 hpf_delayed_work = to_delayed_work(work);
2558 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2559 tabla = hpf_work->tabla;
2560 codec = hpf_work->tabla->codec;
2561 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2562
2563 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL +
2564 (hpf_work->decimator - 1) * 8;
2565
2566 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
2567 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2568
2569 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
2570}
2571
2572#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
2573#define CF_MIN_3DB_4HZ 0x0
2574#define CF_MIN_3DB_75HZ 0x1
2575#define CF_MIN_3DB_150HZ 0x2
2576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
2578 struct snd_kcontrol *kcontrol, int event)
2579{
2580 struct snd_soc_codec *codec = w->codec;
Kiran Kandid8cf5212012-03-02 15:34:53 -08002581 unsigned int decimator;
2582 char *dec_name = NULL;
2583 char *widget_name = NULL;
2584 char *temp;
2585 int ret = 0;
2586 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2587 u8 dec_hpf_cut_of_freq;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002588 int offset;
2589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002590
2591 pr_debug("%s %d\n", __func__, event);
2592
Kiran Kandid8cf5212012-03-02 15:34:53 -08002593 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2594 if (!widget_name)
2595 return -ENOMEM;
2596 temp = widget_name;
2597
2598 dec_name = strsep(&widget_name, " ");
2599 widget_name = temp;
2600 if (!dec_name) {
2601 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2602 ret = -EINVAL;
2603 goto out;
2604 }
2605
2606 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
2607 if (ret < 0) {
2608 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2609 ret = -EINVAL;
2610 goto out;
2611 }
2612
2613 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
2614 w->name, dec_name, decimator);
2615
Kuirong Wange9c8a222012-03-28 16:24:09 -07002616 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002617 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002618 offset = 0;
2619 } else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002620 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002621 offset = 8;
2622 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002623 pr_err("%s: Error, incorrect dec\n", __func__);
2624 return -EINVAL;
2625 }
2626
Kiran Kandid8cf5212012-03-02 15:34:53 -08002627 tx_vol_ctl_reg = TABLA_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator -1);
2628 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2629
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002630 switch (event) {
2631 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002632
2633 // Enableable TX digital mute */
2634 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002636 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2637 1 << w->shift);
2638 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Kiran Kandid8cf5212012-03-02 15:34:53 -08002639
2640 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2641
2642 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
2643
2644 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2645 dec_hpf_cut_of_freq;
2646
2647 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2648
2649 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
2650 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2651 CF_MIN_3DB_150HZ << 4);
2652 }
2653
2654 /* enable HPF */
2655 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
2656
2657 break;
2658
2659 case SND_SOC_DAPM_POST_PMU:
2660
2661 /* Disable TX digital mute */
2662 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2663
2664 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2665 CF_MIN_3DB_150HZ) {
2666
2667 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2668 msecs_to_jiffies(300));
2669 }
Kuirong Wange9c8a222012-03-28 16:24:09 -07002670 /* apply the digital gain after the decimator is enabled*/
2671 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2672 snd_soc_write(codec,
2673 tx_digital_gain_reg[w->shift + offset],
2674 snd_soc_read(codec,
2675 tx_digital_gain_reg[w->shift + offset])
2676 );
2677
Kiran Kandid8cf5212012-03-02 15:34:53 -08002678 break;
2679
2680 case SND_SOC_DAPM_PRE_PMD:
2681
2682 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2683 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2684 break;
2685
2686 case SND_SOC_DAPM_POST_PMD:
2687
2688 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2689 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2690 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002692 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002693 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08002694out:
2695 kfree(widget_name);
2696 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697}
2698
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002699static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002700 struct snd_kcontrol *kcontrol, int event)
2701{
2702 struct snd_soc_codec *codec = w->codec;
2703
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002704 pr_debug("%s %d %s\n", __func__, event, w->name);
2705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002706 switch (event) {
2707 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002708 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2709 1 << w->shift, 1 << w->shift);
2710 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2711 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002712 break;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002713 case SND_SOC_DAPM_POST_PMU:
2714 /* apply the digital gain after the interpolator is enabled*/
2715 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2716 snd_soc_write(codec,
2717 rx_digital_gain_reg[w->shift],
2718 snd_soc_read(codec,
2719 rx_digital_gain_reg[w->shift])
2720 );
2721 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002722 }
2723 return 0;
2724}
2725
Bradley Rubin229c6a52011-07-12 16:18:48 -07002726static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2727 struct snd_kcontrol *kcontrol, int event)
2728{
2729 switch (event) {
2730 case SND_SOC_DAPM_POST_PMU:
2731 case SND_SOC_DAPM_POST_PMD:
2732 usleep_range(1000, 1000);
2733 break;
2734 }
2735 return 0;
2736}
2737
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002738static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2739 struct snd_kcontrol *kcontrol, int event)
2740{
2741 struct snd_soc_codec *codec = w->codec;
2742
2743 pr_debug("%s %d\n", __func__, event);
2744
2745 switch (event) {
2746 case SND_SOC_DAPM_PRE_PMU:
2747 tabla_enable_rx_bias(codec, 1);
2748 break;
2749 case SND_SOC_DAPM_POST_PMD:
2750 tabla_enable_rx_bias(codec, 0);
2751 break;
2752 }
2753 return 0;
2754}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002755static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
2756 struct snd_kcontrol *kcontrol, int event)
2757{
2758 struct snd_soc_codec *codec = w->codec;
2759
2760 pr_debug("%s %s %d\n", __func__, w->name, event);
2761
2762 switch (event) {
2763 case SND_SOC_DAPM_PRE_PMU:
2764 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2765 break;
2766 case SND_SOC_DAPM_POST_PMD:
2767 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2768 break;
2769 }
2770 return 0;
2771}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002772
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002773static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
2774 struct snd_soc_jack *jack, int status,
2775 int mask)
2776{
2777 /* XXX: wake_lock_timeout()? */
Joonwoo Park03324832012-03-19 19:36:16 -07002778 snd_soc_jack_report_no_dapm(jack, status, mask);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002779}
2780
Patrick Lai49efeac2011-11-03 11:01:12 -07002781static void hphocp_off_report(struct tabla_priv *tabla,
2782 u32 jack_status, int irq)
2783{
2784 struct snd_soc_codec *codec;
Joonwoo Park03324832012-03-19 19:36:16 -07002785 if (!tabla) {
2786 pr_err("%s: Bad tabla private data\n", __func__);
2787 return;
2788 }
Patrick Lai49efeac2011-11-03 11:01:12 -07002789
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002790 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
Joonwoo Park03324832012-03-19 19:36:16 -07002791 codec = tabla->codec;
2792 if (tabla->hph_status & jack_status) {
Patrick Lai49efeac2011-11-03 11:01:12 -07002793 tabla->hph_status &= ~jack_status;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002794 if (tabla->mbhc_cfg.headset_jack)
2795 tabla_snd_soc_jack_report(tabla,
2796 tabla->mbhc_cfg.headset_jack,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002797 tabla->hph_status,
2798 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08002799 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2800 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08002801 /* reset retry counter as PA is turned off signifying
2802 * start of new OCP detection session
2803 */
2804 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
2805 tabla->hphlocp_cnt = 0;
2806 else
2807 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302808 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07002809 }
2810}
2811
2812static void hphlocp_off_report(struct work_struct *work)
2813{
2814 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2815 hphlocp_work);
2816 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
2817}
2818
2819static void hphrocp_off_report(struct work_struct *work)
2820{
2821 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2822 hphrocp_work);
2823 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
2824}
2825
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002826static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
2827 struct snd_kcontrol *kcontrol, int event)
2828{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002829 struct snd_soc_codec *codec = w->codec;
2830 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2831 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002832 pr_debug("%s: event = %d\n", __func__, event);
2833
2834 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002835 case SND_SOC_DAPM_PRE_PMU:
2836 mbhc_micb_ctl_val = snd_soc_read(codec,
2837 tabla->mbhc_bias_regs.ctl_reg);
2838
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002839 if (!(mbhc_micb_ctl_val & 0x80)) {
2840 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002841 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002842 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2843 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002844 break;
2845
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002846 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07002847 /* schedule work is required because at the time HPH PA DAPM
2848 * event callback is called by DAPM framework, CODEC dapm mutex
2849 * would have been locked while snd_soc_jack_report also
2850 * attempts to acquire same lock.
2851 */
Joonwoo Parka9444452011-12-08 18:48:27 -08002852 if (w->shift == 5) {
2853 clear_bit(TABLA_HPHL_PA_OFF_ACK,
2854 &tabla->hph_pa_dac_state);
2855 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
2856 &tabla->hph_pa_dac_state);
2857 if (tabla->hph_status & SND_JACK_OC_HPHL)
2858 schedule_work(&tabla->hphlocp_work);
2859 } else if (w->shift == 4) {
2860 clear_bit(TABLA_HPHR_PA_OFF_ACK,
2861 &tabla->hph_pa_dac_state);
2862 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
2863 &tabla->hph_pa_dac_state);
2864 if (tabla->hph_status & SND_JACK_OC_HPHR)
2865 schedule_work(&tabla->hphrocp_work);
2866 }
2867
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002868 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park03324832012-03-19 19:36:16 -07002869 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002870 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002871
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002872 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
2873 w->name);
2874 usleep_range(10000, 10000);
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002875 break;
2876 }
2877 return 0;
2878}
2879
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002880static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002881 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002882{
2883 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002884 unsigned int cfilt;
2885
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002886 switch (tabla->mbhc_cfg.micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002887 case TABLA_MICBIAS1:
2888 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
2889 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
2890 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
2891 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
2892 break;
2893 case TABLA_MICBIAS2:
2894 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
2895 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
2896 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
2897 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
2898 break;
2899 case TABLA_MICBIAS3:
2900 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
2901 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
2902 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
2903 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
2904 break;
2905 case TABLA_MICBIAS4:
2906 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002907 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
2908 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
2909 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002910 break;
2911 default:
2912 /* Should never reach here */
2913 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07002914 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002915 }
2916
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002917 micbias_regs->cfilt_sel = cfilt;
2918
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002919 switch (cfilt) {
2920 case TABLA_CFILT1_SEL:
2921 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
2922 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002923 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002924 break;
2925 case TABLA_CFILT2_SEL:
2926 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
2927 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002928 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002929 break;
2930 case TABLA_CFILT3_SEL:
2931 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
2932 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002933 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002934 break;
2935 }
2936}
Santosh Mardie15e2302011-11-15 10:39:23 +05302937static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
2938 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
2939 4, 0, NULL, 0),
2940 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
2941 0, NULL, 0),
2942};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002943
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002944static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
2945 struct snd_kcontrol *kcontrol, int event)
2946{
2947 struct snd_soc_codec *codec = w->codec;
2948
2949 pr_debug("%s %s %d\n", __func__, w->name, event);
2950
2951 switch (event) {
2952 case SND_SOC_DAPM_PRE_PMU:
2953 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2954 break;
2955
2956 case SND_SOC_DAPM_POST_PMD:
2957 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2958 break;
2959 }
2960 return 0;
2961}
2962
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002963static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
2964 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302965 0, tabla_codec_enable_micbias,
2966 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2967 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002968};
2969
2970static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
2971 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302972 0, tabla_codec_enable_micbias,
2973 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2974 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002975};
2976
Santosh Mardie15e2302011-11-15 10:39:23 +05302977static const struct snd_soc_dapm_route audio_i2s_map[] = {
2978 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2979 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2980 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2981 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2982 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2983
2984 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2985 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2986 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2987 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2988};
2989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002990static const struct snd_soc_dapm_route audio_map[] = {
2991 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002992
2993 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2994 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2995
2996 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2997 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2998
2999 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
3000 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
3001
3002 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
3003 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07003004 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003005 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
3006 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003007 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
3008 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07003009 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
3010 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003011 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
3012 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003013
3014 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003015 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
3016 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
3017 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07003018 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003019 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
3020 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
3021
Kiran Kandi3426e512011-09-13 22:50:10 -07003022 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
3023 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
3024 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
3025 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
3026 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
3027 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
3028 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
3029 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
3030 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
3031 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
3032 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
3033
3034 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
3035 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
3036 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
3037 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
3038 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
3039 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
3040 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
3041 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
3042 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
3043 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
3044 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
3045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003046 /* Earpiece (RX MIX1) */
3047 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003048 {"EAR PA", NULL, "EAR_PA_MIXER"},
3049 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003050 {"DAC1", NULL, "CP"},
3051
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003052 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
3053 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003054 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003055
3056 /* Headset (RX MIX1 and RX MIX2) */
3057 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003058 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003059
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003060 {"HPHL", NULL, "HPHL_PA_MIXER"},
3061 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
3062
3063 {"HPHR", NULL, "HPHR_PA_MIXER"},
3064 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003065
3066 {"HPHL DAC", NULL, "CP"},
3067 {"HPHR DAC", NULL, "CP"},
3068
3069 {"ANC", NULL, "ANC1 MUX"},
3070 {"ANC", NULL, "ANC2 MUX"},
3071 {"ANC1 MUX", "ADC1", "ADC1"},
3072 {"ANC1 MUX", "ADC2", "ADC2"},
3073 {"ANC1 MUX", "ADC3", "ADC3"},
3074 {"ANC1 MUX", "ADC4", "ADC4"},
3075 {"ANC2 MUX", "ADC1", "ADC1"},
3076 {"ANC2 MUX", "ADC2", "ADC2"},
3077 {"ANC2 MUX", "ADC3", "ADC3"},
3078 {"ANC2 MUX", "ADC4", "ADC4"},
3079
Bradley Rubine1d08622011-07-20 18:01:35 -07003080 {"ANC", NULL, "CDC_CONN"},
3081
Bradley Rubin229c6a52011-07-12 16:18:48 -07003082 {"DAC1", "Switch", "RX1 CHAIN"},
3083 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003084 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003085
Kiran Kandidb0a4b02011-08-23 09:32:09 -07003086 {"LINEOUT1", NULL, "LINEOUT1 PA"},
3087 {"LINEOUT2", NULL, "LINEOUT2 PA"},
3088 {"LINEOUT3", NULL, "LINEOUT3 PA"},
3089 {"LINEOUT4", NULL, "LINEOUT4 PA"},
3090 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003091
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003092 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
3093 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
3094 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
3095 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
3096 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
3097 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
3098 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
3099 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
3100 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
3101 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003102
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003103 {"LINEOUT1 DAC", NULL, "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003104 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
3105
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003106 {"RX1 CHAIN", NULL, "RX1 MIX2"},
3107 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003108 {"RX1 CHAIN", NULL, "ANC"},
3109 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003110
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003111 {"CP", NULL, "RX_BIAS"},
3112 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
3113 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
3114 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
3115 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003116 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003117
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003118 {"RX1 MIX1", NULL, "COMP1_CLK"},
3119 {"RX2 MIX1", NULL, "COMP1_CLK"},
3120 {"RX3 MIX1", NULL, "COMP2_CLK"},
3121 {"RX5 MIX1", NULL, "COMP2_CLK"},
3122
3123
Bradley Rubin229c6a52011-07-12 16:18:48 -07003124 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
3125 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
3126 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
3127 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003128 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
3129 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
3130 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
3131 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
3132 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
3133 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
3134 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
3135 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003136 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
3137 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003138 {"RX1 MIX2", NULL, "RX1 MIX1"},
3139 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
3140 {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
3141 {"RX2 MIX2", NULL, "RX2 MIX1"},
3142 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
3143 {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
3144 {"RX3 MIX2", NULL, "RX3 MIX1"},
3145 {"RX3 MIX2", NULL, "RX3 MIX2 INP1"},
3146 {"RX3 MIX2", NULL, "RX3 MIX2 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003147
Bradley Rubin229c6a52011-07-12 16:18:48 -07003148 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
3149 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303150 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
3151 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003152 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
3153 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003154 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
3155 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
3156 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303157 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
3158 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003159 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
3160 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003161 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
3162 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
3163 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303164 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
3165 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003166 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
3167 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003168 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003169 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
3170 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303171 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
3172 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003173 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
3174 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003175 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003176 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
3177 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303178 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
3179 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003180 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
3181 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003182 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003183 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
3184 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303185 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
3186 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003187 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
3188 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003189 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003190 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
3191 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303192 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
3193 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003194 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
3195 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003196 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003197 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
3198 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303199 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
3200 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003201 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
3202 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003203 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003204 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
3205 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303206 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
3207 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003208 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
3209 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003210 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003211 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
3212 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303213 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
3214 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003215 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
3216 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003217 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003218 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
3219 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303220 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
3221 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003222 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
3223 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003224 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003225 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
3226 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303227 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
3228 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003229 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
3230 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003231 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003232 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
3233 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303234 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
3235 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003236 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
3237 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003238 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003239 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
3240 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303241 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
3242 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003243 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
3244 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003245 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003246 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
3247 {"RX1 MIX2 INP2", "IIR1", "IIR1"},
3248 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
3249 {"RX2 MIX2 INP2", "IIR1", "IIR1"},
3250 {"RX3 MIX2 INP1", "IIR1", "IIR1"},
3251 {"RX3 MIX2 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003252
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003253 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003254 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003255 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003256 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003257 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003258 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003259 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003260 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003261 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003262 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003263 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003264 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003265 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003266 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003267 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003268 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003269 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003270 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003271 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003272 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003273 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003274 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003275 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003276 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003277 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003278 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003279 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003280 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003281
3282 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003283 {"ADC1", NULL, "AMIC1"},
3284 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003285 {"ADC3", NULL, "AMIC3"},
3286 {"ADC4", NULL, "AMIC4"},
3287 {"ADC5", NULL, "AMIC5"},
3288 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003290 /* AUX PGA Connections */
3291 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3292 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3293 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3294 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3295 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3296 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3297 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3298 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3299 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3300 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3301 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3302 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3303 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3304 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3305 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3306 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3307 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3308 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3309 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3310 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3311 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3312 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3313 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3314 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3315 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3316 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3317 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3318 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3319 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3320 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3321 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3322 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3323 {"AUX_PGA_Left", NULL, "AMIC5"},
3324 {"AUX_PGA_Right", NULL, "AMIC6"},
3325
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003326 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003327 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
3328 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
3329 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
3330 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
3331 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003332 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003333 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
3334 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
3335 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
3336 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003337
3338 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
3339 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
3340 {"MIC BIAS1 External", NULL, "LDO_H"},
3341 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
3342 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
3343 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
3344 {"MIC BIAS2 External", NULL, "LDO_H"},
3345 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
3346 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
3347 {"MIC BIAS3 External", NULL, "LDO_H"},
3348 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003349};
3350
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003351static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
3352
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003353 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003354 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3355
3356 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
3357
3358 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003359 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003360 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
3361
3362 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3363 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3364
3365 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3366 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
3367 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
3368};
3369
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003370
3371static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
3372
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003373 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX2"},
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003374 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3375
3376 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
3377
3378 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
3379
3380 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3381 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3382
3383 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3384};
3385
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003386static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
3387{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003388 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303389 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003390
3391 if (TABLA_IS_1_X(tabla_core->version)) {
3392 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
3393 if (tabla_1_reg_readable[i] == reg)
3394 return 1;
3395 }
3396 } else {
3397 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
3398 if (tabla_2_reg_readable[i] == reg)
3399 return 1;
3400 }
3401 }
3402
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003403 return tabla_reg_readable[reg];
3404}
Kuirong Wange9c8a222012-03-28 16:24:09 -07003405static bool tabla_is_digital_gain_register(unsigned int reg)
3406{
3407 bool rtn = false;
3408 switch (reg) {
3409 case TABLA_A_CDC_RX1_VOL_CTL_B2_CTL:
3410 case TABLA_A_CDC_RX2_VOL_CTL_B2_CTL:
3411 case TABLA_A_CDC_RX3_VOL_CTL_B2_CTL:
3412 case TABLA_A_CDC_RX4_VOL_CTL_B2_CTL:
3413 case TABLA_A_CDC_RX5_VOL_CTL_B2_CTL:
3414 case TABLA_A_CDC_RX6_VOL_CTL_B2_CTL:
3415 case TABLA_A_CDC_RX7_VOL_CTL_B2_CTL:
3416 case TABLA_A_CDC_TX1_VOL_CTL_GAIN:
3417 case TABLA_A_CDC_TX2_VOL_CTL_GAIN:
3418 case TABLA_A_CDC_TX3_VOL_CTL_GAIN:
3419 case TABLA_A_CDC_TX4_VOL_CTL_GAIN:
3420 case TABLA_A_CDC_TX5_VOL_CTL_GAIN:
3421 case TABLA_A_CDC_TX6_VOL_CTL_GAIN:
3422 case TABLA_A_CDC_TX7_VOL_CTL_GAIN:
3423 case TABLA_A_CDC_TX8_VOL_CTL_GAIN:
3424 case TABLA_A_CDC_TX9_VOL_CTL_GAIN:
3425 case TABLA_A_CDC_TX10_VOL_CTL_GAIN:
3426 rtn = true;
3427 break;
3428 default:
3429 break;
3430 }
3431 return rtn;
3432}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003433static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3434{
3435 /* Registers lower than 0x100 are top level registers which can be
3436 * written by the Tabla core driver.
3437 */
3438
3439 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3440 return 1;
3441
Ben Romberger1f045a72011-11-04 10:14:57 -07003442 /* IIR Coeff registers are not cacheable */
3443 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
3444 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
3445 return 1;
3446
Kuirong Wange9c8a222012-03-28 16:24:09 -07003447 /* Digital gain register is not cacheable so we have to write
3448 * the setting even it is the same
3449 */
3450 if (tabla_is_digital_gain_register(reg))
3451 return 1;
3452
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003453 return 0;
3454}
3455
3456#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3457static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
3458 unsigned int value)
3459{
3460 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003461 BUG_ON(reg > TABLA_MAX_REGISTER);
3462
3463 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003464 ret = snd_soc_cache_write(codec, reg, value);
3465 if (ret != 0)
3466 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3467 reg, ret);
3468 }
3469
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303470 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471}
3472static unsigned int tabla_read(struct snd_soc_codec *codec,
3473 unsigned int reg)
3474{
3475 unsigned int val;
3476 int ret;
3477
3478 BUG_ON(reg > TABLA_MAX_REGISTER);
3479
3480 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
3481 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003482 ret = snd_soc_cache_read(codec, reg, &val);
3483 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003484 return val;
3485 } else
3486 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3487 reg, ret);
3488 }
3489
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303490 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003491 return val;
3492}
3493
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003494static s16 tabla_get_current_v_ins(struct tabla_priv *tabla, bool hu)
3495{
3496 s16 v_ins;
3497 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3498 tabla->mbhc_micbias_switched)
3499 v_ins = hu ? (s16)tabla->mbhc_data.adj_v_ins_hu :
3500 (s16)tabla->mbhc_data.adj_v_ins_h;
3501 else
3502 v_ins = hu ? (s16)tabla->mbhc_data.v_ins_hu :
3503 (s16)tabla->mbhc_data.v_ins_h;
3504 return v_ins;
3505}
3506
3507static s16 tabla_get_current_v_hs_max(struct tabla_priv *tabla)
3508{
3509 s16 v_hs_max;
3510 struct tabla_mbhc_plug_type_cfg *plug_type;
3511
3512 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
3513 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3514 tabla->mbhc_micbias_switched)
3515 v_hs_max = tabla->mbhc_data.adj_v_hs_max;
3516 else
3517 v_hs_max = plug_type->v_hs_max;
3518 return v_hs_max;
3519}
3520
Bradley Rubincb1e2732011-06-23 16:49:20 -07003521static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3522{
Joonwoo Parkc0672392012-01-11 11:03:14 -08003523 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08003524 struct tabla_mbhc_btn_detect_cfg *btn_det;
3525 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003526 const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
3527
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003528 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003529
Joonwoo Park0976d012011-12-22 11:48:18 -08003530 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003531 v_ins_hu & 0xFF);
Joonwoo Park0976d012011-12-22 11:48:18 -08003532 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003533 (v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003534
Joonwoo Park0976d012011-12-22 11:48:18 -08003535 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
3536 tabla->mbhc_data.v_b1_hu & 0xFF);
3537 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
3538 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
3539
3540 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
3541 tabla->mbhc_data.v_b1_h & 0xFF);
3542 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
3543 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
3544
3545 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
3546 tabla->mbhc_data.v_brh & 0xFF);
3547 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
3548 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
3549
3550 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
3551 tabla->mbhc_data.v_brl & 0xFF);
3552 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
3553 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
3554
Joonwoo Parkc0672392012-01-11 11:03:14 -08003555 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003556 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08003557 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003558 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
3559 tabla->mbhc_data.npoll);
3560 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
3561 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08003562 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003563 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
3564 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003565}
3566
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003567static int tabla_startup(struct snd_pcm_substream *substream,
3568 struct snd_soc_dai *dai)
3569{
Kuirong Wanga545e722012-02-06 19:12:54 -08003570 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003571 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3572 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003573 if ((tabla_core != NULL) &&
3574 (tabla_core->dev != NULL) &&
3575 (tabla_core->dev->parent != NULL))
3576 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003577
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003578 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003579}
3580
3581static void tabla_shutdown(struct snd_pcm_substream *substream,
3582 struct snd_soc_dai *dai)
3583{
Kuirong Wanga545e722012-02-06 19:12:54 -08003584 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003585 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3586 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003587 if ((tabla_core != NULL) &&
3588 (tabla_core->dev != NULL) &&
3589 (tabla_core->dev->parent != NULL)) {
3590 pm_runtime_mark_last_busy(tabla_core->dev->parent);
3591 pm_runtime_put(tabla_core->dev->parent);
3592 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003593}
3594
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003595int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003596{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003597 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3598
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003599 pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
3600 dapm);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003601 if (dapm)
3602 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003603 if (mclk_enable) {
3604 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003605
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003606 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07003607 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003608 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003609 TABLA_BANDGAP_AUDIO_MODE);
3610 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003611 tabla_codec_calibrate_hs_polling(codec);
3612 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303613 } else {
3614 tabla_codec_enable_bandgap(codec,
3615 TABLA_BANDGAP_AUDIO_MODE);
3616 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003617 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003618 } else {
3619
3620 if (!tabla->mclk_enabled) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003621 if (dapm)
3622 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003623 pr_err("Error, MCLK already diabled\n");
3624 return -EINVAL;
3625 }
3626 tabla->mclk_enabled = false;
3627
3628 if (tabla->mbhc_polling_active) {
3629 if (!tabla->mclk_enabled) {
3630 tabla_codec_pause_hs_polling(codec);
3631 tabla_codec_enable_bandgap(codec,
3632 TABLA_BANDGAP_MBHC_MODE);
3633 tabla_enable_rx_bias(codec, 1);
3634 tabla_codec_enable_clock_block(codec, 1);
3635 tabla_codec_calibrate_hs_polling(codec);
3636 tabla_codec_start_hs_polling(codec);
3637 }
3638 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
3639 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303640 } else {
3641 tabla_codec_disable_clock_block(codec);
3642 tabla_codec_enable_bandgap(codec,
3643 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003644 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003645 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003646 if (dapm)
3647 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003648 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003649}
3650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003651static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
3652 int clk_id, unsigned int freq, int dir)
3653{
3654 pr_debug("%s\n", __func__);
3655 return 0;
3656}
3657
3658static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3659{
Santosh Mardie15e2302011-11-15 10:39:23 +05303660 u8 val = 0;
3661 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003663 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05303664 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3665 case SND_SOC_DAIFMT_CBS_CFS:
3666 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303667 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003668 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303669 snd_soc_update_bits(dai->codec,
3670 TABLA_A_CDC_CLK_TX_I2S_CTL,
3671 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003672 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303673 snd_soc_update_bits(dai->codec,
3674 TABLA_A_CDC_CLK_RX_I2S_CTL,
3675 TABLA_I2S_MASTER_MODE_MASK, 0);
3676 }
3677 break;
3678 case SND_SOC_DAIFMT_CBM_CFM:
3679 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303680 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303681 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003682 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303683 snd_soc_update_bits(dai->codec,
3684 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003685 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303686 snd_soc_update_bits(dai->codec,
3687 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
3688 }
3689 break;
3690 default:
3691 return -EINVAL;
3692 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003693 return 0;
3694}
3695
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003696static int tabla_set_channel_map(struct snd_soc_dai *dai,
3697 unsigned int tx_num, unsigned int *tx_slot,
3698 unsigned int rx_num, unsigned int *rx_slot)
3699
3700{
3701 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3702 u32 i = 0;
3703 if (!tx_slot && !rx_slot) {
3704 pr_err("%s: Invalid\n", __func__);
3705 return -EINVAL;
3706 }
3707 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3708
Neema Shettyd3a89262012-02-16 10:23:50 -08003709 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003710 for (i = 0; i < rx_num; i++) {
3711 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
3712 tabla->dai[dai->id - 1].ch_act = 0;
3713 tabla->dai[dai->id - 1].ch_tot = rx_num;
3714 }
3715 } else if (dai->id == AIF1_CAP) {
3716 for (i = 0; i < tx_num; i++) {
3717 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
3718 tabla->dai[dai->id - 1].ch_act = 0;
3719 tabla->dai[dai->id - 1].ch_tot = tx_num;
3720 }
3721 }
3722 return 0;
3723}
3724
3725static int tabla_get_channel_map(struct snd_soc_dai *dai,
3726 unsigned int *tx_num, unsigned int *tx_slot,
3727 unsigned int *rx_num, unsigned int *rx_slot)
3728
3729{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303730 struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003731
3732 u32 cnt = 0;
3733 u32 tx_ch[SLIM_MAX_TX_PORTS];
3734 u32 rx_ch[SLIM_MAX_RX_PORTS];
3735
3736 if (!rx_slot && !tx_slot) {
3737 pr_err("%s: Invalid\n", __func__);
3738 return -EINVAL;
3739 }
3740 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
3741 /* for virtual port, codec driver needs to do
3742 * housekeeping, for now should be ok
3743 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303744 wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003745 if (dai->id == AIF1_PB) {
3746 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3747 while (cnt < *rx_num) {
3748 rx_slot[cnt] = rx_ch[cnt];
3749 cnt++;
3750 }
3751 } else if (dai->id == AIF1_CAP) {
3752 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3753 while (cnt < *tx_num) {
3754 tx_slot[cnt] = tx_ch[6 + cnt];
3755 cnt++;
3756 }
Neema Shettyd3a89262012-02-16 10:23:50 -08003757 } else if (dai->id == AIF2_PB) {
3758 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3759 while (cnt < *rx_num) {
3760 rx_slot[cnt] = rx_ch[5 + cnt];
3761 cnt++;
3762 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003763 }
3764 return 0;
3765}
3766
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003767static int tabla_hw_params(struct snd_pcm_substream *substream,
3768 struct snd_pcm_hw_params *params,
3769 struct snd_soc_dai *dai)
3770{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003771 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05303772 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07003773 u8 path, shift;
3774 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003775 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003776 u32 compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003777
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003778 pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
3779 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003780
3781 switch (params_rate(params)) {
3782 case 8000:
3783 tx_fs_rate = 0x00;
3784 rx_fs_rate = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003785 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003786 break;
3787 case 16000:
3788 tx_fs_rate = 0x01;
3789 rx_fs_rate = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003790 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003791 break;
3792 case 32000:
3793 tx_fs_rate = 0x02;
3794 rx_fs_rate = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003795 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003796 break;
3797 case 48000:
3798 tx_fs_rate = 0x03;
3799 rx_fs_rate = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003800 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003801 break;
3802 default:
3803 pr_err("%s: Invalid sampling rate %d\n", __func__,
3804 params_rate(params));
3805 return -EINVAL;
3806 }
3807
3808
3809 /**
3810 * If current dai is a tx dai, set sample rate to
3811 * all the txfe paths that are currently not active
3812 */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003813 if (dai->id == AIF1_CAP) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003814
3815 tx_state = snd_soc_read(codec,
3816 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3817
3818 for (path = 1, shift = 0;
3819 path <= NUM_DECIMATORS; path++, shift++) {
3820
3821 if (path == BITS_PER_REG + 1) {
3822 shift = 0;
3823 tx_state = snd_soc_read(codec,
3824 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
3825 }
3826
3827 if (!(tx_state & (1 << shift))) {
3828 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
3829 + (BITS_PER_REG*(path-1));
3830 snd_soc_update_bits(codec, tx_fs_reg,
3831 0x03, tx_fs_rate);
3832 }
3833 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303834 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303835 switch (params_format(params)) {
3836 case SNDRV_PCM_FORMAT_S16_LE:
3837 snd_soc_update_bits(codec,
3838 TABLA_A_CDC_CLK_TX_I2S_CTL,
3839 0x20, 0x20);
3840 break;
3841 case SNDRV_PCM_FORMAT_S32_LE:
3842 snd_soc_update_bits(codec,
3843 TABLA_A_CDC_CLK_TX_I2S_CTL,
3844 0x20, 0x00);
3845 break;
3846 default:
3847 pr_err("invalid format\n");
3848 break;
3849 }
3850 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
3851 0x03, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003852 } else {
3853 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303854 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003855 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003856 /**
3857 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3858 * with varying sample rates
3859 */
3860
3861 /**
3862 * If current dai is a rx dai, set sample rate to
3863 * all the rx paths that are currently not active
3864 */
Neema Shettyd3a89262012-02-16 10:23:50 -08003865 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003866
3867 rx_state = snd_soc_read(codec,
3868 TABLA_A_CDC_CLK_RX_B1_CTL);
3869
3870 for (path = 1, shift = 0;
3871 path <= NUM_INTERPOLATORS; path++, shift++) {
3872
3873 if (!(rx_state & (1 << shift))) {
3874 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
3875 + (BITS_PER_REG*(path-1));
3876 snd_soc_update_bits(codec, rx_fs_reg,
3877 0xE0, rx_fs_rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003878 if (comp_rx_path[shift] < COMPANDER_MAX)
3879 tabla->comp_fs[comp_rx_path[shift]]
3880 = compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003881 }
3882 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303883 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303884 switch (params_format(params)) {
3885 case SNDRV_PCM_FORMAT_S16_LE:
3886 snd_soc_update_bits(codec,
3887 TABLA_A_CDC_CLK_RX_I2S_CTL,
3888 0x20, 0x20);
3889 break;
3890 case SNDRV_PCM_FORMAT_S32_LE:
3891 snd_soc_update_bits(codec,
3892 TABLA_A_CDC_CLK_RX_I2S_CTL,
3893 0x20, 0x00);
3894 break;
3895 default:
3896 pr_err("invalid format\n");
3897 break;
3898 }
3899 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
3900 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003901 } else {
3902 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303903 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003904 }
3905
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003906 return 0;
3907}
3908
3909static struct snd_soc_dai_ops tabla_dai_ops = {
3910 .startup = tabla_startup,
3911 .shutdown = tabla_shutdown,
3912 .hw_params = tabla_hw_params,
3913 .set_sysclk = tabla_set_dai_sysclk,
3914 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003915 .set_channel_map = tabla_set_channel_map,
3916 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003917};
3918
3919static struct snd_soc_dai_driver tabla_dai[] = {
3920 {
3921 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003922 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003923 .playback = {
3924 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003925 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003926 .formats = TABLA_FORMATS,
3927 .rate_max = 48000,
3928 .rate_min = 8000,
3929 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003930 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003931 },
3932 .ops = &tabla_dai_ops,
3933 },
3934 {
3935 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003936 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003937 .capture = {
3938 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003939 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003940 .formats = TABLA_FORMATS,
3941 .rate_max = 48000,
3942 .rate_min = 8000,
3943 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003944 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003945 },
3946 .ops = &tabla_dai_ops,
3947 },
Neema Shettyd3a89262012-02-16 10:23:50 -08003948 {
3949 .name = "tabla_rx2",
3950 .id = AIF2_PB,
3951 .playback = {
3952 .stream_name = "AIF2 Playback",
3953 .rates = WCD9310_RATES,
3954 .formats = TABLA_FORMATS,
3955 .rate_min = 8000,
3956 .rate_max = 48000,
3957 .channels_min = 1,
3958 .channels_max = 2,
3959 },
3960 .ops = &tabla_dai_ops,
3961 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003962};
Santosh Mardie15e2302011-11-15 10:39:23 +05303963
3964static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3965 {
3966 .name = "tabla_i2s_rx1",
3967 .id = 1,
3968 .playback = {
3969 .stream_name = "AIF1 Playback",
3970 .rates = WCD9310_RATES,
3971 .formats = TABLA_FORMATS,
3972 .rate_max = 48000,
3973 .rate_min = 8000,
3974 .channels_min = 1,
3975 .channels_max = 4,
3976 },
3977 .ops = &tabla_dai_ops,
3978 },
3979 {
3980 .name = "tabla_i2s_tx1",
3981 .id = 2,
3982 .capture = {
3983 .stream_name = "AIF1 Capture",
3984 .rates = WCD9310_RATES,
3985 .formats = TABLA_FORMATS,
3986 .rate_max = 48000,
3987 .rate_min = 8000,
3988 .channels_min = 1,
3989 .channels_max = 4,
3990 },
3991 .ops = &tabla_dai_ops,
3992 },
3993};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003994
3995static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3996 struct snd_kcontrol *kcontrol, int event)
3997{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303998 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003999 struct snd_soc_codec *codec = w->codec;
4000 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
4001 u32 j = 0;
4002 u32 ret = 0;
4003 codec->control_data = dev_get_drvdata(codec->dev->parent);
4004 tabla = codec->control_data;
4005 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304006 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004007 return 0;
4008 switch (event) {
4009 case SND_SOC_DAPM_POST_PMU:
4010 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
4011 if (tabla_dai[j].id == AIF1_CAP)
4012 continue;
4013 if (!strncmp(w->sname,
4014 tabla_dai[j].playback.stream_name, 13)) {
4015 ++tabla_p->dai[j].ch_act;
4016 break;
4017 }
4018 }
4019 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304020 ret = wcd9xxx_cfg_slim_sch_rx(tabla,
4021 tabla_p->dai[j].ch_num,
4022 tabla_p->dai[j].ch_tot,
4023 tabla_p->dai[j].rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004024 break;
4025 case SND_SOC_DAPM_POST_PMD:
4026 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
4027 if (tabla_dai[j].id == AIF1_CAP)
4028 continue;
4029 if (!strncmp(w->sname,
4030 tabla_dai[j].playback.stream_name, 13)) {
4031 --tabla_p->dai[j].ch_act;
4032 break;
4033 }
4034 }
4035 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304036 ret = wcd9xxx_close_slim_sch_rx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004037 tabla_p->dai[j].ch_num,
4038 tabla_p->dai[j].ch_tot);
Bharath Ramachandramurthyda6fa7a2012-03-30 14:35:32 -07004039 usleep_range(5000, 5000);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004040 tabla_p->dai[j].rate = 0;
4041 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304042 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004043 tabla_p->dai[j].ch_tot = 0;
4044 }
4045 }
4046 return ret;
4047}
4048
4049static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
4050 struct snd_kcontrol *kcontrol, int event)
4051{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304052 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004053 struct snd_soc_codec *codec = w->codec;
4054 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
4055 /* index to the DAI ID, for now hardcoding */
4056 u32 j = 0;
4057 u32 ret = 0;
4058
4059 codec->control_data = dev_get_drvdata(codec->dev->parent);
4060 tabla = codec->control_data;
4061
4062 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304063 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004064 return 0;
4065 switch (event) {
4066 case SND_SOC_DAPM_POST_PMU:
4067 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08004068 if (tabla_dai[j].id == AIF1_PB ||
4069 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004070 continue;
4071 if (!strncmp(w->sname,
4072 tabla_dai[j].capture.stream_name, 13)) {
4073 ++tabla_p->dai[j].ch_act;
4074 break;
4075 }
4076 }
4077 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304078 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004079 tabla_p->dai[j].ch_num,
4080 tabla_p->dai[j].ch_tot,
4081 tabla_p->dai[j].rate);
4082 break;
4083 case SND_SOC_DAPM_POST_PMD:
4084 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08004085 if (tabla_dai[j].id == AIF1_PB ||
4086 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004087 continue;
4088 if (!strncmp(w->sname,
4089 tabla_dai[j].capture.stream_name, 13)) {
4090 --tabla_p->dai[j].ch_act;
4091 break;
4092 }
4093 }
4094 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304095 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004096 tabla_p->dai[j].ch_num,
4097 tabla_p->dai[j].ch_tot);
4098 tabla_p->dai[j].rate = 0;
4099 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304100 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004101 tabla_p->dai[j].ch_tot = 0;
4102 }
4103 }
4104 return ret;
4105}
4106
4107/* Todo: Have seperate dapm widgets for I2S and Slimbus.
4108 * Might Need to have callbacks registered only for slimbus
4109 */
4110static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
4111 /*RX stuff */
4112 SND_SOC_DAPM_OUTPUT("EAR"),
4113
4114 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
4115
4116 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
4117 ARRAY_SIZE(dac1_switch)),
4118
4119 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
4120 0, tabla_codec_enable_slimrx,
4121 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4122 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
4123 0, tabla_codec_enable_slimrx,
4124 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4125
4126 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
4127 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
4128
Neema Shettyd3a89262012-02-16 10:23:50 -08004129 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
4130 0, tabla_codec_enable_slimrx,
4131 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4132 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
4133 0, tabla_codec_enable_slimrx,
4134 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4135
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004136 /* Headphone */
4137 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
4138 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
4139 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4140 SND_SOC_DAPM_POST_PMD),
4141 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
4142 hphl_switch, ARRAY_SIZE(hphl_switch)),
4143
4144 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
4145 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4146 SND_SOC_DAPM_POST_PMD),
4147
4148 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
4149 tabla_hphr_dac_event,
4150 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4151
4152 /* Speaker */
4153 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
4154 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
4155 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
4156 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
4157 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
4158
4159 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
4160 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4161 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4162 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
4163 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4164 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4165 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
4166 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4167 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4168 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
4169 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4170 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4171 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
4172 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4173 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4174
4175 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
4176 , tabla_lineout_dac_event,
4177 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4178 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
4179 , tabla_lineout_dac_event,
4180 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4181 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
4182 , tabla_lineout_dac_event,
4183 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4184 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
4185 &lineout3_ground_switch),
4186 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
4187 , tabla_lineout_dac_event,
4188 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4189 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
4190 &lineout4_ground_switch),
4191 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
4192 , tabla_lineout_dac_event,
4193 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4194
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004195 SND_SOC_DAPM_MIXER_E("RX1 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004196 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4197 SND_SOC_DAPM_POST_PMU),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004198 SND_SOC_DAPM_MIXER_E("RX2 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004199 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4200 SND_SOC_DAPM_POST_PMU),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004201 SND_SOC_DAPM_MIXER_E("RX3 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004202 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4203 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004204 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004205 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4206 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004207 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004208 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4209 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004210 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004211 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4212 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004213 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004214 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4215 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004216
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004217 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4218 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4219 SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4220
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004221 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
4222 &rx4_dsm_mux, tabla_codec_reset_interpolator,
4223 SND_SOC_DAPM_PRE_PMU),
4224
4225 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
4226 &rx6_dsm_mux, tabla_codec_reset_interpolator,
4227 SND_SOC_DAPM_PRE_PMU),
4228
4229 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
4230 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
4231
4232 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4233 &rx_mix1_inp1_mux),
4234 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4235 &rx_mix1_inp2_mux),
4236 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4237 &rx2_mix1_inp1_mux),
4238 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4239 &rx2_mix1_inp2_mux),
4240 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4241 &rx3_mix1_inp1_mux),
4242 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4243 &rx3_mix1_inp2_mux),
4244 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4245 &rx4_mix1_inp1_mux),
4246 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4247 &rx4_mix1_inp2_mux),
4248 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4249 &rx5_mix1_inp1_mux),
4250 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4251 &rx5_mix1_inp2_mux),
4252 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4253 &rx6_mix1_inp1_mux),
4254 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4255 &rx6_mix1_inp2_mux),
4256 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4257 &rx7_mix1_inp1_mux),
4258 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4259 &rx7_mix1_inp2_mux),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004260 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4261 &rx1_mix2_inp1_mux),
4262 SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4263 &rx1_mix2_inp2_mux),
4264 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4265 &rx2_mix2_inp1_mux),
4266 SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4267 &rx2_mix2_inp2_mux),
4268 SND_SOC_DAPM_MUX("RX3 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4269 &rx3_mix2_inp1_mux),
4270 SND_SOC_DAPM_MUX("RX3 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4271 &rx3_mix2_inp2_mux),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004272
4273 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
4274 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
4275 SND_SOC_DAPM_PRE_PMD),
4276
4277 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
4278 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
4279 SND_SOC_DAPM_POST_PMD),
4280
4281 /* TX */
4282
4283 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
4284 0),
4285
4286 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
4287 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
4288
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004289 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
4290 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4291 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4292 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
4293 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4294 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4295
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004296 SND_SOC_DAPM_INPUT("AMIC1"),
4297 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
4298 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4299 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4300 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
4301 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4302 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4303 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
4304 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4305 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4306 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
4307 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4308 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4309
4310 SND_SOC_DAPM_INPUT("AMIC3"),
4311 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
4312 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4313 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4314
4315 SND_SOC_DAPM_INPUT("AMIC4"),
4316 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
4317 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4318 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4319
4320 SND_SOC_DAPM_INPUT("AMIC5"),
4321 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
4322 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4323
4324 SND_SOC_DAPM_INPUT("AMIC6"),
4325 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
4326 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4327
4328 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 -08004329 &dec1_mux, tabla_codec_enable_dec,
4330 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4331 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004332
4333 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 -08004334 &dec2_mux, tabla_codec_enable_dec,
4335 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4336 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004337
4338 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 -08004339 &dec3_mux, tabla_codec_enable_dec,
4340 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4341 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004342
4343 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 -08004344 &dec4_mux, tabla_codec_enable_dec,
4345 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4346 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004347
4348 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 -08004349 &dec5_mux, tabla_codec_enable_dec,
4350 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4351 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004352
4353 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 -08004354 &dec6_mux, tabla_codec_enable_dec,
4355 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4356 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004357
4358 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 -08004359 &dec7_mux, tabla_codec_enable_dec,
4360 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4361 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004362
4363 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 -08004364 &dec8_mux, tabla_codec_enable_dec,
4365 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4366 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004367
4368 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 -08004369 &dec9_mux, tabla_codec_enable_dec,
4370 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4371 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004372
4373 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 -08004374 &dec10_mux, tabla_codec_enable_dec,
4375 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4376 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004377
4378 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
4379 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
4380
4381 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
4382 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
4383 SND_SOC_DAPM_POST_PMD),
4384
4385 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
4386
4387 SND_SOC_DAPM_INPUT("AMIC2"),
4388 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
4389 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4390 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4391 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
4392 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4393 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4394 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
4395 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4396 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4397 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
4398 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4399 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4400 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
4401 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4402 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4403 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
4404 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4405 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4406 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
4407 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4408 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4409 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
4410 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4411 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4412
4413 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
4414 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
4415 0, 0),
4416
4417 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
4418 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
4419 4, 0),
4420
4421 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
4422 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
4423 5, 0),
4424
4425 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
4426 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4427 0, tabla_codec_enable_slimtx,
4428 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4429
4430 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
4431 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4432 0, tabla_codec_enable_slimtx,
4433 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4434
4435 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
4436 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
4437 0, 0, tabla_codec_enable_slimtx,
4438 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4439
4440 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
4441 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
4442 0, 0, tabla_codec_enable_slimtx,
4443 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4444
4445 /* Digital Mic Inputs */
4446 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
4447 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4448 SND_SOC_DAPM_POST_PMD),
4449
4450 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
4451 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4452 SND_SOC_DAPM_POST_PMD),
4453
4454 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
4455 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4456 SND_SOC_DAPM_POST_PMD),
4457
4458 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
4459 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4460 SND_SOC_DAPM_POST_PMD),
4461
4462 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
4463 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4464 SND_SOC_DAPM_POST_PMD),
4465 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
4466 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4467 SND_SOC_DAPM_POST_PMD),
4468
4469 /* Sidetone */
4470 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
4471 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08004472
4473 /* AUX PGA */
4474 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
4475 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4476 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4477 SND_SOC_DAPM_POST_PMD),
4478
4479 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
4480 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4481 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4482 SND_SOC_DAPM_POST_PMD),
4483
4484 /* Lineout, ear and HPH PA Mixers */
4485 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
4486 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
4487
4488 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4489 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4490
4491 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4492 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4493
4494 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4495 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
4496
4497 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
4498 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
4499
4500 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
4501 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
4502
4503 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
4504 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
4505
4506 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4507 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004508};
4509
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004510static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004511{
4512 u8 bias_msb, bias_lsb;
4513 short bias_value;
4514
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004515 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
4516 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
4517 bias_value = (bias_msb << 8) | bias_lsb;
4518 return bias_value;
4519}
4520
4521static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
4522{
4523 u8 bias_msb, bias_lsb;
4524 short bias_value;
4525
4526 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
4527 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
4528 bias_value = (bias_msb << 8) | bias_lsb;
4529 return bias_value;
4530}
4531
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004532static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004533{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004534 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
4535}
4536
4537static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4538 bool override_bypass, bool noreldetection)
4539{
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004540 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004541 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4542
4543 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4544 if (noreldetection)
4545 tabla_turn_onoff_rel_detection(codec, false);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004546
Joonwoo Park925914c2012-01-05 13:35:18 -08004547 /* Turn on the override */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004548 if (!override_bypass)
4549 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004550 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004551 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4552 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
4553 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004554 usleep_range(tabla->mbhc_data.t_sta_dce,
4555 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004556 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08004557 usleep_range(tabla->mbhc_data.t_dce,
4558 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004559 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004560 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004561 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004562 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4563 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004564 usleep_range(tabla->mbhc_data.t_sta_dce,
4565 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08004566 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4567 usleep_range(tabla->mbhc_data.t_sta,
4568 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004569 bias_value = tabla_codec_read_sta_result(codec);
4570 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4571 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004572 }
Joonwoo Park925914c2012-01-05 13:35:18 -08004573 /* Turn off the override after measuring mic voltage */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004574 if (!override_bypass)
4575 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4576
4577 if (noreldetection)
4578 tabla_turn_onoff_rel_detection(codec, true);
4579 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004580
Bradley Rubincb1e2732011-06-23 16:49:20 -07004581 return bias_value;
4582}
4583
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004584static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4585 bool norel)
4586{
4587 return __tabla_codec_sta_dce(codec, dce, false, norel);
4588}
4589
4590/* called only from interrupt which is under codec_resource_lock acquisition */
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004591static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004592{
4593 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004594 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004595 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004596
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004597 pr_debug("%s: enter, mclk_enabled %d\n", __func__, tabla->mclk_enabled);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004598 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004599 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004600 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004601 }
4602
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004603 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004604 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004605 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004606 tabla_codec_enable_clock_block(codec, 1);
4607 }
4608
4609 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4610
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004611 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004612 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4613 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004614
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004615 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004616
4617 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004618 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004619
4620 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4621 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4622 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4623
4624 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004625 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4626 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004627
Joonwoo Park925914c2012-01-05 13:35:18 -08004628 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004629 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4630
Bradley Rubincb1e2732011-06-23 16:49:20 -07004631 tabla_codec_calibrate_hs_polling(codec);
4632
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004633 /* don't flip override */
4634 bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004635 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4636 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004637 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004638
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004639 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004640}
4641
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004642static int tabla_cancel_btn_work(struct tabla_priv *tabla)
4643{
4644 int r = 0;
4645 struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
4646
4647 if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
4648 /* if scheduled mbhc_btn_dwork is canceled from here,
4649 * we have to unlock from here instead btn_work */
4650 wcd9xxx_unlock_sleep(core);
4651 r = 1;
4652 }
4653 return r;
4654}
4655
4656/* called under codec_resource_lock acquisition */
4657void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
Joonwoo Park03324832012-03-19 19:36:16 -07004658{
4659 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004660 u8 wg_time;
4661
4662 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4663 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07004664
4665 /* If headphone PA is on, check if userspace receives
4666 * removal event to sync-up PA's state */
4667 if (tabla_is_hph_pa_on(codec)) {
4668 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4669 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4670 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4671 } else {
4672 pr_debug("%s PA is off\n", __func__);
4673 }
4674
4675 if (tabla_is_hph_dac_on(codec, 1))
4676 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4677 if (tabla_is_hph_dac_on(codec, 0))
4678 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004679
4680 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
4681 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
4682 0xC0, 0x00);
4683 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
4684 0xC0, 0x00);
4685 usleep_range(wg_time * 1000, wg_time * 1000);
4686}
4687
4688static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
4689{
4690 bool pa_turned_on = false;
4691 struct snd_soc_codec *codec = tabla->codec;
4692 u8 wg_time;
4693
4694 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4695 wg_time += 1;
4696
4697 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4698 &tabla->hph_pa_dac_state)) {
4699 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4700 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4701 0xC0, 0xC0);
4702 }
4703 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4704 &tabla->hph_pa_dac_state)) {
4705 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4706 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4707 0xC0, 0xC0);
4708 }
4709
4710 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4711 &tabla->hph_pa_dac_state)) {
4712 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4713 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4714 1 << 4);
4715 pa_turned_on = true;
4716 }
4717 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4718 &tabla->hph_pa_dac_state)) {
4719 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4720 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4721 1 << 5);
4722 pa_turned_on = true;
4723 }
4724
4725 if (pa_turned_on) {
4726 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4727 __func__);
4728 usleep_range(wg_time * 1000, wg_time * 1000);
4729 }
4730}
4731
4732/* called under codec_resource_lock acquisition */
4733static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4734 enum snd_jack_types jack_type)
4735{
4736 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4737
4738 if (!insertion) {
4739 /* Report removal */
4740 tabla->hph_status &= ~jack_type;
4741 if (tabla->mbhc_cfg.headset_jack) {
4742 /* cancel possibly scheduled btn work and
4743 * report release if we reported button press */
4744 if (tabla_cancel_btn_work(tabla)) {
4745 pr_debug("%s: button press is canceled\n",
4746 __func__);
4747 } else if (tabla->buttons_pressed) {
4748 pr_debug("%s: Reporting release for reported "
4749 "button press %d\n", __func__,
4750 jack_type);
4751 tabla_snd_soc_jack_report(tabla,
4752 tabla->mbhc_cfg.button_jack, 0,
4753 tabla->buttons_pressed);
4754 tabla->buttons_pressed &=
4755 ~TABLA_JACK_BUTTON_MASK;
4756 }
4757 pr_debug("%s: Reporting removal %d\n", __func__,
4758 jack_type);
4759 tabla_snd_soc_jack_report(tabla,
4760 tabla->mbhc_cfg.headset_jack,
4761 tabla->hph_status,
4762 TABLA_JACK_MASK);
4763 }
4764 tabla_set_and_turnoff_hph_padac(codec);
4765 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
4766 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4767 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
4768 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4769 tabla->current_plug = PLUG_TYPE_NONE;
4770 tabla->mbhc_polling_active = false;
4771 } else {
4772 /* Report insertion */
4773 tabla->hph_status |= jack_type;
4774
4775 if (jack_type == SND_JACK_HEADPHONE)
4776 tabla->current_plug = PLUG_TYPE_HEADPHONE;
4777 else if (jack_type == SND_JACK_HEADSET) {
4778 tabla->mbhc_polling_active = true;
4779 tabla->current_plug = PLUG_TYPE_HEADSET;
4780 }
4781 if (tabla->mbhc_cfg.headset_jack) {
4782 pr_debug("%s: Reporting insertion %d\n", __func__,
4783 jack_type);
4784 tabla_snd_soc_jack_report(tabla,
4785 tabla->mbhc_cfg.headset_jack,
4786 tabla->hph_status,
4787 TABLA_JACK_MASK);
4788 }
4789 tabla_clr_and_turnon_hph_padac(tabla);
4790 }
Joonwoo Park03324832012-03-19 19:36:16 -07004791}
4792
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004793static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07004794 int insertion, int trigger,
4795 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004796{
4797 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004798 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08004799 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004800 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004801 const struct tabla_mbhc_plug_detect_cfg *plug_det =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004802 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004803
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004804 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004805 pr_err("Error, no tabla calibration\n");
4806 return -EINVAL;
4807 }
4808
4809 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
4810
Joonwoo Park03324832012-03-19 19:36:16 -07004811 /* Make sure mic bias and Mic line schmitt trigger
4812 * are turned OFF
4813 */
4814 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
4815 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
4816
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004817 if (insertion) {
Joonwoo Park03324832012-03-19 19:36:16 -07004818 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004819
Joonwoo Park03324832012-03-19 19:36:16 -07004820 /* DAPM can manipulate PA/DAC bits concurrently */
4821 if (padac_off == true) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004822 tabla_set_and_turnoff_hph_padac(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004823 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004824
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004825 if (trigger & MBHC_USE_HPHL_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07004826 /* Enable HPH Schmitt Trigger */
4827 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
4828 0x11);
4829 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
4830 plug_det->hph_current << 2);
4831 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
4832 0x02);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004833 }
4834 if (trigger & MBHC_USE_MB_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07004835 /* enable the mic line schmitt trigger */
4836 snd_soc_update_bits(codec,
4837 tabla->mbhc_bias_regs.mbhc_reg,
4838 0x60, plug_det->mic_current << 5);
4839 snd_soc_update_bits(codec,
4840 tabla->mbhc_bias_regs.mbhc_reg,
4841 0x80, 0x80);
4842 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4843 snd_soc_update_bits(codec,
4844 tabla->mbhc_bias_regs.ctl_reg, 0x01,
4845 0x00);
4846 snd_soc_update_bits(codec,
4847 tabla->mbhc_bias_regs.mbhc_reg,
4848 0x10, 0x10);
4849 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004850
4851 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004852 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004853 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004854 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004855 /* Make sure the HPH schmitt trigger is OFF */
4856 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
4857
4858 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07004859 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
4860 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004861 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08004862 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004863 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4864 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004865 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004866 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4867 0x10, 0x10);
4868
4869 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004870 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004871 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004872
4873 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004874 /* called called by interrupt */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004875 if (!(tabla->clock_active)) {
4876 tabla_codec_enable_config_mode(codec, 1);
4877 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004878 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004879 usleep_range(generic->t_shutdown_plug_rem,
4880 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004881 tabla_codec_enable_config_mode(codec, 0);
4882 } else
4883 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004884 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004885 }
4886
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004887 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004888
4889 /* If central bandgap disabled */
4890 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
4891 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004892 usleep_range(generic->t_bg_fast_settle,
4893 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004894 central_bias_enabled = 1;
4895 }
4896
4897 /* If LDO_H disabled */
4898 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
4899 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
4900 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004901 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004902 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
4903
4904 if (central_bias_enabled)
4905 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
4906 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004907
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004908 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004909 tabla->mbhc_cfg.micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004910
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304911 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004912 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4913 return 0;
4914}
4915
Joonwoo Park0976d012011-12-22 11:48:18 -08004916static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4917 s16 vin_mv)
4918{
Joonwoo Park0976d012011-12-22 11:48:18 -08004919 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004920 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08004921 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07004922 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004923
4924 tabla = snd_soc_codec_get_drvdata(codec);
4925 mb_mv = tabla->mbhc_data.micb_mv;
4926
4927 if (mb_mv == 0) {
4928 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4929 return -EINVAL;
4930 }
4931
4932 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004933 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
4934 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004935 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004936 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
4937 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004938 }
4939 in = (u32) diff * vin_mv;
4940
Joonwoo Park03324832012-03-19 19:36:16 -07004941 value = (u16) (in / mb_mv) + zero;
4942 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004943}
4944
4945static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4946 u16 bias_value)
4947{
4948 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004949 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08004950 s32 mv;
4951
4952 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004953 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004954 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004955 z = (tabla->mbhc_data.dce_z);
4956 mb = (tabla->mbhc_data.dce_mb);
4957 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004958 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004959 z = (tabla->mbhc_data.sta_z);
4960 mb = (tabla->mbhc_data.sta_mb);
4961 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004962 }
4963
4964 return mv;
4965}
4966
Joonwoo Park03324832012-03-19 19:36:16 -07004967static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004968{
4969 struct delayed_work *delayed_work;
4970 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08004971 short bias_value;
4972 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07004973 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004974
4975 pr_debug("%s:\n", __func__);
4976
4977 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07004978 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004979 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004980
4981 if (tabla) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004982 if (tabla->mbhc_cfg.button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004983 bias_value = tabla_codec_read_sta_result(tabla->codec);
4984 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304985 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004986 bias_value = tabla_codec_read_dce_result(tabla->codec);
4987 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304988 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004989 pr_debug("%s: Reporting long button press event"
4990 " STA: %d, DCE: %d\n", __func__,
4991 sta_mv, dce_mv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004992 tabla_snd_soc_jack_report(tabla,
4993 tabla->mbhc_cfg.button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07004994 tabla->buttons_pressed,
4995 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004996 }
4997 } else {
4998 pr_err("%s: Bad tabla private data\n", __func__);
4999 }
5000
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005001 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07005002 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005003}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005004
Joonwoo Park0976d012011-12-22 11:48:18 -08005005void tabla_mbhc_cal(struct snd_soc_codec *codec)
5006{
5007 struct tabla_priv *tabla;
5008 struct tabla_mbhc_btn_detect_cfg *btn_det;
5009 u8 cfilt_mode, bg_mode;
5010 u8 ncic, nmeas, navg;
5011 u32 mclk_rate;
5012 u32 dce_wait, sta_wait;
5013 u8 *n_cic;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005014 void *calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08005015
5016 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005017 calibration = tabla->mbhc_cfg.calibration;
5018
5019 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
5020 tabla_turn_onoff_rel_detection(codec, false);
Joonwoo Park0976d012011-12-22 11:48:18 -08005021
5022 /* First compute the DCE / STA wait times
5023 * depending on tunable parameters.
5024 * The value is computed in microseconds
5025 */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005026 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005027 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08005028 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005029 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
5030 navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
5031 mclk_rate = tabla->mbhc_cfg.mclk_rate;
Joonwoo Park433149a2012-01-11 09:53:54 -08005032 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
5033 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08005034
5035 tabla->mbhc_data.t_dce = dce_wait;
5036 tabla->mbhc_data.t_sta = sta_wait;
5037
5038 /* LDOH and CFILT are already configured during pdata handling.
5039 * Only need to make sure CFILT and bandgap are in Fast mode.
5040 * Need to restore defaults once calculation is done.
5041 */
5042 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
5043 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
5044 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
5045 0x02);
5046
5047 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
5048 * to perform ADC calibration
5049 */
5050 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005051 tabla->mbhc_cfg.micbias << 5);
Joonwoo Park0976d012011-12-22 11:48:18 -08005052 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5053 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
5054 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
5055 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
5056
5057 /* DCE measurement for 0 volts */
5058 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
5059 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
5060 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08005061 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
5062 usleep_range(100, 100);
5063 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
5064 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
5065 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
5066
5067 /* DCE measurment for MB voltage */
5068 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
5069 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
5070 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
5071 usleep_range(100, 100);
5072 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
5073 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
5074 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
5075
5076 /* Sta measuremnt for 0 volts */
5077 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
5078 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
5079 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08005080 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
5081 usleep_range(100, 100);
5082 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
5083 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
5084 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
5085
5086 /* STA Measurement for MB Voltage */
5087 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
5088 usleep_range(100, 100);
5089 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
5090 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
5091 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
5092
5093 /* Restore default settings. */
5094 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
5095 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
5096 cfilt_mode);
5097 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
5098
5099 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
5100 usleep_range(100, 100);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005101
5102 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
5103 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08005104}
5105
5106void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
5107 const enum tabla_mbhc_btn_det_mem mem)
5108{
5109 void *ret = &btn_det->_v_btn_low;
5110
5111 switch (mem) {
5112 case TABLA_BTN_DET_GAIN:
5113 ret += sizeof(btn_det->_n_cic);
5114 case TABLA_BTN_DET_N_CIC:
5115 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08005116 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08005117 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
5118 case TABLA_BTN_DET_V_BTN_HIGH:
5119 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
5120 case TABLA_BTN_DET_V_BTN_LOW:
5121 /* do nothing */
5122 break;
5123 default:
5124 ret = NULL;
5125 }
5126
5127 return ret;
5128}
5129
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005130static s16 tabla_scale_v_micb_vddio(struct tabla_priv *tabla, int v,
5131 bool tovddio)
5132{
5133 int r;
5134 int vddio_k, mb_k;
5135 vddio_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
5136 VDDIO_MICBIAS_MV);
5137 mb_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
5138 tabla->mbhc_data.micb_mv);
5139 if (tovddio)
5140 r = v * vddio_k / mb_k;
5141 else
5142 r = v * mb_k / vddio_k;
5143 return r;
5144}
5145
Joonwoo Park0976d012011-12-22 11:48:18 -08005146static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
5147{
5148 struct tabla_priv *tabla;
5149 s16 btn_mv = 0, btn_delta_mv;
5150 struct tabla_mbhc_btn_detect_cfg *btn_det;
5151 struct tabla_mbhc_plug_type_cfg *plug_type;
5152 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08005153 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08005154 int i;
5155
5156 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005157 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
5158 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005159
Joonwoo Parkc0672392012-01-11 11:03:14 -08005160 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005161 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07005162 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08005163 tabla->mbhc_data.nbounce_wait = 30;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005164 } else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005165 tabla->mbhc_data.npoll = 7;
5166 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08005167 }
Joonwoo Park0976d012011-12-22 11:48:18 -08005168
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005169 tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
5170 (tabla->mbhc_cfg.mclk_rate / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08005171 n_ready[tabla_codec_mclk_index(tabla)]) +
5172 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08005173 tabla->mbhc_data.v_ins_hu =
5174 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
5175 tabla->mbhc_data.v_ins_h =
5176 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
5177
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005178 tabla->mbhc_data.v_inval_ins_low = TABLA_MBHC_FAKE_INSERT_LOW;
5179 if (tabla->mbhc_cfg.gpio)
5180 tabla->mbhc_data.v_inval_ins_high =
5181 TABLA_MBHC_FAKE_INSERT_HIGH;
5182 else
5183 tabla->mbhc_data.v_inval_ins_high =
5184 TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
5185
5186 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
5187 tabla->mbhc_data.adj_v_hs_max =
5188 tabla_scale_v_micb_vddio(tabla, plug_type->v_hs_max, true);
5189 tabla->mbhc_data.adj_v_ins_hu =
5190 tabla_codec_v_sta_dce(codec, STA,
5191 tabla->mbhc_data.adj_v_hs_max);
5192 tabla->mbhc_data.adj_v_ins_h =
5193 tabla_codec_v_sta_dce(codec, DCE,
5194 tabla->mbhc_data.adj_v_hs_max);
5195 tabla->mbhc_data.v_inval_ins_low =
5196 tabla_scale_v_micb_vddio(tabla,
5197 tabla->mbhc_data.v_inval_ins_low,
5198 false);
5199 tabla->mbhc_data.v_inval_ins_high =
5200 tabla_scale_v_micb_vddio(tabla,
5201 tabla->mbhc_data.v_inval_ins_high,
5202 false);
5203 }
5204
Joonwoo Park0976d012011-12-22 11:48:18 -08005205 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
5206 for (i = 0; i < btn_det->num_btn; i++)
5207 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
5208
5209 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
5210 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
Joonwoo Park0976d012011-12-22 11:48:18 -08005211 tabla->mbhc_data.v_b1_hu =
5212 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
5213
5214 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
5215
5216 tabla->mbhc_data.v_b1_huc =
5217 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
5218
5219 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
Joonwoo Park03324832012-03-19 19:36:16 -07005220 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
Joonwoo Park0976d012011-12-22 11:48:18 -08005221
5222 tabla->mbhc_data.v_no_mic =
5223 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
5224}
5225
5226void tabla_mbhc_init(struct snd_soc_codec *codec)
5227{
5228 struct tabla_priv *tabla;
5229 struct tabla_mbhc_general_cfg *generic;
5230 struct tabla_mbhc_btn_detect_cfg *btn_det;
5231 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08005232 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305233 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08005234
5235 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005236 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
5237 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005238
Joonwoo Park0976d012011-12-22 11:48:18 -08005239 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005240 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005241 snd_soc_update_bits(codec,
5242 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
5243 0x07, n);
5244 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
5245 btn_det->c[n]);
5246 }
5247 }
5248 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
5249 btn_det->nc);
5250
5251 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
5252 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08005253 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08005254
5255 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08005256 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
5257 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08005258
5259 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
5260 generic->mbhc_nsa << 4);
5261
5262 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
5263 btn_det->n_meas);
5264
5265 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
5266
5267 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
5268
5269 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
5270 btn_det->mbhc_nsc << 3);
5271
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005272 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
5273 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08005274
5275 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07005276
5277 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Park0976d012011-12-22 11:48:18 -08005278}
5279
Patrick Lai64b43262011-12-06 17:29:15 -08005280static bool tabla_mbhc_fw_validate(const struct firmware *fw)
5281{
5282 u32 cfg_offset;
5283 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
5284 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
5285
5286 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
5287 return false;
5288
5289 /* previous check guarantees that there is enough fw data up
5290 * to num_btn
5291 */
5292 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
5293 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
5294 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
5295 return false;
5296
5297 /* previous check guarantees that there is enough fw data up
5298 * to start of impedance detection configuration
5299 */
5300 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
5301 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
5302
5303 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
5304 return false;
5305
5306 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
5307 return false;
5308
5309 return true;
5310}
Joonwoo Park03324832012-03-19 19:36:16 -07005311
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005312static int tabla_determine_button(const struct tabla_priv *priv,
5313 const s32 bias_mv)
5314{
5315 s16 *v_btn_low, *v_btn_high;
5316 struct tabla_mbhc_btn_detect_cfg *btn_det;
5317 int i, btn = -1;
5318
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005319 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005320 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
5321 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305322 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005323 for (i = 0; i < btn_det->num_btn; i++) {
5324 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
5325 btn = i;
5326 break;
5327 }
5328 }
5329
5330 if (btn == -1)
5331 pr_debug("%s: couldn't find button number for mic mv %d\n",
5332 __func__, bias_mv);
5333
5334 return btn;
5335}
5336
5337static int tabla_get_button_mask(const int btn)
5338{
5339 int mask = 0;
5340 switch (btn) {
5341 case 0:
5342 mask = SND_JACK_BTN_0;
5343 break;
5344 case 1:
5345 mask = SND_JACK_BTN_1;
5346 break;
5347 case 2:
5348 mask = SND_JACK_BTN_2;
5349 break;
5350 case 3:
5351 mask = SND_JACK_BTN_3;
5352 break;
5353 case 4:
5354 mask = SND_JACK_BTN_4;
5355 break;
5356 case 5:
5357 mask = SND_JACK_BTN_5;
5358 break;
5359 case 6:
5360 mask = SND_JACK_BTN_6;
5361 break;
5362 case 7:
5363 mask = SND_JACK_BTN_7;
5364 break;
5365 }
5366 return mask;
5367}
5368
Bradley Rubincb1e2732011-06-23 16:49:20 -07005369static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005370{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005371 int i, mask;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005372 short dce, sta, bias_value_dce;
5373 s32 mv, stamv, bias_mv_dce;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005374 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005375 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005376 const struct tabla_mbhc_btn_detect_cfg *d =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005377 TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005378 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005379 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305380 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07005381 int n_btn_meas = d->n_btn_meas;
5382 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005383
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005384 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005385
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005386 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5387 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
5388 pr_debug("%s: mbhc is being recovered, skip button press\n",
5389 __func__);
5390 goto done;
5391 }
5392
5393 priv->mbhc_state = MBHC_STATE_POTENTIAL;
5394
5395 if (!priv->mbhc_polling_active) {
5396 pr_warn("%s: mbhc polling is not active, skip button press\n",
5397 __func__);
5398 goto done;
5399 }
Joonwoo Park03324832012-03-19 19:36:16 -07005400
5401 dce = tabla_codec_read_dce_result(codec);
5402 mv = tabla_codec_sta_dce_v(codec, 1, dce);
5403
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005404 /* If GPIO interrupt already kicked in, ignore button press */
5405 if (priv->in_gpio_handler) {
5406 pr_debug("%s: GPIO State Changed, ignore button press\n",
5407 __func__);
5408 btn = -1;
5409 goto done;
5410 }
5411
Joonwoo Park03324832012-03-19 19:36:16 -07005412 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
5413 if (priv->mbhc_last_resume &&
5414 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
5415 pr_debug("%s: Button is already released shortly after "
5416 "resume\n", __func__);
5417 n_btn_meas = 0;
5418 } else {
5419 pr_debug("%s: Button is already released without "
5420 "resume", __func__);
5421 sta = tabla_codec_read_sta_result(codec);
5422 stamv = tabla_codec_sta_dce_v(codec, 0, sta);
5423 btn = tabla_determine_button(priv, mv);
5424 if (btn != tabla_determine_button(priv, stamv))
5425 btn = -1;
5426 goto done;
5427 }
5428 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005429
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005430 /* determine pressed button */
Joonwoo Park03324832012-03-19 19:36:16 -07005431 btnmeas[meas++] = tabla_determine_button(priv, mv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005432 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Joonwoo Park03324832012-03-19 19:36:16 -07005433 meas - 1, dce, mv, btnmeas[meas - 1]);
5434 if (n_btn_meas == 0)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005435 btn = btnmeas[0];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005436 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
5437 bias_value_dce = tabla_codec_sta_dce(codec, 1, false);
5438 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
5439 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005440 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005441 __func__, meas, bias_value_dce, bias_mv_dce,
5442 btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005443 /* if large enough measurements are collected,
5444 * start to check if last all n_btn_con measurements were
5445 * in same button low/high range */
5446 if (meas + 1 >= d->n_btn_con) {
5447 for (i = 0; i < d->n_btn_con; i++)
5448 if ((btnmeas[meas] < 0) ||
5449 (btnmeas[meas] != btnmeas[meas - i]))
5450 break;
5451 if (i == d->n_btn_con) {
5452 /* button pressed */
5453 btn = btnmeas[meas];
5454 break;
Joonwoo Park03324832012-03-19 19:36:16 -07005455 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
5456 /* if left measurements are less than n_btn_con,
5457 * it's impossible to find button number */
5458 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005459 }
5460 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005461 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005462
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005463 if (btn >= 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005464 if (priv->in_gpio_handler) {
5465 pr_debug("%s: GPIO already triggered, ignore button "
5466 "press\n", __func__);
5467 goto done;
5468 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005469 mask = tabla_get_button_mask(btn);
5470 priv->buttons_pressed |= mask;
Joonwoo Park03324832012-03-19 19:36:16 -07005471 wcd9xxx_lock_sleep(core);
5472 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
5473 msecs_to_jiffies(400)) == 0) {
5474 WARN(1, "Button pressed twice without release"
5475 "event\n");
5476 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005477 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08005478 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005479 pr_debug("%s: bogus button press, too short press?\n",
5480 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08005481 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005482
Joonwoo Park03324832012-03-19 19:36:16 -07005483 done:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005484 pr_debug("%s: leave\n", __func__);
5485 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005486 return IRQ_HANDLED;
5487}
5488
Joonwoo Park03324832012-03-19 19:36:16 -07005489static int tabla_is_fake_press(struct tabla_priv *priv)
5490{
5491 int i;
5492 int r = 0;
5493 struct snd_soc_codec *codec = priv->codec;
5494 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005495 s16 mb_v, v_ins_hu, v_ins_h;
5496
5497 v_ins_hu = tabla_get_current_v_ins(priv, true);
5498 v_ins_h = tabla_get_current_v_ins(priv, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005499
5500 for (i = 0; i < dces; i++) {
5501 usleep_range(10000, 10000);
5502 if (i == 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005503 mb_v = tabla_codec_sta_dce(codec, 0, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005504 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
5505 tabla_codec_sta_dce_v(codec, 0, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005506 if (mb_v < (s16)priv->mbhc_data.v_b1_hu ||
5507 mb_v > v_ins_hu) {
Joonwoo Park03324832012-03-19 19:36:16 -07005508 r = 1;
5509 break;
5510 }
5511 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005512 mb_v = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005513 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
5514 tabla_codec_sta_dce_v(codec, 1, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005515 if (mb_v < (s16)priv->mbhc_data.v_b1_h ||
5516 mb_v > v_ins_h) {
Joonwoo Park03324832012-03-19 19:36:16 -07005517 r = 1;
5518 break;
5519 }
5520 }
5521 }
5522
5523 return r;
5524}
5525
Bradley Rubincb1e2732011-06-23 16:49:20 -07005526static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005527{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08005528 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08005529 struct tabla_priv *priv = data;
5530 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005531
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005532 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07005533
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005534 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5535 priv->mbhc_state = MBHC_STATE_RELEASE;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005536
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005537 tabla_codec_drive_v_to_micbias(codec, 10000);
5538
Joonwoo Park03324832012-03-19 19:36:16 -07005539 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005540 ret = tabla_cancel_btn_work(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005541 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07005542 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005543 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005544 if (priv->mbhc_cfg.button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005545 tabla_snd_soc_jack_report(priv,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005546 priv->mbhc_cfg.button_jack, 0,
5547 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005548 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005549 if (tabla_is_fake_press(priv)) {
5550 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005551 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005552 } else if (priv->mbhc_cfg.button_jack) {
5553 if (priv->in_gpio_handler) {
5554 pr_debug("%s: GPIO kicked in, ignore\n",
5555 __func__);
5556 } else {
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005557 pr_debug("%s: Reporting short button "
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005558 "press and release\n",
5559 __func__);
5560 tabla_snd_soc_jack_report(priv,
5561 priv->mbhc_cfg.button_jack,
5562 priv->buttons_pressed,
5563 priv->buttons_pressed);
5564 tabla_snd_soc_jack_report(priv,
5565 priv->mbhc_cfg.button_jack, 0,
5566 priv->buttons_pressed);
5567 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005568 }
5569 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005570
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005571 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
5572 }
5573
Joonwoo Park03324832012-03-19 19:36:16 -07005574 tabla_codec_calibrate_hs_polling(codec);
5575
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005576 if (priv->mbhc_cfg.gpio)
5577 msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
Joonwoo Park03324832012-03-19 19:36:16 -07005578
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005579 tabla_codec_start_hs_polling(codec);
5580
5581 pr_debug("%s: leave\n", __func__);
5582 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005583 return IRQ_HANDLED;
5584}
5585
Bradley Rubincb1e2732011-06-23 16:49:20 -07005586static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
5587{
5588 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08005589 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005590 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005591
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005592 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005593 tabla_codec_enable_config_mode(codec, 1);
5594
5595 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
5596 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005597
Joonwoo Park0976d012011-12-22 11:48:18 -08005598 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
5599
5600 usleep_range(generic->t_shutdown_plug_rem,
5601 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005602
5603 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005604 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005605 tabla_codec_enable_config_mode(codec, 0);
5606
5607 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
5608}
5609
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005610static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005611{
5612 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005613
5614 tabla_codec_shutdown_hs_removal_detect(codec);
5615
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005616 if (!tabla->mclk_enabled) {
Asish Bhattacharya486745a2012-01-20 06:41:53 +05305617 tabla_codec_disable_clock_block(codec);
5618 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005619 }
5620
5621 tabla->mbhc_polling_active = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005622 tabla->mbhc_state = MBHC_STATE_NONE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005623}
5624
Patrick Lai49efeac2011-11-03 11:01:12 -07005625static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
5626{
5627 struct tabla_priv *tabla = data;
5628 struct snd_soc_codec *codec;
5629
5630 pr_info("%s: received HPHL OCP irq\n", __func__);
5631
5632 if (tabla) {
5633 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005634 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
5635 pr_info("%s: retry\n", __func__);
5636 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5637 0x00);
5638 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5639 0x10);
5640 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305641 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005642 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5643 tabla->hphlocp_cnt = 0;
5644 tabla->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005645 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005646 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005647 tabla->mbhc_cfg.headset_jack,
5648 tabla->hph_status,
5649 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005650 }
5651 } else {
5652 pr_err("%s: Bad tabla private data\n", __func__);
5653 }
5654
5655 return IRQ_HANDLED;
5656}
5657
5658static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
5659{
5660 struct tabla_priv *tabla = data;
5661 struct snd_soc_codec *codec;
5662
5663 pr_info("%s: received HPHR OCP irq\n", __func__);
5664
5665 if (tabla) {
5666 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005667 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
5668 pr_info("%s: retry\n", __func__);
5669 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5670 0x00);
5671 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5672 0x10);
5673 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305674 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005675 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5676 tabla->hphrocp_cnt = 0;
5677 tabla->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005678 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005679 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005680 tabla->mbhc_cfg.headset_jack,
5681 tabla->hph_status,
5682 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005683 }
5684 } else {
5685 pr_err("%s: Bad tabla private data\n", __func__);
5686 }
5687
5688 return IRQ_HANDLED;
5689}
5690
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005691static bool tabla_is_invalid_insertion_range(struct snd_soc_codec *codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005692 s32 mic_volt)
Joonwoo Park03324832012-03-19 19:36:16 -07005693{
5694 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005695 bool invalid = false;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005696 s16 v_hs_max;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005697
5698 /* Perform this check only when the high voltage headphone
5699 * needs to be considered as invalid
5700 */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005701 v_hs_max = tabla_get_current_v_hs_max(tabla);
5702 if (!tabla->mbhc_inval_hs_range_override && (mic_volt > v_hs_max))
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005703 invalid = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005704 else if (mic_volt < tabla->mbhc_data.v_inval_ins_high &&
5705 (mic_volt > tabla->mbhc_data.v_inval_ins_low))
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005706 invalid = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005707
5708 return invalid;
5709}
5710
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005711static bool tabla_is_inval_insert_delta(struct snd_soc_codec *codec,
5712 int mic_volt, int mic_volt_prev,
5713 int threshold)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005714{
5715 int delta = abs(mic_volt - mic_volt_prev);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005716 if (delta > threshold) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005717 pr_debug("%s: volt delta %dmv\n", __func__, delta);
Joonwoo Park03324832012-03-19 19:36:16 -07005718 return true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005719 }
Joonwoo Park03324832012-03-19 19:36:16 -07005720 return false;
5721}
5722
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005723static bool tabla_codec_is_invalid_plug(struct snd_soc_codec *codec,
5724 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
5725 enum tabla_mbhc_plug_type
5726 plug_type[MBHC_NUM_DCE_PLUG_DETECT])
5727{
5728 int i;
5729 bool r = false;
5730 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5731 struct tabla_mbhc_plug_type_cfg *plug_type_ptr =
5732 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005733 s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005734
5735 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
5736 if (mic_mv[i] < plug_type_ptr->v_no_mic)
5737 plug_type[i] = PLUG_TYPE_HEADPHONE;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005738 else if (mic_mv[i] < v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005739 plug_type[i] = PLUG_TYPE_HEADSET;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005740 else if (mic_mv[i] > v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005741 plug_type[i] = PLUG_TYPE_HIGH_HPH;
5742
5743 r = tabla_is_invalid_insertion_range(codec, mic_mv[i]);
5744 if (!r && i > 0) {
5745 if (plug_type[i-1] != plug_type[i])
5746 r = true;
5747 else
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005748 r = tabla_is_inval_insert_delta(codec,
5749 mic_mv[i], mic_mv[i - 1],
5750 TABLA_MBHC_FAKE_INS_DELTA_MV);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005751 }
5752 }
5753
5754 return r;
5755}
5756
5757/* called under codec_resource_lock acquisition */
5758void tabla_find_plug_and_report(struct snd_soc_codec *codec,
5759 enum tabla_mbhc_plug_type plug_type)
Joonwoo Park03324832012-03-19 19:36:16 -07005760{
5761 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005762
5763 if (plug_type == PLUG_TYPE_HEADPHONE
5764 && tabla->current_plug == PLUG_TYPE_NONE) {
5765 /* Nothing was reported previously
5766 * reporte a headphone
5767 */
5768 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5769 tabla_codec_cleanup_hs_polling(codec);
5770 } else if (plug_type == PLUG_TYPE_HEADSET) {
5771 /* If Headphone was reported previously, this will
5772 * only report the mic line
5773 */
5774 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5775 msleep(100);
5776 tabla_codec_start_hs_polling(codec);
5777 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
5778 if (tabla->current_plug == PLUG_TYPE_NONE)
5779 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5780 tabla_codec_cleanup_hs_polling(codec);
5781 pr_debug("setup mic trigger for further detection\n");
5782 tabla->lpi_enabled = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005783 tabla_codec_enable_hs_detect(codec, 1,
5784 MBHC_USE_MB_TRIGGER |
5785 MBHC_USE_HPHL_TRIGGER,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005786 false);
5787 }
5788}
5789
5790/* should be called under interrupt context that hold suspend */
5791static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla)
5792{
5793 pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
5794 tabla->hs_detect_work_stop = false;
5795 wcd9xxx_lock_sleep(tabla->codec->control_data);
5796 schedule_work(&tabla->hs_correct_plug_work);
5797}
5798
5799/* called under codec_resource_lock acquisition */
5800static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla)
5801{
5802 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
5803 tabla->hs_detect_work_stop = true;
5804 wmb();
5805 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5806 if (cancel_work_sync(&tabla->hs_correct_plug_work)) {
5807 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
5808 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5809 }
5810 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5811}
5812
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005813static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
5814{
5815 return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
5816 tabla->mbhc_cfg.gpio_level_insert);
5817}
5818
5819static void tabla_hs_correct_gpio_plug(struct work_struct *work)
5820{
5821 struct tabla_priv *tabla;
5822 struct snd_soc_codec *codec;
5823 int retry = 0, i;
5824 bool correction = false;
5825 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5826 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5827 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5828 unsigned long timeout;
5829
5830 tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
5831 codec = tabla->codec;
5832
5833 pr_debug("%s: enter\n", __func__);
5834 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
5835
5836 /* Keep override on during entire plug type correction work.
5837 *
5838 * This is okay under the assumption that any GPIO irqs which use
5839 * MBHC block cancel and sync this work so override is off again
5840 * prior to GPIO interrupt handler's MBHC block usage.
5841 * Also while this correction work is running, we can guarantee
5842 * DAPM doesn't use any MBHC block as this work only runs with
5843 * headphone detection.
5844 */
5845 tabla_turn_onoff_override(codec, true);
5846
5847 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5848 while (!time_after(jiffies, timeout)) {
5849 ++retry;
5850 rmb();
5851 if (tabla->hs_detect_work_stop) {
5852 pr_debug("%s: stop requested\n", __func__);
5853 break;
5854 }
5855
5856 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
5857 if (tabla_hs_gpio_level_remove(tabla)) {
5858 pr_debug("%s: GPIO value is low\n", __func__);
5859 break;
5860 }
5861
5862 /* can race with removal interrupt */
5863 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5864 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5865 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5866 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5867 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
5868 __func__, retry, mic_mv[i], mb_v[i]);
5869 }
5870 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5871
5872 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5873 pr_debug("Invalid plug in attempt # %d\n", retry);
5874 if (retry == NUM_ATTEMPTS_TO_REPORT &&
5875 tabla->current_plug == PLUG_TYPE_NONE) {
5876 tabla_codec_report_plug(codec, 1,
5877 SND_JACK_HEADPHONE);
5878 }
5879 } else if (!tabla_codec_is_invalid_plug(codec, mic_mv,
5880 plug_type) &&
5881 plug_type[0] == PLUG_TYPE_HEADPHONE) {
5882 pr_debug("Good headphone detected, continue polling mic\n");
5883 if (tabla->current_plug == PLUG_TYPE_NONE) {
5884 tabla_codec_report_plug(codec, 1,
5885 SND_JACK_HEADPHONE);
5886 }
5887 } else {
5888 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5889 /* Turn off override */
5890 tabla_turn_onoff_override(codec, false);
5891 tabla_find_plug_and_report(codec, plug_type[0]);
5892 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5893 pr_debug("Attempt %d found correct plug %d\n", retry,
5894 plug_type[0]);
5895 correction = true;
5896 break;
5897 }
5898 }
5899
5900 /* Turn off override */
5901 if (!correction)
5902 tabla_turn_onoff_override(codec, false);
5903
5904 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
5905 pr_debug("%s: leave\n", __func__);
5906 /* unlock sleep */
5907 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5908}
5909
5910/* called under codec_resource_lock acquisition */
5911static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
5912{
5913 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005914 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5915 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005916 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5917 int i;
5918
5919 pr_debug("%s: enter\n", __func__);
5920
5921 tabla_turn_onoff_override(codec, true);
5922 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5923 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
5924 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
5925
5926 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5927 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5928 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5929 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
5930 mic_mv[i]);
5931 }
5932 tabla_turn_onoff_override(codec, false);
5933
5934 if (tabla_hs_gpio_level_remove(tabla)) {
5935 pr_debug("%s: GPIO value is low when determining plug\n",
5936 __func__);
5937 return;
5938 }
5939
5940 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5941 tabla_schedule_hs_detect_plug(tabla);
5942 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5943 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5944
5945 tabla_schedule_hs_detect_plug(tabla);
5946 } else {
5947 pr_debug("%s: Valid plug found, determine plug type\n",
5948 __func__);
5949 tabla_find_plug_and_report(codec, plug_type[0]);
5950 }
5951}
5952
5953/* called under codec_resource_lock acquisition */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005954static void tabla_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
5955{
5956 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5957
5958 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
5959 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, on);
5960 if (on)
5961 usleep_range(5000, 5000);
5962 }
5963}
5964
5965/* called under codec_resource_lock acquisition */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005966static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
5967{
5968 int i;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005969 bool gndswitch, vddioswitch;
5970 int scaled;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005971 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5972 const struct tabla_mbhc_plug_detect_cfg *plug_det =
5973 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07005974 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005975 const bool vddio = (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
5976 !tabla->mbhc_micbias_switched);
5977 int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
5978 enum tabla_mbhc_plug_type plug_type[num_det];
5979 short mb_v[num_det];
5980 s32 mic_mv[num_det];
5981 bool inval = false;
Joonwoo Park03324832012-03-19 19:36:16 -07005982
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005983 /* Turn on the override,
5984 * tabla_codec_setup_hs_polling requires override on */
5985 tabla_turn_onoff_override(codec, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005986
5987 if (plug_det->t_ins_complete > 20)
5988 msleep(plug_det->t_ins_complete);
5989 else
5990 usleep_range(plug_det->t_ins_complete * 1000,
5991 plug_det->t_ins_complete * 1000);
5992
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005993 if (tabla->mbhc_cfg.gpio) {
5994 /* Turn off the override */
5995 tabla_turn_onoff_override(codec, false);
5996 if (tabla_hs_gpio_level_remove(tabla))
5997 pr_debug("%s: GPIO value is low when determining "
5998 "plug\n", __func__);
5999 else
6000 tabla_codec_decide_gpio_plug(codec);
6001 return;
6002 }
6003
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006004 /* performs DCEs for N times
6005 * 1st: check if voltage is in invalid range
6006 * 2nd - N-2nd: check voltage range and delta
6007 * N-1st: check voltage range, delta with HPHR GND switch
6008 * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
6009 for (i = 0; i < num_det && !inval; i++) {
6010 gndswitch = (i == (num_det - 1 - vddio));
6011 vddioswitch = (vddio && (i == num_det - 1));
6012 if (i == 0) {
6013 mb_v[i] = tabla_codec_setup_hs_polling(codec);
6014 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
6015 inval = tabla_is_invalid_insertion_range(codec,
6016 mic_mv[i]);
6017 scaled = mic_mv[i];
6018 } else if (vddioswitch) {
6019 __tabla_codec_switch_micbias(tabla->codec, 1, false,
Joonwoo Park03324832012-03-19 19:36:16 -07006020 false);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006021 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
6022 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
6023 scaled = tabla_scale_v_micb_vddio(tabla, mic_mv[i],
6024 false);
6025 inval = (tabla_is_invalid_insertion_range(codec,
6026 mic_mv[i]) ||
6027 tabla_is_inval_insert_delta(codec, scaled,
6028 mic_mv[i - 1],
6029 TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
6030 __tabla_codec_switch_micbias(tabla->codec, 0, false,
6031 false);
6032 } else {
6033 if (gndswitch)
6034 tabla_codec_hphr_gnd_switch(codec, true);
6035 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
6036 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
6037 inval = (tabla_is_invalid_insertion_range(codec,
6038 mic_mv[i]) ||
6039 tabla_is_inval_insert_delta(codec, mic_mv[i],
6040 mic_mv[i - 1],
6041 TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
6042 if (gndswitch)
6043 tabla_codec_hphr_gnd_switch(codec, false);
6044 scaled = mic_mv[i];
Joonwoo Park03324832012-03-19 19:36:16 -07006045 }
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006046 pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
6047 "invalid %d\n", __func__,
6048 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
6049 inval);
Joonwoo Park03324832012-03-19 19:36:16 -07006050 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006051 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006052
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006053 plug_type_ptr =
6054 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07006055
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006056 for (i = 0; !inval && i < num_det; i++) {
6057 /*
6058 * If we are here, means none of the all
6059 * measurements are fake, continue plug type detection.
6060 * If all three measurements do not produce same
6061 * plug type, restart insertion detection
6062 */
Joonwoo Park03324832012-03-19 19:36:16 -07006063 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
6064 plug_type[i] = PLUG_TYPE_HEADPHONE;
6065 pr_debug("%s: Detect attempt %d, detected Headphone\n",
6066 __func__, i);
6067 } else {
6068 plug_type[i] = PLUG_TYPE_HEADSET;
6069 pr_debug("%s: Detect attempt %d, detected Headset\n",
6070 __func__, i);
6071 }
6072
6073 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
6074 pr_err("%s: Detect attempt %d and %d are not same",
6075 __func__, i - 1, i);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006076 inval = true;
6077 break;
Joonwoo Park03324832012-03-19 19:36:16 -07006078 }
6079 }
6080
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006081 if (inval) {
6082 pr_debug("%s: Invalid plug type detected\n", __func__);
6083 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
6084 0x02, 0x02);
6085 tabla_codec_cleanup_hs_polling(codec);
6086 tabla_codec_enable_hs_detect(codec, 1,
6087 MBHC_USE_MB_TRIGGER |
6088 MBHC_USE_HPHL_TRIGGER, false);
6089 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
Joonwoo Park03324832012-03-19 19:36:16 -07006090 pr_debug("%s: Headphone Detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006091 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
6092 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07006093 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006094 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
6095 pr_debug("%s: Headset detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006096 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
6097
Joonwoo Park03324832012-03-19 19:36:16 -07006098 /* avoid false button press detect */
6099 msleep(50);
Joonwoo Park03324832012-03-19 19:36:16 -07006100 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07006101 }
6102}
6103
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006104/* called only from interrupt which is under codec_resource_lock acquisition */
6105static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
Bradley Rubincb1e2732011-06-23 16:49:20 -07006106{
Bradley Rubincb1e2732011-06-23 16:49:20 -07006107 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006108
6109 if (!is_removal) {
6110 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
6111
6112 rmb();
6113 if (priv->lpi_enabled)
6114 msleep(100);
6115
6116 rmb();
6117 if (!priv->lpi_enabled) {
6118 pr_debug("%s: lpi is disabled\n", __func__);
6119 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
6120 priv->mbhc_cfg.gpio_level_insert) {
6121 pr_debug("%s: Valid insertion, "
6122 "detect plug type\n", __func__);
6123 tabla_codec_decide_gpio_plug(codec);
6124 } else {
6125 pr_debug("%s: Invalid insertion, "
6126 "stop plug detection\n", __func__);
6127 }
6128 } else {
6129 pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
6130 }
6131}
6132
6133/* called only from interrupt which is under codec_resource_lock acquisition */
6134static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
6135 bool is_mb_trigger)
6136{
Joonwoo Park03324832012-03-19 19:36:16 -07006137 int ret;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006138 struct snd_soc_codec *codec = priv->codec;
6139 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006140
6141 if (is_removal) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006142 /* cancel possiblely running hs detect work */
6143 tabla_cancel_hs_detect_plug(priv);
6144
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006145 /*
6146 * If headphone is removed while playback is in progress,
6147 * it is possible that micbias will be switched to VDDIO.
6148 */
Joonwoo Park03324832012-03-19 19:36:16 -07006149 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006150 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006151 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006152 tabla_codec_enable_hs_detect(codec, 1,
6153 MBHC_USE_MB_TRIGGER |
6154 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07006155 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006156 } else if (is_mb_trigger && !is_removal) {
Joonwoo Park03324832012-03-19 19:36:16 -07006157 pr_debug("%s: Waiting for Headphone left trigger\n",
6158 __func__);
6159 wcd9xxx_lock_sleep(core);
6160 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
6161 usecs_to_jiffies(1000000)) == 0) {
6162 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
6163 __func__);
6164 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08006165 }
Joonwoo Park03324832012-03-19 19:36:16 -07006166 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
6167 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006168 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006169 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
6170 if (ret != 0) {
6171 pr_debug("%s: Complete plug insertion, Detecting plug "
6172 "type\n", __func__);
6173 tabla_codec_detect_plug_type(codec);
6174 wcd9xxx_unlock_sleep(core);
6175 } else {
6176 wcd9xxx_enable_irq(codec->control_data,
6177 TABLA_IRQ_MBHC_INSERTION);
6178 pr_err("%s: Error detecting plug insertion\n",
6179 __func__);
6180 }
Joonwoo Park03324832012-03-19 19:36:16 -07006181 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006182}
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08006183
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006184static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
6185{
6186 bool is_mb_trigger, is_removal;
6187 struct tabla_priv *priv = data;
6188 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07006189
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006190 pr_debug("%s: enter\n", __func__);
6191 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
6192 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
6193
6194 is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
6195 0x10);
6196 is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
6197 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
6198
6199 /* Turn off both HPH and MIC line schmitt triggers */
6200 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6201 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
6202 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6203
6204 if (priv->mbhc_cfg.gpio)
6205 tabla_hs_insert_irq_gpio(priv, is_removal);
6206 else
6207 tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
6208
6209 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006210 return IRQ_HANDLED;
6211}
6212
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006213static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
6214{
6215 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006216 const struct tabla_mbhc_plug_type_cfg *plug_type =
6217 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
6218 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006219
6220 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006221 && (mic_mv < v_hs_max)) ? true : false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006222}
6223
6224/* called under codec_resource_lock acquisition
6225 * returns true if mic voltage range is back to normal insertion
6226 * returns false either if timedout or removed */
6227static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
6228{
6229 int i;
6230 bool timedout, settled = false;
6231 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
6232 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
6233 unsigned long retry = 0, timeout;
6234 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006235 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006236
6237 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
6238 while (!(timedout = time_after(jiffies, timeout))) {
6239 retry++;
6240 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6241 pr_debug("%s: GPIO indicates removal\n", __func__);
6242 break;
6243 }
6244
6245 if (tabla->mbhc_cfg.gpio) {
6246 if (retry > 1)
6247 msleep(250);
6248 else
6249 msleep(50);
6250 }
6251
6252 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6253 pr_debug("%s: GPIO indicates removal\n", __func__);
6254 break;
6255 }
6256
6257 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
6258 mb_v[i] = tabla_codec_sta_dce(codec, 1, true);
6259 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
6260 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
6261 __func__, retry, mic_mv[i], mb_v[i]);
6262 }
6263
6264 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6265 pr_debug("%s: GPIO indicates removal\n", __func__);
6266 break;
6267 }
6268
6269 if (tabla->current_plug == PLUG_TYPE_NONE) {
6270 pr_debug("%s : headset/headphone is removed\n",
6271 __func__);
6272 break;
6273 }
6274
6275 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
6276 if (!is_valid_mic_voltage(codec, mic_mv[i]))
6277 break;
6278
6279 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6280 pr_debug("%s: MIC voltage settled\n", __func__);
6281 settled = true;
6282 msleep(200);
6283 break;
6284 }
6285
6286 /* only for non-GPIO remove irq */
6287 if (!tabla->mbhc_cfg.gpio) {
6288 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006289 if (mic_mv[i] < v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006290 break;
6291 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6292 pr_debug("%s: Headset is removed\n", __func__);
6293 break;
6294 }
6295 }
6296 }
6297
6298 if (timedout)
6299 pr_debug("%s: Microphone did not settle in %d seconds\n",
6300 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
6301 return settled;
6302}
6303
6304/* called only from interrupt which is under codec_resource_lock acquisition */
6305static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
6306{
6307 struct snd_soc_codec *codec = priv->codec;
6308
6309 if (tabla_hs_remove_settle(codec))
6310 tabla_codec_start_hs_polling(codec);
6311 pr_debug("%s: remove settle done\n", __func__);
6312}
6313
6314/* called only from interrupt which is under codec_resource_lock acquisition */
6315static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006316{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006317 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006318 bool removed = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006319 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08006320 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006321 TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006322 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006323
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006324 if (priv->current_plug != PLUG_TYPE_HEADSET) {
6325 pr_debug("%s(): Headset is not inserted, ignore removal\n",
6326 __func__);
6327 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6328 0x08, 0x08);
6329 return;
6330 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006331
Joonwoo Park0976d012011-12-22 11:48:18 -08006332 usleep_range(generic->t_shutdown_plug_rem,
6333 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006334
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006335 do {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006336 bias_value = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006337 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
6338 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006339 if (bias_value < tabla_get_current_v_ins(priv, false)) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006340 pr_debug("%s: checking false removal\n", __func__);
6341 msleep(500);
6342 removed = !tabla_hs_remove_settle(codec);
6343 pr_debug("%s: headset %sactually removed\n", __func__,
6344 removed ? "" : "not ");
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006345 break;
6346 }
6347 min_us -= priv->mbhc_data.t_dce;
6348 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07006349
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006350 if (removed) {
6351 /* cancel possiblely running hs detect work */
6352 tabla_cancel_hs_detect_plug(priv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006353 /*
6354 * If this removal is not false, first check the micbias
6355 * switch status and switch it to LDOH if it is already
6356 * switched to VDDIO.
6357 */
Joonwoo Park03324832012-03-19 19:36:16 -07006358 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07006359
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006360 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6361 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006362 tabla_codec_enable_hs_detect(codec, 1,
6363 MBHC_USE_MB_TRIGGER |
6364 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07006365 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006366 } else {
6367 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006368 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006369}
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006370
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006371static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
6372{
6373 struct tabla_priv *priv = data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006374 bool vddio;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006375 pr_debug("%s: enter, removal interrupt\n", __func__);
6376
6377 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006378 vddio = (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
6379 priv->mbhc_micbias_switched);
6380 if (vddio)
6381 __tabla_codec_switch_micbias(priv->codec, 0, false, true);
6382
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006383 if (priv->mbhc_cfg.gpio)
6384 tabla_hs_remove_irq_gpio(priv);
6385 else
6386 tabla_hs_remove_irq_nogpio(priv);
6387
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006388 /* if driver turned off vddio switch and headset is not removed,
6389 * turn on the vddio switch back, if headset is removed then vddio
6390 * switch is off by time now and shouldn't be turn on again from here */
6391 if (vddio && priv->current_plug == PLUG_TYPE_HEADSET)
6392 __tabla_codec_switch_micbias(priv->codec, 1, true, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006393 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006394
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006395 return IRQ_HANDLED;
6396}
6397
Joonwoo Park03324832012-03-19 19:36:16 -07006398void mbhc_insert_work(struct work_struct *work)
6399{
6400 struct delayed_work *dwork;
6401 struct tabla_priv *tabla;
6402 struct snd_soc_codec *codec;
6403 struct wcd9xxx *tabla_core;
6404
6405 dwork = to_delayed_work(work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006406 tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
Joonwoo Park03324832012-03-19 19:36:16 -07006407 codec = tabla->codec;
6408 tabla_core = dev_get_drvdata(codec->dev->parent);
6409
6410 pr_debug("%s:\n", __func__);
6411
6412 /* Turn off both HPH and MIC line schmitt triggers */
6413 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6414 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
6415 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6416 wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
6417 tabla_codec_detect_plug_type(codec);
6418 wcd9xxx_unlock_sleep(tabla_core);
6419}
6420
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006421static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
6422{
6423 bool insert;
6424 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6425 bool is_removed = false;
6426
6427 pr_debug("%s: enter\n", __func__);
6428
6429 tabla->in_gpio_handler = true;
6430 /* Wait here for debounce time */
6431 usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
6432 TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
6433
6434 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
6435
6436 /* cancel pending button press */
6437 if (tabla_cancel_btn_work(tabla))
6438 pr_debug("%s: button press is canceled\n", __func__);
6439
6440 insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
6441 tabla->mbhc_cfg.gpio_level_insert);
6442 if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
6443 tabla->lpi_enabled = false;
6444 wmb();
6445
6446 /* cancel detect plug */
6447 tabla_cancel_hs_detect_plug(tabla);
6448
6449 /* Disable Mic Bias pull down and HPH Switch to GND */
6450 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
6451 0x00);
6452 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
6453 tabla_codec_detect_plug_type(codec);
6454 } else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
6455 tabla->lpi_enabled = false;
6456 wmb();
6457
6458 /* cancel detect plug */
6459 tabla_cancel_hs_detect_plug(tabla);
6460
6461 if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
6462 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
6463 is_removed = true;
6464 } else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
6465 tabla_codec_pause_hs_polling(codec);
6466 tabla_codec_cleanup_hs_polling(codec);
6467 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6468 is_removed = true;
6469 }
6470
6471 if (is_removed) {
6472 /* Enable Mic Bias pull down and HPH Switch to GND */
6473 snd_soc_update_bits(codec,
6474 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6475 0x01);
6476 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6477 0x01);
6478 /* Make sure mic trigger is turned off */
6479 snd_soc_update_bits(codec,
6480 tabla->mbhc_bias_regs.ctl_reg,
6481 0x01, 0x01);
6482 snd_soc_update_bits(codec,
6483 tabla->mbhc_bias_regs.mbhc_reg,
6484 0x90, 0x00);
6485 /* Reset MBHC State Machine */
6486 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6487 0x08, 0x08);
6488 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6489 0x08, 0x00);
6490 /* Turn off override */
6491 tabla_turn_onoff_override(codec, false);
6492 }
6493 }
6494
6495 tabla->in_gpio_handler = false;
6496 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6497 pr_debug("%s: leave\n", __func__);
6498}
6499
6500static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
6501{
6502 int r = IRQ_HANDLED;
6503 struct snd_soc_codec *codec = data;
6504
6505 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
6506 pr_warn("%s: failed to hold suspend\n", __func__);
6507 r = IRQ_NONE;
6508 } else {
6509 tabla_hs_gpio_handler(codec);
6510 wcd9xxx_unlock_sleep(codec->control_data);
6511 }
6512
6513 return r;
6514}
6515
6516static void mbhc_fw_read(struct work_struct *work)
6517{
6518 struct delayed_work *dwork;
6519 struct tabla_priv *tabla;
6520 struct snd_soc_codec *codec;
6521 const struct firmware *fw;
6522 int ret = -1, retry = 0, rc;
6523
6524 dwork = to_delayed_work(work);
6525 tabla = container_of(dwork, struct tabla_priv,
6526 mbhc_firmware_dwork);
6527 codec = tabla->codec;
6528
6529 while (retry < MBHC_FW_READ_ATTEMPTS) {
6530 retry++;
6531 pr_info("%s:Attempt %d to request MBHC firmware\n",
6532 __func__, retry);
6533 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
6534 codec->dev);
6535
6536 if (ret != 0) {
6537 usleep_range(MBHC_FW_READ_TIMEOUT,
6538 MBHC_FW_READ_TIMEOUT);
6539 } else {
6540 pr_info("%s: MBHC Firmware read succesful\n", __func__);
6541 break;
6542 }
6543 }
6544
6545 if (ret != 0) {
6546 pr_err("%s: Cannot load MBHC firmware use default cal\n",
6547 __func__);
6548 } else if (tabla_mbhc_fw_validate(fw) == false) {
6549 pr_err("%s: Invalid MBHC cal data size use default cal\n",
6550 __func__);
6551 release_firmware(fw);
6552 } else {
6553 tabla->mbhc_cfg.calibration = (void *)fw->data;
6554 tabla->mbhc_fw = fw;
6555 }
6556
6557 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
6558 tabla_mbhc_init(codec);
6559 tabla_mbhc_cal(codec);
6560 tabla_mbhc_calc_thres(codec);
6561 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
6562 tabla_codec_calibrate_hs_polling(codec);
6563 if (!tabla->mbhc_cfg.gpio) {
6564 tabla->mbhc_inval_hs_range_override = false;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006565 rc = tabla_codec_enable_hs_detect(codec, 1,
6566 MBHC_USE_MB_TRIGGER |
6567 MBHC_USE_HPHL_TRIGGER,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006568 false);
6569
6570 if (IS_ERR_VALUE(rc))
6571 pr_err("%s: Failed to setup MBHC detection\n",
6572 __func__);
6573 } else {
6574 tabla->mbhc_inval_hs_range_override = true;
6575 /* Enable Mic Bias pull down and HPH Switch to GND */
6576 snd_soc_update_bits(codec,
6577 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6578 0x01);
6579 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6580 0x01);
6581 INIT_WORK(&tabla->hs_correct_plug_work,
6582 tabla_hs_correct_gpio_plug);
6583 }
6584
6585}
6586
Joonwoo Park03324832012-03-19 19:36:16 -07006587int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006588 const struct tabla_mbhc_config *cfg)
Joonwoo Park03324832012-03-19 19:36:16 -07006589{
6590 struct tabla_priv *tabla;
6591 int rc = 0;
6592
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006593 if (!codec || !cfg->calibration) {
Joonwoo Park03324832012-03-19 19:36:16 -07006594 pr_err("Error: no codec or calibration\n");
6595 return -EINVAL;
6596 }
6597
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006598 if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
6599 if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Joonwoo Park03324832012-03-19 19:36:16 -07006600 pr_err("Error: clock rate %dHz is not yet supported\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006601 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006602 else
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006603 pr_err("Error: unsupported clock rate %d\n",
6604 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006605 return -EINVAL;
6606 }
6607
6608 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006609 tabla->mbhc_cfg = *cfg;
6610 tabla->in_gpio_handler = false;
6611 tabla->current_plug = PLUG_TYPE_NONE;
6612 tabla->lpi_enabled = false;
Joonwoo Park03324832012-03-19 19:36:16 -07006613 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
6614
6615 /* Put CFILT in fast mode by default */
6616 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
6617 0x40, TABLA_CFILT_FAST_MODE);
6618 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
6619 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
6620 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
6621 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
6622 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
6623
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006624 if (!tabla->mbhc_cfg.read_fw_bin) {
6625 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006626 tabla_mbhc_init(codec);
6627 tabla_mbhc_cal(codec);
6628 tabla_mbhc_calc_thres(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006629 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006630 tabla_codec_calibrate_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006631 if (!tabla->mbhc_cfg.gpio) {
6632 tabla->mbhc_inval_hs_range_override = false;
6633 rc = tabla_codec_enable_hs_detect(codec, 1,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006634 MBHC_USE_MB_TRIGGER |
6635 MBHC_USE_HPHL_TRIGGER,
6636 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006637 } else {
6638 tabla->mbhc_inval_hs_range_override = true;
6639 /* Enable Mic Bias pull down and HPH Switch to GND */
6640 snd_soc_update_bits(codec,
6641 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6642 0x01);
6643 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6644 0x01);
6645 INIT_WORK(&tabla->hs_correct_plug_work,
6646 tabla_hs_correct_gpio_plug);
6647 }
Joonwoo Park03324832012-03-19 19:36:16 -07006648 } else {
6649 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
6650 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
6651 }
6652
6653 if (!IS_ERR_VALUE(rc)) {
6654 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
6655 wcd9xxx_enable_irq(codec->control_data,
6656 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6657 wcd9xxx_enable_irq(codec->control_data,
6658 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6659 }
6660
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006661 if (!IS_ERR_VALUE(rc) && tabla->mbhc_cfg.gpio) {
6662 rc = request_threaded_irq(tabla->mbhc_cfg.gpio_irq, NULL,
6663 tabla_mechanical_plug_detect_irq,
6664 (IRQF_TRIGGER_RISING |
6665 IRQF_TRIGGER_FALLING),
6666 "tabla-gpio", codec);
6667 if (!IS_ERR_VALUE(rc)) {
6668 rc = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
6669 /* Bootup time detection */
6670 tabla_hs_gpio_handler(codec);
6671 }
6672 }
6673
Joonwoo Park03324832012-03-19 19:36:16 -07006674 return rc;
6675}
6676EXPORT_SYMBOL_GPL(tabla_hs_detect);
6677
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006678static unsigned long slimbus_value;
6679
6680static irqreturn_t tabla_slimbus_irq(int irq, void *data)
6681{
6682 struct tabla_priv *priv = data;
6683 struct snd_soc_codec *codec = priv->codec;
6684 int i, j;
6685 u8 val;
6686
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306687 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
6688 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006689 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
6690 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306691 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006692 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
6693 if (val & 0x1)
6694 pr_err_ratelimited("overflow error on port %x,"
6695 " value %x\n", i*8 + j, val);
6696 if (val & 0x2)
6697 pr_err_ratelimited("underflow error on port %x,"
6698 " value %x\n", i*8 + j, val);
6699 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306700 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006701 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
6702 }
6703
6704 return IRQ_HANDLED;
6705}
6706
Patrick Lai3043fba2011-08-01 14:15:57 -07006707
6708static int tabla_handle_pdata(struct tabla_priv *tabla)
6709{
6710 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306711 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07006712 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05306713 u8 leg_mode = pdata->amic_settings.legacy_mode;
6714 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
6715 u8 txfe_buff = pdata->amic_settings.txfe_buff;
6716 u8 flag = pdata->amic_settings.use_pdata;
6717 u8 i = 0, j = 0;
6718 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07006719
6720 if (!pdata) {
6721 rc = -ENODEV;
6722 goto done;
6723 }
6724
6725 /* Make sure settings are correct */
6726 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
6727 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
6728 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
6729 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
6730 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
6731 rc = -EINVAL;
6732 goto done;
6733 }
6734
6735 /* figure out k value */
6736 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
6737 pdata->micbias.cfilt1_mv);
6738 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
6739 pdata->micbias.cfilt2_mv);
6740 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
6741 pdata->micbias.cfilt3_mv);
6742
6743 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
6744 rc = -EINVAL;
6745 goto done;
6746 }
6747
6748 /* Set voltage level and always use LDO */
6749 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
6750 (pdata->micbias.ldoh_v << 2));
6751
6752 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
6753 (k1 << 2));
6754 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
6755 (k2 << 2));
6756 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
6757 (k3 << 2));
6758
6759 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
6760 (pdata->micbias.bias1_cfilt_sel << 5));
6761 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
6762 (pdata->micbias.bias2_cfilt_sel << 5));
6763 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
6764 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006765 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
6766 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07006767
Santosh Mardi22920282011-10-26 02:38:40 +05306768 for (i = 0; i < 6; j++, i += 2) {
6769 if (flag & (0x01 << i)) {
6770 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
6771 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
6772 val_txfe = val_txfe |
6773 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
6774 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6775 0x10, value);
6776 snd_soc_update_bits(codec,
6777 TABLA_A_TX_1_2_TEST_EN + j * 10,
6778 0x30, val_txfe);
6779 }
6780 if (flag & (0x01 << (i + 1))) {
6781 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
6782 val_txfe = (txfe_bypass &
6783 (0x01 << (i + 1))) ? 0x02 : 0x00;
6784 val_txfe |= (txfe_buff &
6785 (0x01 << (i + 1))) ? 0x01 : 0x00;
6786 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6787 0x01, value);
6788 snd_soc_update_bits(codec,
6789 TABLA_A_TX_1_2_TEST_EN + j * 10,
6790 0x03, val_txfe);
6791 }
6792 }
6793 if (flag & 0x40) {
6794 value = (leg_mode & 0x40) ? 0x10 : 0x00;
6795 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
6796 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
6797 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
6798 0x13, value);
6799 }
Patrick Lai49efeac2011-11-03 11:01:12 -07006800
6801 if (pdata->ocp.use_pdata) {
6802 /* not defined in CODEC specification */
6803 if (pdata->ocp.hph_ocp_limit == 1 ||
6804 pdata->ocp.hph_ocp_limit == 5) {
6805 rc = -EINVAL;
6806 goto done;
6807 }
6808 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
6809 0x0F, pdata->ocp.num_attempts);
6810 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
6811 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
6812 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
6813 0xE0, (pdata->ocp.hph_ocp_limit << 5));
6814 }
Joonwoo Park03324832012-03-19 19:36:16 -07006815
6816 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
6817 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
6818 if (pdata->regulator[i].min_uV == 1800000 &&
6819 pdata->regulator[i].max_uV == 1800000) {
6820 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6821 0x1C);
6822 } else if (pdata->regulator[i].min_uV == 2200000 &&
6823 pdata->regulator[i].max_uV == 2200000) {
6824 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6825 0x1E);
6826 } else {
6827 pr_err("%s: unsupported CDC_VDDA_RX voltage "
6828 "min %d, max %d\n", __func__,
6829 pdata->regulator[i].min_uV,
6830 pdata->regulator[i].max_uV);
6831 rc = -EINVAL;
6832 }
6833 break;
6834 }
6835 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006836done:
6837 return rc;
6838}
6839
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006840static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
6841
6842 /* Tabla 1.1 MICBIAS changes */
6843 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
6844 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
6845 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006846
6847 /* Tabla 1.1 HPH changes */
6848 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
6849 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
6850
6851 /* Tabla 1.1 EAR PA changes */
6852 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
6853 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
6854 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
6855
6856 /* Tabla 1.1 Lineout_5 Changes */
6857 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
6858
6859 /* Tabla 1.1 RX Changes */
6860 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
6861 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
6862 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
6863 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
6864 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
6865 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
6866 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
6867
6868 /* Tabla 1.1 RX1 and RX2 Changes */
6869 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
6870 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
6871
6872 /* Tabla 1.1 RX3 to RX7 Changes */
6873 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
6874 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
6875 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
6876 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
6877 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
6878
6879 /* Tabla 1.1 CLASSG Changes */
6880 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
6881};
6882
6883static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006884 /* Tabla 2.0 MICBIAS changes */
6885 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
6886};
6887
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006888static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
6889 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
6890};
6891
6892static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
6893 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
6894};
6895
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006896static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
6897{
6898 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306899 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006900
6901 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
6902 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
6903 tabla_1_1_reg_defaults[i].val);
6904
6905 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
6906 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
6907 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006908
6909 if (TABLA_IS_1_X(tabla_core->version)) {
6910 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
6911 i++)
6912 snd_soc_write(codec,
6913 tabla_1_x_only_reg_2_0_defaults[i].reg,
6914 tabla_1_x_only_reg_2_0_defaults[i].val);
6915 } else {
6916 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
6917 snd_soc_write(codec,
6918 tabla_2_only_reg_2_0_defaults[i].reg,
6919 tabla_2_only_reg_2_0_defaults[i].val);
6920 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006921}
6922
6923static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08006924 /* Initialize current threshold to 350MA
6925 * number of wait and run cycles to 4096
6926 */
Patrick Lai49efeac2011-11-03 11:01:12 -07006927 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08006928 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006929
Santosh Mardi32171012011-10-28 23:32:06 +05306930 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
6931
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006932 /* Initialize gain registers to use register gain */
6933 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
6934 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
6935 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
6936 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
6937 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
6938 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
6939
6940 /* Initialize mic biases to differential mode */
6941 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
6942 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
6943 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006944
6945 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
6946
6947 /* Use 16 bit sample size for TX1 to TX6 */
6948 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
6949 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
6950 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
6951 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
6952 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
6953 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
6954
6955 /* Use 16 bit sample size for TX7 to TX10 */
6956 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
6957 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
6958 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
6959 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
6960
6961 /* Use 16 bit sample size for RX */
6962 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
6963 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
6964
6965 /*enable HPF filter for TX paths */
6966 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
6967 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
6968 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
6969 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
6970 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
6971 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
6972 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
6973 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
6974 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
6975 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
6976};
6977
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006978static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
6979 /* Initialize mic biases to differential mode */
6980 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6981};
6982
6983static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
6984 /* Initialize mic biases to differential mode */
6985 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6986};
6987
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006988static void tabla_codec_init_reg(struct snd_soc_codec *codec)
6989{
6990 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306991 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006992
6993 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
6994 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
6995 tabla_codec_reg_init_val[i].mask,
6996 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006997 if (TABLA_IS_1_X(tabla_core->version)) {
6998 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
6999 snd_soc_update_bits(codec,
7000 tabla_1_x_codec_reg_init_val[i].reg,
7001 tabla_1_x_codec_reg_init_val[i].mask,
7002 tabla_1_x_codec_reg_init_val[i].val);
7003 } else {
7004 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
7005 i++)
7006 snd_soc_update_bits(codec,
7007 tabla_2_higher_codec_reg_init_val[i].reg,
7008 tabla_2_higher_codec_reg_init_val[i].mask,
7009 tabla_2_higher_codec_reg_init_val[i].val);
7010 }
7011}
7012
7013static void tabla_update_reg_address(struct tabla_priv *priv)
7014{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307015 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007016 struct tabla_reg_address *reg_addr = &priv->reg_addr;
7017
7018 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08007019 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
7020 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007021 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007022 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08007023 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
7024 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007025 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007026 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007027}
7028
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007029#ifdef CONFIG_DEBUG_FS
7030static int codec_debug_open(struct inode *inode, struct file *file)
7031{
7032 file->private_data = inode->i_private;
7033 return 0;
7034}
7035
7036static ssize_t codec_debug_write(struct file *filp,
7037 const char __user *ubuf, size_t cnt, loff_t *ppos)
7038{
7039 char lbuf[32];
7040 char *buf;
7041 int rc;
7042 struct tabla_priv *tabla = filp->private_data;
7043
7044 if (cnt > sizeof(lbuf) - 1)
7045 return -EINVAL;
7046
7047 rc = copy_from_user(lbuf, ubuf, cnt);
7048 if (rc)
7049 return -EFAULT;
7050
7051 lbuf[cnt] = '\0';
7052 buf = (char *)lbuf;
7053 tabla->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
7054 false : true;
7055 return rc;
7056}
7057
7058static ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
7059 size_t count, loff_t *pos)
7060{
7061 const int size = 768;
7062 char buffer[size];
7063 int n = 0;
7064 struct tabla_priv *tabla = file->private_data;
7065 struct snd_soc_codec *codec = tabla->codec;
7066 const struct mbhc_internal_cal_data *p = &tabla->mbhc_data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007067 const s16 v_ins_hu_cur = tabla_get_current_v_ins(tabla, true);
7068 const s16 v_ins_h_cur = tabla_get_current_v_ins(tabla, false);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007069
7070 n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
7071 tabla_codec_sta_dce_v(codec, 1, p->dce_z));
7072 n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
7073 p->dce_mb, tabla_codec_sta_dce_v(codec, 1, p->dce_mb));
7074 n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
7075 p->sta_z, tabla_codec_sta_dce_v(codec, 0, p->sta_z));
7076 n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
7077 p->sta_mb, tabla_codec_sta_dce_v(codec, 0, p->sta_mb));
7078 n += scnprintf(buffer + n, size - n, "t_dce = %x\n", p->t_dce);
7079 n += scnprintf(buffer + n, size - n, "t_sta = %x\n", p->t_sta);
7080 n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
7081 p->micb_mv);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007082 n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007083 p->v_ins_hu,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007084 tabla_codec_sta_dce_v(codec, 0, p->v_ins_hu),
7085 p->v_ins_hu == v_ins_hu_cur ? "*" : "");
7086 n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
7087 p->v_ins_h, tabla_codec_sta_dce_v(codec, 1, p->v_ins_h),
7088 p->v_ins_h == v_ins_h_cur ? "*" : "");
7089 n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
7090 p->adj_v_ins_hu,
7091 tabla_codec_sta_dce_v(codec, 0, p->adj_v_ins_hu),
7092 p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
7093 n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
7094 p->adj_v_ins_h,
7095 tabla_codec_sta_dce_v(codec, 1, p->adj_v_ins_h),
7096 p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007097 n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
7098 p->v_b1_hu, tabla_codec_sta_dce_v(codec, 0, p->v_b1_hu));
7099 n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
7100 p->v_b1_h, tabla_codec_sta_dce_v(codec, 1, p->v_b1_h));
7101 n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
7102 p->v_b1_huc,
7103 tabla_codec_sta_dce_v(codec, 1, p->v_b1_huc));
7104 n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
7105 p->v_brh, tabla_codec_sta_dce_v(codec, 1, p->v_brh));
7106 n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
7107 tabla_codec_sta_dce_v(codec, 0, p->v_brl));
7108 n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
7109 p->v_no_mic,
7110 tabla_codec_sta_dce_v(codec, 0, p->v_no_mic));
7111 n += scnprintf(buffer + n, size - n, "npoll = %d\n", p->npoll);
7112 n += scnprintf(buffer + n, size - n, "nbounce_wait = %d\n",
7113 p->nbounce_wait);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007114 n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
7115 p->v_inval_ins_low);
7116 n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
7117 p->v_inval_ins_high);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007118 buffer[n] = 0;
7119
7120 return simple_read_from_buffer(buf, count, pos, buffer, n);
7121}
7122
7123static const struct file_operations codec_debug_ops = {
7124 .open = codec_debug_open,
7125 .write = codec_debug_write,
7126};
7127
7128static const struct file_operations codec_mbhc_debug_ops = {
7129 .open = codec_debug_open,
7130 .read = codec_mbhc_debug_read,
7131};
7132#endif
7133
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007134static int tabla_codec_probe(struct snd_soc_codec *codec)
7135{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307136 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007137 struct tabla_priv *tabla;
7138 struct snd_soc_dapm_context *dapm = &codec->dapm;
7139 int ret = 0;
7140 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007141 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007142
7143 codec->control_data = dev_get_drvdata(codec->dev->parent);
7144 control = codec->control_data;
7145
7146 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
7147 if (!tabla) {
7148 dev_err(codec->dev, "Failed to allocate private data\n");
7149 return -ENOMEM;
7150 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08007151 for (i = 0 ; i < NUM_DECIMATORS; i++) {
7152 tx_hpf_work[i].tabla = tabla;
7153 tx_hpf_work[i].decimator = i + 1;
7154 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
7155 tx_hpf_corner_freq_callback);
7156 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007157
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07007158 /* Make sure mbhc micbias register addresses are zeroed out */
7159 memset(&tabla->mbhc_bias_regs, 0,
7160 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07007161 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07007162
Joonwoo Park0976d012011-12-22 11:48:18 -08007163 /* Make sure mbhc intenal calibration data is zeroed out */
7164 memset(&tabla->mbhc_data, 0,
7165 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08007166 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08007167 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
7168 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007169 snd_soc_codec_set_drvdata(codec, tabla);
7170
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07007171 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007172 tabla->bandgap_type = TABLA_BANDGAP_OFF;
7173 tabla->clock_active = false;
7174 tabla->config_mode_active = false;
7175 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08007176 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07007177 tabla->no_mic_headset_override = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007178 tabla->hs_polling_irq_prepared = false;
7179 mutex_init(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007180 tabla->codec = codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007181 tabla->mbhc_state = MBHC_STATE_NONE;
Joonwoo Park03324832012-03-19 19:36:16 -07007182 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08007183 for (i = 0; i < COMPANDER_MAX; i++) {
7184 tabla->comp_enabled[i] = 0;
7185 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
7186 }
Patrick Lai3043fba2011-08-01 14:15:57 -07007187 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307188 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08007189 tabla->aux_pga_cnt = 0;
7190 tabla->aux_l_gain = 0x1F;
7191 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007192 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05307193 tabla_update_reg_defaults(codec);
7194 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05307195 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07007196 if (IS_ERR_VALUE(ret)) {
7197 pr_err("%s: bad pdata\n", __func__);
7198 goto err_pdata;
7199 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007200
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007201 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007202 ARRAY_SIZE(tabla_snd_controls));
7203 if (TABLA_IS_1_X(control->version))
7204 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
7205 ARRAY_SIZE(tabla_1_x_snd_controls));
7206 else
7207 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
7208 ARRAY_SIZE(tabla_2_higher_snd_controls));
7209
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007210 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007211 ARRAY_SIZE(tabla_dapm_widgets));
7212 if (TABLA_IS_1_X(control->version))
7213 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
7214 ARRAY_SIZE(tabla_1_x_dapm_widgets));
7215 else
7216 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
7217 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
7218
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307219 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05307220 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
7221 ARRAY_SIZE(tabla_dapm_i2s_widgets));
7222 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
7223 ARRAY_SIZE(audio_i2s_map));
7224 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007225 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07007226
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007227 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007228 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007229 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
7230 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007231 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007232 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007233 } else {
7234 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307235 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007236 goto err_pdata;
7237 }
7238
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007239 snd_soc_dapm_sync(dapm);
7240
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307241 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007242 tabla_hs_insert_irq, "Headset insert detect", tabla);
7243 if (ret) {
7244 pr_err("%s: Failed to request irq %d\n", __func__,
7245 TABLA_IRQ_MBHC_INSERTION);
7246 goto err_insert_irq;
7247 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307248 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007249
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307250 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007251 tabla_hs_remove_irq, "Headset remove detect", tabla);
7252 if (ret) {
7253 pr_err("%s: Failed to request irq %d\n", __func__,
7254 TABLA_IRQ_MBHC_REMOVAL);
7255 goto err_remove_irq;
7256 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007257
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307258 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007259 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007260 if (ret) {
7261 pr_err("%s: Failed to request irq %d\n", __func__,
7262 TABLA_IRQ_MBHC_POTENTIAL);
7263 goto err_potential_irq;
7264 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007265
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307266 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007267 tabla_release_handler, "Button Release detect", tabla);
7268 if (ret) {
7269 pr_err("%s: Failed to request irq %d\n", __func__,
7270 TABLA_IRQ_MBHC_RELEASE);
7271 goto err_release_irq;
7272 }
7273
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307274 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007275 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
7276 if (ret) {
7277 pr_err("%s: Failed to request irq %d\n", __func__,
7278 TABLA_IRQ_SLIMBUS);
7279 goto err_slimbus_irq;
7280 }
7281
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307282 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
7283 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007284 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
7285
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307286 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007287 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
7288 "HPH_L OCP detect", tabla);
7289 if (ret) {
7290 pr_err("%s: Failed to request irq %d\n", __func__,
7291 TABLA_IRQ_HPH_PA_OCPL_FAULT);
7292 goto err_hphl_ocp_irq;
7293 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307294 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07007295
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307296 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007297 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
7298 "HPH_R OCP detect", tabla);
7299 if (ret) {
7300 pr_err("%s: Failed to request irq %d\n", __func__,
7301 TABLA_IRQ_HPH_PA_OCPR_FAULT);
7302 goto err_hphr_ocp_irq;
7303 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307304 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007305 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
7306 switch (tabla_dai[i].id) {
7307 case AIF1_PB:
7308 ch_cnt = tabla_dai[i].playback.channels_max;
7309 break;
7310 case AIF1_CAP:
7311 ch_cnt = tabla_dai[i].capture.channels_max;
7312 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08007313 case AIF2_PB:
7314 ch_cnt = tabla_dai[i].playback.channels_max;
7315 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007316 default:
7317 continue;
7318 }
7319 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
7320 ch_cnt), GFP_KERNEL);
7321 }
Patrick Lai49efeac2011-11-03 11:01:12 -07007322
Bradley Rubincb3950a2011-08-18 13:07:26 -07007323#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007324 if (ret == 0) {
7325 tabla->debugfs_poke =
7326 debugfs_create_file("TRRS", S_IFREG | S_IRUGO, NULL, tabla,
7327 &codec_debug_ops);
7328 tabla->debugfs_mbhc =
7329 debugfs_create_file("tabla_mbhc", S_IFREG | S_IRUGO,
7330 NULL, tabla, &codec_mbhc_debug_ops);
7331 }
Bradley Rubincb3950a2011-08-18 13:07:26 -07007332#endif
7333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007334 return ret;
7335
Patrick Lai49efeac2011-11-03 11:01:12 -07007336err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307337 wcd9xxx_free_irq(codec->control_data,
7338 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07007339err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307340 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007341err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307342 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07007343err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307344 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007345err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307346 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007347err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307348 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007349err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07007350err_pdata:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007351 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007352 kfree(tabla);
7353 return ret;
7354}
7355static int tabla_codec_remove(struct snd_soc_codec *codec)
7356{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007357 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007358 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307359 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
7360 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
7361 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
7362 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
7363 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007364 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007365 tabla_codec_disable_clock_block(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007366 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007367 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08007368 if (tabla->mbhc_fw)
7369 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007370 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
7371 kfree(tabla->dai[i].ch_num);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007372 mutex_destroy(&tabla->codec_resource_lock);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007373#ifdef CONFIG_DEBUG_FS
7374 debugfs_remove(tabla->debugfs_poke);
7375 debugfs_remove(tabla->debugfs_mbhc);
7376#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007377 kfree(tabla);
7378 return 0;
7379}
7380static struct snd_soc_codec_driver soc_codec_dev_tabla = {
7381 .probe = tabla_codec_probe,
7382 .remove = tabla_codec_remove,
7383 .read = tabla_read,
7384 .write = tabla_write,
7385
7386 .readable_register = tabla_readable,
7387 .volatile_register = tabla_volatile,
7388
7389 .reg_cache_size = TABLA_CACHE_SIZE,
7390 .reg_cache_default = tabla_reg_defaults,
7391 .reg_word_size = 1,
7392};
Bradley Rubincb3950a2011-08-18 13:07:26 -07007393
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007394#ifdef CONFIG_PM
7395static int tabla_suspend(struct device *dev)
7396{
Joonwoo Park816b8e62012-01-23 16:03:21 -08007397 dev_dbg(dev, "%s: system suspend\n", __func__);
7398 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007399}
7400
7401static int tabla_resume(struct device *dev)
7402{
Joonwoo Park03324832012-03-19 19:36:16 -07007403 struct platform_device *pdev = to_platform_device(dev);
7404 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Park816b8e62012-01-23 16:03:21 -08007405 dev_dbg(dev, "%s: system resume\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07007406 tabla->mbhc_last_resume = jiffies;
Joonwoo Park816b8e62012-01-23 16:03:21 -08007407 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007408}
7409
7410static const struct dev_pm_ops tabla_pm_ops = {
7411 .suspend = tabla_suspend,
7412 .resume = tabla_resume,
7413};
7414#endif
7415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007416static int __devinit tabla_probe(struct platform_device *pdev)
7417{
Santosh Mardie15e2302011-11-15 10:39:23 +05307418 int ret = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307419 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05307420 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7421 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307422 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05307423 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7424 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
7425 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007426}
7427static int __devexit tabla_remove(struct platform_device *pdev)
7428{
7429 snd_soc_unregister_codec(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007430 return 0;
7431}
7432static struct platform_driver tabla_codec_driver = {
7433 .probe = tabla_probe,
7434 .remove = tabla_remove,
7435 .driver = {
7436 .name = "tabla_codec",
7437 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007438#ifdef CONFIG_PM
7439 .pm = &tabla_pm_ops,
7440#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007441 },
7442};
7443
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007444static struct platform_driver tabla1x_codec_driver = {
7445 .probe = tabla_probe,
7446 .remove = tabla_remove,
7447 .driver = {
7448 .name = "tabla1x_codec",
7449 .owner = THIS_MODULE,
7450#ifdef CONFIG_PM
7451 .pm = &tabla_pm_ops,
7452#endif
7453 },
7454};
7455
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007456static int __init tabla_codec_init(void)
7457{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007458 int rtn = platform_driver_register(&tabla_codec_driver);
7459 if (rtn == 0) {
7460 rtn = platform_driver_register(&tabla1x_codec_driver);
7461 if (rtn != 0)
7462 platform_driver_unregister(&tabla_codec_driver);
7463 }
7464 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007465}
7466
7467static void __exit tabla_codec_exit(void)
7468{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007469 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007470 platform_driver_unregister(&tabla_codec_driver);
7471}
7472
7473module_init(tabla_codec_init);
7474module_exit(tabla_codec_exit);
7475
7476MODULE_DESCRIPTION("Tabla codec driver");
7477MODULE_VERSION("1.0");
7478MODULE_LICENSE("GPL v2");