blob: 67883222c1c8a820f499d09e44c244430c9895af [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700357static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
358 struct snd_kcontrol *kcontrol, int event)
359{
360 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700361
362 pr_debug("%s %d\n", __func__, event);
363 switch (event) {
364 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700365 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
366 0x01);
367 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
368 usleep_range(200, 200);
369 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
370 break;
371 case SND_SOC_DAPM_PRE_PMD:
372 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
373 0x10);
374 usleep_range(20, 20);
375 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
376 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
377 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
378 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
379 0x00);
380 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 break;
382 }
383 return 0;
384}
385
Bradley Rubina7096d02011-08-03 18:29:02 -0700386static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
387 struct snd_ctl_elem_value *ucontrol)
388{
389 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
390 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
391 ucontrol->value.integer.value[0] = tabla->anc_slot;
392 return 0;
393}
394
395static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
396 struct snd_ctl_elem_value *ucontrol)
397{
398 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
399 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
400 tabla->anc_slot = ucontrol->value.integer.value[0];
401 return 0;
402}
403
Kiran Kandid2d86b52011-09-09 17:44:28 -0700404static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
405 struct snd_ctl_elem_value *ucontrol)
406{
407 u8 ear_pa_gain;
408 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
409
410 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
411
412 ear_pa_gain = ear_pa_gain >> 5;
413
414 if (ear_pa_gain == 0x00) {
415 ucontrol->value.integer.value[0] = 0;
416 } else if (ear_pa_gain == 0x04) {
417 ucontrol->value.integer.value[0] = 1;
418 } else {
419 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
420 __func__, ear_pa_gain);
421 return -EINVAL;
422 }
423
424 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
425
426 return 0;
427}
428
429static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
430 struct snd_ctl_elem_value *ucontrol)
431{
432 u8 ear_pa_gain;
433 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
434
435 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
436 ucontrol->value.integer.value[0]);
437
438 switch (ucontrol->value.integer.value[0]) {
439 case 0:
440 ear_pa_gain = 0x00;
441 break;
442 case 1:
443 ear_pa_gain = 0x80;
444 break;
445 default:
446 return -EINVAL;
447 }
448
449 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
450 return 0;
451}
452
Ben Romberger1f045a72011-11-04 10:14:57 -0700453static int tabla_get_iir_enable_audio_mixer(
454 struct snd_kcontrol *kcontrol,
455 struct snd_ctl_elem_value *ucontrol)
456{
457 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
458 int iir_idx = ((struct soc_multi_mixer_control *)
459 kcontrol->private_value)->reg;
460 int band_idx = ((struct soc_multi_mixer_control *)
461 kcontrol->private_value)->shift;
462
463 ucontrol->value.integer.value[0] =
464 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
465 (1 << band_idx);
466
467 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
468 iir_idx, band_idx,
469 (uint32_t)ucontrol->value.integer.value[0]);
470 return 0;
471}
472
473static int tabla_put_iir_enable_audio_mixer(
474 struct snd_kcontrol *kcontrol,
475 struct snd_ctl_elem_value *ucontrol)
476{
477 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
478 int iir_idx = ((struct soc_multi_mixer_control *)
479 kcontrol->private_value)->reg;
480 int band_idx = ((struct soc_multi_mixer_control *)
481 kcontrol->private_value)->shift;
482 int value = ucontrol->value.integer.value[0];
483
484 /* Mask first 5 bits, 6-8 are reserved */
485 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
486 (1 << band_idx), (value << band_idx));
487
488 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
489 iir_idx, band_idx, value);
490 return 0;
491}
492static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
493 int iir_idx, int band_idx,
494 int coeff_idx)
495{
496 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800497 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700498 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800499 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700500
501 /* Mask bits top 2 bits since they are reserved */
502 return ((snd_soc_read(codec,
503 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
504 (snd_soc_read(codec,
505 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
506 (snd_soc_read(codec,
507 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
508 (snd_soc_read(codec,
509 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
510 0x3FFFFFFF;
511}
512
513static int tabla_get_iir_band_audio_mixer(
514 struct snd_kcontrol *kcontrol,
515 struct snd_ctl_elem_value *ucontrol)
516{
517 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
518 int iir_idx = ((struct soc_multi_mixer_control *)
519 kcontrol->private_value)->reg;
520 int band_idx = ((struct soc_multi_mixer_control *)
521 kcontrol->private_value)->shift;
522
523 ucontrol->value.integer.value[0] =
524 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
525 ucontrol->value.integer.value[1] =
526 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
527 ucontrol->value.integer.value[2] =
528 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
529 ucontrol->value.integer.value[3] =
530 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
531 ucontrol->value.integer.value[4] =
532 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
533
534 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
535 "%s: IIR #%d band #%d b1 = 0x%x\n"
536 "%s: IIR #%d band #%d b2 = 0x%x\n"
537 "%s: IIR #%d band #%d a1 = 0x%x\n"
538 "%s: IIR #%d band #%d a2 = 0x%x\n",
539 __func__, iir_idx, band_idx,
540 (uint32_t)ucontrol->value.integer.value[0],
541 __func__, iir_idx, band_idx,
542 (uint32_t)ucontrol->value.integer.value[1],
543 __func__, iir_idx, band_idx,
544 (uint32_t)ucontrol->value.integer.value[2],
545 __func__, iir_idx, band_idx,
546 (uint32_t)ucontrol->value.integer.value[3],
547 __func__, iir_idx, band_idx,
548 (uint32_t)ucontrol->value.integer.value[4]);
549 return 0;
550}
551
552static void set_iir_band_coeff(struct snd_soc_codec *codec,
553 int iir_idx, int band_idx,
554 int coeff_idx, uint32_t value)
555{
556 /* Mask top 3 bits, 6-8 are reserved */
557 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800558 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700559 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800560 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700561
562 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800563 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700564 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800565 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700566
567 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800568 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700569 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800570 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700571
Ben Romberger0915aae2012-02-06 23:32:43 -0800572 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700573 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800574 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700575
Ben Romberger0915aae2012-02-06 23:32:43 -0800576 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700577 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800578 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700579}
580
581static int tabla_put_iir_band_audio_mixer(
582 struct snd_kcontrol *kcontrol,
583 struct snd_ctl_elem_value *ucontrol)
584{
585 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
586 int iir_idx = ((struct soc_multi_mixer_control *)
587 kcontrol->private_value)->reg;
588 int band_idx = ((struct soc_multi_mixer_control *)
589 kcontrol->private_value)->shift;
590
591 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
592 ucontrol->value.integer.value[0]);
593 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
594 ucontrol->value.integer.value[1]);
595 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
596 ucontrol->value.integer.value[2]);
597 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
598 ucontrol->value.integer.value[3]);
599 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
600 ucontrol->value.integer.value[4]);
601
602 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
603 "%s: IIR #%d band #%d b1 = 0x%x\n"
604 "%s: IIR #%d band #%d b2 = 0x%x\n"
605 "%s: IIR #%d band #%d a1 = 0x%x\n"
606 "%s: IIR #%d band #%d a2 = 0x%x\n",
607 __func__, iir_idx, band_idx,
608 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
609 __func__, iir_idx, band_idx,
610 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
611 __func__, iir_idx, band_idx,
612 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
613 __func__, iir_idx, band_idx,
614 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
615 __func__, iir_idx, band_idx,
616 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
617 return 0;
618}
619
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800620static int tabla_compander_gain_offset(
621 struct snd_soc_codec *codec, u32 enable,
622 unsigned int reg, int mask, int event)
623{
624 int pa_mode = snd_soc_read(codec, reg) & mask;
625 int gain_offset = 0;
626 /* if PMU && enable is 1-> offset is 3
627 * if PMU && enable is 0-> offset is 0
628 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
629 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
630 */
631
632 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
633 gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
634 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
635 gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
636 return gain_offset;
637}
638
639
640static int tabla_config_gain_compander(
641 struct snd_soc_codec *codec,
642 u32 compander, u32 enable, int event)
643{
644 int value = 0;
645 int mask = 1 << 4;
646 int gain = 0;
647 int gain_offset;
648 if (compander >= COMPANDER_MAX) {
649 pr_err("%s: Error, invalid compander channel\n", __func__);
650 return -EINVAL;
651 }
652
653 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
654 value = 1 << 4;
655
656 if (compander == COMPANDER_1) {
657 gain_offset = tabla_compander_gain_offset(codec, enable,
658 TABLA_A_RX_HPH_L_GAIN, mask, event);
659 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
660 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
661 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
662 0xFF, gain - gain_offset);
663 gain_offset = tabla_compander_gain_offset(codec, enable,
664 TABLA_A_RX_HPH_R_GAIN, mask, event);
665 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
666 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
667 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
668 0xFF, gain - gain_offset);
669 } else if (compander == COMPANDER_2) {
670 gain_offset = tabla_compander_gain_offset(codec, enable,
671 TABLA_A_RX_LINE_1_GAIN, mask, event);
672 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
673 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
674 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
675 0xFF, gain - gain_offset);
676 gain_offset = tabla_compander_gain_offset(codec, enable,
677 TABLA_A_RX_LINE_3_GAIN, mask, event);
678 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
679 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
680 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
681 0xFF, gain - gain_offset);
682 gain_offset = tabla_compander_gain_offset(codec, enable,
683 TABLA_A_RX_LINE_2_GAIN, mask, event);
684 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
685 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
686 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
687 0xFF, gain - gain_offset);
688 gain_offset = tabla_compander_gain_offset(codec, enable,
689 TABLA_A_RX_LINE_4_GAIN, mask, event);
690 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
691 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
692 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
693 0xFF, gain - gain_offset);
694 }
695 return 0;
696}
697static int tabla_get_compander(struct snd_kcontrol *kcontrol,
698 struct snd_ctl_elem_value *ucontrol)
699{
700
701 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
702 int comp = ((struct soc_multi_mixer_control *)
703 kcontrol->private_value)->max;
704 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
705
706 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
707
708 return 0;
709}
710
711static int tabla_set_compander(struct snd_kcontrol *kcontrol,
712 struct snd_ctl_elem_value *ucontrol)
713{
714 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
715 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
716 int comp = ((struct soc_multi_mixer_control *)
717 kcontrol->private_value)->max;
718 int value = ucontrol->value.integer.value[0];
719
720 if (value == tabla->comp_enabled[comp]) {
721 pr_debug("%s: compander #%d enable %d no change\n",
722 __func__, comp, value);
723 return 0;
724 }
725 tabla->comp_enabled[comp] = value;
726 return 0;
727}
728
729
730static int tabla_config_compander(struct snd_soc_dapm_widget *w,
731 struct snd_kcontrol *kcontrol,
732 int event)
733{
734 struct snd_soc_codec *codec = w->codec;
735 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
736 u32 rate = tabla->comp_fs[w->shift];
737
738 switch (event) {
739 case SND_SOC_DAPM_PRE_PMU:
740 if (tabla->comp_enabled[w->shift] != 0) {
741 /* Enable both L/R compander clocks */
742 snd_soc_update_bits(codec,
743 TABLA_A_CDC_CLK_RX_B2_CTL,
744 0x03 << comp_shift[w->shift],
745 0x03 << comp_shift[w->shift]);
746 /* Clar the HALT for the compander*/
747 snd_soc_update_bits(codec,
748 TABLA_A_CDC_COMP1_B1_CTL +
749 w->shift * 8, 1 << 2, 0);
750 /* Toggle compander reset bits*/
751 snd_soc_update_bits(codec,
752 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
753 0x03 << comp_shift[w->shift],
754 0x03 << comp_shift[w->shift]);
755 snd_soc_update_bits(codec,
756 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
757 0x03 << comp_shift[w->shift], 0);
758 tabla_config_gain_compander(codec, w->shift, 1, event);
759 /* Update the RMS meter resampling*/
760 snd_soc_update_bits(codec,
761 TABLA_A_CDC_COMP1_B3_CTL +
762 w->shift * 8, 0xFF, 0x01);
763 /* Wait for 1ms*/
764 usleep_range(1000, 1000);
765 }
766 break;
767 case SND_SOC_DAPM_POST_PMU:
768 /* Set sample rate dependent paramater*/
769 if (tabla->comp_enabled[w->shift] != 0) {
770 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
771 w->shift * 8, 0x03, rate);
772 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
773 w->shift * 8, 0x0F,
774 comp_samp_params[rate].peak_det_timeout);
775 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
776 w->shift * 8, 0xF0,
777 comp_samp_params[rate].rms_meter_div_fact);
778 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
779 w->shift * 8, 0xFF,
780 comp_samp_params[rate].rms_meter_resamp_fact);
781 /* Compander enable -> 0x370/0x378*/
782 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
783 w->shift * 8, 0x03, 0x03);
784 }
785 break;
786 case SND_SOC_DAPM_PRE_PMD:
787 /* Halt the compander*/
788 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
789 w->shift * 8, 1 << 2, 1 << 2);
790 break;
791 case SND_SOC_DAPM_POST_PMD:
792 /* Restore the gain */
793 tabla_config_gain_compander(codec, w->shift,
794 tabla->comp_enabled[w->shift], event);
795 /* Disable the compander*/
796 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
797 w->shift * 8, 0x03, 0x00);
798 /* Turn off the clock for compander in pair*/
799 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
800 0x03 << comp_shift[w->shift], 0);
801 break;
802 }
803 return 0;
804}
805
Kiran Kandid2d86b52011-09-09 17:44:28 -0700806static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
807static const struct soc_enum tabla_ear_pa_gain_enum[] = {
808 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
809};
810
Santosh Mardi024010f2011-10-18 06:27:21 +0530811/*cut of frequency for high pass filter*/
812static const char *cf_text[] = {
813 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
814};
815
816static const struct soc_enum cf_dec1_enum =
817 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
818
819static const struct soc_enum cf_dec2_enum =
820 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
821
822static const struct soc_enum cf_dec3_enum =
823 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
824
825static const struct soc_enum cf_dec4_enum =
826 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
827
828static const struct soc_enum cf_dec5_enum =
829 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
830
831static const struct soc_enum cf_dec6_enum =
832 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
833
834static const struct soc_enum cf_dec7_enum =
835 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
836
837static const struct soc_enum cf_dec8_enum =
838 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
839
840static const struct soc_enum cf_dec9_enum =
841 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
842
843static const struct soc_enum cf_dec10_enum =
844 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
845
846static const struct soc_enum cf_rxmix1_enum =
847 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
848
849static const struct soc_enum cf_rxmix2_enum =
850 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
851
852static const struct soc_enum cf_rxmix3_enum =
853 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
854
855static const struct soc_enum cf_rxmix4_enum =
856 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
857
858static const struct soc_enum cf_rxmix5_enum =
859 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
860;
861static const struct soc_enum cf_rxmix6_enum =
862 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
863
864static const struct soc_enum cf_rxmix7_enum =
865 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
866
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700868
869 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
870 tabla_pa_gain_get, tabla_pa_gain_put),
871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700872 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
873 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700874 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
875 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700876 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
877 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700878 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
879 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700880 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
881 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700882
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700883 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
884 line_gain),
885 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
886 line_gain),
887
Bradley Rubin410383f2011-07-22 13:44:23 -0700888 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
889 -84, 40, digital_gain),
890 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
891 -84, 40, digital_gain),
892 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
893 -84, 40, digital_gain),
894 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
895 -84, 40, digital_gain),
896 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
897 -84, 40, digital_gain),
898 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
899 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -0800900 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
901 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902
Bradley Rubin410383f2011-07-22 13:44:23 -0700903 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700905 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700907 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
908 digital_gain),
909 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
910 digital_gain),
911 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
912 digital_gain),
913 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
914 digital_gain),
915 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
916 digital_gain),
917 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
918 digital_gain),
919 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
920 digital_gain),
921 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
922 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700923 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
924 40, digital_gain),
925 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
926 40, digital_gain),
927 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
928 40, digital_gain),
929 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
930 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700931 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
932 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700933 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
934 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700935 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
936 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800938 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
939 aux_pga_gain),
940 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
941 aux_pga_gain),
942
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800944 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700945 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700946
947 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
948 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530949 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
950 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
951 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
952 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
953 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
954 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
955 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
956 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
957 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
958 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
959
960 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
961 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
962 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
963 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
964 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
965 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
966 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
967 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
968 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
969 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
970
971 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
972 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
973 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
974 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
975 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
976 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
977 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
978
979 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
980 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
981 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
982 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
983 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
984 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
985 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -0700986
987 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
988 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
989 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
990 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
991 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
992 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
993 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
994 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
995 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
996 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
997 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
998 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
999 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1000 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1001 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1002 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1003 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1004 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1005 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1006 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1007
1008 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1009 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1010 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1011 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1012 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1013 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1014 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1015 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1016 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1017 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1018 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1019 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1020 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1021 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1022 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1023 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1024 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1025 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1026 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1027 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001028 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
1029 tabla_get_compander, tabla_set_compander),
1030 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
1031 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001032};
1033
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001034static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
1035 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
1036};
1037
1038static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
1039 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
1040};
1041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042static const char *rx_mix1_text[] = {
1043 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1044 "RX5", "RX6", "RX7"
1045};
1046
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001047static const char *rx_dsm_text[] = {
1048 "CIC_OUT", "DSM_INV"
1049};
1050
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051static const char *sb_tx1_mux_text[] = {
1052 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1053 "DEC1"
1054};
1055
1056static const char *sb_tx5_mux_text[] = {
1057 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1058 "DEC5"
1059};
1060
1061static const char *sb_tx6_mux_text[] = {
1062 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1063 "DEC6"
1064};
1065
1066static const char const *sb_tx7_to_tx10_mux_text[] = {
1067 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1068 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1069 "DEC9", "DEC10"
1070};
1071
1072static const char *dec1_mux_text[] = {
1073 "ZERO", "DMIC1", "ADC6",
1074};
1075
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001076static const char *dec2_mux_text[] = {
1077 "ZERO", "DMIC2", "ADC5",
1078};
1079
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001080static const char *dec3_mux_text[] = {
1081 "ZERO", "DMIC3", "ADC4",
1082};
1083
1084static const char *dec4_mux_text[] = {
1085 "ZERO", "DMIC4", "ADC3",
1086};
1087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001088static const char *dec5_mux_text[] = {
1089 "ZERO", "DMIC5", "ADC2",
1090};
1091
1092static const char *dec6_mux_text[] = {
1093 "ZERO", "DMIC6", "ADC1",
1094};
1095
1096static const char const *dec7_mux_text[] = {
1097 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1098};
1099
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001100static const char *dec8_mux_text[] = {
1101 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1102};
1103
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001104static const char *dec9_mux_text[] = {
1105 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1106};
1107
1108static const char *dec10_mux_text[] = {
1109 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1110};
1111
Bradley Rubin229c6a52011-07-12 16:18:48 -07001112static const char const *anc_mux_text[] = {
1113 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1114 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1115};
1116
1117static const char const *anc1_fb_mux_text[] = {
1118 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1119};
1120
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121static const char *iir1_inp1_text[] = {
1122 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1123 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1124};
1125
1126static const struct soc_enum rx_mix1_inp1_chain_enum =
1127 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1128
Bradley Rubin229c6a52011-07-12 16:18:48 -07001129static const struct soc_enum rx_mix1_inp2_chain_enum =
1130 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1131
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132static const struct soc_enum rx2_mix1_inp1_chain_enum =
1133 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1134
Bradley Rubin229c6a52011-07-12 16:18:48 -07001135static const struct soc_enum rx2_mix1_inp2_chain_enum =
1136 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1137
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138static const struct soc_enum rx3_mix1_inp1_chain_enum =
1139 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1140
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001141static const struct soc_enum rx3_mix1_inp2_chain_enum =
1142 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1143
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001144static const struct soc_enum rx4_mix1_inp1_chain_enum =
1145 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1146
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001147static const struct soc_enum rx4_mix1_inp2_chain_enum =
1148 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001150static const struct soc_enum rx5_mix1_inp1_chain_enum =
1151 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1152
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001153static const struct soc_enum rx5_mix1_inp2_chain_enum =
1154 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1155
1156static const struct soc_enum rx6_mix1_inp1_chain_enum =
1157 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1158
1159static const struct soc_enum rx6_mix1_inp2_chain_enum =
1160 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1161
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001162static const struct soc_enum rx7_mix1_inp1_chain_enum =
1163 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1164
1165static const struct soc_enum rx7_mix1_inp2_chain_enum =
1166 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1167
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001168static const struct soc_enum rx4_dsm_enum =
1169 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1170
1171static const struct soc_enum rx6_dsm_enum =
1172 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174static const struct soc_enum sb_tx5_mux_enum =
1175 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1176
1177static const struct soc_enum sb_tx6_mux_enum =
1178 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1179
1180static const struct soc_enum sb_tx7_mux_enum =
1181 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1182 sb_tx7_to_tx10_mux_text);
1183
1184static const struct soc_enum sb_tx8_mux_enum =
1185 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1186 sb_tx7_to_tx10_mux_text);
1187
Kiran Kandi3426e512011-09-13 22:50:10 -07001188static const struct soc_enum sb_tx9_mux_enum =
1189 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1190 sb_tx7_to_tx10_mux_text);
1191
1192static const struct soc_enum sb_tx10_mux_enum =
1193 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1194 sb_tx7_to_tx10_mux_text);
1195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196static const struct soc_enum sb_tx1_mux_enum =
1197 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1198
1199static const struct soc_enum dec1_mux_enum =
1200 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1201
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001202static const struct soc_enum dec2_mux_enum =
1203 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1204
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001205static const struct soc_enum dec3_mux_enum =
1206 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1207
1208static const struct soc_enum dec4_mux_enum =
1209 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001211static const struct soc_enum dec5_mux_enum =
1212 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1213
1214static const struct soc_enum dec6_mux_enum =
1215 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1216
1217static const struct soc_enum dec7_mux_enum =
1218 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1219
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001220static const struct soc_enum dec8_mux_enum =
1221 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1222
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001223static const struct soc_enum dec9_mux_enum =
1224 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1225
1226static const struct soc_enum dec10_mux_enum =
1227 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1228
Bradley Rubin229c6a52011-07-12 16:18:48 -07001229static const struct soc_enum anc1_mux_enum =
1230 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1231
1232static const struct soc_enum anc2_mux_enum =
1233 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1234
1235static const struct soc_enum anc1_fb_mux_enum =
1236 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1237
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001238static const struct soc_enum iir1_inp1_mux_enum =
1239 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
1240
1241static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1242 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1243
Bradley Rubin229c6a52011-07-12 16:18:48 -07001244static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1245 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1246
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001247static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1248 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1249
Bradley Rubin229c6a52011-07-12 16:18:48 -07001250static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1251 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1254 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1255
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001256static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1257 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1260 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1261
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001262static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1263 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1264
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1266 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1267
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001268static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1269 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1270
1271static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1272 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1273
1274static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1275 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1276
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001277static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1278 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1279
1280static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1281 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1282
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001283static const struct snd_kcontrol_new rx4_dsm_mux =
1284 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1285
1286static const struct snd_kcontrol_new rx6_dsm_mux =
1287 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289static const struct snd_kcontrol_new sb_tx5_mux =
1290 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1291
1292static const struct snd_kcontrol_new sb_tx6_mux =
1293 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1294
1295static const struct snd_kcontrol_new sb_tx7_mux =
1296 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1297
1298static const struct snd_kcontrol_new sb_tx8_mux =
1299 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1300
Kiran Kandi3426e512011-09-13 22:50:10 -07001301static const struct snd_kcontrol_new sb_tx9_mux =
1302 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1303
1304static const struct snd_kcontrol_new sb_tx10_mux =
1305 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307static const struct snd_kcontrol_new sb_tx1_mux =
1308 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1309
1310static const struct snd_kcontrol_new dec1_mux =
1311 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1312
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001313static const struct snd_kcontrol_new dec2_mux =
1314 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1315
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001316static const struct snd_kcontrol_new dec3_mux =
1317 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1318
1319static const struct snd_kcontrol_new dec4_mux =
1320 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322static const struct snd_kcontrol_new dec5_mux =
1323 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
1324
1325static const struct snd_kcontrol_new dec6_mux =
1326 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
1327
1328static const struct snd_kcontrol_new dec7_mux =
1329 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
1330
Bradley Rubin229c6a52011-07-12 16:18:48 -07001331static const struct snd_kcontrol_new anc1_mux =
1332 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001333static const struct snd_kcontrol_new dec8_mux =
1334 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
1335
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001336static const struct snd_kcontrol_new dec9_mux =
1337 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
1338
1339static const struct snd_kcontrol_new dec10_mux =
1340 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
1341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342static const struct snd_kcontrol_new iir1_inp1_mux =
1343 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1344
Bradley Rubin229c6a52011-07-12 16:18:48 -07001345static const struct snd_kcontrol_new anc2_mux =
1346 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347
Bradley Rubin229c6a52011-07-12 16:18:48 -07001348static const struct snd_kcontrol_new anc1_fb_mux =
1349 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001350
Bradley Rubin229c6a52011-07-12 16:18:48 -07001351static const struct snd_kcontrol_new dac1_switch[] = {
1352 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1353};
1354static const struct snd_kcontrol_new hphl_switch[] = {
1355 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1356};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001357
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001358static const struct snd_kcontrol_new hphl_pa_mix[] = {
1359 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1360 7, 1, 0),
1361 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1362 7, 1, 0),
1363 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1364 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1365 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1366 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1367};
1368
1369static const struct snd_kcontrol_new hphr_pa_mix[] = {
1370 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1371 6, 1, 0),
1372 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1373 6, 1, 0),
1374 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1375 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1376 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1377 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1378};
1379
1380static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1381 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1382 5, 1, 0),
1383 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1384 5, 1, 0),
1385 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1386 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1387 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1388 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1389};
1390
1391static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1392 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1393 4, 1, 0),
1394 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1395 4, 1, 0),
1396 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1397 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1398 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1399 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1400};
1401
1402static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1403 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1404 3, 1, 0),
1405 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1406 3, 1, 0),
1407 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1408 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1409 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1410 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1411};
1412
1413static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1414 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1415 2, 1, 0),
1416 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1417 2, 1, 0),
1418 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1419 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1420 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1421 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1422};
1423
1424static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1425 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1426 1, 1, 0),
1427 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1428 1, 1, 0),
1429 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1430 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1431 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1432 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1433};
1434
1435static const struct snd_kcontrol_new ear_pa_mix[] = {
1436 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1437 0, 1, 0),
1438 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1439 0, 1, 0),
1440 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1441 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1442 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1443 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1444};
1445
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001446static const struct snd_kcontrol_new lineout3_ground_switch =
1447 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1448
1449static const struct snd_kcontrol_new lineout4_ground_switch =
1450 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001451
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001453 int enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454{
1455 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1456
1457 pr_debug("%s %d\n", __func__, enable);
1458
1459 if (enable) {
1460 tabla->adc_count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1462 } else {
1463 tabla->adc_count--;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001464 if (!tabla->adc_count)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001465 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
Joonwoo Park03324832012-03-19 19:36:16 -07001466 0x2, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 }
1468}
1469
1470static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1471 struct snd_kcontrol *kcontrol, int event)
1472{
1473 struct snd_soc_codec *codec = w->codec;
1474 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001475 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476
1477 pr_debug("%s %d\n", __func__, event);
1478
1479 if (w->reg == TABLA_A_TX_1_2_EN)
1480 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1481 else if (w->reg == TABLA_A_TX_3_4_EN)
1482 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1483 else if (w->reg == TABLA_A_TX_5_6_EN)
1484 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1485 else {
1486 pr_err("%s: Error, invalid adc register\n", __func__);
1487 return -EINVAL;
1488 }
1489
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001490 if (w->shift == 3)
1491 init_bit_shift = 6;
1492 else if (w->shift == 7)
1493 init_bit_shift = 7;
1494 else {
1495 pr_err("%s: Error, invalid init bit postion adc register\n",
1496 __func__);
1497 return -EINVAL;
1498 }
1499
1500
1501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001502 switch (event) {
1503 case SND_SOC_DAPM_PRE_PMU:
1504 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001505 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1506 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507 break;
1508 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001509
1510 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1511
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001512 break;
1513 case SND_SOC_DAPM_POST_PMD:
1514 tabla_codec_enable_adc_block(codec, 0);
1515 break;
1516 }
1517 return 0;
1518}
1519
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001520static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1521{
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001522 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1523 0x80);
1524 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1525 0x04);
1526 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1527 0x01);
1528 usleep_range(1000, 1000);
1529 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1530 0x00);
1531}
1532
1533static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1534 enum tabla_bandgap_type choice)
1535{
1536 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1537
1538 /* TODO lock resources accessed by audio streams and threaded
1539 * interrupt handlers
1540 */
1541
1542 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1543 tabla->bandgap_type);
1544
1545 if (tabla->bandgap_type == choice)
1546 return;
1547
1548 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1549 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1550 tabla_codec_enable_audio_mode_bandgap(codec);
1551 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
1552 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1553 0x2);
1554 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1555 0x80);
1556 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1557 0x4);
1558 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1559 0x01);
1560 usleep_range(1000, 1000);
1561 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1562 0x00);
1563 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1564 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1565 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1566 usleep_range(100, 100);
1567 tabla_codec_enable_audio_mode_bandgap(codec);
1568 } else if (choice == TABLA_BANDGAP_OFF) {
1569 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1570 } else {
1571 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1572 }
1573 tabla->bandgap_type = choice;
1574}
1575
1576static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1577{
1578 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1579 pr_debug("%s\n", __func__);
1580 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1581 ndelay(160);
1582 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1583 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1584 tabla->clock_active = false;
1585}
1586
1587static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
1588{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001589 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001590 return 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001591 else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001592 return 1;
1593 else {
1594 BUG_ON(1);
1595 return -EINVAL;
1596 }
1597}
1598
1599static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1600{
1601 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1602
1603 if (enable) {
1604 tabla->rx_bias_count++;
1605 if (tabla->rx_bias_count == 1)
1606 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1607 0x80, 0x80);
1608 } else {
1609 tabla->rx_bias_count--;
1610 if (!tabla->rx_bias_count)
1611 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1612 0x80, 0x00);
1613 }
1614}
1615
1616static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1617 int enable)
1618{
1619 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1620
1621 pr_debug("%s: enable = %d\n", __func__, enable);
1622 if (enable) {
1623 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1624 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1625 usleep_range(5, 5);
1626 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1627 0x80);
1628 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1629 0x80);
1630 usleep_range(10, 10);
1631 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1632 usleep_range(20, 20);
1633 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1634 } else {
1635 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1636 0);
1637 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1638 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1639 }
1640 tabla->config_mode_active = enable ? true : false;
1641
1642 return 0;
1643}
1644
1645static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1646 int config_mode)
1647{
1648 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1649
1650 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
1651
1652 if (config_mode) {
1653 tabla_codec_enable_config_mode(codec, 1);
1654 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1655 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1656 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1657 usleep_range(1000, 1000);
1658 } else
1659 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1660
1661 if (!config_mode && tabla->mbhc_polling_active) {
1662 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1663 tabla_codec_enable_config_mode(codec, 0);
1664
1665 }
1666
1667 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1668 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1669 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1670 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1671 usleep_range(50, 50);
1672 tabla->clock_active = true;
1673 return 0;
1674}
1675
1676static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1677 struct snd_kcontrol *kcontrol, int event)
1678{
1679 struct snd_soc_codec *codec = w->codec;
1680 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1681
1682 pr_debug("%s: %d\n", __func__, event);
1683
1684 switch (event) {
1685 case SND_SOC_DAPM_PRE_PMU:
1686 tabla_codec_enable_bandgap(codec,
1687 TABLA_BANDGAP_AUDIO_MODE);
1688 tabla_enable_rx_bias(codec, 1);
1689
1690 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1691 0x08, 0x08);
1692 /* Enable Zero Cross detect for AUX PGA channel
1693 * and set the initial AUX PGA gain to NEG_0P0_DB
1694 * to avoid glitches.
1695 */
1696 if (w->reg == TABLA_A_AUX_L_EN) {
1697 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1698 0x20, 0x20);
1699 tabla->aux_l_gain = snd_soc_read(codec,
1700 TABLA_A_AUX_L_GAIN);
1701 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1702 } else {
1703 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1704 0x20, 0x20);
1705 tabla->aux_r_gain = snd_soc_read(codec,
1706 TABLA_A_AUX_R_GAIN);
1707 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1708 }
1709 if (tabla->aux_pga_cnt++ == 1
1710 && !tabla->mclk_enabled) {
1711 tabla_codec_enable_clock_block(codec, 1);
1712 pr_debug("AUX PGA enabled RC osc\n");
1713 }
1714 break;
1715
1716 case SND_SOC_DAPM_POST_PMU:
1717 if (w->reg == TABLA_A_AUX_L_EN)
1718 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1719 tabla->aux_l_gain);
1720 else
1721 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1722 tabla->aux_r_gain);
1723 break;
1724
1725 case SND_SOC_DAPM_PRE_PMD:
1726 /* Mute AUX PGA channel in use before disabling AUX PGA */
1727 if (w->reg == TABLA_A_AUX_L_EN) {
1728 tabla->aux_l_gain = snd_soc_read(codec,
1729 TABLA_A_AUX_L_GAIN);
1730 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1731 } else {
1732 tabla->aux_r_gain = snd_soc_read(codec,
1733 TABLA_A_AUX_R_GAIN);
1734 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1735 }
1736 break;
1737
1738 case SND_SOC_DAPM_POST_PMD:
1739 tabla_enable_rx_bias(codec, 0);
1740
1741 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1742 0x08, 0x00);
1743 if (w->reg == TABLA_A_AUX_L_EN) {
1744 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1745 tabla->aux_l_gain);
1746 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1747 0x20, 0x00);
1748 } else {
1749 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1750 tabla->aux_r_gain);
1751 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1752 0x20, 0x00);
1753 }
1754
1755 if (tabla->aux_pga_cnt-- == 0) {
1756 if (tabla->mbhc_polling_active)
1757 tabla_codec_enable_bandgap(codec,
1758 TABLA_BANDGAP_MBHC_MODE);
1759 else
1760 tabla_codec_enable_bandgap(codec,
1761 TABLA_BANDGAP_OFF);
1762
1763 if (!tabla->mclk_enabled &&
1764 !tabla->mbhc_polling_active) {
1765 tabla_codec_enable_clock_block(codec, 0);
1766 }
1767 }
1768 break;
1769 }
1770 return 0;
1771}
1772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1774 struct snd_kcontrol *kcontrol, int event)
1775{
1776 struct snd_soc_codec *codec = w->codec;
1777 u16 lineout_gain_reg;
1778
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001779 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780
1781 switch (w->shift) {
1782 case 0:
1783 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1784 break;
1785 case 1:
1786 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1787 break;
1788 case 2:
1789 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1790 break;
1791 case 3:
1792 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1793 break;
1794 case 4:
1795 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1796 break;
1797 default:
1798 pr_err("%s: Error, incorrect lineout register value\n",
1799 __func__);
1800 return -EINVAL;
1801 }
1802
1803 switch (event) {
1804 case SND_SOC_DAPM_PRE_PMU:
1805 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1806 break;
1807 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001808 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001809 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001810 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001811 break;
1812 case SND_SOC_DAPM_POST_PMD:
1813 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1814 break;
1815 }
1816 return 0;
1817}
1818
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001819
1820static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 struct snd_kcontrol *kcontrol, int event)
1822{
1823 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001824 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1825 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001826 unsigned int dmic;
1827 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001828
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001829 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1830 if (ret < 0) {
1831 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001832 return -EINVAL;
1833 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001834
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001835 switch (dmic) {
1836 case 1:
1837 case 2:
1838 dmic_clk_sel = 0x02;
1839 dmic_clk_en = 0x01;
1840 break;
1841
1842 case 3:
1843 case 4:
1844 dmic_clk_sel = 0x08;
1845 dmic_clk_en = 0x04;
1846 break;
1847
1848 case 5:
1849 case 6:
1850 dmic_clk_sel = 0x20;
1851 dmic_clk_en = 0x10;
1852 break;
1853
1854 default:
1855 pr_err("%s: Invalid DMIC Selection\n", __func__);
1856 return -EINVAL;
1857 }
1858
1859 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1860 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001862 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001863
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001864 switch (event) {
1865 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001866 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1867
1868 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1869 dmic_clk_sel, dmic_clk_sel);
1870
1871 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1872
1873 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1874 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001875 break;
1876 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001877 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1878 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001879 break;
1880 }
1881 return 0;
1882}
1883
Bradley Rubin229c6a52011-07-12 16:18:48 -07001884static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1885 struct snd_kcontrol *kcontrol, int event)
1886{
1887 struct snd_soc_codec *codec = w->codec;
1888 const char *filename;
1889 const struct firmware *fw;
1890 int i;
1891 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001892 int num_anc_slots;
1893 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001894 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001895 u32 anc_writes_size = 0;
1896 int anc_size_remaining;
1897 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001898 u16 reg;
1899 u8 mask, val, old_val;
1900
1901 pr_debug("%s %d\n", __func__, event);
1902 switch (event) {
1903 case SND_SOC_DAPM_PRE_PMU:
1904
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001905 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001906
1907 ret = request_firmware(&fw, filename, codec->dev);
1908 if (ret != 0) {
1909 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1910 ret);
1911 return -ENODEV;
1912 }
1913
Bradley Rubina7096d02011-08-03 18:29:02 -07001914 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001915 dev_err(codec->dev, "Not enough data\n");
1916 release_firmware(fw);
1917 return -ENOMEM;
1918 }
1919
1920 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001921 anc_head = (struct anc_header *)(fw->data);
1922 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1923 anc_size_remaining = fw->size - sizeof(struct anc_header);
1924 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001925
Bradley Rubina7096d02011-08-03 18:29:02 -07001926 if (tabla->anc_slot >= num_anc_slots) {
1927 dev_err(codec->dev, "Invalid ANC slot selected\n");
1928 release_firmware(fw);
1929 return -EINVAL;
1930 }
1931
1932 for (i = 0; i < num_anc_slots; i++) {
1933
1934 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1935 dev_err(codec->dev, "Invalid register format\n");
1936 release_firmware(fw);
1937 return -EINVAL;
1938 }
1939 anc_writes_size = (u32)(*anc_ptr);
1940 anc_size_remaining -= sizeof(u32);
1941 anc_ptr += 1;
1942
1943 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1944 > anc_size_remaining) {
1945 dev_err(codec->dev, "Invalid register format\n");
1946 release_firmware(fw);
1947 return -ENOMEM;
1948 }
1949
1950 if (tabla->anc_slot == i)
1951 break;
1952
1953 anc_size_remaining -= (anc_writes_size *
1954 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001955 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001956 }
1957 if (i == num_anc_slots) {
1958 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001959 release_firmware(fw);
1960 return -ENOMEM;
1961 }
1962
Bradley Rubina7096d02011-08-03 18:29:02 -07001963 for (i = 0; i < anc_writes_size; i++) {
1964 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001965 mask, val);
1966 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001967 snd_soc_write(codec, reg, (old_val & ~mask) |
1968 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001969 }
1970 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001971
1972 break;
1973 case SND_SOC_DAPM_POST_PMD:
1974 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1975 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1976 break;
1977 }
1978 return 0;
1979}
1980
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001981/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07001982static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
1983{
Bradley Rubincb3950a2011-08-18 13:07:26 -07001984 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07001985 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
1986 int mbhc_state = tabla->mbhc_state;
Bradley Rubincb3950a2011-08-18 13:07:26 -07001987
Joonwoo Park03324832012-03-19 19:36:16 -07001988 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001989 if (!tabla->mbhc_polling_active) {
1990 pr_debug("Polling is not active, do not start polling\n");
1991 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07001992 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001993 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Joonwoo Park03324832012-03-19 19:36:16 -07001994
1995 if (!tabla->no_mic_headset_override) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001996 if (mbhc_state == MBHC_STATE_POTENTIAL) {
1997 pr_debug("%s recovering MBHC state macine\n", __func__);
1998 tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
Joonwoo Park03324832012-03-19 19:36:16 -07001999 /* set to max button press threshold */
2000 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2001 0x7F);
2002 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2003 0xFF);
2004 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2005 (TABLA_IS_1_X(tabla_core->version) ?
2006 0x07 : 0x7F));
2007 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2008 0xFF);
2009 /* set to max */
2010 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2011 0x7F);
2012 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2013 0xFF);
2014 }
2015 }
2016
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002017 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
2018 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2019 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
Joonwoo Park03324832012-03-19 19:36:16 -07002020 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002021}
2022
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002023/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002024static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
2025{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002026 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2027
Joonwoo Park03324832012-03-19 19:36:16 -07002028 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002029 if (!tabla->mbhc_polling_active) {
2030 pr_debug("polling not active, nothing to pause\n");
2031 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002032 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002033
2034 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Joonwoo Park03324832012-03-19 19:36:16 -07002035 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002036}
2037
Joonwoo Park03324832012-03-19 19:36:16 -07002038static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002039{
2040 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2041 u8 reg_mode_val, cur_mode_val;
2042 bool mbhc_was_polling = false;
2043
2044 if (mode)
2045 reg_mode_val = TABLA_CFILT_FAST_MODE;
2046 else
2047 reg_mode_val = TABLA_CFILT_SLOW_MODE;
2048
2049 cur_mode_val = snd_soc_read(codec,
2050 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
2051
2052 if (cur_mode_val != reg_mode_val) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002053 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002054 if (tabla->mbhc_polling_active) {
2055 tabla_codec_pause_hs_polling(codec);
2056 mbhc_was_polling = true;
2057 }
2058 snd_soc_update_bits(codec,
2059 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
2060 if (mbhc_was_polling)
2061 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002062 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002063 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
2064 cur_mode_val, reg_mode_val);
2065 } else {
2066 pr_debug("%s: CFILT Value is already %x\n",
2067 __func__, cur_mode_val);
2068 }
2069}
2070
2071static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
2072 u8 cfilt_sel, int inc)
2073{
2074 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2075 u32 *cfilt_cnt_ptr = NULL;
2076 u16 micb_cfilt_reg;
2077
2078 switch (cfilt_sel) {
2079 case TABLA_CFILT1_SEL:
2080 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2081 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2082 break;
2083 case TABLA_CFILT2_SEL:
2084 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2085 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2086 break;
2087 case TABLA_CFILT3_SEL:
2088 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2089 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2090 break;
2091 default:
2092 return; /* should not happen */
2093 }
2094
2095 if (inc) {
2096 if (!(*cfilt_cnt_ptr)++) {
2097 /* Switch CFILT to slow mode if MBHC CFILT being used */
2098 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2099 tabla_codec_switch_cfilt_mode(codec, 0);
2100
2101 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2102 }
2103 } else {
2104 /* check if count not zero, decrement
2105 * then check if zero, go ahead disable cfilter
2106 */
2107 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2108 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2109
2110 /* Switch CFILT to fast mode if MBHC CFILT being used */
2111 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2112 tabla_codec_switch_cfilt_mode(codec, 1);
2113 }
2114 }
2115}
2116
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002117static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2118{
2119 int rc = -EINVAL;
2120 unsigned min_mv, max_mv;
2121
2122 switch (ldoh_v) {
2123 case TABLA_LDOH_1P95_V:
2124 min_mv = 160;
2125 max_mv = 1800;
2126 break;
2127 case TABLA_LDOH_2P35_V:
2128 min_mv = 200;
2129 max_mv = 2200;
2130 break;
2131 case TABLA_LDOH_2P75_V:
2132 min_mv = 240;
2133 max_mv = 2600;
2134 break;
2135 case TABLA_LDOH_2P85_V:
2136 min_mv = 250;
2137 max_mv = 2700;
2138 break;
2139 default:
2140 goto done;
2141 }
2142
2143 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2144 goto done;
2145
2146 for (rc = 4; rc <= 44; rc++) {
2147 min_mv = max_mv * (rc) / 44;
2148 if (min_mv >= cfilt_mv) {
2149 rc -= 4;
2150 break;
2151 }
2152 }
2153done:
2154 return rc;
2155}
2156
2157static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2158{
2159 u8 hph_reg_val = 0;
2160 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2161
2162 return (hph_reg_val & 0x30) ? true : false;
2163}
2164
Joonwoo Parka9444452011-12-08 18:48:27 -08002165static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2166{
2167 u8 hph_reg_val = 0;
2168 if (left)
2169 hph_reg_val = snd_soc_read(codec,
2170 TABLA_A_RX_HPH_L_DAC_CTL);
2171 else
2172 hph_reg_val = snd_soc_read(codec,
2173 TABLA_A_RX_HPH_R_DAC_CTL);
2174
2175 return (hph_reg_val & 0xC0) ? true : false;
2176}
2177
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002178static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
2179{
2180 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
2181}
2182
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002183/* called under codec_resource_lock acquisition */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002184static void tabla_codec_drive_v_to_micbias(struct snd_soc_codec *codec,
2185 int usec)
2186{
2187 int cfilt_k_val;
2188 bool set = true;
2189 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2190
2191 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2192 tabla->mbhc_micbias_switched) {
2193 pr_debug("%s: set mic V to micbias V\n", __func__);
2194 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2195 tabla_turn_onoff_override(codec, true);
2196 while (1) {
2197 cfilt_k_val = tabla_find_k_value(
2198 tabla->pdata->micbias.ldoh_v,
2199 set ? tabla->mbhc_data.micb_mv :
2200 VDDIO_MICBIAS_MV);
2201 snd_soc_update_bits(codec,
2202 tabla->mbhc_bias_regs.cfilt_val,
2203 0xFC, (cfilt_k_val << 2));
2204 if (!set)
2205 break;
2206 usleep_range(usec, usec);
2207 set = false;
2208 }
2209 tabla_turn_onoff_override(codec, false);
2210 }
2211}
2212
2213/* called under codec_resource_lock acquisition */
2214static void __tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2215 int vddio_switch, bool restartpolling,
2216 bool checkpolling)
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002217{
2218 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2219 int cfilt_k_val;
2220
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002221 if (vddio_switch && !tabla->mbhc_micbias_switched &&
2222 (!checkpolling || tabla->mbhc_polling_active)) {
2223 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002224 tabla_codec_pause_hs_polling(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002225 tabla_turn_onoff_override(codec, true);
2226 /* Adjust threshold if Mic Bias voltage changes */
2227 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002228 cfilt_k_val = tabla_find_k_value(
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002229 tabla->pdata->micbias.ldoh_v,
2230 VDDIO_MICBIAS_MV);
2231 usleep_range(10000, 10000);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002232 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002233 tabla->mbhc_bias_regs.cfilt_val,
2234 0xFC, (cfilt_k_val << 2));
2235 usleep_range(10000, 10000);
2236 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2237 tabla->mbhc_data.adj_v_ins_hu & 0xFF);
2238 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2239 (tabla->mbhc_data.adj_v_ins_hu >> 8) &
2240 0xFF);
2241 pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
2242 __func__);
2243 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002244
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002245 /* enable MIC BIAS Switch to VDDIO */
2246 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2247 0x80, 0x80);
2248 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2249 0x10, 0x00);
2250 tabla_turn_onoff_override(codec, false);
2251 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002252 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002253
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002254 tabla->mbhc_micbias_switched = true;
2255 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002256
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002257 } else if (!vddio_switch && tabla->mbhc_micbias_switched) {
2258 if ((!checkpolling || tabla->mbhc_polling_active) &&
2259 restartpolling)
2260 tabla_codec_pause_hs_polling(codec);
2261 /* Reprogram thresholds */
2262 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
2263 cfilt_k_val = tabla_find_k_value(
2264 tabla->pdata->micbias.ldoh_v,
2265 tabla->mbhc_data.micb_mv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002266 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002267 tabla->mbhc_bias_regs.cfilt_val,
2268 0xFC, (cfilt_k_val << 2));
2269 usleep_range(10000, 10000);
2270 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2271 tabla->mbhc_data.v_ins_hu & 0xFF);
2272 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2273 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
2274 pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
2275 __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002276 }
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002277
2278 /* Disable MIC BIAS Switch to VDDIO */
2279 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2280 0x80, 0x00);
2281 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2282 0x10, 0x00);
2283
2284 if ((!checkpolling || tabla->mbhc_polling_active) &&
2285 restartpolling)
2286 tabla_codec_start_hs_polling(codec);
2287
2288 tabla->mbhc_micbias_switched = false;
2289 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002290 }
2291}
2292
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002293static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2294 int vddio_switch)
2295{
2296 return __tabla_codec_switch_micbias(codec, vddio_switch, true, true);
2297}
2298
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2300 struct snd_kcontrol *kcontrol, int event)
2301{
2302 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002303 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2304 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002305 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002306 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002307 char *internal1_text = "Internal1";
2308 char *internal2_text = "Internal2";
2309 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002310
2311 pr_debug("%s %d\n", __func__, event);
2312 switch (w->reg) {
2313 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002314 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002315 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002316 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002317 break;
2318 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002319 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002320 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002321 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002322 break;
2323 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002325 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002326 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002327 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002328 case TABLA_1_A_MICB_4_CTL:
2329 case TABLA_2_A_MICB_4_CTL:
2330 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002331 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002332 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002333 break;
2334 default:
2335 pr_err("%s: Error, invalid micbias register\n", __func__);
2336 return -EINVAL;
2337 }
2338
2339 switch (event) {
2340 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002341 /* Decide whether to switch the micbias for MBHC */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002342 if (w->reg == tabla->mbhc_bias_regs.ctl_reg) {
2343 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002344 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002345 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2346 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002347
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002348 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002349 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002350
2351 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002352 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002353 else if (strnstr(w->name, internal2_text, 30))
2354 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2355 else if (strnstr(w->name, internal3_text, 30))
2356 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2357
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002358 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002359 case SND_SOC_DAPM_POST_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002360
2361 usleep_range(20000, 20000);
2362
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002363 if (tabla->mbhc_polling_active &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002364 tabla->mbhc_cfg.micbias == micb_line) {
2365 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002366 tabla_codec_pause_hs_polling(codec);
2367 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002368 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002369 }
2370 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002371
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002372 case SND_SOC_DAPM_POST_PMD:
Joonwoo Park03324832012-03-19 19:36:16 -07002373 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg) &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002374 tabla_is_hph_pa_on(codec)) {
2375 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002376 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002377 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2378 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002379
Bradley Rubin229c6a52011-07-12 16:18:48 -07002380 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002381 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002382 else if (strnstr(w->name, internal2_text, 30))
2383 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2384 else if (strnstr(w->name, internal3_text, 30))
2385 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2386
Patrick Lai3043fba2011-08-01 14:15:57 -07002387 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002388 break;
2389 }
2390
2391 return 0;
2392}
2393
Kiran Kandid8cf5212012-03-02 15:34:53 -08002394
2395static void tx_hpf_corner_freq_callback(struct work_struct *work)
2396{
2397 struct delayed_work *hpf_delayed_work;
2398 struct hpf_work *hpf_work;
2399 struct tabla_priv *tabla;
2400 struct snd_soc_codec *codec;
2401 u16 tx_mux_ctl_reg;
2402 u8 hpf_cut_of_freq;
2403
2404 hpf_delayed_work = to_delayed_work(work);
2405 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2406 tabla = hpf_work->tabla;
2407 codec = hpf_work->tabla->codec;
2408 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2409
2410 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL +
2411 (hpf_work->decimator - 1) * 8;
2412
2413 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
2414 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2415
2416 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
2417}
2418
2419#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
2420#define CF_MIN_3DB_4HZ 0x0
2421#define CF_MIN_3DB_75HZ 0x1
2422#define CF_MIN_3DB_150HZ 0x2
2423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002424static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
2425 struct snd_kcontrol *kcontrol, int event)
2426{
2427 struct snd_soc_codec *codec = w->codec;
Kiran Kandid8cf5212012-03-02 15:34:53 -08002428 unsigned int decimator;
2429 char *dec_name = NULL;
2430 char *widget_name = NULL;
2431 char *temp;
2432 int ret = 0;
2433 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2434 u8 dec_hpf_cut_of_freq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002435
2436 pr_debug("%s %d\n", __func__, event);
2437
Kiran Kandid8cf5212012-03-02 15:34:53 -08002438 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2439 if (!widget_name)
2440 return -ENOMEM;
2441 temp = widget_name;
2442
2443 dec_name = strsep(&widget_name, " ");
2444 widget_name = temp;
2445 if (!dec_name) {
2446 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2447 ret = -EINVAL;
2448 goto out;
2449 }
2450
2451 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
2452 if (ret < 0) {
2453 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2454 ret = -EINVAL;
2455 goto out;
2456 }
2457
2458 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
2459 w->name, dec_name, decimator);
2460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL)
2462 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
2463 else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL)
2464 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
2465 else {
2466 pr_err("%s: Error, incorrect dec\n", __func__);
2467 return -EINVAL;
2468 }
2469
Kiran Kandid8cf5212012-03-02 15:34:53 -08002470 tx_vol_ctl_reg = TABLA_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator -1);
2471 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2472
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002473 switch (event) {
2474 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002475
2476 // Enableable TX digital mute */
2477 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002479 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2480 1 << w->shift);
2481 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Kiran Kandid8cf5212012-03-02 15:34:53 -08002482
2483 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2484
2485 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
2486
2487 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2488 dec_hpf_cut_of_freq;
2489
2490 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2491
2492 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
2493 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2494 CF_MIN_3DB_150HZ << 4);
2495 }
2496
2497 /* enable HPF */
2498 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
2499
2500 break;
2501
2502 case SND_SOC_DAPM_POST_PMU:
2503
2504 /* Disable TX digital mute */
2505 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2506
2507 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2508 CF_MIN_3DB_150HZ) {
2509
2510 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2511 msecs_to_jiffies(300));
2512 }
2513 break;
2514
2515 case SND_SOC_DAPM_PRE_PMD:
2516
2517 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2518 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2519 break;
2520
2521 case SND_SOC_DAPM_POST_PMD:
2522
2523 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2524 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2525 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002527 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002528 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08002529out:
2530 kfree(widget_name);
2531 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002532}
2533
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002534static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002535 struct snd_kcontrol *kcontrol, int event)
2536{
2537 struct snd_soc_codec *codec = w->codec;
2538
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002539 pr_debug("%s %d %s\n", __func__, event, w->name);
2540
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541 switch (event) {
2542 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002543 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2544 1 << w->shift, 1 << w->shift);
2545 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2546 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002547 break;
2548 }
2549 return 0;
2550}
2551
Bradley Rubin229c6a52011-07-12 16:18:48 -07002552static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2553 struct snd_kcontrol *kcontrol, int event)
2554{
2555 switch (event) {
2556 case SND_SOC_DAPM_POST_PMU:
2557 case SND_SOC_DAPM_POST_PMD:
2558 usleep_range(1000, 1000);
2559 break;
2560 }
2561 return 0;
2562}
2563
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002564static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2565 struct snd_kcontrol *kcontrol, int event)
2566{
2567 struct snd_soc_codec *codec = w->codec;
2568
2569 pr_debug("%s %d\n", __func__, event);
2570
2571 switch (event) {
2572 case SND_SOC_DAPM_PRE_PMU:
2573 tabla_enable_rx_bias(codec, 1);
2574 break;
2575 case SND_SOC_DAPM_POST_PMD:
2576 tabla_enable_rx_bias(codec, 0);
2577 break;
2578 }
2579 return 0;
2580}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002581static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
2582 struct snd_kcontrol *kcontrol, int event)
2583{
2584 struct snd_soc_codec *codec = w->codec;
2585
2586 pr_debug("%s %s %d\n", __func__, w->name, event);
2587
2588 switch (event) {
2589 case SND_SOC_DAPM_PRE_PMU:
2590 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2591 break;
2592 case SND_SOC_DAPM_POST_PMD:
2593 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2594 break;
2595 }
2596 return 0;
2597}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002598
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002599static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
2600 struct snd_soc_jack *jack, int status,
2601 int mask)
2602{
2603 /* XXX: wake_lock_timeout()? */
Joonwoo Park03324832012-03-19 19:36:16 -07002604 snd_soc_jack_report_no_dapm(jack, status, mask);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002605}
2606
Patrick Lai49efeac2011-11-03 11:01:12 -07002607static void hphocp_off_report(struct tabla_priv *tabla,
2608 u32 jack_status, int irq)
2609{
2610 struct snd_soc_codec *codec;
Joonwoo Park03324832012-03-19 19:36:16 -07002611 if (!tabla) {
2612 pr_err("%s: Bad tabla private data\n", __func__);
2613 return;
2614 }
Patrick Lai49efeac2011-11-03 11:01:12 -07002615
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002616 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
Joonwoo Park03324832012-03-19 19:36:16 -07002617 codec = tabla->codec;
2618 if (tabla->hph_status & jack_status) {
Patrick Lai49efeac2011-11-03 11:01:12 -07002619 tabla->hph_status &= ~jack_status;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002620 if (tabla->mbhc_cfg.headset_jack)
2621 tabla_snd_soc_jack_report(tabla,
2622 tabla->mbhc_cfg.headset_jack,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002623 tabla->hph_status,
2624 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08002625 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2626 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08002627 /* reset retry counter as PA is turned off signifying
2628 * start of new OCP detection session
2629 */
2630 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
2631 tabla->hphlocp_cnt = 0;
2632 else
2633 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302634 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07002635 }
2636}
2637
2638static void hphlocp_off_report(struct work_struct *work)
2639{
2640 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2641 hphlocp_work);
2642 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
2643}
2644
2645static void hphrocp_off_report(struct work_struct *work)
2646{
2647 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2648 hphrocp_work);
2649 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
2650}
2651
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002652static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
2653 struct snd_kcontrol *kcontrol, int event)
2654{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002655 struct snd_soc_codec *codec = w->codec;
2656 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2657 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002658 pr_debug("%s: event = %d\n", __func__, event);
2659
2660 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002661 case SND_SOC_DAPM_PRE_PMU:
2662 mbhc_micb_ctl_val = snd_soc_read(codec,
2663 tabla->mbhc_bias_regs.ctl_reg);
2664
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002665 if (!(mbhc_micb_ctl_val & 0x80)) {
2666 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002667 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002668 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2669 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002670 break;
2671
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002672 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07002673 /* schedule work is required because at the time HPH PA DAPM
2674 * event callback is called by DAPM framework, CODEC dapm mutex
2675 * would have been locked while snd_soc_jack_report also
2676 * attempts to acquire same lock.
2677 */
Joonwoo Parka9444452011-12-08 18:48:27 -08002678 if (w->shift == 5) {
2679 clear_bit(TABLA_HPHL_PA_OFF_ACK,
2680 &tabla->hph_pa_dac_state);
2681 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
2682 &tabla->hph_pa_dac_state);
2683 if (tabla->hph_status & SND_JACK_OC_HPHL)
2684 schedule_work(&tabla->hphlocp_work);
2685 } else if (w->shift == 4) {
2686 clear_bit(TABLA_HPHR_PA_OFF_ACK,
2687 &tabla->hph_pa_dac_state);
2688 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
2689 &tabla->hph_pa_dac_state);
2690 if (tabla->hph_status & SND_JACK_OC_HPHR)
2691 schedule_work(&tabla->hphrocp_work);
2692 }
2693
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002694 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park03324832012-03-19 19:36:16 -07002695 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002696 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002697
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002698 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
2699 w->name);
2700 usleep_range(10000, 10000);
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002701 break;
2702 }
2703 return 0;
2704}
2705
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002706static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002707 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002708{
2709 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002710 unsigned int cfilt;
2711
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002712 switch (tabla->mbhc_cfg.micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002713 case TABLA_MICBIAS1:
2714 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
2715 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
2716 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
2717 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
2718 break;
2719 case TABLA_MICBIAS2:
2720 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
2721 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
2722 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
2723 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
2724 break;
2725 case TABLA_MICBIAS3:
2726 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
2727 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
2728 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
2729 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
2730 break;
2731 case TABLA_MICBIAS4:
2732 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002733 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
2734 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
2735 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002736 break;
2737 default:
2738 /* Should never reach here */
2739 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07002740 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002741 }
2742
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002743 micbias_regs->cfilt_sel = cfilt;
2744
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002745 switch (cfilt) {
2746 case TABLA_CFILT1_SEL:
2747 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
2748 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002749 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002750 break;
2751 case TABLA_CFILT2_SEL:
2752 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
2753 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002754 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002755 break;
2756 case TABLA_CFILT3_SEL:
2757 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
2758 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002759 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002760 break;
2761 }
2762}
Santosh Mardie15e2302011-11-15 10:39:23 +05302763static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
2764 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
2765 4, 0, NULL, 0),
2766 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
2767 0, NULL, 0),
2768};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002769
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002770static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
2771 struct snd_kcontrol *kcontrol, int event)
2772{
2773 struct snd_soc_codec *codec = w->codec;
2774
2775 pr_debug("%s %s %d\n", __func__, w->name, event);
2776
2777 switch (event) {
2778 case SND_SOC_DAPM_PRE_PMU:
2779 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2780 break;
2781
2782 case SND_SOC_DAPM_POST_PMD:
2783 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2784 break;
2785 }
2786 return 0;
2787}
2788
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002789static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
2790 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302791 0, tabla_codec_enable_micbias,
2792 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2793 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002794};
2795
2796static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
2797 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302798 0, tabla_codec_enable_micbias,
2799 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2800 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002801};
2802
Santosh Mardie15e2302011-11-15 10:39:23 +05302803static const struct snd_soc_dapm_route audio_i2s_map[] = {
2804 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2805 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2806 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2807 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2808 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2809
2810 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2811 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2812 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2813 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2814};
2815
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002816static const struct snd_soc_dapm_route audio_map[] = {
2817 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002818
2819 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2820 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2821
2822 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2823 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2824
2825 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2826 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2827
2828 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2829 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002830 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002831 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2832 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002833 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2834 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002835 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2836 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002837 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2838 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002839
2840 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002841 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2842 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2843 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002844 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002845 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2846 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2847
Kiran Kandi3426e512011-09-13 22:50:10 -07002848 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
2849 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
2850 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
2851 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
2852 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
2853 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
2854 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
2855 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
2856 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
2857 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
2858 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
2859
2860 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
2861 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
2862 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
2863 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
2864 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
2865 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
2866 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
2867 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
2868 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
2869 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
2870 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
2871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002872 /* Earpiece (RX MIX1) */
2873 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002874 {"EAR PA", NULL, "EAR_PA_MIXER"},
2875 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002876 {"DAC1", NULL, "CP"},
2877
2878 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2879 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2880 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002881
2882 /* Headset (RX MIX1 and RX MIX2) */
2883 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002884 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002885
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002886 {"HPHL", NULL, "HPHL_PA_MIXER"},
2887 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
2888
2889 {"HPHR", NULL, "HPHR_PA_MIXER"},
2890 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002891
2892 {"HPHL DAC", NULL, "CP"},
2893 {"HPHR DAC", NULL, "CP"},
2894
2895 {"ANC", NULL, "ANC1 MUX"},
2896 {"ANC", NULL, "ANC2 MUX"},
2897 {"ANC1 MUX", "ADC1", "ADC1"},
2898 {"ANC1 MUX", "ADC2", "ADC2"},
2899 {"ANC1 MUX", "ADC3", "ADC3"},
2900 {"ANC1 MUX", "ADC4", "ADC4"},
2901 {"ANC2 MUX", "ADC1", "ADC1"},
2902 {"ANC2 MUX", "ADC2", "ADC2"},
2903 {"ANC2 MUX", "ADC3", "ADC3"},
2904 {"ANC2 MUX", "ADC4", "ADC4"},
2905
Bradley Rubine1d08622011-07-20 18:01:35 -07002906 {"ANC", NULL, "CDC_CONN"},
2907
Bradley Rubin229c6a52011-07-12 16:18:48 -07002908 {"DAC1", "Switch", "RX1 CHAIN"},
2909 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002910 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002911
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002912 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2913 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2914 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2915 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2916 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002917
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002918 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2919 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
2920 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2921 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2922 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
2923 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
2924 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
2925 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
2926 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
2927 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002928
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002929 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2930 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2931
Bradley Rubin229c6a52011-07-12 16:18:48 -07002932 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2933 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2934 {"RX1 CHAIN", NULL, "ANC"},
2935 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002936
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002937 {"CP", NULL, "RX_BIAS"},
2938 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2939 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2940 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2941 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002942 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002943
Kuirong Wang0f8ade32012-02-27 16:29:45 -08002944 {"RX1 MIX1", NULL, "COMP1_CLK"},
2945 {"RX2 MIX1", NULL, "COMP1_CLK"},
2946 {"RX3 MIX1", NULL, "COMP2_CLK"},
2947 {"RX5 MIX1", NULL, "COMP2_CLK"},
2948
2949
Bradley Rubin229c6a52011-07-12 16:18:48 -07002950 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2951 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2952 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2953 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002954 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2955 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2956 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2957 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2958 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
2959 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
2960 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
2961 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07002962 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
2963 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002964
Bradley Rubin229c6a52011-07-12 16:18:48 -07002965 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2966 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302967 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2968 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002969 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
2970 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002971 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2972 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2973 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302974 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2975 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002976 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
2977 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002978 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2979 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2980 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302981 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2982 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002983 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
2984 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002985 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002986 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2987 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302988 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2989 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002990 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
2991 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002992 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002993 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2994 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05302995 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2996 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08002997 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
2998 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07002999 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003000 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
3001 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303002 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
3003 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003004 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
3005 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003006 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003007 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
3008 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303009 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
3010 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003011 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
3012 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003013 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003014 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
3015 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303016 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
3017 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003018 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
3019 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003020 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003021 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
3022 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303023 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
3024 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003025 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
3026 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003027 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003028 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
3029 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303030 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
3031 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003032 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
3033 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003034 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003035 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
3036 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303037 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
3038 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003039 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
3040 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003041 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003042 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
3043 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303044 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
3045 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003046 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
3047 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003048 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003049 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
3050 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303051 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
3052 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003053 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
3054 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003055 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003056 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
3057 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303058 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
3059 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003060 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
3061 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003062 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003063
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003064 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003065 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003066 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003067 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003068 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003069 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003070 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003071 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003072 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003073 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003074 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003075 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003076 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003077 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003078 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003079 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003080 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003081 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003082 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003083 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003084 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003085 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003086 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003087 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003088 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003089 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003090 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003091 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003092
3093 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003094 {"ADC1", NULL, "AMIC1"},
3095 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003096 {"ADC3", NULL, "AMIC3"},
3097 {"ADC4", NULL, "AMIC4"},
3098 {"ADC5", NULL, "AMIC5"},
3099 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003100
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003101 /* AUX PGA Connections */
3102 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3103 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3104 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3105 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3106 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3107 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3108 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3109 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3110 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3111 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3112 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3113 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3114 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3115 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3116 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3117 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3118 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3119 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3120 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3121 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3122 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3123 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3124 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3125 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3126 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3127 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3128 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3129 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3130 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3131 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3132 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3133 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3134 {"AUX_PGA_Left", NULL, "AMIC5"},
3135 {"AUX_PGA_Right", NULL, "AMIC6"},
3136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003137 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003138 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
3139 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
3140 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
3141 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
3142 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003143 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003144 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
3145 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
3146 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
3147 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003148
3149 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
3150 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
3151 {"MIC BIAS1 External", NULL, "LDO_H"},
3152 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
3153 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
3154 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
3155 {"MIC BIAS2 External", NULL, "LDO_H"},
3156 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
3157 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
3158 {"MIC BIAS3 External", NULL, "LDO_H"},
3159 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003160};
3161
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003162static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
3163
3164 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
3165 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3166
3167 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
3168
3169 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
3170 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
3171 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
3172
3173 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3174 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3175
3176 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3177 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
3178 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
3179};
3180
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003181
3182static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
3183
3184 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
3185 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3186
3187 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
3188
3189 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
3190
3191 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3192 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3193
3194 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3195};
3196
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003197static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
3198{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003199 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303200 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003201
3202 if (TABLA_IS_1_X(tabla_core->version)) {
3203 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
3204 if (tabla_1_reg_readable[i] == reg)
3205 return 1;
3206 }
3207 } else {
3208 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
3209 if (tabla_2_reg_readable[i] == reg)
3210 return 1;
3211 }
3212 }
3213
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003214 return tabla_reg_readable[reg];
3215}
3216
3217static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3218{
3219 /* Registers lower than 0x100 are top level registers which can be
3220 * written by the Tabla core driver.
3221 */
3222
3223 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3224 return 1;
3225
Ben Romberger1f045a72011-11-04 10:14:57 -07003226 /* IIR Coeff registers are not cacheable */
3227 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
3228 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
3229 return 1;
3230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003231 return 0;
3232}
3233
3234#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3235static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
3236 unsigned int value)
3237{
3238 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003239 BUG_ON(reg > TABLA_MAX_REGISTER);
3240
3241 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242 ret = snd_soc_cache_write(codec, reg, value);
3243 if (ret != 0)
3244 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3245 reg, ret);
3246 }
3247
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303248 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003249}
3250static unsigned int tabla_read(struct snd_soc_codec *codec,
3251 unsigned int reg)
3252{
3253 unsigned int val;
3254 int ret;
3255
3256 BUG_ON(reg > TABLA_MAX_REGISTER);
3257
3258 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
3259 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003260 ret = snd_soc_cache_read(codec, reg, &val);
3261 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003262 return val;
3263 } else
3264 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3265 reg, ret);
3266 }
3267
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303268 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003269 return val;
3270}
3271
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003272static s16 tabla_get_current_v_ins(struct tabla_priv *tabla, bool hu)
3273{
3274 s16 v_ins;
3275 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3276 tabla->mbhc_micbias_switched)
3277 v_ins = hu ? (s16)tabla->mbhc_data.adj_v_ins_hu :
3278 (s16)tabla->mbhc_data.adj_v_ins_h;
3279 else
3280 v_ins = hu ? (s16)tabla->mbhc_data.v_ins_hu :
3281 (s16)tabla->mbhc_data.v_ins_h;
3282 return v_ins;
3283}
3284
3285static s16 tabla_get_current_v_hs_max(struct tabla_priv *tabla)
3286{
3287 s16 v_hs_max;
3288 struct tabla_mbhc_plug_type_cfg *plug_type;
3289
3290 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
3291 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3292 tabla->mbhc_micbias_switched)
3293 v_hs_max = tabla->mbhc_data.adj_v_hs_max;
3294 else
3295 v_hs_max = plug_type->v_hs_max;
3296 return v_hs_max;
3297}
3298
Bradley Rubincb1e2732011-06-23 16:49:20 -07003299static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3300{
Joonwoo Parkc0672392012-01-11 11:03:14 -08003301 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08003302 struct tabla_mbhc_btn_detect_cfg *btn_det;
3303 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003304 const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
3305
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003306 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003307
Joonwoo Park0976d012011-12-22 11:48:18 -08003308 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003309 v_ins_hu & 0xFF);
Joonwoo Park0976d012011-12-22 11:48:18 -08003310 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003311 (v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003312
Joonwoo Park0976d012011-12-22 11:48:18 -08003313 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
3314 tabla->mbhc_data.v_b1_hu & 0xFF);
3315 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
3316 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
3317
3318 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
3319 tabla->mbhc_data.v_b1_h & 0xFF);
3320 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
3321 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
3322
3323 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
3324 tabla->mbhc_data.v_brh & 0xFF);
3325 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
3326 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
3327
3328 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
3329 tabla->mbhc_data.v_brl & 0xFF);
3330 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
3331 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
3332
Joonwoo Parkc0672392012-01-11 11:03:14 -08003333 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003334 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08003335 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003336 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
3337 tabla->mbhc_data.npoll);
3338 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
3339 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08003340 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003341 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
3342 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003343}
3344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003345static int tabla_startup(struct snd_pcm_substream *substream,
3346 struct snd_soc_dai *dai)
3347{
Kuirong Wanga545e722012-02-06 19:12:54 -08003348 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003349 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3350 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003351 if ((tabla_core != NULL) &&
3352 (tabla_core->dev != NULL) &&
3353 (tabla_core->dev->parent != NULL))
3354 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003355
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003356 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003357}
3358
3359static void tabla_shutdown(struct snd_pcm_substream *substream,
3360 struct snd_soc_dai *dai)
3361{
Kuirong Wanga545e722012-02-06 19:12:54 -08003362 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003363 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3364 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003365 if ((tabla_core != NULL) &&
3366 (tabla_core->dev != NULL) &&
3367 (tabla_core->dev->parent != NULL)) {
3368 pm_runtime_mark_last_busy(tabla_core->dev->parent);
3369 pm_runtime_put(tabla_core->dev->parent);
3370 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003371}
3372
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003373int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003374{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003375 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3376
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003377 pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
3378 dapm);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003379 if (dapm)
3380 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003381 if (mclk_enable) {
3382 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003383
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003384 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07003385 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003386 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003387 TABLA_BANDGAP_AUDIO_MODE);
3388 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003389 tabla_codec_calibrate_hs_polling(codec);
3390 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303391 } else {
3392 tabla_codec_enable_bandgap(codec,
3393 TABLA_BANDGAP_AUDIO_MODE);
3394 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003395 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003396 } else {
3397
3398 if (!tabla->mclk_enabled) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003399 if (dapm)
3400 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003401 pr_err("Error, MCLK already diabled\n");
3402 return -EINVAL;
3403 }
3404 tabla->mclk_enabled = false;
3405
3406 if (tabla->mbhc_polling_active) {
3407 if (!tabla->mclk_enabled) {
3408 tabla_codec_pause_hs_polling(codec);
3409 tabla_codec_enable_bandgap(codec,
3410 TABLA_BANDGAP_MBHC_MODE);
3411 tabla_enable_rx_bias(codec, 1);
3412 tabla_codec_enable_clock_block(codec, 1);
3413 tabla_codec_calibrate_hs_polling(codec);
3414 tabla_codec_start_hs_polling(codec);
3415 }
3416 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
3417 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303418 } else {
3419 tabla_codec_disable_clock_block(codec);
3420 tabla_codec_enable_bandgap(codec,
3421 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003422 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003424 if (dapm)
3425 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003426 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003427}
3428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003429static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
3430 int clk_id, unsigned int freq, int dir)
3431{
3432 pr_debug("%s\n", __func__);
3433 return 0;
3434}
3435
3436static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3437{
Santosh Mardie15e2302011-11-15 10:39:23 +05303438 u8 val = 0;
3439 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003441 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05303442 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3443 case SND_SOC_DAIFMT_CBS_CFS:
3444 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303445 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003446 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303447 snd_soc_update_bits(dai->codec,
3448 TABLA_A_CDC_CLK_TX_I2S_CTL,
3449 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003450 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303451 snd_soc_update_bits(dai->codec,
3452 TABLA_A_CDC_CLK_RX_I2S_CTL,
3453 TABLA_I2S_MASTER_MODE_MASK, 0);
3454 }
3455 break;
3456 case SND_SOC_DAIFMT_CBM_CFM:
3457 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303458 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303459 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003460 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303461 snd_soc_update_bits(dai->codec,
3462 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003463 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303464 snd_soc_update_bits(dai->codec,
3465 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
3466 }
3467 break;
3468 default:
3469 return -EINVAL;
3470 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003471 return 0;
3472}
3473
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003474static int tabla_set_channel_map(struct snd_soc_dai *dai,
3475 unsigned int tx_num, unsigned int *tx_slot,
3476 unsigned int rx_num, unsigned int *rx_slot)
3477
3478{
3479 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3480 u32 i = 0;
3481 if (!tx_slot && !rx_slot) {
3482 pr_err("%s: Invalid\n", __func__);
3483 return -EINVAL;
3484 }
3485 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3486
Neema Shettyd3a89262012-02-16 10:23:50 -08003487 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003488 for (i = 0; i < rx_num; i++) {
3489 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
3490 tabla->dai[dai->id - 1].ch_act = 0;
3491 tabla->dai[dai->id - 1].ch_tot = rx_num;
3492 }
3493 } else if (dai->id == AIF1_CAP) {
3494 for (i = 0; i < tx_num; i++) {
3495 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
3496 tabla->dai[dai->id - 1].ch_act = 0;
3497 tabla->dai[dai->id - 1].ch_tot = tx_num;
3498 }
3499 }
3500 return 0;
3501}
3502
3503static int tabla_get_channel_map(struct snd_soc_dai *dai,
3504 unsigned int *tx_num, unsigned int *tx_slot,
3505 unsigned int *rx_num, unsigned int *rx_slot)
3506
3507{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303508 struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003509
3510 u32 cnt = 0;
3511 u32 tx_ch[SLIM_MAX_TX_PORTS];
3512 u32 rx_ch[SLIM_MAX_RX_PORTS];
3513
3514 if (!rx_slot && !tx_slot) {
3515 pr_err("%s: Invalid\n", __func__);
3516 return -EINVAL;
3517 }
3518 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
3519 /* for virtual port, codec driver needs to do
3520 * housekeeping, for now should be ok
3521 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303522 wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003523 if (dai->id == AIF1_PB) {
3524 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3525 while (cnt < *rx_num) {
3526 rx_slot[cnt] = rx_ch[cnt];
3527 cnt++;
3528 }
3529 } else if (dai->id == AIF1_CAP) {
3530 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3531 while (cnt < *tx_num) {
3532 tx_slot[cnt] = tx_ch[6 + cnt];
3533 cnt++;
3534 }
Neema Shettyd3a89262012-02-16 10:23:50 -08003535 } else if (dai->id == AIF2_PB) {
3536 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3537 while (cnt < *rx_num) {
3538 rx_slot[cnt] = rx_ch[5 + cnt];
3539 cnt++;
3540 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003541 }
3542 return 0;
3543}
3544
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545static int tabla_hw_params(struct snd_pcm_substream *substream,
3546 struct snd_pcm_hw_params *params,
3547 struct snd_soc_dai *dai)
3548{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003549 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05303550 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07003551 u8 path, shift;
3552 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003553 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003554 u32 compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003555
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003556 pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
3557 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003558
3559 switch (params_rate(params)) {
3560 case 8000:
3561 tx_fs_rate = 0x00;
3562 rx_fs_rate = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003563 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003564 break;
3565 case 16000:
3566 tx_fs_rate = 0x01;
3567 rx_fs_rate = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003568 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003569 break;
3570 case 32000:
3571 tx_fs_rate = 0x02;
3572 rx_fs_rate = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003573 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003574 break;
3575 case 48000:
3576 tx_fs_rate = 0x03;
3577 rx_fs_rate = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003578 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003579 break;
3580 default:
3581 pr_err("%s: Invalid sampling rate %d\n", __func__,
3582 params_rate(params));
3583 return -EINVAL;
3584 }
3585
3586
3587 /**
3588 * If current dai is a tx dai, set sample rate to
3589 * all the txfe paths that are currently not active
3590 */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003591 if (dai->id == AIF1_CAP) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003592
3593 tx_state = snd_soc_read(codec,
3594 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3595
3596 for (path = 1, shift = 0;
3597 path <= NUM_DECIMATORS; path++, shift++) {
3598
3599 if (path == BITS_PER_REG + 1) {
3600 shift = 0;
3601 tx_state = snd_soc_read(codec,
3602 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
3603 }
3604
3605 if (!(tx_state & (1 << shift))) {
3606 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
3607 + (BITS_PER_REG*(path-1));
3608 snd_soc_update_bits(codec, tx_fs_reg,
3609 0x03, tx_fs_rate);
3610 }
3611 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303612 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303613 switch (params_format(params)) {
3614 case SNDRV_PCM_FORMAT_S16_LE:
3615 snd_soc_update_bits(codec,
3616 TABLA_A_CDC_CLK_TX_I2S_CTL,
3617 0x20, 0x20);
3618 break;
3619 case SNDRV_PCM_FORMAT_S32_LE:
3620 snd_soc_update_bits(codec,
3621 TABLA_A_CDC_CLK_TX_I2S_CTL,
3622 0x20, 0x00);
3623 break;
3624 default:
3625 pr_err("invalid format\n");
3626 break;
3627 }
3628 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
3629 0x03, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003630 } else {
3631 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303632 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003633 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003634 /**
3635 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3636 * with varying sample rates
3637 */
3638
3639 /**
3640 * If current dai is a rx dai, set sample rate to
3641 * all the rx paths that are currently not active
3642 */
Neema Shettyd3a89262012-02-16 10:23:50 -08003643 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003644
3645 rx_state = snd_soc_read(codec,
3646 TABLA_A_CDC_CLK_RX_B1_CTL);
3647
3648 for (path = 1, shift = 0;
3649 path <= NUM_INTERPOLATORS; path++, shift++) {
3650
3651 if (!(rx_state & (1 << shift))) {
3652 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
3653 + (BITS_PER_REG*(path-1));
3654 snd_soc_update_bits(codec, rx_fs_reg,
3655 0xE0, rx_fs_rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003656 if (comp_rx_path[shift] < COMPANDER_MAX)
3657 tabla->comp_fs[comp_rx_path[shift]]
3658 = compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003659 }
3660 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303661 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303662 switch (params_format(params)) {
3663 case SNDRV_PCM_FORMAT_S16_LE:
3664 snd_soc_update_bits(codec,
3665 TABLA_A_CDC_CLK_RX_I2S_CTL,
3666 0x20, 0x20);
3667 break;
3668 case SNDRV_PCM_FORMAT_S32_LE:
3669 snd_soc_update_bits(codec,
3670 TABLA_A_CDC_CLK_RX_I2S_CTL,
3671 0x20, 0x00);
3672 break;
3673 default:
3674 pr_err("invalid format\n");
3675 break;
3676 }
3677 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
3678 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003679 } else {
3680 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303681 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003682 }
3683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003684 return 0;
3685}
3686
3687static struct snd_soc_dai_ops tabla_dai_ops = {
3688 .startup = tabla_startup,
3689 .shutdown = tabla_shutdown,
3690 .hw_params = tabla_hw_params,
3691 .set_sysclk = tabla_set_dai_sysclk,
3692 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003693 .set_channel_map = tabla_set_channel_map,
3694 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003695};
3696
3697static struct snd_soc_dai_driver tabla_dai[] = {
3698 {
3699 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003700 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003701 .playback = {
3702 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003703 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003704 .formats = TABLA_FORMATS,
3705 .rate_max = 48000,
3706 .rate_min = 8000,
3707 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003708 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003709 },
3710 .ops = &tabla_dai_ops,
3711 },
3712 {
3713 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003714 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003715 .capture = {
3716 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003717 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003718 .formats = TABLA_FORMATS,
3719 .rate_max = 48000,
3720 .rate_min = 8000,
3721 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003722 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003723 },
3724 .ops = &tabla_dai_ops,
3725 },
Neema Shettyd3a89262012-02-16 10:23:50 -08003726 {
3727 .name = "tabla_rx2",
3728 .id = AIF2_PB,
3729 .playback = {
3730 .stream_name = "AIF2 Playback",
3731 .rates = WCD9310_RATES,
3732 .formats = TABLA_FORMATS,
3733 .rate_min = 8000,
3734 .rate_max = 48000,
3735 .channels_min = 1,
3736 .channels_max = 2,
3737 },
3738 .ops = &tabla_dai_ops,
3739 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003740};
Santosh Mardie15e2302011-11-15 10:39:23 +05303741
3742static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3743 {
3744 .name = "tabla_i2s_rx1",
3745 .id = 1,
3746 .playback = {
3747 .stream_name = "AIF1 Playback",
3748 .rates = WCD9310_RATES,
3749 .formats = TABLA_FORMATS,
3750 .rate_max = 48000,
3751 .rate_min = 8000,
3752 .channels_min = 1,
3753 .channels_max = 4,
3754 },
3755 .ops = &tabla_dai_ops,
3756 },
3757 {
3758 .name = "tabla_i2s_tx1",
3759 .id = 2,
3760 .capture = {
3761 .stream_name = "AIF1 Capture",
3762 .rates = WCD9310_RATES,
3763 .formats = TABLA_FORMATS,
3764 .rate_max = 48000,
3765 .rate_min = 8000,
3766 .channels_min = 1,
3767 .channels_max = 4,
3768 },
3769 .ops = &tabla_dai_ops,
3770 },
3771};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003772
3773static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3774 struct snd_kcontrol *kcontrol, int event)
3775{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303776 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003777 struct snd_soc_codec *codec = w->codec;
3778 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3779 u32 j = 0;
3780 u32 ret = 0;
3781 codec->control_data = dev_get_drvdata(codec->dev->parent);
3782 tabla = codec->control_data;
3783 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303784 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003785 return 0;
3786 switch (event) {
3787 case SND_SOC_DAPM_POST_PMU:
3788 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3789 if (tabla_dai[j].id == AIF1_CAP)
3790 continue;
3791 if (!strncmp(w->sname,
3792 tabla_dai[j].playback.stream_name, 13)) {
3793 ++tabla_p->dai[j].ch_act;
3794 break;
3795 }
3796 }
3797 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303798 ret = wcd9xxx_cfg_slim_sch_rx(tabla,
3799 tabla_p->dai[j].ch_num,
3800 tabla_p->dai[j].ch_tot,
3801 tabla_p->dai[j].rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003802 break;
3803 case SND_SOC_DAPM_POST_PMD:
3804 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3805 if (tabla_dai[j].id == AIF1_CAP)
3806 continue;
3807 if (!strncmp(w->sname,
3808 tabla_dai[j].playback.stream_name, 13)) {
3809 --tabla_p->dai[j].ch_act;
3810 break;
3811 }
3812 }
3813 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303814 ret = wcd9xxx_close_slim_sch_rx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003815 tabla_p->dai[j].ch_num,
3816 tabla_p->dai[j].ch_tot);
Bharath Ramachandramurthyda6fa7a2012-03-30 14:35:32 -07003817 usleep_range(5000, 5000);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003818 tabla_p->dai[j].rate = 0;
3819 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303820 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003821 tabla_p->dai[j].ch_tot = 0;
3822 }
3823 }
3824 return ret;
3825}
3826
3827static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3828 struct snd_kcontrol *kcontrol, int event)
3829{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303830 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003831 struct snd_soc_codec *codec = w->codec;
3832 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3833 /* index to the DAI ID, for now hardcoding */
3834 u32 j = 0;
3835 u32 ret = 0;
3836
3837 codec->control_data = dev_get_drvdata(codec->dev->parent);
3838 tabla = codec->control_data;
3839
3840 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303841 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003842 return 0;
3843 switch (event) {
3844 case SND_SOC_DAPM_POST_PMU:
3845 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003846 if (tabla_dai[j].id == AIF1_PB ||
3847 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003848 continue;
3849 if (!strncmp(w->sname,
3850 tabla_dai[j].capture.stream_name, 13)) {
3851 ++tabla_p->dai[j].ch_act;
3852 break;
3853 }
3854 }
3855 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303856 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003857 tabla_p->dai[j].ch_num,
3858 tabla_p->dai[j].ch_tot,
3859 tabla_p->dai[j].rate);
3860 break;
3861 case SND_SOC_DAPM_POST_PMD:
3862 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003863 if (tabla_dai[j].id == AIF1_PB ||
3864 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003865 continue;
3866 if (!strncmp(w->sname,
3867 tabla_dai[j].capture.stream_name, 13)) {
3868 --tabla_p->dai[j].ch_act;
3869 break;
3870 }
3871 }
3872 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303873 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003874 tabla_p->dai[j].ch_num,
3875 tabla_p->dai[j].ch_tot);
3876 tabla_p->dai[j].rate = 0;
3877 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303878 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003879 tabla_p->dai[j].ch_tot = 0;
3880 }
3881 }
3882 return ret;
3883}
3884
3885/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3886 * Might Need to have callbacks registered only for slimbus
3887 */
3888static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
3889 /*RX stuff */
3890 SND_SOC_DAPM_OUTPUT("EAR"),
3891
3892 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
3893
3894 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
3895 ARRAY_SIZE(dac1_switch)),
3896
3897 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3898 0, tabla_codec_enable_slimrx,
3899 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3900 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3901 0, tabla_codec_enable_slimrx,
3902 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3903
3904 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3905 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3906
Neema Shettyd3a89262012-02-16 10:23:50 -08003907 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3908 0, tabla_codec_enable_slimrx,
3909 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3910 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3911 0, tabla_codec_enable_slimrx,
3912 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3913
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003914 /* Headphone */
3915 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3916 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3917 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3918 SND_SOC_DAPM_POST_PMD),
3919 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
3920 hphl_switch, ARRAY_SIZE(hphl_switch)),
3921
3922 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
3923 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3924 SND_SOC_DAPM_POST_PMD),
3925
3926 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
3927 tabla_hphr_dac_event,
3928 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3929
3930 /* Speaker */
3931 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
3932 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
3933 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
3934 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
3935 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
3936
3937 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
3938 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3939 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3940 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
3941 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3942 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3943 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
3944 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3945 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3946 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
3947 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3948 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3949 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
3950 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3951 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3952
3953 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
3954 , tabla_lineout_dac_event,
3955 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3956 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
3957 , tabla_lineout_dac_event,
3958 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3959 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
3960 , tabla_lineout_dac_event,
3961 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3962 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
3963 &lineout3_ground_switch),
3964 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
3965 , tabla_lineout_dac_event,
3966 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3967 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
3968 &lineout4_ground_switch),
3969 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
3970 , tabla_lineout_dac_event,
3971 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3972
3973 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
3974 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3975 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
3976 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3977 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
3978 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3979 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
3980 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3981 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
3982 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3983 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
3984 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3985 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
3986 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU),
3987
3988 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
3989 &rx4_dsm_mux, tabla_codec_reset_interpolator,
3990 SND_SOC_DAPM_PRE_PMU),
3991
3992 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
3993 &rx6_dsm_mux, tabla_codec_reset_interpolator,
3994 SND_SOC_DAPM_PRE_PMU),
3995
3996 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
3997 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
3998
3999 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4000 &rx_mix1_inp1_mux),
4001 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4002 &rx_mix1_inp2_mux),
4003 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4004 &rx2_mix1_inp1_mux),
4005 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4006 &rx2_mix1_inp2_mux),
4007 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4008 &rx3_mix1_inp1_mux),
4009 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4010 &rx3_mix1_inp2_mux),
4011 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4012 &rx4_mix1_inp1_mux),
4013 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4014 &rx4_mix1_inp2_mux),
4015 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4016 &rx5_mix1_inp1_mux),
4017 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4018 &rx5_mix1_inp2_mux),
4019 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4020 &rx6_mix1_inp1_mux),
4021 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4022 &rx6_mix1_inp2_mux),
4023 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4024 &rx7_mix1_inp1_mux),
4025 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4026 &rx7_mix1_inp2_mux),
4027
4028 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
4029 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
4030 SND_SOC_DAPM_PRE_PMD),
4031
4032 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
4033 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
4034 SND_SOC_DAPM_POST_PMD),
4035
4036 /* TX */
4037
4038 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
4039 0),
4040
4041 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
4042 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
4043
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004044 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
4045 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4046 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4047 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
4048 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4049 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4050
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004051 SND_SOC_DAPM_INPUT("AMIC1"),
4052 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
4053 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4054 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4055 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
4056 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4057 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4058 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
4059 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4060 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4061 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
4062 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4063 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4064
4065 SND_SOC_DAPM_INPUT("AMIC3"),
4066 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
4067 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4068 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4069
4070 SND_SOC_DAPM_INPUT("AMIC4"),
4071 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
4072 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4073 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4074
4075 SND_SOC_DAPM_INPUT("AMIC5"),
4076 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
4077 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4078
4079 SND_SOC_DAPM_INPUT("AMIC6"),
4080 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
4081 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4082
4083 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 -08004084 &dec1_mux, tabla_codec_enable_dec,
4085 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4086 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004087
4088 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 -08004089 &dec2_mux, tabla_codec_enable_dec,
4090 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4091 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004092
4093 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 -08004094 &dec3_mux, tabla_codec_enable_dec,
4095 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4096 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004097
4098 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 -08004099 &dec4_mux, tabla_codec_enable_dec,
4100 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4101 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004102
4103 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 -08004104 &dec5_mux, tabla_codec_enable_dec,
4105 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4106 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004107
4108 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 -08004109 &dec6_mux, tabla_codec_enable_dec,
4110 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4111 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004112
4113 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 -08004114 &dec7_mux, tabla_codec_enable_dec,
4115 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4116 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004117
4118 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 -08004119 &dec8_mux, tabla_codec_enable_dec,
4120 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4121 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004122
4123 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 -08004124 &dec9_mux, tabla_codec_enable_dec,
4125 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4126 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004127
4128 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 -08004129 &dec10_mux, tabla_codec_enable_dec,
4130 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4131 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004132
4133 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
4134 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
4135
4136 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
4137 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
4138 SND_SOC_DAPM_POST_PMD),
4139
4140 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
4141
4142 SND_SOC_DAPM_INPUT("AMIC2"),
4143 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
4144 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4145 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4146 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
4147 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4148 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4149 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
4150 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4151 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4152 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
4153 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4154 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4155 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
4156 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4157 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4158 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
4159 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4160 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4161 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
4162 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4163 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4164 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
4165 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4166 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4167
4168 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
4169 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
4170 0, 0),
4171
4172 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
4173 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
4174 4, 0),
4175
4176 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
4177 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
4178 5, 0),
4179
4180 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
4181 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4182 0, tabla_codec_enable_slimtx,
4183 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4184
4185 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
4186 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4187 0, tabla_codec_enable_slimtx,
4188 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4189
4190 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
4191 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
4192 0, 0, tabla_codec_enable_slimtx,
4193 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4194
4195 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
4196 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
4197 0, 0, tabla_codec_enable_slimtx,
4198 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4199
4200 /* Digital Mic Inputs */
4201 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
4202 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4203 SND_SOC_DAPM_POST_PMD),
4204
4205 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
4206 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4207 SND_SOC_DAPM_POST_PMD),
4208
4209 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
4210 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4211 SND_SOC_DAPM_POST_PMD),
4212
4213 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
4214 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4215 SND_SOC_DAPM_POST_PMD),
4216
4217 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
4218 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4219 SND_SOC_DAPM_POST_PMD),
4220 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
4221 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4222 SND_SOC_DAPM_POST_PMD),
4223
4224 /* Sidetone */
4225 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
4226 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08004227
4228 /* AUX PGA */
4229 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
4230 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4231 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4232 SND_SOC_DAPM_POST_PMD),
4233
4234 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
4235 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4236 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4237 SND_SOC_DAPM_POST_PMD),
4238
4239 /* Lineout, ear and HPH PA Mixers */
4240 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
4241 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
4242
4243 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4244 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4245
4246 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4247 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4248
4249 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4250 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
4251
4252 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
4253 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
4254
4255 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
4256 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
4257
4258 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
4259 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
4260
4261 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4262 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004263};
4264
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004265static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004266{
4267 u8 bias_msb, bias_lsb;
4268 short bias_value;
4269
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004270 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
4271 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
4272 bias_value = (bias_msb << 8) | bias_lsb;
4273 return bias_value;
4274}
4275
4276static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
4277{
4278 u8 bias_msb, bias_lsb;
4279 short bias_value;
4280
4281 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
4282 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
4283 bias_value = (bias_msb << 8) | bias_lsb;
4284 return bias_value;
4285}
4286
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004287static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004288{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004289 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
4290}
4291
4292static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4293 bool override_bypass, bool noreldetection)
4294{
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004295 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004296 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4297
4298 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4299 if (noreldetection)
4300 tabla_turn_onoff_rel_detection(codec, false);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004301
Joonwoo Park925914c2012-01-05 13:35:18 -08004302 /* Turn on the override */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004303 if (!override_bypass)
4304 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004305 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004306 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4307 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
4308 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004309 usleep_range(tabla->mbhc_data.t_sta_dce,
4310 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004311 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08004312 usleep_range(tabla->mbhc_data.t_dce,
4313 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004314 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004315 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004316 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004317 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4318 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004319 usleep_range(tabla->mbhc_data.t_sta_dce,
4320 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08004321 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4322 usleep_range(tabla->mbhc_data.t_sta,
4323 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004324 bias_value = tabla_codec_read_sta_result(codec);
4325 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4326 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004327 }
Joonwoo Park925914c2012-01-05 13:35:18 -08004328 /* Turn off the override after measuring mic voltage */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004329 if (!override_bypass)
4330 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4331
4332 if (noreldetection)
4333 tabla_turn_onoff_rel_detection(codec, true);
4334 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004335
Bradley Rubincb1e2732011-06-23 16:49:20 -07004336 return bias_value;
4337}
4338
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004339static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4340 bool norel)
4341{
4342 return __tabla_codec_sta_dce(codec, dce, false, norel);
4343}
4344
4345/* called only from interrupt which is under codec_resource_lock acquisition */
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004346static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004347{
4348 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004349 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004350 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004351
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004352 pr_debug("%s: enter, mclk_enabled %d\n", __func__, tabla->mclk_enabled);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004353 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004354 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004355 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004356 }
4357
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004358 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004359 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004360 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004361 tabla_codec_enable_clock_block(codec, 1);
4362 }
4363
4364 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4365
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004366 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004367 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4368 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004369
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004370 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004371
4372 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004373 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004374
4375 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4376 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4377 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4378
4379 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004380 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4381 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004382
Joonwoo Park925914c2012-01-05 13:35:18 -08004383 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004384 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4385
Bradley Rubincb1e2732011-06-23 16:49:20 -07004386 tabla_codec_calibrate_hs_polling(codec);
4387
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004388 /* don't flip override */
4389 bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004390 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4391 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004392 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004393
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004394 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004395}
4396
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004397static int tabla_cancel_btn_work(struct tabla_priv *tabla)
4398{
4399 int r = 0;
4400 struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
4401
4402 if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
4403 /* if scheduled mbhc_btn_dwork is canceled from here,
4404 * we have to unlock from here instead btn_work */
4405 wcd9xxx_unlock_sleep(core);
4406 r = 1;
4407 }
4408 return r;
4409}
4410
4411/* called under codec_resource_lock acquisition */
4412void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
Joonwoo Park03324832012-03-19 19:36:16 -07004413{
4414 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004415 u8 wg_time;
4416
4417 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4418 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07004419
4420 /* If headphone PA is on, check if userspace receives
4421 * removal event to sync-up PA's state */
4422 if (tabla_is_hph_pa_on(codec)) {
4423 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4424 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4425 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4426 } else {
4427 pr_debug("%s PA is off\n", __func__);
4428 }
4429
4430 if (tabla_is_hph_dac_on(codec, 1))
4431 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4432 if (tabla_is_hph_dac_on(codec, 0))
4433 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004434
4435 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
4436 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
4437 0xC0, 0x00);
4438 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
4439 0xC0, 0x00);
4440 usleep_range(wg_time * 1000, wg_time * 1000);
4441}
4442
4443static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
4444{
4445 bool pa_turned_on = false;
4446 struct snd_soc_codec *codec = tabla->codec;
4447 u8 wg_time;
4448
4449 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4450 wg_time += 1;
4451
4452 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4453 &tabla->hph_pa_dac_state)) {
4454 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4455 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4456 0xC0, 0xC0);
4457 }
4458 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4459 &tabla->hph_pa_dac_state)) {
4460 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4461 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4462 0xC0, 0xC0);
4463 }
4464
4465 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4466 &tabla->hph_pa_dac_state)) {
4467 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4468 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4469 1 << 4);
4470 pa_turned_on = true;
4471 }
4472 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4473 &tabla->hph_pa_dac_state)) {
4474 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4475 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4476 1 << 5);
4477 pa_turned_on = true;
4478 }
4479
4480 if (pa_turned_on) {
4481 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4482 __func__);
4483 usleep_range(wg_time * 1000, wg_time * 1000);
4484 }
4485}
4486
4487/* called under codec_resource_lock acquisition */
4488static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4489 enum snd_jack_types jack_type)
4490{
4491 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4492
4493 if (!insertion) {
4494 /* Report removal */
4495 tabla->hph_status &= ~jack_type;
4496 if (tabla->mbhc_cfg.headset_jack) {
4497 /* cancel possibly scheduled btn work and
4498 * report release if we reported button press */
4499 if (tabla_cancel_btn_work(tabla)) {
4500 pr_debug("%s: button press is canceled\n",
4501 __func__);
4502 } else if (tabla->buttons_pressed) {
4503 pr_debug("%s: Reporting release for reported "
4504 "button press %d\n", __func__,
4505 jack_type);
4506 tabla_snd_soc_jack_report(tabla,
4507 tabla->mbhc_cfg.button_jack, 0,
4508 tabla->buttons_pressed);
4509 tabla->buttons_pressed &=
4510 ~TABLA_JACK_BUTTON_MASK;
4511 }
4512 pr_debug("%s: Reporting removal %d\n", __func__,
4513 jack_type);
4514 tabla_snd_soc_jack_report(tabla,
4515 tabla->mbhc_cfg.headset_jack,
4516 tabla->hph_status,
4517 TABLA_JACK_MASK);
4518 }
4519 tabla_set_and_turnoff_hph_padac(codec);
4520 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
4521 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4522 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
4523 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4524 tabla->current_plug = PLUG_TYPE_NONE;
4525 tabla->mbhc_polling_active = false;
4526 } else {
4527 /* Report insertion */
4528 tabla->hph_status |= jack_type;
4529
4530 if (jack_type == SND_JACK_HEADPHONE)
4531 tabla->current_plug = PLUG_TYPE_HEADPHONE;
4532 else if (jack_type == SND_JACK_HEADSET) {
4533 tabla->mbhc_polling_active = true;
4534 tabla->current_plug = PLUG_TYPE_HEADSET;
4535 }
4536 if (tabla->mbhc_cfg.headset_jack) {
4537 pr_debug("%s: Reporting insertion %d\n", __func__,
4538 jack_type);
4539 tabla_snd_soc_jack_report(tabla,
4540 tabla->mbhc_cfg.headset_jack,
4541 tabla->hph_status,
4542 TABLA_JACK_MASK);
4543 }
4544 tabla_clr_and_turnon_hph_padac(tabla);
4545 }
Joonwoo Park03324832012-03-19 19:36:16 -07004546}
4547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004548static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07004549 int insertion, int trigger,
4550 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004551{
4552 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004553 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08004554 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004555 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004556 const struct tabla_mbhc_plug_detect_cfg *plug_det =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004557 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004558
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004559 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004560 pr_err("Error, no tabla calibration\n");
4561 return -EINVAL;
4562 }
4563
4564 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
4565
Joonwoo Park03324832012-03-19 19:36:16 -07004566 /* Make sure mic bias and Mic line schmitt trigger
4567 * are turned OFF
4568 */
4569 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
4570 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
4571
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004572 if (insertion) {
Joonwoo Park03324832012-03-19 19:36:16 -07004573 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004574
Joonwoo Park03324832012-03-19 19:36:16 -07004575 /* DAPM can manipulate PA/DAC bits concurrently */
4576 if (padac_off == true) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004577 tabla_set_and_turnoff_hph_padac(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004578 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004579
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004580 if (trigger & MBHC_USE_HPHL_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07004581 /* Enable HPH Schmitt Trigger */
4582 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
4583 0x11);
4584 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
4585 plug_det->hph_current << 2);
4586 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
4587 0x02);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004588 }
4589 if (trigger & MBHC_USE_MB_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07004590 /* enable the mic line schmitt trigger */
4591 snd_soc_update_bits(codec,
4592 tabla->mbhc_bias_regs.mbhc_reg,
4593 0x60, plug_det->mic_current << 5);
4594 snd_soc_update_bits(codec,
4595 tabla->mbhc_bias_regs.mbhc_reg,
4596 0x80, 0x80);
4597 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4598 snd_soc_update_bits(codec,
4599 tabla->mbhc_bias_regs.ctl_reg, 0x01,
4600 0x00);
4601 snd_soc_update_bits(codec,
4602 tabla->mbhc_bias_regs.mbhc_reg,
4603 0x10, 0x10);
4604 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004605
4606 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004607 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004608 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004609 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004610 /* Make sure the HPH schmitt trigger is OFF */
4611 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
4612
4613 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07004614 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
4615 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004616 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08004617 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004618 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4619 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004620 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004621 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4622 0x10, 0x10);
4623
4624 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004625 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004626 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004627
4628 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004629 /* called called by interrupt */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004630 if (!(tabla->clock_active)) {
4631 tabla_codec_enable_config_mode(codec, 1);
4632 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004633 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004634 usleep_range(generic->t_shutdown_plug_rem,
4635 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004636 tabla_codec_enable_config_mode(codec, 0);
4637 } else
4638 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004639 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004640 }
4641
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004642 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004643
4644 /* If central bandgap disabled */
4645 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
4646 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004647 usleep_range(generic->t_bg_fast_settle,
4648 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004649 central_bias_enabled = 1;
4650 }
4651
4652 /* If LDO_H disabled */
4653 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
4654 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
4655 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004656 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004657 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
4658
4659 if (central_bias_enabled)
4660 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
4661 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004662
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004663 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004664 tabla->mbhc_cfg.micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004665
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304666 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004667 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4668 return 0;
4669}
4670
Joonwoo Park0976d012011-12-22 11:48:18 -08004671static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4672 s16 vin_mv)
4673{
Joonwoo Park0976d012011-12-22 11:48:18 -08004674 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004675 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08004676 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07004677 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004678
4679 tabla = snd_soc_codec_get_drvdata(codec);
4680 mb_mv = tabla->mbhc_data.micb_mv;
4681
4682 if (mb_mv == 0) {
4683 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4684 return -EINVAL;
4685 }
4686
4687 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004688 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
4689 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004690 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004691 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
4692 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004693 }
4694 in = (u32) diff * vin_mv;
4695
Joonwoo Park03324832012-03-19 19:36:16 -07004696 value = (u16) (in / mb_mv) + zero;
4697 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004698}
4699
4700static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4701 u16 bias_value)
4702{
4703 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004704 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08004705 s32 mv;
4706
4707 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004708 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004709 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004710 z = (tabla->mbhc_data.dce_z);
4711 mb = (tabla->mbhc_data.dce_mb);
4712 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004713 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004714 z = (tabla->mbhc_data.sta_z);
4715 mb = (tabla->mbhc_data.sta_mb);
4716 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004717 }
4718
4719 return mv;
4720}
4721
Joonwoo Park03324832012-03-19 19:36:16 -07004722static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004723{
4724 struct delayed_work *delayed_work;
4725 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08004726 short bias_value;
4727 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07004728 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004729
4730 pr_debug("%s:\n", __func__);
4731
4732 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07004733 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004734 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004735
4736 if (tabla) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004737 if (tabla->mbhc_cfg.button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004738 bias_value = tabla_codec_read_sta_result(tabla->codec);
4739 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304740 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004741 bias_value = tabla_codec_read_dce_result(tabla->codec);
4742 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304743 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004744 pr_debug("%s: Reporting long button press event"
4745 " STA: %d, DCE: %d\n", __func__,
4746 sta_mv, dce_mv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004747 tabla_snd_soc_jack_report(tabla,
4748 tabla->mbhc_cfg.button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07004749 tabla->buttons_pressed,
4750 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004751 }
4752 } else {
4753 pr_err("%s: Bad tabla private data\n", __func__);
4754 }
4755
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004756 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07004757 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004758}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004759
Joonwoo Park0976d012011-12-22 11:48:18 -08004760void tabla_mbhc_cal(struct snd_soc_codec *codec)
4761{
4762 struct tabla_priv *tabla;
4763 struct tabla_mbhc_btn_detect_cfg *btn_det;
4764 u8 cfilt_mode, bg_mode;
4765 u8 ncic, nmeas, navg;
4766 u32 mclk_rate;
4767 u32 dce_wait, sta_wait;
4768 u8 *n_cic;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004769 void *calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08004770
4771 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004772 calibration = tabla->mbhc_cfg.calibration;
4773
4774 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4775 tabla_turn_onoff_rel_detection(codec, false);
Joonwoo Park0976d012011-12-22 11:48:18 -08004776
4777 /* First compute the DCE / STA wait times
4778 * depending on tunable parameters.
4779 * The value is computed in microseconds
4780 */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004781 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004782 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08004783 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004784 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
4785 navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
4786 mclk_rate = tabla->mbhc_cfg.mclk_rate;
Joonwoo Park433149a2012-01-11 09:53:54 -08004787 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
4788 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08004789
4790 tabla->mbhc_data.t_dce = dce_wait;
4791 tabla->mbhc_data.t_sta = sta_wait;
4792
4793 /* LDOH and CFILT are already configured during pdata handling.
4794 * Only need to make sure CFILT and bandgap are in Fast mode.
4795 * Need to restore defaults once calculation is done.
4796 */
4797 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4798 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
4799 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
4800 0x02);
4801
4802 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
4803 * to perform ADC calibration
4804 */
4805 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004806 tabla->mbhc_cfg.micbias << 5);
Joonwoo Park0976d012011-12-22 11:48:18 -08004807 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
4808 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
4809 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
4810 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
4811
4812 /* DCE measurement for 0 volts */
4813 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4814 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4815 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004816 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4817 usleep_range(100, 100);
4818 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4819 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4820 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
4821
4822 /* DCE measurment for MB voltage */
4823 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4824 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
4825 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4826 usleep_range(100, 100);
4827 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4828 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4829 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
4830
4831 /* Sta measuremnt for 0 volts */
4832 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4833 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4834 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004835 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4836 usleep_range(100, 100);
4837 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4838 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4839 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
4840
4841 /* STA Measurement for MB Voltage */
4842 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4843 usleep_range(100, 100);
4844 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4845 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4846 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
4847
4848 /* Restore default settings. */
4849 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4850 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4851 cfilt_mode);
4852 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
4853
4854 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
4855 usleep_range(100, 100);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004856
4857 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4858 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004859}
4860
4861void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
4862 const enum tabla_mbhc_btn_det_mem mem)
4863{
4864 void *ret = &btn_det->_v_btn_low;
4865
4866 switch (mem) {
4867 case TABLA_BTN_DET_GAIN:
4868 ret += sizeof(btn_det->_n_cic);
4869 case TABLA_BTN_DET_N_CIC:
4870 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08004871 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08004872 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
4873 case TABLA_BTN_DET_V_BTN_HIGH:
4874 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
4875 case TABLA_BTN_DET_V_BTN_LOW:
4876 /* do nothing */
4877 break;
4878 default:
4879 ret = NULL;
4880 }
4881
4882 return ret;
4883}
4884
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004885static s16 tabla_scale_v_micb_vddio(struct tabla_priv *tabla, int v,
4886 bool tovddio)
4887{
4888 int r;
4889 int vddio_k, mb_k;
4890 vddio_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
4891 VDDIO_MICBIAS_MV);
4892 mb_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
4893 tabla->mbhc_data.micb_mv);
4894 if (tovddio)
4895 r = v * vddio_k / mb_k;
4896 else
4897 r = v * mb_k / vddio_k;
4898 return r;
4899}
4900
Joonwoo Park0976d012011-12-22 11:48:18 -08004901static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
4902{
4903 struct tabla_priv *tabla;
4904 s16 btn_mv = 0, btn_delta_mv;
4905 struct tabla_mbhc_btn_detect_cfg *btn_det;
4906 struct tabla_mbhc_plug_type_cfg *plug_type;
4907 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004908 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08004909 int i;
4910
4911 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004912 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
4913 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004914
Joonwoo Parkc0672392012-01-11 11:03:14 -08004915 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004916 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07004917 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08004918 tabla->mbhc_data.nbounce_wait = 30;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004919 } else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004920 tabla->mbhc_data.npoll = 7;
4921 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004922 }
Joonwoo Park0976d012011-12-22 11:48:18 -08004923
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004924 tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
4925 (tabla->mbhc_cfg.mclk_rate / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08004926 n_ready[tabla_codec_mclk_index(tabla)]) +
4927 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08004928 tabla->mbhc_data.v_ins_hu =
4929 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
4930 tabla->mbhc_data.v_ins_h =
4931 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
4932
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004933 tabla->mbhc_data.v_inval_ins_low = TABLA_MBHC_FAKE_INSERT_LOW;
4934 if (tabla->mbhc_cfg.gpio)
4935 tabla->mbhc_data.v_inval_ins_high =
4936 TABLA_MBHC_FAKE_INSERT_HIGH;
4937 else
4938 tabla->mbhc_data.v_inval_ins_high =
4939 TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
4940
4941 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
4942 tabla->mbhc_data.adj_v_hs_max =
4943 tabla_scale_v_micb_vddio(tabla, plug_type->v_hs_max, true);
4944 tabla->mbhc_data.adj_v_ins_hu =
4945 tabla_codec_v_sta_dce(codec, STA,
4946 tabla->mbhc_data.adj_v_hs_max);
4947 tabla->mbhc_data.adj_v_ins_h =
4948 tabla_codec_v_sta_dce(codec, DCE,
4949 tabla->mbhc_data.adj_v_hs_max);
4950 tabla->mbhc_data.v_inval_ins_low =
4951 tabla_scale_v_micb_vddio(tabla,
4952 tabla->mbhc_data.v_inval_ins_low,
4953 false);
4954 tabla->mbhc_data.v_inval_ins_high =
4955 tabla_scale_v_micb_vddio(tabla,
4956 tabla->mbhc_data.v_inval_ins_high,
4957 false);
4958 }
4959
Joonwoo Park0976d012011-12-22 11:48:18 -08004960 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
4961 for (i = 0; i < btn_det->num_btn; i++)
4962 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
4963
4964 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
4965 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
Joonwoo Park0976d012011-12-22 11:48:18 -08004966 tabla->mbhc_data.v_b1_hu =
4967 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
4968
4969 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
4970
4971 tabla->mbhc_data.v_b1_huc =
4972 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
4973
4974 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
Joonwoo Park03324832012-03-19 19:36:16 -07004975 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
Joonwoo Park0976d012011-12-22 11:48:18 -08004976
4977 tabla->mbhc_data.v_no_mic =
4978 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
4979}
4980
4981void tabla_mbhc_init(struct snd_soc_codec *codec)
4982{
4983 struct tabla_priv *tabla;
4984 struct tabla_mbhc_general_cfg *generic;
4985 struct tabla_mbhc_btn_detect_cfg *btn_det;
4986 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08004987 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304988 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08004989
4990 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004991 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
4992 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004993
Joonwoo Park0976d012011-12-22 11:48:18 -08004994 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08004995 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004996 snd_soc_update_bits(codec,
4997 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
4998 0x07, n);
4999 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
5000 btn_det->c[n]);
5001 }
5002 }
5003 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
5004 btn_det->nc);
5005
5006 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
5007 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08005008 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08005009
5010 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08005011 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
5012 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08005013
5014 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
5015 generic->mbhc_nsa << 4);
5016
5017 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
5018 btn_det->n_meas);
5019
5020 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
5021
5022 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
5023
5024 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
5025 btn_det->mbhc_nsc << 3);
5026
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005027 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
5028 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08005029
5030 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07005031
5032 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Park0976d012011-12-22 11:48:18 -08005033}
5034
Patrick Lai64b43262011-12-06 17:29:15 -08005035static bool tabla_mbhc_fw_validate(const struct firmware *fw)
5036{
5037 u32 cfg_offset;
5038 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
5039 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
5040
5041 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
5042 return false;
5043
5044 /* previous check guarantees that there is enough fw data up
5045 * to num_btn
5046 */
5047 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
5048 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
5049 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
5050 return false;
5051
5052 /* previous check guarantees that there is enough fw data up
5053 * to start of impedance detection configuration
5054 */
5055 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
5056 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
5057
5058 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
5059 return false;
5060
5061 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
5062 return false;
5063
5064 return true;
5065}
Joonwoo Park03324832012-03-19 19:36:16 -07005066
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005067static int tabla_determine_button(const struct tabla_priv *priv,
5068 const s32 bias_mv)
5069{
5070 s16 *v_btn_low, *v_btn_high;
5071 struct tabla_mbhc_btn_detect_cfg *btn_det;
5072 int i, btn = -1;
5073
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005074 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005075 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
5076 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305077 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005078 for (i = 0; i < btn_det->num_btn; i++) {
5079 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
5080 btn = i;
5081 break;
5082 }
5083 }
5084
5085 if (btn == -1)
5086 pr_debug("%s: couldn't find button number for mic mv %d\n",
5087 __func__, bias_mv);
5088
5089 return btn;
5090}
5091
5092static int tabla_get_button_mask(const int btn)
5093{
5094 int mask = 0;
5095 switch (btn) {
5096 case 0:
5097 mask = SND_JACK_BTN_0;
5098 break;
5099 case 1:
5100 mask = SND_JACK_BTN_1;
5101 break;
5102 case 2:
5103 mask = SND_JACK_BTN_2;
5104 break;
5105 case 3:
5106 mask = SND_JACK_BTN_3;
5107 break;
5108 case 4:
5109 mask = SND_JACK_BTN_4;
5110 break;
5111 case 5:
5112 mask = SND_JACK_BTN_5;
5113 break;
5114 case 6:
5115 mask = SND_JACK_BTN_6;
5116 break;
5117 case 7:
5118 mask = SND_JACK_BTN_7;
5119 break;
5120 }
5121 return mask;
5122}
5123
Bradley Rubincb1e2732011-06-23 16:49:20 -07005124static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005125{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005126 int i, mask;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005127 short dce, sta, bias_value_dce;
5128 s32 mv, stamv, bias_mv_dce;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005129 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005130 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005131 const struct tabla_mbhc_btn_detect_cfg *d =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005132 TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005133 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005134 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305135 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07005136 int n_btn_meas = d->n_btn_meas;
5137 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005138
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005139 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005140
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005141 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5142 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
5143 pr_debug("%s: mbhc is being recovered, skip button press\n",
5144 __func__);
5145 goto done;
5146 }
5147
5148 priv->mbhc_state = MBHC_STATE_POTENTIAL;
5149
5150 if (!priv->mbhc_polling_active) {
5151 pr_warn("%s: mbhc polling is not active, skip button press\n",
5152 __func__);
5153 goto done;
5154 }
Joonwoo Park03324832012-03-19 19:36:16 -07005155
5156 dce = tabla_codec_read_dce_result(codec);
5157 mv = tabla_codec_sta_dce_v(codec, 1, dce);
5158
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005159 /* If GPIO interrupt already kicked in, ignore button press */
5160 if (priv->in_gpio_handler) {
5161 pr_debug("%s: GPIO State Changed, ignore button press\n",
5162 __func__);
5163 btn = -1;
5164 goto done;
5165 }
5166
Joonwoo Park03324832012-03-19 19:36:16 -07005167 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
5168 if (priv->mbhc_last_resume &&
5169 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
5170 pr_debug("%s: Button is already released shortly after "
5171 "resume\n", __func__);
5172 n_btn_meas = 0;
5173 } else {
5174 pr_debug("%s: Button is already released without "
5175 "resume", __func__);
5176 sta = tabla_codec_read_sta_result(codec);
5177 stamv = tabla_codec_sta_dce_v(codec, 0, sta);
5178 btn = tabla_determine_button(priv, mv);
5179 if (btn != tabla_determine_button(priv, stamv))
5180 btn = -1;
5181 goto done;
5182 }
5183 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005184
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005185 /* determine pressed button */
Joonwoo Park03324832012-03-19 19:36:16 -07005186 btnmeas[meas++] = tabla_determine_button(priv, mv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005187 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Joonwoo Park03324832012-03-19 19:36:16 -07005188 meas - 1, dce, mv, btnmeas[meas - 1]);
5189 if (n_btn_meas == 0)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005190 btn = btnmeas[0];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005191 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
5192 bias_value_dce = tabla_codec_sta_dce(codec, 1, false);
5193 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
5194 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005195 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005196 __func__, meas, bias_value_dce, bias_mv_dce,
5197 btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005198 /* if large enough measurements are collected,
5199 * start to check if last all n_btn_con measurements were
5200 * in same button low/high range */
5201 if (meas + 1 >= d->n_btn_con) {
5202 for (i = 0; i < d->n_btn_con; i++)
5203 if ((btnmeas[meas] < 0) ||
5204 (btnmeas[meas] != btnmeas[meas - i]))
5205 break;
5206 if (i == d->n_btn_con) {
5207 /* button pressed */
5208 btn = btnmeas[meas];
5209 break;
Joonwoo Park03324832012-03-19 19:36:16 -07005210 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
5211 /* if left measurements are less than n_btn_con,
5212 * it's impossible to find button number */
5213 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005214 }
5215 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005216 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005217
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005218 if (btn >= 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005219 if (priv->in_gpio_handler) {
5220 pr_debug("%s: GPIO already triggered, ignore button "
5221 "press\n", __func__);
5222 goto done;
5223 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005224 mask = tabla_get_button_mask(btn);
5225 priv->buttons_pressed |= mask;
Joonwoo Park03324832012-03-19 19:36:16 -07005226 wcd9xxx_lock_sleep(core);
5227 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
5228 msecs_to_jiffies(400)) == 0) {
5229 WARN(1, "Button pressed twice without release"
5230 "event\n");
5231 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005232 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08005233 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005234 pr_debug("%s: bogus button press, too short press?\n",
5235 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08005236 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005237
Joonwoo Park03324832012-03-19 19:36:16 -07005238 done:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005239 pr_debug("%s: leave\n", __func__);
5240 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005241 return IRQ_HANDLED;
5242}
5243
Joonwoo Park03324832012-03-19 19:36:16 -07005244static int tabla_is_fake_press(struct tabla_priv *priv)
5245{
5246 int i;
5247 int r = 0;
5248 struct snd_soc_codec *codec = priv->codec;
5249 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005250 s16 mb_v, v_ins_hu, v_ins_h;
5251
5252 v_ins_hu = tabla_get_current_v_ins(priv, true);
5253 v_ins_h = tabla_get_current_v_ins(priv, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005254
5255 for (i = 0; i < dces; i++) {
5256 usleep_range(10000, 10000);
5257 if (i == 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005258 mb_v = tabla_codec_sta_dce(codec, 0, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005259 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
5260 tabla_codec_sta_dce_v(codec, 0, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005261 if (mb_v < (s16)priv->mbhc_data.v_b1_hu ||
5262 mb_v > v_ins_hu) {
Joonwoo Park03324832012-03-19 19:36:16 -07005263 r = 1;
5264 break;
5265 }
5266 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005267 mb_v = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005268 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
5269 tabla_codec_sta_dce_v(codec, 1, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005270 if (mb_v < (s16)priv->mbhc_data.v_b1_h ||
5271 mb_v > v_ins_h) {
Joonwoo Park03324832012-03-19 19:36:16 -07005272 r = 1;
5273 break;
5274 }
5275 }
5276 }
5277
5278 return r;
5279}
5280
Bradley Rubincb1e2732011-06-23 16:49:20 -07005281static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005282{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08005283 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08005284 struct tabla_priv *priv = data;
5285 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005286
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005287 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07005288
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005289 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5290 priv->mbhc_state = MBHC_STATE_RELEASE;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005291
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005292 tabla_codec_drive_v_to_micbias(codec, 10000);
5293
Joonwoo Park03324832012-03-19 19:36:16 -07005294 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005295 ret = tabla_cancel_btn_work(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005296 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07005297 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005298 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005299 if (priv->mbhc_cfg.button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005300 tabla_snd_soc_jack_report(priv,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005301 priv->mbhc_cfg.button_jack, 0,
5302 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005303 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005304 if (tabla_is_fake_press(priv)) {
5305 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005306 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005307 } else if (priv->mbhc_cfg.button_jack) {
5308 if (priv->in_gpio_handler) {
5309 pr_debug("%s: GPIO kicked in, ignore\n",
5310 __func__);
5311 } else {
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005312 pr_debug("%s: Reporting short button "
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005313 "press and release\n",
5314 __func__);
5315 tabla_snd_soc_jack_report(priv,
5316 priv->mbhc_cfg.button_jack,
5317 priv->buttons_pressed,
5318 priv->buttons_pressed);
5319 tabla_snd_soc_jack_report(priv,
5320 priv->mbhc_cfg.button_jack, 0,
5321 priv->buttons_pressed);
5322 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005323 }
5324 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005325
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005326 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
5327 }
5328
Joonwoo Park03324832012-03-19 19:36:16 -07005329 tabla_codec_calibrate_hs_polling(codec);
5330
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005331 if (priv->mbhc_cfg.gpio)
5332 msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
Joonwoo Park03324832012-03-19 19:36:16 -07005333
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005334 tabla_codec_start_hs_polling(codec);
5335
5336 pr_debug("%s: leave\n", __func__);
5337 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005338 return IRQ_HANDLED;
5339}
5340
Bradley Rubincb1e2732011-06-23 16:49:20 -07005341static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
5342{
5343 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08005344 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005345 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005346
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005347 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005348 tabla_codec_enable_config_mode(codec, 1);
5349
5350 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
5351 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005352
Joonwoo Park0976d012011-12-22 11:48:18 -08005353 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
5354
5355 usleep_range(generic->t_shutdown_plug_rem,
5356 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005357
5358 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005359 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005360 tabla_codec_enable_config_mode(codec, 0);
5361
5362 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
5363}
5364
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005365static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005366{
5367 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005368
5369 tabla_codec_shutdown_hs_removal_detect(codec);
5370
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005371 if (!tabla->mclk_enabled) {
Asish Bhattacharya486745a2012-01-20 06:41:53 +05305372 tabla_codec_disable_clock_block(codec);
5373 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005374 }
5375
5376 tabla->mbhc_polling_active = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005377 tabla->mbhc_state = MBHC_STATE_NONE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005378}
5379
Patrick Lai49efeac2011-11-03 11:01:12 -07005380static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
5381{
5382 struct tabla_priv *tabla = data;
5383 struct snd_soc_codec *codec;
5384
5385 pr_info("%s: received HPHL OCP irq\n", __func__);
5386
5387 if (tabla) {
5388 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005389 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
5390 pr_info("%s: retry\n", __func__);
5391 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5392 0x00);
5393 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5394 0x10);
5395 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305396 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005397 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5398 tabla->hphlocp_cnt = 0;
5399 tabla->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005400 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005401 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005402 tabla->mbhc_cfg.headset_jack,
5403 tabla->hph_status,
5404 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005405 }
5406 } else {
5407 pr_err("%s: Bad tabla private data\n", __func__);
5408 }
5409
5410 return IRQ_HANDLED;
5411}
5412
5413static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
5414{
5415 struct tabla_priv *tabla = data;
5416 struct snd_soc_codec *codec;
5417
5418 pr_info("%s: received HPHR OCP irq\n", __func__);
5419
5420 if (tabla) {
5421 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005422 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
5423 pr_info("%s: retry\n", __func__);
5424 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5425 0x00);
5426 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5427 0x10);
5428 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305429 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005430 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5431 tabla->hphrocp_cnt = 0;
5432 tabla->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005433 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005434 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005435 tabla->mbhc_cfg.headset_jack,
5436 tabla->hph_status,
5437 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005438 }
5439 } else {
5440 pr_err("%s: Bad tabla private data\n", __func__);
5441 }
5442
5443 return IRQ_HANDLED;
5444}
5445
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005446static bool tabla_is_invalid_insertion_range(struct snd_soc_codec *codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005447 s32 mic_volt)
Joonwoo Park03324832012-03-19 19:36:16 -07005448{
5449 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005450 bool invalid = false;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005451 s16 v_hs_max;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005452
5453 /* Perform this check only when the high voltage headphone
5454 * needs to be considered as invalid
5455 */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005456 v_hs_max = tabla_get_current_v_hs_max(tabla);
5457 if (!tabla->mbhc_inval_hs_range_override && (mic_volt > v_hs_max))
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005458 invalid = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005459 else if (mic_volt < tabla->mbhc_data.v_inval_ins_high &&
5460 (mic_volt > tabla->mbhc_data.v_inval_ins_low))
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005461 invalid = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005462
5463 return invalid;
5464}
5465
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005466static bool tabla_is_inval_insert_delta(struct snd_soc_codec *codec,
5467 int mic_volt, int mic_volt_prev,
5468 int threshold)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005469{
5470 int delta = abs(mic_volt - mic_volt_prev);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005471 if (delta > threshold) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005472 pr_debug("%s: volt delta %dmv\n", __func__, delta);
Joonwoo Park03324832012-03-19 19:36:16 -07005473 return true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005474 }
Joonwoo Park03324832012-03-19 19:36:16 -07005475 return false;
5476}
5477
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005478static bool tabla_codec_is_invalid_plug(struct snd_soc_codec *codec,
5479 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
5480 enum tabla_mbhc_plug_type
5481 plug_type[MBHC_NUM_DCE_PLUG_DETECT])
5482{
5483 int i;
5484 bool r = false;
5485 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5486 struct tabla_mbhc_plug_type_cfg *plug_type_ptr =
5487 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005488 s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005489
5490 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
5491 if (mic_mv[i] < plug_type_ptr->v_no_mic)
5492 plug_type[i] = PLUG_TYPE_HEADPHONE;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005493 else if (mic_mv[i] < v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005494 plug_type[i] = PLUG_TYPE_HEADSET;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005495 else if (mic_mv[i] > v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005496 plug_type[i] = PLUG_TYPE_HIGH_HPH;
5497
5498 r = tabla_is_invalid_insertion_range(codec, mic_mv[i]);
5499 if (!r && i > 0) {
5500 if (plug_type[i-1] != plug_type[i])
5501 r = true;
5502 else
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005503 r = tabla_is_inval_insert_delta(codec,
5504 mic_mv[i], mic_mv[i - 1],
5505 TABLA_MBHC_FAKE_INS_DELTA_MV);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005506 }
5507 }
5508
5509 return r;
5510}
5511
5512/* called under codec_resource_lock acquisition */
5513void tabla_find_plug_and_report(struct snd_soc_codec *codec,
5514 enum tabla_mbhc_plug_type plug_type)
Joonwoo Park03324832012-03-19 19:36:16 -07005515{
5516 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005517
5518 if (plug_type == PLUG_TYPE_HEADPHONE
5519 && tabla->current_plug == PLUG_TYPE_NONE) {
5520 /* Nothing was reported previously
5521 * reporte a headphone
5522 */
5523 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5524 tabla_codec_cleanup_hs_polling(codec);
5525 } else if (plug_type == PLUG_TYPE_HEADSET) {
5526 /* If Headphone was reported previously, this will
5527 * only report the mic line
5528 */
5529 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5530 msleep(100);
5531 tabla_codec_start_hs_polling(codec);
5532 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
5533 if (tabla->current_plug == PLUG_TYPE_NONE)
5534 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5535 tabla_codec_cleanup_hs_polling(codec);
5536 pr_debug("setup mic trigger for further detection\n");
5537 tabla->lpi_enabled = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005538 tabla_codec_enable_hs_detect(codec, 1,
5539 MBHC_USE_MB_TRIGGER |
5540 MBHC_USE_HPHL_TRIGGER,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005541 false);
5542 }
5543}
5544
5545/* should be called under interrupt context that hold suspend */
5546static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla)
5547{
5548 pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
5549 tabla->hs_detect_work_stop = false;
5550 wcd9xxx_lock_sleep(tabla->codec->control_data);
5551 schedule_work(&tabla->hs_correct_plug_work);
5552}
5553
5554/* called under codec_resource_lock acquisition */
5555static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla)
5556{
5557 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
5558 tabla->hs_detect_work_stop = true;
5559 wmb();
5560 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5561 if (cancel_work_sync(&tabla->hs_correct_plug_work)) {
5562 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
5563 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5564 }
5565 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5566}
5567
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005568static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
5569{
5570 return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
5571 tabla->mbhc_cfg.gpio_level_insert);
5572}
5573
5574static void tabla_hs_correct_gpio_plug(struct work_struct *work)
5575{
5576 struct tabla_priv *tabla;
5577 struct snd_soc_codec *codec;
5578 int retry = 0, i;
5579 bool correction = false;
5580 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5581 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5582 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5583 unsigned long timeout;
5584
5585 tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
5586 codec = tabla->codec;
5587
5588 pr_debug("%s: enter\n", __func__);
5589 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
5590
5591 /* Keep override on during entire plug type correction work.
5592 *
5593 * This is okay under the assumption that any GPIO irqs which use
5594 * MBHC block cancel and sync this work so override is off again
5595 * prior to GPIO interrupt handler's MBHC block usage.
5596 * Also while this correction work is running, we can guarantee
5597 * DAPM doesn't use any MBHC block as this work only runs with
5598 * headphone detection.
5599 */
5600 tabla_turn_onoff_override(codec, true);
5601
5602 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5603 while (!time_after(jiffies, timeout)) {
5604 ++retry;
5605 rmb();
5606 if (tabla->hs_detect_work_stop) {
5607 pr_debug("%s: stop requested\n", __func__);
5608 break;
5609 }
5610
5611 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
5612 if (tabla_hs_gpio_level_remove(tabla)) {
5613 pr_debug("%s: GPIO value is low\n", __func__);
5614 break;
5615 }
5616
5617 /* can race with removal interrupt */
5618 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5619 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5620 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5621 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5622 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
5623 __func__, retry, mic_mv[i], mb_v[i]);
5624 }
5625 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5626
5627 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5628 pr_debug("Invalid plug in attempt # %d\n", retry);
5629 if (retry == NUM_ATTEMPTS_TO_REPORT &&
5630 tabla->current_plug == PLUG_TYPE_NONE) {
5631 tabla_codec_report_plug(codec, 1,
5632 SND_JACK_HEADPHONE);
5633 }
5634 } else if (!tabla_codec_is_invalid_plug(codec, mic_mv,
5635 plug_type) &&
5636 plug_type[0] == PLUG_TYPE_HEADPHONE) {
5637 pr_debug("Good headphone detected, continue polling mic\n");
5638 if (tabla->current_plug == PLUG_TYPE_NONE) {
5639 tabla_codec_report_plug(codec, 1,
5640 SND_JACK_HEADPHONE);
5641 }
5642 } else {
5643 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5644 /* Turn off override */
5645 tabla_turn_onoff_override(codec, false);
5646 tabla_find_plug_and_report(codec, plug_type[0]);
5647 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5648 pr_debug("Attempt %d found correct plug %d\n", retry,
5649 plug_type[0]);
5650 correction = true;
5651 break;
5652 }
5653 }
5654
5655 /* Turn off override */
5656 if (!correction)
5657 tabla_turn_onoff_override(codec, false);
5658
5659 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
5660 pr_debug("%s: leave\n", __func__);
5661 /* unlock sleep */
5662 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5663}
5664
5665/* called under codec_resource_lock acquisition */
5666static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
5667{
5668 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005669 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5670 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005671 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5672 int i;
5673
5674 pr_debug("%s: enter\n", __func__);
5675
5676 tabla_turn_onoff_override(codec, true);
5677 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5678 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
5679 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
5680
5681 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5682 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5683 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5684 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
5685 mic_mv[i]);
5686 }
5687 tabla_turn_onoff_override(codec, false);
5688
5689 if (tabla_hs_gpio_level_remove(tabla)) {
5690 pr_debug("%s: GPIO value is low when determining plug\n",
5691 __func__);
5692 return;
5693 }
5694
5695 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5696 tabla_schedule_hs_detect_plug(tabla);
5697 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5698 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5699
5700 tabla_schedule_hs_detect_plug(tabla);
5701 } else {
5702 pr_debug("%s: Valid plug found, determine plug type\n",
5703 __func__);
5704 tabla_find_plug_and_report(codec, plug_type[0]);
5705 }
5706}
5707
5708/* called under codec_resource_lock acquisition */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005709static void tabla_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
5710{
5711 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5712
5713 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
5714 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, on);
5715 if (on)
5716 usleep_range(5000, 5000);
5717 }
5718}
5719
5720/* called under codec_resource_lock acquisition */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005721static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
5722{
5723 int i;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005724 bool gndswitch, vddioswitch;
5725 int scaled;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005726 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5727 const struct tabla_mbhc_plug_detect_cfg *plug_det =
5728 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07005729 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005730 const bool vddio = (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
5731 !tabla->mbhc_micbias_switched);
5732 int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
5733 enum tabla_mbhc_plug_type plug_type[num_det];
5734 short mb_v[num_det];
5735 s32 mic_mv[num_det];
5736 bool inval = false;
Joonwoo Park03324832012-03-19 19:36:16 -07005737
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005738 /* Turn on the override,
5739 * tabla_codec_setup_hs_polling requires override on */
5740 tabla_turn_onoff_override(codec, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005741
5742 if (plug_det->t_ins_complete > 20)
5743 msleep(plug_det->t_ins_complete);
5744 else
5745 usleep_range(plug_det->t_ins_complete * 1000,
5746 plug_det->t_ins_complete * 1000);
5747
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005748 if (tabla->mbhc_cfg.gpio) {
5749 /* Turn off the override */
5750 tabla_turn_onoff_override(codec, false);
5751 if (tabla_hs_gpio_level_remove(tabla))
5752 pr_debug("%s: GPIO value is low when determining "
5753 "plug\n", __func__);
5754 else
5755 tabla_codec_decide_gpio_plug(codec);
5756 return;
5757 }
5758
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005759 /* performs DCEs for N times
5760 * 1st: check if voltage is in invalid range
5761 * 2nd - N-2nd: check voltage range and delta
5762 * N-1st: check voltage range, delta with HPHR GND switch
5763 * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
5764 for (i = 0; i < num_det && !inval; i++) {
5765 gndswitch = (i == (num_det - 1 - vddio));
5766 vddioswitch = (vddio && (i == num_det - 1));
5767 if (i == 0) {
5768 mb_v[i] = tabla_codec_setup_hs_polling(codec);
5769 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5770 inval = tabla_is_invalid_insertion_range(codec,
5771 mic_mv[i]);
5772 scaled = mic_mv[i];
5773 } else if (vddioswitch) {
5774 __tabla_codec_switch_micbias(tabla->codec, 1, false,
Joonwoo Park03324832012-03-19 19:36:16 -07005775 false);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005776 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5777 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5778 scaled = tabla_scale_v_micb_vddio(tabla, mic_mv[i],
5779 false);
5780 inval = (tabla_is_invalid_insertion_range(codec,
5781 mic_mv[i]) ||
5782 tabla_is_inval_insert_delta(codec, scaled,
5783 mic_mv[i - 1],
5784 TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
5785 __tabla_codec_switch_micbias(tabla->codec, 0, false,
5786 false);
5787 } else {
5788 if (gndswitch)
5789 tabla_codec_hphr_gnd_switch(codec, true);
5790 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5791 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5792 inval = (tabla_is_invalid_insertion_range(codec,
5793 mic_mv[i]) ||
5794 tabla_is_inval_insert_delta(codec, mic_mv[i],
5795 mic_mv[i - 1],
5796 TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
5797 if (gndswitch)
5798 tabla_codec_hphr_gnd_switch(codec, false);
5799 scaled = mic_mv[i];
Joonwoo Park03324832012-03-19 19:36:16 -07005800 }
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005801 pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
5802 "invalid %d\n", __func__,
5803 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
5804 inval);
Joonwoo Park03324832012-03-19 19:36:16 -07005805 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005806 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005807
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005808 plug_type_ptr =
5809 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07005810
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005811 for (i = 0; !inval && i < num_det; i++) {
5812 /*
5813 * If we are here, means none of the all
5814 * measurements are fake, continue plug type detection.
5815 * If all three measurements do not produce same
5816 * plug type, restart insertion detection
5817 */
Joonwoo Park03324832012-03-19 19:36:16 -07005818 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
5819 plug_type[i] = PLUG_TYPE_HEADPHONE;
5820 pr_debug("%s: Detect attempt %d, detected Headphone\n",
5821 __func__, i);
5822 } else {
5823 plug_type[i] = PLUG_TYPE_HEADSET;
5824 pr_debug("%s: Detect attempt %d, detected Headset\n",
5825 __func__, i);
5826 }
5827
5828 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
5829 pr_err("%s: Detect attempt %d and %d are not same",
5830 __func__, i - 1, i);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005831 inval = true;
5832 break;
Joonwoo Park03324832012-03-19 19:36:16 -07005833 }
5834 }
5835
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005836 if (inval) {
5837 pr_debug("%s: Invalid plug type detected\n", __func__);
5838 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
5839 0x02, 0x02);
5840 tabla_codec_cleanup_hs_polling(codec);
5841 tabla_codec_enable_hs_detect(codec, 1,
5842 MBHC_USE_MB_TRIGGER |
5843 MBHC_USE_HPHL_TRIGGER, false);
5844 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
Joonwoo Park03324832012-03-19 19:36:16 -07005845 pr_debug("%s: Headphone Detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005846 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5847 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005848 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005849 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
5850 pr_debug("%s: Headset detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005851 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5852
Joonwoo Park03324832012-03-19 19:36:16 -07005853 /* avoid false button press detect */
5854 msleep(50);
Joonwoo Park03324832012-03-19 19:36:16 -07005855 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005856 }
5857}
5858
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005859/* called only from interrupt which is under codec_resource_lock acquisition */
5860static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005861{
Bradley Rubincb1e2732011-06-23 16:49:20 -07005862 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005863
5864 if (!is_removal) {
5865 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
5866
5867 rmb();
5868 if (priv->lpi_enabled)
5869 msleep(100);
5870
5871 rmb();
5872 if (!priv->lpi_enabled) {
5873 pr_debug("%s: lpi is disabled\n", __func__);
5874 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
5875 priv->mbhc_cfg.gpio_level_insert) {
5876 pr_debug("%s: Valid insertion, "
5877 "detect plug type\n", __func__);
5878 tabla_codec_decide_gpio_plug(codec);
5879 } else {
5880 pr_debug("%s: Invalid insertion, "
5881 "stop plug detection\n", __func__);
5882 }
5883 } else {
5884 pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
5885 }
5886}
5887
5888/* called only from interrupt which is under codec_resource_lock acquisition */
5889static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
5890 bool is_mb_trigger)
5891{
Joonwoo Park03324832012-03-19 19:36:16 -07005892 int ret;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005893 struct snd_soc_codec *codec = priv->codec;
5894 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005895
5896 if (is_removal) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005897 /* cancel possiblely running hs detect work */
5898 tabla_cancel_hs_detect_plug(priv);
5899
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005900 /*
5901 * If headphone is removed while playback is in progress,
5902 * it is possible that micbias will be switched to VDDIO.
5903 */
Joonwoo Park03324832012-03-19 19:36:16 -07005904 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005905 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005906 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005907 tabla_codec_enable_hs_detect(codec, 1,
5908 MBHC_USE_MB_TRIGGER |
5909 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07005910 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005911 } else if (is_mb_trigger && !is_removal) {
Joonwoo Park03324832012-03-19 19:36:16 -07005912 pr_debug("%s: Waiting for Headphone left trigger\n",
5913 __func__);
5914 wcd9xxx_lock_sleep(core);
5915 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
5916 usecs_to_jiffies(1000000)) == 0) {
5917 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
5918 __func__);
5919 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005920 }
Joonwoo Park03324832012-03-19 19:36:16 -07005921 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
5922 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005923 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005924 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
5925 if (ret != 0) {
5926 pr_debug("%s: Complete plug insertion, Detecting plug "
5927 "type\n", __func__);
5928 tabla_codec_detect_plug_type(codec);
5929 wcd9xxx_unlock_sleep(core);
5930 } else {
5931 wcd9xxx_enable_irq(codec->control_data,
5932 TABLA_IRQ_MBHC_INSERTION);
5933 pr_err("%s: Error detecting plug insertion\n",
5934 __func__);
5935 }
Joonwoo Park03324832012-03-19 19:36:16 -07005936 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005937}
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08005938
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005939static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
5940{
5941 bool is_mb_trigger, is_removal;
5942 struct tabla_priv *priv = data;
5943 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005944
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005945 pr_debug("%s: enter\n", __func__);
5946 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5947 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
5948
5949 is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
5950 0x10);
5951 is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
5952 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
5953
5954 /* Turn off both HPH and MIC line schmitt triggers */
5955 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5956 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
5957 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5958
5959 if (priv->mbhc_cfg.gpio)
5960 tabla_hs_insert_irq_gpio(priv, is_removal);
5961 else
5962 tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
5963
5964 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005965 return IRQ_HANDLED;
5966}
5967
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005968static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
5969{
5970 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005971 const struct tabla_mbhc_plug_type_cfg *plug_type =
5972 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
5973 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005974
5975 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005976 && (mic_mv < v_hs_max)) ? true : false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005977}
5978
5979/* called under codec_resource_lock acquisition
5980 * returns true if mic voltage range is back to normal insertion
5981 * returns false either if timedout or removed */
5982static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
5983{
5984 int i;
5985 bool timedout, settled = false;
5986 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5987 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5988 unsigned long retry = 0, timeout;
5989 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005990 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005991
5992 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5993 while (!(timedout = time_after(jiffies, timeout))) {
5994 retry++;
5995 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
5996 pr_debug("%s: GPIO indicates removal\n", __func__);
5997 break;
5998 }
5999
6000 if (tabla->mbhc_cfg.gpio) {
6001 if (retry > 1)
6002 msleep(250);
6003 else
6004 msleep(50);
6005 }
6006
6007 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6008 pr_debug("%s: GPIO indicates removal\n", __func__);
6009 break;
6010 }
6011
6012 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
6013 mb_v[i] = tabla_codec_sta_dce(codec, 1, true);
6014 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
6015 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
6016 __func__, retry, mic_mv[i], mb_v[i]);
6017 }
6018
6019 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6020 pr_debug("%s: GPIO indicates removal\n", __func__);
6021 break;
6022 }
6023
6024 if (tabla->current_plug == PLUG_TYPE_NONE) {
6025 pr_debug("%s : headset/headphone is removed\n",
6026 __func__);
6027 break;
6028 }
6029
6030 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
6031 if (!is_valid_mic_voltage(codec, mic_mv[i]))
6032 break;
6033
6034 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6035 pr_debug("%s: MIC voltage settled\n", __func__);
6036 settled = true;
6037 msleep(200);
6038 break;
6039 }
6040
6041 /* only for non-GPIO remove irq */
6042 if (!tabla->mbhc_cfg.gpio) {
6043 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006044 if (mic_mv[i] < v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006045 break;
6046 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6047 pr_debug("%s: Headset is removed\n", __func__);
6048 break;
6049 }
6050 }
6051 }
6052
6053 if (timedout)
6054 pr_debug("%s: Microphone did not settle in %d seconds\n",
6055 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
6056 return settled;
6057}
6058
6059/* called only from interrupt which is under codec_resource_lock acquisition */
6060static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
6061{
6062 struct snd_soc_codec *codec = priv->codec;
6063
6064 if (tabla_hs_remove_settle(codec))
6065 tabla_codec_start_hs_polling(codec);
6066 pr_debug("%s: remove settle done\n", __func__);
6067}
6068
6069/* called only from interrupt which is under codec_resource_lock acquisition */
6070static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006071{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006072 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006073 bool removed = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006074 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08006075 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006076 TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006077 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006078
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006079 if (priv->current_plug != PLUG_TYPE_HEADSET) {
6080 pr_debug("%s(): Headset is not inserted, ignore removal\n",
6081 __func__);
6082 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6083 0x08, 0x08);
6084 return;
6085 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006086
Joonwoo Park0976d012011-12-22 11:48:18 -08006087 usleep_range(generic->t_shutdown_plug_rem,
6088 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006089
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006090 do {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006091 bias_value = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006092 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
6093 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006094 if (bias_value < tabla_get_current_v_ins(priv, false)) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006095 pr_debug("%s: checking false removal\n", __func__);
6096 msleep(500);
6097 removed = !tabla_hs_remove_settle(codec);
6098 pr_debug("%s: headset %sactually removed\n", __func__,
6099 removed ? "" : "not ");
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006100 break;
6101 }
6102 min_us -= priv->mbhc_data.t_dce;
6103 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07006104
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006105 if (removed) {
6106 /* cancel possiblely running hs detect work */
6107 tabla_cancel_hs_detect_plug(priv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006108 /*
6109 * If this removal is not false, first check the micbias
6110 * switch status and switch it to LDOH if it is already
6111 * switched to VDDIO.
6112 */
Joonwoo Park03324832012-03-19 19:36:16 -07006113 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07006114
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006115 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6116 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006117 tabla_codec_enable_hs_detect(codec, 1,
6118 MBHC_USE_MB_TRIGGER |
6119 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07006120 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006121 } else {
6122 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006123 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006124}
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006125
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006126static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
6127{
6128 struct tabla_priv *priv = data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006129 bool vddio;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006130 pr_debug("%s: enter, removal interrupt\n", __func__);
6131
6132 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006133 vddio = (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
6134 priv->mbhc_micbias_switched);
6135 if (vddio)
6136 __tabla_codec_switch_micbias(priv->codec, 0, false, true);
6137
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006138 if (priv->mbhc_cfg.gpio)
6139 tabla_hs_remove_irq_gpio(priv);
6140 else
6141 tabla_hs_remove_irq_nogpio(priv);
6142
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006143 /* if driver turned off vddio switch and headset is not removed,
6144 * turn on the vddio switch back, if headset is removed then vddio
6145 * switch is off by time now and shouldn't be turn on again from here */
6146 if (vddio && priv->current_plug == PLUG_TYPE_HEADSET)
6147 __tabla_codec_switch_micbias(priv->codec, 1, true, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006148 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006149
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006150 return IRQ_HANDLED;
6151}
6152
Joonwoo Park03324832012-03-19 19:36:16 -07006153void mbhc_insert_work(struct work_struct *work)
6154{
6155 struct delayed_work *dwork;
6156 struct tabla_priv *tabla;
6157 struct snd_soc_codec *codec;
6158 struct wcd9xxx *tabla_core;
6159
6160 dwork = to_delayed_work(work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006161 tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
Joonwoo Park03324832012-03-19 19:36:16 -07006162 codec = tabla->codec;
6163 tabla_core = dev_get_drvdata(codec->dev->parent);
6164
6165 pr_debug("%s:\n", __func__);
6166
6167 /* Turn off both HPH and MIC line schmitt triggers */
6168 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6169 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
6170 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6171 wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
6172 tabla_codec_detect_plug_type(codec);
6173 wcd9xxx_unlock_sleep(tabla_core);
6174}
6175
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006176static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
6177{
6178 bool insert;
6179 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6180 bool is_removed = false;
6181
6182 pr_debug("%s: enter\n", __func__);
6183
6184 tabla->in_gpio_handler = true;
6185 /* Wait here for debounce time */
6186 usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
6187 TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
6188
6189 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
6190
6191 /* cancel pending button press */
6192 if (tabla_cancel_btn_work(tabla))
6193 pr_debug("%s: button press is canceled\n", __func__);
6194
6195 insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
6196 tabla->mbhc_cfg.gpio_level_insert);
6197 if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
6198 tabla->lpi_enabled = false;
6199 wmb();
6200
6201 /* cancel detect plug */
6202 tabla_cancel_hs_detect_plug(tabla);
6203
6204 /* Disable Mic Bias pull down and HPH Switch to GND */
6205 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
6206 0x00);
6207 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
6208 tabla_codec_detect_plug_type(codec);
6209 } else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
6210 tabla->lpi_enabled = false;
6211 wmb();
6212
6213 /* cancel detect plug */
6214 tabla_cancel_hs_detect_plug(tabla);
6215
6216 if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
6217 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
6218 is_removed = true;
6219 } else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
6220 tabla_codec_pause_hs_polling(codec);
6221 tabla_codec_cleanup_hs_polling(codec);
6222 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6223 is_removed = true;
6224 }
6225
6226 if (is_removed) {
6227 /* Enable Mic Bias pull down and HPH Switch to GND */
6228 snd_soc_update_bits(codec,
6229 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6230 0x01);
6231 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6232 0x01);
6233 /* Make sure mic trigger is turned off */
6234 snd_soc_update_bits(codec,
6235 tabla->mbhc_bias_regs.ctl_reg,
6236 0x01, 0x01);
6237 snd_soc_update_bits(codec,
6238 tabla->mbhc_bias_regs.mbhc_reg,
6239 0x90, 0x00);
6240 /* Reset MBHC State Machine */
6241 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6242 0x08, 0x08);
6243 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6244 0x08, 0x00);
6245 /* Turn off override */
6246 tabla_turn_onoff_override(codec, false);
6247 }
6248 }
6249
6250 tabla->in_gpio_handler = false;
6251 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6252 pr_debug("%s: leave\n", __func__);
6253}
6254
6255static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
6256{
6257 int r = IRQ_HANDLED;
6258 struct snd_soc_codec *codec = data;
6259
6260 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
6261 pr_warn("%s: failed to hold suspend\n", __func__);
6262 r = IRQ_NONE;
6263 } else {
6264 tabla_hs_gpio_handler(codec);
6265 wcd9xxx_unlock_sleep(codec->control_data);
6266 }
6267
6268 return r;
6269}
6270
6271static void mbhc_fw_read(struct work_struct *work)
6272{
6273 struct delayed_work *dwork;
6274 struct tabla_priv *tabla;
6275 struct snd_soc_codec *codec;
6276 const struct firmware *fw;
6277 int ret = -1, retry = 0, rc;
6278
6279 dwork = to_delayed_work(work);
6280 tabla = container_of(dwork, struct tabla_priv,
6281 mbhc_firmware_dwork);
6282 codec = tabla->codec;
6283
6284 while (retry < MBHC_FW_READ_ATTEMPTS) {
6285 retry++;
6286 pr_info("%s:Attempt %d to request MBHC firmware\n",
6287 __func__, retry);
6288 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
6289 codec->dev);
6290
6291 if (ret != 0) {
6292 usleep_range(MBHC_FW_READ_TIMEOUT,
6293 MBHC_FW_READ_TIMEOUT);
6294 } else {
6295 pr_info("%s: MBHC Firmware read succesful\n", __func__);
6296 break;
6297 }
6298 }
6299
6300 if (ret != 0) {
6301 pr_err("%s: Cannot load MBHC firmware use default cal\n",
6302 __func__);
6303 } else if (tabla_mbhc_fw_validate(fw) == false) {
6304 pr_err("%s: Invalid MBHC cal data size use default cal\n",
6305 __func__);
6306 release_firmware(fw);
6307 } else {
6308 tabla->mbhc_cfg.calibration = (void *)fw->data;
6309 tabla->mbhc_fw = fw;
6310 }
6311
6312 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
6313 tabla_mbhc_init(codec);
6314 tabla_mbhc_cal(codec);
6315 tabla_mbhc_calc_thres(codec);
6316 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
6317 tabla_codec_calibrate_hs_polling(codec);
6318 if (!tabla->mbhc_cfg.gpio) {
6319 tabla->mbhc_inval_hs_range_override = false;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006320 rc = tabla_codec_enable_hs_detect(codec, 1,
6321 MBHC_USE_MB_TRIGGER |
6322 MBHC_USE_HPHL_TRIGGER,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006323 false);
6324
6325 if (IS_ERR_VALUE(rc))
6326 pr_err("%s: Failed to setup MBHC detection\n",
6327 __func__);
6328 } else {
6329 tabla->mbhc_inval_hs_range_override = true;
6330 /* Enable Mic Bias pull down and HPH Switch to GND */
6331 snd_soc_update_bits(codec,
6332 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6333 0x01);
6334 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6335 0x01);
6336 INIT_WORK(&tabla->hs_correct_plug_work,
6337 tabla_hs_correct_gpio_plug);
6338 }
6339
6340}
6341
Joonwoo Park03324832012-03-19 19:36:16 -07006342int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006343 const struct tabla_mbhc_config *cfg)
Joonwoo Park03324832012-03-19 19:36:16 -07006344{
6345 struct tabla_priv *tabla;
6346 int rc = 0;
6347
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006348 if (!codec || !cfg->calibration) {
Joonwoo Park03324832012-03-19 19:36:16 -07006349 pr_err("Error: no codec or calibration\n");
6350 return -EINVAL;
6351 }
6352
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006353 if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
6354 if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Joonwoo Park03324832012-03-19 19:36:16 -07006355 pr_err("Error: clock rate %dHz is not yet supported\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006356 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006357 else
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006358 pr_err("Error: unsupported clock rate %d\n",
6359 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006360 return -EINVAL;
6361 }
6362
6363 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006364 tabla->mbhc_cfg = *cfg;
6365 tabla->in_gpio_handler = false;
6366 tabla->current_plug = PLUG_TYPE_NONE;
6367 tabla->lpi_enabled = false;
Joonwoo Park03324832012-03-19 19:36:16 -07006368 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
6369
6370 /* Put CFILT in fast mode by default */
6371 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
6372 0x40, TABLA_CFILT_FAST_MODE);
6373 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
6374 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
6375 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
6376 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
6377 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
6378
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006379 if (!tabla->mbhc_cfg.read_fw_bin) {
6380 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006381 tabla_mbhc_init(codec);
6382 tabla_mbhc_cal(codec);
6383 tabla_mbhc_calc_thres(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006384 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006385 tabla_codec_calibrate_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006386 if (!tabla->mbhc_cfg.gpio) {
6387 tabla->mbhc_inval_hs_range_override = false;
6388 rc = tabla_codec_enable_hs_detect(codec, 1,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006389 MBHC_USE_MB_TRIGGER |
6390 MBHC_USE_HPHL_TRIGGER,
6391 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006392 } else {
6393 tabla->mbhc_inval_hs_range_override = true;
6394 /* Enable Mic Bias pull down and HPH Switch to GND */
6395 snd_soc_update_bits(codec,
6396 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6397 0x01);
6398 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6399 0x01);
6400 INIT_WORK(&tabla->hs_correct_plug_work,
6401 tabla_hs_correct_gpio_plug);
6402 }
Joonwoo Park03324832012-03-19 19:36:16 -07006403 } else {
6404 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
6405 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
6406 }
6407
6408 if (!IS_ERR_VALUE(rc)) {
6409 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
6410 wcd9xxx_enable_irq(codec->control_data,
6411 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6412 wcd9xxx_enable_irq(codec->control_data,
6413 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6414 }
6415
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006416 if (!IS_ERR_VALUE(rc) && tabla->mbhc_cfg.gpio) {
6417 rc = request_threaded_irq(tabla->mbhc_cfg.gpio_irq, NULL,
6418 tabla_mechanical_plug_detect_irq,
6419 (IRQF_TRIGGER_RISING |
6420 IRQF_TRIGGER_FALLING),
6421 "tabla-gpio", codec);
6422 if (!IS_ERR_VALUE(rc)) {
6423 rc = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
6424 /* Bootup time detection */
6425 tabla_hs_gpio_handler(codec);
6426 }
6427 }
6428
Joonwoo Park03324832012-03-19 19:36:16 -07006429 return rc;
6430}
6431EXPORT_SYMBOL_GPL(tabla_hs_detect);
6432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006433static unsigned long slimbus_value;
6434
6435static irqreturn_t tabla_slimbus_irq(int irq, void *data)
6436{
6437 struct tabla_priv *priv = data;
6438 struct snd_soc_codec *codec = priv->codec;
6439 int i, j;
6440 u8 val;
6441
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306442 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
6443 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006444 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
6445 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306446 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006447 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
6448 if (val & 0x1)
6449 pr_err_ratelimited("overflow error on port %x,"
6450 " value %x\n", i*8 + j, val);
6451 if (val & 0x2)
6452 pr_err_ratelimited("underflow error on port %x,"
6453 " value %x\n", i*8 + j, val);
6454 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306455 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006456 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
6457 }
6458
6459 return IRQ_HANDLED;
6460}
6461
Patrick Lai3043fba2011-08-01 14:15:57 -07006462
6463static int tabla_handle_pdata(struct tabla_priv *tabla)
6464{
6465 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306466 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07006467 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05306468 u8 leg_mode = pdata->amic_settings.legacy_mode;
6469 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
6470 u8 txfe_buff = pdata->amic_settings.txfe_buff;
6471 u8 flag = pdata->amic_settings.use_pdata;
6472 u8 i = 0, j = 0;
6473 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07006474
6475 if (!pdata) {
6476 rc = -ENODEV;
6477 goto done;
6478 }
6479
6480 /* Make sure settings are correct */
6481 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
6482 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
6483 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
6484 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
6485 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
6486 rc = -EINVAL;
6487 goto done;
6488 }
6489
6490 /* figure out k value */
6491 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
6492 pdata->micbias.cfilt1_mv);
6493 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
6494 pdata->micbias.cfilt2_mv);
6495 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
6496 pdata->micbias.cfilt3_mv);
6497
6498 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
6499 rc = -EINVAL;
6500 goto done;
6501 }
6502
6503 /* Set voltage level and always use LDO */
6504 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
6505 (pdata->micbias.ldoh_v << 2));
6506
6507 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
6508 (k1 << 2));
6509 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
6510 (k2 << 2));
6511 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
6512 (k3 << 2));
6513
6514 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
6515 (pdata->micbias.bias1_cfilt_sel << 5));
6516 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
6517 (pdata->micbias.bias2_cfilt_sel << 5));
6518 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
6519 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006520 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
6521 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07006522
Santosh Mardi22920282011-10-26 02:38:40 +05306523 for (i = 0; i < 6; j++, i += 2) {
6524 if (flag & (0x01 << i)) {
6525 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
6526 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
6527 val_txfe = val_txfe |
6528 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
6529 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6530 0x10, value);
6531 snd_soc_update_bits(codec,
6532 TABLA_A_TX_1_2_TEST_EN + j * 10,
6533 0x30, val_txfe);
6534 }
6535 if (flag & (0x01 << (i + 1))) {
6536 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
6537 val_txfe = (txfe_bypass &
6538 (0x01 << (i + 1))) ? 0x02 : 0x00;
6539 val_txfe |= (txfe_buff &
6540 (0x01 << (i + 1))) ? 0x01 : 0x00;
6541 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6542 0x01, value);
6543 snd_soc_update_bits(codec,
6544 TABLA_A_TX_1_2_TEST_EN + j * 10,
6545 0x03, val_txfe);
6546 }
6547 }
6548 if (flag & 0x40) {
6549 value = (leg_mode & 0x40) ? 0x10 : 0x00;
6550 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
6551 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
6552 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
6553 0x13, value);
6554 }
Patrick Lai49efeac2011-11-03 11:01:12 -07006555
6556 if (pdata->ocp.use_pdata) {
6557 /* not defined in CODEC specification */
6558 if (pdata->ocp.hph_ocp_limit == 1 ||
6559 pdata->ocp.hph_ocp_limit == 5) {
6560 rc = -EINVAL;
6561 goto done;
6562 }
6563 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
6564 0x0F, pdata->ocp.num_attempts);
6565 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
6566 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
6567 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
6568 0xE0, (pdata->ocp.hph_ocp_limit << 5));
6569 }
Joonwoo Park03324832012-03-19 19:36:16 -07006570
6571 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
6572 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
6573 if (pdata->regulator[i].min_uV == 1800000 &&
6574 pdata->regulator[i].max_uV == 1800000) {
6575 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6576 0x1C);
6577 } else if (pdata->regulator[i].min_uV == 2200000 &&
6578 pdata->regulator[i].max_uV == 2200000) {
6579 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6580 0x1E);
6581 } else {
6582 pr_err("%s: unsupported CDC_VDDA_RX voltage "
6583 "min %d, max %d\n", __func__,
6584 pdata->regulator[i].min_uV,
6585 pdata->regulator[i].max_uV);
6586 rc = -EINVAL;
6587 }
6588 break;
6589 }
6590 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006591done:
6592 return rc;
6593}
6594
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006595static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
6596
6597 /* Tabla 1.1 MICBIAS changes */
6598 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
6599 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
6600 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006601
6602 /* Tabla 1.1 HPH changes */
6603 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
6604 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
6605
6606 /* Tabla 1.1 EAR PA changes */
6607 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
6608 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
6609 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
6610
6611 /* Tabla 1.1 Lineout_5 Changes */
6612 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
6613
6614 /* Tabla 1.1 RX Changes */
6615 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
6616 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
6617 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
6618 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
6619 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
6620 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
6621 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
6622
6623 /* Tabla 1.1 RX1 and RX2 Changes */
6624 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
6625 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
6626
6627 /* Tabla 1.1 RX3 to RX7 Changes */
6628 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
6629 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
6630 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
6631 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
6632 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
6633
6634 /* Tabla 1.1 CLASSG Changes */
6635 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
6636};
6637
6638static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006639 /* Tabla 2.0 MICBIAS changes */
6640 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
6641};
6642
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006643static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
6644 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
6645};
6646
6647static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
6648 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
6649};
6650
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006651static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
6652{
6653 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306654 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006655
6656 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
6657 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
6658 tabla_1_1_reg_defaults[i].val);
6659
6660 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
6661 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
6662 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006663
6664 if (TABLA_IS_1_X(tabla_core->version)) {
6665 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
6666 i++)
6667 snd_soc_write(codec,
6668 tabla_1_x_only_reg_2_0_defaults[i].reg,
6669 tabla_1_x_only_reg_2_0_defaults[i].val);
6670 } else {
6671 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
6672 snd_soc_write(codec,
6673 tabla_2_only_reg_2_0_defaults[i].reg,
6674 tabla_2_only_reg_2_0_defaults[i].val);
6675 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006676}
6677
6678static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08006679 /* Initialize current threshold to 350MA
6680 * number of wait and run cycles to 4096
6681 */
Patrick Lai49efeac2011-11-03 11:01:12 -07006682 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08006683 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006684
Santosh Mardi32171012011-10-28 23:32:06 +05306685 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
6686
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006687 /* Initialize gain registers to use register gain */
6688 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
6689 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
6690 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
6691 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
6692 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
6693 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
6694
6695 /* Initialize mic biases to differential mode */
6696 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
6697 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
6698 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006699
6700 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
6701
6702 /* Use 16 bit sample size for TX1 to TX6 */
6703 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
6704 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
6705 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
6706 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
6707 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
6708 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
6709
6710 /* Use 16 bit sample size for TX7 to TX10 */
6711 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
6712 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
6713 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
6714 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
6715
6716 /* Use 16 bit sample size for RX */
6717 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
6718 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
6719
6720 /*enable HPF filter for TX paths */
6721 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
6722 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
6723 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
6724 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
6725 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
6726 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
6727 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
6728 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
6729 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
6730 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
6731};
6732
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006733static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
6734 /* Initialize mic biases to differential mode */
6735 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6736};
6737
6738static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
6739 /* Initialize mic biases to differential mode */
6740 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6741};
6742
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006743static void tabla_codec_init_reg(struct snd_soc_codec *codec)
6744{
6745 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306746 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006747
6748 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
6749 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
6750 tabla_codec_reg_init_val[i].mask,
6751 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006752 if (TABLA_IS_1_X(tabla_core->version)) {
6753 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
6754 snd_soc_update_bits(codec,
6755 tabla_1_x_codec_reg_init_val[i].reg,
6756 tabla_1_x_codec_reg_init_val[i].mask,
6757 tabla_1_x_codec_reg_init_val[i].val);
6758 } else {
6759 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
6760 i++)
6761 snd_soc_update_bits(codec,
6762 tabla_2_higher_codec_reg_init_val[i].reg,
6763 tabla_2_higher_codec_reg_init_val[i].mask,
6764 tabla_2_higher_codec_reg_init_val[i].val);
6765 }
6766}
6767
6768static void tabla_update_reg_address(struct tabla_priv *priv)
6769{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306770 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006771 struct tabla_reg_address *reg_addr = &priv->reg_addr;
6772
6773 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006774 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
6775 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006776 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006777 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006778 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
6779 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006780 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006781 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006782}
6783
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006784#ifdef CONFIG_DEBUG_FS
6785static int codec_debug_open(struct inode *inode, struct file *file)
6786{
6787 file->private_data = inode->i_private;
6788 return 0;
6789}
6790
6791static ssize_t codec_debug_write(struct file *filp,
6792 const char __user *ubuf, size_t cnt, loff_t *ppos)
6793{
6794 char lbuf[32];
6795 char *buf;
6796 int rc;
6797 struct tabla_priv *tabla = filp->private_data;
6798
6799 if (cnt > sizeof(lbuf) - 1)
6800 return -EINVAL;
6801
6802 rc = copy_from_user(lbuf, ubuf, cnt);
6803 if (rc)
6804 return -EFAULT;
6805
6806 lbuf[cnt] = '\0';
6807 buf = (char *)lbuf;
6808 tabla->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
6809 false : true;
6810 return rc;
6811}
6812
6813static ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
6814 size_t count, loff_t *pos)
6815{
6816 const int size = 768;
6817 char buffer[size];
6818 int n = 0;
6819 struct tabla_priv *tabla = file->private_data;
6820 struct snd_soc_codec *codec = tabla->codec;
6821 const struct mbhc_internal_cal_data *p = &tabla->mbhc_data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006822 const s16 v_ins_hu_cur = tabla_get_current_v_ins(tabla, true);
6823 const s16 v_ins_h_cur = tabla_get_current_v_ins(tabla, false);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006824
6825 n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
6826 tabla_codec_sta_dce_v(codec, 1, p->dce_z));
6827 n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
6828 p->dce_mb, tabla_codec_sta_dce_v(codec, 1, p->dce_mb));
6829 n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
6830 p->sta_z, tabla_codec_sta_dce_v(codec, 0, p->sta_z));
6831 n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
6832 p->sta_mb, tabla_codec_sta_dce_v(codec, 0, p->sta_mb));
6833 n += scnprintf(buffer + n, size - n, "t_dce = %x\n", p->t_dce);
6834 n += scnprintf(buffer + n, size - n, "t_sta = %x\n", p->t_sta);
6835 n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
6836 p->micb_mv);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006837 n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006838 p->v_ins_hu,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006839 tabla_codec_sta_dce_v(codec, 0, p->v_ins_hu),
6840 p->v_ins_hu == v_ins_hu_cur ? "*" : "");
6841 n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
6842 p->v_ins_h, tabla_codec_sta_dce_v(codec, 1, p->v_ins_h),
6843 p->v_ins_h == v_ins_h_cur ? "*" : "");
6844 n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
6845 p->adj_v_ins_hu,
6846 tabla_codec_sta_dce_v(codec, 0, p->adj_v_ins_hu),
6847 p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
6848 n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
6849 p->adj_v_ins_h,
6850 tabla_codec_sta_dce_v(codec, 1, p->adj_v_ins_h),
6851 p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006852 n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
6853 p->v_b1_hu, tabla_codec_sta_dce_v(codec, 0, p->v_b1_hu));
6854 n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
6855 p->v_b1_h, tabla_codec_sta_dce_v(codec, 1, p->v_b1_h));
6856 n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
6857 p->v_b1_huc,
6858 tabla_codec_sta_dce_v(codec, 1, p->v_b1_huc));
6859 n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
6860 p->v_brh, tabla_codec_sta_dce_v(codec, 1, p->v_brh));
6861 n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
6862 tabla_codec_sta_dce_v(codec, 0, p->v_brl));
6863 n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
6864 p->v_no_mic,
6865 tabla_codec_sta_dce_v(codec, 0, p->v_no_mic));
6866 n += scnprintf(buffer + n, size - n, "npoll = %d\n", p->npoll);
6867 n += scnprintf(buffer + n, size - n, "nbounce_wait = %d\n",
6868 p->nbounce_wait);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006869 n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
6870 p->v_inval_ins_low);
6871 n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
6872 p->v_inval_ins_high);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006873 buffer[n] = 0;
6874
6875 return simple_read_from_buffer(buf, count, pos, buffer, n);
6876}
6877
6878static const struct file_operations codec_debug_ops = {
6879 .open = codec_debug_open,
6880 .write = codec_debug_write,
6881};
6882
6883static const struct file_operations codec_mbhc_debug_ops = {
6884 .open = codec_debug_open,
6885 .read = codec_mbhc_debug_read,
6886};
6887#endif
6888
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006889static int tabla_codec_probe(struct snd_soc_codec *codec)
6890{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306891 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006892 struct tabla_priv *tabla;
6893 struct snd_soc_dapm_context *dapm = &codec->dapm;
6894 int ret = 0;
6895 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006896 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006897
6898 codec->control_data = dev_get_drvdata(codec->dev->parent);
6899 control = codec->control_data;
6900
6901 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
6902 if (!tabla) {
6903 dev_err(codec->dev, "Failed to allocate private data\n");
6904 return -ENOMEM;
6905 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08006906 for (i = 0 ; i < NUM_DECIMATORS; i++) {
6907 tx_hpf_work[i].tabla = tabla;
6908 tx_hpf_work[i].decimator = i + 1;
6909 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
6910 tx_hpf_corner_freq_callback);
6911 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006912
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006913 /* Make sure mbhc micbias register addresses are zeroed out */
6914 memset(&tabla->mbhc_bias_regs, 0,
6915 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006916 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006917
Joonwoo Park0976d012011-12-22 11:48:18 -08006918 /* Make sure mbhc intenal calibration data is zeroed out */
6919 memset(&tabla->mbhc_data, 0,
6920 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08006921 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08006922 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
6923 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006924 snd_soc_codec_set_drvdata(codec, tabla);
6925
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07006926 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006927 tabla->bandgap_type = TABLA_BANDGAP_OFF;
6928 tabla->clock_active = false;
6929 tabla->config_mode_active = false;
6930 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08006931 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07006932 tabla->no_mic_headset_override = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006933 tabla->hs_polling_irq_prepared = false;
6934 mutex_init(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006935 tabla->codec = codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006936 tabla->mbhc_state = MBHC_STATE_NONE;
Joonwoo Park03324832012-03-19 19:36:16 -07006937 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08006938 for (i = 0; i < COMPANDER_MAX; i++) {
6939 tabla->comp_enabled[i] = 0;
6940 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
6941 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006942 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306943 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08006944 tabla->aux_pga_cnt = 0;
6945 tabla->aux_l_gain = 0x1F;
6946 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006947 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05306948 tabla_update_reg_defaults(codec);
6949 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05306950 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07006951 if (IS_ERR_VALUE(ret)) {
6952 pr_err("%s: bad pdata\n", __func__);
6953 goto err_pdata;
6954 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006955
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006956 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006957 ARRAY_SIZE(tabla_snd_controls));
6958 if (TABLA_IS_1_X(control->version))
6959 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
6960 ARRAY_SIZE(tabla_1_x_snd_controls));
6961 else
6962 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
6963 ARRAY_SIZE(tabla_2_higher_snd_controls));
6964
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006965 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006966 ARRAY_SIZE(tabla_dapm_widgets));
6967 if (TABLA_IS_1_X(control->version))
6968 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
6969 ARRAY_SIZE(tabla_1_x_dapm_widgets));
6970 else
6971 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
6972 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
6973
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306974 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05306975 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
6976 ARRAY_SIZE(tabla_dapm_i2s_widgets));
6977 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
6978 ARRAY_SIZE(audio_i2s_map));
6979 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006980 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07006981
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006982 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006983 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006984 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
6985 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006986 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006987 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006988 } else {
6989 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306990 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08006991 goto err_pdata;
6992 }
6993
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006994 snd_soc_dapm_sync(dapm);
6995
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306996 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006997 tabla_hs_insert_irq, "Headset insert detect", tabla);
6998 if (ret) {
6999 pr_err("%s: Failed to request irq %d\n", __func__,
7000 TABLA_IRQ_MBHC_INSERTION);
7001 goto err_insert_irq;
7002 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307003 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007004
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307005 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007006 tabla_hs_remove_irq, "Headset remove detect", tabla);
7007 if (ret) {
7008 pr_err("%s: Failed to request irq %d\n", __func__,
7009 TABLA_IRQ_MBHC_REMOVAL);
7010 goto err_remove_irq;
7011 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007012
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307013 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007014 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007015 if (ret) {
7016 pr_err("%s: Failed to request irq %d\n", __func__,
7017 TABLA_IRQ_MBHC_POTENTIAL);
7018 goto err_potential_irq;
7019 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007020
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307021 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007022 tabla_release_handler, "Button Release detect", tabla);
7023 if (ret) {
7024 pr_err("%s: Failed to request irq %d\n", __func__,
7025 TABLA_IRQ_MBHC_RELEASE);
7026 goto err_release_irq;
7027 }
7028
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307029 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007030 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
7031 if (ret) {
7032 pr_err("%s: Failed to request irq %d\n", __func__,
7033 TABLA_IRQ_SLIMBUS);
7034 goto err_slimbus_irq;
7035 }
7036
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307037 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
7038 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007039 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
7040
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307041 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007042 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
7043 "HPH_L OCP detect", tabla);
7044 if (ret) {
7045 pr_err("%s: Failed to request irq %d\n", __func__,
7046 TABLA_IRQ_HPH_PA_OCPL_FAULT);
7047 goto err_hphl_ocp_irq;
7048 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307049 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07007050
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307051 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007052 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
7053 "HPH_R OCP detect", tabla);
7054 if (ret) {
7055 pr_err("%s: Failed to request irq %d\n", __func__,
7056 TABLA_IRQ_HPH_PA_OCPR_FAULT);
7057 goto err_hphr_ocp_irq;
7058 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307059 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007060 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
7061 switch (tabla_dai[i].id) {
7062 case AIF1_PB:
7063 ch_cnt = tabla_dai[i].playback.channels_max;
7064 break;
7065 case AIF1_CAP:
7066 ch_cnt = tabla_dai[i].capture.channels_max;
7067 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08007068 case AIF2_PB:
7069 ch_cnt = tabla_dai[i].playback.channels_max;
7070 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007071 default:
7072 continue;
7073 }
7074 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
7075 ch_cnt), GFP_KERNEL);
7076 }
Patrick Lai49efeac2011-11-03 11:01:12 -07007077
Bradley Rubincb3950a2011-08-18 13:07:26 -07007078#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007079 if (ret == 0) {
7080 tabla->debugfs_poke =
7081 debugfs_create_file("TRRS", S_IFREG | S_IRUGO, NULL, tabla,
7082 &codec_debug_ops);
7083 tabla->debugfs_mbhc =
7084 debugfs_create_file("tabla_mbhc", S_IFREG | S_IRUGO,
7085 NULL, tabla, &codec_mbhc_debug_ops);
7086 }
Bradley Rubincb3950a2011-08-18 13:07:26 -07007087#endif
7088
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007089 return ret;
7090
Patrick Lai49efeac2011-11-03 11:01:12 -07007091err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307092 wcd9xxx_free_irq(codec->control_data,
7093 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07007094err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307095 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007096err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307097 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07007098err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307099 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007100err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307101 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007102err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307103 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007104err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07007105err_pdata:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007106 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007107 kfree(tabla);
7108 return ret;
7109}
7110static int tabla_codec_remove(struct snd_soc_codec *codec)
7111{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007112 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007113 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307114 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
7115 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
7116 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
7117 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
7118 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007119 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007120 tabla_codec_disable_clock_block(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007121 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007122 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08007123 if (tabla->mbhc_fw)
7124 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007125 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
7126 kfree(tabla->dai[i].ch_num);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007127 mutex_destroy(&tabla->codec_resource_lock);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007128#ifdef CONFIG_DEBUG_FS
7129 debugfs_remove(tabla->debugfs_poke);
7130 debugfs_remove(tabla->debugfs_mbhc);
7131#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007132 kfree(tabla);
7133 return 0;
7134}
7135static struct snd_soc_codec_driver soc_codec_dev_tabla = {
7136 .probe = tabla_codec_probe,
7137 .remove = tabla_codec_remove,
7138 .read = tabla_read,
7139 .write = tabla_write,
7140
7141 .readable_register = tabla_readable,
7142 .volatile_register = tabla_volatile,
7143
7144 .reg_cache_size = TABLA_CACHE_SIZE,
7145 .reg_cache_default = tabla_reg_defaults,
7146 .reg_word_size = 1,
7147};
Bradley Rubincb3950a2011-08-18 13:07:26 -07007148
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007149#ifdef CONFIG_PM
7150static int tabla_suspend(struct device *dev)
7151{
Joonwoo Park816b8e62012-01-23 16:03:21 -08007152 dev_dbg(dev, "%s: system suspend\n", __func__);
7153 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007154}
7155
7156static int tabla_resume(struct device *dev)
7157{
Joonwoo Park03324832012-03-19 19:36:16 -07007158 struct platform_device *pdev = to_platform_device(dev);
7159 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Park816b8e62012-01-23 16:03:21 -08007160 dev_dbg(dev, "%s: system resume\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07007161 tabla->mbhc_last_resume = jiffies;
Joonwoo Park816b8e62012-01-23 16:03:21 -08007162 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007163}
7164
7165static const struct dev_pm_ops tabla_pm_ops = {
7166 .suspend = tabla_suspend,
7167 .resume = tabla_resume,
7168};
7169#endif
7170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007171static int __devinit tabla_probe(struct platform_device *pdev)
7172{
Santosh Mardie15e2302011-11-15 10:39:23 +05307173 int ret = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307174 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05307175 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7176 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307177 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05307178 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7179 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
7180 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007181}
7182static int __devexit tabla_remove(struct platform_device *pdev)
7183{
7184 snd_soc_unregister_codec(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007185 return 0;
7186}
7187static struct platform_driver tabla_codec_driver = {
7188 .probe = tabla_probe,
7189 .remove = tabla_remove,
7190 .driver = {
7191 .name = "tabla_codec",
7192 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007193#ifdef CONFIG_PM
7194 .pm = &tabla_pm_ops,
7195#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007196 },
7197};
7198
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007199static struct platform_driver tabla1x_codec_driver = {
7200 .probe = tabla_probe,
7201 .remove = tabla_remove,
7202 .driver = {
7203 .name = "tabla1x_codec",
7204 .owner = THIS_MODULE,
7205#ifdef CONFIG_PM
7206 .pm = &tabla_pm_ops,
7207#endif
7208 },
7209};
7210
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007211static int __init tabla_codec_init(void)
7212{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007213 int rtn = platform_driver_register(&tabla_codec_driver);
7214 if (rtn == 0) {
7215 rtn = platform_driver_register(&tabla1x_codec_driver);
7216 if (rtn != 0)
7217 platform_driver_unregister(&tabla_codec_driver);
7218 }
7219 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007220}
7221
7222static void __exit tabla_codec_exit(void)
7223{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007224 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007225 platform_driver_unregister(&tabla_codec_driver);
7226}
7227
7228module_init(tabla_codec_init);
7229module_exit(tabla_codec_exit);
7230
7231MODULE_DESCRIPTION("Tabla codec driver");
7232MODULE_VERSION("1.0");
7233MODULE_LICENSE("GPL v2");