blob: 830b98f834dc737a4a2e5dc100f16d36581a0447 [file] [log] [blame]
Kiran Kandi3426e512011-09-13 22:50:10 -07001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/init.h>
Bradley Rubin229c6a52011-07-12 16:18:48 -070014#include <linux/firmware.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070015#include <linux/slab.h>
16#include <linux/platform_device.h>
Santosh Mardie15e2302011-11-15 10:39:23 +053017#include <linux/device.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070018#include <linux/printk.h>
19#include <linux/ratelimit.h>
Bradley Rubincb3950a2011-08-18 13:07:26 -070020#include <linux/debugfs.h>
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053021#include <linux/mfd/wcd9xxx/core.h>
22#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
23#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
24#include <linux/mfd/wcd9xxx/pdata.h>
Santosh Mardie15e2302011-11-15 10:39:23 +053025#include <sound/pcm.h>
26#include <sound/pcm_params.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027#include <sound/soc.h>
28#include <sound/soc-dapm.h>
29#include <sound/tlv.h>
30#include <linux/bitops.h>
31#include <linux/delay.h>
Kuirong Wanga545e722012-02-06 19:12:54 -080032#include <linux/pm_runtime.h>
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070033#include <linux/kernel.h>
34#include <linux/gpio.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070035#include "wcd9310.h"
36
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070037#define WCD9310_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\
38 SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_48000)
39
40#define NUM_DECIMATORS 10
41#define NUM_INTERPOLATORS 7
42#define BITS_PER_REG 8
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080043#define TABLA_CFILT_FAST_MODE 0x00
44#define TABLA_CFILT_SLOW_MODE 0x40
Patrick Lai64b43262011-12-06 17:29:15 -080045#define MBHC_FW_READ_ATTEMPTS 15
46#define MBHC_FW_READ_TIMEOUT 2000000
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070047
Joonwoo Park03324832012-03-19 19:36:16 -070048enum {
49 MBHC_USE_HPHL_TRIGGER = 1,
50 MBHC_USE_MB_TRIGGER = 2
51};
52
53#define MBHC_NUM_DCE_PLUG_DETECT 3
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070054#define NUM_ATTEMPTS_INSERT_DETECT 25
55#define NUM_ATTEMPTS_TO_REPORT 5
Joonwoo Park03324832012-03-19 19:36:16 -070056
Patrick Lai49efeac2011-11-03 11:01:12 -070057#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR)
58
Santosh Mardie15e2302011-11-15 10:39:23 +053059#define TABLA_I2S_MASTER_MODE_MASK 0x08
60
Patrick Laic7cae882011-11-18 11:52:49 -080061#define TABLA_OCP_ATTEMPT 1
62
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080063#define AIF1_PB 1
64#define AIF1_CAP 2
Neema Shettyd3a89262012-02-16 10:23:50 -080065#define AIF2_PB 3
66#define NUM_CODEC_DAIS 3
Kuirong Wang0f8ade32012-02-27 16:29:45 -080067#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080068
69struct tabla_codec_dai_data {
70 u32 rate;
71 u32 *ch_num;
72 u32 ch_act;
73 u32 ch_tot;
74};
75
Joonwoo Park0976d012011-12-22 11:48:18 -080076#define TABLA_MCLK_RATE_12288KHZ 12288000
77#define TABLA_MCLK_RATE_9600KHZ 9600000
78
Joonwoo Parkf4267c22012-01-10 13:25:24 -080079#define TABLA_FAKE_INS_THRESHOLD_MS 2500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -080080#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
Joonwoo Parkf4267c22012-01-10 13:25:24 -080081
Joonwoo Park03324832012-03-19 19:36:16 -070082#define TABLA_MBHC_BUTTON_MIN 0x8000
83
Joonwoo Park03324832012-03-19 19:36:16 -070084#define TABLA_MBHC_FAKE_INSERT_LOW 10
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070085#define TABLA_MBHC_FAKE_INSERT_HIGH 80
86#define TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO 150
Joonwoo Park03324832012-03-19 19:36:16 -070087
88#define TABLA_MBHC_STATUS_REL_DETECTION 0x0C
89
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070090#define TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
91
Joonwoo Parkcf473b42012-03-29 19:48:16 -070092#define TABLA_MBHC_FAKE_INS_DELTA_MV 200
93#define TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV 300
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070094
95#define TABLA_HS_DETECT_PLUG_TIME_MS (5 * 1000)
96#define TABLA_HS_DETECT_PLUG_INERVAL_MS 100
97
98#define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
99
100#define TABLA_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
101#define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
102
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700103static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
104static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
105static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800106static struct snd_soc_dai_driver tabla_dai[];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800107static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108
109enum tabla_bandgap_type {
110 TABLA_BANDGAP_OFF = 0,
111 TABLA_BANDGAP_AUDIO_MODE,
112 TABLA_BANDGAP_MBHC_MODE,
113};
114
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700115struct mbhc_micbias_regs {
116 u16 cfilt_val;
117 u16 cfilt_ctl;
118 u16 mbhc_reg;
119 u16 int_rbias;
120 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -0800121 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700122};
123
Ben Romberger1f045a72011-11-04 10:14:57 -0700124/* Codec supports 2 IIR filters */
125enum {
126 IIR1 = 0,
127 IIR2,
128 IIR_MAX,
129};
130/* Codec supports 5 bands */
131enum {
132 BAND1 = 0,
133 BAND2,
134 BAND3,
135 BAND4,
136 BAND5,
137 BAND_MAX,
138};
139
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800140enum {
141 COMPANDER_1 = 0,
142 COMPANDER_2,
143 COMPANDER_MAX,
144};
145
146enum {
147 COMPANDER_FS_8KHZ = 0,
148 COMPANDER_FS_16KHZ,
149 COMPANDER_FS_32KHZ,
150 COMPANDER_FS_48KHZ,
151 COMPANDER_FS_MAX,
152};
153
Joonwoo Parka9444452011-12-08 18:48:27 -0800154/* Flags to track of PA and DAC state.
155 * PA and DAC should be tracked separately as AUXPGA loopback requires
156 * only PA to be turned on without DAC being on. */
157enum tabla_priv_ack_flags {
158 TABLA_HPHL_PA_OFF_ACK = 0,
159 TABLA_HPHR_PA_OFF_ACK,
160 TABLA_HPHL_DAC_OFF_ACK,
161 TABLA_HPHR_DAC_OFF_ACK
162};
163
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800164
165struct comp_sample_dependent_params {
166 u32 peak_det_timeout;
167 u32 rms_meter_div_fact;
168 u32 rms_meter_resamp_fact;
169};
170
Joonwoo Park0976d012011-12-22 11:48:18 -0800171/* Data used by MBHC */
172struct mbhc_internal_cal_data {
173 u16 dce_z;
174 u16 dce_mb;
175 u16 sta_z;
176 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800177 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800178 u32 t_dce;
179 u32 t_sta;
180 u32 micb_mv;
181 u16 v_ins_hu;
182 u16 v_ins_h;
183 u16 v_b1_hu;
184 u16 v_b1_h;
185 u16 v_b1_huc;
186 u16 v_brh;
187 u16 v_brl;
188 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800189 u8 npoll;
190 u8 nbounce_wait;
Joonwoo Parkcf473b42012-03-29 19:48:16 -0700191 s16 adj_v_hs_max;
192 u16 adj_v_ins_hu;
193 u16 adj_v_ins_h;
194 s16 v_inval_ins_low;
195 s16 v_inval_ins_high;
Joonwoo Park0976d012011-12-22 11:48:18 -0800196};
197
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800198struct tabla_reg_address {
199 u16 micb_4_ctl;
200 u16 micb_4_int_rbias;
201 u16 micb_4_mbhc;
202};
203
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700204enum tabla_mbhc_plug_type {
205 PLUG_TYPE_NONE = 0,
206 PLUG_TYPE_HEADSET,
207 PLUG_TYPE_HEADPHONE,
208 PLUG_TYPE_HIGH_HPH,
209};
210
211enum tabla_mbhc_state {
212 MBHC_STATE_NONE = -1,
213 MBHC_STATE_POTENTIAL,
214 MBHC_STATE_POTENTIAL_RECOVERY,
215 MBHC_STATE_RELEASE,
216};
217
Kiran Kandid8cf5212012-03-02 15:34:53 -0800218struct hpf_work {
219 struct tabla_priv *tabla;
220 u32 decimator;
221 u8 tx_hpf_cut_of_freq;
222 struct delayed_work dwork;
223};
224
225static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
226
Bradley Rubin229c6a52011-07-12 16:18:48 -0700227struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700228 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800229 struct tabla_reg_address reg_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700231 u32 cfilt1_cnt;
232 u32 cfilt2_cnt;
233 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700234 u32 rx_bias_count;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700235 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700236 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 bool clock_active;
238 bool config_mode_active;
239 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800240 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700241 int buttons_pressed;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700242 enum tabla_mbhc_state mbhc_state;
243 struct tabla_mbhc_config mbhc_cfg;
Joonwoo Park0976d012011-12-22 11:48:18 -0800244 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700245
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530246 struct wcd9xxx_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700247 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700248
249 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700250 /* Delayed work to report long button press */
Joonwoo Park03324832012-03-19 19:36:16 -0700251 struct delayed_work mbhc_btn_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700252
253 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700254 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700255
Joonwoo Parka9444452011-12-08 18:48:27 -0800256 /* track PA/DAC state */
257 unsigned long hph_pa_dac_state;
258
Santosh Mardie15e2302011-11-15 10:39:23 +0530259 /*track tabla interface type*/
260 u8 intf_type;
261
Patrick Lai49efeac2011-11-03 11:01:12 -0700262 u32 hph_status; /* track headhpone status */
263 /* define separate work for left and right headphone OCP to avoid
264 * additional checking on which OCP event to report so no locking
265 * to ensure synchronization is required
266 */
267 struct work_struct hphlocp_work; /* reporting left hph ocp off */
268 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800269
Patrick Laic7cae882011-11-18 11:52:49 -0800270 u8 hphlocp_cnt; /* headphone left ocp retry */
271 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800272
Patrick Lai64b43262011-12-06 17:29:15 -0800273 /* Work to perform MBHC Firmware Read */
274 struct delayed_work mbhc_firmware_dwork;
275 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800276
277 /* num of slim ports required */
278 struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800279
280 /*compander*/
281 int comp_enabled[COMPANDER_MAX];
282 u32 comp_fs[COMPANDER_MAX];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800283
284 /* Maintain the status of AUX PGA */
285 int aux_pga_cnt;
286 u8 aux_l_gain;
287 u8 aux_r_gain;
Joonwoo Park03324832012-03-19 19:36:16 -0700288
Joonwoo Park03324832012-03-19 19:36:16 -0700289 struct delayed_work mbhc_insert_dwork;
290 unsigned long mbhc_last_resume; /* in jiffies */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700291
292 u8 current_plug;
293 struct work_struct hs_correct_plug_work;
294 bool hs_detect_work_stop;
295 bool hs_polling_irq_prepared;
296 bool lpi_enabled; /* low power insertion detection */
297 bool in_gpio_handler;
298 /* Currently, only used for mbhc purpose, to protect
299 * concurrent execution of mbhc threaded irq handlers and
300 * kill race between DAPM and MBHC.But can serve as a
301 * general lock to protect codec resource
302 */
303 struct mutex codec_resource_lock;
304
305 /* Used to override the rule "invalid headset
306 * when microphone voltage is too high"
307 */
308 bool mbhc_inval_hs_range_override;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700309
Bradley Rubincb3950a2011-08-18 13:07:26 -0700310#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700311 struct dentry *debugfs_poke;
312 struct dentry *debugfs_mbhc;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700313#endif
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700314};
315
Bradley Rubincb3950a2011-08-18 13:07:26 -0700316
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800317static const u32 comp_shift[] = {
318 0,
319 2,
320};
321
322static const int comp_rx_path[] = {
323 COMPANDER_1,
324 COMPANDER_1,
325 COMPANDER_2,
326 COMPANDER_2,
327 COMPANDER_2,
328 COMPANDER_2,
329 COMPANDER_MAX,
330};
331
332static const struct comp_sample_dependent_params comp_samp_params[] = {
333 {
334 .peak_det_timeout = 0x2,
335 .rms_meter_div_fact = 0x8 << 4,
336 .rms_meter_resamp_fact = 0x21,
337 },
338 {
339 .peak_det_timeout = 0x3,
340 .rms_meter_div_fact = 0x9 << 4,
341 .rms_meter_resamp_fact = 0x28,
342 },
343
344 {
345 .peak_det_timeout = 0x5,
346 .rms_meter_div_fact = 0xB << 4,
347 .rms_meter_resamp_fact = 0x28,
348 },
349
350 {
351 .peak_det_timeout = 0x5,
352 .rms_meter_div_fact = 0xB << 4,
353 .rms_meter_resamp_fact = 0x28,
354 },
355};
356
Kuirong Wange9c8a222012-03-28 16:24:09 -0700357static unsigned short rx_digital_gain_reg[] = {
358 TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
359 TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
360 TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
361 TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
362 TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
363 TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
364 TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
365};
366
367
368static unsigned short tx_digital_gain_reg[] = {
369 TABLA_A_CDC_TX1_VOL_CTL_GAIN,
370 TABLA_A_CDC_TX2_VOL_CTL_GAIN,
371 TABLA_A_CDC_TX3_VOL_CTL_GAIN,
372 TABLA_A_CDC_TX4_VOL_CTL_GAIN,
373 TABLA_A_CDC_TX5_VOL_CTL_GAIN,
374 TABLA_A_CDC_TX6_VOL_CTL_GAIN,
375 TABLA_A_CDC_TX7_VOL_CTL_GAIN,
376 TABLA_A_CDC_TX8_VOL_CTL_GAIN,
377 TABLA_A_CDC_TX9_VOL_CTL_GAIN,
378 TABLA_A_CDC_TX10_VOL_CTL_GAIN,
379};
380
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
382 struct snd_kcontrol *kcontrol, int event)
383{
384 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700385
386 pr_debug("%s %d\n", __func__, event);
387 switch (event) {
388 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700389 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
390 0x01);
391 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
392 usleep_range(200, 200);
393 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
394 break;
395 case SND_SOC_DAPM_PRE_PMD:
396 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
397 0x10);
398 usleep_range(20, 20);
399 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
400 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
401 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
402 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
403 0x00);
404 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 break;
406 }
407 return 0;
408}
409
Bradley Rubina7096d02011-08-03 18:29:02 -0700410static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
411 struct snd_ctl_elem_value *ucontrol)
412{
413 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
414 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
415 ucontrol->value.integer.value[0] = tabla->anc_slot;
416 return 0;
417}
418
419static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
420 struct snd_ctl_elem_value *ucontrol)
421{
422 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
423 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
424 tabla->anc_slot = ucontrol->value.integer.value[0];
425 return 0;
426}
427
Kiran Kandid2d86b52011-09-09 17:44:28 -0700428static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
429 struct snd_ctl_elem_value *ucontrol)
430{
431 u8 ear_pa_gain;
432 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
433
434 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
435
436 ear_pa_gain = ear_pa_gain >> 5;
437
438 if (ear_pa_gain == 0x00) {
439 ucontrol->value.integer.value[0] = 0;
440 } else if (ear_pa_gain == 0x04) {
441 ucontrol->value.integer.value[0] = 1;
442 } else {
443 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
444 __func__, ear_pa_gain);
445 return -EINVAL;
446 }
447
448 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
449
450 return 0;
451}
452
453static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
454 struct snd_ctl_elem_value *ucontrol)
455{
456 u8 ear_pa_gain;
457 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
458
459 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
460 ucontrol->value.integer.value[0]);
461
462 switch (ucontrol->value.integer.value[0]) {
463 case 0:
464 ear_pa_gain = 0x00;
465 break;
466 case 1:
467 ear_pa_gain = 0x80;
468 break;
469 default:
470 return -EINVAL;
471 }
472
473 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
474 return 0;
475}
476
Ben Romberger1f045a72011-11-04 10:14:57 -0700477static int tabla_get_iir_enable_audio_mixer(
478 struct snd_kcontrol *kcontrol,
479 struct snd_ctl_elem_value *ucontrol)
480{
481 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
482 int iir_idx = ((struct soc_multi_mixer_control *)
483 kcontrol->private_value)->reg;
484 int band_idx = ((struct soc_multi_mixer_control *)
485 kcontrol->private_value)->shift;
486
487 ucontrol->value.integer.value[0] =
488 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
489 (1 << band_idx);
490
491 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
492 iir_idx, band_idx,
493 (uint32_t)ucontrol->value.integer.value[0]);
494 return 0;
495}
496
497static int tabla_put_iir_enable_audio_mixer(
498 struct snd_kcontrol *kcontrol,
499 struct snd_ctl_elem_value *ucontrol)
500{
501 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
502 int iir_idx = ((struct soc_multi_mixer_control *)
503 kcontrol->private_value)->reg;
504 int band_idx = ((struct soc_multi_mixer_control *)
505 kcontrol->private_value)->shift;
506 int value = ucontrol->value.integer.value[0];
507
508 /* Mask first 5 bits, 6-8 are reserved */
509 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
510 (1 << band_idx), (value << band_idx));
511
512 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
513 iir_idx, band_idx, value);
514 return 0;
515}
516static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
517 int iir_idx, int band_idx,
518 int coeff_idx)
519{
520 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800521 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700522 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800523 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700524
525 /* Mask bits top 2 bits since they are reserved */
526 return ((snd_soc_read(codec,
527 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
528 (snd_soc_read(codec,
529 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
530 (snd_soc_read(codec,
531 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
532 (snd_soc_read(codec,
533 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
534 0x3FFFFFFF;
535}
536
537static int tabla_get_iir_band_audio_mixer(
538 struct snd_kcontrol *kcontrol,
539 struct snd_ctl_elem_value *ucontrol)
540{
541 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
542 int iir_idx = ((struct soc_multi_mixer_control *)
543 kcontrol->private_value)->reg;
544 int band_idx = ((struct soc_multi_mixer_control *)
545 kcontrol->private_value)->shift;
546
547 ucontrol->value.integer.value[0] =
548 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
549 ucontrol->value.integer.value[1] =
550 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
551 ucontrol->value.integer.value[2] =
552 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
553 ucontrol->value.integer.value[3] =
554 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
555 ucontrol->value.integer.value[4] =
556 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
557
558 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
559 "%s: IIR #%d band #%d b1 = 0x%x\n"
560 "%s: IIR #%d band #%d b2 = 0x%x\n"
561 "%s: IIR #%d band #%d a1 = 0x%x\n"
562 "%s: IIR #%d band #%d a2 = 0x%x\n",
563 __func__, iir_idx, band_idx,
564 (uint32_t)ucontrol->value.integer.value[0],
565 __func__, iir_idx, band_idx,
566 (uint32_t)ucontrol->value.integer.value[1],
567 __func__, iir_idx, band_idx,
568 (uint32_t)ucontrol->value.integer.value[2],
569 __func__, iir_idx, band_idx,
570 (uint32_t)ucontrol->value.integer.value[3],
571 __func__, iir_idx, band_idx,
572 (uint32_t)ucontrol->value.integer.value[4]);
573 return 0;
574}
575
576static void set_iir_band_coeff(struct snd_soc_codec *codec,
577 int iir_idx, int band_idx,
578 int coeff_idx, uint32_t value)
579{
580 /* Mask top 3 bits, 6-8 are reserved */
581 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800582 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700583 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800584 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700585
586 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800587 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700588 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800589 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700590
591 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800592 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700593 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800594 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700595
Ben Romberger0915aae2012-02-06 23:32:43 -0800596 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700597 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800598 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700599
Ben Romberger0915aae2012-02-06 23:32:43 -0800600 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700601 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800602 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700603}
604
605static int tabla_put_iir_band_audio_mixer(
606 struct snd_kcontrol *kcontrol,
607 struct snd_ctl_elem_value *ucontrol)
608{
609 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
610 int iir_idx = ((struct soc_multi_mixer_control *)
611 kcontrol->private_value)->reg;
612 int band_idx = ((struct soc_multi_mixer_control *)
613 kcontrol->private_value)->shift;
614
615 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
616 ucontrol->value.integer.value[0]);
617 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
618 ucontrol->value.integer.value[1]);
619 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
620 ucontrol->value.integer.value[2]);
621 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
622 ucontrol->value.integer.value[3]);
623 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
624 ucontrol->value.integer.value[4]);
625
626 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
627 "%s: IIR #%d band #%d b1 = 0x%x\n"
628 "%s: IIR #%d band #%d b2 = 0x%x\n"
629 "%s: IIR #%d band #%d a1 = 0x%x\n"
630 "%s: IIR #%d band #%d a2 = 0x%x\n",
631 __func__, iir_idx, band_idx,
632 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
633 __func__, iir_idx, band_idx,
634 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
635 __func__, iir_idx, band_idx,
636 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
637 __func__, iir_idx, band_idx,
638 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
639 __func__, iir_idx, band_idx,
640 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
641 return 0;
642}
643
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800644static int tabla_compander_gain_offset(
645 struct snd_soc_codec *codec, u32 enable,
646 unsigned int reg, int mask, int event)
647{
648 int pa_mode = snd_soc_read(codec, reg) & mask;
649 int gain_offset = 0;
650 /* if PMU && enable is 1-> offset is 3
651 * if PMU && enable is 0-> offset is 0
652 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
653 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
654 */
655
656 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
657 gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
658 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
659 gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
660 return gain_offset;
661}
662
663
664static int tabla_config_gain_compander(
665 struct snd_soc_codec *codec,
666 u32 compander, u32 enable, int event)
667{
668 int value = 0;
669 int mask = 1 << 4;
670 int gain = 0;
671 int gain_offset;
672 if (compander >= COMPANDER_MAX) {
673 pr_err("%s: Error, invalid compander channel\n", __func__);
674 return -EINVAL;
675 }
676
677 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
678 value = 1 << 4;
679
680 if (compander == COMPANDER_1) {
681 gain_offset = tabla_compander_gain_offset(codec, enable,
682 TABLA_A_RX_HPH_L_GAIN, mask, event);
683 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
684 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
685 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
686 0xFF, gain - gain_offset);
687 gain_offset = tabla_compander_gain_offset(codec, enable,
688 TABLA_A_RX_HPH_R_GAIN, mask, event);
689 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
690 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
691 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
692 0xFF, gain - gain_offset);
693 } else if (compander == COMPANDER_2) {
694 gain_offset = tabla_compander_gain_offset(codec, enable,
695 TABLA_A_RX_LINE_1_GAIN, mask, event);
696 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
697 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
698 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
699 0xFF, gain - gain_offset);
700 gain_offset = tabla_compander_gain_offset(codec, enable,
701 TABLA_A_RX_LINE_3_GAIN, mask, event);
702 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
703 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
704 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
705 0xFF, gain - gain_offset);
706 gain_offset = tabla_compander_gain_offset(codec, enable,
707 TABLA_A_RX_LINE_2_GAIN, mask, event);
708 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
709 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
710 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
711 0xFF, gain - gain_offset);
712 gain_offset = tabla_compander_gain_offset(codec, enable,
713 TABLA_A_RX_LINE_4_GAIN, mask, event);
714 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
715 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
716 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
717 0xFF, gain - gain_offset);
718 }
719 return 0;
720}
721static int tabla_get_compander(struct snd_kcontrol *kcontrol,
722 struct snd_ctl_elem_value *ucontrol)
723{
724
725 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
726 int comp = ((struct soc_multi_mixer_control *)
727 kcontrol->private_value)->max;
728 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
729
730 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
731
732 return 0;
733}
734
735static int tabla_set_compander(struct snd_kcontrol *kcontrol,
736 struct snd_ctl_elem_value *ucontrol)
737{
738 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
739 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
740 int comp = ((struct soc_multi_mixer_control *)
741 kcontrol->private_value)->max;
742 int value = ucontrol->value.integer.value[0];
743
744 if (value == tabla->comp_enabled[comp]) {
745 pr_debug("%s: compander #%d enable %d no change\n",
746 __func__, comp, value);
747 return 0;
748 }
749 tabla->comp_enabled[comp] = value;
750 return 0;
751}
752
753
754static int tabla_config_compander(struct snd_soc_dapm_widget *w,
755 struct snd_kcontrol *kcontrol,
756 int event)
757{
758 struct snd_soc_codec *codec = w->codec;
759 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
760 u32 rate = tabla->comp_fs[w->shift];
761
762 switch (event) {
763 case SND_SOC_DAPM_PRE_PMU:
764 if (tabla->comp_enabled[w->shift] != 0) {
765 /* Enable both L/R compander clocks */
766 snd_soc_update_bits(codec,
767 TABLA_A_CDC_CLK_RX_B2_CTL,
768 0x03 << comp_shift[w->shift],
769 0x03 << comp_shift[w->shift]);
770 /* Clar the HALT for the compander*/
771 snd_soc_update_bits(codec,
772 TABLA_A_CDC_COMP1_B1_CTL +
773 w->shift * 8, 1 << 2, 0);
774 /* Toggle compander reset bits*/
775 snd_soc_update_bits(codec,
776 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
777 0x03 << comp_shift[w->shift],
778 0x03 << comp_shift[w->shift]);
779 snd_soc_update_bits(codec,
780 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
781 0x03 << comp_shift[w->shift], 0);
782 tabla_config_gain_compander(codec, w->shift, 1, event);
783 /* Update the RMS meter resampling*/
784 snd_soc_update_bits(codec,
785 TABLA_A_CDC_COMP1_B3_CTL +
786 w->shift * 8, 0xFF, 0x01);
787 /* Wait for 1ms*/
788 usleep_range(1000, 1000);
789 }
790 break;
791 case SND_SOC_DAPM_POST_PMU:
792 /* Set sample rate dependent paramater*/
793 if (tabla->comp_enabled[w->shift] != 0) {
794 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
795 w->shift * 8, 0x03, rate);
796 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
797 w->shift * 8, 0x0F,
798 comp_samp_params[rate].peak_det_timeout);
799 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
800 w->shift * 8, 0xF0,
801 comp_samp_params[rate].rms_meter_div_fact);
802 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
803 w->shift * 8, 0xFF,
804 comp_samp_params[rate].rms_meter_resamp_fact);
805 /* Compander enable -> 0x370/0x378*/
806 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
807 w->shift * 8, 0x03, 0x03);
808 }
809 break;
810 case SND_SOC_DAPM_PRE_PMD:
811 /* Halt the compander*/
812 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
813 w->shift * 8, 1 << 2, 1 << 2);
814 break;
815 case SND_SOC_DAPM_POST_PMD:
816 /* Restore the gain */
817 tabla_config_gain_compander(codec, w->shift,
818 tabla->comp_enabled[w->shift], event);
819 /* Disable the compander*/
820 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
821 w->shift * 8, 0x03, 0x00);
822 /* Turn off the clock for compander in pair*/
823 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
824 0x03 << comp_shift[w->shift], 0);
825 break;
826 }
827 return 0;
828}
829
Kiran Kandid2d86b52011-09-09 17:44:28 -0700830static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
831static const struct soc_enum tabla_ear_pa_gain_enum[] = {
832 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
833};
834
Santosh Mardi024010f2011-10-18 06:27:21 +0530835/*cut of frequency for high pass filter*/
836static const char *cf_text[] = {
837 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
838};
839
840static const struct soc_enum cf_dec1_enum =
841 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
842
843static const struct soc_enum cf_dec2_enum =
844 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
845
846static const struct soc_enum cf_dec3_enum =
847 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
848
849static const struct soc_enum cf_dec4_enum =
850 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
851
852static const struct soc_enum cf_dec5_enum =
853 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
854
855static const struct soc_enum cf_dec6_enum =
856 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
857
858static const struct soc_enum cf_dec7_enum =
859 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
860
861static const struct soc_enum cf_dec8_enum =
862 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
863
864static const struct soc_enum cf_dec9_enum =
865 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
866
867static const struct soc_enum cf_dec10_enum =
868 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
869
870static const struct soc_enum cf_rxmix1_enum =
871 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
872
873static const struct soc_enum cf_rxmix2_enum =
874 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
875
876static const struct soc_enum cf_rxmix3_enum =
877 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
878
879static const struct soc_enum cf_rxmix4_enum =
880 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
881
882static const struct soc_enum cf_rxmix5_enum =
883 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
884;
885static const struct soc_enum cf_rxmix6_enum =
886 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
887
888static const struct soc_enum cf_rxmix7_enum =
889 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700892
893 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
894 tabla_pa_gain_get, tabla_pa_gain_put),
895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
897 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700898 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
899 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700900 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
901 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700902 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
903 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700904 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
905 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
908 line_gain),
909 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
910 line_gain),
911
Bradley Rubin410383f2011-07-22 13:44:23 -0700912 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
913 -84, 40, digital_gain),
914 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
915 -84, 40, digital_gain),
916 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
917 -84, 40, digital_gain),
918 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
919 -84, 40, digital_gain),
920 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
921 -84, 40, digital_gain),
922 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
923 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -0800924 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
925 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700926
Bradley Rubin410383f2011-07-22 13:44:23 -0700927 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700929 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700931 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
932 digital_gain),
933 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
934 digital_gain),
935 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
936 digital_gain),
937 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
938 digital_gain),
939 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
940 digital_gain),
941 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
942 digital_gain),
943 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
944 digital_gain),
945 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
946 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700947 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
948 40, digital_gain),
949 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
950 40, digital_gain),
951 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
952 40, digital_gain),
953 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
954 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700955 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
956 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700957 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
958 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700959 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
960 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800962 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
963 aux_pga_gain),
964 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
965 aux_pga_gain),
966
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800968 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700969 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700970
971 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
972 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530973 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
974 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
975 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
976 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
977 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
978 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
979 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
980 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
981 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
982 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
983
984 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
985 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
986 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
987 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
988 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
989 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
990 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
991 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
992 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
993 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
994
995 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
996 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
997 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
998 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
999 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
1000 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
1001 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
1002
1003 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1004 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1005 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
1006 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
1007 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
1008 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
1009 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -07001010
1011 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1012 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1013 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1014 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1015 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1016 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1017 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1018 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1019 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1020 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1021 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1022 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1023 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1024 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1025 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1026 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1027 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1028 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1029 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1030 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1031
1032 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1033 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1034 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1035 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1036 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1037 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1038 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1039 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1040 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1041 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1042 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1043 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1044 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1045 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1046 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1047 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1048 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1049 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1050 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1051 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001052 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
1053 tabla_get_compander, tabla_set_compander),
1054 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
1055 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056};
1057
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001058static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
1059 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
1060};
1061
1062static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
1063 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
1064};
1065
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066static const char *rx_mix1_text[] = {
1067 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1068 "RX5", "RX6", "RX7"
1069};
1070
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001071static const char *rx_dsm_text[] = {
1072 "CIC_OUT", "DSM_INV"
1073};
1074
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001075static const char *sb_tx1_mux_text[] = {
1076 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1077 "DEC1"
1078};
1079
1080static const char *sb_tx5_mux_text[] = {
1081 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1082 "DEC5"
1083};
1084
1085static const char *sb_tx6_mux_text[] = {
1086 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1087 "DEC6"
1088};
1089
1090static const char const *sb_tx7_to_tx10_mux_text[] = {
1091 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1092 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1093 "DEC9", "DEC10"
1094};
1095
1096static const char *dec1_mux_text[] = {
1097 "ZERO", "DMIC1", "ADC6",
1098};
1099
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001100static const char *dec2_mux_text[] = {
1101 "ZERO", "DMIC2", "ADC5",
1102};
1103
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001104static const char *dec3_mux_text[] = {
1105 "ZERO", "DMIC3", "ADC4",
1106};
1107
1108static const char *dec4_mux_text[] = {
1109 "ZERO", "DMIC4", "ADC3",
1110};
1111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001112static const char *dec5_mux_text[] = {
1113 "ZERO", "DMIC5", "ADC2",
1114};
1115
1116static const char *dec6_mux_text[] = {
1117 "ZERO", "DMIC6", "ADC1",
1118};
1119
1120static const char const *dec7_mux_text[] = {
1121 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1122};
1123
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001124static const char *dec8_mux_text[] = {
1125 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1126};
1127
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001128static const char *dec9_mux_text[] = {
1129 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1130};
1131
1132static const char *dec10_mux_text[] = {
1133 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1134};
1135
Bradley Rubin229c6a52011-07-12 16:18:48 -07001136static const char const *anc_mux_text[] = {
1137 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1138 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1139};
1140
1141static const char const *anc1_fb_mux_text[] = {
1142 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1143};
1144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145static const char *iir1_inp1_text[] = {
1146 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1147 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1148};
1149
1150static const struct soc_enum rx_mix1_inp1_chain_enum =
1151 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1152
Bradley Rubin229c6a52011-07-12 16:18:48 -07001153static const struct soc_enum rx_mix1_inp2_chain_enum =
1154 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1155
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156static const struct soc_enum rx2_mix1_inp1_chain_enum =
1157 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1158
Bradley Rubin229c6a52011-07-12 16:18:48 -07001159static const struct soc_enum rx2_mix1_inp2_chain_enum =
1160 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162static const struct soc_enum rx3_mix1_inp1_chain_enum =
1163 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1164
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001165static const struct soc_enum rx3_mix1_inp2_chain_enum =
1166 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1167
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168static const struct soc_enum rx4_mix1_inp1_chain_enum =
1169 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1170
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001171static const struct soc_enum rx4_mix1_inp2_chain_enum =
1172 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174static const struct soc_enum rx5_mix1_inp1_chain_enum =
1175 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1176
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001177static const struct soc_enum rx5_mix1_inp2_chain_enum =
1178 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1179
1180static const struct soc_enum rx6_mix1_inp1_chain_enum =
1181 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1182
1183static const struct soc_enum rx6_mix1_inp2_chain_enum =
1184 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1185
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001186static const struct soc_enum rx7_mix1_inp1_chain_enum =
1187 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1188
1189static const struct soc_enum rx7_mix1_inp2_chain_enum =
1190 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1191
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001192static const struct soc_enum rx4_dsm_enum =
1193 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1194
1195static const struct soc_enum rx6_dsm_enum =
1196 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198static const struct soc_enum sb_tx5_mux_enum =
1199 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1200
1201static const struct soc_enum sb_tx6_mux_enum =
1202 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1203
1204static const struct soc_enum sb_tx7_mux_enum =
1205 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1206 sb_tx7_to_tx10_mux_text);
1207
1208static const struct soc_enum sb_tx8_mux_enum =
1209 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1210 sb_tx7_to_tx10_mux_text);
1211
Kiran Kandi3426e512011-09-13 22:50:10 -07001212static const struct soc_enum sb_tx9_mux_enum =
1213 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1214 sb_tx7_to_tx10_mux_text);
1215
1216static const struct soc_enum sb_tx10_mux_enum =
1217 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1218 sb_tx7_to_tx10_mux_text);
1219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220static const struct soc_enum sb_tx1_mux_enum =
1221 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1222
1223static const struct soc_enum dec1_mux_enum =
1224 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1225
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001226static const struct soc_enum dec2_mux_enum =
1227 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1228
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001229static const struct soc_enum dec3_mux_enum =
1230 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1231
1232static const struct soc_enum dec4_mux_enum =
1233 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235static const struct soc_enum dec5_mux_enum =
1236 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1237
1238static const struct soc_enum dec6_mux_enum =
1239 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1240
1241static const struct soc_enum dec7_mux_enum =
1242 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1243
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001244static const struct soc_enum dec8_mux_enum =
1245 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1246
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001247static const struct soc_enum dec9_mux_enum =
1248 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1249
1250static const struct soc_enum dec10_mux_enum =
1251 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1252
Bradley Rubin229c6a52011-07-12 16:18:48 -07001253static const struct soc_enum anc1_mux_enum =
1254 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1255
1256static const struct soc_enum anc2_mux_enum =
1257 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1258
1259static const struct soc_enum anc1_fb_mux_enum =
1260 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262static const struct soc_enum iir1_inp1_mux_enum =
1263 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
1264
1265static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1266 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1267
Bradley Rubin229c6a52011-07-12 16:18:48 -07001268static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1269 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1272 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1273
Bradley Rubin229c6a52011-07-12 16:18:48 -07001274static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1275 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1278 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1279
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001280static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1281 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1282
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1284 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1285
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001286static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1287 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1288
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001289static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1290 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1291
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001292static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1293 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1294
1295static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1296 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1297
1298static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1299 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1300
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001301static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1302 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1303
1304static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1305 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1306
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001307static const struct snd_kcontrol_new rx4_dsm_mux =
1308 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1309
1310static const struct snd_kcontrol_new rx6_dsm_mux =
1311 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1312
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313static const struct snd_kcontrol_new sb_tx5_mux =
1314 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1315
1316static const struct snd_kcontrol_new sb_tx6_mux =
1317 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1318
1319static const struct snd_kcontrol_new sb_tx7_mux =
1320 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1321
1322static const struct snd_kcontrol_new sb_tx8_mux =
1323 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1324
Kiran Kandi3426e512011-09-13 22:50:10 -07001325static const struct snd_kcontrol_new sb_tx9_mux =
1326 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1327
1328static const struct snd_kcontrol_new sb_tx10_mux =
1329 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1330
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331static const struct snd_kcontrol_new sb_tx1_mux =
1332 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1333
1334static const struct snd_kcontrol_new dec1_mux =
1335 SOC_DAPM_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1336
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001337static const struct snd_kcontrol_new dec2_mux =
1338 SOC_DAPM_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1339
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001340static const struct snd_kcontrol_new dec3_mux =
1341 SOC_DAPM_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1342
1343static const struct snd_kcontrol_new dec4_mux =
1344 SOC_DAPM_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001346static const struct snd_kcontrol_new dec5_mux =
1347 SOC_DAPM_ENUM("DEC5 MUX Mux", dec5_mux_enum);
1348
1349static const struct snd_kcontrol_new dec6_mux =
1350 SOC_DAPM_ENUM("DEC6 MUX Mux", dec6_mux_enum);
1351
1352static const struct snd_kcontrol_new dec7_mux =
1353 SOC_DAPM_ENUM("DEC7 MUX Mux", dec7_mux_enum);
1354
Bradley Rubin229c6a52011-07-12 16:18:48 -07001355static const struct snd_kcontrol_new anc1_mux =
1356 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001357static const struct snd_kcontrol_new dec8_mux =
1358 SOC_DAPM_ENUM("DEC8 MUX Mux", dec8_mux_enum);
1359
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001360static const struct snd_kcontrol_new dec9_mux =
1361 SOC_DAPM_ENUM("DEC9 MUX Mux", dec9_mux_enum);
1362
1363static const struct snd_kcontrol_new dec10_mux =
1364 SOC_DAPM_ENUM("DEC10 MUX Mux", dec10_mux_enum);
1365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366static const struct snd_kcontrol_new iir1_inp1_mux =
1367 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1368
Bradley Rubin229c6a52011-07-12 16:18:48 -07001369static const struct snd_kcontrol_new anc2_mux =
1370 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371
Bradley Rubin229c6a52011-07-12 16:18:48 -07001372static const struct snd_kcontrol_new anc1_fb_mux =
1373 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374
Bradley Rubin229c6a52011-07-12 16:18:48 -07001375static const struct snd_kcontrol_new dac1_switch[] = {
1376 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1377};
1378static const struct snd_kcontrol_new hphl_switch[] = {
1379 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1380};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001381
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001382static const struct snd_kcontrol_new hphl_pa_mix[] = {
1383 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1384 7, 1, 0),
1385 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1386 7, 1, 0),
1387 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1388 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1389 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1390 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1391};
1392
1393static const struct snd_kcontrol_new hphr_pa_mix[] = {
1394 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1395 6, 1, 0),
1396 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1397 6, 1, 0),
1398 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1399 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1400 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1401 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1402};
1403
1404static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1405 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1406 5, 1, 0),
1407 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1408 5, 1, 0),
1409 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1410 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1411 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1412 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1413};
1414
1415static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1416 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1417 4, 1, 0),
1418 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1419 4, 1, 0),
1420 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1421 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1422 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1423 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1424};
1425
1426static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1427 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1428 3, 1, 0),
1429 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1430 3, 1, 0),
1431 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1432 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1433 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1434 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1435};
1436
1437static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1438 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1439 2, 1, 0),
1440 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1441 2, 1, 0),
1442 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1443 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1444 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1445 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1446};
1447
1448static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1449 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1450 1, 1, 0),
1451 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1452 1, 1, 0),
1453 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1454 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1455 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1456 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1457};
1458
1459static const struct snd_kcontrol_new ear_pa_mix[] = {
1460 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1461 0, 1, 0),
1462 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1463 0, 1, 0),
1464 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1465 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1466 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1467 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1468};
1469
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001470static const struct snd_kcontrol_new lineout3_ground_switch =
1471 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1472
1473static const struct snd_kcontrol_new lineout4_ground_switch =
1474 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001475
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001477 int enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478{
1479 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1480
1481 pr_debug("%s %d\n", __func__, enable);
1482
1483 if (enable) {
1484 tabla->adc_count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1486 } else {
1487 tabla->adc_count--;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001488 if (!tabla->adc_count)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
Joonwoo Park03324832012-03-19 19:36:16 -07001490 0x2, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 }
1492}
1493
1494static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1495 struct snd_kcontrol *kcontrol, int event)
1496{
1497 struct snd_soc_codec *codec = w->codec;
1498 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001499 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500
1501 pr_debug("%s %d\n", __func__, event);
1502
1503 if (w->reg == TABLA_A_TX_1_2_EN)
1504 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1505 else if (w->reg == TABLA_A_TX_3_4_EN)
1506 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1507 else if (w->reg == TABLA_A_TX_5_6_EN)
1508 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1509 else {
1510 pr_err("%s: Error, invalid adc register\n", __func__);
1511 return -EINVAL;
1512 }
1513
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001514 if (w->shift == 3)
1515 init_bit_shift = 6;
1516 else if (w->shift == 7)
1517 init_bit_shift = 7;
1518 else {
1519 pr_err("%s: Error, invalid init bit postion adc register\n",
1520 __func__);
1521 return -EINVAL;
1522 }
1523
1524
1525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526 switch (event) {
1527 case SND_SOC_DAPM_PRE_PMU:
1528 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001529 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1530 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001531 break;
1532 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001533
1534 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536 break;
1537 case SND_SOC_DAPM_POST_PMD:
1538 tabla_codec_enable_adc_block(codec, 0);
1539 break;
1540 }
1541 return 0;
1542}
1543
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001544static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1545{
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001546 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1547 0x80);
1548 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1549 0x04);
1550 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1551 0x01);
1552 usleep_range(1000, 1000);
1553 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1554 0x00);
1555}
1556
1557static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1558 enum tabla_bandgap_type choice)
1559{
1560 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1561
1562 /* TODO lock resources accessed by audio streams and threaded
1563 * interrupt handlers
1564 */
1565
1566 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1567 tabla->bandgap_type);
1568
1569 if (tabla->bandgap_type == choice)
1570 return;
1571
1572 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1573 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1574 tabla_codec_enable_audio_mode_bandgap(codec);
1575 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
1576 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1577 0x2);
1578 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1579 0x80);
1580 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1581 0x4);
1582 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1583 0x01);
1584 usleep_range(1000, 1000);
1585 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1586 0x00);
1587 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1588 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1589 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1590 usleep_range(100, 100);
1591 tabla_codec_enable_audio_mode_bandgap(codec);
1592 } else if (choice == TABLA_BANDGAP_OFF) {
1593 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1594 } else {
1595 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1596 }
1597 tabla->bandgap_type = choice;
1598}
1599
1600static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1601{
1602 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1603 pr_debug("%s\n", __func__);
1604 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
1605 ndelay(160);
1606 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1607 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
1608 tabla->clock_active = false;
1609}
1610
1611static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
1612{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001613 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001614 return 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001615 else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001616 return 1;
1617 else {
1618 BUG_ON(1);
1619 return -EINVAL;
1620 }
1621}
1622
1623static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1624{
1625 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1626
1627 if (enable) {
1628 tabla->rx_bias_count++;
1629 if (tabla->rx_bias_count == 1)
1630 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1631 0x80, 0x80);
1632 } else {
1633 tabla->rx_bias_count--;
1634 if (!tabla->rx_bias_count)
1635 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1636 0x80, 0x00);
1637 }
1638}
1639
1640static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1641 int enable)
1642{
1643 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1644
1645 pr_debug("%s: enable = %d\n", __func__, enable);
1646 if (enable) {
1647 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
1648 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1649 usleep_range(5, 5);
1650 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
1651 0x80);
1652 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
1653 0x80);
1654 usleep_range(10, 10);
1655 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
1656 usleep_range(20, 20);
1657 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1658 } else {
1659 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
1660 0);
1661 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
1662 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1663 }
1664 tabla->config_mode_active = enable ? true : false;
1665
1666 return 0;
1667}
1668
1669static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
1670 int config_mode)
1671{
1672 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1673
1674 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
1675
1676 if (config_mode) {
1677 tabla_codec_enable_config_mode(codec, 1);
1678 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x00);
1679 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1680 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN1, 0x0D);
1681 usleep_range(1000, 1000);
1682 } else
1683 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1684
1685 if (!config_mode && tabla->mbhc_polling_active) {
1686 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1687 tabla_codec_enable_config_mode(codec, 0);
1688
1689 }
1690
1691 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x05);
1692 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
1693 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1694 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1695 usleep_range(50, 50);
1696 tabla->clock_active = true;
1697 return 0;
1698}
1699
1700static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1701 struct snd_kcontrol *kcontrol, int event)
1702{
1703 struct snd_soc_codec *codec = w->codec;
1704 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1705
1706 pr_debug("%s: %d\n", __func__, event);
1707
1708 switch (event) {
1709 case SND_SOC_DAPM_PRE_PMU:
1710 tabla_codec_enable_bandgap(codec,
1711 TABLA_BANDGAP_AUDIO_MODE);
1712 tabla_enable_rx_bias(codec, 1);
1713
1714 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1715 0x08, 0x08);
1716 /* Enable Zero Cross detect for AUX PGA channel
1717 * and set the initial AUX PGA gain to NEG_0P0_DB
1718 * to avoid glitches.
1719 */
1720 if (w->reg == TABLA_A_AUX_L_EN) {
1721 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1722 0x20, 0x20);
1723 tabla->aux_l_gain = snd_soc_read(codec,
1724 TABLA_A_AUX_L_GAIN);
1725 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1726 } else {
1727 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1728 0x20, 0x20);
1729 tabla->aux_r_gain = snd_soc_read(codec,
1730 TABLA_A_AUX_R_GAIN);
1731 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1732 }
1733 if (tabla->aux_pga_cnt++ == 1
1734 && !tabla->mclk_enabled) {
1735 tabla_codec_enable_clock_block(codec, 1);
1736 pr_debug("AUX PGA enabled RC osc\n");
1737 }
1738 break;
1739
1740 case SND_SOC_DAPM_POST_PMU:
1741 if (w->reg == TABLA_A_AUX_L_EN)
1742 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1743 tabla->aux_l_gain);
1744 else
1745 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1746 tabla->aux_r_gain);
1747 break;
1748
1749 case SND_SOC_DAPM_PRE_PMD:
1750 /* Mute AUX PGA channel in use before disabling AUX PGA */
1751 if (w->reg == TABLA_A_AUX_L_EN) {
1752 tabla->aux_l_gain = snd_soc_read(codec,
1753 TABLA_A_AUX_L_GAIN);
1754 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1755 } else {
1756 tabla->aux_r_gain = snd_soc_read(codec,
1757 TABLA_A_AUX_R_GAIN);
1758 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1759 }
1760 break;
1761
1762 case SND_SOC_DAPM_POST_PMD:
1763 tabla_enable_rx_bias(codec, 0);
1764
1765 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1766 0x08, 0x00);
1767 if (w->reg == TABLA_A_AUX_L_EN) {
1768 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1769 tabla->aux_l_gain);
1770 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1771 0x20, 0x00);
1772 } else {
1773 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1774 tabla->aux_r_gain);
1775 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1776 0x20, 0x00);
1777 }
1778
1779 if (tabla->aux_pga_cnt-- == 0) {
1780 if (tabla->mbhc_polling_active)
1781 tabla_codec_enable_bandgap(codec,
1782 TABLA_BANDGAP_MBHC_MODE);
1783 else
1784 tabla_codec_enable_bandgap(codec,
1785 TABLA_BANDGAP_OFF);
1786
1787 if (!tabla->mclk_enabled &&
1788 !tabla->mbhc_polling_active) {
1789 tabla_codec_enable_clock_block(codec, 0);
1790 }
1791 }
1792 break;
1793 }
1794 return 0;
1795}
1796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001797static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1798 struct snd_kcontrol *kcontrol, int event)
1799{
1800 struct snd_soc_codec *codec = w->codec;
1801 u16 lineout_gain_reg;
1802
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001803 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001804
1805 switch (w->shift) {
1806 case 0:
1807 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1808 break;
1809 case 1:
1810 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1811 break;
1812 case 2:
1813 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
1814 break;
1815 case 3:
1816 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
1817 break;
1818 case 4:
1819 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
1820 break;
1821 default:
1822 pr_err("%s: Error, incorrect lineout register value\n",
1823 __func__);
1824 return -EINVAL;
1825 }
1826
1827 switch (event) {
1828 case SND_SOC_DAPM_PRE_PMU:
1829 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1830 break;
1831 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001832 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001833 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08001834 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001835 break;
1836 case SND_SOC_DAPM_POST_PMD:
1837 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1838 break;
1839 }
1840 return 0;
1841}
1842
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001843
1844static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001845 struct snd_kcontrol *kcontrol, int event)
1846{
1847 struct snd_soc_codec *codec = w->codec;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001848 u16 tx_mux_ctl_reg, tx_dmic_ctl_reg;
1849 u8 dmic_clk_sel, dmic_clk_en;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001850 unsigned int dmic;
1851 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001852
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001853 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
1854 if (ret < 0) {
1855 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001856 return -EINVAL;
1857 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001858
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07001859 switch (dmic) {
1860 case 1:
1861 case 2:
1862 dmic_clk_sel = 0x02;
1863 dmic_clk_en = 0x01;
1864 break;
1865
1866 case 3:
1867 case 4:
1868 dmic_clk_sel = 0x08;
1869 dmic_clk_en = 0x04;
1870 break;
1871
1872 case 5:
1873 case 6:
1874 dmic_clk_sel = 0x20;
1875 dmic_clk_en = 0x10;
1876 break;
1877
1878 default:
1879 pr_err("%s: Invalid DMIC Selection\n", __func__);
1880 return -EINVAL;
1881 }
1882
1883 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (dmic - 1);
1884 tx_dmic_ctl_reg = TABLA_A_CDC_TX1_DMIC_CTL + 8 * (dmic - 1);
1885
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001886 pr_debug("%s %d\n", __func__, event);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001887
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001888 switch (event) {
1889 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001890 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, 0x1);
1891
1892 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1893 dmic_clk_sel, dmic_clk_sel);
1894
1895 snd_soc_update_bits(codec, tx_dmic_ctl_reg, 0x1, 0x1);
1896
1897 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1898 dmic_clk_en, dmic_clk_en);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001899 break;
1900 case SND_SOC_DAPM_POST_PMD:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07001901 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
1902 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001903 break;
1904 }
1905 return 0;
1906}
1907
Bradley Rubin229c6a52011-07-12 16:18:48 -07001908static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
1909 struct snd_kcontrol *kcontrol, int event)
1910{
1911 struct snd_soc_codec *codec = w->codec;
1912 const char *filename;
1913 const struct firmware *fw;
1914 int i;
1915 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07001916 int num_anc_slots;
1917 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001918 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07001919 u32 anc_writes_size = 0;
1920 int anc_size_remaining;
1921 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001922 u16 reg;
1923 u8 mask, val, old_val;
1924
1925 pr_debug("%s %d\n", __func__, event);
1926 switch (event) {
1927 case SND_SOC_DAPM_PRE_PMU:
1928
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001929 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07001930
1931 ret = request_firmware(&fw, filename, codec->dev);
1932 if (ret != 0) {
1933 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1934 ret);
1935 return -ENODEV;
1936 }
1937
Bradley Rubina7096d02011-08-03 18:29:02 -07001938 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07001939 dev_err(codec->dev, "Not enough data\n");
1940 release_firmware(fw);
1941 return -ENOMEM;
1942 }
1943
1944 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07001945 anc_head = (struct anc_header *)(fw->data);
1946 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1947 anc_size_remaining = fw->size - sizeof(struct anc_header);
1948 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07001949
Bradley Rubina7096d02011-08-03 18:29:02 -07001950 if (tabla->anc_slot >= num_anc_slots) {
1951 dev_err(codec->dev, "Invalid ANC slot selected\n");
1952 release_firmware(fw);
1953 return -EINVAL;
1954 }
1955
1956 for (i = 0; i < num_anc_slots; i++) {
1957
1958 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
1959 dev_err(codec->dev, "Invalid register format\n");
1960 release_firmware(fw);
1961 return -EINVAL;
1962 }
1963 anc_writes_size = (u32)(*anc_ptr);
1964 anc_size_remaining -= sizeof(u32);
1965 anc_ptr += 1;
1966
1967 if (anc_writes_size * TABLA_PACKED_REG_SIZE
1968 > anc_size_remaining) {
1969 dev_err(codec->dev, "Invalid register format\n");
1970 release_firmware(fw);
1971 return -ENOMEM;
1972 }
1973
1974 if (tabla->anc_slot == i)
1975 break;
1976
1977 anc_size_remaining -= (anc_writes_size *
1978 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07001979 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07001980 }
1981 if (i == num_anc_slots) {
1982 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07001983 release_firmware(fw);
1984 return -ENOMEM;
1985 }
1986
Bradley Rubina7096d02011-08-03 18:29:02 -07001987 for (i = 0; i < anc_writes_size; i++) {
1988 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07001989 mask, val);
1990 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07001991 snd_soc_write(codec, reg, (old_val & ~mask) |
1992 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07001993 }
1994 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07001995
1996 break;
1997 case SND_SOC_DAPM_POST_PMD:
1998 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1999 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
2000 break;
2001 }
2002 return 0;
2003}
2004
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002005/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002006static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
2007{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002008 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07002009 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
2010 int mbhc_state = tabla->mbhc_state;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002011
Joonwoo Park03324832012-03-19 19:36:16 -07002012 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002013 if (!tabla->mbhc_polling_active) {
2014 pr_debug("Polling is not active, do not start polling\n");
2015 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002016 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002017 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Joonwoo Park03324832012-03-19 19:36:16 -07002018
2019 if (!tabla->no_mic_headset_override) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002020 if (mbhc_state == MBHC_STATE_POTENTIAL) {
2021 pr_debug("%s recovering MBHC state macine\n", __func__);
2022 tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
Joonwoo Park03324832012-03-19 19:36:16 -07002023 /* set to max button press threshold */
2024 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2025 0x7F);
2026 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2027 0xFF);
2028 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2029 (TABLA_IS_1_X(tabla_core->version) ?
2030 0x07 : 0x7F));
2031 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2032 0xFF);
2033 /* set to max */
2034 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2035 0x7F);
2036 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2037 0xFF);
2038 }
2039 }
2040
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002041 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
2042 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2043 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
Joonwoo Park03324832012-03-19 19:36:16 -07002044 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002045}
2046
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002047/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002048static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
2049{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002050 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2051
Joonwoo Park03324832012-03-19 19:36:16 -07002052 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002053 if (!tabla->mbhc_polling_active) {
2054 pr_debug("polling not active, nothing to pause\n");
2055 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002056 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002057
2058 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Joonwoo Park03324832012-03-19 19:36:16 -07002059 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002060}
2061
Joonwoo Park03324832012-03-19 19:36:16 -07002062static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002063{
2064 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2065 u8 reg_mode_val, cur_mode_val;
2066 bool mbhc_was_polling = false;
2067
2068 if (mode)
2069 reg_mode_val = TABLA_CFILT_FAST_MODE;
2070 else
2071 reg_mode_val = TABLA_CFILT_SLOW_MODE;
2072
2073 cur_mode_val = snd_soc_read(codec,
2074 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
2075
2076 if (cur_mode_val != reg_mode_val) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002077 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002078 if (tabla->mbhc_polling_active) {
2079 tabla_codec_pause_hs_polling(codec);
2080 mbhc_was_polling = true;
2081 }
2082 snd_soc_update_bits(codec,
2083 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
2084 if (mbhc_was_polling)
2085 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002086 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002087 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
2088 cur_mode_val, reg_mode_val);
2089 } else {
2090 pr_debug("%s: CFILT Value is already %x\n",
2091 __func__, cur_mode_val);
2092 }
2093}
2094
2095static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
2096 u8 cfilt_sel, int inc)
2097{
2098 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2099 u32 *cfilt_cnt_ptr = NULL;
2100 u16 micb_cfilt_reg;
2101
2102 switch (cfilt_sel) {
2103 case TABLA_CFILT1_SEL:
2104 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2105 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2106 break;
2107 case TABLA_CFILT2_SEL:
2108 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2109 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2110 break;
2111 case TABLA_CFILT3_SEL:
2112 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2113 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2114 break;
2115 default:
2116 return; /* should not happen */
2117 }
2118
2119 if (inc) {
2120 if (!(*cfilt_cnt_ptr)++) {
2121 /* Switch CFILT to slow mode if MBHC CFILT being used */
2122 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2123 tabla_codec_switch_cfilt_mode(codec, 0);
2124
2125 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2126 }
2127 } else {
2128 /* check if count not zero, decrement
2129 * then check if zero, go ahead disable cfilter
2130 */
2131 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2132 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2133
2134 /* Switch CFILT to fast mode if MBHC CFILT being used */
2135 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2136 tabla_codec_switch_cfilt_mode(codec, 1);
2137 }
2138 }
2139}
2140
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002141static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2142{
2143 int rc = -EINVAL;
2144 unsigned min_mv, max_mv;
2145
2146 switch (ldoh_v) {
2147 case TABLA_LDOH_1P95_V:
2148 min_mv = 160;
2149 max_mv = 1800;
2150 break;
2151 case TABLA_LDOH_2P35_V:
2152 min_mv = 200;
2153 max_mv = 2200;
2154 break;
2155 case TABLA_LDOH_2P75_V:
2156 min_mv = 240;
2157 max_mv = 2600;
2158 break;
2159 case TABLA_LDOH_2P85_V:
2160 min_mv = 250;
2161 max_mv = 2700;
2162 break;
2163 default:
2164 goto done;
2165 }
2166
2167 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2168 goto done;
2169
2170 for (rc = 4; rc <= 44; rc++) {
2171 min_mv = max_mv * (rc) / 44;
2172 if (min_mv >= cfilt_mv) {
2173 rc -= 4;
2174 break;
2175 }
2176 }
2177done:
2178 return rc;
2179}
2180
2181static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2182{
2183 u8 hph_reg_val = 0;
2184 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2185
2186 return (hph_reg_val & 0x30) ? true : false;
2187}
2188
Joonwoo Parka9444452011-12-08 18:48:27 -08002189static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2190{
2191 u8 hph_reg_val = 0;
2192 if (left)
2193 hph_reg_val = snd_soc_read(codec,
2194 TABLA_A_RX_HPH_L_DAC_CTL);
2195 else
2196 hph_reg_val = snd_soc_read(codec,
2197 TABLA_A_RX_HPH_R_DAC_CTL);
2198
2199 return (hph_reg_val & 0xC0) ? true : false;
2200}
2201
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002202static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
2203{
2204 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
2205}
2206
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002207/* called under codec_resource_lock acquisition */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002208static void tabla_codec_drive_v_to_micbias(struct snd_soc_codec *codec,
2209 int usec)
2210{
2211 int cfilt_k_val;
2212 bool set = true;
2213 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2214
2215 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2216 tabla->mbhc_micbias_switched) {
2217 pr_debug("%s: set mic V to micbias V\n", __func__);
2218 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2219 tabla_turn_onoff_override(codec, true);
2220 while (1) {
2221 cfilt_k_val = tabla_find_k_value(
2222 tabla->pdata->micbias.ldoh_v,
2223 set ? tabla->mbhc_data.micb_mv :
2224 VDDIO_MICBIAS_MV);
2225 snd_soc_update_bits(codec,
2226 tabla->mbhc_bias_regs.cfilt_val,
2227 0xFC, (cfilt_k_val << 2));
2228 if (!set)
2229 break;
2230 usleep_range(usec, usec);
2231 set = false;
2232 }
2233 tabla_turn_onoff_override(codec, false);
2234 }
2235}
2236
2237/* called under codec_resource_lock acquisition */
2238static void __tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2239 int vddio_switch, bool restartpolling,
2240 bool checkpolling)
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002241{
2242 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2243 int cfilt_k_val;
2244
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002245 if (vddio_switch && !tabla->mbhc_micbias_switched &&
2246 (!checkpolling || tabla->mbhc_polling_active)) {
2247 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002248 tabla_codec_pause_hs_polling(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002249 tabla_turn_onoff_override(codec, true);
2250 /* Adjust threshold if Mic Bias voltage changes */
2251 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002252 cfilt_k_val = tabla_find_k_value(
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002253 tabla->pdata->micbias.ldoh_v,
2254 VDDIO_MICBIAS_MV);
2255 usleep_range(10000, 10000);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002256 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002257 tabla->mbhc_bias_regs.cfilt_val,
2258 0xFC, (cfilt_k_val << 2));
2259 usleep_range(10000, 10000);
2260 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2261 tabla->mbhc_data.adj_v_ins_hu & 0xFF);
2262 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2263 (tabla->mbhc_data.adj_v_ins_hu >> 8) &
2264 0xFF);
2265 pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
2266 __func__);
2267 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002268
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002269 /* enable MIC BIAS Switch to VDDIO */
2270 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2271 0x80, 0x80);
2272 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2273 0x10, 0x00);
2274 tabla_turn_onoff_override(codec, false);
2275 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002276 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002277
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002278 tabla->mbhc_micbias_switched = true;
2279 pr_debug("%s: VDDIO switch enabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002280
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002281 } else if (!vddio_switch && tabla->mbhc_micbias_switched) {
2282 if ((!checkpolling || tabla->mbhc_polling_active) &&
2283 restartpolling)
2284 tabla_codec_pause_hs_polling(codec);
2285 /* Reprogram thresholds */
2286 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
2287 cfilt_k_val = tabla_find_k_value(
2288 tabla->pdata->micbias.ldoh_v,
2289 tabla->mbhc_data.micb_mv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002290 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002291 tabla->mbhc_bias_regs.cfilt_val,
2292 0xFC, (cfilt_k_val << 2));
2293 usleep_range(10000, 10000);
2294 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2295 tabla->mbhc_data.v_ins_hu & 0xFF);
2296 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2297 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
2298 pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
2299 __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002300 }
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002301
2302 /* Disable MIC BIAS Switch to VDDIO */
2303 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2304 0x80, 0x00);
2305 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2306 0x10, 0x00);
2307
2308 if ((!checkpolling || tabla->mbhc_polling_active) &&
2309 restartpolling)
2310 tabla_codec_start_hs_polling(codec);
2311
2312 tabla->mbhc_micbias_switched = false;
2313 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002314 }
2315}
2316
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002317static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2318 int vddio_switch)
2319{
2320 return __tabla_codec_switch_micbias(codec, vddio_switch, true, true);
2321}
2322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002323static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2324 struct snd_kcontrol *kcontrol, int event)
2325{
2326 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002327 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2328 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002329 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002330 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002331 char *internal1_text = "Internal1";
2332 char *internal2_text = "Internal2";
2333 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002334
2335 pr_debug("%s %d\n", __func__, event);
2336 switch (w->reg) {
2337 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002338 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002339 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002340 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341 break;
2342 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002344 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002345 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002346 break;
2347 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002348 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002349 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002350 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002351 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002352 case TABLA_1_A_MICB_4_CTL:
2353 case TABLA_2_A_MICB_4_CTL:
2354 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002355 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002356 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002357 break;
2358 default:
2359 pr_err("%s: Error, invalid micbias register\n", __func__);
2360 return -EINVAL;
2361 }
2362
2363 switch (event) {
2364 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002365 /* Decide whether to switch the micbias for MBHC */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002366 if (w->reg == tabla->mbhc_bias_regs.ctl_reg) {
2367 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002368 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002369 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2370 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002371
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002372 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002373 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002374
2375 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002376 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002377 else if (strnstr(w->name, internal2_text, 30))
2378 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2379 else if (strnstr(w->name, internal3_text, 30))
2380 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2381
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002383 case SND_SOC_DAPM_POST_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002384
2385 usleep_range(20000, 20000);
2386
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002387 if (tabla->mbhc_polling_active &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002388 tabla->mbhc_cfg.micbias == micb_line) {
2389 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002390 tabla_codec_pause_hs_polling(codec);
2391 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002392 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002393 }
2394 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002395
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002396 case SND_SOC_DAPM_POST_PMD:
Joonwoo Park03324832012-03-19 19:36:16 -07002397 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg) &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002398 tabla_is_hph_pa_on(codec)) {
2399 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002400 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002401 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2402 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002403
Bradley Rubin229c6a52011-07-12 16:18:48 -07002404 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002405 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002406 else if (strnstr(w->name, internal2_text, 30))
2407 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2408 else if (strnstr(w->name, internal3_text, 30))
2409 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2410
Patrick Lai3043fba2011-08-01 14:15:57 -07002411 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002412 break;
2413 }
2414
2415 return 0;
2416}
2417
Kiran Kandid8cf5212012-03-02 15:34:53 -08002418
2419static void tx_hpf_corner_freq_callback(struct work_struct *work)
2420{
2421 struct delayed_work *hpf_delayed_work;
2422 struct hpf_work *hpf_work;
2423 struct tabla_priv *tabla;
2424 struct snd_soc_codec *codec;
2425 u16 tx_mux_ctl_reg;
2426 u8 hpf_cut_of_freq;
2427
2428 hpf_delayed_work = to_delayed_work(work);
2429 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2430 tabla = hpf_work->tabla;
2431 codec = hpf_work->tabla->codec;
2432 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2433
2434 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL +
2435 (hpf_work->decimator - 1) * 8;
2436
2437 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
2438 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2439
2440 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
2441}
2442
2443#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
2444#define CF_MIN_3DB_4HZ 0x0
2445#define CF_MIN_3DB_75HZ 0x1
2446#define CF_MIN_3DB_150HZ 0x2
2447
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002448static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
2449 struct snd_kcontrol *kcontrol, int event)
2450{
2451 struct snd_soc_codec *codec = w->codec;
Kiran Kandid8cf5212012-03-02 15:34:53 -08002452 unsigned int decimator;
2453 char *dec_name = NULL;
2454 char *widget_name = NULL;
2455 char *temp;
2456 int ret = 0;
2457 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2458 u8 dec_hpf_cut_of_freq;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002459 int offset;
2460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002461
2462 pr_debug("%s %d\n", __func__, event);
2463
Kiran Kandid8cf5212012-03-02 15:34:53 -08002464 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2465 if (!widget_name)
2466 return -ENOMEM;
2467 temp = widget_name;
2468
2469 dec_name = strsep(&widget_name, " ");
2470 widget_name = temp;
2471 if (!dec_name) {
2472 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2473 ret = -EINVAL;
2474 goto out;
2475 }
2476
2477 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
2478 if (ret < 0) {
2479 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2480 ret = -EINVAL;
2481 goto out;
2482 }
2483
2484 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
2485 w->name, dec_name, decimator);
2486
Kuirong Wange9c8a222012-03-28 16:24:09 -07002487 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002488 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002489 offset = 0;
2490 } else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002491 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002492 offset = 8;
2493 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002494 pr_err("%s: Error, incorrect dec\n", __func__);
2495 return -EINVAL;
2496 }
2497
Kiran Kandid8cf5212012-03-02 15:34:53 -08002498 tx_vol_ctl_reg = TABLA_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator -1);
2499 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002501 switch (event) {
2502 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002503
2504 // Enableable TX digital mute */
2505 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002507 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2508 1 << w->shift);
2509 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Kiran Kandid8cf5212012-03-02 15:34:53 -08002510
2511 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2512
2513 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
2514
2515 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2516 dec_hpf_cut_of_freq;
2517
2518 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2519
2520 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
2521 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2522 CF_MIN_3DB_150HZ << 4);
2523 }
2524
2525 /* enable HPF */
2526 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
2527
2528 break;
2529
2530 case SND_SOC_DAPM_POST_PMU:
2531
2532 /* Disable TX digital mute */
2533 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2534
2535 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2536 CF_MIN_3DB_150HZ) {
2537
2538 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2539 msecs_to_jiffies(300));
2540 }
Kuirong Wange9c8a222012-03-28 16:24:09 -07002541 /* apply the digital gain after the decimator is enabled*/
2542 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2543 snd_soc_write(codec,
2544 tx_digital_gain_reg[w->shift + offset],
2545 snd_soc_read(codec,
2546 tx_digital_gain_reg[w->shift + offset])
2547 );
2548
Kiran Kandid8cf5212012-03-02 15:34:53 -08002549 break;
2550
2551 case SND_SOC_DAPM_PRE_PMD:
2552
2553 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2554 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2555 break;
2556
2557 case SND_SOC_DAPM_POST_PMD:
2558
2559 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2560 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2561 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2562
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002563 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002564 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08002565out:
2566 kfree(widget_name);
2567 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002568}
2569
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002570static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002571 struct snd_kcontrol *kcontrol, int event)
2572{
2573 struct snd_soc_codec *codec = w->codec;
2574
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002575 pr_debug("%s %d %s\n", __func__, event, w->name);
2576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002577 switch (event) {
2578 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002579 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2580 1 << w->shift, 1 << w->shift);
2581 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2582 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002583 break;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002584 case SND_SOC_DAPM_POST_PMU:
2585 /* apply the digital gain after the interpolator is enabled*/
2586 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2587 snd_soc_write(codec,
2588 rx_digital_gain_reg[w->shift],
2589 snd_soc_read(codec,
2590 rx_digital_gain_reg[w->shift])
2591 );
2592 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002593 }
2594 return 0;
2595}
2596
Bradley Rubin229c6a52011-07-12 16:18:48 -07002597static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2598 struct snd_kcontrol *kcontrol, int event)
2599{
2600 switch (event) {
2601 case SND_SOC_DAPM_POST_PMU:
2602 case SND_SOC_DAPM_POST_PMD:
2603 usleep_range(1000, 1000);
2604 break;
2605 }
2606 return 0;
2607}
2608
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002609static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2610 struct snd_kcontrol *kcontrol, int event)
2611{
2612 struct snd_soc_codec *codec = w->codec;
2613
2614 pr_debug("%s %d\n", __func__, event);
2615
2616 switch (event) {
2617 case SND_SOC_DAPM_PRE_PMU:
2618 tabla_enable_rx_bias(codec, 1);
2619 break;
2620 case SND_SOC_DAPM_POST_PMD:
2621 tabla_enable_rx_bias(codec, 0);
2622 break;
2623 }
2624 return 0;
2625}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002626static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
2627 struct snd_kcontrol *kcontrol, int event)
2628{
2629 struct snd_soc_codec *codec = w->codec;
2630
2631 pr_debug("%s %s %d\n", __func__, w->name, event);
2632
2633 switch (event) {
2634 case SND_SOC_DAPM_PRE_PMU:
2635 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2636 break;
2637 case SND_SOC_DAPM_POST_PMD:
2638 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2639 break;
2640 }
2641 return 0;
2642}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002643
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002644static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
2645 struct snd_soc_jack *jack, int status,
2646 int mask)
2647{
2648 /* XXX: wake_lock_timeout()? */
Joonwoo Park03324832012-03-19 19:36:16 -07002649 snd_soc_jack_report_no_dapm(jack, status, mask);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002650}
2651
Patrick Lai49efeac2011-11-03 11:01:12 -07002652static void hphocp_off_report(struct tabla_priv *tabla,
2653 u32 jack_status, int irq)
2654{
2655 struct snd_soc_codec *codec;
Joonwoo Park03324832012-03-19 19:36:16 -07002656 if (!tabla) {
2657 pr_err("%s: Bad tabla private data\n", __func__);
2658 return;
2659 }
Patrick Lai49efeac2011-11-03 11:01:12 -07002660
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002661 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
Joonwoo Park03324832012-03-19 19:36:16 -07002662 codec = tabla->codec;
2663 if (tabla->hph_status & jack_status) {
Patrick Lai49efeac2011-11-03 11:01:12 -07002664 tabla->hph_status &= ~jack_status;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002665 if (tabla->mbhc_cfg.headset_jack)
2666 tabla_snd_soc_jack_report(tabla,
2667 tabla->mbhc_cfg.headset_jack,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002668 tabla->hph_status,
2669 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08002670 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2671 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08002672 /* reset retry counter as PA is turned off signifying
2673 * start of new OCP detection session
2674 */
2675 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
2676 tabla->hphlocp_cnt = 0;
2677 else
2678 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302679 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07002680 }
2681}
2682
2683static void hphlocp_off_report(struct work_struct *work)
2684{
2685 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2686 hphlocp_work);
2687 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
2688}
2689
2690static void hphrocp_off_report(struct work_struct *work)
2691{
2692 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2693 hphrocp_work);
2694 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
2695}
2696
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002697static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
2698 struct snd_kcontrol *kcontrol, int event)
2699{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002700 struct snd_soc_codec *codec = w->codec;
2701 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2702 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002703 pr_debug("%s: event = %d\n", __func__, event);
2704
2705 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002706 case SND_SOC_DAPM_PRE_PMU:
2707 mbhc_micb_ctl_val = snd_soc_read(codec,
2708 tabla->mbhc_bias_regs.ctl_reg);
2709
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002710 if (!(mbhc_micb_ctl_val & 0x80)) {
2711 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002712 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002713 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2714 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002715 break;
2716
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002717 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07002718 /* schedule work is required because at the time HPH PA DAPM
2719 * event callback is called by DAPM framework, CODEC dapm mutex
2720 * would have been locked while snd_soc_jack_report also
2721 * attempts to acquire same lock.
2722 */
Joonwoo Parka9444452011-12-08 18:48:27 -08002723 if (w->shift == 5) {
2724 clear_bit(TABLA_HPHL_PA_OFF_ACK,
2725 &tabla->hph_pa_dac_state);
2726 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
2727 &tabla->hph_pa_dac_state);
2728 if (tabla->hph_status & SND_JACK_OC_HPHL)
2729 schedule_work(&tabla->hphlocp_work);
2730 } else if (w->shift == 4) {
2731 clear_bit(TABLA_HPHR_PA_OFF_ACK,
2732 &tabla->hph_pa_dac_state);
2733 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
2734 &tabla->hph_pa_dac_state);
2735 if (tabla->hph_status & SND_JACK_OC_HPHR)
2736 schedule_work(&tabla->hphrocp_work);
2737 }
2738
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002739 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park03324832012-03-19 19:36:16 -07002740 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002741 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002742
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002743 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
2744 w->name);
2745 usleep_range(10000, 10000);
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002746 break;
2747 }
2748 return 0;
2749}
2750
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002751static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002752 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002753{
2754 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002755 unsigned int cfilt;
2756
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002757 switch (tabla->mbhc_cfg.micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002758 case TABLA_MICBIAS1:
2759 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
2760 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
2761 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
2762 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
2763 break;
2764 case TABLA_MICBIAS2:
2765 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
2766 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
2767 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
2768 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
2769 break;
2770 case TABLA_MICBIAS3:
2771 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
2772 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
2773 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
2774 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
2775 break;
2776 case TABLA_MICBIAS4:
2777 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002778 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
2779 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
2780 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002781 break;
2782 default:
2783 /* Should never reach here */
2784 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07002785 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002786 }
2787
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002788 micbias_regs->cfilt_sel = cfilt;
2789
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002790 switch (cfilt) {
2791 case TABLA_CFILT1_SEL:
2792 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
2793 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002794 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002795 break;
2796 case TABLA_CFILT2_SEL:
2797 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
2798 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002799 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002800 break;
2801 case TABLA_CFILT3_SEL:
2802 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
2803 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002804 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002805 break;
2806 }
2807}
Santosh Mardie15e2302011-11-15 10:39:23 +05302808static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
2809 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
2810 4, 0, NULL, 0),
2811 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
2812 0, NULL, 0),
2813};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002814
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002815static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
2816 struct snd_kcontrol *kcontrol, int event)
2817{
2818 struct snd_soc_codec *codec = w->codec;
2819
2820 pr_debug("%s %s %d\n", __func__, w->name, event);
2821
2822 switch (event) {
2823 case SND_SOC_DAPM_PRE_PMU:
2824 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2825 break;
2826
2827 case SND_SOC_DAPM_POST_PMD:
2828 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2829 break;
2830 }
2831 return 0;
2832}
2833
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002834static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
2835 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302836 0, tabla_codec_enable_micbias,
2837 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2838 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002839};
2840
2841static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
2842 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302843 0, tabla_codec_enable_micbias,
2844 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2845 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002846};
2847
Santosh Mardie15e2302011-11-15 10:39:23 +05302848static const struct snd_soc_dapm_route audio_i2s_map[] = {
2849 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2850 {"SLIM RX1", NULL, "RX_I2S_CLK"},
2851 {"SLIM RX2", NULL, "RX_I2S_CLK"},
2852 {"SLIM RX3", NULL, "RX_I2S_CLK"},
2853 {"SLIM RX4", NULL, "RX_I2S_CLK"},
2854
2855 {"SLIM TX7", NULL, "TX_I2S_CLK"},
2856 {"SLIM TX8", NULL, "TX_I2S_CLK"},
2857 {"SLIM TX9", NULL, "TX_I2S_CLK"},
2858 {"SLIM TX10", NULL, "TX_I2S_CLK"},
2859};
2860
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002861static const struct snd_soc_dapm_route audio_map[] = {
2862 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002863
2864 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
2865 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2866
2867 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
2868 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
2869
2870 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
2871 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
2872
2873 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
2874 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002875 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002876 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
2877 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002878 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
2879 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07002880 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
2881 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002882 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
2883 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002884
2885 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002886 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
2887 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
2888 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07002889 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002890 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
2891 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
2892
Kiran Kandi3426e512011-09-13 22:50:10 -07002893 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
2894 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
2895 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
2896 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
2897 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
2898 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
2899 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
2900 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
2901 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
2902 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
2903 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
2904
2905 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
2906 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
2907 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
2908 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
2909 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
2910 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
2911 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
2912 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
2913 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
2914 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
2915 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
2916
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002917 /* Earpiece (RX MIX1) */
2918 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002919 {"EAR PA", NULL, "EAR_PA_MIXER"},
2920 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002921 {"DAC1", NULL, "CP"},
2922
2923 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX1"},
2924 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX1"},
2925 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002926
2927 /* Headset (RX MIX1 and RX MIX2) */
2928 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002929 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002930
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002931 {"HPHL", NULL, "HPHL_PA_MIXER"},
2932 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
2933
2934 {"HPHR", NULL, "HPHR_PA_MIXER"},
2935 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07002936
2937 {"HPHL DAC", NULL, "CP"},
2938 {"HPHR DAC", NULL, "CP"},
2939
2940 {"ANC", NULL, "ANC1 MUX"},
2941 {"ANC", NULL, "ANC2 MUX"},
2942 {"ANC1 MUX", "ADC1", "ADC1"},
2943 {"ANC1 MUX", "ADC2", "ADC2"},
2944 {"ANC1 MUX", "ADC3", "ADC3"},
2945 {"ANC1 MUX", "ADC4", "ADC4"},
2946 {"ANC2 MUX", "ADC1", "ADC1"},
2947 {"ANC2 MUX", "ADC2", "ADC2"},
2948 {"ANC2 MUX", "ADC3", "ADC3"},
2949 {"ANC2 MUX", "ADC4", "ADC4"},
2950
Bradley Rubine1d08622011-07-20 18:01:35 -07002951 {"ANC", NULL, "CDC_CONN"},
2952
Bradley Rubin229c6a52011-07-12 16:18:48 -07002953 {"DAC1", "Switch", "RX1 CHAIN"},
2954 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002955 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002956
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002957 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2958 {"LINEOUT2", NULL, "LINEOUT2 PA"},
2959 {"LINEOUT3", NULL, "LINEOUT3 PA"},
2960 {"LINEOUT4", NULL, "LINEOUT4 PA"},
2961 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002962
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002963 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2964 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
2965 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2966 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2967 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
2968 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
2969 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
2970 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
2971 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
2972 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002973
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002974 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2975 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
2976
Bradley Rubin229c6a52011-07-12 16:18:48 -07002977 {"RX1 CHAIN", NULL, "RX1 MIX1"},
2978 {"RX2 CHAIN", NULL, "RX2 MIX1"},
2979 {"RX1 CHAIN", NULL, "ANC"},
2980 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002981
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002982 {"CP", NULL, "RX_BIAS"},
2983 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2984 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
2985 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
2986 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002987 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002988
Kuirong Wang0f8ade32012-02-27 16:29:45 -08002989 {"RX1 MIX1", NULL, "COMP1_CLK"},
2990 {"RX2 MIX1", NULL, "COMP1_CLK"},
2991 {"RX3 MIX1", NULL, "COMP2_CLK"},
2992 {"RX5 MIX1", NULL, "COMP2_CLK"},
2993
2994
Bradley Rubin229c6a52011-07-12 16:18:48 -07002995 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2996 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2997 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2998 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002999 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
3000 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
3001 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
3002 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
3003 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
3004 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
3005 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
3006 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003007 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
3008 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003009
Bradley Rubin229c6a52011-07-12 16:18:48 -07003010 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
3011 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303012 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
3013 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003014 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
3015 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003016 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
3017 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
3018 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303019 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
3020 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003021 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
3022 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003023 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
3024 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
3025 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303026 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
3027 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003028 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
3029 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003030 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003031 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
3032 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303033 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
3034 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003035 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
3036 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003037 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003038 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
3039 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303040 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
3041 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003042 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
3043 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003044 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003045 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
3046 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303047 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
3048 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003049 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
3050 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003051 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003052 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
3053 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303054 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
3055 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003056 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
3057 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003058 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003059 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
3060 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303061 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
3062 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003063 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
3064 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003065 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003066 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
3067 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303068 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
3069 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003070 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
3071 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003072 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003073 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
3074 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303075 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
3076 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003077 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
3078 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003079 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003080 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
3081 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303082 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
3083 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003084 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
3085 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003086 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003087 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
3088 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303089 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
3090 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003091 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
3092 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003093 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003094 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
3095 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303096 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
3097 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003098 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
3099 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003100 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003101 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
3102 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303103 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
3104 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003105 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
3106 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003107 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003108
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003109 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003110 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003111 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003112 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003113 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003114 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003115 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003116 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003117 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003118 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003119 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003120 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003121 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003122 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003123 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003124 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003125 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003126 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003127 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003128 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003129 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003130 {"DEC7 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003131 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003132 {"DEC8 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003133 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003134 {"DEC9 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003135 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003136 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003137
3138 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003139 {"ADC1", NULL, "AMIC1"},
3140 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003141 {"ADC3", NULL, "AMIC3"},
3142 {"ADC4", NULL, "AMIC4"},
3143 {"ADC5", NULL, "AMIC5"},
3144 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003145
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003146 /* AUX PGA Connections */
3147 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3148 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3149 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3150 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3151 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3152 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3153 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3154 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3155 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3156 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3157 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3158 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3159 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3160 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3161 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3162 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3163 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3164 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3165 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3166 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3167 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3168 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3169 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3170 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3171 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3172 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3173 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3174 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3175 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3176 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3177 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3178 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3179 {"AUX_PGA_Left", NULL, "AMIC5"},
3180 {"AUX_PGA_Right", NULL, "AMIC6"},
3181
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003182 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003183 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
3184 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
3185 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
3186 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
3187 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003188 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003189 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
3190 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
3191 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
3192 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003193
3194 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
3195 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
3196 {"MIC BIAS1 External", NULL, "LDO_H"},
3197 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
3198 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
3199 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
3200 {"MIC BIAS2 External", NULL, "LDO_H"},
3201 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
3202 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
3203 {"MIC BIAS3 External", NULL, "LDO_H"},
3204 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003205};
3206
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003207static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
3208
3209 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
3210 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3211
3212 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
3213
3214 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
3215 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX1"},
3216 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
3217
3218 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3219 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3220
3221 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3222 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
3223 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
3224};
3225
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003226
3227static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
3228
3229 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX1"},
3230 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3231
3232 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
3233
3234 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
3235
3236 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3237 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3238
3239 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3240};
3241
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003242static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
3243{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003244 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303245 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003246
3247 if (TABLA_IS_1_X(tabla_core->version)) {
3248 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
3249 if (tabla_1_reg_readable[i] == reg)
3250 return 1;
3251 }
3252 } else {
3253 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
3254 if (tabla_2_reg_readable[i] == reg)
3255 return 1;
3256 }
3257 }
3258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003259 return tabla_reg_readable[reg];
3260}
Kuirong Wange9c8a222012-03-28 16:24:09 -07003261static bool tabla_is_digital_gain_register(unsigned int reg)
3262{
3263 bool rtn = false;
3264 switch (reg) {
3265 case TABLA_A_CDC_RX1_VOL_CTL_B2_CTL:
3266 case TABLA_A_CDC_RX2_VOL_CTL_B2_CTL:
3267 case TABLA_A_CDC_RX3_VOL_CTL_B2_CTL:
3268 case TABLA_A_CDC_RX4_VOL_CTL_B2_CTL:
3269 case TABLA_A_CDC_RX5_VOL_CTL_B2_CTL:
3270 case TABLA_A_CDC_RX6_VOL_CTL_B2_CTL:
3271 case TABLA_A_CDC_RX7_VOL_CTL_B2_CTL:
3272 case TABLA_A_CDC_TX1_VOL_CTL_GAIN:
3273 case TABLA_A_CDC_TX2_VOL_CTL_GAIN:
3274 case TABLA_A_CDC_TX3_VOL_CTL_GAIN:
3275 case TABLA_A_CDC_TX4_VOL_CTL_GAIN:
3276 case TABLA_A_CDC_TX5_VOL_CTL_GAIN:
3277 case TABLA_A_CDC_TX6_VOL_CTL_GAIN:
3278 case TABLA_A_CDC_TX7_VOL_CTL_GAIN:
3279 case TABLA_A_CDC_TX8_VOL_CTL_GAIN:
3280 case TABLA_A_CDC_TX9_VOL_CTL_GAIN:
3281 case TABLA_A_CDC_TX10_VOL_CTL_GAIN:
3282 rtn = true;
3283 break;
3284 default:
3285 break;
3286 }
3287 return rtn;
3288}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003289static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3290{
3291 /* Registers lower than 0x100 are top level registers which can be
3292 * written by the Tabla core driver.
3293 */
3294
3295 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3296 return 1;
3297
Ben Romberger1f045a72011-11-04 10:14:57 -07003298 /* IIR Coeff registers are not cacheable */
3299 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
3300 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
3301 return 1;
3302
Kuirong Wange9c8a222012-03-28 16:24:09 -07003303 /* Digital gain register is not cacheable so we have to write
3304 * the setting even it is the same
3305 */
3306 if (tabla_is_digital_gain_register(reg))
3307 return 1;
3308
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003309 return 0;
3310}
3311
3312#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3313static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
3314 unsigned int value)
3315{
3316 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003317 BUG_ON(reg > TABLA_MAX_REGISTER);
3318
3319 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003320 ret = snd_soc_cache_write(codec, reg, value);
3321 if (ret != 0)
3322 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3323 reg, ret);
3324 }
3325
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303326 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003327}
3328static unsigned int tabla_read(struct snd_soc_codec *codec,
3329 unsigned int reg)
3330{
3331 unsigned int val;
3332 int ret;
3333
3334 BUG_ON(reg > TABLA_MAX_REGISTER);
3335
3336 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
3337 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003338 ret = snd_soc_cache_read(codec, reg, &val);
3339 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003340 return val;
3341 } else
3342 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3343 reg, ret);
3344 }
3345
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303346 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003347 return val;
3348}
3349
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003350static s16 tabla_get_current_v_ins(struct tabla_priv *tabla, bool hu)
3351{
3352 s16 v_ins;
3353 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3354 tabla->mbhc_micbias_switched)
3355 v_ins = hu ? (s16)tabla->mbhc_data.adj_v_ins_hu :
3356 (s16)tabla->mbhc_data.adj_v_ins_h;
3357 else
3358 v_ins = hu ? (s16)tabla->mbhc_data.v_ins_hu :
3359 (s16)tabla->mbhc_data.v_ins_h;
3360 return v_ins;
3361}
3362
3363static s16 tabla_get_current_v_hs_max(struct tabla_priv *tabla)
3364{
3365 s16 v_hs_max;
3366 struct tabla_mbhc_plug_type_cfg *plug_type;
3367
3368 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
3369 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3370 tabla->mbhc_micbias_switched)
3371 v_hs_max = tabla->mbhc_data.adj_v_hs_max;
3372 else
3373 v_hs_max = plug_type->v_hs_max;
3374 return v_hs_max;
3375}
3376
Bradley Rubincb1e2732011-06-23 16:49:20 -07003377static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3378{
Joonwoo Parkc0672392012-01-11 11:03:14 -08003379 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08003380 struct tabla_mbhc_btn_detect_cfg *btn_det;
3381 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003382 const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
3383
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003384 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003385
Joonwoo Park0976d012011-12-22 11:48:18 -08003386 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003387 v_ins_hu & 0xFF);
Joonwoo Park0976d012011-12-22 11:48:18 -08003388 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003389 (v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003390
Joonwoo Park0976d012011-12-22 11:48:18 -08003391 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
3392 tabla->mbhc_data.v_b1_hu & 0xFF);
3393 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
3394 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
3395
3396 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
3397 tabla->mbhc_data.v_b1_h & 0xFF);
3398 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
3399 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
3400
3401 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
3402 tabla->mbhc_data.v_brh & 0xFF);
3403 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
3404 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
3405
3406 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
3407 tabla->mbhc_data.v_brl & 0xFF);
3408 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
3409 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
3410
Joonwoo Parkc0672392012-01-11 11:03:14 -08003411 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003412 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08003413 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003414 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
3415 tabla->mbhc_data.npoll);
3416 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
3417 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08003418 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003419 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
3420 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003421}
3422
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003423static int tabla_startup(struct snd_pcm_substream *substream,
3424 struct snd_soc_dai *dai)
3425{
Kuirong Wanga545e722012-02-06 19:12:54 -08003426 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003427 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3428 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003429 if ((tabla_core != NULL) &&
3430 (tabla_core->dev != NULL) &&
3431 (tabla_core->dev->parent != NULL))
3432 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003433
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003434 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003435}
3436
3437static void tabla_shutdown(struct snd_pcm_substream *substream,
3438 struct snd_soc_dai *dai)
3439{
Kuirong Wanga545e722012-02-06 19:12:54 -08003440 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003441 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3442 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003443 if ((tabla_core != NULL) &&
3444 (tabla_core->dev != NULL) &&
3445 (tabla_core->dev->parent != NULL)) {
3446 pm_runtime_mark_last_busy(tabla_core->dev->parent);
3447 pm_runtime_put(tabla_core->dev->parent);
3448 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003449}
3450
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003451int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003452{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003453 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3454
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003455 pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
3456 dapm);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003457 if (dapm)
3458 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003459 if (mclk_enable) {
3460 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003461
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003462 if (tabla->mbhc_polling_active && (tabla->mclk_enabled)) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07003463 tabla_codec_pause_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003464 tabla_codec_enable_bandgap(codec,
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003465 TABLA_BANDGAP_AUDIO_MODE);
3466 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003467 tabla_codec_calibrate_hs_polling(codec);
3468 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303469 } else {
3470 tabla_codec_enable_bandgap(codec,
3471 TABLA_BANDGAP_AUDIO_MODE);
3472 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003473 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003474 } else {
3475
3476 if (!tabla->mclk_enabled) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003477 if (dapm)
3478 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003479 pr_err("Error, MCLK already diabled\n");
3480 return -EINVAL;
3481 }
3482 tabla->mclk_enabled = false;
3483
3484 if (tabla->mbhc_polling_active) {
3485 if (!tabla->mclk_enabled) {
3486 tabla_codec_pause_hs_polling(codec);
3487 tabla_codec_enable_bandgap(codec,
3488 TABLA_BANDGAP_MBHC_MODE);
3489 tabla_enable_rx_bias(codec, 1);
3490 tabla_codec_enable_clock_block(codec, 1);
3491 tabla_codec_calibrate_hs_polling(codec);
3492 tabla_codec_start_hs_polling(codec);
3493 }
3494 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
3495 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303496 } else {
3497 tabla_codec_disable_clock_block(codec);
3498 tabla_codec_enable_bandgap(codec,
3499 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003500 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003501 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003502 if (dapm)
3503 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003504 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003505}
3506
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003507static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
3508 int clk_id, unsigned int freq, int dir)
3509{
3510 pr_debug("%s\n", __func__);
3511 return 0;
3512}
3513
3514static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3515{
Santosh Mardie15e2302011-11-15 10:39:23 +05303516 u8 val = 0;
3517 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003519 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05303520 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3521 case SND_SOC_DAIFMT_CBS_CFS:
3522 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303523 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003524 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303525 snd_soc_update_bits(dai->codec,
3526 TABLA_A_CDC_CLK_TX_I2S_CTL,
3527 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003528 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303529 snd_soc_update_bits(dai->codec,
3530 TABLA_A_CDC_CLK_RX_I2S_CTL,
3531 TABLA_I2S_MASTER_MODE_MASK, 0);
3532 }
3533 break;
3534 case SND_SOC_DAIFMT_CBM_CFM:
3535 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303536 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303537 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003538 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303539 snd_soc_update_bits(dai->codec,
3540 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003541 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303542 snd_soc_update_bits(dai->codec,
3543 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
3544 }
3545 break;
3546 default:
3547 return -EINVAL;
3548 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003549 return 0;
3550}
3551
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003552static int tabla_set_channel_map(struct snd_soc_dai *dai,
3553 unsigned int tx_num, unsigned int *tx_slot,
3554 unsigned int rx_num, unsigned int *rx_slot)
3555
3556{
3557 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3558 u32 i = 0;
3559 if (!tx_slot && !rx_slot) {
3560 pr_err("%s: Invalid\n", __func__);
3561 return -EINVAL;
3562 }
3563 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3564
Neema Shettyd3a89262012-02-16 10:23:50 -08003565 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003566 for (i = 0; i < rx_num; i++) {
3567 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
3568 tabla->dai[dai->id - 1].ch_act = 0;
3569 tabla->dai[dai->id - 1].ch_tot = rx_num;
3570 }
3571 } else if (dai->id == AIF1_CAP) {
3572 for (i = 0; i < tx_num; i++) {
3573 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
3574 tabla->dai[dai->id - 1].ch_act = 0;
3575 tabla->dai[dai->id - 1].ch_tot = tx_num;
3576 }
3577 }
3578 return 0;
3579}
3580
3581static int tabla_get_channel_map(struct snd_soc_dai *dai,
3582 unsigned int *tx_num, unsigned int *tx_slot,
3583 unsigned int *rx_num, unsigned int *rx_slot)
3584
3585{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303586 struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003587
3588 u32 cnt = 0;
3589 u32 tx_ch[SLIM_MAX_TX_PORTS];
3590 u32 rx_ch[SLIM_MAX_RX_PORTS];
3591
3592 if (!rx_slot && !tx_slot) {
3593 pr_err("%s: Invalid\n", __func__);
3594 return -EINVAL;
3595 }
3596 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
3597 /* for virtual port, codec driver needs to do
3598 * housekeeping, for now should be ok
3599 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303600 wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003601 if (dai->id == AIF1_PB) {
3602 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3603 while (cnt < *rx_num) {
3604 rx_slot[cnt] = rx_ch[cnt];
3605 cnt++;
3606 }
3607 } else if (dai->id == AIF1_CAP) {
3608 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3609 while (cnt < *tx_num) {
3610 tx_slot[cnt] = tx_ch[6 + cnt];
3611 cnt++;
3612 }
Neema Shettyd3a89262012-02-16 10:23:50 -08003613 } else if (dai->id == AIF2_PB) {
3614 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3615 while (cnt < *rx_num) {
3616 rx_slot[cnt] = rx_ch[5 + cnt];
3617 cnt++;
3618 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003619 }
3620 return 0;
3621}
3622
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003623static int tabla_hw_params(struct snd_pcm_substream *substream,
3624 struct snd_pcm_hw_params *params,
3625 struct snd_soc_dai *dai)
3626{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003627 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05303628 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07003629 u8 path, shift;
3630 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003631 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003632 u32 compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003633
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003634 pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
3635 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003636
3637 switch (params_rate(params)) {
3638 case 8000:
3639 tx_fs_rate = 0x00;
3640 rx_fs_rate = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003641 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003642 break;
3643 case 16000:
3644 tx_fs_rate = 0x01;
3645 rx_fs_rate = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003646 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003647 break;
3648 case 32000:
3649 tx_fs_rate = 0x02;
3650 rx_fs_rate = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003651 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003652 break;
3653 case 48000:
3654 tx_fs_rate = 0x03;
3655 rx_fs_rate = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003656 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003657 break;
3658 default:
3659 pr_err("%s: Invalid sampling rate %d\n", __func__,
3660 params_rate(params));
3661 return -EINVAL;
3662 }
3663
3664
3665 /**
3666 * If current dai is a tx dai, set sample rate to
3667 * all the txfe paths that are currently not active
3668 */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003669 if (dai->id == AIF1_CAP) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003670
3671 tx_state = snd_soc_read(codec,
3672 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3673
3674 for (path = 1, shift = 0;
3675 path <= NUM_DECIMATORS; path++, shift++) {
3676
3677 if (path == BITS_PER_REG + 1) {
3678 shift = 0;
3679 tx_state = snd_soc_read(codec,
3680 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
3681 }
3682
3683 if (!(tx_state & (1 << shift))) {
3684 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
3685 + (BITS_PER_REG*(path-1));
3686 snd_soc_update_bits(codec, tx_fs_reg,
3687 0x03, tx_fs_rate);
3688 }
3689 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303690 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303691 switch (params_format(params)) {
3692 case SNDRV_PCM_FORMAT_S16_LE:
3693 snd_soc_update_bits(codec,
3694 TABLA_A_CDC_CLK_TX_I2S_CTL,
3695 0x20, 0x20);
3696 break;
3697 case SNDRV_PCM_FORMAT_S32_LE:
3698 snd_soc_update_bits(codec,
3699 TABLA_A_CDC_CLK_TX_I2S_CTL,
3700 0x20, 0x00);
3701 break;
3702 default:
3703 pr_err("invalid format\n");
3704 break;
3705 }
3706 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
3707 0x03, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003708 } else {
3709 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303710 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003711 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003712 /**
3713 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3714 * with varying sample rates
3715 */
3716
3717 /**
3718 * If current dai is a rx dai, set sample rate to
3719 * all the rx paths that are currently not active
3720 */
Neema Shettyd3a89262012-02-16 10:23:50 -08003721 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003722
3723 rx_state = snd_soc_read(codec,
3724 TABLA_A_CDC_CLK_RX_B1_CTL);
3725
3726 for (path = 1, shift = 0;
3727 path <= NUM_INTERPOLATORS; path++, shift++) {
3728
3729 if (!(rx_state & (1 << shift))) {
3730 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
3731 + (BITS_PER_REG*(path-1));
3732 snd_soc_update_bits(codec, rx_fs_reg,
3733 0xE0, rx_fs_rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003734 if (comp_rx_path[shift] < COMPANDER_MAX)
3735 tabla->comp_fs[comp_rx_path[shift]]
3736 = compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003737 }
3738 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303739 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303740 switch (params_format(params)) {
3741 case SNDRV_PCM_FORMAT_S16_LE:
3742 snd_soc_update_bits(codec,
3743 TABLA_A_CDC_CLK_RX_I2S_CTL,
3744 0x20, 0x20);
3745 break;
3746 case SNDRV_PCM_FORMAT_S32_LE:
3747 snd_soc_update_bits(codec,
3748 TABLA_A_CDC_CLK_RX_I2S_CTL,
3749 0x20, 0x00);
3750 break;
3751 default:
3752 pr_err("invalid format\n");
3753 break;
3754 }
3755 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
3756 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003757 } else {
3758 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303759 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003760 }
3761
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003762 return 0;
3763}
3764
3765static struct snd_soc_dai_ops tabla_dai_ops = {
3766 .startup = tabla_startup,
3767 .shutdown = tabla_shutdown,
3768 .hw_params = tabla_hw_params,
3769 .set_sysclk = tabla_set_dai_sysclk,
3770 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003771 .set_channel_map = tabla_set_channel_map,
3772 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003773};
3774
3775static struct snd_soc_dai_driver tabla_dai[] = {
3776 {
3777 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003778 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003779 .playback = {
3780 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003781 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003782 .formats = TABLA_FORMATS,
3783 .rate_max = 48000,
3784 .rate_min = 8000,
3785 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003786 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003787 },
3788 .ops = &tabla_dai_ops,
3789 },
3790 {
3791 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003792 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003793 .capture = {
3794 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003795 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003796 .formats = TABLA_FORMATS,
3797 .rate_max = 48000,
3798 .rate_min = 8000,
3799 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003800 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003801 },
3802 .ops = &tabla_dai_ops,
3803 },
Neema Shettyd3a89262012-02-16 10:23:50 -08003804 {
3805 .name = "tabla_rx2",
3806 .id = AIF2_PB,
3807 .playback = {
3808 .stream_name = "AIF2 Playback",
3809 .rates = WCD9310_RATES,
3810 .formats = TABLA_FORMATS,
3811 .rate_min = 8000,
3812 .rate_max = 48000,
3813 .channels_min = 1,
3814 .channels_max = 2,
3815 },
3816 .ops = &tabla_dai_ops,
3817 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003818};
Santosh Mardie15e2302011-11-15 10:39:23 +05303819
3820static struct snd_soc_dai_driver tabla_i2s_dai[] = {
3821 {
3822 .name = "tabla_i2s_rx1",
3823 .id = 1,
3824 .playback = {
3825 .stream_name = "AIF1 Playback",
3826 .rates = WCD9310_RATES,
3827 .formats = TABLA_FORMATS,
3828 .rate_max = 48000,
3829 .rate_min = 8000,
3830 .channels_min = 1,
3831 .channels_max = 4,
3832 },
3833 .ops = &tabla_dai_ops,
3834 },
3835 {
3836 .name = "tabla_i2s_tx1",
3837 .id = 2,
3838 .capture = {
3839 .stream_name = "AIF1 Capture",
3840 .rates = WCD9310_RATES,
3841 .formats = TABLA_FORMATS,
3842 .rate_max = 48000,
3843 .rate_min = 8000,
3844 .channels_min = 1,
3845 .channels_max = 4,
3846 },
3847 .ops = &tabla_dai_ops,
3848 },
3849};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003850
3851static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3852 struct snd_kcontrol *kcontrol, int event)
3853{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303854 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003855 struct snd_soc_codec *codec = w->codec;
3856 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3857 u32 j = 0;
3858 u32 ret = 0;
3859 codec->control_data = dev_get_drvdata(codec->dev->parent);
3860 tabla = codec->control_data;
3861 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303862 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003863 return 0;
3864 switch (event) {
3865 case SND_SOC_DAPM_POST_PMU:
3866 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3867 if (tabla_dai[j].id == AIF1_CAP)
3868 continue;
3869 if (!strncmp(w->sname,
3870 tabla_dai[j].playback.stream_name, 13)) {
3871 ++tabla_p->dai[j].ch_act;
3872 break;
3873 }
3874 }
3875 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303876 ret = wcd9xxx_cfg_slim_sch_rx(tabla,
3877 tabla_p->dai[j].ch_num,
3878 tabla_p->dai[j].ch_tot,
3879 tabla_p->dai[j].rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003880 break;
3881 case SND_SOC_DAPM_POST_PMD:
3882 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
3883 if (tabla_dai[j].id == AIF1_CAP)
3884 continue;
3885 if (!strncmp(w->sname,
3886 tabla_dai[j].playback.stream_name, 13)) {
3887 --tabla_p->dai[j].ch_act;
3888 break;
3889 }
3890 }
3891 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303892 ret = wcd9xxx_close_slim_sch_rx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003893 tabla_p->dai[j].ch_num,
3894 tabla_p->dai[j].ch_tot);
Bharath Ramachandramurthyda6fa7a2012-03-30 14:35:32 -07003895 usleep_range(5000, 5000);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003896 tabla_p->dai[j].rate = 0;
3897 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303898 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003899 tabla_p->dai[j].ch_tot = 0;
3900 }
3901 }
3902 return ret;
3903}
3904
3905static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3906 struct snd_kcontrol *kcontrol, int event)
3907{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303908 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003909 struct snd_soc_codec *codec = w->codec;
3910 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
3911 /* index to the DAI ID, for now hardcoding */
3912 u32 j = 0;
3913 u32 ret = 0;
3914
3915 codec->control_data = dev_get_drvdata(codec->dev->parent);
3916 tabla = codec->control_data;
3917
3918 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303919 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003920 return 0;
3921 switch (event) {
3922 case SND_SOC_DAPM_POST_PMU:
3923 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003924 if (tabla_dai[j].id == AIF1_PB ||
3925 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003926 continue;
3927 if (!strncmp(w->sname,
3928 tabla_dai[j].capture.stream_name, 13)) {
3929 ++tabla_p->dai[j].ch_act;
3930 break;
3931 }
3932 }
3933 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303934 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003935 tabla_p->dai[j].ch_num,
3936 tabla_p->dai[j].ch_tot,
3937 tabla_p->dai[j].rate);
3938 break;
3939 case SND_SOC_DAPM_POST_PMD:
3940 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08003941 if (tabla_dai[j].id == AIF1_PB ||
3942 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003943 continue;
3944 if (!strncmp(w->sname,
3945 tabla_dai[j].capture.stream_name, 13)) {
3946 --tabla_p->dai[j].ch_act;
3947 break;
3948 }
3949 }
3950 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303951 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003952 tabla_p->dai[j].ch_num,
3953 tabla_p->dai[j].ch_tot);
3954 tabla_p->dai[j].rate = 0;
3955 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303956 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003957 tabla_p->dai[j].ch_tot = 0;
3958 }
3959 }
3960 return ret;
3961}
3962
3963/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3964 * Might Need to have callbacks registered only for slimbus
3965 */
3966static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
3967 /*RX stuff */
3968 SND_SOC_DAPM_OUTPUT("EAR"),
3969
3970 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
3971
3972 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
3973 ARRAY_SIZE(dac1_switch)),
3974
3975 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3976 0, tabla_codec_enable_slimrx,
3977 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3978 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
3979 0, tabla_codec_enable_slimrx,
3980 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3981
3982 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3983 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
3984
Neema Shettyd3a89262012-02-16 10:23:50 -08003985 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3986 0, tabla_codec_enable_slimrx,
3987 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3988 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
3989 0, tabla_codec_enable_slimrx,
3990 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3991
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003992 /* Headphone */
3993 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3994 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3995 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3996 SND_SOC_DAPM_POST_PMD),
3997 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
3998 hphl_switch, ARRAY_SIZE(hphl_switch)),
3999
4000 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
4001 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4002 SND_SOC_DAPM_POST_PMD),
4003
4004 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
4005 tabla_hphr_dac_event,
4006 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4007
4008 /* Speaker */
4009 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
4010 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
4011 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
4012 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
4013 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
4014
4015 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
4016 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4017 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4018 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
4019 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4020 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4021 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
4022 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4023 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4024 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
4025 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4026 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4027 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
4028 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4029 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4030
4031 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
4032 , tabla_lineout_dac_event,
4033 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4034 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
4035 , tabla_lineout_dac_event,
4036 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4037 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
4038 , tabla_lineout_dac_event,
4039 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4040 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
4041 &lineout3_ground_switch),
4042 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
4043 , tabla_lineout_dac_event,
4044 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4045 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
4046 &lineout4_ground_switch),
4047 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
4048 , tabla_lineout_dac_event,
4049 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4050
4051 SND_SOC_DAPM_MIXER_E("RX1 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004052 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4053 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004054 SND_SOC_DAPM_MIXER_E("RX2 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004055 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4056 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004057 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004058 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4059 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004060 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004061 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4062 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004063 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004064 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4065 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004066 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004067 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4068 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004069 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004070 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4071 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004072
4073 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
4074 &rx4_dsm_mux, tabla_codec_reset_interpolator,
4075 SND_SOC_DAPM_PRE_PMU),
4076
4077 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
4078 &rx6_dsm_mux, tabla_codec_reset_interpolator,
4079 SND_SOC_DAPM_PRE_PMU),
4080
4081 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
4082 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
4083
4084 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4085 &rx_mix1_inp1_mux),
4086 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4087 &rx_mix1_inp2_mux),
4088 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4089 &rx2_mix1_inp1_mux),
4090 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4091 &rx2_mix1_inp2_mux),
4092 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4093 &rx3_mix1_inp1_mux),
4094 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4095 &rx3_mix1_inp2_mux),
4096 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4097 &rx4_mix1_inp1_mux),
4098 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4099 &rx4_mix1_inp2_mux),
4100 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4101 &rx5_mix1_inp1_mux),
4102 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4103 &rx5_mix1_inp2_mux),
4104 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4105 &rx6_mix1_inp1_mux),
4106 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4107 &rx6_mix1_inp2_mux),
4108 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4109 &rx7_mix1_inp1_mux),
4110 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4111 &rx7_mix1_inp2_mux),
4112
4113 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
4114 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
4115 SND_SOC_DAPM_PRE_PMD),
4116
4117 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
4118 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
4119 SND_SOC_DAPM_POST_PMD),
4120
4121 /* TX */
4122
4123 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
4124 0),
4125
4126 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
4127 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
4128
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004129 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
4130 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4131 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4132 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
4133 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4134 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4135
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004136 SND_SOC_DAPM_INPUT("AMIC1"),
4137 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
4138 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4139 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4140 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
4141 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4142 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4143 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_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_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
4147 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4148 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4149
4150 SND_SOC_DAPM_INPUT("AMIC3"),
4151 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
4152 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4153 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4154
4155 SND_SOC_DAPM_INPUT("AMIC4"),
4156 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
4157 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4158 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4159
4160 SND_SOC_DAPM_INPUT("AMIC5"),
4161 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
4162 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4163
4164 SND_SOC_DAPM_INPUT("AMIC6"),
4165 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
4166 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4167
4168 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 -08004169 &dec1_mux, tabla_codec_enable_dec,
4170 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4171 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004172
4173 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 -08004174 &dec2_mux, tabla_codec_enable_dec,
4175 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4176 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004177
4178 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 -08004179 &dec3_mux, tabla_codec_enable_dec,
4180 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4181 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004182
4183 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 -08004184 &dec4_mux, tabla_codec_enable_dec,
4185 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4186 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004187
4188 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 -08004189 &dec5_mux, tabla_codec_enable_dec,
4190 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4191 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004192
4193 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 -08004194 &dec6_mux, tabla_codec_enable_dec,
4195 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4196 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004197
4198 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 -08004199 &dec7_mux, tabla_codec_enable_dec,
4200 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4201 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004202
4203 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 -08004204 &dec8_mux, tabla_codec_enable_dec,
4205 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4206 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004207
4208 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 -08004209 &dec9_mux, tabla_codec_enable_dec,
4210 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4211 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004212
4213 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 -08004214 &dec10_mux, tabla_codec_enable_dec,
4215 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4216 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004217
4218 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
4219 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
4220
4221 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
4222 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
4223 SND_SOC_DAPM_POST_PMD),
4224
4225 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
4226
4227 SND_SOC_DAPM_INPUT("AMIC2"),
4228 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
4229 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4230 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4231 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
4232 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4233 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4234 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
4235 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4236 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4237 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
4238 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4239 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4240 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
4241 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4242 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4243 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
4244 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4245 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4246 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
4247 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4248 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4249 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
4250 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4251 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4252
4253 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
4254 SND_SOC_DAPM_AIF_OUT("SLIM TX1", "AIF1 Capture", NULL, SND_SOC_NOPM,
4255 0, 0),
4256
4257 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
4258 SND_SOC_DAPM_AIF_OUT("SLIM TX5", "AIF1 Capture", NULL, SND_SOC_NOPM,
4259 4, 0),
4260
4261 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
4262 SND_SOC_DAPM_AIF_OUT("SLIM TX6", "AIF1 Capture", NULL, SND_SOC_NOPM,
4263 5, 0),
4264
4265 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
4266 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4267 0, tabla_codec_enable_slimtx,
4268 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4269
4270 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
4271 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4272 0, tabla_codec_enable_slimtx,
4273 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4274
4275 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
4276 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
4277 0, 0, tabla_codec_enable_slimtx,
4278 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4279
4280 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
4281 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
4282 0, 0, tabla_codec_enable_slimtx,
4283 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4284
4285 /* Digital Mic Inputs */
4286 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
4287 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4288 SND_SOC_DAPM_POST_PMD),
4289
4290 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
4291 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4292 SND_SOC_DAPM_POST_PMD),
4293
4294 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
4295 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4296 SND_SOC_DAPM_POST_PMD),
4297
4298 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
4299 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4300 SND_SOC_DAPM_POST_PMD),
4301
4302 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
4303 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4304 SND_SOC_DAPM_POST_PMD),
4305 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
4306 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4307 SND_SOC_DAPM_POST_PMD),
4308
4309 /* Sidetone */
4310 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
4311 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08004312
4313 /* AUX PGA */
4314 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
4315 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4316 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4317 SND_SOC_DAPM_POST_PMD),
4318
4319 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
4320 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4321 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4322 SND_SOC_DAPM_POST_PMD),
4323
4324 /* Lineout, ear and HPH PA Mixers */
4325 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
4326 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
4327
4328 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4329 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4330
4331 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4332 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4333
4334 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4335 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
4336
4337 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
4338 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
4339
4340 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
4341 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
4342
4343 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
4344 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
4345
4346 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4347 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004348};
4349
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004350static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004351{
4352 u8 bias_msb, bias_lsb;
4353 short bias_value;
4354
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004355 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
4356 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
4357 bias_value = (bias_msb << 8) | bias_lsb;
4358 return bias_value;
4359}
4360
4361static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
4362{
4363 u8 bias_msb, bias_lsb;
4364 short bias_value;
4365
4366 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
4367 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
4368 bias_value = (bias_msb << 8) | bias_lsb;
4369 return bias_value;
4370}
4371
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004372static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004373{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004374 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
4375}
4376
4377static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4378 bool override_bypass, bool noreldetection)
4379{
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004380 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004381 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4382
4383 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4384 if (noreldetection)
4385 tabla_turn_onoff_rel_detection(codec, false);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004386
Joonwoo Park925914c2012-01-05 13:35:18 -08004387 /* Turn on the override */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004388 if (!override_bypass)
4389 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004390 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004391 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4392 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
4393 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004394 usleep_range(tabla->mbhc_data.t_sta_dce,
4395 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004396 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08004397 usleep_range(tabla->mbhc_data.t_dce,
4398 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004399 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004400 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004401 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004402 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4403 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004404 usleep_range(tabla->mbhc_data.t_sta_dce,
4405 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08004406 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4407 usleep_range(tabla->mbhc_data.t_sta,
4408 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004409 bias_value = tabla_codec_read_sta_result(codec);
4410 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4411 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004412 }
Joonwoo Park925914c2012-01-05 13:35:18 -08004413 /* Turn off the override after measuring mic voltage */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004414 if (!override_bypass)
4415 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4416
4417 if (noreldetection)
4418 tabla_turn_onoff_rel_detection(codec, true);
4419 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004420
Bradley Rubincb1e2732011-06-23 16:49:20 -07004421 return bias_value;
4422}
4423
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004424static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4425 bool norel)
4426{
4427 return __tabla_codec_sta_dce(codec, dce, false, norel);
4428}
4429
4430/* called only from interrupt which is under codec_resource_lock acquisition */
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004431static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004432{
4433 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004434 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004435 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004436
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004437 pr_debug("%s: enter, mclk_enabled %d\n", __func__, tabla->mclk_enabled);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004438 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004439 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004440 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004441 }
4442
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004443 if (!tabla->mclk_enabled) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004444 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004445 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004446 tabla_codec_enable_clock_block(codec, 1);
4447 }
4448
4449 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4450
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004451 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004452 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4453 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004454
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004455 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004456
4457 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004458 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004459
4460 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4461 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4462 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4463
4464 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004465 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4466 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004467
Joonwoo Park925914c2012-01-05 13:35:18 -08004468 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004469 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4470
Bradley Rubincb1e2732011-06-23 16:49:20 -07004471 tabla_codec_calibrate_hs_polling(codec);
4472
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004473 /* don't flip override */
4474 bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004475 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4476 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004477 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004478
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004479 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004480}
4481
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004482static int tabla_cancel_btn_work(struct tabla_priv *tabla)
4483{
4484 int r = 0;
4485 struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
4486
4487 if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
4488 /* if scheduled mbhc_btn_dwork is canceled from here,
4489 * we have to unlock from here instead btn_work */
4490 wcd9xxx_unlock_sleep(core);
4491 r = 1;
4492 }
4493 return r;
4494}
4495
4496/* called under codec_resource_lock acquisition */
4497void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
Joonwoo Park03324832012-03-19 19:36:16 -07004498{
4499 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004500 u8 wg_time;
4501
4502 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4503 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07004504
4505 /* If headphone PA is on, check if userspace receives
4506 * removal event to sync-up PA's state */
4507 if (tabla_is_hph_pa_on(codec)) {
4508 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4509 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4510 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4511 } else {
4512 pr_debug("%s PA is off\n", __func__);
4513 }
4514
4515 if (tabla_is_hph_dac_on(codec, 1))
4516 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4517 if (tabla_is_hph_dac_on(codec, 0))
4518 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004519
4520 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
4521 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
4522 0xC0, 0x00);
4523 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
4524 0xC0, 0x00);
4525 usleep_range(wg_time * 1000, wg_time * 1000);
4526}
4527
4528static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
4529{
4530 bool pa_turned_on = false;
4531 struct snd_soc_codec *codec = tabla->codec;
4532 u8 wg_time;
4533
4534 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4535 wg_time += 1;
4536
4537 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4538 &tabla->hph_pa_dac_state)) {
4539 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4540 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4541 0xC0, 0xC0);
4542 }
4543 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4544 &tabla->hph_pa_dac_state)) {
4545 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4546 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4547 0xC0, 0xC0);
4548 }
4549
4550 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4551 &tabla->hph_pa_dac_state)) {
4552 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4553 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4554 1 << 4);
4555 pa_turned_on = true;
4556 }
4557 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4558 &tabla->hph_pa_dac_state)) {
4559 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4560 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4561 1 << 5);
4562 pa_turned_on = true;
4563 }
4564
4565 if (pa_turned_on) {
4566 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4567 __func__);
4568 usleep_range(wg_time * 1000, wg_time * 1000);
4569 }
4570}
4571
4572/* called under codec_resource_lock acquisition */
4573static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4574 enum snd_jack_types jack_type)
4575{
4576 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4577
4578 if (!insertion) {
4579 /* Report removal */
4580 tabla->hph_status &= ~jack_type;
4581 if (tabla->mbhc_cfg.headset_jack) {
4582 /* cancel possibly scheduled btn work and
4583 * report release if we reported button press */
4584 if (tabla_cancel_btn_work(tabla)) {
4585 pr_debug("%s: button press is canceled\n",
4586 __func__);
4587 } else if (tabla->buttons_pressed) {
4588 pr_debug("%s: Reporting release for reported "
4589 "button press %d\n", __func__,
4590 jack_type);
4591 tabla_snd_soc_jack_report(tabla,
4592 tabla->mbhc_cfg.button_jack, 0,
4593 tabla->buttons_pressed);
4594 tabla->buttons_pressed &=
4595 ~TABLA_JACK_BUTTON_MASK;
4596 }
4597 pr_debug("%s: Reporting removal %d\n", __func__,
4598 jack_type);
4599 tabla_snd_soc_jack_report(tabla,
4600 tabla->mbhc_cfg.headset_jack,
4601 tabla->hph_status,
4602 TABLA_JACK_MASK);
4603 }
4604 tabla_set_and_turnoff_hph_padac(codec);
4605 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
4606 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4607 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
4608 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4609 tabla->current_plug = PLUG_TYPE_NONE;
4610 tabla->mbhc_polling_active = false;
4611 } else {
4612 /* Report insertion */
4613 tabla->hph_status |= jack_type;
4614
4615 if (jack_type == SND_JACK_HEADPHONE)
4616 tabla->current_plug = PLUG_TYPE_HEADPHONE;
4617 else if (jack_type == SND_JACK_HEADSET) {
4618 tabla->mbhc_polling_active = true;
4619 tabla->current_plug = PLUG_TYPE_HEADSET;
4620 }
4621 if (tabla->mbhc_cfg.headset_jack) {
4622 pr_debug("%s: Reporting insertion %d\n", __func__,
4623 jack_type);
4624 tabla_snd_soc_jack_report(tabla,
4625 tabla->mbhc_cfg.headset_jack,
4626 tabla->hph_status,
4627 TABLA_JACK_MASK);
4628 }
4629 tabla_clr_and_turnon_hph_padac(tabla);
4630 }
Joonwoo Park03324832012-03-19 19:36:16 -07004631}
4632
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004633static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07004634 int insertion, int trigger,
4635 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004636{
4637 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004638 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08004639 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004640 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004641 const struct tabla_mbhc_plug_detect_cfg *plug_det =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004642 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004643
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004644 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004645 pr_err("Error, no tabla calibration\n");
4646 return -EINVAL;
4647 }
4648
4649 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
4650
Joonwoo Park03324832012-03-19 19:36:16 -07004651 /* Make sure mic bias and Mic line schmitt trigger
4652 * are turned OFF
4653 */
4654 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
4655 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
4656
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004657 if (insertion) {
Joonwoo Park03324832012-03-19 19:36:16 -07004658 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004659
Joonwoo Park03324832012-03-19 19:36:16 -07004660 /* DAPM can manipulate PA/DAC bits concurrently */
4661 if (padac_off == true) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004662 tabla_set_and_turnoff_hph_padac(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004663 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004664
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004665 if (trigger & MBHC_USE_HPHL_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07004666 /* Enable HPH Schmitt Trigger */
4667 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
4668 0x11);
4669 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
4670 plug_det->hph_current << 2);
4671 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
4672 0x02);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004673 }
4674 if (trigger & MBHC_USE_MB_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07004675 /* enable the mic line schmitt trigger */
4676 snd_soc_update_bits(codec,
4677 tabla->mbhc_bias_regs.mbhc_reg,
4678 0x60, plug_det->mic_current << 5);
4679 snd_soc_update_bits(codec,
4680 tabla->mbhc_bias_regs.mbhc_reg,
4681 0x80, 0x80);
4682 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
4683 snd_soc_update_bits(codec,
4684 tabla->mbhc_bias_regs.ctl_reg, 0x01,
4685 0x00);
4686 snd_soc_update_bits(codec,
4687 tabla->mbhc_bias_regs.mbhc_reg,
4688 0x10, 0x10);
4689 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004690
4691 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004692 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004693 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004694 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004695 /* Make sure the HPH schmitt trigger is OFF */
4696 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
4697
4698 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07004699 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
4700 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004701 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08004702 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004703 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4704 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004705 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004706 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
4707 0x10, 0x10);
4708
4709 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004710 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07004711 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004712
4713 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004714 /* called called by interrupt */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004715 if (!(tabla->clock_active)) {
4716 tabla_codec_enable_config_mode(codec, 1);
4717 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004718 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08004719 usleep_range(generic->t_shutdown_plug_rem,
4720 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004721 tabla_codec_enable_config_mode(codec, 0);
4722 } else
4723 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07004724 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004725 }
4726
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07004727 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004728
4729 /* If central bandgap disabled */
4730 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
4731 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08004732 usleep_range(generic->t_bg_fast_settle,
4733 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004734 central_bias_enabled = 1;
4735 }
4736
4737 /* If LDO_H disabled */
4738 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
4739 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
4740 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08004741 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004742 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
4743
4744 if (central_bias_enabled)
4745 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
4746 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004747
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004748 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004749 tabla->mbhc_cfg.micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004750
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304751 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004752 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
4753 return 0;
4754}
4755
Joonwoo Park0976d012011-12-22 11:48:18 -08004756static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
4757 s16 vin_mv)
4758{
Joonwoo Park0976d012011-12-22 11:48:18 -08004759 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004760 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08004761 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07004762 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004763
4764 tabla = snd_soc_codec_get_drvdata(codec);
4765 mb_mv = tabla->mbhc_data.micb_mv;
4766
4767 if (mb_mv == 0) {
4768 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
4769 return -EINVAL;
4770 }
4771
4772 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004773 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
4774 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004775 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004776 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
4777 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004778 }
4779 in = (u32) diff * vin_mv;
4780
Joonwoo Park03324832012-03-19 19:36:16 -07004781 value = (u16) (in / mb_mv) + zero;
4782 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004783}
4784
4785static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
4786 u16 bias_value)
4787{
4788 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07004789 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08004790 s32 mv;
4791
4792 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07004793 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08004794 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07004795 z = (tabla->mbhc_data.dce_z);
4796 mb = (tabla->mbhc_data.dce_mb);
4797 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004798 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07004799 z = (tabla->mbhc_data.sta_z);
4800 mb = (tabla->mbhc_data.sta_mb);
4801 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08004802 }
4803
4804 return mv;
4805}
4806
Joonwoo Park03324832012-03-19 19:36:16 -07004807static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004808{
4809 struct delayed_work *delayed_work;
4810 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08004811 short bias_value;
4812 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07004813 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004814
4815 pr_debug("%s:\n", __func__);
4816
4817 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07004818 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08004819 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004820
4821 if (tabla) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004822 if (tabla->mbhc_cfg.button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08004823 bias_value = tabla_codec_read_sta_result(tabla->codec);
4824 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304825 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004826 bias_value = tabla_codec_read_dce_result(tabla->codec);
4827 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304828 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08004829 pr_debug("%s: Reporting long button press event"
4830 " STA: %d, DCE: %d\n", __func__,
4831 sta_mv, dce_mv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004832 tabla_snd_soc_jack_report(tabla,
4833 tabla->mbhc_cfg.button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07004834 tabla->buttons_pressed,
4835 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004836 }
4837 } else {
4838 pr_err("%s: Bad tabla private data\n", __func__);
4839 }
4840
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004841 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07004842 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07004843}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07004844
Joonwoo Park0976d012011-12-22 11:48:18 -08004845void tabla_mbhc_cal(struct snd_soc_codec *codec)
4846{
4847 struct tabla_priv *tabla;
4848 struct tabla_mbhc_btn_detect_cfg *btn_det;
4849 u8 cfilt_mode, bg_mode;
4850 u8 ncic, nmeas, navg;
4851 u32 mclk_rate;
4852 u32 dce_wait, sta_wait;
4853 u8 *n_cic;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004854 void *calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08004855
4856 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004857 calibration = tabla->mbhc_cfg.calibration;
4858
4859 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4860 tabla_turn_onoff_rel_detection(codec, false);
Joonwoo Park0976d012011-12-22 11:48:18 -08004861
4862 /* First compute the DCE / STA wait times
4863 * depending on tunable parameters.
4864 * The value is computed in microseconds
4865 */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004866 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004867 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08004868 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004869 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
4870 navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
4871 mclk_rate = tabla->mbhc_cfg.mclk_rate;
Joonwoo Park433149a2012-01-11 09:53:54 -08004872 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
4873 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08004874
4875 tabla->mbhc_data.t_dce = dce_wait;
4876 tabla->mbhc_data.t_sta = sta_wait;
4877
4878 /* LDOH and CFILT are already configured during pdata handling.
4879 * Only need to make sure CFILT and bandgap are in Fast mode.
4880 * Need to restore defaults once calculation is done.
4881 */
4882 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4883 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
4884 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
4885 0x02);
4886
4887 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
4888 * to perform ADC calibration
4889 */
4890 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004891 tabla->mbhc_cfg.micbias << 5);
Joonwoo Park0976d012011-12-22 11:48:18 -08004892 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
4893 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
4894 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
4895 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
4896
4897 /* DCE measurement for 0 volts */
4898 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4899 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4900 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004901 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4902 usleep_range(100, 100);
4903 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4904 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4905 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
4906
4907 /* DCE measurment for MB voltage */
4908 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4909 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
4910 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4911 usleep_range(100, 100);
4912 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
4913 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
4914 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
4915
4916 /* Sta measuremnt for 0 volts */
4917 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
4918 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4919 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08004920 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
4921 usleep_range(100, 100);
4922 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4923 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4924 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
4925
4926 /* STA Measurement for MB Voltage */
4927 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
4928 usleep_range(100, 100);
4929 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
4930 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
4931 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
4932
4933 /* Restore default settings. */
4934 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4935 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4936 cfilt_mode);
4937 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
4938
4939 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
4940 usleep_range(100, 100);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004941
4942 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4943 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004944}
4945
4946void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
4947 const enum tabla_mbhc_btn_det_mem mem)
4948{
4949 void *ret = &btn_det->_v_btn_low;
4950
4951 switch (mem) {
4952 case TABLA_BTN_DET_GAIN:
4953 ret += sizeof(btn_det->_n_cic);
4954 case TABLA_BTN_DET_N_CIC:
4955 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08004956 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08004957 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
4958 case TABLA_BTN_DET_V_BTN_HIGH:
4959 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
4960 case TABLA_BTN_DET_V_BTN_LOW:
4961 /* do nothing */
4962 break;
4963 default:
4964 ret = NULL;
4965 }
4966
4967 return ret;
4968}
4969
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004970static s16 tabla_scale_v_micb_vddio(struct tabla_priv *tabla, int v,
4971 bool tovddio)
4972{
4973 int r;
4974 int vddio_k, mb_k;
4975 vddio_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
4976 VDDIO_MICBIAS_MV);
4977 mb_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
4978 tabla->mbhc_data.micb_mv);
4979 if (tovddio)
4980 r = v * vddio_k / mb_k;
4981 else
4982 r = v * mb_k / vddio_k;
4983 return r;
4984}
4985
Joonwoo Park0976d012011-12-22 11:48:18 -08004986static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
4987{
4988 struct tabla_priv *tabla;
4989 s16 btn_mv = 0, btn_delta_mv;
4990 struct tabla_mbhc_btn_detect_cfg *btn_det;
4991 struct tabla_mbhc_plug_type_cfg *plug_type;
4992 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08004993 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08004994 int i;
4995
4996 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004997 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
4998 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004999
Joonwoo Parkc0672392012-01-11 11:03:14 -08005000 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005001 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07005002 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08005003 tabla->mbhc_data.nbounce_wait = 30;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005004 } else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005005 tabla->mbhc_data.npoll = 7;
5006 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08005007 }
Joonwoo Park0976d012011-12-22 11:48:18 -08005008
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005009 tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
5010 (tabla->mbhc_cfg.mclk_rate / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08005011 n_ready[tabla_codec_mclk_index(tabla)]) +
5012 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08005013 tabla->mbhc_data.v_ins_hu =
5014 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
5015 tabla->mbhc_data.v_ins_h =
5016 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
5017
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005018 tabla->mbhc_data.v_inval_ins_low = TABLA_MBHC_FAKE_INSERT_LOW;
5019 if (tabla->mbhc_cfg.gpio)
5020 tabla->mbhc_data.v_inval_ins_high =
5021 TABLA_MBHC_FAKE_INSERT_HIGH;
5022 else
5023 tabla->mbhc_data.v_inval_ins_high =
5024 TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
5025
5026 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
5027 tabla->mbhc_data.adj_v_hs_max =
5028 tabla_scale_v_micb_vddio(tabla, plug_type->v_hs_max, true);
5029 tabla->mbhc_data.adj_v_ins_hu =
5030 tabla_codec_v_sta_dce(codec, STA,
5031 tabla->mbhc_data.adj_v_hs_max);
5032 tabla->mbhc_data.adj_v_ins_h =
5033 tabla_codec_v_sta_dce(codec, DCE,
5034 tabla->mbhc_data.adj_v_hs_max);
5035 tabla->mbhc_data.v_inval_ins_low =
5036 tabla_scale_v_micb_vddio(tabla,
5037 tabla->mbhc_data.v_inval_ins_low,
5038 false);
5039 tabla->mbhc_data.v_inval_ins_high =
5040 tabla_scale_v_micb_vddio(tabla,
5041 tabla->mbhc_data.v_inval_ins_high,
5042 false);
5043 }
5044
Joonwoo Park0976d012011-12-22 11:48:18 -08005045 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
5046 for (i = 0; i < btn_det->num_btn; i++)
5047 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
5048
5049 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
5050 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
Joonwoo Park0976d012011-12-22 11:48:18 -08005051 tabla->mbhc_data.v_b1_hu =
5052 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
5053
5054 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
5055
5056 tabla->mbhc_data.v_b1_huc =
5057 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
5058
5059 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
Joonwoo Park03324832012-03-19 19:36:16 -07005060 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
Joonwoo Park0976d012011-12-22 11:48:18 -08005061
5062 tabla->mbhc_data.v_no_mic =
5063 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
5064}
5065
5066void tabla_mbhc_init(struct snd_soc_codec *codec)
5067{
5068 struct tabla_priv *tabla;
5069 struct tabla_mbhc_general_cfg *generic;
5070 struct tabla_mbhc_btn_detect_cfg *btn_det;
5071 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08005072 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305073 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08005074
5075 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005076 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
5077 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005078
Joonwoo Park0976d012011-12-22 11:48:18 -08005079 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005080 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005081 snd_soc_update_bits(codec,
5082 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
5083 0x07, n);
5084 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
5085 btn_det->c[n]);
5086 }
5087 }
5088 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
5089 btn_det->nc);
5090
5091 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
5092 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08005093 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08005094
5095 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08005096 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
5097 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08005098
5099 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
5100 generic->mbhc_nsa << 4);
5101
5102 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
5103 btn_det->n_meas);
5104
5105 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
5106
5107 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
5108
5109 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
5110 btn_det->mbhc_nsc << 3);
5111
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005112 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
5113 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08005114
5115 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07005116
5117 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Park0976d012011-12-22 11:48:18 -08005118}
5119
Patrick Lai64b43262011-12-06 17:29:15 -08005120static bool tabla_mbhc_fw_validate(const struct firmware *fw)
5121{
5122 u32 cfg_offset;
5123 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
5124 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
5125
5126 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
5127 return false;
5128
5129 /* previous check guarantees that there is enough fw data up
5130 * to num_btn
5131 */
5132 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
5133 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
5134 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
5135 return false;
5136
5137 /* previous check guarantees that there is enough fw data up
5138 * to start of impedance detection configuration
5139 */
5140 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
5141 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
5142
5143 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
5144 return false;
5145
5146 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
5147 return false;
5148
5149 return true;
5150}
Joonwoo Park03324832012-03-19 19:36:16 -07005151
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005152static int tabla_determine_button(const struct tabla_priv *priv,
5153 const s32 bias_mv)
5154{
5155 s16 *v_btn_low, *v_btn_high;
5156 struct tabla_mbhc_btn_detect_cfg *btn_det;
5157 int i, btn = -1;
5158
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005159 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005160 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
5161 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305162 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005163 for (i = 0; i < btn_det->num_btn; i++) {
5164 if ((v_btn_low[i] <= bias_mv) && (v_btn_high[i] >= bias_mv)) {
5165 btn = i;
5166 break;
5167 }
5168 }
5169
5170 if (btn == -1)
5171 pr_debug("%s: couldn't find button number for mic mv %d\n",
5172 __func__, bias_mv);
5173
5174 return btn;
5175}
5176
5177static int tabla_get_button_mask(const int btn)
5178{
5179 int mask = 0;
5180 switch (btn) {
5181 case 0:
5182 mask = SND_JACK_BTN_0;
5183 break;
5184 case 1:
5185 mask = SND_JACK_BTN_1;
5186 break;
5187 case 2:
5188 mask = SND_JACK_BTN_2;
5189 break;
5190 case 3:
5191 mask = SND_JACK_BTN_3;
5192 break;
5193 case 4:
5194 mask = SND_JACK_BTN_4;
5195 break;
5196 case 5:
5197 mask = SND_JACK_BTN_5;
5198 break;
5199 case 6:
5200 mask = SND_JACK_BTN_6;
5201 break;
5202 case 7:
5203 mask = SND_JACK_BTN_7;
5204 break;
5205 }
5206 return mask;
5207}
5208
Bradley Rubincb1e2732011-06-23 16:49:20 -07005209static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005210{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005211 int i, mask;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005212 short dce, sta, bias_value_dce;
5213 s32 mv, stamv, bias_mv_dce;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005214 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005215 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005216 const struct tabla_mbhc_btn_detect_cfg *d =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005217 TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005218 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005219 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305220 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07005221 int n_btn_meas = d->n_btn_meas;
5222 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005223
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005224 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005225
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005226 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5227 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
5228 pr_debug("%s: mbhc is being recovered, skip button press\n",
5229 __func__);
5230 goto done;
5231 }
5232
5233 priv->mbhc_state = MBHC_STATE_POTENTIAL;
5234
5235 if (!priv->mbhc_polling_active) {
5236 pr_warn("%s: mbhc polling is not active, skip button press\n",
5237 __func__);
5238 goto done;
5239 }
Joonwoo Park03324832012-03-19 19:36:16 -07005240
5241 dce = tabla_codec_read_dce_result(codec);
5242 mv = tabla_codec_sta_dce_v(codec, 1, dce);
5243
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005244 /* If GPIO interrupt already kicked in, ignore button press */
5245 if (priv->in_gpio_handler) {
5246 pr_debug("%s: GPIO State Changed, ignore button press\n",
5247 __func__);
5248 btn = -1;
5249 goto done;
5250 }
5251
Joonwoo Park03324832012-03-19 19:36:16 -07005252 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
5253 if (priv->mbhc_last_resume &&
5254 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
5255 pr_debug("%s: Button is already released shortly after "
5256 "resume\n", __func__);
5257 n_btn_meas = 0;
5258 } else {
5259 pr_debug("%s: Button is already released without "
5260 "resume", __func__);
5261 sta = tabla_codec_read_sta_result(codec);
5262 stamv = tabla_codec_sta_dce_v(codec, 0, sta);
5263 btn = tabla_determine_button(priv, mv);
5264 if (btn != tabla_determine_button(priv, stamv))
5265 btn = -1;
5266 goto done;
5267 }
5268 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005269
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005270 /* determine pressed button */
Joonwoo Park03324832012-03-19 19:36:16 -07005271 btnmeas[meas++] = tabla_determine_button(priv, mv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005272 pr_debug("%s: meas %d - DCE %d,%d, button %d\n", __func__,
Joonwoo Park03324832012-03-19 19:36:16 -07005273 meas - 1, dce, mv, btnmeas[meas - 1]);
5274 if (n_btn_meas == 0)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005275 btn = btnmeas[0];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005276 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
5277 bias_value_dce = tabla_codec_sta_dce(codec, 1, false);
5278 bias_mv_dce = tabla_codec_sta_dce_v(codec, 1, bias_value_dce);
5279 btnmeas[meas] = tabla_determine_button(priv, bias_mv_dce);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005280 pr_debug("%s: meas %d - DCE %d,%d, button %d\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005281 __func__, meas, bias_value_dce, bias_mv_dce,
5282 btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005283 /* if large enough measurements are collected,
5284 * start to check if last all n_btn_con measurements were
5285 * in same button low/high range */
5286 if (meas + 1 >= d->n_btn_con) {
5287 for (i = 0; i < d->n_btn_con; i++)
5288 if ((btnmeas[meas] < 0) ||
5289 (btnmeas[meas] != btnmeas[meas - i]))
5290 break;
5291 if (i == d->n_btn_con) {
5292 /* button pressed */
5293 btn = btnmeas[meas];
5294 break;
Joonwoo Park03324832012-03-19 19:36:16 -07005295 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
5296 /* if left measurements are less than n_btn_con,
5297 * it's impossible to find button number */
5298 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005299 }
5300 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005301 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005302
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005303 if (btn >= 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005304 if (priv->in_gpio_handler) {
5305 pr_debug("%s: GPIO already triggered, ignore button "
5306 "press\n", __func__);
5307 goto done;
5308 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005309 mask = tabla_get_button_mask(btn);
5310 priv->buttons_pressed |= mask;
Joonwoo Park03324832012-03-19 19:36:16 -07005311 wcd9xxx_lock_sleep(core);
5312 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
5313 msecs_to_jiffies(400)) == 0) {
5314 WARN(1, "Button pressed twice without release"
5315 "event\n");
5316 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005317 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08005318 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005319 pr_debug("%s: bogus button press, too short press?\n",
5320 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08005321 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005322
Joonwoo Park03324832012-03-19 19:36:16 -07005323 done:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005324 pr_debug("%s: leave\n", __func__);
5325 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005326 return IRQ_HANDLED;
5327}
5328
Joonwoo Park03324832012-03-19 19:36:16 -07005329static int tabla_is_fake_press(struct tabla_priv *priv)
5330{
5331 int i;
5332 int r = 0;
5333 struct snd_soc_codec *codec = priv->codec;
5334 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005335 s16 mb_v, v_ins_hu, v_ins_h;
5336
5337 v_ins_hu = tabla_get_current_v_ins(priv, true);
5338 v_ins_h = tabla_get_current_v_ins(priv, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005339
5340 for (i = 0; i < dces; i++) {
5341 usleep_range(10000, 10000);
5342 if (i == 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005343 mb_v = tabla_codec_sta_dce(codec, 0, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005344 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
5345 tabla_codec_sta_dce_v(codec, 0, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005346 if (mb_v < (s16)priv->mbhc_data.v_b1_hu ||
5347 mb_v > v_ins_hu) {
Joonwoo Park03324832012-03-19 19:36:16 -07005348 r = 1;
5349 break;
5350 }
5351 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005352 mb_v = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005353 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
5354 tabla_codec_sta_dce_v(codec, 1, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005355 if (mb_v < (s16)priv->mbhc_data.v_b1_h ||
5356 mb_v > v_ins_h) {
Joonwoo Park03324832012-03-19 19:36:16 -07005357 r = 1;
5358 break;
5359 }
5360 }
5361 }
5362
5363 return r;
5364}
5365
Bradley Rubincb1e2732011-06-23 16:49:20 -07005366static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005367{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08005368 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08005369 struct tabla_priv *priv = data;
5370 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005371
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005372 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07005373
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005374 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5375 priv->mbhc_state = MBHC_STATE_RELEASE;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005376
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005377 tabla_codec_drive_v_to_micbias(codec, 10000);
5378
Joonwoo Park03324832012-03-19 19:36:16 -07005379 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005380 ret = tabla_cancel_btn_work(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005381 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07005382 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005383 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005384 if (priv->mbhc_cfg.button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005385 tabla_snd_soc_jack_report(priv,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005386 priv->mbhc_cfg.button_jack, 0,
5387 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005388 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005389 if (tabla_is_fake_press(priv)) {
5390 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005391 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005392 } else if (priv->mbhc_cfg.button_jack) {
5393 if (priv->in_gpio_handler) {
5394 pr_debug("%s: GPIO kicked in, ignore\n",
5395 __func__);
5396 } else {
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005397 pr_debug("%s: Reporting short button "
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005398 "press and release\n",
5399 __func__);
5400 tabla_snd_soc_jack_report(priv,
5401 priv->mbhc_cfg.button_jack,
5402 priv->buttons_pressed,
5403 priv->buttons_pressed);
5404 tabla_snd_soc_jack_report(priv,
5405 priv->mbhc_cfg.button_jack, 0,
5406 priv->buttons_pressed);
5407 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005408 }
5409 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005410
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005411 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
5412 }
5413
Joonwoo Park03324832012-03-19 19:36:16 -07005414 tabla_codec_calibrate_hs_polling(codec);
5415
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005416 if (priv->mbhc_cfg.gpio)
5417 msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
Joonwoo Park03324832012-03-19 19:36:16 -07005418
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005419 tabla_codec_start_hs_polling(codec);
5420
5421 pr_debug("%s: leave\n", __func__);
5422 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005423 return IRQ_HANDLED;
5424}
5425
Bradley Rubincb1e2732011-06-23 16:49:20 -07005426static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
5427{
5428 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08005429 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005430 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005431
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005432 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005433 tabla_codec_enable_config_mode(codec, 1);
5434
5435 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
5436 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005437
Joonwoo Park0976d012011-12-22 11:48:18 -08005438 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
5439
5440 usleep_range(generic->t_shutdown_plug_rem,
5441 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005442
5443 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005444 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005445 tabla_codec_enable_config_mode(codec, 0);
5446
5447 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
5448}
5449
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005450static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005451{
5452 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005453
5454 tabla_codec_shutdown_hs_removal_detect(codec);
5455
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005456 if (!tabla->mclk_enabled) {
Asish Bhattacharya486745a2012-01-20 06:41:53 +05305457 tabla_codec_disable_clock_block(codec);
5458 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005459 }
5460
5461 tabla->mbhc_polling_active = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005462 tabla->mbhc_state = MBHC_STATE_NONE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005463}
5464
Patrick Lai49efeac2011-11-03 11:01:12 -07005465static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
5466{
5467 struct tabla_priv *tabla = data;
5468 struct snd_soc_codec *codec;
5469
5470 pr_info("%s: received HPHL OCP irq\n", __func__);
5471
5472 if (tabla) {
5473 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005474 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
5475 pr_info("%s: retry\n", __func__);
5476 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5477 0x00);
5478 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5479 0x10);
5480 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305481 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005482 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5483 tabla->hphlocp_cnt = 0;
5484 tabla->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005485 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005486 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005487 tabla->mbhc_cfg.headset_jack,
5488 tabla->hph_status,
5489 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005490 }
5491 } else {
5492 pr_err("%s: Bad tabla private data\n", __func__);
5493 }
5494
5495 return IRQ_HANDLED;
5496}
5497
5498static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
5499{
5500 struct tabla_priv *tabla = data;
5501 struct snd_soc_codec *codec;
5502
5503 pr_info("%s: received HPHR OCP irq\n", __func__);
5504
5505 if (tabla) {
5506 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005507 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
5508 pr_info("%s: retry\n", __func__);
5509 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5510 0x00);
5511 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5512 0x10);
5513 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305514 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005515 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5516 tabla->hphrocp_cnt = 0;
5517 tabla->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005518 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005519 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005520 tabla->mbhc_cfg.headset_jack,
5521 tabla->hph_status,
5522 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005523 }
5524 } else {
5525 pr_err("%s: Bad tabla private data\n", __func__);
5526 }
5527
5528 return IRQ_HANDLED;
5529}
5530
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005531static bool tabla_is_invalid_insertion_range(struct snd_soc_codec *codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005532 s32 mic_volt)
Joonwoo Park03324832012-03-19 19:36:16 -07005533{
5534 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005535 bool invalid = false;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005536 s16 v_hs_max;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005537
5538 /* Perform this check only when the high voltage headphone
5539 * needs to be considered as invalid
5540 */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005541 v_hs_max = tabla_get_current_v_hs_max(tabla);
5542 if (!tabla->mbhc_inval_hs_range_override && (mic_volt > v_hs_max))
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005543 invalid = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005544 else if (mic_volt < tabla->mbhc_data.v_inval_ins_high &&
5545 (mic_volt > tabla->mbhc_data.v_inval_ins_low))
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005546 invalid = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005547
5548 return invalid;
5549}
5550
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005551static bool tabla_is_inval_insert_delta(struct snd_soc_codec *codec,
5552 int mic_volt, int mic_volt_prev,
5553 int threshold)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005554{
5555 int delta = abs(mic_volt - mic_volt_prev);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005556 if (delta > threshold) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005557 pr_debug("%s: volt delta %dmv\n", __func__, delta);
Joonwoo Park03324832012-03-19 19:36:16 -07005558 return true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005559 }
Joonwoo Park03324832012-03-19 19:36:16 -07005560 return false;
5561}
5562
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005563static bool tabla_codec_is_invalid_plug(struct snd_soc_codec *codec,
5564 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT],
5565 enum tabla_mbhc_plug_type
5566 plug_type[MBHC_NUM_DCE_PLUG_DETECT])
5567{
5568 int i;
5569 bool r = false;
5570 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5571 struct tabla_mbhc_plug_type_cfg *plug_type_ptr =
5572 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005573 s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005574
5575 for (i = 0 ; i < MBHC_NUM_DCE_PLUG_DETECT && !r; i++) {
5576 if (mic_mv[i] < plug_type_ptr->v_no_mic)
5577 plug_type[i] = PLUG_TYPE_HEADPHONE;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005578 else if (mic_mv[i] < v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005579 plug_type[i] = PLUG_TYPE_HEADSET;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005580 else if (mic_mv[i] > v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005581 plug_type[i] = PLUG_TYPE_HIGH_HPH;
5582
5583 r = tabla_is_invalid_insertion_range(codec, mic_mv[i]);
5584 if (!r && i > 0) {
5585 if (plug_type[i-1] != plug_type[i])
5586 r = true;
5587 else
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005588 r = tabla_is_inval_insert_delta(codec,
5589 mic_mv[i], mic_mv[i - 1],
5590 TABLA_MBHC_FAKE_INS_DELTA_MV);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005591 }
5592 }
5593
5594 return r;
5595}
5596
5597/* called under codec_resource_lock acquisition */
5598void tabla_find_plug_and_report(struct snd_soc_codec *codec,
5599 enum tabla_mbhc_plug_type plug_type)
Joonwoo Park03324832012-03-19 19:36:16 -07005600{
5601 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005602
5603 if (plug_type == PLUG_TYPE_HEADPHONE
5604 && tabla->current_plug == PLUG_TYPE_NONE) {
5605 /* Nothing was reported previously
5606 * reporte a headphone
5607 */
5608 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5609 tabla_codec_cleanup_hs_polling(codec);
5610 } else if (plug_type == PLUG_TYPE_HEADSET) {
5611 /* If Headphone was reported previously, this will
5612 * only report the mic line
5613 */
5614 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5615 msleep(100);
5616 tabla_codec_start_hs_polling(codec);
5617 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
5618 if (tabla->current_plug == PLUG_TYPE_NONE)
5619 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5620 tabla_codec_cleanup_hs_polling(codec);
5621 pr_debug("setup mic trigger for further detection\n");
5622 tabla->lpi_enabled = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005623 tabla_codec_enable_hs_detect(codec, 1,
5624 MBHC_USE_MB_TRIGGER |
5625 MBHC_USE_HPHL_TRIGGER,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005626 false);
5627 }
5628}
5629
5630/* should be called under interrupt context that hold suspend */
5631static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla)
5632{
5633 pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
5634 tabla->hs_detect_work_stop = false;
5635 wcd9xxx_lock_sleep(tabla->codec->control_data);
5636 schedule_work(&tabla->hs_correct_plug_work);
5637}
5638
5639/* called under codec_resource_lock acquisition */
5640static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla)
5641{
5642 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
5643 tabla->hs_detect_work_stop = true;
5644 wmb();
5645 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5646 if (cancel_work_sync(&tabla->hs_correct_plug_work)) {
5647 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
5648 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5649 }
5650 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5651}
5652
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005653static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
5654{
5655 return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
5656 tabla->mbhc_cfg.gpio_level_insert);
5657}
5658
5659static void tabla_hs_correct_gpio_plug(struct work_struct *work)
5660{
5661 struct tabla_priv *tabla;
5662 struct snd_soc_codec *codec;
5663 int retry = 0, i;
5664 bool correction = false;
5665 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
5666 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5667 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5668 unsigned long timeout;
5669
5670 tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
5671 codec = tabla->codec;
5672
5673 pr_debug("%s: enter\n", __func__);
5674 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
5675
5676 /* Keep override on during entire plug type correction work.
5677 *
5678 * This is okay under the assumption that any GPIO irqs which use
5679 * MBHC block cancel and sync this work so override is off again
5680 * prior to GPIO interrupt handler's MBHC block usage.
5681 * Also while this correction work is running, we can guarantee
5682 * DAPM doesn't use any MBHC block as this work only runs with
5683 * headphone detection.
5684 */
5685 tabla_turn_onoff_override(codec, true);
5686
5687 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
5688 while (!time_after(jiffies, timeout)) {
5689 ++retry;
5690 rmb();
5691 if (tabla->hs_detect_work_stop) {
5692 pr_debug("%s: stop requested\n", __func__);
5693 break;
5694 }
5695
5696 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
5697 if (tabla_hs_gpio_level_remove(tabla)) {
5698 pr_debug("%s: GPIO value is low\n", __func__);
5699 break;
5700 }
5701
5702 /* can race with removal interrupt */
5703 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5704 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5705 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5706 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5707 pr_debug("%s : DCE run %d, mic_mv = %d(%x)\n",
5708 __func__, retry, mic_mv[i], mb_v[i]);
5709 }
5710 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5711
5712 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5713 pr_debug("Invalid plug in attempt # %d\n", retry);
5714 if (retry == NUM_ATTEMPTS_TO_REPORT &&
5715 tabla->current_plug == PLUG_TYPE_NONE) {
5716 tabla_codec_report_plug(codec, 1,
5717 SND_JACK_HEADPHONE);
5718 }
5719 } else if (!tabla_codec_is_invalid_plug(codec, mic_mv,
5720 plug_type) &&
5721 plug_type[0] == PLUG_TYPE_HEADPHONE) {
5722 pr_debug("Good headphone detected, continue polling mic\n");
5723 if (tabla->current_plug == PLUG_TYPE_NONE) {
5724 tabla_codec_report_plug(codec, 1,
5725 SND_JACK_HEADPHONE);
5726 }
5727 } else {
5728 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5729 /* Turn off override */
5730 tabla_turn_onoff_override(codec, false);
5731 tabla_find_plug_and_report(codec, plug_type[0]);
5732 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5733 pr_debug("Attempt %d found correct plug %d\n", retry,
5734 plug_type[0]);
5735 correction = true;
5736 break;
5737 }
5738 }
5739
5740 /* Turn off override */
5741 if (!correction)
5742 tabla_turn_onoff_override(codec, false);
5743
5744 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
5745 pr_debug("%s: leave\n", __func__);
5746 /* unlock sleep */
5747 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5748}
5749
5750/* called under codec_resource_lock acquisition */
5751static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
5752{
5753 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005754 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
5755 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005756 enum tabla_mbhc_plug_type plug_type[MBHC_NUM_DCE_PLUG_DETECT];
5757 int i;
5758
5759 pr_debug("%s: enter\n", __func__);
5760
5761 tabla_turn_onoff_override(codec, true);
5762 mb_v[0] = tabla_codec_setup_hs_polling(codec);
5763 mic_mv[0] = tabla_codec_sta_dce_v(codec, 1, mb_v[0]);
5764 pr_debug("%s: DCE run 1, mic_mv = %d\n", __func__, mic_mv[0]);
5765
5766 for (i = 1; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
5767 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5768 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5769 pr_debug("%s: DCE run %d, mic_mv = %d\n", __func__, i + 1,
5770 mic_mv[i]);
5771 }
5772 tabla_turn_onoff_override(codec, false);
5773
5774 if (tabla_hs_gpio_level_remove(tabla)) {
5775 pr_debug("%s: GPIO value is low when determining plug\n",
5776 __func__);
5777 return;
5778 }
5779
5780 if (tabla_codec_is_invalid_plug(codec, mic_mv, plug_type)) {
5781 tabla_schedule_hs_detect_plug(tabla);
5782 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
5783 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5784
5785 tabla_schedule_hs_detect_plug(tabla);
5786 } else {
5787 pr_debug("%s: Valid plug found, determine plug type\n",
5788 __func__);
5789 tabla_find_plug_and_report(codec, plug_type[0]);
5790 }
5791}
5792
5793/* called under codec_resource_lock acquisition */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005794static void tabla_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
5795{
5796 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5797
5798 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
5799 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, on);
5800 if (on)
5801 usleep_range(5000, 5000);
5802 }
5803}
5804
5805/* called under codec_resource_lock acquisition */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005806static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
5807{
5808 int i;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005809 bool gndswitch, vddioswitch;
5810 int scaled;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005811 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5812 const struct tabla_mbhc_plug_detect_cfg *plug_det =
5813 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07005814 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005815 const bool vddio = (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
5816 !tabla->mbhc_micbias_switched);
5817 int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
5818 enum tabla_mbhc_plug_type plug_type[num_det];
5819 short mb_v[num_det];
5820 s32 mic_mv[num_det];
5821 bool inval = false;
Joonwoo Park03324832012-03-19 19:36:16 -07005822
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005823 /* Turn on the override,
5824 * tabla_codec_setup_hs_polling requires override on */
5825 tabla_turn_onoff_override(codec, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005826
5827 if (plug_det->t_ins_complete > 20)
5828 msleep(plug_det->t_ins_complete);
5829 else
5830 usleep_range(plug_det->t_ins_complete * 1000,
5831 plug_det->t_ins_complete * 1000);
5832
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005833 if (tabla->mbhc_cfg.gpio) {
5834 /* Turn off the override */
5835 tabla_turn_onoff_override(codec, false);
5836 if (tabla_hs_gpio_level_remove(tabla))
5837 pr_debug("%s: GPIO value is low when determining "
5838 "plug\n", __func__);
5839 else
5840 tabla_codec_decide_gpio_plug(codec);
5841 return;
5842 }
5843
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005844 /* performs DCEs for N times
5845 * 1st: check if voltage is in invalid range
5846 * 2nd - N-2nd: check voltage range and delta
5847 * N-1st: check voltage range, delta with HPHR GND switch
5848 * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
5849 for (i = 0; i < num_det && !inval; i++) {
5850 gndswitch = (i == (num_det - 1 - vddio));
5851 vddioswitch = (vddio && (i == num_det - 1));
5852 if (i == 0) {
5853 mb_v[i] = tabla_codec_setup_hs_polling(codec);
5854 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5855 inval = tabla_is_invalid_insertion_range(codec,
5856 mic_mv[i]);
5857 scaled = mic_mv[i];
5858 } else if (vddioswitch) {
5859 __tabla_codec_switch_micbias(tabla->codec, 1, false,
Joonwoo Park03324832012-03-19 19:36:16 -07005860 false);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005861 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5862 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5863 scaled = tabla_scale_v_micb_vddio(tabla, mic_mv[i],
5864 false);
5865 inval = (tabla_is_invalid_insertion_range(codec,
5866 mic_mv[i]) ||
5867 tabla_is_inval_insert_delta(codec, scaled,
5868 mic_mv[i - 1],
5869 TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
5870 __tabla_codec_switch_micbias(tabla->codec, 0, false,
5871 false);
5872 } else {
5873 if (gndswitch)
5874 tabla_codec_hphr_gnd_switch(codec, true);
5875 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
5876 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
5877 inval = (tabla_is_invalid_insertion_range(codec,
5878 mic_mv[i]) ||
5879 tabla_is_inval_insert_delta(codec, mic_mv[i],
5880 mic_mv[i - 1],
5881 TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV));
5882 if (gndswitch)
5883 tabla_codec_hphr_gnd_switch(codec, false);
5884 scaled = mic_mv[i];
Joonwoo Park03324832012-03-19 19:36:16 -07005885 }
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005886 pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
5887 "invalid %d\n", __func__,
5888 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
5889 inval);
Joonwoo Park03324832012-03-19 19:36:16 -07005890 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005891 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005892
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005893 plug_type_ptr =
5894 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07005895
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005896 for (i = 0; !inval && i < num_det; i++) {
5897 /*
5898 * If we are here, means none of the all
5899 * measurements are fake, continue plug type detection.
5900 * If all three measurements do not produce same
5901 * plug type, restart insertion detection
5902 */
Joonwoo Park03324832012-03-19 19:36:16 -07005903 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
5904 plug_type[i] = PLUG_TYPE_HEADPHONE;
5905 pr_debug("%s: Detect attempt %d, detected Headphone\n",
5906 __func__, i);
5907 } else {
5908 plug_type[i] = PLUG_TYPE_HEADSET;
5909 pr_debug("%s: Detect attempt %d, detected Headset\n",
5910 __func__, i);
5911 }
5912
5913 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
5914 pr_err("%s: Detect attempt %d and %d are not same",
5915 __func__, i - 1, i);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005916 inval = true;
5917 break;
Joonwoo Park03324832012-03-19 19:36:16 -07005918 }
5919 }
5920
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005921 if (inval) {
5922 pr_debug("%s: Invalid plug type detected\n", __func__);
5923 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
5924 0x02, 0x02);
5925 tabla_codec_cleanup_hs_polling(codec);
5926 tabla_codec_enable_hs_detect(codec, 1,
5927 MBHC_USE_MB_TRIGGER |
5928 MBHC_USE_HPHL_TRIGGER, false);
5929 } else if (plug_type[0] == PLUG_TYPE_HEADPHONE) {
Joonwoo Park03324832012-03-19 19:36:16 -07005930 pr_debug("%s: Headphone Detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005931 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5932 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005933 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005934 } else if (plug_type[0] == PLUG_TYPE_HEADSET) {
5935 pr_debug("%s: Headset detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005936 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5937
Joonwoo Park03324832012-03-19 19:36:16 -07005938 /* avoid false button press detect */
5939 msleep(50);
Joonwoo Park03324832012-03-19 19:36:16 -07005940 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005941 }
5942}
5943
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005944/* called only from interrupt which is under codec_resource_lock acquisition */
5945static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005946{
Bradley Rubincb1e2732011-06-23 16:49:20 -07005947 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005948
5949 if (!is_removal) {
5950 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
5951
5952 rmb();
5953 if (priv->lpi_enabled)
5954 msleep(100);
5955
5956 rmb();
5957 if (!priv->lpi_enabled) {
5958 pr_debug("%s: lpi is disabled\n", __func__);
5959 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
5960 priv->mbhc_cfg.gpio_level_insert) {
5961 pr_debug("%s: Valid insertion, "
5962 "detect plug type\n", __func__);
5963 tabla_codec_decide_gpio_plug(codec);
5964 } else {
5965 pr_debug("%s: Invalid insertion, "
5966 "stop plug detection\n", __func__);
5967 }
5968 } else {
5969 pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
5970 }
5971}
5972
5973/* called only from interrupt which is under codec_resource_lock acquisition */
5974static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
5975 bool is_mb_trigger)
5976{
Joonwoo Park03324832012-03-19 19:36:16 -07005977 int ret;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005978 struct snd_soc_codec *codec = priv->codec;
5979 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005980
5981 if (is_removal) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005982 /* cancel possiblely running hs detect work */
5983 tabla_cancel_hs_detect_plug(priv);
5984
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005985 /*
5986 * If headphone is removed while playback is in progress,
5987 * it is possible that micbias will be switched to VDDIO.
5988 */
Joonwoo Park03324832012-03-19 19:36:16 -07005989 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005990 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005991 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005992 tabla_codec_enable_hs_detect(codec, 1,
5993 MBHC_USE_MB_TRIGGER |
5994 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07005995 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005996 } else if (is_mb_trigger && !is_removal) {
Joonwoo Park03324832012-03-19 19:36:16 -07005997 pr_debug("%s: Waiting for Headphone left trigger\n",
5998 __func__);
5999 wcd9xxx_lock_sleep(core);
6000 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
6001 usecs_to_jiffies(1000000)) == 0) {
6002 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
6003 __func__);
6004 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08006005 }
Joonwoo Park03324832012-03-19 19:36:16 -07006006 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
6007 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006008 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006009 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
6010 if (ret != 0) {
6011 pr_debug("%s: Complete plug insertion, Detecting plug "
6012 "type\n", __func__);
6013 tabla_codec_detect_plug_type(codec);
6014 wcd9xxx_unlock_sleep(core);
6015 } else {
6016 wcd9xxx_enable_irq(codec->control_data,
6017 TABLA_IRQ_MBHC_INSERTION);
6018 pr_err("%s: Error detecting plug insertion\n",
6019 __func__);
6020 }
Joonwoo Park03324832012-03-19 19:36:16 -07006021 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006022}
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08006023
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006024static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
6025{
6026 bool is_mb_trigger, is_removal;
6027 struct tabla_priv *priv = data;
6028 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07006029
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006030 pr_debug("%s: enter\n", __func__);
6031 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
6032 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
6033
6034 is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
6035 0x10);
6036 is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
6037 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
6038
6039 /* Turn off both HPH and MIC line schmitt triggers */
6040 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6041 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
6042 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6043
6044 if (priv->mbhc_cfg.gpio)
6045 tabla_hs_insert_irq_gpio(priv, is_removal);
6046 else
6047 tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
6048
6049 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006050 return IRQ_HANDLED;
6051}
6052
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006053static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
6054{
6055 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006056 const struct tabla_mbhc_plug_type_cfg *plug_type =
6057 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
6058 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006059
6060 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006061 && (mic_mv < v_hs_max)) ? true : false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006062}
6063
6064/* called under codec_resource_lock acquisition
6065 * returns true if mic voltage range is back to normal insertion
6066 * returns false either if timedout or removed */
6067static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
6068{
6069 int i;
6070 bool timedout, settled = false;
6071 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
6072 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
6073 unsigned long retry = 0, timeout;
6074 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006075 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006076
6077 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
6078 while (!(timedout = time_after(jiffies, timeout))) {
6079 retry++;
6080 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6081 pr_debug("%s: GPIO indicates removal\n", __func__);
6082 break;
6083 }
6084
6085 if (tabla->mbhc_cfg.gpio) {
6086 if (retry > 1)
6087 msleep(250);
6088 else
6089 msleep(50);
6090 }
6091
6092 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6093 pr_debug("%s: GPIO indicates removal\n", __func__);
6094 break;
6095 }
6096
6097 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
6098 mb_v[i] = tabla_codec_sta_dce(codec, 1, true);
6099 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
6100 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
6101 __func__, retry, mic_mv[i], mb_v[i]);
6102 }
6103
6104 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6105 pr_debug("%s: GPIO indicates removal\n", __func__);
6106 break;
6107 }
6108
6109 if (tabla->current_plug == PLUG_TYPE_NONE) {
6110 pr_debug("%s : headset/headphone is removed\n",
6111 __func__);
6112 break;
6113 }
6114
6115 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
6116 if (!is_valid_mic_voltage(codec, mic_mv[i]))
6117 break;
6118
6119 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6120 pr_debug("%s: MIC voltage settled\n", __func__);
6121 settled = true;
6122 msleep(200);
6123 break;
6124 }
6125
6126 /* only for non-GPIO remove irq */
6127 if (!tabla->mbhc_cfg.gpio) {
6128 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006129 if (mic_mv[i] < v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006130 break;
6131 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6132 pr_debug("%s: Headset is removed\n", __func__);
6133 break;
6134 }
6135 }
6136 }
6137
6138 if (timedout)
6139 pr_debug("%s: Microphone did not settle in %d seconds\n",
6140 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
6141 return settled;
6142}
6143
6144/* called only from interrupt which is under codec_resource_lock acquisition */
6145static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
6146{
6147 struct snd_soc_codec *codec = priv->codec;
6148
6149 if (tabla_hs_remove_settle(codec))
6150 tabla_codec_start_hs_polling(codec);
6151 pr_debug("%s: remove settle done\n", __func__);
6152}
6153
6154/* called only from interrupt which is under codec_resource_lock acquisition */
6155static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006156{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006157 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006158 bool removed = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006159 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08006160 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006161 TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006162 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006163
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006164 if (priv->current_plug != PLUG_TYPE_HEADSET) {
6165 pr_debug("%s(): Headset is not inserted, ignore removal\n",
6166 __func__);
6167 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6168 0x08, 0x08);
6169 return;
6170 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006171
Joonwoo Park0976d012011-12-22 11:48:18 -08006172 usleep_range(generic->t_shutdown_plug_rem,
6173 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006174
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006175 do {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006176 bias_value = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006177 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
6178 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006179 if (bias_value < tabla_get_current_v_ins(priv, false)) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006180 pr_debug("%s: checking false removal\n", __func__);
6181 msleep(500);
6182 removed = !tabla_hs_remove_settle(codec);
6183 pr_debug("%s: headset %sactually removed\n", __func__,
6184 removed ? "" : "not ");
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006185 break;
6186 }
6187 min_us -= priv->mbhc_data.t_dce;
6188 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07006189
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006190 if (removed) {
6191 /* cancel possiblely running hs detect work */
6192 tabla_cancel_hs_detect_plug(priv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006193 /*
6194 * If this removal is not false, first check the micbias
6195 * switch status and switch it to LDOH if it is already
6196 * switched to VDDIO.
6197 */
Joonwoo Park03324832012-03-19 19:36:16 -07006198 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07006199
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006200 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6201 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006202 tabla_codec_enable_hs_detect(codec, 1,
6203 MBHC_USE_MB_TRIGGER |
6204 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07006205 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006206 } else {
6207 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006208 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006209}
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006210
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006211static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
6212{
6213 struct tabla_priv *priv = data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006214 bool vddio;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006215 pr_debug("%s: enter, removal interrupt\n", __func__);
6216
6217 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006218 vddio = (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
6219 priv->mbhc_micbias_switched);
6220 if (vddio)
6221 __tabla_codec_switch_micbias(priv->codec, 0, false, true);
6222
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006223 if (priv->mbhc_cfg.gpio)
6224 tabla_hs_remove_irq_gpio(priv);
6225 else
6226 tabla_hs_remove_irq_nogpio(priv);
6227
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006228 /* if driver turned off vddio switch and headset is not removed,
6229 * turn on the vddio switch back, if headset is removed then vddio
6230 * switch is off by time now and shouldn't be turn on again from here */
6231 if (vddio && priv->current_plug == PLUG_TYPE_HEADSET)
6232 __tabla_codec_switch_micbias(priv->codec, 1, true, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006233 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006234
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006235 return IRQ_HANDLED;
6236}
6237
Joonwoo Park03324832012-03-19 19:36:16 -07006238void mbhc_insert_work(struct work_struct *work)
6239{
6240 struct delayed_work *dwork;
6241 struct tabla_priv *tabla;
6242 struct snd_soc_codec *codec;
6243 struct wcd9xxx *tabla_core;
6244
6245 dwork = to_delayed_work(work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006246 tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
Joonwoo Park03324832012-03-19 19:36:16 -07006247 codec = tabla->codec;
6248 tabla_core = dev_get_drvdata(codec->dev->parent);
6249
6250 pr_debug("%s:\n", __func__);
6251
6252 /* Turn off both HPH and MIC line schmitt triggers */
6253 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6254 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
6255 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6256 wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
6257 tabla_codec_detect_plug_type(codec);
6258 wcd9xxx_unlock_sleep(tabla_core);
6259}
6260
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006261static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
6262{
6263 bool insert;
6264 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6265 bool is_removed = false;
6266
6267 pr_debug("%s: enter\n", __func__);
6268
6269 tabla->in_gpio_handler = true;
6270 /* Wait here for debounce time */
6271 usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
6272 TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
6273
6274 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
6275
6276 /* cancel pending button press */
6277 if (tabla_cancel_btn_work(tabla))
6278 pr_debug("%s: button press is canceled\n", __func__);
6279
6280 insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
6281 tabla->mbhc_cfg.gpio_level_insert);
6282 if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
6283 tabla->lpi_enabled = false;
6284 wmb();
6285
6286 /* cancel detect plug */
6287 tabla_cancel_hs_detect_plug(tabla);
6288
6289 /* Disable Mic Bias pull down and HPH Switch to GND */
6290 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
6291 0x00);
6292 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
6293 tabla_codec_detect_plug_type(codec);
6294 } else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
6295 tabla->lpi_enabled = false;
6296 wmb();
6297
6298 /* cancel detect plug */
6299 tabla_cancel_hs_detect_plug(tabla);
6300
6301 if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
6302 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
6303 is_removed = true;
6304 } else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
6305 tabla_codec_pause_hs_polling(codec);
6306 tabla_codec_cleanup_hs_polling(codec);
6307 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6308 is_removed = true;
6309 }
6310
6311 if (is_removed) {
6312 /* Enable Mic Bias pull down and HPH Switch to GND */
6313 snd_soc_update_bits(codec,
6314 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6315 0x01);
6316 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6317 0x01);
6318 /* Make sure mic trigger is turned off */
6319 snd_soc_update_bits(codec,
6320 tabla->mbhc_bias_regs.ctl_reg,
6321 0x01, 0x01);
6322 snd_soc_update_bits(codec,
6323 tabla->mbhc_bias_regs.mbhc_reg,
6324 0x90, 0x00);
6325 /* Reset MBHC State Machine */
6326 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6327 0x08, 0x08);
6328 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6329 0x08, 0x00);
6330 /* Turn off override */
6331 tabla_turn_onoff_override(codec, false);
6332 }
6333 }
6334
6335 tabla->in_gpio_handler = false;
6336 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6337 pr_debug("%s: leave\n", __func__);
6338}
6339
6340static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
6341{
6342 int r = IRQ_HANDLED;
6343 struct snd_soc_codec *codec = data;
6344
6345 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
6346 pr_warn("%s: failed to hold suspend\n", __func__);
6347 r = IRQ_NONE;
6348 } else {
6349 tabla_hs_gpio_handler(codec);
6350 wcd9xxx_unlock_sleep(codec->control_data);
6351 }
6352
6353 return r;
6354}
6355
6356static void mbhc_fw_read(struct work_struct *work)
6357{
6358 struct delayed_work *dwork;
6359 struct tabla_priv *tabla;
6360 struct snd_soc_codec *codec;
6361 const struct firmware *fw;
6362 int ret = -1, retry = 0, rc;
6363
6364 dwork = to_delayed_work(work);
6365 tabla = container_of(dwork, struct tabla_priv,
6366 mbhc_firmware_dwork);
6367 codec = tabla->codec;
6368
6369 while (retry < MBHC_FW_READ_ATTEMPTS) {
6370 retry++;
6371 pr_info("%s:Attempt %d to request MBHC firmware\n",
6372 __func__, retry);
6373 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
6374 codec->dev);
6375
6376 if (ret != 0) {
6377 usleep_range(MBHC_FW_READ_TIMEOUT,
6378 MBHC_FW_READ_TIMEOUT);
6379 } else {
6380 pr_info("%s: MBHC Firmware read succesful\n", __func__);
6381 break;
6382 }
6383 }
6384
6385 if (ret != 0) {
6386 pr_err("%s: Cannot load MBHC firmware use default cal\n",
6387 __func__);
6388 } else if (tabla_mbhc_fw_validate(fw) == false) {
6389 pr_err("%s: Invalid MBHC cal data size use default cal\n",
6390 __func__);
6391 release_firmware(fw);
6392 } else {
6393 tabla->mbhc_cfg.calibration = (void *)fw->data;
6394 tabla->mbhc_fw = fw;
6395 }
6396
6397 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
6398 tabla_mbhc_init(codec);
6399 tabla_mbhc_cal(codec);
6400 tabla_mbhc_calc_thres(codec);
6401 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
6402 tabla_codec_calibrate_hs_polling(codec);
6403 if (!tabla->mbhc_cfg.gpio) {
6404 tabla->mbhc_inval_hs_range_override = false;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006405 rc = tabla_codec_enable_hs_detect(codec, 1,
6406 MBHC_USE_MB_TRIGGER |
6407 MBHC_USE_HPHL_TRIGGER,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006408 false);
6409
6410 if (IS_ERR_VALUE(rc))
6411 pr_err("%s: Failed to setup MBHC detection\n",
6412 __func__);
6413 } else {
6414 tabla->mbhc_inval_hs_range_override = true;
6415 /* Enable Mic Bias pull down and HPH Switch to GND */
6416 snd_soc_update_bits(codec,
6417 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6418 0x01);
6419 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6420 0x01);
6421 INIT_WORK(&tabla->hs_correct_plug_work,
6422 tabla_hs_correct_gpio_plug);
6423 }
6424
6425}
6426
Joonwoo Park03324832012-03-19 19:36:16 -07006427int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006428 const struct tabla_mbhc_config *cfg)
Joonwoo Park03324832012-03-19 19:36:16 -07006429{
6430 struct tabla_priv *tabla;
6431 int rc = 0;
6432
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006433 if (!codec || !cfg->calibration) {
Joonwoo Park03324832012-03-19 19:36:16 -07006434 pr_err("Error: no codec or calibration\n");
6435 return -EINVAL;
6436 }
6437
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006438 if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
6439 if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Joonwoo Park03324832012-03-19 19:36:16 -07006440 pr_err("Error: clock rate %dHz is not yet supported\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006441 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006442 else
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006443 pr_err("Error: unsupported clock rate %d\n",
6444 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006445 return -EINVAL;
6446 }
6447
6448 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006449 tabla->mbhc_cfg = *cfg;
6450 tabla->in_gpio_handler = false;
6451 tabla->current_plug = PLUG_TYPE_NONE;
6452 tabla->lpi_enabled = false;
Joonwoo Park03324832012-03-19 19:36:16 -07006453 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
6454
6455 /* Put CFILT in fast mode by default */
6456 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
6457 0x40, TABLA_CFILT_FAST_MODE);
6458 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
6459 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
6460 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
6461 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
6462 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
6463
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006464 if (!tabla->mbhc_cfg.read_fw_bin) {
6465 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006466 tabla_mbhc_init(codec);
6467 tabla_mbhc_cal(codec);
6468 tabla_mbhc_calc_thres(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006469 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006470 tabla_codec_calibrate_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006471 if (!tabla->mbhc_cfg.gpio) {
6472 tabla->mbhc_inval_hs_range_override = false;
6473 rc = tabla_codec_enable_hs_detect(codec, 1,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006474 MBHC_USE_MB_TRIGGER |
6475 MBHC_USE_HPHL_TRIGGER,
6476 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006477 } else {
6478 tabla->mbhc_inval_hs_range_override = true;
6479 /* Enable Mic Bias pull down and HPH Switch to GND */
6480 snd_soc_update_bits(codec,
6481 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6482 0x01);
6483 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6484 0x01);
6485 INIT_WORK(&tabla->hs_correct_plug_work,
6486 tabla_hs_correct_gpio_plug);
6487 }
Joonwoo Park03324832012-03-19 19:36:16 -07006488 } else {
6489 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
6490 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
6491 }
6492
6493 if (!IS_ERR_VALUE(rc)) {
6494 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
6495 wcd9xxx_enable_irq(codec->control_data,
6496 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6497 wcd9xxx_enable_irq(codec->control_data,
6498 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6499 }
6500
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006501 if (!IS_ERR_VALUE(rc) && tabla->mbhc_cfg.gpio) {
6502 rc = request_threaded_irq(tabla->mbhc_cfg.gpio_irq, NULL,
6503 tabla_mechanical_plug_detect_irq,
6504 (IRQF_TRIGGER_RISING |
6505 IRQF_TRIGGER_FALLING),
6506 "tabla-gpio", codec);
6507 if (!IS_ERR_VALUE(rc)) {
6508 rc = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
6509 /* Bootup time detection */
6510 tabla_hs_gpio_handler(codec);
6511 }
6512 }
6513
Joonwoo Park03324832012-03-19 19:36:16 -07006514 return rc;
6515}
6516EXPORT_SYMBOL_GPL(tabla_hs_detect);
6517
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006518static unsigned long slimbus_value;
6519
6520static irqreturn_t tabla_slimbus_irq(int irq, void *data)
6521{
6522 struct tabla_priv *priv = data;
6523 struct snd_soc_codec *codec = priv->codec;
6524 int i, j;
6525 u8 val;
6526
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306527 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
6528 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006529 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
6530 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306531 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006532 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
6533 if (val & 0x1)
6534 pr_err_ratelimited("overflow error on port %x,"
6535 " value %x\n", i*8 + j, val);
6536 if (val & 0x2)
6537 pr_err_ratelimited("underflow error on port %x,"
6538 " value %x\n", i*8 + j, val);
6539 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306540 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006541 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
6542 }
6543
6544 return IRQ_HANDLED;
6545}
6546
Patrick Lai3043fba2011-08-01 14:15:57 -07006547
6548static int tabla_handle_pdata(struct tabla_priv *tabla)
6549{
6550 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306551 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07006552 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05306553 u8 leg_mode = pdata->amic_settings.legacy_mode;
6554 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
6555 u8 txfe_buff = pdata->amic_settings.txfe_buff;
6556 u8 flag = pdata->amic_settings.use_pdata;
6557 u8 i = 0, j = 0;
6558 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07006559
6560 if (!pdata) {
6561 rc = -ENODEV;
6562 goto done;
6563 }
6564
6565 /* Make sure settings are correct */
6566 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
6567 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
6568 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
6569 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
6570 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
6571 rc = -EINVAL;
6572 goto done;
6573 }
6574
6575 /* figure out k value */
6576 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
6577 pdata->micbias.cfilt1_mv);
6578 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
6579 pdata->micbias.cfilt2_mv);
6580 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
6581 pdata->micbias.cfilt3_mv);
6582
6583 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
6584 rc = -EINVAL;
6585 goto done;
6586 }
6587
6588 /* Set voltage level and always use LDO */
6589 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
6590 (pdata->micbias.ldoh_v << 2));
6591
6592 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
6593 (k1 << 2));
6594 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
6595 (k2 << 2));
6596 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
6597 (k3 << 2));
6598
6599 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
6600 (pdata->micbias.bias1_cfilt_sel << 5));
6601 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
6602 (pdata->micbias.bias2_cfilt_sel << 5));
6603 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
6604 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006605 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
6606 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07006607
Santosh Mardi22920282011-10-26 02:38:40 +05306608 for (i = 0; i < 6; j++, i += 2) {
6609 if (flag & (0x01 << i)) {
6610 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
6611 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
6612 val_txfe = val_txfe |
6613 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
6614 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6615 0x10, value);
6616 snd_soc_update_bits(codec,
6617 TABLA_A_TX_1_2_TEST_EN + j * 10,
6618 0x30, val_txfe);
6619 }
6620 if (flag & (0x01 << (i + 1))) {
6621 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
6622 val_txfe = (txfe_bypass &
6623 (0x01 << (i + 1))) ? 0x02 : 0x00;
6624 val_txfe |= (txfe_buff &
6625 (0x01 << (i + 1))) ? 0x01 : 0x00;
6626 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6627 0x01, value);
6628 snd_soc_update_bits(codec,
6629 TABLA_A_TX_1_2_TEST_EN + j * 10,
6630 0x03, val_txfe);
6631 }
6632 }
6633 if (flag & 0x40) {
6634 value = (leg_mode & 0x40) ? 0x10 : 0x00;
6635 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
6636 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
6637 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
6638 0x13, value);
6639 }
Patrick Lai49efeac2011-11-03 11:01:12 -07006640
6641 if (pdata->ocp.use_pdata) {
6642 /* not defined in CODEC specification */
6643 if (pdata->ocp.hph_ocp_limit == 1 ||
6644 pdata->ocp.hph_ocp_limit == 5) {
6645 rc = -EINVAL;
6646 goto done;
6647 }
6648 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
6649 0x0F, pdata->ocp.num_attempts);
6650 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
6651 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
6652 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
6653 0xE0, (pdata->ocp.hph_ocp_limit << 5));
6654 }
Joonwoo Park03324832012-03-19 19:36:16 -07006655
6656 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
6657 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
6658 if (pdata->regulator[i].min_uV == 1800000 &&
6659 pdata->regulator[i].max_uV == 1800000) {
6660 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6661 0x1C);
6662 } else if (pdata->regulator[i].min_uV == 2200000 &&
6663 pdata->regulator[i].max_uV == 2200000) {
6664 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
6665 0x1E);
6666 } else {
6667 pr_err("%s: unsupported CDC_VDDA_RX voltage "
6668 "min %d, max %d\n", __func__,
6669 pdata->regulator[i].min_uV,
6670 pdata->regulator[i].max_uV);
6671 rc = -EINVAL;
6672 }
6673 break;
6674 }
6675 }
Patrick Lai3043fba2011-08-01 14:15:57 -07006676done:
6677 return rc;
6678}
6679
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006680static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
6681
6682 /* Tabla 1.1 MICBIAS changes */
6683 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
6684 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
6685 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006686
6687 /* Tabla 1.1 HPH changes */
6688 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
6689 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
6690
6691 /* Tabla 1.1 EAR PA changes */
6692 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
6693 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
6694 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
6695
6696 /* Tabla 1.1 Lineout_5 Changes */
6697 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
6698
6699 /* Tabla 1.1 RX Changes */
6700 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
6701 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
6702 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
6703 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
6704 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
6705 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
6706 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
6707
6708 /* Tabla 1.1 RX1 and RX2 Changes */
6709 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
6710 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
6711
6712 /* Tabla 1.1 RX3 to RX7 Changes */
6713 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
6714 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
6715 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
6716 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
6717 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
6718
6719 /* Tabla 1.1 CLASSG Changes */
6720 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
6721};
6722
6723static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006724 /* Tabla 2.0 MICBIAS changes */
6725 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
6726};
6727
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006728static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
6729 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
6730};
6731
6732static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
6733 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
6734};
6735
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006736static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
6737{
6738 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306739 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006740
6741 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
6742 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
6743 tabla_1_1_reg_defaults[i].val);
6744
6745 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
6746 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
6747 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006748
6749 if (TABLA_IS_1_X(tabla_core->version)) {
6750 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
6751 i++)
6752 snd_soc_write(codec,
6753 tabla_1_x_only_reg_2_0_defaults[i].reg,
6754 tabla_1_x_only_reg_2_0_defaults[i].val);
6755 } else {
6756 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
6757 snd_soc_write(codec,
6758 tabla_2_only_reg_2_0_defaults[i].reg,
6759 tabla_2_only_reg_2_0_defaults[i].val);
6760 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006761}
6762
6763static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08006764 /* Initialize current threshold to 350MA
6765 * number of wait and run cycles to 4096
6766 */
Patrick Lai49efeac2011-11-03 11:01:12 -07006767 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08006768 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006769
Santosh Mardi32171012011-10-28 23:32:06 +05306770 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
6771
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006772 /* Initialize gain registers to use register gain */
6773 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
6774 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
6775 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
6776 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
6777 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
6778 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
6779
6780 /* Initialize mic biases to differential mode */
6781 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
6782 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
6783 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006784
6785 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
6786
6787 /* Use 16 bit sample size for TX1 to TX6 */
6788 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
6789 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
6790 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
6791 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
6792 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
6793 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
6794
6795 /* Use 16 bit sample size for TX7 to TX10 */
6796 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
6797 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
6798 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
6799 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
6800
6801 /* Use 16 bit sample size for RX */
6802 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
6803 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
6804
6805 /*enable HPF filter for TX paths */
6806 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
6807 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
6808 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
6809 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
6810 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
6811 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
6812 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
6813 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
6814 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
6815 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
6816};
6817
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006818static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
6819 /* Initialize mic biases to differential mode */
6820 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6821};
6822
6823static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
6824 /* Initialize mic biases to differential mode */
6825 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
6826};
6827
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006828static void tabla_codec_init_reg(struct snd_soc_codec *codec)
6829{
6830 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306831 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006832
6833 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
6834 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
6835 tabla_codec_reg_init_val[i].mask,
6836 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006837 if (TABLA_IS_1_X(tabla_core->version)) {
6838 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
6839 snd_soc_update_bits(codec,
6840 tabla_1_x_codec_reg_init_val[i].reg,
6841 tabla_1_x_codec_reg_init_val[i].mask,
6842 tabla_1_x_codec_reg_init_val[i].val);
6843 } else {
6844 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
6845 i++)
6846 snd_soc_update_bits(codec,
6847 tabla_2_higher_codec_reg_init_val[i].reg,
6848 tabla_2_higher_codec_reg_init_val[i].mask,
6849 tabla_2_higher_codec_reg_init_val[i].val);
6850 }
6851}
6852
6853static void tabla_update_reg_address(struct tabla_priv *priv)
6854{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306855 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006856 struct tabla_reg_address *reg_addr = &priv->reg_addr;
6857
6858 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006859 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
6860 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006861 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006862 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08006863 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
6864 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006865 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006866 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07006867}
6868
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006869#ifdef CONFIG_DEBUG_FS
6870static int codec_debug_open(struct inode *inode, struct file *file)
6871{
6872 file->private_data = inode->i_private;
6873 return 0;
6874}
6875
6876static ssize_t codec_debug_write(struct file *filp,
6877 const char __user *ubuf, size_t cnt, loff_t *ppos)
6878{
6879 char lbuf[32];
6880 char *buf;
6881 int rc;
6882 struct tabla_priv *tabla = filp->private_data;
6883
6884 if (cnt > sizeof(lbuf) - 1)
6885 return -EINVAL;
6886
6887 rc = copy_from_user(lbuf, ubuf, cnt);
6888 if (rc)
6889 return -EFAULT;
6890
6891 lbuf[cnt] = '\0';
6892 buf = (char *)lbuf;
6893 tabla->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
6894 false : true;
6895 return rc;
6896}
6897
6898static ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
6899 size_t count, loff_t *pos)
6900{
6901 const int size = 768;
6902 char buffer[size];
6903 int n = 0;
6904 struct tabla_priv *tabla = file->private_data;
6905 struct snd_soc_codec *codec = tabla->codec;
6906 const struct mbhc_internal_cal_data *p = &tabla->mbhc_data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006907 const s16 v_ins_hu_cur = tabla_get_current_v_ins(tabla, true);
6908 const s16 v_ins_h_cur = tabla_get_current_v_ins(tabla, false);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006909
6910 n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
6911 tabla_codec_sta_dce_v(codec, 1, p->dce_z));
6912 n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
6913 p->dce_mb, tabla_codec_sta_dce_v(codec, 1, p->dce_mb));
6914 n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
6915 p->sta_z, tabla_codec_sta_dce_v(codec, 0, p->sta_z));
6916 n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
6917 p->sta_mb, tabla_codec_sta_dce_v(codec, 0, p->sta_mb));
6918 n += scnprintf(buffer + n, size - n, "t_dce = %x\n", p->t_dce);
6919 n += scnprintf(buffer + n, size - n, "t_sta = %x\n", p->t_sta);
6920 n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
6921 p->micb_mv);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006922 n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006923 p->v_ins_hu,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006924 tabla_codec_sta_dce_v(codec, 0, p->v_ins_hu),
6925 p->v_ins_hu == v_ins_hu_cur ? "*" : "");
6926 n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
6927 p->v_ins_h, tabla_codec_sta_dce_v(codec, 1, p->v_ins_h),
6928 p->v_ins_h == v_ins_h_cur ? "*" : "");
6929 n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
6930 p->adj_v_ins_hu,
6931 tabla_codec_sta_dce_v(codec, 0, p->adj_v_ins_hu),
6932 p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
6933 n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
6934 p->adj_v_ins_h,
6935 tabla_codec_sta_dce_v(codec, 1, p->adj_v_ins_h),
6936 p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006937 n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
6938 p->v_b1_hu, tabla_codec_sta_dce_v(codec, 0, p->v_b1_hu));
6939 n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
6940 p->v_b1_h, tabla_codec_sta_dce_v(codec, 1, p->v_b1_h));
6941 n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
6942 p->v_b1_huc,
6943 tabla_codec_sta_dce_v(codec, 1, p->v_b1_huc));
6944 n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
6945 p->v_brh, tabla_codec_sta_dce_v(codec, 1, p->v_brh));
6946 n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
6947 tabla_codec_sta_dce_v(codec, 0, p->v_brl));
6948 n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
6949 p->v_no_mic,
6950 tabla_codec_sta_dce_v(codec, 0, p->v_no_mic));
6951 n += scnprintf(buffer + n, size - n, "npoll = %d\n", p->npoll);
6952 n += scnprintf(buffer + n, size - n, "nbounce_wait = %d\n",
6953 p->nbounce_wait);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006954 n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
6955 p->v_inval_ins_low);
6956 n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
6957 p->v_inval_ins_high);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07006958 buffer[n] = 0;
6959
6960 return simple_read_from_buffer(buf, count, pos, buffer, n);
6961}
6962
6963static const struct file_operations codec_debug_ops = {
6964 .open = codec_debug_open,
6965 .write = codec_debug_write,
6966};
6967
6968static const struct file_operations codec_mbhc_debug_ops = {
6969 .open = codec_debug_open,
6970 .read = codec_mbhc_debug_read,
6971};
6972#endif
6973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006974static int tabla_codec_probe(struct snd_soc_codec *codec)
6975{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306976 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006977 struct tabla_priv *tabla;
6978 struct snd_soc_dapm_context *dapm = &codec->dapm;
6979 int ret = 0;
6980 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08006981 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006982
6983 codec->control_data = dev_get_drvdata(codec->dev->parent);
6984 control = codec->control_data;
6985
6986 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
6987 if (!tabla) {
6988 dev_err(codec->dev, "Failed to allocate private data\n");
6989 return -ENOMEM;
6990 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08006991 for (i = 0 ; i < NUM_DECIMATORS; i++) {
6992 tx_hpf_work[i].tabla = tabla;
6993 tx_hpf_work[i].decimator = i + 1;
6994 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
6995 tx_hpf_corner_freq_callback);
6996 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006997
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006998 /* Make sure mbhc micbias register addresses are zeroed out */
6999 memset(&tabla->mbhc_bias_regs, 0,
7000 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07007001 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07007002
Joonwoo Park0976d012011-12-22 11:48:18 -08007003 /* Make sure mbhc intenal calibration data is zeroed out */
7004 memset(&tabla->mbhc_data, 0,
7005 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08007006 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08007007 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
7008 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007009 snd_soc_codec_set_drvdata(codec, tabla);
7010
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07007011 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007012 tabla->bandgap_type = TABLA_BANDGAP_OFF;
7013 tabla->clock_active = false;
7014 tabla->config_mode_active = false;
7015 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08007016 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07007017 tabla->no_mic_headset_override = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007018 tabla->hs_polling_irq_prepared = false;
7019 mutex_init(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007020 tabla->codec = codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007021 tabla->mbhc_state = MBHC_STATE_NONE;
Joonwoo Park03324832012-03-19 19:36:16 -07007022 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08007023 for (i = 0; i < COMPANDER_MAX; i++) {
7024 tabla->comp_enabled[i] = 0;
7025 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
7026 }
Patrick Lai3043fba2011-08-01 14:15:57 -07007027 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307028 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08007029 tabla->aux_pga_cnt = 0;
7030 tabla->aux_l_gain = 0x1F;
7031 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007032 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05307033 tabla_update_reg_defaults(codec);
7034 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05307035 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07007036 if (IS_ERR_VALUE(ret)) {
7037 pr_err("%s: bad pdata\n", __func__);
7038 goto err_pdata;
7039 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007040
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007041 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007042 ARRAY_SIZE(tabla_snd_controls));
7043 if (TABLA_IS_1_X(control->version))
7044 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
7045 ARRAY_SIZE(tabla_1_x_snd_controls));
7046 else
7047 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
7048 ARRAY_SIZE(tabla_2_higher_snd_controls));
7049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007050 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007051 ARRAY_SIZE(tabla_dapm_widgets));
7052 if (TABLA_IS_1_X(control->version))
7053 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
7054 ARRAY_SIZE(tabla_1_x_dapm_widgets));
7055 else
7056 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
7057 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
7058
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307059 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05307060 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
7061 ARRAY_SIZE(tabla_dapm_i2s_widgets));
7062 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
7063 ARRAY_SIZE(audio_i2s_map));
7064 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007065 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07007066
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007067 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007068 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007069 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
7070 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007071 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007072 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007073 } else {
7074 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307075 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007076 goto err_pdata;
7077 }
7078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007079 snd_soc_dapm_sync(dapm);
7080
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307081 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007082 tabla_hs_insert_irq, "Headset insert detect", tabla);
7083 if (ret) {
7084 pr_err("%s: Failed to request irq %d\n", __func__,
7085 TABLA_IRQ_MBHC_INSERTION);
7086 goto err_insert_irq;
7087 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307088 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007089
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307090 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007091 tabla_hs_remove_irq, "Headset remove detect", tabla);
7092 if (ret) {
7093 pr_err("%s: Failed to request irq %d\n", __func__,
7094 TABLA_IRQ_MBHC_REMOVAL);
7095 goto err_remove_irq;
7096 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007097
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307098 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007099 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007100 if (ret) {
7101 pr_err("%s: Failed to request irq %d\n", __func__,
7102 TABLA_IRQ_MBHC_POTENTIAL);
7103 goto err_potential_irq;
7104 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007105
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307106 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007107 tabla_release_handler, "Button Release detect", tabla);
7108 if (ret) {
7109 pr_err("%s: Failed to request irq %d\n", __func__,
7110 TABLA_IRQ_MBHC_RELEASE);
7111 goto err_release_irq;
7112 }
7113
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307114 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007115 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
7116 if (ret) {
7117 pr_err("%s: Failed to request irq %d\n", __func__,
7118 TABLA_IRQ_SLIMBUS);
7119 goto err_slimbus_irq;
7120 }
7121
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307122 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
7123 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007124 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
7125
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307126 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007127 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
7128 "HPH_L OCP detect", tabla);
7129 if (ret) {
7130 pr_err("%s: Failed to request irq %d\n", __func__,
7131 TABLA_IRQ_HPH_PA_OCPL_FAULT);
7132 goto err_hphl_ocp_irq;
7133 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307134 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07007135
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307136 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007137 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
7138 "HPH_R OCP detect", tabla);
7139 if (ret) {
7140 pr_err("%s: Failed to request irq %d\n", __func__,
7141 TABLA_IRQ_HPH_PA_OCPR_FAULT);
7142 goto err_hphr_ocp_irq;
7143 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307144 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007145 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
7146 switch (tabla_dai[i].id) {
7147 case AIF1_PB:
7148 ch_cnt = tabla_dai[i].playback.channels_max;
7149 break;
7150 case AIF1_CAP:
7151 ch_cnt = tabla_dai[i].capture.channels_max;
7152 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08007153 case AIF2_PB:
7154 ch_cnt = tabla_dai[i].playback.channels_max;
7155 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007156 default:
7157 continue;
7158 }
7159 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
7160 ch_cnt), GFP_KERNEL);
7161 }
Patrick Lai49efeac2011-11-03 11:01:12 -07007162
Bradley Rubincb3950a2011-08-18 13:07:26 -07007163#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007164 if (ret == 0) {
7165 tabla->debugfs_poke =
7166 debugfs_create_file("TRRS", S_IFREG | S_IRUGO, NULL, tabla,
7167 &codec_debug_ops);
7168 tabla->debugfs_mbhc =
7169 debugfs_create_file("tabla_mbhc", S_IFREG | S_IRUGO,
7170 NULL, tabla, &codec_mbhc_debug_ops);
7171 }
Bradley Rubincb3950a2011-08-18 13:07:26 -07007172#endif
7173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007174 return ret;
7175
Patrick Lai49efeac2011-11-03 11:01:12 -07007176err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307177 wcd9xxx_free_irq(codec->control_data,
7178 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07007179err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307180 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007181err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307182 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07007183err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307184 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007185err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307186 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007187err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307188 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007189err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07007190err_pdata:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007191 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007192 kfree(tabla);
7193 return ret;
7194}
7195static int tabla_codec_remove(struct snd_soc_codec *codec)
7196{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007197 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007198 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307199 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
7200 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
7201 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
7202 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
7203 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007204 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007205 tabla_codec_disable_clock_block(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007206 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007207 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08007208 if (tabla->mbhc_fw)
7209 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007210 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
7211 kfree(tabla->dai[i].ch_num);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007212 mutex_destroy(&tabla->codec_resource_lock);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007213#ifdef CONFIG_DEBUG_FS
7214 debugfs_remove(tabla->debugfs_poke);
7215 debugfs_remove(tabla->debugfs_mbhc);
7216#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007217 kfree(tabla);
7218 return 0;
7219}
7220static struct snd_soc_codec_driver soc_codec_dev_tabla = {
7221 .probe = tabla_codec_probe,
7222 .remove = tabla_codec_remove,
7223 .read = tabla_read,
7224 .write = tabla_write,
7225
7226 .readable_register = tabla_readable,
7227 .volatile_register = tabla_volatile,
7228
7229 .reg_cache_size = TABLA_CACHE_SIZE,
7230 .reg_cache_default = tabla_reg_defaults,
7231 .reg_word_size = 1,
7232};
Bradley Rubincb3950a2011-08-18 13:07:26 -07007233
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007234#ifdef CONFIG_PM
7235static int tabla_suspend(struct device *dev)
7236{
Joonwoo Park816b8e62012-01-23 16:03:21 -08007237 dev_dbg(dev, "%s: system suspend\n", __func__);
7238 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007239}
7240
7241static int tabla_resume(struct device *dev)
7242{
Joonwoo Park03324832012-03-19 19:36:16 -07007243 struct platform_device *pdev = to_platform_device(dev);
7244 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Park816b8e62012-01-23 16:03:21 -08007245 dev_dbg(dev, "%s: system resume\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07007246 tabla->mbhc_last_resume = jiffies;
Joonwoo Park816b8e62012-01-23 16:03:21 -08007247 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007248}
7249
7250static const struct dev_pm_ops tabla_pm_ops = {
7251 .suspend = tabla_suspend,
7252 .resume = tabla_resume,
7253};
7254#endif
7255
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007256static int __devinit tabla_probe(struct platform_device *pdev)
7257{
Santosh Mardie15e2302011-11-15 10:39:23 +05307258 int ret = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307259 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05307260 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7261 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307262 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05307263 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7264 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
7265 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007266}
7267static int __devexit tabla_remove(struct platform_device *pdev)
7268{
7269 snd_soc_unregister_codec(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007270 return 0;
7271}
7272static struct platform_driver tabla_codec_driver = {
7273 .probe = tabla_probe,
7274 .remove = tabla_remove,
7275 .driver = {
7276 .name = "tabla_codec",
7277 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007278#ifdef CONFIG_PM
7279 .pm = &tabla_pm_ops,
7280#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007281 },
7282};
7283
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007284static struct platform_driver tabla1x_codec_driver = {
7285 .probe = tabla_probe,
7286 .remove = tabla_remove,
7287 .driver = {
7288 .name = "tabla1x_codec",
7289 .owner = THIS_MODULE,
7290#ifdef CONFIG_PM
7291 .pm = &tabla_pm_ops,
7292#endif
7293 },
7294};
7295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007296static int __init tabla_codec_init(void)
7297{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007298 int rtn = platform_driver_register(&tabla_codec_driver);
7299 if (rtn == 0) {
7300 rtn = platform_driver_register(&tabla1x_codec_driver);
7301 if (rtn != 0)
7302 platform_driver_unregister(&tabla_codec_driver);
7303 }
7304 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007305}
7306
7307static void __exit tabla_codec_exit(void)
7308{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007309 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007310 platform_driver_unregister(&tabla_codec_driver);
7311}
7312
7313module_init(tabla_codec_init);
7314module_exit(tabla_codec_exit);
7315
7316MODULE_DESCRIPTION("Tabla codec driver");
7317MODULE_VERSION("1.0");
7318MODULE_LICENSE("GPL v2");