blob: 88bdcad9dc83a1d6b224950e4cafe0fceace9843 [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
Kiran Kandi1e6371d2012-03-29 11:48:57 -070037#define WCD9310_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
38 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
39 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
40
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070041
42#define NUM_DECIMATORS 10
43#define NUM_INTERPOLATORS 7
44#define BITS_PER_REG 8
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080045#define TABLA_CFILT_FAST_MODE 0x00
46#define TABLA_CFILT_SLOW_MODE 0x40
Patrick Lai64b43262011-12-06 17:29:15 -080047#define MBHC_FW_READ_ATTEMPTS 15
48#define MBHC_FW_READ_TIMEOUT 2000000
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070049
Joonwoo Park03324832012-03-19 19:36:16 -070050enum {
51 MBHC_USE_HPHL_TRIGGER = 1,
52 MBHC_USE_MB_TRIGGER = 2
53};
54
55#define MBHC_NUM_DCE_PLUG_DETECT 3
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070056#define NUM_ATTEMPTS_INSERT_DETECT 25
57#define NUM_ATTEMPTS_TO_REPORT 5
Joonwoo Park03324832012-03-19 19:36:16 -070058
Joonwoo Park2cc13f02012-05-09 12:44:25 -070059#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
60 SND_JACK_OC_HPHR | SND_JACK_UNSUPPORTED)
Patrick Lai49efeac2011-11-03 11:01:12 -070061
Santosh Mardie15e2302011-11-15 10:39:23 +053062#define TABLA_I2S_MASTER_MODE_MASK 0x08
63
Patrick Laic7cae882011-11-18 11:52:49 -080064#define TABLA_OCP_ATTEMPT 1
65
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080066#define AIF1_PB 1
67#define AIF1_CAP 2
Neema Shettyd3a89262012-02-16 10:23:50 -080068#define AIF2_PB 3
Kiran Kandi1e6371d2012-03-29 11:48:57 -070069#define AIF2_CAP 4
Neema Shetty3fb1b802012-04-27 13:53:24 -070070#define AIF3_CAP 5
Kiran Kandia9fffe92012-05-20 23:42:30 -070071#define AIF3_PB 6
Kiran Kandi1e6371d2012-03-29 11:48:57 -070072
Kiran Kandia9fffe92012-05-20 23:42:30 -070073#define NUM_CODEC_DAIS 6
Kuirong Wang0f8ade32012-02-27 16:29:45 -080074#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080075
76struct tabla_codec_dai_data {
77 u32 rate;
78 u32 *ch_num;
79 u32 ch_act;
80 u32 ch_tot;
81};
82
Joonwoo Park0976d012011-12-22 11:48:18 -080083#define TABLA_MCLK_RATE_12288KHZ 12288000
84#define TABLA_MCLK_RATE_9600KHZ 9600000
85
Joonwoo Parkf4267c22012-01-10 13:25:24 -080086#define TABLA_FAKE_INS_THRESHOLD_MS 2500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -080087#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
Joonwoo Parkf4267c22012-01-10 13:25:24 -080088
Joonwoo Park03324832012-03-19 19:36:16 -070089#define TABLA_MBHC_BUTTON_MIN 0x8000
90
Joonwoo Park03324832012-03-19 19:36:16 -070091#define TABLA_MBHC_FAKE_INSERT_LOW 10
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070092#define TABLA_MBHC_FAKE_INSERT_HIGH 80
93#define TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO 150
Joonwoo Park03324832012-03-19 19:36:16 -070094
95#define TABLA_MBHC_STATUS_REL_DETECTION 0x0C
96
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070097#define TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
98
Joonwoo Parkcf473b42012-03-29 19:48:16 -070099#define TABLA_MBHC_FAKE_INS_DELTA_MV 200
100#define TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV 300
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700101
102#define TABLA_HS_DETECT_PLUG_TIME_MS (5 * 1000)
103#define TABLA_HS_DETECT_PLUG_INERVAL_MS 100
104
105#define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
106
Joonwoo Park2cc13f02012-05-09 12:44:25 -0700107#define TABLA_MBHC_GND_MIC_SWAP_THRESHOLD 2
108
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700109#define TABLA_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
110#define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
111
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
113static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
114static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800115static struct snd_soc_dai_driver tabla_dai[];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800116static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700117
118enum tabla_bandgap_type {
119 TABLA_BANDGAP_OFF = 0,
120 TABLA_BANDGAP_AUDIO_MODE,
121 TABLA_BANDGAP_MBHC_MODE,
122};
123
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700124struct mbhc_micbias_regs {
125 u16 cfilt_val;
126 u16 cfilt_ctl;
127 u16 mbhc_reg;
128 u16 int_rbias;
129 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -0800130 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700131};
132
Ben Romberger1f045a72011-11-04 10:14:57 -0700133/* Codec supports 2 IIR filters */
134enum {
135 IIR1 = 0,
136 IIR2,
137 IIR_MAX,
138};
139/* Codec supports 5 bands */
140enum {
141 BAND1 = 0,
142 BAND2,
143 BAND3,
144 BAND4,
145 BAND5,
146 BAND_MAX,
147};
148
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800149enum {
150 COMPANDER_1 = 0,
151 COMPANDER_2,
152 COMPANDER_MAX,
153};
154
155enum {
156 COMPANDER_FS_8KHZ = 0,
157 COMPANDER_FS_16KHZ,
158 COMPANDER_FS_32KHZ,
159 COMPANDER_FS_48KHZ,
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700160 COMPANDER_FS_96KHZ,
161 COMPANDER_FS_192KHZ,
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800162 COMPANDER_FS_MAX,
163};
164
Joonwoo Parka9444452011-12-08 18:48:27 -0800165/* Flags to track of PA and DAC state.
166 * PA and DAC should be tracked separately as AUXPGA loopback requires
167 * only PA to be turned on without DAC being on. */
168enum tabla_priv_ack_flags {
169 TABLA_HPHL_PA_OFF_ACK = 0,
170 TABLA_HPHR_PA_OFF_ACK,
171 TABLA_HPHL_DAC_OFF_ACK,
172 TABLA_HPHR_DAC_OFF_ACK
173};
174
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800175
176struct comp_sample_dependent_params {
177 u32 peak_det_timeout;
178 u32 rms_meter_div_fact;
179 u32 rms_meter_resamp_fact;
180};
181
Joonwoo Park0976d012011-12-22 11:48:18 -0800182/* Data used by MBHC */
183struct mbhc_internal_cal_data {
184 u16 dce_z;
185 u16 dce_mb;
186 u16 sta_z;
187 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800188 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800189 u32 t_dce;
190 u32 t_sta;
191 u32 micb_mv;
192 u16 v_ins_hu;
193 u16 v_ins_h;
194 u16 v_b1_hu;
195 u16 v_b1_h;
196 u16 v_b1_huc;
197 u16 v_brh;
198 u16 v_brl;
199 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800200 u8 npoll;
201 u8 nbounce_wait;
Joonwoo Parkcf473b42012-03-29 19:48:16 -0700202 s16 adj_v_hs_max;
203 u16 adj_v_ins_hu;
204 u16 adj_v_ins_h;
205 s16 v_inval_ins_low;
206 s16 v_inval_ins_high;
Joonwoo Park0976d012011-12-22 11:48:18 -0800207};
208
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800209struct tabla_reg_address {
210 u16 micb_4_ctl;
211 u16 micb_4_int_rbias;
212 u16 micb_4_mbhc;
213};
214
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700215enum tabla_mbhc_plug_type {
Joonwoo Park41956722012-04-18 13:13:07 -0700216 PLUG_TYPE_INVALID = -1,
217 PLUG_TYPE_NONE,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700218 PLUG_TYPE_HEADSET,
219 PLUG_TYPE_HEADPHONE,
220 PLUG_TYPE_HIGH_HPH,
Joonwoo Park2cc13f02012-05-09 12:44:25 -0700221 PLUG_TYPE_GND_MIC_SWAP,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700222};
223
224enum tabla_mbhc_state {
225 MBHC_STATE_NONE = -1,
226 MBHC_STATE_POTENTIAL,
227 MBHC_STATE_POTENTIAL_RECOVERY,
228 MBHC_STATE_RELEASE,
229};
230
Kiran Kandid8cf5212012-03-02 15:34:53 -0800231struct hpf_work {
232 struct tabla_priv *tabla;
233 u32 decimator;
234 u8 tx_hpf_cut_of_freq;
235 struct delayed_work dwork;
236};
237
238static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
239
Bradley Rubin229c6a52011-07-12 16:18:48 -0700240struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700241 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800242 struct tabla_reg_address reg_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700243 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700244 u32 cfilt1_cnt;
245 u32 cfilt2_cnt;
246 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700247 u32 rx_bias_count;
Kiran Kandi0ba468f2012-05-08 11:45:05 -0700248 s32 dmic_1_2_clk_cnt;
249 s32 dmic_3_4_clk_cnt;
250 s32 dmic_5_6_clk_cnt;
251
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700252 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700253 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254 bool clock_active;
255 bool config_mode_active;
256 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800257 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700258 int buttons_pressed;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700259 enum tabla_mbhc_state mbhc_state;
260 struct tabla_mbhc_config mbhc_cfg;
Joonwoo Park0976d012011-12-22 11:48:18 -0800261 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700262
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530263 struct wcd9xxx_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700264 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700265
266 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700267 /* Delayed work to report long button press */
Joonwoo Park03324832012-03-19 19:36:16 -0700268 struct delayed_work mbhc_btn_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700269
270 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700271 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700272
Joonwoo Parka9444452011-12-08 18:48:27 -0800273 /* track PA/DAC state */
274 unsigned long hph_pa_dac_state;
275
Santosh Mardie15e2302011-11-15 10:39:23 +0530276 /*track tabla interface type*/
277 u8 intf_type;
278
Patrick Lai49efeac2011-11-03 11:01:12 -0700279 u32 hph_status; /* track headhpone status */
280 /* define separate work for left and right headphone OCP to avoid
281 * additional checking on which OCP event to report so no locking
282 * to ensure synchronization is required
283 */
284 struct work_struct hphlocp_work; /* reporting left hph ocp off */
285 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800286
Patrick Laic7cae882011-11-18 11:52:49 -0800287 u8 hphlocp_cnt; /* headphone left ocp retry */
288 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800289
Patrick Lai64b43262011-12-06 17:29:15 -0800290 /* Work to perform MBHC Firmware Read */
291 struct delayed_work mbhc_firmware_dwork;
292 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800293
294 /* num of slim ports required */
295 struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800296
297 /*compander*/
298 int comp_enabled[COMPANDER_MAX];
299 u32 comp_fs[COMPANDER_MAX];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800300
301 /* Maintain the status of AUX PGA */
302 int aux_pga_cnt;
303 u8 aux_l_gain;
304 u8 aux_r_gain;
Joonwoo Park03324832012-03-19 19:36:16 -0700305
Joonwoo Park03324832012-03-19 19:36:16 -0700306 struct delayed_work mbhc_insert_dwork;
307 unsigned long mbhc_last_resume; /* in jiffies */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700308
309 u8 current_plug;
310 struct work_struct hs_correct_plug_work;
311 bool hs_detect_work_stop;
312 bool hs_polling_irq_prepared;
313 bool lpi_enabled; /* low power insertion detection */
314 bool in_gpio_handler;
315 /* Currently, only used for mbhc purpose, to protect
316 * concurrent execution of mbhc threaded irq handlers and
317 * kill race between DAPM and MBHC.But can serve as a
318 * general lock to protect codec resource
319 */
320 struct mutex codec_resource_lock;
321
Bradley Rubincb3950a2011-08-18 13:07:26 -0700322#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700323 struct dentry *debugfs_poke;
324 struct dentry *debugfs_mbhc;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700325#endif
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700326};
327
Bradley Rubincb3950a2011-08-18 13:07:26 -0700328
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800329static const u32 comp_shift[] = {
330 0,
331 2,
332};
333
334static const int comp_rx_path[] = {
335 COMPANDER_1,
336 COMPANDER_1,
337 COMPANDER_2,
338 COMPANDER_2,
339 COMPANDER_2,
340 COMPANDER_2,
341 COMPANDER_MAX,
342};
343
344static const struct comp_sample_dependent_params comp_samp_params[] = {
345 {
346 .peak_det_timeout = 0x2,
347 .rms_meter_div_fact = 0x8 << 4,
348 .rms_meter_resamp_fact = 0x21,
349 },
350 {
351 .peak_det_timeout = 0x3,
352 .rms_meter_div_fact = 0x9 << 4,
353 .rms_meter_resamp_fact = 0x28,
354 },
355
356 {
357 .peak_det_timeout = 0x5,
358 .rms_meter_div_fact = 0xB << 4,
359 .rms_meter_resamp_fact = 0x28,
360 },
361
362 {
363 .peak_det_timeout = 0x5,
364 .rms_meter_div_fact = 0xB << 4,
365 .rms_meter_resamp_fact = 0x28,
366 },
367};
368
Kuirong Wange9c8a222012-03-28 16:24:09 -0700369static unsigned short rx_digital_gain_reg[] = {
370 TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
371 TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
372 TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
373 TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
374 TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
375 TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
376 TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
377};
378
379
380static unsigned short tx_digital_gain_reg[] = {
381 TABLA_A_CDC_TX1_VOL_CTL_GAIN,
382 TABLA_A_CDC_TX2_VOL_CTL_GAIN,
383 TABLA_A_CDC_TX3_VOL_CTL_GAIN,
384 TABLA_A_CDC_TX4_VOL_CTL_GAIN,
385 TABLA_A_CDC_TX5_VOL_CTL_GAIN,
386 TABLA_A_CDC_TX6_VOL_CTL_GAIN,
387 TABLA_A_CDC_TX7_VOL_CTL_GAIN,
388 TABLA_A_CDC_TX8_VOL_CTL_GAIN,
389 TABLA_A_CDC_TX9_VOL_CTL_GAIN,
390 TABLA_A_CDC_TX10_VOL_CTL_GAIN,
391};
392
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700393static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
394 struct snd_kcontrol *kcontrol, int event)
395{
396 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397
398 pr_debug("%s %d\n", __func__, event);
399 switch (event) {
400 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700401 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
402 0x01);
403 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
404 usleep_range(200, 200);
405 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
406 break;
407 case SND_SOC_DAPM_PRE_PMD:
408 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
409 0x10);
410 usleep_range(20, 20);
411 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
412 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
413 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
414 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
415 0x00);
416 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417 break;
418 }
419 return 0;
420}
421
Bradley Rubina7096d02011-08-03 18:29:02 -0700422static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
423 struct snd_ctl_elem_value *ucontrol)
424{
425 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
426 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
427 ucontrol->value.integer.value[0] = tabla->anc_slot;
428 return 0;
429}
430
431static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
432 struct snd_ctl_elem_value *ucontrol)
433{
434 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
435 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
436 tabla->anc_slot = ucontrol->value.integer.value[0];
437 return 0;
438}
439
Kiran Kandid2d86b52011-09-09 17:44:28 -0700440static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
441 struct snd_ctl_elem_value *ucontrol)
442{
443 u8 ear_pa_gain;
444 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
445
446 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
447
448 ear_pa_gain = ear_pa_gain >> 5;
449
450 if (ear_pa_gain == 0x00) {
451 ucontrol->value.integer.value[0] = 0;
452 } else if (ear_pa_gain == 0x04) {
453 ucontrol->value.integer.value[0] = 1;
454 } else {
455 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
456 __func__, ear_pa_gain);
457 return -EINVAL;
458 }
459
460 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
461
462 return 0;
463}
464
465static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
466 struct snd_ctl_elem_value *ucontrol)
467{
468 u8 ear_pa_gain;
469 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
470
471 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
472 ucontrol->value.integer.value[0]);
473
474 switch (ucontrol->value.integer.value[0]) {
475 case 0:
476 ear_pa_gain = 0x00;
477 break;
478 case 1:
479 ear_pa_gain = 0x80;
480 break;
481 default:
482 return -EINVAL;
483 }
484
485 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
486 return 0;
487}
488
Ben Romberger1f045a72011-11-04 10:14:57 -0700489static int tabla_get_iir_enable_audio_mixer(
490 struct snd_kcontrol *kcontrol,
491 struct snd_ctl_elem_value *ucontrol)
492{
493 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
494 int iir_idx = ((struct soc_multi_mixer_control *)
495 kcontrol->private_value)->reg;
496 int band_idx = ((struct soc_multi_mixer_control *)
497 kcontrol->private_value)->shift;
498
499 ucontrol->value.integer.value[0] =
500 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
501 (1 << band_idx);
502
503 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
504 iir_idx, band_idx,
505 (uint32_t)ucontrol->value.integer.value[0]);
506 return 0;
507}
508
509static int tabla_put_iir_enable_audio_mixer(
510 struct snd_kcontrol *kcontrol,
511 struct snd_ctl_elem_value *ucontrol)
512{
513 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
514 int iir_idx = ((struct soc_multi_mixer_control *)
515 kcontrol->private_value)->reg;
516 int band_idx = ((struct soc_multi_mixer_control *)
517 kcontrol->private_value)->shift;
518 int value = ucontrol->value.integer.value[0];
519
520 /* Mask first 5 bits, 6-8 are reserved */
521 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
522 (1 << band_idx), (value << band_idx));
523
524 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
525 iir_idx, band_idx, value);
526 return 0;
527}
528static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
529 int iir_idx, int band_idx,
530 int coeff_idx)
531{
532 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800533 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700534 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800535 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700536
537 /* Mask bits top 2 bits since they are reserved */
538 return ((snd_soc_read(codec,
539 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
540 (snd_soc_read(codec,
541 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
542 (snd_soc_read(codec,
543 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
544 (snd_soc_read(codec,
545 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
546 0x3FFFFFFF;
547}
548
549static int tabla_get_iir_band_audio_mixer(
550 struct snd_kcontrol *kcontrol,
551 struct snd_ctl_elem_value *ucontrol)
552{
553 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
554 int iir_idx = ((struct soc_multi_mixer_control *)
555 kcontrol->private_value)->reg;
556 int band_idx = ((struct soc_multi_mixer_control *)
557 kcontrol->private_value)->shift;
558
559 ucontrol->value.integer.value[0] =
560 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
561 ucontrol->value.integer.value[1] =
562 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
563 ucontrol->value.integer.value[2] =
564 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
565 ucontrol->value.integer.value[3] =
566 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
567 ucontrol->value.integer.value[4] =
568 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
569
570 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
571 "%s: IIR #%d band #%d b1 = 0x%x\n"
572 "%s: IIR #%d band #%d b2 = 0x%x\n"
573 "%s: IIR #%d band #%d a1 = 0x%x\n"
574 "%s: IIR #%d band #%d a2 = 0x%x\n",
575 __func__, iir_idx, band_idx,
576 (uint32_t)ucontrol->value.integer.value[0],
577 __func__, iir_idx, band_idx,
578 (uint32_t)ucontrol->value.integer.value[1],
579 __func__, iir_idx, band_idx,
580 (uint32_t)ucontrol->value.integer.value[2],
581 __func__, iir_idx, band_idx,
582 (uint32_t)ucontrol->value.integer.value[3],
583 __func__, iir_idx, band_idx,
584 (uint32_t)ucontrol->value.integer.value[4]);
585 return 0;
586}
587
588static void set_iir_band_coeff(struct snd_soc_codec *codec,
589 int iir_idx, int band_idx,
590 int coeff_idx, uint32_t value)
591{
592 /* Mask top 3 bits, 6-8 are reserved */
593 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800594 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700595 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800596 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700597
598 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800599 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700600 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800601 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700602
603 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800604 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700605 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800606 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700607
Ben Romberger0915aae2012-02-06 23:32:43 -0800608 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700609 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800610 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700611
Ben Romberger0915aae2012-02-06 23:32:43 -0800612 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700613 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800614 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700615}
616
617static int tabla_put_iir_band_audio_mixer(
618 struct snd_kcontrol *kcontrol,
619 struct snd_ctl_elem_value *ucontrol)
620{
621 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
622 int iir_idx = ((struct soc_multi_mixer_control *)
623 kcontrol->private_value)->reg;
624 int band_idx = ((struct soc_multi_mixer_control *)
625 kcontrol->private_value)->shift;
626
627 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
628 ucontrol->value.integer.value[0]);
629 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
630 ucontrol->value.integer.value[1]);
631 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
632 ucontrol->value.integer.value[2]);
633 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
634 ucontrol->value.integer.value[3]);
635 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
636 ucontrol->value.integer.value[4]);
637
638 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
639 "%s: IIR #%d band #%d b1 = 0x%x\n"
640 "%s: IIR #%d band #%d b2 = 0x%x\n"
641 "%s: IIR #%d band #%d a1 = 0x%x\n"
642 "%s: IIR #%d band #%d a2 = 0x%x\n",
643 __func__, iir_idx, band_idx,
644 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
645 __func__, iir_idx, band_idx,
646 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
647 __func__, iir_idx, band_idx,
648 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
649 __func__, iir_idx, band_idx,
650 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
651 __func__, iir_idx, band_idx,
652 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
653 return 0;
654}
655
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800656static int tabla_compander_gain_offset(
657 struct snd_soc_codec *codec, u32 enable,
658 unsigned int reg, int mask, int event)
659{
660 int pa_mode = snd_soc_read(codec, reg) & mask;
661 int gain_offset = 0;
662 /* if PMU && enable is 1-> offset is 3
663 * if PMU && enable is 0-> offset is 0
664 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
665 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
666 */
667
668 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
669 gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
670 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
671 gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
672 return gain_offset;
673}
674
675
676static int tabla_config_gain_compander(
677 struct snd_soc_codec *codec,
678 u32 compander, u32 enable, int event)
679{
680 int value = 0;
681 int mask = 1 << 4;
682 int gain = 0;
683 int gain_offset;
684 if (compander >= COMPANDER_MAX) {
685 pr_err("%s: Error, invalid compander channel\n", __func__);
686 return -EINVAL;
687 }
688
689 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
690 value = 1 << 4;
691
692 if (compander == COMPANDER_1) {
693 gain_offset = tabla_compander_gain_offset(codec, enable,
694 TABLA_A_RX_HPH_L_GAIN, mask, event);
695 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
696 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
697 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
698 0xFF, gain - gain_offset);
699 gain_offset = tabla_compander_gain_offset(codec, enable,
700 TABLA_A_RX_HPH_R_GAIN, mask, event);
701 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
702 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
703 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
704 0xFF, gain - gain_offset);
705 } else if (compander == COMPANDER_2) {
706 gain_offset = tabla_compander_gain_offset(codec, enable,
707 TABLA_A_RX_LINE_1_GAIN, mask, event);
708 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
709 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
710 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
711 0xFF, gain - gain_offset);
712 gain_offset = tabla_compander_gain_offset(codec, enable,
713 TABLA_A_RX_LINE_3_GAIN, mask, event);
714 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
715 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
716 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
717 0xFF, gain - gain_offset);
718 gain_offset = tabla_compander_gain_offset(codec, enable,
719 TABLA_A_RX_LINE_2_GAIN, mask, event);
720 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
721 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
722 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
723 0xFF, gain - gain_offset);
724 gain_offset = tabla_compander_gain_offset(codec, enable,
725 TABLA_A_RX_LINE_4_GAIN, mask, event);
726 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
727 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
728 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
729 0xFF, gain - gain_offset);
730 }
731 return 0;
732}
733static int tabla_get_compander(struct snd_kcontrol *kcontrol,
734 struct snd_ctl_elem_value *ucontrol)
735{
736
737 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
738 int comp = ((struct soc_multi_mixer_control *)
739 kcontrol->private_value)->max;
740 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
741
742 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
743
744 return 0;
745}
746
747static int tabla_set_compander(struct snd_kcontrol *kcontrol,
748 struct snd_ctl_elem_value *ucontrol)
749{
750 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
751 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
752 int comp = ((struct soc_multi_mixer_control *)
753 kcontrol->private_value)->max;
754 int value = ucontrol->value.integer.value[0];
755
756 if (value == tabla->comp_enabled[comp]) {
757 pr_debug("%s: compander #%d enable %d no change\n",
758 __func__, comp, value);
759 return 0;
760 }
761 tabla->comp_enabled[comp] = value;
762 return 0;
763}
764
765
766static int tabla_config_compander(struct snd_soc_dapm_widget *w,
767 struct snd_kcontrol *kcontrol,
768 int event)
769{
770 struct snd_soc_codec *codec = w->codec;
771 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
772 u32 rate = tabla->comp_fs[w->shift];
773
774 switch (event) {
775 case SND_SOC_DAPM_PRE_PMU:
776 if (tabla->comp_enabled[w->shift] != 0) {
777 /* Enable both L/R compander clocks */
778 snd_soc_update_bits(codec,
779 TABLA_A_CDC_CLK_RX_B2_CTL,
780 0x03 << comp_shift[w->shift],
781 0x03 << comp_shift[w->shift]);
782 /* Clar the HALT for the compander*/
783 snd_soc_update_bits(codec,
784 TABLA_A_CDC_COMP1_B1_CTL +
785 w->shift * 8, 1 << 2, 0);
786 /* Toggle compander reset bits*/
787 snd_soc_update_bits(codec,
788 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
789 0x03 << comp_shift[w->shift],
790 0x03 << comp_shift[w->shift]);
791 snd_soc_update_bits(codec,
792 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
793 0x03 << comp_shift[w->shift], 0);
794 tabla_config_gain_compander(codec, w->shift, 1, event);
795 /* Update the RMS meter resampling*/
796 snd_soc_update_bits(codec,
797 TABLA_A_CDC_COMP1_B3_CTL +
798 w->shift * 8, 0xFF, 0x01);
799 /* Wait for 1ms*/
800 usleep_range(1000, 1000);
801 }
802 break;
803 case SND_SOC_DAPM_POST_PMU:
804 /* Set sample rate dependent paramater*/
805 if (tabla->comp_enabled[w->shift] != 0) {
806 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
807 w->shift * 8, 0x03, rate);
808 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
809 w->shift * 8, 0x0F,
810 comp_samp_params[rate].peak_det_timeout);
811 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
812 w->shift * 8, 0xF0,
813 comp_samp_params[rate].rms_meter_div_fact);
814 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
815 w->shift * 8, 0xFF,
816 comp_samp_params[rate].rms_meter_resamp_fact);
817 /* Compander enable -> 0x370/0x378*/
818 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
819 w->shift * 8, 0x03, 0x03);
820 }
821 break;
822 case SND_SOC_DAPM_PRE_PMD:
823 /* Halt the compander*/
824 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
825 w->shift * 8, 1 << 2, 1 << 2);
826 break;
827 case SND_SOC_DAPM_POST_PMD:
828 /* Restore the gain */
829 tabla_config_gain_compander(codec, w->shift,
830 tabla->comp_enabled[w->shift], event);
831 /* Disable the compander*/
832 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
833 w->shift * 8, 0x03, 0x00);
834 /* Turn off the clock for compander in pair*/
835 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
836 0x03 << comp_shift[w->shift], 0);
837 break;
838 }
839 return 0;
840}
841
Kiran Kandid2d86b52011-09-09 17:44:28 -0700842static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
843static const struct soc_enum tabla_ear_pa_gain_enum[] = {
844 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
845};
846
Santosh Mardi024010f2011-10-18 06:27:21 +0530847/*cut of frequency for high pass filter*/
848static const char *cf_text[] = {
849 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
850};
851
852static const struct soc_enum cf_dec1_enum =
853 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
854
855static const struct soc_enum cf_dec2_enum =
856 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
857
858static const struct soc_enum cf_dec3_enum =
859 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
860
861static const struct soc_enum cf_dec4_enum =
862 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
863
864static const struct soc_enum cf_dec5_enum =
865 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
866
867static const struct soc_enum cf_dec6_enum =
868 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
869
870static const struct soc_enum cf_dec7_enum =
871 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
872
873static const struct soc_enum cf_dec8_enum =
874 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
875
876static const struct soc_enum cf_dec9_enum =
877 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
878
879static const struct soc_enum cf_dec10_enum =
880 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
881
882static const struct soc_enum cf_rxmix1_enum =
883 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
884
885static const struct soc_enum cf_rxmix2_enum =
886 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
887
888static const struct soc_enum cf_rxmix3_enum =
889 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
890
891static const struct soc_enum cf_rxmix4_enum =
892 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
893
894static const struct soc_enum cf_rxmix5_enum =
895 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
896;
897static const struct soc_enum cf_rxmix6_enum =
898 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
899
900static const struct soc_enum cf_rxmix7_enum =
901 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700904
905 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
906 tabla_pa_gain_get, tabla_pa_gain_put),
907
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
909 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700910 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
911 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
913 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700914 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
915 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700916 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
917 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700918
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700919 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
920 line_gain),
921 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
922 line_gain),
923
Bradley Rubin410383f2011-07-22 13:44:23 -0700924 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
925 -84, 40, digital_gain),
926 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
927 -84, 40, digital_gain),
928 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
929 -84, 40, digital_gain),
930 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
931 -84, 40, digital_gain),
932 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
933 -84, 40, digital_gain),
934 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
935 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -0800936 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
937 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700938
Bradley Rubin410383f2011-07-22 13:44:23 -0700939 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700941 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700943 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
944 digital_gain),
945 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
946 digital_gain),
947 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
948 digital_gain),
949 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
950 digital_gain),
951 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
952 digital_gain),
953 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
954 digital_gain),
955 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
956 digital_gain),
957 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
958 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700959 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
960 40, digital_gain),
961 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
962 40, digital_gain),
963 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
964 40, digital_gain),
965 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
966 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700967 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
968 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700969 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
970 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700971 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
972 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700973
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800974 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
975 aux_pga_gain),
976 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
977 aux_pga_gain),
978
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700979 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800980 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700981 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700982
983 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
984 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530985 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
986 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
987 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
988 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
989 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
990 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
991 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
992 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
993 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
994 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
995
996 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
997 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
998 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
999 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
1000 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
1001 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
1002 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
1003 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
1004 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
1005 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
1006
1007 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
1008 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
1009 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
1010 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
1011 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
1012 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
1013 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
1014
1015 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1016 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1017 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
1018 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
1019 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
1020 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
1021 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -07001022
1023 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1024 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1025 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1026 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1027 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1028 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1029 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1030 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1031 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1032 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1033 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1034 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1035 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1036 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1037 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1038 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1039 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1040 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1041 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1042 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1043
1044 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1045 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1046 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1047 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1048 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1049 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1050 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1051 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1052 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1053 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1054 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1055 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1056 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1057 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1058 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1059 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1060 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1061 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1062 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1063 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001064 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
1065 tabla_get_compander, tabla_set_compander),
1066 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
1067 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001068};
1069
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001070static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
1071 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
1072};
1073
1074static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
1075 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
1076};
1077
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001078static const char *rx_mix1_text[] = {
1079 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1080 "RX5", "RX6", "RX7"
1081};
1082
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001083static const char *rx_mix2_text[] = {
1084 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
1085};
1086
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001087static const char *rx_dsm_text[] = {
1088 "CIC_OUT", "DSM_INV"
1089};
1090
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001091static const char *sb_tx1_mux_text[] = {
1092 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1093 "DEC1"
1094};
1095
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001096static const char *sb_tx2_mux_text[] = {
1097 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1098 "DEC2"
1099};
1100
1101static const char *sb_tx3_mux_text[] = {
1102 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1103 "DEC3"
1104};
1105
1106static const char *sb_tx4_mux_text[] = {
1107 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1108 "DEC4"
1109};
1110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111static const char *sb_tx5_mux_text[] = {
1112 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1113 "DEC5"
1114};
1115
1116static const char *sb_tx6_mux_text[] = {
1117 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1118 "DEC6"
1119};
1120
1121static const char const *sb_tx7_to_tx10_mux_text[] = {
1122 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1123 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1124 "DEC9", "DEC10"
1125};
1126
1127static const char *dec1_mux_text[] = {
1128 "ZERO", "DMIC1", "ADC6",
1129};
1130
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001131static const char *dec2_mux_text[] = {
1132 "ZERO", "DMIC2", "ADC5",
1133};
1134
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001135static const char *dec3_mux_text[] = {
1136 "ZERO", "DMIC3", "ADC4",
1137};
1138
1139static const char *dec4_mux_text[] = {
1140 "ZERO", "DMIC4", "ADC3",
1141};
1142
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143static const char *dec5_mux_text[] = {
1144 "ZERO", "DMIC5", "ADC2",
1145};
1146
1147static const char *dec6_mux_text[] = {
1148 "ZERO", "DMIC6", "ADC1",
1149};
1150
1151static const char const *dec7_mux_text[] = {
1152 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1153};
1154
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001155static const char *dec8_mux_text[] = {
1156 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1157};
1158
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001159static const char *dec9_mux_text[] = {
1160 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1161};
1162
1163static const char *dec10_mux_text[] = {
1164 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1165};
1166
Bradley Rubin229c6a52011-07-12 16:18:48 -07001167static const char const *anc_mux_text[] = {
1168 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1169 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1170};
1171
1172static const char const *anc1_fb_mux_text[] = {
1173 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1174};
1175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176static const char *iir1_inp1_text[] = {
1177 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1178 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1179};
1180
1181static const struct soc_enum rx_mix1_inp1_chain_enum =
1182 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1183
Bradley Rubin229c6a52011-07-12 16:18:48 -07001184static const struct soc_enum rx_mix1_inp2_chain_enum =
1185 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1186
Kiran Kandia9fffe92012-05-20 23:42:30 -07001187static const struct soc_enum rx_mix1_inp3_chain_enum =
1188 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_mix1_text);
1189
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001190static const struct soc_enum rx2_mix1_inp1_chain_enum =
1191 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1192
Bradley Rubin229c6a52011-07-12 16:18:48 -07001193static const struct soc_enum rx2_mix1_inp2_chain_enum =
1194 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1195
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196static const struct soc_enum rx3_mix1_inp1_chain_enum =
1197 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1198
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001199static const struct soc_enum rx3_mix1_inp2_chain_enum =
1200 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202static const struct soc_enum rx4_mix1_inp1_chain_enum =
1203 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1204
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001205static const struct soc_enum rx4_mix1_inp2_chain_enum =
1206 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1207
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208static const struct soc_enum rx5_mix1_inp1_chain_enum =
1209 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1210
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001211static const struct soc_enum rx5_mix1_inp2_chain_enum =
1212 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1213
1214static const struct soc_enum rx6_mix1_inp1_chain_enum =
1215 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1216
1217static const struct soc_enum rx6_mix1_inp2_chain_enum =
1218 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1219
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001220static const struct soc_enum rx7_mix1_inp1_chain_enum =
1221 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1222
1223static const struct soc_enum rx7_mix1_inp2_chain_enum =
1224 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1225
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001226static const struct soc_enum rx1_mix2_inp1_chain_enum =
1227 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
1228
1229static const struct soc_enum rx1_mix2_inp2_chain_enum =
1230 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
1231
1232static const struct soc_enum rx2_mix2_inp1_chain_enum =
1233 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
1234
1235static const struct soc_enum rx2_mix2_inp2_chain_enum =
1236 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
1237
1238static const struct soc_enum rx3_mix2_inp1_chain_enum =
1239 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B3_CTL, 0, 5, rx_mix2_text);
1240
1241static const struct soc_enum rx3_mix2_inp2_chain_enum =
1242 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B3_CTL, 3, 5, rx_mix2_text);
1243
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001244static const struct soc_enum rx4_dsm_enum =
1245 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1246
1247static const struct soc_enum rx6_dsm_enum =
1248 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1249
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001250static const struct soc_enum sb_tx1_mux_enum =
1251 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1252
1253static const struct soc_enum sb_tx2_mux_enum =
1254 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
1255
1256static const struct soc_enum sb_tx3_mux_enum =
1257 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
1258
1259static const struct soc_enum sb_tx4_mux_enum =
1260 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
1261
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262static const struct soc_enum sb_tx5_mux_enum =
1263 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1264
1265static const struct soc_enum sb_tx6_mux_enum =
1266 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1267
1268static const struct soc_enum sb_tx7_mux_enum =
1269 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1270 sb_tx7_to_tx10_mux_text);
1271
1272static const struct soc_enum sb_tx8_mux_enum =
1273 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1274 sb_tx7_to_tx10_mux_text);
1275
Kiran Kandi3426e512011-09-13 22:50:10 -07001276static const struct soc_enum sb_tx9_mux_enum =
1277 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1278 sb_tx7_to_tx10_mux_text);
1279
1280static const struct soc_enum sb_tx10_mux_enum =
1281 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1282 sb_tx7_to_tx10_mux_text);
1283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284static const struct soc_enum dec1_mux_enum =
1285 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1286
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001287static const struct soc_enum dec2_mux_enum =
1288 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1289
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001290static const struct soc_enum dec3_mux_enum =
1291 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1292
1293static const struct soc_enum dec4_mux_enum =
1294 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296static const struct soc_enum dec5_mux_enum =
1297 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1298
1299static const struct soc_enum dec6_mux_enum =
1300 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1301
1302static const struct soc_enum dec7_mux_enum =
1303 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1304
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001305static const struct soc_enum dec8_mux_enum =
1306 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1307
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001308static const struct soc_enum dec9_mux_enum =
1309 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1310
1311static const struct soc_enum dec10_mux_enum =
1312 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1313
Bradley Rubin229c6a52011-07-12 16:18:48 -07001314static const struct soc_enum anc1_mux_enum =
1315 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1316
1317static const struct soc_enum anc2_mux_enum =
1318 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1319
1320static const struct soc_enum anc1_fb_mux_enum =
1321 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1322
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001323static const struct soc_enum iir1_inp1_mux_enum =
1324 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
1325
1326static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1327 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1328
Bradley Rubin229c6a52011-07-12 16:18:48 -07001329static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1330 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1331
Kiran Kandia9fffe92012-05-20 23:42:30 -07001332static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1333 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1334
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1336 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1337
Bradley Rubin229c6a52011-07-12 16:18:48 -07001338static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1339 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1340
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1342 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1343
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001344static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1345 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1346
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1348 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1349
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001350static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1351 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1352
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001353static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1354 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1355
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001356static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1357 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1358
1359static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1360 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1361
1362static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1363 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1364
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001365static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1366 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1367
1368static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1369 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1370
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001371static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1372 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1373
1374static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
1375 SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
1376
1377static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1378 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1379
1380static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
1381 SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
1382
1383static const struct snd_kcontrol_new rx3_mix2_inp1_mux =
1384 SOC_DAPM_ENUM("RX3 MIX2 INP1 Mux", rx3_mix2_inp1_chain_enum);
1385
1386static const struct snd_kcontrol_new rx3_mix2_inp2_mux =
1387 SOC_DAPM_ENUM("RX3 MIX2 INP2 Mux", rx3_mix2_inp2_chain_enum);
1388
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001389static const struct snd_kcontrol_new rx4_dsm_mux =
1390 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1391
1392static const struct snd_kcontrol_new rx6_dsm_mux =
1393 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1394
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001395static const struct snd_kcontrol_new sb_tx1_mux =
1396 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1397
1398static const struct snd_kcontrol_new sb_tx2_mux =
1399 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
1400
1401static const struct snd_kcontrol_new sb_tx3_mux =
1402 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
1403
1404static const struct snd_kcontrol_new sb_tx4_mux =
1405 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
1406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407static const struct snd_kcontrol_new sb_tx5_mux =
1408 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1409
1410static const struct snd_kcontrol_new sb_tx6_mux =
1411 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1412
1413static const struct snd_kcontrol_new sb_tx7_mux =
1414 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1415
1416static const struct snd_kcontrol_new sb_tx8_mux =
1417 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1418
Kiran Kandi3426e512011-09-13 22:50:10 -07001419static const struct snd_kcontrol_new sb_tx9_mux =
1420 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1421
1422static const struct snd_kcontrol_new sb_tx10_mux =
1423 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1424
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001425
Kiran Kandi59a96b12012-01-16 02:20:03 -08001426static int wcd9310_put_dec_enum(struct snd_kcontrol *kcontrol,
1427 struct snd_ctl_elem_value *ucontrol)
1428{
1429 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1430 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1431 struct snd_soc_codec *codec = w->codec;
1432 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1433 unsigned int dec_mux, decimator;
1434 char *dec_name = NULL;
1435 char *widget_name = NULL;
1436 char *temp;
1437 u16 tx_mux_ctl_reg;
1438 u8 adc_dmic_sel = 0x0;
1439 int ret = 0;
1440
1441 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1442 return -EINVAL;
1443
1444 dec_mux = ucontrol->value.enumerated.item[0];
1445
1446 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1447 if (!widget_name)
1448 return -ENOMEM;
1449 temp = widget_name;
1450
1451 dec_name = strsep(&widget_name, " ");
1452 widget_name = temp;
1453 if (!dec_name) {
1454 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1455 ret = -EINVAL;
1456 goto out;
1457 }
1458
1459 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
1460 if (ret < 0) {
1461 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1462 ret = -EINVAL;
1463 goto out;
1464 }
1465
1466 dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"
1467 " dec_mux = %u\n", __func__, w->name, dec_name, decimator,
1468 dec_mux);
1469
1470
1471 switch (decimator) {
1472 case 1:
1473 case 2:
1474 case 3:
1475 case 4:
1476 case 5:
1477 case 6:
1478 if (dec_mux == 1)
1479 adc_dmic_sel = 0x1;
1480 else
1481 adc_dmic_sel = 0x0;
1482 break;
1483 case 7:
1484 case 8:
1485 case 9:
1486 case 10:
1487 if ((dec_mux == 1) || (dec_mux == 2))
1488 adc_dmic_sel = 0x1;
1489 else
1490 adc_dmic_sel = 0x0;
1491 break;
1492 default:
1493 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1494 ret = -EINVAL;
1495 goto out;
1496 }
1497
1498 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1499
1500 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1501
1502 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1503
1504out:
1505 kfree(widget_name);
1506 return ret;
1507}
1508
1509#define WCD9310_DEC_ENUM(xname, xenum) \
1510{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1511 .info = snd_soc_info_enum_double, \
1512 .get = snd_soc_dapm_get_enum_double, \
1513 .put = wcd9310_put_dec_enum, \
1514 .private_value = (unsigned long)&xenum }
1515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001516static const struct snd_kcontrol_new dec1_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001517 WCD9310_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001519static const struct snd_kcontrol_new dec2_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001520 WCD9310_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001521
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001522static const struct snd_kcontrol_new dec3_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001523 WCD9310_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001524
1525static const struct snd_kcontrol_new dec4_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001526 WCD9310_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528static const struct snd_kcontrol_new dec5_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001529 WCD9310_DEC_ENUM("DEC5 MUX Mux", dec5_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001530
1531static const struct snd_kcontrol_new dec6_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001532 WCD9310_DEC_ENUM("DEC6 MUX Mux", dec6_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533
1534static const struct snd_kcontrol_new dec7_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001535 WCD9310_DEC_ENUM("DEC7 MUX Mux", dec7_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001537static const struct snd_kcontrol_new dec8_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001538 WCD9310_DEC_ENUM("DEC8 MUX Mux", dec8_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001539
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001540static const struct snd_kcontrol_new dec9_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001541 WCD9310_DEC_ENUM("DEC9 MUX Mux", dec9_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001542
1543static const struct snd_kcontrol_new dec10_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001544 WCD9310_DEC_ENUM("DEC10 MUX Mux", dec10_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001545
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001546static const struct snd_kcontrol_new iir1_inp1_mux =
1547 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1548
Kiran Kandi59a96b12012-01-16 02:20:03 -08001549static const struct snd_kcontrol_new anc1_mux =
1550 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1551
Bradley Rubin229c6a52011-07-12 16:18:48 -07001552static const struct snd_kcontrol_new anc2_mux =
1553 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001554
Bradley Rubin229c6a52011-07-12 16:18:48 -07001555static const struct snd_kcontrol_new anc1_fb_mux =
1556 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557
Bradley Rubin229c6a52011-07-12 16:18:48 -07001558static const struct snd_kcontrol_new dac1_switch[] = {
1559 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1560};
1561static const struct snd_kcontrol_new hphl_switch[] = {
1562 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1563};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001564
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001565static const struct snd_kcontrol_new hphl_pa_mix[] = {
1566 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1567 7, 1, 0),
1568 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1569 7, 1, 0),
1570 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1571 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1572 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1573 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1574};
1575
1576static const struct snd_kcontrol_new hphr_pa_mix[] = {
1577 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1578 6, 1, 0),
1579 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1580 6, 1, 0),
1581 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1582 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1583 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1584 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1585};
1586
1587static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1588 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1589 5, 1, 0),
1590 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1591 5, 1, 0),
1592 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1593 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1594 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1595 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1596};
1597
1598static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1599 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1600 4, 1, 0),
1601 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1602 4, 1, 0),
1603 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1604 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1605 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1606 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1607};
1608
1609static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1610 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1611 3, 1, 0),
1612 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1613 3, 1, 0),
1614 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1615 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1616 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1617 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1618};
1619
1620static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1621 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1622 2, 1, 0),
1623 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1624 2, 1, 0),
1625 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1626 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1627 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1628 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1629};
1630
1631static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1632 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1633 1, 1, 0),
1634 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1635 1, 1, 0),
1636 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1637 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1638 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1639 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1640};
1641
1642static const struct snd_kcontrol_new ear_pa_mix[] = {
1643 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1644 0, 1, 0),
1645 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1646 0, 1, 0),
1647 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1648 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1649 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1650 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1651};
1652
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001653static const struct snd_kcontrol_new lineout3_ground_switch =
1654 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1655
1656static const struct snd_kcontrol_new lineout4_ground_switch =
1657 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001658
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001659static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001660 int enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661{
1662 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1663
1664 pr_debug("%s %d\n", __func__, enable);
1665
1666 if (enable) {
1667 tabla->adc_count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1669 } else {
1670 tabla->adc_count--;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001671 if (!tabla->adc_count)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
Joonwoo Park03324832012-03-19 19:36:16 -07001673 0x2, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001674 }
1675}
1676
1677static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1678 struct snd_kcontrol *kcontrol, int event)
1679{
1680 struct snd_soc_codec *codec = w->codec;
1681 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001682 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001683
1684 pr_debug("%s %d\n", __func__, event);
1685
1686 if (w->reg == TABLA_A_TX_1_2_EN)
1687 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1688 else if (w->reg == TABLA_A_TX_3_4_EN)
1689 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1690 else if (w->reg == TABLA_A_TX_5_6_EN)
1691 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1692 else {
1693 pr_err("%s: Error, invalid adc register\n", __func__);
1694 return -EINVAL;
1695 }
1696
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001697 if (w->shift == 3)
1698 init_bit_shift = 6;
1699 else if (w->shift == 7)
1700 init_bit_shift = 7;
1701 else {
1702 pr_err("%s: Error, invalid init bit postion adc register\n",
1703 __func__);
1704 return -EINVAL;
1705 }
1706
1707
1708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 switch (event) {
1710 case SND_SOC_DAPM_PRE_PMU:
1711 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001712 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1713 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001714 break;
1715 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001716
1717 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1718
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001719 break;
1720 case SND_SOC_DAPM_POST_PMD:
1721 tabla_codec_enable_adc_block(codec, 0);
1722 break;
1723 }
1724 return 0;
1725}
1726
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001727static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1728{
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001729 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1730 0x80);
1731 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1732 0x04);
1733 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1734 0x01);
1735 usleep_range(1000, 1000);
1736 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1737 0x00);
1738}
1739
1740static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1741 enum tabla_bandgap_type choice)
1742{
1743 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1744
1745 /* TODO lock resources accessed by audio streams and threaded
1746 * interrupt handlers
1747 */
1748
1749 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1750 tabla->bandgap_type);
1751
1752 if (tabla->bandgap_type == choice)
1753 return;
1754
1755 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1756 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1757 tabla_codec_enable_audio_mode_bandgap(codec);
1758 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001759 /* bandgap mode becomes fast,
1760 * mclk should be off or clk buff source souldn't be VBG
1761 * Let's turn off mclk always */
1762 WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001763 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1764 0x2);
1765 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1766 0x80);
1767 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1768 0x4);
1769 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1770 0x01);
1771 usleep_range(1000, 1000);
1772 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1773 0x00);
1774 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1775 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1776 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1777 usleep_range(100, 100);
1778 tabla_codec_enable_audio_mode_bandgap(codec);
1779 } else if (choice == TABLA_BANDGAP_OFF) {
1780 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1781 } else {
1782 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1783 }
1784 tabla->bandgap_type = choice;
1785}
1786
1787static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1788{
1789 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1790 pr_debug("%s\n", __func__);
1791 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001792 usleep_range(50, 50);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001793 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1794 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001795 usleep_range(50, 50);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001796 tabla->clock_active = false;
1797}
1798
1799static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
1800{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001801 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001802 return 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001803 else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001804 return 1;
1805 else {
1806 BUG_ON(1);
1807 return -EINVAL;
1808 }
1809}
1810
1811static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1812{
1813 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1814
1815 if (enable) {
1816 tabla->rx_bias_count++;
1817 if (tabla->rx_bias_count == 1)
1818 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1819 0x80, 0x80);
1820 } else {
1821 tabla->rx_bias_count--;
1822 if (!tabla->rx_bias_count)
1823 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1824 0x80, 0x00);
1825 }
1826}
1827
1828static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1829 int enable)
1830{
1831 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1832
1833 pr_debug("%s: enable = %d\n", __func__, enable);
1834 if (enable) {
1835 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001836 /* bandgap mode to fast */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001837 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1838 usleep_range(5, 5);
1839 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001840 0x80);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001841 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001842 0x80);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001843 usleep_range(10, 10);
1844 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001845 usleep_range(10000, 10000);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001846 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1847 } else {
1848 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001849 0);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001850 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001851 /* clk source to ext clk and clk buff ref to VBG */
1852 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x0C, 0x04);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001853 }
1854 tabla->config_mode_active = enable ? true : false;
1855
1856 return 0;
1857}
1858
1859static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001860 int config_mode)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001861{
1862 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1863
1864 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
1865
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001866 /* transit to RCO requires mclk off */
1867 WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001868 if (config_mode) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001869 /* enable RCO and switch to it */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001870 tabla_codec_enable_config_mode(codec, 1);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001871 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001872 usleep_range(1000, 1000);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001873 } else {
1874 /* switch to MCLK */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001875 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1876
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001877 if (tabla->mbhc_polling_active) {
1878 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1879 tabla_codec_enable_config_mode(codec, 0);
1880 }
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001881 }
1882
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001883 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x01, 0x01);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001884 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001885 /* on MCLK */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001886 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1887 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1888 usleep_range(50, 50);
1889 tabla->clock_active = true;
1890 return 0;
1891}
1892
1893static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1894 struct snd_kcontrol *kcontrol, int event)
1895{
1896 struct snd_soc_codec *codec = w->codec;
1897 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1898
1899 pr_debug("%s: %d\n", __func__, event);
1900
1901 switch (event) {
1902 case SND_SOC_DAPM_PRE_PMU:
1903 tabla_codec_enable_bandgap(codec,
1904 TABLA_BANDGAP_AUDIO_MODE);
1905 tabla_enable_rx_bias(codec, 1);
1906
1907 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1908 0x08, 0x08);
1909 /* Enable Zero Cross detect for AUX PGA channel
1910 * and set the initial AUX PGA gain to NEG_0P0_DB
1911 * to avoid glitches.
1912 */
1913 if (w->reg == TABLA_A_AUX_L_EN) {
1914 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1915 0x20, 0x20);
1916 tabla->aux_l_gain = snd_soc_read(codec,
1917 TABLA_A_AUX_L_GAIN);
1918 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1919 } else {
1920 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1921 0x20, 0x20);
1922 tabla->aux_r_gain = snd_soc_read(codec,
1923 TABLA_A_AUX_R_GAIN);
1924 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1925 }
1926 if (tabla->aux_pga_cnt++ == 1
1927 && !tabla->mclk_enabled) {
1928 tabla_codec_enable_clock_block(codec, 1);
1929 pr_debug("AUX PGA enabled RC osc\n");
1930 }
1931 break;
1932
1933 case SND_SOC_DAPM_POST_PMU:
1934 if (w->reg == TABLA_A_AUX_L_EN)
1935 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1936 tabla->aux_l_gain);
1937 else
1938 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1939 tabla->aux_r_gain);
1940 break;
1941
1942 case SND_SOC_DAPM_PRE_PMD:
1943 /* Mute AUX PGA channel in use before disabling AUX PGA */
1944 if (w->reg == TABLA_A_AUX_L_EN) {
1945 tabla->aux_l_gain = snd_soc_read(codec,
1946 TABLA_A_AUX_L_GAIN);
1947 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1948 } else {
1949 tabla->aux_r_gain = snd_soc_read(codec,
1950 TABLA_A_AUX_R_GAIN);
1951 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1952 }
1953 break;
1954
1955 case SND_SOC_DAPM_POST_PMD:
1956 tabla_enable_rx_bias(codec, 0);
1957
1958 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1959 0x08, 0x00);
1960 if (w->reg == TABLA_A_AUX_L_EN) {
1961 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1962 tabla->aux_l_gain);
1963 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1964 0x20, 0x00);
1965 } else {
1966 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1967 tabla->aux_r_gain);
1968 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1969 0x20, 0x00);
1970 }
1971
1972 if (tabla->aux_pga_cnt-- == 0) {
1973 if (tabla->mbhc_polling_active)
1974 tabla_codec_enable_bandgap(codec,
1975 TABLA_BANDGAP_MBHC_MODE);
1976 else
1977 tabla_codec_enable_bandgap(codec,
1978 TABLA_BANDGAP_OFF);
1979
1980 if (!tabla->mclk_enabled &&
1981 !tabla->mbhc_polling_active) {
1982 tabla_codec_enable_clock_block(codec, 0);
1983 }
1984 }
1985 break;
1986 }
1987 return 0;
1988}
1989
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001990static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1991 struct snd_kcontrol *kcontrol, int event)
1992{
1993 struct snd_soc_codec *codec = w->codec;
1994 u16 lineout_gain_reg;
1995
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001996 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001997
1998 switch (w->shift) {
1999 case 0:
2000 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
2001 break;
2002 case 1:
2003 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
2004 break;
2005 case 2:
2006 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
2007 break;
2008 case 3:
2009 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
2010 break;
2011 case 4:
2012 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
2013 break;
2014 default:
2015 pr_err("%s: Error, incorrect lineout register value\n",
2016 __func__);
2017 return -EINVAL;
2018 }
2019
2020 switch (event) {
2021 case SND_SOC_DAPM_PRE_PMU:
2022 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
2023 break;
2024 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08002025 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002026 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08002027 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028 break;
2029 case SND_SOC_DAPM_POST_PMD:
2030 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
2031 break;
2032 }
2033 return 0;
2034}
2035
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002036
2037static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 struct snd_kcontrol *kcontrol, int event)
2039{
2040 struct snd_soc_codec *codec = w->codec;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002041 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2042 u8 dmic_clk_en;
2043 s32 *dmic_clk_cnt;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002044 unsigned int dmic;
2045 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002046
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002047 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
2048 if (ret < 0) {
2049 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002050 return -EINVAL;
2051 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002052
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002053 switch (dmic) {
2054 case 1:
2055 case 2:
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002056 dmic_clk_en = 0x01;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002057 dmic_clk_cnt = &(tabla->dmic_1_2_clk_cnt);
2058
2059 pr_debug("%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
2060 __func__, event, dmic, *dmic_clk_cnt);
2061
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002062 break;
2063
2064 case 3:
2065 case 4:
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002066 dmic_clk_en = 0x04;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002067 dmic_clk_cnt = &(tabla->dmic_3_4_clk_cnt);
2068
2069 pr_debug("%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
2070 __func__, event, dmic, *dmic_clk_cnt);
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002071 break;
2072
2073 case 5:
2074 case 6:
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002075 dmic_clk_en = 0x10;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002076 dmic_clk_cnt = &(tabla->dmic_5_6_clk_cnt);
2077
2078 pr_debug("%s() event %d DMIC%d dmic_5_6_clk_cnt %d\n",
2079 __func__, event, dmic, *dmic_clk_cnt);
2080
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002081 break;
2082
2083 default:
2084 pr_err("%s: Invalid DMIC Selection\n", __func__);
2085 return -EINVAL;
2086 }
2087
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088 switch (event) {
2089 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002090
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002091 (*dmic_clk_cnt)++;
2092 if (*dmic_clk_cnt == 1)
2093 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
2094 dmic_clk_en, dmic_clk_en);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002095
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096 break;
2097 case SND_SOC_DAPM_POST_PMD:
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002098
2099 (*dmic_clk_cnt)--;
2100 if (*dmic_clk_cnt == 0)
2101 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
2102 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 break;
2104 }
2105 return 0;
2106}
2107
Bradley Rubin229c6a52011-07-12 16:18:48 -07002108static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
2109 struct snd_kcontrol *kcontrol, int event)
2110{
2111 struct snd_soc_codec *codec = w->codec;
2112 const char *filename;
2113 const struct firmware *fw;
2114 int i;
2115 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07002116 int num_anc_slots;
2117 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002118 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07002119 u32 anc_writes_size = 0;
2120 int anc_size_remaining;
2121 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002122 u16 reg;
2123 u8 mask, val, old_val;
2124
2125 pr_debug("%s %d\n", __func__, event);
2126 switch (event) {
2127 case SND_SOC_DAPM_PRE_PMU:
2128
Bradley Rubin4283a4c2011-07-29 16:18:54 -07002129 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07002130
2131 ret = request_firmware(&fw, filename, codec->dev);
2132 if (ret != 0) {
2133 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
2134 ret);
2135 return -ENODEV;
2136 }
2137
Bradley Rubina7096d02011-08-03 18:29:02 -07002138 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07002139 dev_err(codec->dev, "Not enough data\n");
2140 release_firmware(fw);
2141 return -ENOMEM;
2142 }
2143
2144 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07002145 anc_head = (struct anc_header *)(fw->data);
2146 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
2147 anc_size_remaining = fw->size - sizeof(struct anc_header);
2148 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002149
Bradley Rubina7096d02011-08-03 18:29:02 -07002150 if (tabla->anc_slot >= num_anc_slots) {
2151 dev_err(codec->dev, "Invalid ANC slot selected\n");
2152 release_firmware(fw);
2153 return -EINVAL;
2154 }
2155
2156 for (i = 0; i < num_anc_slots; i++) {
2157
2158 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
2159 dev_err(codec->dev, "Invalid register format\n");
2160 release_firmware(fw);
2161 return -EINVAL;
2162 }
2163 anc_writes_size = (u32)(*anc_ptr);
2164 anc_size_remaining -= sizeof(u32);
2165 anc_ptr += 1;
2166
2167 if (anc_writes_size * TABLA_PACKED_REG_SIZE
2168 > anc_size_remaining) {
2169 dev_err(codec->dev, "Invalid register format\n");
2170 release_firmware(fw);
2171 return -ENOMEM;
2172 }
2173
2174 if (tabla->anc_slot == i)
2175 break;
2176
2177 anc_size_remaining -= (anc_writes_size *
2178 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07002179 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07002180 }
2181 if (i == num_anc_slots) {
2182 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07002183 release_firmware(fw);
2184 return -ENOMEM;
2185 }
2186
Bradley Rubina7096d02011-08-03 18:29:02 -07002187 for (i = 0; i < anc_writes_size; i++) {
2188 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07002189 mask, val);
2190 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07002191 snd_soc_write(codec, reg, (old_val & ~mask) |
2192 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07002193 }
2194 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002195
2196 break;
2197 case SND_SOC_DAPM_POST_PMD:
2198 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
2199 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
2200 break;
2201 }
2202 return 0;
2203}
2204
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002205/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002206static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
2207{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002208 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07002209 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
2210 int mbhc_state = tabla->mbhc_state;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002211
Joonwoo Park03324832012-03-19 19:36:16 -07002212 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002213 if (!tabla->mbhc_polling_active) {
2214 pr_debug("Polling is not active, do not start polling\n");
2215 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002216 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002217 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Joonwoo Park03324832012-03-19 19:36:16 -07002218
2219 if (!tabla->no_mic_headset_override) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002220 if (mbhc_state == MBHC_STATE_POTENTIAL) {
2221 pr_debug("%s recovering MBHC state macine\n", __func__);
2222 tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
Joonwoo Park03324832012-03-19 19:36:16 -07002223 /* set to max button press threshold */
2224 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2225 0x7F);
2226 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2227 0xFF);
2228 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2229 (TABLA_IS_1_X(tabla_core->version) ?
2230 0x07 : 0x7F));
2231 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2232 0xFF);
2233 /* set to max */
2234 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2235 0x7F);
2236 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2237 0xFF);
2238 }
2239 }
2240
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002241 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
2242 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2243 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
Joonwoo Park03324832012-03-19 19:36:16 -07002244 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002245}
2246
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002247/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002248static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
2249{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002250 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2251
Joonwoo Park03324832012-03-19 19:36:16 -07002252 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002253 if (!tabla->mbhc_polling_active) {
2254 pr_debug("polling not active, nothing to pause\n");
2255 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002256 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002257
2258 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Joonwoo Park03324832012-03-19 19:36:16 -07002259 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002260}
2261
Joonwoo Park03324832012-03-19 19:36:16 -07002262static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002263{
2264 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2265 u8 reg_mode_val, cur_mode_val;
2266 bool mbhc_was_polling = false;
2267
2268 if (mode)
2269 reg_mode_val = TABLA_CFILT_FAST_MODE;
2270 else
2271 reg_mode_val = TABLA_CFILT_SLOW_MODE;
2272
2273 cur_mode_val = snd_soc_read(codec,
2274 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
2275
2276 if (cur_mode_val != reg_mode_val) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002277 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002278 if (tabla->mbhc_polling_active) {
2279 tabla_codec_pause_hs_polling(codec);
2280 mbhc_was_polling = true;
2281 }
2282 snd_soc_update_bits(codec,
2283 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
2284 if (mbhc_was_polling)
2285 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002286 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002287 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
2288 cur_mode_val, reg_mode_val);
2289 } else {
2290 pr_debug("%s: CFILT Value is already %x\n",
2291 __func__, cur_mode_val);
2292 }
2293}
2294
2295static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
2296 u8 cfilt_sel, int inc)
2297{
2298 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2299 u32 *cfilt_cnt_ptr = NULL;
2300 u16 micb_cfilt_reg;
2301
2302 switch (cfilt_sel) {
2303 case TABLA_CFILT1_SEL:
2304 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2305 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2306 break;
2307 case TABLA_CFILT2_SEL:
2308 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2309 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2310 break;
2311 case TABLA_CFILT3_SEL:
2312 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2313 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2314 break;
2315 default:
2316 return; /* should not happen */
2317 }
2318
2319 if (inc) {
2320 if (!(*cfilt_cnt_ptr)++) {
2321 /* Switch CFILT to slow mode if MBHC CFILT being used */
2322 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2323 tabla_codec_switch_cfilt_mode(codec, 0);
2324
2325 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2326 }
2327 } else {
2328 /* check if count not zero, decrement
2329 * then check if zero, go ahead disable cfilter
2330 */
2331 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2332 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2333
2334 /* Switch CFILT to fast mode if MBHC CFILT being used */
2335 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2336 tabla_codec_switch_cfilt_mode(codec, 1);
2337 }
2338 }
2339}
2340
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002341static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2342{
2343 int rc = -EINVAL;
2344 unsigned min_mv, max_mv;
2345
2346 switch (ldoh_v) {
2347 case TABLA_LDOH_1P95_V:
2348 min_mv = 160;
2349 max_mv = 1800;
2350 break;
2351 case TABLA_LDOH_2P35_V:
2352 min_mv = 200;
2353 max_mv = 2200;
2354 break;
2355 case TABLA_LDOH_2P75_V:
2356 min_mv = 240;
2357 max_mv = 2600;
2358 break;
2359 case TABLA_LDOH_2P85_V:
2360 min_mv = 250;
2361 max_mv = 2700;
2362 break;
2363 default:
2364 goto done;
2365 }
2366
2367 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2368 goto done;
2369
2370 for (rc = 4; rc <= 44; rc++) {
2371 min_mv = max_mv * (rc) / 44;
2372 if (min_mv >= cfilt_mv) {
2373 rc -= 4;
2374 break;
2375 }
2376 }
2377done:
2378 return rc;
2379}
2380
2381static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2382{
2383 u8 hph_reg_val = 0;
2384 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2385
2386 return (hph_reg_val & 0x30) ? true : false;
2387}
2388
Joonwoo Parka9444452011-12-08 18:48:27 -08002389static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2390{
2391 u8 hph_reg_val = 0;
2392 if (left)
2393 hph_reg_val = snd_soc_read(codec,
2394 TABLA_A_RX_HPH_L_DAC_CTL);
2395 else
2396 hph_reg_val = snd_soc_read(codec,
2397 TABLA_A_RX_HPH_R_DAC_CTL);
2398
2399 return (hph_reg_val & 0xC0) ? true : false;
2400}
2401
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002402static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
2403{
2404 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
2405}
2406
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002407/* called under codec_resource_lock acquisition */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002408static void tabla_codec_drive_v_to_micbias(struct snd_soc_codec *codec,
2409 int usec)
2410{
2411 int cfilt_k_val;
2412 bool set = true;
2413 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2414
2415 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2416 tabla->mbhc_micbias_switched) {
2417 pr_debug("%s: set mic V to micbias V\n", __func__);
2418 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2419 tabla_turn_onoff_override(codec, true);
2420 while (1) {
2421 cfilt_k_val = tabla_find_k_value(
2422 tabla->pdata->micbias.ldoh_v,
2423 set ? tabla->mbhc_data.micb_mv :
2424 VDDIO_MICBIAS_MV);
2425 snd_soc_update_bits(codec,
2426 tabla->mbhc_bias_regs.cfilt_val,
2427 0xFC, (cfilt_k_val << 2));
2428 if (!set)
2429 break;
2430 usleep_range(usec, usec);
2431 set = false;
2432 }
2433 tabla_turn_onoff_override(codec, false);
2434 }
2435}
2436
2437/* called under codec_resource_lock acquisition */
2438static void __tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2439 int vddio_switch, bool restartpolling,
2440 bool checkpolling)
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002441{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002442 int cfilt_k_val;
Joonwoo Park41956722012-04-18 13:13:07 -07002443 bool override;
2444 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002445
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002446 if (vddio_switch && !tabla->mbhc_micbias_switched &&
2447 (!checkpolling || tabla->mbhc_polling_active)) {
2448 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002449 tabla_codec_pause_hs_polling(codec);
Joonwoo Park41956722012-04-18 13:13:07 -07002450 override = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04;
2451 if (!override)
2452 tabla_turn_onoff_override(codec, true);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002453 /* Adjust threshold if Mic Bias voltage changes */
2454 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002455 cfilt_k_val = tabla_find_k_value(
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002456 tabla->pdata->micbias.ldoh_v,
2457 VDDIO_MICBIAS_MV);
2458 usleep_range(10000, 10000);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002459 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002460 tabla->mbhc_bias_regs.cfilt_val,
2461 0xFC, (cfilt_k_val << 2));
2462 usleep_range(10000, 10000);
2463 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2464 tabla->mbhc_data.adj_v_ins_hu & 0xFF);
2465 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2466 (tabla->mbhc_data.adj_v_ins_hu >> 8) &
2467 0xFF);
2468 pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
2469 __func__);
2470 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002471
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002472 /* enable MIC BIAS Switch to VDDIO */
2473 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2474 0x80, 0x80);
2475 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2476 0x10, 0x00);
Joonwoo Park41956722012-04-18 13:13:07 -07002477 if (!override)
2478 tabla_turn_onoff_override(codec, false);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002479 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002480 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002481
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002482 tabla->mbhc_micbias_switched = true;
2483 pr_debug("%s: VDDIO switch enabled\n", __func__);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002484 } else if (!vddio_switch && tabla->mbhc_micbias_switched) {
2485 if ((!checkpolling || tabla->mbhc_polling_active) &&
2486 restartpolling)
2487 tabla_codec_pause_hs_polling(codec);
2488 /* Reprogram thresholds */
2489 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
2490 cfilt_k_val = tabla_find_k_value(
2491 tabla->pdata->micbias.ldoh_v,
2492 tabla->mbhc_data.micb_mv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002493 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002494 tabla->mbhc_bias_regs.cfilt_val,
2495 0xFC, (cfilt_k_val << 2));
2496 usleep_range(10000, 10000);
2497 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2498 tabla->mbhc_data.v_ins_hu & 0xFF);
2499 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2500 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
2501 pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
2502 __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002503 }
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002504
2505 /* Disable MIC BIAS Switch to VDDIO */
2506 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2507 0x80, 0x00);
2508 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2509 0x10, 0x00);
2510
2511 if ((!checkpolling || tabla->mbhc_polling_active) &&
2512 restartpolling)
2513 tabla_codec_start_hs_polling(codec);
2514
2515 tabla->mbhc_micbias_switched = false;
2516 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002517 }
2518}
2519
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002520static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2521 int vddio_switch)
2522{
2523 return __tabla_codec_switch_micbias(codec, vddio_switch, true, true);
2524}
2525
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002526static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2527 struct snd_kcontrol *kcontrol, int event)
2528{
2529 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002530 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2531 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002532 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002533 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002534 char *internal1_text = "Internal1";
2535 char *internal2_text = "Internal2";
2536 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537
2538 pr_debug("%s %d\n", __func__, event);
2539 switch (w->reg) {
2540 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002541 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002542 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002543 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544 break;
2545 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002546 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002547 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002548 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002549 break;
2550 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002551 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002552 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002553 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002554 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002555 case TABLA_1_A_MICB_4_CTL:
2556 case TABLA_2_A_MICB_4_CTL:
2557 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002558 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002559 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002560 break;
2561 default:
2562 pr_err("%s: Error, invalid micbias register\n", __func__);
2563 return -EINVAL;
2564 }
2565
2566 switch (event) {
2567 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002568 /* Decide whether to switch the micbias for MBHC */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002569 if (w->reg == tabla->mbhc_bias_regs.ctl_reg) {
2570 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002571 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002572 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2573 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002574
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002575 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002576 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002577
2578 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002579 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002580 else if (strnstr(w->name, internal2_text, 30))
2581 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2582 else if (strnstr(w->name, internal3_text, 30))
2583 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2584
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002585 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002586 case SND_SOC_DAPM_POST_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002587
2588 usleep_range(20000, 20000);
2589
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002590 if (tabla->mbhc_polling_active &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002591 tabla->mbhc_cfg.micbias == micb_line) {
2592 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002593 tabla_codec_pause_hs_polling(codec);
2594 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002595 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002596 }
2597 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002598
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002599 case SND_SOC_DAPM_POST_PMD:
Joonwoo Park03324832012-03-19 19:36:16 -07002600 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg) &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002601 tabla_is_hph_pa_on(codec)) {
2602 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002603 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002604 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2605 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002606
Bradley Rubin229c6a52011-07-12 16:18:48 -07002607 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002608 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002609 else if (strnstr(w->name, internal2_text, 30))
2610 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2611 else if (strnstr(w->name, internal3_text, 30))
2612 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2613
Patrick Lai3043fba2011-08-01 14:15:57 -07002614 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002615 break;
2616 }
2617
2618 return 0;
2619}
2620
Kiran Kandid8cf5212012-03-02 15:34:53 -08002621
2622static void tx_hpf_corner_freq_callback(struct work_struct *work)
2623{
2624 struct delayed_work *hpf_delayed_work;
2625 struct hpf_work *hpf_work;
2626 struct tabla_priv *tabla;
2627 struct snd_soc_codec *codec;
2628 u16 tx_mux_ctl_reg;
2629 u8 hpf_cut_of_freq;
2630
2631 hpf_delayed_work = to_delayed_work(work);
2632 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2633 tabla = hpf_work->tabla;
2634 codec = hpf_work->tabla->codec;
2635 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2636
2637 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL +
2638 (hpf_work->decimator - 1) * 8;
2639
2640 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
2641 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2642
2643 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
2644}
2645
2646#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
2647#define CF_MIN_3DB_4HZ 0x0
2648#define CF_MIN_3DB_75HZ 0x1
2649#define CF_MIN_3DB_150HZ 0x2
2650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002651static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
2652 struct snd_kcontrol *kcontrol, int event)
2653{
2654 struct snd_soc_codec *codec = w->codec;
Kiran Kandid8cf5212012-03-02 15:34:53 -08002655 unsigned int decimator;
2656 char *dec_name = NULL;
2657 char *widget_name = NULL;
2658 char *temp;
2659 int ret = 0;
2660 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2661 u8 dec_hpf_cut_of_freq;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002662 int offset;
2663
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002664
2665 pr_debug("%s %d\n", __func__, event);
2666
Kiran Kandid8cf5212012-03-02 15:34:53 -08002667 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2668 if (!widget_name)
2669 return -ENOMEM;
2670 temp = widget_name;
2671
2672 dec_name = strsep(&widget_name, " ");
2673 widget_name = temp;
2674 if (!dec_name) {
2675 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2676 ret = -EINVAL;
2677 goto out;
2678 }
2679
2680 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
2681 if (ret < 0) {
2682 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2683 ret = -EINVAL;
2684 goto out;
2685 }
2686
2687 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
2688 w->name, dec_name, decimator);
2689
Kuirong Wange9c8a222012-03-28 16:24:09 -07002690 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002691 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002692 offset = 0;
2693 } else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002694 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002695 offset = 8;
2696 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697 pr_err("%s: Error, incorrect dec\n", __func__);
2698 return -EINVAL;
2699 }
2700
Kiran Kandid8cf5212012-03-02 15:34:53 -08002701 tx_vol_ctl_reg = TABLA_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator -1);
2702 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2703
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002704 switch (event) {
2705 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002706
2707 // Enableable TX digital mute */
2708 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2709
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002710 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2711 1 << w->shift);
2712 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Kiran Kandid8cf5212012-03-02 15:34:53 -08002713
2714 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2715
2716 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
2717
2718 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2719 dec_hpf_cut_of_freq;
2720
2721 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2722
2723 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
2724 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2725 CF_MIN_3DB_150HZ << 4);
2726 }
2727
2728 /* enable HPF */
2729 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
2730
2731 break;
2732
2733 case SND_SOC_DAPM_POST_PMU:
2734
2735 /* Disable TX digital mute */
2736 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2737
2738 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2739 CF_MIN_3DB_150HZ) {
2740
2741 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2742 msecs_to_jiffies(300));
2743 }
Kuirong Wange9c8a222012-03-28 16:24:09 -07002744 /* apply the digital gain after the decimator is enabled*/
2745 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2746 snd_soc_write(codec,
2747 tx_digital_gain_reg[w->shift + offset],
2748 snd_soc_read(codec,
2749 tx_digital_gain_reg[w->shift + offset])
2750 );
2751
Kiran Kandid8cf5212012-03-02 15:34:53 -08002752 break;
2753
2754 case SND_SOC_DAPM_PRE_PMD:
2755
2756 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2757 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2758 break;
2759
2760 case SND_SOC_DAPM_POST_PMD:
2761
2762 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2763 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2764 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002766 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002767 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08002768out:
2769 kfree(widget_name);
2770 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002771}
2772
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002773static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002774 struct snd_kcontrol *kcontrol, int event)
2775{
2776 struct snd_soc_codec *codec = w->codec;
2777
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002778 pr_debug("%s %d %s\n", __func__, event, w->name);
2779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002780 switch (event) {
2781 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002782 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2783 1 << w->shift, 1 << w->shift);
2784 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2785 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002786 break;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002787 case SND_SOC_DAPM_POST_PMU:
2788 /* apply the digital gain after the interpolator is enabled*/
2789 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2790 snd_soc_write(codec,
2791 rx_digital_gain_reg[w->shift],
2792 snd_soc_read(codec,
2793 rx_digital_gain_reg[w->shift])
2794 );
2795 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002796 }
2797 return 0;
2798}
2799
Bradley Rubin229c6a52011-07-12 16:18:48 -07002800static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2801 struct snd_kcontrol *kcontrol, int event)
2802{
2803 switch (event) {
2804 case SND_SOC_DAPM_POST_PMU:
2805 case SND_SOC_DAPM_POST_PMD:
2806 usleep_range(1000, 1000);
2807 break;
2808 }
2809 return 0;
2810}
2811
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002812static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2813 struct snd_kcontrol *kcontrol, int event)
2814{
2815 struct snd_soc_codec *codec = w->codec;
2816
2817 pr_debug("%s %d\n", __func__, event);
2818
2819 switch (event) {
2820 case SND_SOC_DAPM_PRE_PMU:
2821 tabla_enable_rx_bias(codec, 1);
2822 break;
2823 case SND_SOC_DAPM_POST_PMD:
2824 tabla_enable_rx_bias(codec, 0);
2825 break;
2826 }
2827 return 0;
2828}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002829static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
2830 struct snd_kcontrol *kcontrol, int event)
2831{
2832 struct snd_soc_codec *codec = w->codec;
2833
2834 pr_debug("%s %s %d\n", __func__, w->name, event);
2835
2836 switch (event) {
2837 case SND_SOC_DAPM_PRE_PMU:
2838 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2839 break;
2840 case SND_SOC_DAPM_POST_PMD:
2841 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2842 break;
2843 }
2844 return 0;
2845}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002846
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002847static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
2848 struct snd_soc_jack *jack, int status,
2849 int mask)
2850{
2851 /* XXX: wake_lock_timeout()? */
Joonwoo Park03324832012-03-19 19:36:16 -07002852 snd_soc_jack_report_no_dapm(jack, status, mask);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002853}
2854
Patrick Lai49efeac2011-11-03 11:01:12 -07002855static void hphocp_off_report(struct tabla_priv *tabla,
2856 u32 jack_status, int irq)
2857{
2858 struct snd_soc_codec *codec;
Joonwoo Park03324832012-03-19 19:36:16 -07002859 if (!tabla) {
2860 pr_err("%s: Bad tabla private data\n", __func__);
2861 return;
2862 }
Patrick Lai49efeac2011-11-03 11:01:12 -07002863
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002864 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
Joonwoo Park03324832012-03-19 19:36:16 -07002865 codec = tabla->codec;
2866 if (tabla->hph_status & jack_status) {
Patrick Lai49efeac2011-11-03 11:01:12 -07002867 tabla->hph_status &= ~jack_status;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002868 if (tabla->mbhc_cfg.headset_jack)
2869 tabla_snd_soc_jack_report(tabla,
2870 tabla->mbhc_cfg.headset_jack,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002871 tabla->hph_status,
2872 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08002873 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2874 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08002875 /* reset retry counter as PA is turned off signifying
2876 * start of new OCP detection session
2877 */
2878 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
2879 tabla->hphlocp_cnt = 0;
2880 else
2881 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302882 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07002883 }
2884}
2885
2886static void hphlocp_off_report(struct work_struct *work)
2887{
2888 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2889 hphlocp_work);
2890 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
2891}
2892
2893static void hphrocp_off_report(struct work_struct *work)
2894{
2895 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2896 hphrocp_work);
2897 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
2898}
2899
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002900static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
2901 struct snd_kcontrol *kcontrol, int event)
2902{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002903 struct snd_soc_codec *codec = w->codec;
2904 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2905 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002906 pr_debug("%s: event = %d\n", __func__, event);
2907
2908 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002909 case SND_SOC_DAPM_PRE_PMU:
2910 mbhc_micb_ctl_val = snd_soc_read(codec,
2911 tabla->mbhc_bias_regs.ctl_reg);
2912
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002913 if (!(mbhc_micb_ctl_val & 0x80)) {
2914 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002915 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002916 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2917 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002918 break;
2919
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002920 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07002921 /* schedule work is required because at the time HPH PA DAPM
2922 * event callback is called by DAPM framework, CODEC dapm mutex
2923 * would have been locked while snd_soc_jack_report also
2924 * attempts to acquire same lock.
2925 */
Joonwoo Parka9444452011-12-08 18:48:27 -08002926 if (w->shift == 5) {
2927 clear_bit(TABLA_HPHL_PA_OFF_ACK,
2928 &tabla->hph_pa_dac_state);
2929 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
2930 &tabla->hph_pa_dac_state);
2931 if (tabla->hph_status & SND_JACK_OC_HPHL)
2932 schedule_work(&tabla->hphlocp_work);
2933 } else if (w->shift == 4) {
2934 clear_bit(TABLA_HPHR_PA_OFF_ACK,
2935 &tabla->hph_pa_dac_state);
2936 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
2937 &tabla->hph_pa_dac_state);
2938 if (tabla->hph_status & SND_JACK_OC_HPHR)
2939 schedule_work(&tabla->hphrocp_work);
2940 }
2941
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002942 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park03324832012-03-19 19:36:16 -07002943 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002944 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002945
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002946 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
2947 w->name);
2948 usleep_range(10000, 10000);
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002949 break;
2950 }
2951 return 0;
2952}
2953
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002954static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002955 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002956{
2957 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002958 unsigned int cfilt;
2959
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002960 switch (tabla->mbhc_cfg.micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002961 case TABLA_MICBIAS1:
2962 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
2963 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
2964 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
2965 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
2966 break;
2967 case TABLA_MICBIAS2:
2968 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
2969 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
2970 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
2971 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
2972 break;
2973 case TABLA_MICBIAS3:
2974 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
2975 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
2976 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
2977 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
2978 break;
2979 case TABLA_MICBIAS4:
2980 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002981 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
2982 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
2983 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002984 break;
2985 default:
2986 /* Should never reach here */
2987 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07002988 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002989 }
2990
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002991 micbias_regs->cfilt_sel = cfilt;
2992
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002993 switch (cfilt) {
2994 case TABLA_CFILT1_SEL:
2995 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
2996 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002997 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002998 break;
2999 case TABLA_CFILT2_SEL:
3000 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
3001 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08003002 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003003 break;
3004 case TABLA_CFILT3_SEL:
3005 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
3006 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08003007 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003008 break;
3009 }
3010}
Santosh Mardie15e2302011-11-15 10:39:23 +05303011static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
3012 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
3013 4, 0, NULL, 0),
3014 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
3015 0, NULL, 0),
3016};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003017
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003018static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
3019 struct snd_kcontrol *kcontrol, int event)
3020{
3021 struct snd_soc_codec *codec = w->codec;
3022
3023 pr_debug("%s %s %d\n", __func__, w->name, event);
3024
3025 switch (event) {
3026 case SND_SOC_DAPM_PRE_PMU:
3027 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
3028 break;
3029
3030 case SND_SOC_DAPM_POST_PMD:
3031 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
3032 break;
3033 }
3034 return 0;
3035}
3036
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003037static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
3038 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303039 0, tabla_codec_enable_micbias,
3040 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3041 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003042};
3043
3044static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
3045 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303046 0, tabla_codec_enable_micbias,
3047 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3048 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003049};
3050
Santosh Mardie15e2302011-11-15 10:39:23 +05303051static const struct snd_soc_dapm_route audio_i2s_map[] = {
3052 {"RX_I2S_CLK", NULL, "CDC_CONN"},
3053 {"SLIM RX1", NULL, "RX_I2S_CLK"},
3054 {"SLIM RX2", NULL, "RX_I2S_CLK"},
3055 {"SLIM RX3", NULL, "RX_I2S_CLK"},
3056 {"SLIM RX4", NULL, "RX_I2S_CLK"},
3057
3058 {"SLIM TX7", NULL, "TX_I2S_CLK"},
3059 {"SLIM TX8", NULL, "TX_I2S_CLK"},
3060 {"SLIM TX9", NULL, "TX_I2S_CLK"},
3061 {"SLIM TX10", NULL, "TX_I2S_CLK"},
3062};
3063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003064static const struct snd_soc_dapm_route audio_map[] = {
3065 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003066
3067 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
3068 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
3069
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003070 {"SLIM TX2", NULL, "SLIM TX2 MUX"},
3071 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
3072
3073 {"SLIM TX3", NULL, "SLIM TX3 MUX"},
3074 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Neema Shetty3fb1b802012-04-27 13:53:24 -07003075 {"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
3076 {"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
3077 {"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
3078 {"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
3079 {"SLIM TX3 MUX", "RMIX5", "RX5 MIX1"},
3080 {"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
3081 {"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003082
3083 {"SLIM TX4", NULL, "SLIM TX4 MUX"},
3084 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
3085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003086 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
3087 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
Neema Shetty3fb1b802012-04-27 13:53:24 -07003088 {"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
3089 {"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
3090 {"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
3091 {"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
3092 {"SLIM TX5 MUX", "RMIX5", "RX5 MIX1"},
3093 {"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
3094 {"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003095
3096 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
3097 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
3098
3099 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
3100 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07003101 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003102 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
3103 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003104 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
3105 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07003106 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
3107 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003108 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
3109 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Neema Shetty3fb1b802012-04-27 13:53:24 -07003110 {"SLIM TX7 MUX", "RMIX1", "RX1 MIX1"},
3111 {"SLIM TX7 MUX", "RMIX2", "RX2 MIX1"},
3112 {"SLIM TX7 MUX", "RMIX3", "RX3 MIX1"},
3113 {"SLIM TX7 MUX", "RMIX4", "RX4 MIX1"},
3114 {"SLIM TX7 MUX", "RMIX5", "RX5 MIX1"},
3115 {"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
3116 {"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003117
3118 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003119 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
3120 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
3121 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07003122 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003123 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
3124 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003125 {"SLIM TX8 MUX", "DEC7", "DEC7 MUX"},
3126 {"SLIM TX8 MUX", "DEC8", "DEC8 MUX"},
3127 {"SLIM TX8 MUX", "DEC9", "DEC9 MUX"},
3128 {"SLIM TX8 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003129
Kiran Kandi3426e512011-09-13 22:50:10 -07003130 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
3131 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
3132 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
3133 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
3134 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
3135 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
3136 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
3137 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
3138 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
3139 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
3140 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
3141
3142 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
3143 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
3144 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
3145 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
3146 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
3147 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
3148 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
3149 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
3150 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
3151 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
3152 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
3153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003154 /* Earpiece (RX MIX1) */
3155 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003156 {"EAR PA", NULL, "EAR_PA_MIXER"},
3157 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003158 {"DAC1", NULL, "CP"},
3159
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003160 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
3161 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003162 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003163
3164 /* Headset (RX MIX1 and RX MIX2) */
3165 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003166 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003167
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003168 {"HPHL", NULL, "HPHL_PA_MIXER"},
3169 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
3170
3171 {"HPHR", NULL, "HPHR_PA_MIXER"},
3172 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003173
3174 {"HPHL DAC", NULL, "CP"},
3175 {"HPHR DAC", NULL, "CP"},
3176
3177 {"ANC", NULL, "ANC1 MUX"},
3178 {"ANC", NULL, "ANC2 MUX"},
3179 {"ANC1 MUX", "ADC1", "ADC1"},
3180 {"ANC1 MUX", "ADC2", "ADC2"},
3181 {"ANC1 MUX", "ADC3", "ADC3"},
3182 {"ANC1 MUX", "ADC4", "ADC4"},
3183 {"ANC2 MUX", "ADC1", "ADC1"},
3184 {"ANC2 MUX", "ADC2", "ADC2"},
3185 {"ANC2 MUX", "ADC3", "ADC3"},
3186 {"ANC2 MUX", "ADC4", "ADC4"},
3187
Bradley Rubine1d08622011-07-20 18:01:35 -07003188 {"ANC", NULL, "CDC_CONN"},
3189
Bradley Rubin229c6a52011-07-12 16:18:48 -07003190 {"DAC1", "Switch", "RX1 CHAIN"},
3191 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003192 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003193
Kiran Kandidb0a4b02011-08-23 09:32:09 -07003194 {"LINEOUT1", NULL, "LINEOUT1 PA"},
3195 {"LINEOUT2", NULL, "LINEOUT2 PA"},
3196 {"LINEOUT3", NULL, "LINEOUT3 PA"},
3197 {"LINEOUT4", NULL, "LINEOUT4 PA"},
3198 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003199
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003200 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
3201 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
3202 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
3203 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
3204 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
3205 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
3206 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
3207 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
3208 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
3209 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003210
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003211 {"LINEOUT1 DAC", NULL, "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003212 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
3213
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003214 {"RX1 CHAIN", NULL, "RX1 MIX2"},
3215 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003216 {"RX1 CHAIN", NULL, "ANC"},
3217 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003218
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003219 {"CP", NULL, "RX_BIAS"},
3220 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
3221 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
3222 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
3223 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003224 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003225
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003226 {"RX1 MIX1", NULL, "COMP1_CLK"},
3227 {"RX2 MIX1", NULL, "COMP1_CLK"},
3228 {"RX3 MIX1", NULL, "COMP2_CLK"},
3229 {"RX5 MIX1", NULL, "COMP2_CLK"},
3230
3231
Bradley Rubin229c6a52011-07-12 16:18:48 -07003232 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
3233 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003234 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003235 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
3236 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003237 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
3238 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
3239 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
3240 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
3241 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
3242 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
3243 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
3244 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003245 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
3246 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003247 {"RX1 MIX2", NULL, "RX1 MIX1"},
3248 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
3249 {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
3250 {"RX2 MIX2", NULL, "RX2 MIX1"},
3251 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
3252 {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
3253 {"RX3 MIX2", NULL, "RX3 MIX1"},
3254 {"RX3 MIX2", NULL, "RX3 MIX2 INP1"},
3255 {"RX3 MIX2", NULL, "RX3 MIX2 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003256
Bradley Rubin229c6a52011-07-12 16:18:48 -07003257 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
3258 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303259 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
3260 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003261 {"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003262 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
3263 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003264 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
3265 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
3266 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303267 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
3268 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003269 {"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003270 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
3271 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003272 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003273 {"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
3274 {"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
3275 {"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
3276 {"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
3277 {"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
3278 {"RX1 MIX1 INP3", "RX6", "SLIM RX6"},
3279 {"RX1 MIX1 INP3", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003280 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
3281 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303282 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
3283 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003284 {"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003285 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
3286 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003287 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003288 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
3289 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303290 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
3291 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003292 {"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003293 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
3294 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003295 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003296 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
3297 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303298 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
3299 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003300 {"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003301 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
3302 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003303 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003304 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
3305 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303306 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
3307 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003308 {"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003309 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
3310 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003311 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003312 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
3313 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303314 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
3315 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003316 {"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003317 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
3318 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003319 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003320 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
3321 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303322 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003323 {"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303324 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003325 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
3326 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003327 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003328 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
3329 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303330 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
3331 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003332 {"RX5 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003333 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
3334 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003335 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003336 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
3337 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303338 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
3339 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003340 {"RX5 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003341 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
3342 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003343 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003344 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
3345 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303346 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
3347 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003348 {"RX6 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003349 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
3350 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003351 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003352 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
3353 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303354 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
3355 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003356 {"RX6 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003357 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
3358 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003359 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003360 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
3361 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303362 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
3363 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003364 {"RX7 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003365 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
3366 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003367 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003368 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
3369 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303370 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
3371 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003372 {"RX7 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003373 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
3374 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003375 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003376 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
3377 {"RX1 MIX2 INP2", "IIR1", "IIR1"},
3378 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
3379 {"RX2 MIX2 INP2", "IIR1", "IIR1"},
3380 {"RX3 MIX2 INP1", "IIR1", "IIR1"},
3381 {"RX3 MIX2 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003382
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003383 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003384 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003385 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003386 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003387 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003388 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003389 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003390 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003391 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003392 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003393 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003394 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003395 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003396 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003397 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003398 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003399 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003400 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003401 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003402 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003403 {"DEC7 MUX", "DMIC6", "DMIC6"},
3404 {"DEC7 MUX", "ADC1", "ADC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003405 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003406 {"DEC7 MUX", NULL, "CDC_CONN"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003407 {"DEC8 MUX", "DMIC2", "DMIC2"},
3408 {"DEC8 MUX", "DMIC5", "DMIC5"},
3409 {"DEC8 MUX", "ADC2", "ADC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003410 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003411 {"DEC8 MUX", NULL, "CDC_CONN"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003412 {"DEC9 MUX", "DMIC4", "DMIC4"},
3413 {"DEC9 MUX", "DMIC5", "DMIC5"},
3414 {"DEC9 MUX", "ADC2", "ADC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003415 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003416 {"DEC9 MUX", NULL, "CDC_CONN"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003417 {"DEC10 MUX", "DMIC3", "DMIC3"},
3418 {"DEC10 MUX", "DMIC6", "DMIC6"},
3419 {"DEC10 MUX", "ADC1", "ADC1"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003420 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003421 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003422
3423 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003424 {"ADC1", NULL, "AMIC1"},
3425 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003426 {"ADC3", NULL, "AMIC3"},
3427 {"ADC4", NULL, "AMIC4"},
3428 {"ADC5", NULL, "AMIC5"},
3429 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003430
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003431 /* AUX PGA Connections */
3432 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3433 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3434 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3435 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3436 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3437 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3438 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3439 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3440 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3441 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3442 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3443 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3444 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3445 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3446 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3447 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3448 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3449 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3450 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3451 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3452 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3453 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3454 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3455 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3456 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3457 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3458 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3459 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3460 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3461 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3462 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3463 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3464 {"AUX_PGA_Left", NULL, "AMIC5"},
3465 {"AUX_PGA_Right", NULL, "AMIC6"},
3466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003467 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003468 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
3469 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
3470 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
3471 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
3472 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003473 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003474 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
3475 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
3476 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
3477 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003478
3479 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
3480 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
3481 {"MIC BIAS1 External", NULL, "LDO_H"},
3482 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
3483 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
3484 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
3485 {"MIC BIAS2 External", NULL, "LDO_H"},
3486 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
3487 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
3488 {"MIC BIAS3 External", NULL, "LDO_H"},
3489 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003490};
3491
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003492static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
3493
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003494 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003495 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3496
3497 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
3498
3499 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003500 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003501 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
3502
3503 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3504 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3505
3506 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3507 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
3508 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
3509};
3510
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003511
3512static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
3513
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003514 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX2"},
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003515 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3516
3517 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
3518
3519 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
3520
3521 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3522 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3523
3524 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3525};
3526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003527static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
3528{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003529 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303530 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003531
3532 if (TABLA_IS_1_X(tabla_core->version)) {
3533 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
3534 if (tabla_1_reg_readable[i] == reg)
3535 return 1;
3536 }
3537 } else {
3538 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
3539 if (tabla_2_reg_readable[i] == reg)
3540 return 1;
3541 }
3542 }
3543
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003544 return tabla_reg_readable[reg];
3545}
Kuirong Wange9c8a222012-03-28 16:24:09 -07003546static bool tabla_is_digital_gain_register(unsigned int reg)
3547{
3548 bool rtn = false;
3549 switch (reg) {
3550 case TABLA_A_CDC_RX1_VOL_CTL_B2_CTL:
3551 case TABLA_A_CDC_RX2_VOL_CTL_B2_CTL:
3552 case TABLA_A_CDC_RX3_VOL_CTL_B2_CTL:
3553 case TABLA_A_CDC_RX4_VOL_CTL_B2_CTL:
3554 case TABLA_A_CDC_RX5_VOL_CTL_B2_CTL:
3555 case TABLA_A_CDC_RX6_VOL_CTL_B2_CTL:
3556 case TABLA_A_CDC_RX7_VOL_CTL_B2_CTL:
3557 case TABLA_A_CDC_TX1_VOL_CTL_GAIN:
3558 case TABLA_A_CDC_TX2_VOL_CTL_GAIN:
3559 case TABLA_A_CDC_TX3_VOL_CTL_GAIN:
3560 case TABLA_A_CDC_TX4_VOL_CTL_GAIN:
3561 case TABLA_A_CDC_TX5_VOL_CTL_GAIN:
3562 case TABLA_A_CDC_TX6_VOL_CTL_GAIN:
3563 case TABLA_A_CDC_TX7_VOL_CTL_GAIN:
3564 case TABLA_A_CDC_TX8_VOL_CTL_GAIN:
3565 case TABLA_A_CDC_TX9_VOL_CTL_GAIN:
3566 case TABLA_A_CDC_TX10_VOL_CTL_GAIN:
3567 rtn = true;
3568 break;
3569 default:
3570 break;
3571 }
3572 return rtn;
3573}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003574static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3575{
3576 /* Registers lower than 0x100 are top level registers which can be
3577 * written by the Tabla core driver.
3578 */
3579
3580 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3581 return 1;
3582
Ben Romberger1f045a72011-11-04 10:14:57 -07003583 /* IIR Coeff registers are not cacheable */
3584 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
3585 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
3586 return 1;
3587
Kuirong Wange9c8a222012-03-28 16:24:09 -07003588 /* Digital gain register is not cacheable so we have to write
3589 * the setting even it is the same
3590 */
3591 if (tabla_is_digital_gain_register(reg))
3592 return 1;
3593
Joonwoo Parkab2c5872012-05-03 15:16:02 -07003594 /* HPH status registers */
3595 if (reg == TABLA_A_RX_HPH_L_STATUS || reg == TABLA_A_RX_HPH_R_STATUS)
3596 return 1;
3597
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003598 return 0;
3599}
3600
3601#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3602static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
3603 unsigned int value)
3604{
3605 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003606 BUG_ON(reg > TABLA_MAX_REGISTER);
3607
3608 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003609 ret = snd_soc_cache_write(codec, reg, value);
3610 if (ret != 0)
3611 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3612 reg, ret);
3613 }
3614
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303615 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003616}
3617static unsigned int tabla_read(struct snd_soc_codec *codec,
3618 unsigned int reg)
3619{
3620 unsigned int val;
3621 int ret;
3622
3623 BUG_ON(reg > TABLA_MAX_REGISTER);
3624
3625 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
3626 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003627 ret = snd_soc_cache_read(codec, reg, &val);
3628 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003629 return val;
3630 } else
3631 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3632 reg, ret);
3633 }
3634
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303635 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003636 return val;
3637}
3638
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003639static s16 tabla_get_current_v_ins(struct tabla_priv *tabla, bool hu)
3640{
3641 s16 v_ins;
3642 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3643 tabla->mbhc_micbias_switched)
3644 v_ins = hu ? (s16)tabla->mbhc_data.adj_v_ins_hu :
3645 (s16)tabla->mbhc_data.adj_v_ins_h;
3646 else
3647 v_ins = hu ? (s16)tabla->mbhc_data.v_ins_hu :
3648 (s16)tabla->mbhc_data.v_ins_h;
3649 return v_ins;
3650}
3651
3652static s16 tabla_get_current_v_hs_max(struct tabla_priv *tabla)
3653{
3654 s16 v_hs_max;
3655 struct tabla_mbhc_plug_type_cfg *plug_type;
3656
3657 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
3658 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3659 tabla->mbhc_micbias_switched)
3660 v_hs_max = tabla->mbhc_data.adj_v_hs_max;
3661 else
3662 v_hs_max = plug_type->v_hs_max;
3663 return v_hs_max;
3664}
3665
Bradley Rubincb1e2732011-06-23 16:49:20 -07003666static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3667{
Joonwoo Parkc0672392012-01-11 11:03:14 -08003668 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08003669 struct tabla_mbhc_btn_detect_cfg *btn_det;
3670 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003671 const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
3672
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003673 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003674
Joonwoo Park0976d012011-12-22 11:48:18 -08003675 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003676 v_ins_hu & 0xFF);
Joonwoo Park0976d012011-12-22 11:48:18 -08003677 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003678 (v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003679
Joonwoo Park0976d012011-12-22 11:48:18 -08003680 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
3681 tabla->mbhc_data.v_b1_hu & 0xFF);
3682 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
3683 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
3684
3685 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
3686 tabla->mbhc_data.v_b1_h & 0xFF);
3687 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
3688 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
3689
3690 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
3691 tabla->mbhc_data.v_brh & 0xFF);
3692 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
3693 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
3694
3695 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
3696 tabla->mbhc_data.v_brl & 0xFF);
3697 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
3698 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
3699
Joonwoo Parkc0672392012-01-11 11:03:14 -08003700 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003701 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08003702 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003703 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
3704 tabla->mbhc_data.npoll);
3705 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
3706 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08003707 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003708 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
3709 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003710}
3711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003712static int tabla_startup(struct snd_pcm_substream *substream,
3713 struct snd_soc_dai *dai)
3714{
Kuirong Wanga545e722012-02-06 19:12:54 -08003715 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003716 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3717 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003718 if ((tabla_core != NULL) &&
3719 (tabla_core->dev != NULL) &&
3720 (tabla_core->dev->parent != NULL))
3721 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003722
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003723 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003724}
3725
3726static void tabla_shutdown(struct snd_pcm_substream *substream,
3727 struct snd_soc_dai *dai)
3728{
Kuirong Wanga545e722012-02-06 19:12:54 -08003729 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003730 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3731 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003732 if ((tabla_core != NULL) &&
3733 (tabla_core->dev != NULL) &&
3734 (tabla_core->dev->parent != NULL)) {
3735 pm_runtime_mark_last_busy(tabla_core->dev->parent);
3736 pm_runtime_put(tabla_core->dev->parent);
3737 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003738}
3739
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003740int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003741{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003742 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3743
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003744 pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
3745 dapm);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003746 if (dapm)
3747 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003748 if (mclk_enable) {
3749 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003750
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003751 if (tabla->mbhc_polling_active) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07003752 tabla_codec_pause_hs_polling(codec);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003753 tabla_codec_disable_clock_block(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003754 tabla_codec_enable_bandgap(codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003755 TABLA_BANDGAP_AUDIO_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003756 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003757 tabla_codec_calibrate_hs_polling(codec);
3758 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303759 } else {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003760 tabla_codec_disable_clock_block(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303761 tabla_codec_enable_bandgap(codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003762 TABLA_BANDGAP_AUDIO_MODE);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303763 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003764 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003765 } else {
3766
3767 if (!tabla->mclk_enabled) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003768 if (dapm)
3769 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003770 pr_err("Error, MCLK already diabled\n");
3771 return -EINVAL;
3772 }
3773 tabla->mclk_enabled = false;
3774
3775 if (tabla->mbhc_polling_active) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003776 tabla_codec_pause_hs_polling(codec);
3777 tabla_codec_disable_clock_block(codec);
3778 tabla_codec_enable_bandgap(codec,
3779 TABLA_BANDGAP_MBHC_MODE);
3780 tabla_enable_rx_bias(codec, 1);
3781 tabla_codec_enable_clock_block(codec, 1);
3782 tabla_codec_calibrate_hs_polling(codec);
3783 tabla_codec_start_hs_polling(codec);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003784 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
3785 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303786 } else {
3787 tabla_codec_disable_clock_block(codec);
3788 tabla_codec_enable_bandgap(codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003789 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003790 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003791 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003792 if (dapm)
3793 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003794 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003795}
3796
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003797static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
3798 int clk_id, unsigned int freq, int dir)
3799{
3800 pr_debug("%s\n", __func__);
3801 return 0;
3802}
3803
3804static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3805{
Santosh Mardie15e2302011-11-15 10:39:23 +05303806 u8 val = 0;
3807 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3808
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003809 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05303810 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3811 case SND_SOC_DAIFMT_CBS_CFS:
3812 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303813 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003814 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303815 snd_soc_update_bits(dai->codec,
3816 TABLA_A_CDC_CLK_TX_I2S_CTL,
3817 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003818 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303819 snd_soc_update_bits(dai->codec,
3820 TABLA_A_CDC_CLK_RX_I2S_CTL,
3821 TABLA_I2S_MASTER_MODE_MASK, 0);
3822 }
3823 break;
3824 case SND_SOC_DAIFMT_CBM_CFM:
3825 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303826 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303827 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003828 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303829 snd_soc_update_bits(dai->codec,
3830 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003831 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303832 snd_soc_update_bits(dai->codec,
3833 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
3834 }
3835 break;
3836 default:
3837 return -EINVAL;
3838 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003839 return 0;
3840}
3841
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003842static int tabla_set_channel_map(struct snd_soc_dai *dai,
3843 unsigned int tx_num, unsigned int *tx_slot,
3844 unsigned int rx_num, unsigned int *rx_slot)
3845
3846{
3847 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3848 u32 i = 0;
3849 if (!tx_slot && !rx_slot) {
3850 pr_err("%s: Invalid\n", __func__);
3851 return -EINVAL;
3852 }
Kiran Kandia9fffe92012-05-20 23:42:30 -07003853 pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
3854 __func__, dai->name, dai->id, tx_num, rx_num);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003855
Kiran Kandia9fffe92012-05-20 23:42:30 -07003856 if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_PB) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003857 for (i = 0; i < rx_num; i++) {
3858 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
3859 tabla->dai[dai->id - 1].ch_act = 0;
3860 tabla->dai[dai->id - 1].ch_tot = rx_num;
3861 }
Neema Shetty3fb1b802012-04-27 13:53:24 -07003862 } else if (dai->id == AIF1_CAP || dai->id == AIF2_CAP ||
3863 dai->id == AIF3_CAP) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003864 for (i = 0; i < tx_num; i++) {
3865 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
3866 tabla->dai[dai->id - 1].ch_act = 0;
3867 tabla->dai[dai->id - 1].ch_tot = tx_num;
3868 }
3869 }
3870 return 0;
3871}
3872
3873static int tabla_get_channel_map(struct snd_soc_dai *dai,
3874 unsigned int *tx_num, unsigned int *tx_slot,
3875 unsigned int *rx_num, unsigned int *rx_slot)
3876
3877{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303878 struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003879
3880 u32 cnt = 0;
3881 u32 tx_ch[SLIM_MAX_TX_PORTS];
3882 u32 rx_ch[SLIM_MAX_RX_PORTS];
3883
3884 if (!rx_slot && !tx_slot) {
3885 pr_err("%s: Invalid\n", __func__);
3886 return -EINVAL;
3887 }
Kiran Kandia9fffe92012-05-20 23:42:30 -07003888
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003889 /* for virtual port, codec driver needs to do
3890 * housekeeping, for now should be ok
3891 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303892 wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003893 if (dai->id == AIF1_PB) {
3894 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3895 while (cnt < *rx_num) {
3896 rx_slot[cnt] = rx_ch[cnt];
3897 cnt++;
3898 }
3899 } else if (dai->id == AIF1_CAP) {
3900 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3901 while (cnt < *tx_num) {
3902 tx_slot[cnt] = tx_ch[6 + cnt];
3903 cnt++;
3904 }
Neema Shettyd3a89262012-02-16 10:23:50 -08003905 } else if (dai->id == AIF2_PB) {
3906 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3907 while (cnt < *rx_num) {
3908 rx_slot[cnt] = rx_ch[5 + cnt];
3909 cnt++;
3910 }
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003911 } else if (dai->id == AIF2_CAP) {
3912 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3913 tx_slot[0] = tx_ch[cnt];
3914 tx_slot[1] = tx_ch[1 + cnt];
Kiran Kandi323d7102012-04-18 19:56:14 -07003915 tx_slot[2] = tx_ch[5 + cnt];
Kiran Kandie408b842012-05-17 19:48:04 -07003916 tx_slot[3] = tx_ch[3 + cnt];
Kiran Kandia9fffe92012-05-20 23:42:30 -07003917
3918 } else if (dai->id == AIF3_PB) {
3919 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3920 rx_slot[0] = rx_ch[3];
3921 rx_slot[1] = rx_ch[4];
3922
Neema Shetty3fb1b802012-04-27 13:53:24 -07003923 } else if (dai->id == AIF3_CAP) {
3924 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3925 tx_slot[cnt] = tx_ch[2 + cnt];
3926 tx_slot[cnt + 1] = tx_ch[4 + cnt];
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003927 }
Kiran Kandia9fffe92012-05-20 23:42:30 -07003928 pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n",
3929 __func__, dai->name, dai->id, *tx_num, *rx_num);
3930
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003931
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003932 return 0;
3933}
3934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003935static int tabla_hw_params(struct snd_pcm_substream *substream,
3936 struct snd_pcm_hw_params *params,
3937 struct snd_soc_dai *dai)
3938{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003939 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05303940 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07003941 u8 path, shift;
3942 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003943 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003944 u32 compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003945
Kiran Kandia9fffe92012-05-20 23:42:30 -07003946 pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
3947 dai->name, dai->id, params_rate(params),
3948 params_channels(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003949
3950 switch (params_rate(params)) {
3951 case 8000:
3952 tx_fs_rate = 0x00;
3953 rx_fs_rate = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003954 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003955 break;
3956 case 16000:
3957 tx_fs_rate = 0x01;
3958 rx_fs_rate = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003959 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003960 break;
3961 case 32000:
3962 tx_fs_rate = 0x02;
3963 rx_fs_rate = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003964 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003965 break;
3966 case 48000:
3967 tx_fs_rate = 0x03;
3968 rx_fs_rate = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003969 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003970 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003971 case 96000:
3972 tx_fs_rate = 0x04;
3973 rx_fs_rate = 0x80;
3974 compander_fs = COMPANDER_FS_96KHZ;
3975 break;
3976 case 192000:
3977 tx_fs_rate = 0x05;
3978 rx_fs_rate = 0xA0;
3979 compander_fs = COMPANDER_FS_192KHZ;
3980 break;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003981 default:
3982 pr_err("%s: Invalid sampling rate %d\n", __func__,
3983 params_rate(params));
3984 return -EINVAL;
3985 }
3986
3987
3988 /**
3989 * If current dai is a tx dai, set sample rate to
3990 * all the txfe paths that are currently not active
3991 */
Neema Shetty3fb1b802012-04-27 13:53:24 -07003992 if ((dai->id == AIF1_CAP) || (dai->id == AIF2_CAP) ||
3993 (dai->id == AIF3_CAP)) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003994
3995 tx_state = snd_soc_read(codec,
3996 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3997
3998 for (path = 1, shift = 0;
3999 path <= NUM_DECIMATORS; path++, shift++) {
4000
4001 if (path == BITS_PER_REG + 1) {
4002 shift = 0;
4003 tx_state = snd_soc_read(codec,
4004 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
4005 }
4006
4007 if (!(tx_state & (1 << shift))) {
4008 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
4009 + (BITS_PER_REG*(path-1));
4010 snd_soc_update_bits(codec, tx_fs_reg,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004011 0x07, tx_fs_rate);
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004012 }
4013 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304014 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05304015 switch (params_format(params)) {
4016 case SNDRV_PCM_FORMAT_S16_LE:
4017 snd_soc_update_bits(codec,
4018 TABLA_A_CDC_CLK_TX_I2S_CTL,
4019 0x20, 0x20);
4020 break;
4021 case SNDRV_PCM_FORMAT_S32_LE:
4022 snd_soc_update_bits(codec,
4023 TABLA_A_CDC_CLK_TX_I2S_CTL,
4024 0x20, 0x00);
4025 break;
4026 default:
4027 pr_err("invalid format\n");
4028 break;
4029 }
4030 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004031 0x07, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004032 } else {
4033 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05304034 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004035 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004036 /**
4037 * TODO: Need to handle case where same RX chain takes 2 or more inputs
4038 * with varying sample rates
4039 */
4040
4041 /**
4042 * If current dai is a rx dai, set sample rate to
4043 * all the rx paths that are currently not active
4044 */
Kiran Kandia9fffe92012-05-20 23:42:30 -07004045 if (dai->id == AIF1_PB || dai->id == AIF2_PB || dai->id == AIF3_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004046
4047 rx_state = snd_soc_read(codec,
4048 TABLA_A_CDC_CLK_RX_B1_CTL);
4049
4050 for (path = 1, shift = 0;
4051 path <= NUM_INTERPOLATORS; path++, shift++) {
4052
4053 if (!(rx_state & (1 << shift))) {
4054 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
4055 + (BITS_PER_REG*(path-1));
4056 snd_soc_update_bits(codec, rx_fs_reg,
4057 0xE0, rx_fs_rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004058 if (comp_rx_path[shift] < COMPANDER_MAX)
4059 tabla->comp_fs[comp_rx_path[shift]]
4060 = compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004061 }
4062 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304063 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05304064 switch (params_format(params)) {
4065 case SNDRV_PCM_FORMAT_S16_LE:
4066 snd_soc_update_bits(codec,
4067 TABLA_A_CDC_CLK_RX_I2S_CTL,
4068 0x20, 0x20);
4069 break;
4070 case SNDRV_PCM_FORMAT_S32_LE:
4071 snd_soc_update_bits(codec,
4072 TABLA_A_CDC_CLK_RX_I2S_CTL,
4073 0x20, 0x00);
4074 break;
4075 default:
4076 pr_err("invalid format\n");
4077 break;
4078 }
4079 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
4080 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004081 } else {
4082 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05304083 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004084 }
4085
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004086 return 0;
4087}
4088
4089static struct snd_soc_dai_ops tabla_dai_ops = {
4090 .startup = tabla_startup,
4091 .shutdown = tabla_shutdown,
4092 .hw_params = tabla_hw_params,
4093 .set_sysclk = tabla_set_dai_sysclk,
4094 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004095 .set_channel_map = tabla_set_channel_map,
4096 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004097};
4098
4099static struct snd_soc_dai_driver tabla_dai[] = {
4100 {
4101 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004102 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004103 .playback = {
4104 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004105 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004106 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004107 .rate_max = 192000,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108 .rate_min = 8000,
4109 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004110 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004111 },
4112 .ops = &tabla_dai_ops,
4113 },
4114 {
4115 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004116 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004117 .capture = {
4118 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004119 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004120 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004121 .rate_max = 192000,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004122 .rate_min = 8000,
4123 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004124 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004125 },
4126 .ops = &tabla_dai_ops,
4127 },
Neema Shettyd3a89262012-02-16 10:23:50 -08004128 {
4129 .name = "tabla_rx2",
4130 .id = AIF2_PB,
4131 .playback = {
4132 .stream_name = "AIF2 Playback",
4133 .rates = WCD9310_RATES,
4134 .formats = TABLA_FORMATS,
4135 .rate_min = 8000,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004136 .rate_max = 192000,
Neema Shettyd3a89262012-02-16 10:23:50 -08004137 .channels_min = 1,
4138 .channels_max = 2,
4139 },
4140 .ops = &tabla_dai_ops,
4141 },
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004142 {
4143 .name = "tabla_tx2",
4144 .id = AIF2_CAP,
4145 .capture = {
4146 .stream_name = "AIF2 Capture",
4147 .rates = WCD9310_RATES,
4148 .formats = TABLA_FORMATS,
4149 .rate_max = 192000,
4150 .rate_min = 8000,
4151 .channels_min = 1,
4152 .channels_max = 4,
4153 },
4154 .ops = &tabla_dai_ops,
4155 },
Neema Shetty3fb1b802012-04-27 13:53:24 -07004156 {
4157 .name = "tabla_tx3",
4158 .id = AIF3_CAP,
4159 .capture = {
4160 .stream_name = "AIF3 Capture",
4161 .rates = WCD9310_RATES,
4162 .formats = TABLA_FORMATS,
4163 .rate_max = 48000,
4164 .rate_min = 8000,
4165 .channels_min = 1,
4166 .channels_max = 2,
4167 },
4168 .ops = &tabla_dai_ops,
4169 },
Kiran Kandia9fffe92012-05-20 23:42:30 -07004170 {
4171 .name = "tabla_rx3",
4172 .id = AIF3_PB,
4173 .playback = {
4174 .stream_name = "AIF3 Playback",
4175 .rates = WCD9310_RATES,
4176 .formats = TABLA_FORMATS,
4177 .rate_min = 8000,
4178 .rate_max = 192000,
4179 .channels_min = 1,
4180 .channels_max = 2,
4181 },
4182 .ops = &tabla_dai_ops,
4183 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004184};
Santosh Mardie15e2302011-11-15 10:39:23 +05304185
4186static struct snd_soc_dai_driver tabla_i2s_dai[] = {
4187 {
4188 .name = "tabla_i2s_rx1",
4189 .id = 1,
4190 .playback = {
4191 .stream_name = "AIF1 Playback",
4192 .rates = WCD9310_RATES,
4193 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004194 .rate_max = 192000,
Santosh Mardie15e2302011-11-15 10:39:23 +05304195 .rate_min = 8000,
4196 .channels_min = 1,
4197 .channels_max = 4,
4198 },
4199 .ops = &tabla_dai_ops,
4200 },
4201 {
4202 .name = "tabla_i2s_tx1",
4203 .id = 2,
4204 .capture = {
4205 .stream_name = "AIF1 Capture",
4206 .rates = WCD9310_RATES,
4207 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004208 .rate_max = 192000,
Santosh Mardie15e2302011-11-15 10:39:23 +05304209 .rate_min = 8000,
4210 .channels_min = 1,
4211 .channels_max = 4,
4212 },
4213 .ops = &tabla_dai_ops,
4214 },
4215};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004216
4217static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
4218 struct snd_kcontrol *kcontrol, int event)
4219{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304220 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004221 struct snd_soc_codec *codec = w->codec;
4222 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
4223 u32 j = 0;
4224 u32 ret = 0;
4225 codec->control_data = dev_get_drvdata(codec->dev->parent);
4226 tabla = codec->control_data;
4227 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304228 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004229 return 0;
Kiran Kandia9fffe92012-05-20 23:42:30 -07004230
4231 pr_debug("%s: %s %d\n", __func__, w->name, event);
4232
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004233 switch (event) {
4234 case SND_SOC_DAPM_POST_PMU:
4235 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004236 if ((tabla_dai[j].id == AIF1_CAP) ||
Neema Shetty3fb1b802012-04-27 13:53:24 -07004237 (tabla_dai[j].id == AIF2_CAP) ||
4238 (tabla_dai[j].id == AIF3_CAP))
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004239 continue;
4240 if (!strncmp(w->sname,
4241 tabla_dai[j].playback.stream_name, 13)) {
4242 ++tabla_p->dai[j].ch_act;
4243 break;
4244 }
4245 }
4246 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304247 ret = wcd9xxx_cfg_slim_sch_rx(tabla,
4248 tabla_p->dai[j].ch_num,
4249 tabla_p->dai[j].ch_tot,
4250 tabla_p->dai[j].rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004251 break;
4252 case SND_SOC_DAPM_POST_PMD:
4253 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004254 if ((tabla_dai[j].id == AIF1_CAP) ||
Neema Shetty3fb1b802012-04-27 13:53:24 -07004255 (tabla_dai[j].id == AIF2_CAP) ||
4256 (tabla_dai[j].id == AIF3_CAP))
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004257 continue;
4258 if (!strncmp(w->sname,
4259 tabla_dai[j].playback.stream_name, 13)) {
4260 --tabla_p->dai[j].ch_act;
4261 break;
4262 }
4263 }
4264 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304265 ret = wcd9xxx_close_slim_sch_rx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004266 tabla_p->dai[j].ch_num,
4267 tabla_p->dai[j].ch_tot);
Bharath Ramachandramurthyda6fa7a2012-03-30 14:35:32 -07004268 usleep_range(5000, 5000);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004269 tabla_p->dai[j].rate = 0;
4270 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304271 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004272 tabla_p->dai[j].ch_tot = 0;
4273 }
4274 }
4275 return ret;
4276}
4277
4278static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
4279 struct snd_kcontrol *kcontrol, int event)
4280{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304281 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004282 struct snd_soc_codec *codec = w->codec;
4283 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
4284 /* index to the DAI ID, for now hardcoding */
4285 u32 j = 0;
4286 u32 ret = 0;
4287
4288 codec->control_data = dev_get_drvdata(codec->dev->parent);
4289 tabla = codec->control_data;
4290
4291 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304292 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004293 return 0;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004294
4295 pr_debug("%s(): %s %d\n", __func__, w->name, event);
4296
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004297 switch (event) {
4298 case SND_SOC_DAPM_POST_PMU:
4299 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08004300 if (tabla_dai[j].id == AIF1_PB ||
Kiran Kandia9fffe92012-05-20 23:42:30 -07004301 tabla_dai[j].id == AIF2_PB ||
4302 tabla_dai[j].id == AIF3_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004303 continue;
4304 if (!strncmp(w->sname,
4305 tabla_dai[j].capture.stream_name, 13)) {
4306 ++tabla_p->dai[j].ch_act;
4307 break;
4308 }
4309 }
4310 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304311 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004312 tabla_p->dai[j].ch_num,
4313 tabla_p->dai[j].ch_tot,
4314 tabla_p->dai[j].rate);
4315 break;
4316 case SND_SOC_DAPM_POST_PMD:
4317 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08004318 if (tabla_dai[j].id == AIF1_PB ||
Kiran Kandia9fffe92012-05-20 23:42:30 -07004319 tabla_dai[j].id == AIF2_PB ||
4320 tabla_dai[j].id == AIF3_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004321 continue;
4322 if (!strncmp(w->sname,
4323 tabla_dai[j].capture.stream_name, 13)) {
4324 --tabla_p->dai[j].ch_act;
4325 break;
4326 }
4327 }
4328 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304329 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004330 tabla_p->dai[j].ch_num,
4331 tabla_p->dai[j].ch_tot);
4332 tabla_p->dai[j].rate = 0;
4333 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304334 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004335 tabla_p->dai[j].ch_tot = 0;
4336 }
4337 }
4338 return ret;
4339}
4340
4341/* Todo: Have seperate dapm widgets for I2S and Slimbus.
4342 * Might Need to have callbacks registered only for slimbus
4343 */
4344static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
4345 /*RX stuff */
4346 SND_SOC_DAPM_OUTPUT("EAR"),
4347
4348 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
4349
4350 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
4351 ARRAY_SIZE(dac1_switch)),
4352
4353 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
4354 0, tabla_codec_enable_slimrx,
4355 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4356 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
4357 0, tabla_codec_enable_slimrx,
4358 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kiran Kandia9fffe92012-05-20 23:42:30 -07004359 SND_SOC_DAPM_AIF_IN_E("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
4360 0, tabla_codec_enable_slimrx,
4361 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004362
Kiran Kandia9fffe92012-05-20 23:42:30 -07004363 SND_SOC_DAPM_AIF_IN_E("SLIM RX4", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
4364 0, tabla_codec_enable_slimrx,
4365 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4366 SND_SOC_DAPM_AIF_IN_E("SLIM RX5", "AIF3 Playback", 0, SND_SOC_NOPM, 0,
4367 0, tabla_codec_enable_slimrx,
4368 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004369
Neema Shettyd3a89262012-02-16 10:23:50 -08004370 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
4371 0, tabla_codec_enable_slimrx,
4372 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4373 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
4374 0, tabla_codec_enable_slimrx,
4375 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4376
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004377 /* Headphone */
4378 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
4379 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
4380 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4381 SND_SOC_DAPM_POST_PMD),
4382 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
4383 hphl_switch, ARRAY_SIZE(hphl_switch)),
4384
4385 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
4386 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4387 SND_SOC_DAPM_POST_PMD),
4388
4389 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
4390 tabla_hphr_dac_event,
4391 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4392
4393 /* Speaker */
4394 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
4395 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
4396 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
4397 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
4398 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
4399
4400 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
4401 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4402 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4403 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
4404 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4405 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4406 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
4407 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4408 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4409 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
4410 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4411 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4412 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
4413 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4414 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4415
4416 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
4417 , tabla_lineout_dac_event,
4418 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4419 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
4420 , tabla_lineout_dac_event,
4421 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4422 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
4423 , tabla_lineout_dac_event,
4424 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4425 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
4426 &lineout3_ground_switch),
4427 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
4428 , tabla_lineout_dac_event,
4429 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4430 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
4431 &lineout4_ground_switch),
4432 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
4433 , tabla_lineout_dac_event,
4434 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4435
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004436 SND_SOC_DAPM_MIXER_E("RX1 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004437 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4438 SND_SOC_DAPM_POST_PMU),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004439 SND_SOC_DAPM_MIXER_E("RX2 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004440 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4441 SND_SOC_DAPM_POST_PMU),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004442 SND_SOC_DAPM_MIXER_E("RX3 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004443 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4444 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004445 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004446 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4447 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004448 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004449 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4450 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004451 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004452 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4453 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004454 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004455 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4456 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004457
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004458 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4459 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4460 SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4461
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004462 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
4463 &rx4_dsm_mux, tabla_codec_reset_interpolator,
4464 SND_SOC_DAPM_PRE_PMU),
4465
4466 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
4467 &rx6_dsm_mux, tabla_codec_reset_interpolator,
4468 SND_SOC_DAPM_PRE_PMU),
4469
4470 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
4471 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
4472
4473 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4474 &rx_mix1_inp1_mux),
4475 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4476 &rx_mix1_inp2_mux),
Kiran Kandia9fffe92012-05-20 23:42:30 -07004477 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
4478 &rx_mix1_inp3_mux),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004479 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4480 &rx2_mix1_inp1_mux),
4481 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4482 &rx2_mix1_inp2_mux),
4483 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4484 &rx3_mix1_inp1_mux),
4485 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4486 &rx3_mix1_inp2_mux),
4487 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4488 &rx4_mix1_inp1_mux),
4489 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4490 &rx4_mix1_inp2_mux),
4491 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4492 &rx5_mix1_inp1_mux),
4493 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4494 &rx5_mix1_inp2_mux),
4495 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4496 &rx6_mix1_inp1_mux),
4497 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4498 &rx6_mix1_inp2_mux),
4499 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4500 &rx7_mix1_inp1_mux),
4501 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4502 &rx7_mix1_inp2_mux),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004503 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4504 &rx1_mix2_inp1_mux),
4505 SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4506 &rx1_mix2_inp2_mux),
4507 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4508 &rx2_mix2_inp1_mux),
4509 SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4510 &rx2_mix2_inp2_mux),
4511 SND_SOC_DAPM_MUX("RX3 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4512 &rx3_mix2_inp1_mux),
4513 SND_SOC_DAPM_MUX("RX3 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4514 &rx3_mix2_inp2_mux),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004515
4516 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
4517 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
4518 SND_SOC_DAPM_PRE_PMD),
4519
4520 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
4521 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
4522 SND_SOC_DAPM_POST_PMD),
4523
4524 /* TX */
4525
4526 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
4527 0),
4528
4529 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
4530 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
4531
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004532 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
4533 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4534 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4535 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
4536 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4537 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4538
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004539 SND_SOC_DAPM_INPUT("AMIC1"),
4540 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
4541 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4542 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4543 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
4544 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4545 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4546 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
4547 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4548 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4549 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
4550 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4551 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4552
4553 SND_SOC_DAPM_INPUT("AMIC3"),
4554 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
4555 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4556 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4557
4558 SND_SOC_DAPM_INPUT("AMIC4"),
4559 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
4560 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4561 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4562
4563 SND_SOC_DAPM_INPUT("AMIC5"),
4564 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
4565 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4566
4567 SND_SOC_DAPM_INPUT("AMIC6"),
4568 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
4569 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4570
4571 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 -08004572 &dec1_mux, tabla_codec_enable_dec,
4573 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4574 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004575
4576 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 -08004577 &dec2_mux, tabla_codec_enable_dec,
4578 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4579 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004580
4581 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 -08004582 &dec3_mux, tabla_codec_enable_dec,
4583 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4584 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004585
4586 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 -08004587 &dec4_mux, tabla_codec_enable_dec,
4588 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4589 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004590
4591 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 -08004592 &dec5_mux, tabla_codec_enable_dec,
4593 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4594 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004595
4596 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 -08004597 &dec6_mux, tabla_codec_enable_dec,
4598 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4599 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004600
4601 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 -08004602 &dec7_mux, tabla_codec_enable_dec,
4603 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4604 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004605
4606 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 -08004607 &dec8_mux, tabla_codec_enable_dec,
4608 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4609 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004610
4611 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 -08004612 &dec9_mux, tabla_codec_enable_dec,
4613 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4614 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004615
4616 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 -08004617 &dec10_mux, tabla_codec_enable_dec,
4618 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4619 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004620
4621 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
4622 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
4623
4624 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
4625 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
4626 SND_SOC_DAPM_POST_PMD),
4627
4628 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
4629
4630 SND_SOC_DAPM_INPUT("AMIC2"),
4631 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
4632 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4633 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4634 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
4635 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4636 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4637 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
4638 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4639 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4640 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
4641 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4642 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4643 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
4644 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4645 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4646 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
4647 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4648 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4649 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
4650 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4651 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4652 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
4653 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4654 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4655
4656 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004657 SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
4658 0, tabla_codec_enable_slimtx,
4659 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4660
4661 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
4662 SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
4663 0, tabla_codec_enable_slimtx,
4664 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4665
4666 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
Neema Shetty3fb1b802012-04-27 13:53:24 -07004667 SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004668 0, tabla_codec_enable_slimtx,
4669 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4670
4671 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
Kiran Kandie408b842012-05-17 19:48:04 -07004672 SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004673 0, tabla_codec_enable_slimtx,
4674 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004675
4676 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
Neema Shetty3fb1b802012-04-27 13:53:24 -07004677 SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004678 0, tabla_codec_enable_slimtx,
4679 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004680
4681 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004682 SND_SOC_DAPM_AIF_OUT_E("SLIM TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
4683 0, tabla_codec_enable_slimtx,
4684 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004685
4686 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
4687 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4688 0, tabla_codec_enable_slimtx,
4689 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4690
4691 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
4692 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4693 0, tabla_codec_enable_slimtx,
4694 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4695
4696 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
4697 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
4698 0, 0, tabla_codec_enable_slimtx,
4699 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4700
4701 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
4702 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
4703 0, 0, tabla_codec_enable_slimtx,
4704 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4705
4706 /* Digital Mic Inputs */
4707 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
4708 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4709 SND_SOC_DAPM_POST_PMD),
4710
4711 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
4712 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4713 SND_SOC_DAPM_POST_PMD),
4714
4715 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
4716 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4717 SND_SOC_DAPM_POST_PMD),
4718
4719 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
4720 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4721 SND_SOC_DAPM_POST_PMD),
4722
4723 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
4724 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4725 SND_SOC_DAPM_POST_PMD),
4726 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
4727 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4728 SND_SOC_DAPM_POST_PMD),
4729
4730 /* Sidetone */
4731 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
4732 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08004733
4734 /* AUX PGA */
4735 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
4736 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4737 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4738 SND_SOC_DAPM_POST_PMD),
4739
4740 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
4741 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4742 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4743 SND_SOC_DAPM_POST_PMD),
4744
4745 /* Lineout, ear and HPH PA Mixers */
4746 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
4747 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
4748
4749 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4750 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4751
4752 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4753 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4754
4755 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4756 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
4757
4758 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
4759 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
4760
4761 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
4762 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
4763
4764 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
4765 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
4766
4767 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4768 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004769};
4770
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004771static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004772{
4773 u8 bias_msb, bias_lsb;
4774 short bias_value;
4775
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004776 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
4777 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
4778 bias_value = (bias_msb << 8) | bias_lsb;
4779 return bias_value;
4780}
4781
4782static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
4783{
4784 u8 bias_msb, bias_lsb;
4785 short bias_value;
4786
4787 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
4788 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
4789 bias_value = (bias_msb << 8) | bias_lsb;
4790 return bias_value;
4791}
4792
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004793static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004794{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004795 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
4796}
4797
4798static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4799 bool override_bypass, bool noreldetection)
4800{
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004801 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004802 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4803
4804 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4805 if (noreldetection)
4806 tabla_turn_onoff_rel_detection(codec, false);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004807
Joonwoo Park925914c2012-01-05 13:35:18 -08004808 /* Turn on the override */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004809 if (!override_bypass)
4810 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004811 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004812 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4813 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
4814 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004815 usleep_range(tabla->mbhc_data.t_sta_dce,
4816 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004817 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08004818 usleep_range(tabla->mbhc_data.t_dce,
4819 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004820 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004821 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004822 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004823 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4824 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004825 usleep_range(tabla->mbhc_data.t_sta_dce,
4826 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08004827 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4828 usleep_range(tabla->mbhc_data.t_sta,
4829 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004830 bias_value = tabla_codec_read_sta_result(codec);
4831 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4832 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004833 }
Joonwoo Park925914c2012-01-05 13:35:18 -08004834 /* Turn off the override after measuring mic voltage */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004835 if (!override_bypass)
4836 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4837
4838 if (noreldetection)
4839 tabla_turn_onoff_rel_detection(codec, true);
4840 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004841
Bradley Rubincb1e2732011-06-23 16:49:20 -07004842 return bias_value;
4843}
4844
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004845static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4846 bool norel)
4847{
4848 return __tabla_codec_sta_dce(codec, dce, false, norel);
4849}
4850
4851/* called only from interrupt which is under codec_resource_lock acquisition */
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004852static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004853{
4854 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004855 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004856 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004857
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004858 pr_debug("%s: enter, mclk_enabled %d\n", __func__, tabla->mclk_enabled);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004859 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004860 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004861 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004862 }
4863
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004864 if (!tabla->mclk_enabled) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004865 tabla_codec_disable_clock_block(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004866 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004867 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004868 tabla_codec_enable_clock_block(codec, 1);
4869 }
4870
4871 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4872
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004873 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004874 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4875 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004876
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004877 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004878
4879 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004880 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004881
4882 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4883 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4884 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4885
4886 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004887 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4888 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004889
Joonwoo Park925914c2012-01-05 13:35:18 -08004890 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004891 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4892
Bradley Rubincb1e2732011-06-23 16:49:20 -07004893 tabla_codec_calibrate_hs_polling(codec);
4894
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004895 /* don't flip override */
4896 bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004897 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4898 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004899 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004900
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004901 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004902}
4903
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004904static int tabla_cancel_btn_work(struct tabla_priv *tabla)
4905{
4906 int r = 0;
4907 struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
4908
4909 if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
4910 /* if scheduled mbhc_btn_dwork is canceled from here,
4911 * we have to unlock from here instead btn_work */
4912 wcd9xxx_unlock_sleep(core);
4913 r = 1;
4914 }
4915 return r;
4916}
4917
4918/* called under codec_resource_lock acquisition */
4919void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
Joonwoo Park03324832012-03-19 19:36:16 -07004920{
4921 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004922 u8 wg_time;
4923
4924 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4925 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07004926
4927 /* If headphone PA is on, check if userspace receives
4928 * removal event to sync-up PA's state */
4929 if (tabla_is_hph_pa_on(codec)) {
4930 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4931 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4932 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4933 } else {
4934 pr_debug("%s PA is off\n", __func__);
4935 }
4936
4937 if (tabla_is_hph_dac_on(codec, 1))
4938 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4939 if (tabla_is_hph_dac_on(codec, 0))
4940 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004941
4942 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
4943 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
4944 0xC0, 0x00);
4945 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
4946 0xC0, 0x00);
4947 usleep_range(wg_time * 1000, wg_time * 1000);
4948}
4949
4950static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
4951{
4952 bool pa_turned_on = false;
4953 struct snd_soc_codec *codec = tabla->codec;
4954 u8 wg_time;
4955
4956 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4957 wg_time += 1;
4958
4959 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4960 &tabla->hph_pa_dac_state)) {
4961 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4962 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4963 0xC0, 0xC0);
4964 }
4965 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4966 &tabla->hph_pa_dac_state)) {
4967 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4968 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4969 0xC0, 0xC0);
4970 }
4971
4972 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4973 &tabla->hph_pa_dac_state)) {
4974 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4975 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4976 1 << 4);
4977 pa_turned_on = true;
4978 }
4979 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4980 &tabla->hph_pa_dac_state)) {
4981 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4982 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4983 1 << 5);
4984 pa_turned_on = true;
4985 }
4986
4987 if (pa_turned_on) {
4988 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4989 __func__);
4990 usleep_range(wg_time * 1000, wg_time * 1000);
4991 }
4992}
4993
4994/* called under codec_resource_lock acquisition */
4995static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4996 enum snd_jack_types jack_type)
4997{
4998 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4999
5000 if (!insertion) {
5001 /* Report removal */
5002 tabla->hph_status &= ~jack_type;
5003 if (tabla->mbhc_cfg.headset_jack) {
5004 /* cancel possibly scheduled btn work and
5005 * report release if we reported button press */
5006 if (tabla_cancel_btn_work(tabla)) {
5007 pr_debug("%s: button press is canceled\n",
5008 __func__);
5009 } else if (tabla->buttons_pressed) {
5010 pr_debug("%s: Reporting release for reported "
5011 "button press %d\n", __func__,
5012 jack_type);
5013 tabla_snd_soc_jack_report(tabla,
5014 tabla->mbhc_cfg.button_jack, 0,
5015 tabla->buttons_pressed);
5016 tabla->buttons_pressed &=
5017 ~TABLA_JACK_BUTTON_MASK;
5018 }
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005019 pr_debug("%s: Reporting removal %d(%x)\n", __func__,
5020 jack_type, tabla->hph_status);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005021 tabla_snd_soc_jack_report(tabla,
5022 tabla->mbhc_cfg.headset_jack,
5023 tabla->hph_status,
5024 TABLA_JACK_MASK);
5025 }
5026 tabla_set_and_turnoff_hph_padac(codec);
5027 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
5028 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5029 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
5030 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5031 tabla->current_plug = PLUG_TYPE_NONE;
5032 tabla->mbhc_polling_active = false;
5033 } else {
5034 /* Report insertion */
5035 tabla->hph_status |= jack_type;
5036
5037 if (jack_type == SND_JACK_HEADPHONE)
5038 tabla->current_plug = PLUG_TYPE_HEADPHONE;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005039 else if (jack_type == SND_JACK_UNSUPPORTED)
5040 tabla->current_plug = PLUG_TYPE_GND_MIC_SWAP;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005041 else if (jack_type == SND_JACK_HEADSET) {
5042 tabla->mbhc_polling_active = true;
5043 tabla->current_plug = PLUG_TYPE_HEADSET;
5044 }
5045 if (tabla->mbhc_cfg.headset_jack) {
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005046 pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
5047 jack_type, tabla->hph_status);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005048 tabla_snd_soc_jack_report(tabla,
5049 tabla->mbhc_cfg.headset_jack,
5050 tabla->hph_status,
5051 TABLA_JACK_MASK);
5052 }
5053 tabla_clr_and_turnon_hph_padac(tabla);
5054 }
Joonwoo Park03324832012-03-19 19:36:16 -07005055}
5056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005057static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07005058 int insertion, int trigger,
5059 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005060{
5061 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005062 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08005063 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005064 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005065 const struct tabla_mbhc_plug_detect_cfg *plug_det =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005066 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005067
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005068 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005069 pr_err("Error, no tabla calibration\n");
5070 return -EINVAL;
5071 }
5072
5073 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
5074
Joonwoo Park03324832012-03-19 19:36:16 -07005075 /* Make sure mic bias and Mic line schmitt trigger
5076 * are turned OFF
5077 */
5078 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
5079 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5080
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005081 if (insertion) {
Joonwoo Park03324832012-03-19 19:36:16 -07005082 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005083
Joonwoo Park03324832012-03-19 19:36:16 -07005084 /* DAPM can manipulate PA/DAC bits concurrently */
5085 if (padac_off == true) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005086 tabla_set_and_turnoff_hph_padac(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005087 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005088
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005089 if (trigger & MBHC_USE_HPHL_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07005090 /* Enable HPH Schmitt Trigger */
5091 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
5092 0x11);
5093 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
5094 plug_det->hph_current << 2);
5095 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
5096 0x02);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005097 }
5098 if (trigger & MBHC_USE_MB_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07005099 /* enable the mic line schmitt trigger */
5100 snd_soc_update_bits(codec,
5101 tabla->mbhc_bias_regs.mbhc_reg,
5102 0x60, plug_det->mic_current << 5);
5103 snd_soc_update_bits(codec,
5104 tabla->mbhc_bias_regs.mbhc_reg,
5105 0x80, 0x80);
5106 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
5107 snd_soc_update_bits(codec,
5108 tabla->mbhc_bias_regs.ctl_reg, 0x01,
5109 0x00);
5110 snd_soc_update_bits(codec,
5111 tabla->mbhc_bias_regs.mbhc_reg,
5112 0x10, 0x10);
5113 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005114
5115 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005116 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005117 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005118 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005119 /* Make sure the HPH schmitt trigger is OFF */
5120 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
5121
5122 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07005123 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
5124 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005125 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08005126 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005127 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
5128 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08005129 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005130 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
5131 0x10, 0x10);
5132
5133 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005134 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005135 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005136
5137 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005138 /* called called by interrupt */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005139 if (!(tabla->clock_active)) {
5140 tabla_codec_enable_config_mode(codec, 1);
5141 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07005142 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08005143 usleep_range(generic->t_shutdown_plug_rem,
5144 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005145 tabla_codec_enable_config_mode(codec, 0);
5146 } else
5147 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07005148 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005149 }
5150
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07005151 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005152
5153 /* If central bandgap disabled */
5154 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
5155 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08005156 usleep_range(generic->t_bg_fast_settle,
5157 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005158 central_bias_enabled = 1;
5159 }
5160
5161 /* If LDO_H disabled */
5162 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
5163 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
5164 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08005165 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005166 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
5167
5168 if (central_bias_enabled)
5169 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
5170 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005171
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005172 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005173 tabla->mbhc_cfg.micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005174
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305175 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005176 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
5177 return 0;
5178}
5179
Joonwoo Park0976d012011-12-22 11:48:18 -08005180static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
5181 s16 vin_mv)
5182{
Joonwoo Park0976d012011-12-22 11:48:18 -08005183 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07005184 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08005185 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07005186 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08005187
5188 tabla = snd_soc_codec_get_drvdata(codec);
5189 mb_mv = tabla->mbhc_data.micb_mv;
5190
5191 if (mb_mv == 0) {
5192 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
5193 return -EINVAL;
5194 }
5195
5196 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07005197 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
5198 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08005199 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005200 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
5201 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08005202 }
5203 in = (u32) diff * vin_mv;
5204
Joonwoo Park03324832012-03-19 19:36:16 -07005205 value = (u16) (in / mb_mv) + zero;
5206 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08005207}
5208
5209static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
5210 u16 bias_value)
5211{
5212 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07005213 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08005214 s32 mv;
5215
5216 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005217 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08005218 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07005219 z = (tabla->mbhc_data.dce_z);
5220 mb = (tabla->mbhc_data.dce_mb);
5221 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08005222 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005223 z = (tabla->mbhc_data.sta_z);
5224 mb = (tabla->mbhc_data.sta_mb);
5225 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08005226 }
5227
5228 return mv;
5229}
5230
Joonwoo Park03324832012-03-19 19:36:16 -07005231static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005232{
5233 struct delayed_work *delayed_work;
5234 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08005235 short bias_value;
5236 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07005237 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005238
5239 pr_debug("%s:\n", __func__);
5240
5241 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07005242 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08005243 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005244
5245 if (tabla) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005246 if (tabla->mbhc_cfg.button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005247 bias_value = tabla_codec_read_sta_result(tabla->codec);
5248 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305249 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08005250 bias_value = tabla_codec_read_dce_result(tabla->codec);
5251 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305252 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08005253 pr_debug("%s: Reporting long button press event"
5254 " STA: %d, DCE: %d\n", __func__,
5255 sta_mv, dce_mv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005256 tabla_snd_soc_jack_report(tabla,
5257 tabla->mbhc_cfg.button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07005258 tabla->buttons_pressed,
5259 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005260 }
5261 } else {
5262 pr_err("%s: Bad tabla private data\n", __func__);
5263 }
5264
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005265 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07005266 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005267}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005268
Joonwoo Park0976d012011-12-22 11:48:18 -08005269void tabla_mbhc_cal(struct snd_soc_codec *codec)
5270{
5271 struct tabla_priv *tabla;
5272 struct tabla_mbhc_btn_detect_cfg *btn_det;
5273 u8 cfilt_mode, bg_mode;
5274 u8 ncic, nmeas, navg;
5275 u32 mclk_rate;
5276 u32 dce_wait, sta_wait;
5277 u8 *n_cic;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005278 void *calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08005279
5280 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005281 calibration = tabla->mbhc_cfg.calibration;
5282
5283 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
5284 tabla_turn_onoff_rel_detection(codec, false);
Joonwoo Park0976d012011-12-22 11:48:18 -08005285
5286 /* First compute the DCE / STA wait times
5287 * depending on tunable parameters.
5288 * The value is computed in microseconds
5289 */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005290 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005291 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08005292 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005293 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
5294 navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
5295 mclk_rate = tabla->mbhc_cfg.mclk_rate;
Joonwoo Park433149a2012-01-11 09:53:54 -08005296 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
5297 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08005298
5299 tabla->mbhc_data.t_dce = dce_wait;
5300 tabla->mbhc_data.t_sta = sta_wait;
5301
5302 /* LDOH and CFILT are already configured during pdata handling.
5303 * Only need to make sure CFILT and bandgap are in Fast mode.
5304 * Need to restore defaults once calculation is done.
5305 */
5306 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
5307 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
5308 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
5309 0x02);
5310
5311 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
5312 * to perform ADC calibration
5313 */
5314 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005315 tabla->mbhc_cfg.micbias << 5);
Joonwoo Park0976d012011-12-22 11:48:18 -08005316 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5317 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
5318 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
5319 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
5320
5321 /* DCE measurement for 0 volts */
5322 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
5323 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
5324 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08005325 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
5326 usleep_range(100, 100);
5327 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
5328 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
5329 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
5330
5331 /* DCE measurment for MB voltage */
5332 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
5333 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
5334 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
5335 usleep_range(100, 100);
5336 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
5337 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
5338 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
5339
5340 /* Sta measuremnt for 0 volts */
5341 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
5342 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
5343 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08005344 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
5345 usleep_range(100, 100);
5346 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
5347 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
5348 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
5349
5350 /* STA Measurement for MB Voltage */
5351 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
5352 usleep_range(100, 100);
5353 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
5354 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
5355 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
5356
5357 /* Restore default settings. */
5358 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
5359 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
5360 cfilt_mode);
5361 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
5362
5363 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
5364 usleep_range(100, 100);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005365
5366 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
5367 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08005368}
5369
5370void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
5371 const enum tabla_mbhc_btn_det_mem mem)
5372{
5373 void *ret = &btn_det->_v_btn_low;
5374
5375 switch (mem) {
5376 case TABLA_BTN_DET_GAIN:
5377 ret += sizeof(btn_det->_n_cic);
5378 case TABLA_BTN_DET_N_CIC:
5379 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08005380 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08005381 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
5382 case TABLA_BTN_DET_V_BTN_HIGH:
5383 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
5384 case TABLA_BTN_DET_V_BTN_LOW:
5385 /* do nothing */
5386 break;
5387 default:
5388 ret = NULL;
5389 }
5390
5391 return ret;
5392}
5393
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005394static s16 tabla_scale_v_micb_vddio(struct tabla_priv *tabla, int v,
5395 bool tovddio)
5396{
5397 int r;
5398 int vddio_k, mb_k;
5399 vddio_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
5400 VDDIO_MICBIAS_MV);
5401 mb_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
5402 tabla->mbhc_data.micb_mv);
5403 if (tovddio)
5404 r = v * vddio_k / mb_k;
5405 else
5406 r = v * mb_k / vddio_k;
5407 return r;
5408}
5409
Joonwoo Park0976d012011-12-22 11:48:18 -08005410static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
5411{
5412 struct tabla_priv *tabla;
5413 s16 btn_mv = 0, btn_delta_mv;
5414 struct tabla_mbhc_btn_detect_cfg *btn_det;
5415 struct tabla_mbhc_plug_type_cfg *plug_type;
5416 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08005417 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08005418 int i;
5419
5420 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005421 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
5422 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005423
Joonwoo Parkc0672392012-01-11 11:03:14 -08005424 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005425 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07005426 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08005427 tabla->mbhc_data.nbounce_wait = 30;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005428 } else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005429 tabla->mbhc_data.npoll = 7;
5430 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08005431 }
Joonwoo Park0976d012011-12-22 11:48:18 -08005432
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005433 tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
5434 (tabla->mbhc_cfg.mclk_rate / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08005435 n_ready[tabla_codec_mclk_index(tabla)]) +
5436 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08005437 tabla->mbhc_data.v_ins_hu =
5438 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
5439 tabla->mbhc_data.v_ins_h =
5440 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
5441
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005442 tabla->mbhc_data.v_inval_ins_low = TABLA_MBHC_FAKE_INSERT_LOW;
5443 if (tabla->mbhc_cfg.gpio)
5444 tabla->mbhc_data.v_inval_ins_high =
5445 TABLA_MBHC_FAKE_INSERT_HIGH;
5446 else
5447 tabla->mbhc_data.v_inval_ins_high =
5448 TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
5449
5450 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
5451 tabla->mbhc_data.adj_v_hs_max =
5452 tabla_scale_v_micb_vddio(tabla, plug_type->v_hs_max, true);
5453 tabla->mbhc_data.adj_v_ins_hu =
5454 tabla_codec_v_sta_dce(codec, STA,
5455 tabla->mbhc_data.adj_v_hs_max);
5456 tabla->mbhc_data.adj_v_ins_h =
5457 tabla_codec_v_sta_dce(codec, DCE,
5458 tabla->mbhc_data.adj_v_hs_max);
5459 tabla->mbhc_data.v_inval_ins_low =
5460 tabla_scale_v_micb_vddio(tabla,
5461 tabla->mbhc_data.v_inval_ins_low,
5462 false);
5463 tabla->mbhc_data.v_inval_ins_high =
5464 tabla_scale_v_micb_vddio(tabla,
5465 tabla->mbhc_data.v_inval_ins_high,
5466 false);
5467 }
5468
Joonwoo Park0976d012011-12-22 11:48:18 -08005469 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
5470 for (i = 0; i < btn_det->num_btn; i++)
5471 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
5472
5473 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
5474 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
Joonwoo Park0976d012011-12-22 11:48:18 -08005475 tabla->mbhc_data.v_b1_hu =
5476 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
5477
5478 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
5479
5480 tabla->mbhc_data.v_b1_huc =
5481 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
5482
5483 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
Joonwoo Park03324832012-03-19 19:36:16 -07005484 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
Joonwoo Park0976d012011-12-22 11:48:18 -08005485
5486 tabla->mbhc_data.v_no_mic =
5487 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
5488}
5489
5490void tabla_mbhc_init(struct snd_soc_codec *codec)
5491{
5492 struct tabla_priv *tabla;
5493 struct tabla_mbhc_general_cfg *generic;
5494 struct tabla_mbhc_btn_detect_cfg *btn_det;
5495 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08005496 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305497 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08005498
5499 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005500 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
5501 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005502
Joonwoo Park0976d012011-12-22 11:48:18 -08005503 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005504 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005505 snd_soc_update_bits(codec,
5506 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
5507 0x07, n);
5508 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
5509 btn_det->c[n]);
5510 }
5511 }
5512 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
5513 btn_det->nc);
5514
5515 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
5516 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08005517 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08005518
5519 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08005520 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
5521 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08005522
5523 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
5524 generic->mbhc_nsa << 4);
5525
5526 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
5527 btn_det->n_meas);
5528
5529 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
5530
5531 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
5532
5533 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
5534 btn_det->mbhc_nsc << 3);
5535
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005536 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
5537 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08005538
5539 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07005540
5541 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Park0976d012011-12-22 11:48:18 -08005542}
5543
Patrick Lai64b43262011-12-06 17:29:15 -08005544static bool tabla_mbhc_fw_validate(const struct firmware *fw)
5545{
5546 u32 cfg_offset;
5547 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
5548 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
5549
5550 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
5551 return false;
5552
5553 /* previous check guarantees that there is enough fw data up
5554 * to num_btn
5555 */
5556 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
5557 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
5558 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
5559 return false;
5560
5561 /* previous check guarantees that there is enough fw data up
5562 * to start of impedance detection configuration
5563 */
5564 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
5565 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
5566
5567 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
5568 return false;
5569
5570 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
5571 return false;
5572
5573 return true;
5574}
Joonwoo Park03324832012-03-19 19:36:16 -07005575
Joonwoo Parkfee17432012-04-16 16:33:55 -07005576/* called under codec_resource_lock acquisition */
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005577static int tabla_determine_button(const struct tabla_priv *priv,
Joonwoo Parkfee17432012-04-16 16:33:55 -07005578 const s32 micmv)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005579{
5580 s16 *v_btn_low, *v_btn_high;
5581 struct tabla_mbhc_btn_detect_cfg *btn_det;
5582 int i, btn = -1;
5583
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005584 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005585 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
5586 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305587 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Parkfee17432012-04-16 16:33:55 -07005588
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005589 for (i = 0; i < btn_det->num_btn; i++) {
Joonwoo Parkfee17432012-04-16 16:33:55 -07005590 if ((v_btn_low[i] <= micmv) && (v_btn_high[i] >= micmv)) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005591 btn = i;
5592 break;
5593 }
5594 }
5595
5596 if (btn == -1)
5597 pr_debug("%s: couldn't find button number for mic mv %d\n",
Joonwoo Parkfee17432012-04-16 16:33:55 -07005598 __func__, micmv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005599
5600 return btn;
5601}
5602
5603static int tabla_get_button_mask(const int btn)
5604{
5605 int mask = 0;
5606 switch (btn) {
5607 case 0:
5608 mask = SND_JACK_BTN_0;
5609 break;
5610 case 1:
5611 mask = SND_JACK_BTN_1;
5612 break;
5613 case 2:
5614 mask = SND_JACK_BTN_2;
5615 break;
5616 case 3:
5617 mask = SND_JACK_BTN_3;
5618 break;
5619 case 4:
5620 mask = SND_JACK_BTN_4;
5621 break;
5622 case 5:
5623 mask = SND_JACK_BTN_5;
5624 break;
5625 case 6:
5626 mask = SND_JACK_BTN_6;
5627 break;
5628 case 7:
5629 mask = SND_JACK_BTN_7;
5630 break;
5631 }
5632 return mask;
5633}
5634
Bradley Rubincb1e2732011-06-23 16:49:20 -07005635static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005636{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005637 int i, mask;
Joonwoo Parkfee17432012-04-16 16:33:55 -07005638 short dce, sta;
5639 s32 mv, mv_s, stamv_s;
5640 bool vddio;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005641 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005642 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005643 const struct tabla_mbhc_btn_detect_cfg *d =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005644 TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005645 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005646 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305647 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07005648 int n_btn_meas = d->n_btn_meas;
5649 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005650
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005651 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005652
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005653 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5654 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
5655 pr_debug("%s: mbhc is being recovered, skip button press\n",
5656 __func__);
5657 goto done;
5658 }
5659
5660 priv->mbhc_state = MBHC_STATE_POTENTIAL;
5661
5662 if (!priv->mbhc_polling_active) {
5663 pr_warn("%s: mbhc polling is not active, skip button press\n",
5664 __func__);
5665 goto done;
5666 }
Joonwoo Park03324832012-03-19 19:36:16 -07005667
5668 dce = tabla_codec_read_dce_result(codec);
5669 mv = tabla_codec_sta_dce_v(codec, 1, dce);
5670
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005671 /* If GPIO interrupt already kicked in, ignore button press */
5672 if (priv->in_gpio_handler) {
5673 pr_debug("%s: GPIO State Changed, ignore button press\n",
5674 __func__);
5675 btn = -1;
5676 goto done;
5677 }
5678
Joonwoo Parkfee17432012-04-16 16:33:55 -07005679 vddio = (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
5680 priv->mbhc_micbias_switched);
5681 mv_s = vddio ? tabla_scale_v_micb_vddio(priv, mv, false) : mv;
5682
Joonwoo Park03324832012-03-19 19:36:16 -07005683 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
5684 if (priv->mbhc_last_resume &&
5685 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
5686 pr_debug("%s: Button is already released shortly after "
5687 "resume\n", __func__);
5688 n_btn_meas = 0;
5689 } else {
5690 pr_debug("%s: Button is already released without "
5691 "resume", __func__);
5692 sta = tabla_codec_read_sta_result(codec);
Joonwoo Parkfee17432012-04-16 16:33:55 -07005693 stamv_s = tabla_codec_sta_dce_v(codec, 0, sta);
5694 if (vddio)
5695 stamv_s = tabla_scale_v_micb_vddio(priv,
5696 stamv_s,
5697 false);
5698 btn = tabla_determine_button(priv, mv_s);
5699 if (btn != tabla_determine_button(priv, stamv_s))
Joonwoo Park03324832012-03-19 19:36:16 -07005700 btn = -1;
5701 goto done;
5702 }
5703 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005704
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005705 /* determine pressed button */
Joonwoo Parkfee17432012-04-16 16:33:55 -07005706 btnmeas[meas++] = tabla_determine_button(priv, mv_s);
5707 pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n", __func__,
5708 meas - 1, dce, mv, mv_s, btnmeas[meas - 1]);
Joonwoo Park03324832012-03-19 19:36:16 -07005709 if (n_btn_meas == 0)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005710 btn = btnmeas[0];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005711 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
Joonwoo Parkfee17432012-04-16 16:33:55 -07005712 dce = tabla_codec_sta_dce(codec, 1, false);
5713 mv = tabla_codec_sta_dce_v(codec, 1, dce);
5714 mv_s = vddio ? tabla_scale_v_micb_vddio(priv, mv, false) : mv;
5715
5716 btnmeas[meas] = tabla_determine_button(priv, mv_s);
5717 pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n",
5718 __func__, meas, dce, mv, mv_s, btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005719 /* if large enough measurements are collected,
5720 * start to check if last all n_btn_con measurements were
5721 * in same button low/high range */
5722 if (meas + 1 >= d->n_btn_con) {
5723 for (i = 0; i < d->n_btn_con; i++)
5724 if ((btnmeas[meas] < 0) ||
5725 (btnmeas[meas] != btnmeas[meas - i]))
5726 break;
5727 if (i == d->n_btn_con) {
5728 /* button pressed */
5729 btn = btnmeas[meas];
5730 break;
Joonwoo Park03324832012-03-19 19:36:16 -07005731 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
5732 /* if left measurements are less than n_btn_con,
5733 * it's impossible to find button number */
5734 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005735 }
5736 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005737 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005738
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005739 if (btn >= 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005740 if (priv->in_gpio_handler) {
5741 pr_debug("%s: GPIO already triggered, ignore button "
5742 "press\n", __func__);
5743 goto done;
5744 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005745 mask = tabla_get_button_mask(btn);
5746 priv->buttons_pressed |= mask;
Joonwoo Park03324832012-03-19 19:36:16 -07005747 wcd9xxx_lock_sleep(core);
5748 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
5749 msecs_to_jiffies(400)) == 0) {
5750 WARN(1, "Button pressed twice without release"
5751 "event\n");
5752 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005753 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08005754 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005755 pr_debug("%s: bogus button press, too short press?\n",
5756 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08005757 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005758
Joonwoo Park03324832012-03-19 19:36:16 -07005759 done:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005760 pr_debug("%s: leave\n", __func__);
5761 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005762 return IRQ_HANDLED;
5763}
5764
Joonwoo Park03324832012-03-19 19:36:16 -07005765static int tabla_is_fake_press(struct tabla_priv *priv)
5766{
5767 int i;
5768 int r = 0;
5769 struct snd_soc_codec *codec = priv->codec;
5770 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005771 s16 mb_v, v_ins_hu, v_ins_h;
5772
5773 v_ins_hu = tabla_get_current_v_ins(priv, true);
5774 v_ins_h = tabla_get_current_v_ins(priv, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005775
5776 for (i = 0; i < dces; i++) {
5777 usleep_range(10000, 10000);
5778 if (i == 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005779 mb_v = tabla_codec_sta_dce(codec, 0, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005780 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
5781 tabla_codec_sta_dce_v(codec, 0, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005782 if (mb_v < (s16)priv->mbhc_data.v_b1_hu ||
5783 mb_v > v_ins_hu) {
Joonwoo Park03324832012-03-19 19:36:16 -07005784 r = 1;
5785 break;
5786 }
5787 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005788 mb_v = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005789 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
5790 tabla_codec_sta_dce_v(codec, 1, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005791 if (mb_v < (s16)priv->mbhc_data.v_b1_h ||
5792 mb_v > v_ins_h) {
Joonwoo Park03324832012-03-19 19:36:16 -07005793 r = 1;
5794 break;
5795 }
5796 }
5797 }
5798
5799 return r;
5800}
5801
Bradley Rubincb1e2732011-06-23 16:49:20 -07005802static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005803{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08005804 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08005805 struct tabla_priv *priv = data;
5806 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005807
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005808 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07005809
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005810 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5811 priv->mbhc_state = MBHC_STATE_RELEASE;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005812
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005813 tabla_codec_drive_v_to_micbias(codec, 10000);
5814
Joonwoo Park03324832012-03-19 19:36:16 -07005815 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005816 ret = tabla_cancel_btn_work(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005817 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07005818 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005819 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005820 if (priv->mbhc_cfg.button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005821 tabla_snd_soc_jack_report(priv,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005822 priv->mbhc_cfg.button_jack, 0,
5823 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005824 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005825 if (tabla_is_fake_press(priv)) {
5826 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005827 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005828 } else if (priv->mbhc_cfg.button_jack) {
5829 if (priv->in_gpio_handler) {
5830 pr_debug("%s: GPIO kicked in, ignore\n",
5831 __func__);
5832 } else {
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005833 pr_debug("%s: Reporting short button "
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005834 "press and release\n",
5835 __func__);
5836 tabla_snd_soc_jack_report(priv,
5837 priv->mbhc_cfg.button_jack,
5838 priv->buttons_pressed,
5839 priv->buttons_pressed);
5840 tabla_snd_soc_jack_report(priv,
5841 priv->mbhc_cfg.button_jack, 0,
5842 priv->buttons_pressed);
5843 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005844 }
5845 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005846
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005847 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
5848 }
5849
Joonwoo Park03324832012-03-19 19:36:16 -07005850 tabla_codec_calibrate_hs_polling(codec);
5851
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005852 if (priv->mbhc_cfg.gpio)
5853 msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
Joonwoo Park03324832012-03-19 19:36:16 -07005854
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005855 tabla_codec_start_hs_polling(codec);
5856
5857 pr_debug("%s: leave\n", __func__);
5858 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005859 return IRQ_HANDLED;
5860}
5861
Bradley Rubincb1e2732011-06-23 16:49:20 -07005862static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
5863{
5864 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08005865 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005866 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005867
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005868 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005869 tabla_codec_enable_config_mode(codec, 1);
5870
5871 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
5872 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005873
Joonwoo Park0976d012011-12-22 11:48:18 -08005874 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
5875
5876 usleep_range(generic->t_shutdown_plug_rem,
5877 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005878
5879 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005880 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005881 tabla_codec_enable_config_mode(codec, 0);
5882
5883 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
5884}
5885
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005886static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005887{
5888 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005889
5890 tabla_codec_shutdown_hs_removal_detect(codec);
5891
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005892 if (!tabla->mclk_enabled) {
Asish Bhattacharya486745a2012-01-20 06:41:53 +05305893 tabla_codec_disable_clock_block(codec);
5894 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005895 }
5896
5897 tabla->mbhc_polling_active = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005898 tabla->mbhc_state = MBHC_STATE_NONE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005899}
5900
Patrick Lai49efeac2011-11-03 11:01:12 -07005901static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
5902{
5903 struct tabla_priv *tabla = data;
5904 struct snd_soc_codec *codec;
5905
5906 pr_info("%s: received HPHL OCP irq\n", __func__);
5907
5908 if (tabla) {
5909 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005910 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
5911 pr_info("%s: retry\n", __func__);
5912 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5913 0x00);
5914 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5915 0x10);
5916 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305917 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005918 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5919 tabla->hphlocp_cnt = 0;
5920 tabla->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005921 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005922 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005923 tabla->mbhc_cfg.headset_jack,
5924 tabla->hph_status,
5925 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005926 }
5927 } else {
5928 pr_err("%s: Bad tabla private data\n", __func__);
5929 }
5930
5931 return IRQ_HANDLED;
5932}
5933
5934static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
5935{
5936 struct tabla_priv *tabla = data;
5937 struct snd_soc_codec *codec;
5938
5939 pr_info("%s: received HPHR OCP irq\n", __func__);
5940
5941 if (tabla) {
5942 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005943 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
5944 pr_info("%s: retry\n", __func__);
5945 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5946 0x00);
5947 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5948 0x10);
5949 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305950 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005951 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5952 tabla->hphrocp_cnt = 0;
5953 tabla->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005954 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005955 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005956 tabla->mbhc_cfg.headset_jack,
5957 tabla->hph_status,
5958 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005959 }
5960 } else {
5961 pr_err("%s: Bad tabla private data\n", __func__);
5962 }
5963
5964 return IRQ_HANDLED;
5965}
5966
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005967static bool tabla_is_inval_ins_range(struct snd_soc_codec *codec,
5968 s32 mic_volt, bool highhph, bool *highv)
Joonwoo Park03324832012-03-19 19:36:16 -07005969{
5970 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005971 bool invalid = false;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005972 s16 v_hs_max;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005973
5974 /* Perform this check only when the high voltage headphone
5975 * needs to be considered as invalid
5976 */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005977 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005978 *highv = mic_volt > v_hs_max;
5979 if (!highhph && *highv)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005980 invalid = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005981 else if (mic_volt < tabla->mbhc_data.v_inval_ins_high &&
5982 (mic_volt > tabla->mbhc_data.v_inval_ins_low))
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005983 invalid = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005984
5985 return invalid;
5986}
5987
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005988static bool tabla_is_inval_ins_delta(struct snd_soc_codec *codec,
5989 int mic_volt, int mic_volt_prev,
5990 int threshold)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005991{
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005992 return abs(mic_volt - mic_volt_prev) > threshold;
Joonwoo Park03324832012-03-19 19:36:16 -07005993}
5994
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005995/* called under codec_resource_lock acquisition */
5996void tabla_find_plug_and_report(struct snd_soc_codec *codec,
5997 enum tabla_mbhc_plug_type plug_type)
Joonwoo Park03324832012-03-19 19:36:16 -07005998{
5999 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006000
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006001 if (plug_type == PLUG_TYPE_HEADPHONE &&
6002 tabla->current_plug == PLUG_TYPE_NONE) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006003 /* Nothing was reported previously
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006004 * report a headphone or unsupported
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006005 */
6006 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
6007 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006008 } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
6009 if (tabla->current_plug == PLUG_TYPE_HEADSET)
6010 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6011 else if (tabla->current_plug == PLUG_TYPE_HEADPHONE)
6012 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
6013
6014 tabla_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
6015 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006016 } else if (plug_type == PLUG_TYPE_HEADSET) {
6017 /* If Headphone was reported previously, this will
6018 * only report the mic line
6019 */
6020 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
6021 msleep(100);
6022 tabla_codec_start_hs_polling(codec);
6023 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
6024 if (tabla->current_plug == PLUG_TYPE_NONE)
6025 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
6026 tabla_codec_cleanup_hs_polling(codec);
6027 pr_debug("setup mic trigger for further detection\n");
6028 tabla->lpi_enabled = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006029 tabla_codec_enable_hs_detect(codec, 1,
6030 MBHC_USE_MB_TRIGGER |
6031 MBHC_USE_HPHL_TRIGGER,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006032 false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006033 } else {
6034 WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
6035 tabla->current_plug, plug_type);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006036 }
6037}
6038
6039/* should be called under interrupt context that hold suspend */
6040static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla)
6041{
6042 pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
6043 tabla->hs_detect_work_stop = false;
6044 wcd9xxx_lock_sleep(tabla->codec->control_data);
6045 schedule_work(&tabla->hs_correct_plug_work);
6046}
6047
6048/* called under codec_resource_lock acquisition */
6049static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla)
6050{
6051 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
6052 tabla->hs_detect_work_stop = true;
6053 wmb();
6054 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6055 if (cancel_work_sync(&tabla->hs_correct_plug_work)) {
6056 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
6057 wcd9xxx_unlock_sleep(tabla->codec->control_data);
6058 }
6059 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
6060}
6061
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006062static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
6063{
6064 return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
6065 tabla->mbhc_cfg.gpio_level_insert);
6066}
6067
Joonwoo Park41956722012-04-18 13:13:07 -07006068/* called under codec_resource_lock acquisition */
6069static void tabla_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
6070{
6071 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, on);
6072 if (on)
6073 usleep_range(5000, 5000);
6074}
6075
6076/* called under codec_resource_lock acquisition and mbhc override = 1 */
6077static enum tabla_mbhc_plug_type
6078tabla_codec_get_plug_type(struct snd_soc_codec *codec, bool highhph)
6079{
6080 int i;
6081 bool gndswitch, vddioswitch;
6082 int scaled;
6083 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
6084 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6085 const bool vddio = (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV);
6086 int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
6087 enum tabla_mbhc_plug_type plug_type[num_det];
6088 s16 mb_v[num_det];
6089 s32 mic_mv[num_det];
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006090 bool inval;
6091 bool highdelta;
6092 bool ahighv = false, highv;
Joonwoo Park41956722012-04-18 13:13:07 -07006093
6094 /* make sure override is on */
6095 WARN_ON(!(snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04));
6096
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006097 /* GND and MIC swap detection requires at least 2 rounds of DCE */
6098 BUG_ON(num_det < 2);
6099
6100 plug_type_ptr =
6101 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
6102
6103 plug_type[0] = PLUG_TYPE_INVALID;
6104
Joonwoo Park41956722012-04-18 13:13:07 -07006105 /* performs DCEs for N times
6106 * 1st: check if voltage is in invalid range
6107 * 2nd - N-2nd: check voltage range and delta
6108 * N-1st: check voltage range, delta with HPHR GND switch
6109 * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006110 for (i = 0; i < num_det; i++) {
Joonwoo Park41956722012-04-18 13:13:07 -07006111 gndswitch = (i == (num_det - 1 - vddio));
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006112 vddioswitch = (vddio && ((i == num_det - 1) ||
6113 (i == num_det - 2)));
Joonwoo Park41956722012-04-18 13:13:07 -07006114 if (i == 0) {
6115 mb_v[i] = tabla_codec_setup_hs_polling(codec);
6116 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006117 inval = tabla_is_inval_ins_range(codec, mic_mv[i],
6118 highhph, &highv);
6119 ahighv |= highv;
Joonwoo Park41956722012-04-18 13:13:07 -07006120 scaled = mic_mv[i];
Joonwoo Park41956722012-04-18 13:13:07 -07006121 } else {
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006122 if (vddioswitch)
6123 __tabla_codec_switch_micbias(tabla->codec, 1,
6124 false, false);
Joonwoo Park41956722012-04-18 13:13:07 -07006125 if (gndswitch)
6126 tabla_codec_hphr_gnd_switch(codec, true);
6127 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
6128 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006129 if (vddioswitch)
6130 scaled = tabla_scale_v_micb_vddio(tabla,
Joonwoo Park41956722012-04-18 13:13:07 -07006131 mic_mv[i],
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006132 false);
6133 else
6134 scaled = mic_mv[i];
6135 /* !gndswitch & vddioswitch means the previous DCE
6136 * was done with gndswitch, don't compare with DCE
6137 * with gndswitch */
6138 highdelta = tabla_is_inval_ins_delta(codec, scaled,
6139 mic_mv[i - !gndswitch - vddioswitch],
6140 TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV);
6141 inval = (tabla_is_inval_ins_range(codec, mic_mv[i],
6142 highhph, &highv) ||
6143 highdelta);
6144 ahighv |= highv;
Joonwoo Park41956722012-04-18 13:13:07 -07006145 if (gndswitch)
6146 tabla_codec_hphr_gnd_switch(codec, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006147 if (vddioswitch)
6148 __tabla_codec_switch_micbias(tabla->codec, 0,
6149 false, false);
6150 /* claim UNSUPPORTED plug insertion when
6151 * good headset is detected but HPHR GND switch makes
6152 * delta difference */
6153 if (i == (num_det - 2) && highdelta && !ahighv)
6154 plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
6155 else if (i == (num_det - 1) && inval)
6156 plug_type[0] = PLUG_TYPE_INVALID;
Joonwoo Park41956722012-04-18 13:13:07 -07006157 }
6158 pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006159 "VDDIO %d, inval %d\n", __func__,
Joonwoo Park41956722012-04-18 13:13:07 -07006160 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006161 vddioswitch, inval);
6162 /* don't need to run further DCEs */
6163 if (ahighv && inval)
6164 break;
6165 mic_mv[i] = scaled;
Joonwoo Park41956722012-04-18 13:13:07 -07006166 }
6167
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006168 for (i = 0; (plug_type[0] != PLUG_TYPE_GND_MIC_SWAP && !inval) &&
6169 i < num_det; i++) {
Joonwoo Park41956722012-04-18 13:13:07 -07006170 /*
6171 * If we are here, means none of the all
6172 * measurements are fake, continue plug type detection.
6173 * If all three measurements do not produce same
6174 * plug type, restart insertion detection
6175 */
6176 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
6177 plug_type[i] = PLUG_TYPE_HEADPHONE;
6178 pr_debug("%s: Detect attempt %d, detected Headphone\n",
6179 __func__, i);
6180 } else if (highhph && (mic_mv[i] > plug_type_ptr->v_hs_max)) {
6181 plug_type[i] = PLUG_TYPE_HIGH_HPH;
6182 pr_debug("%s: Detect attempt %d, detected High "
6183 "Headphone\n", __func__, i);
6184 } else {
6185 plug_type[i] = PLUG_TYPE_HEADSET;
6186 pr_debug("%s: Detect attempt %d, detected Headset\n",
6187 __func__, i);
6188 }
6189
6190 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
6191 pr_err("%s: Detect attempt %d and %d are not same",
6192 __func__, i - 1, i);
6193 plug_type[0] = PLUG_TYPE_INVALID;
6194 inval = true;
6195 break;
6196 }
6197 }
6198
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006199 pr_debug("%s: Detected plug type %d\n", __func__, plug_type[0]);
Joonwoo Park41956722012-04-18 13:13:07 -07006200 return plug_type[0];
6201}
6202
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006203static void tabla_hs_correct_gpio_plug(struct work_struct *work)
6204{
6205 struct tabla_priv *tabla;
6206 struct snd_soc_codec *codec;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006207 int retry = 0, pt_gnd_mic_swap_cnt = 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006208 bool correction = false;
Joonwoo Park41956722012-04-18 13:13:07 -07006209 enum tabla_mbhc_plug_type plug_type;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006210 unsigned long timeout;
6211
6212 tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
6213 codec = tabla->codec;
6214
6215 pr_debug("%s: enter\n", __func__);
6216 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
6217
6218 /* Keep override on during entire plug type correction work.
6219 *
6220 * This is okay under the assumption that any GPIO irqs which use
6221 * MBHC block cancel and sync this work so override is off again
6222 * prior to GPIO interrupt handler's MBHC block usage.
6223 * Also while this correction work is running, we can guarantee
6224 * DAPM doesn't use any MBHC block as this work only runs with
6225 * headphone detection.
6226 */
6227 tabla_turn_onoff_override(codec, true);
6228
6229 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
6230 while (!time_after(jiffies, timeout)) {
6231 ++retry;
6232 rmb();
6233 if (tabla->hs_detect_work_stop) {
6234 pr_debug("%s: stop requested\n", __func__);
6235 break;
6236 }
6237
6238 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
6239 if (tabla_hs_gpio_level_remove(tabla)) {
6240 pr_debug("%s: GPIO value is low\n", __func__);
6241 break;
6242 }
6243
6244 /* can race with removal interrupt */
6245 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park41956722012-04-18 13:13:07 -07006246 plug_type = tabla_codec_get_plug_type(codec, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006247 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6248
Joonwoo Park41956722012-04-18 13:13:07 -07006249 if (plug_type == PLUG_TYPE_INVALID) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006250 pr_debug("Invalid plug in attempt # %d\n", retry);
6251 if (retry == NUM_ATTEMPTS_TO_REPORT &&
6252 tabla->current_plug == PLUG_TYPE_NONE) {
6253 tabla_codec_report_plug(codec, 1,
6254 SND_JACK_HEADPHONE);
6255 }
Joonwoo Park41956722012-04-18 13:13:07 -07006256 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006257 pr_debug("Good headphone detected, continue polling mic\n");
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006258 if (tabla->current_plug == PLUG_TYPE_NONE)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006259 tabla_codec_report_plug(codec, 1,
6260 SND_JACK_HEADPHONE);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006261 } else {
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006262 if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
6263 pt_gnd_mic_swap_cnt++;
6264 if (pt_gnd_mic_swap_cnt <
6265 TABLA_MBHC_GND_MIC_SWAP_THRESHOLD)
6266 continue;
6267 else if (pt_gnd_mic_swap_cnt >
6268 TABLA_MBHC_GND_MIC_SWAP_THRESHOLD) {
6269 /* This is due to GND/MIC switch didn't
6270 * work, Report unsupported plug */
6271 } else if (tabla->mbhc_cfg.swap_gnd_mic) {
6272 /* if switch is toggled, check again,
6273 * otherwise report unsupported plug */
6274 if (tabla->mbhc_cfg.swap_gnd_mic(codec))
6275 continue;
6276 }
6277 } else
6278 pt_gnd_mic_swap_cnt = 0;
6279
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006280 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
6281 /* Turn off override */
6282 tabla_turn_onoff_override(codec, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006283 /* The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
6284 */
Joonwoo Park41956722012-04-18 13:13:07 -07006285 tabla_find_plug_and_report(codec, plug_type);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006286 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6287 pr_debug("Attempt %d found correct plug %d\n", retry,
Joonwoo Park41956722012-04-18 13:13:07 -07006288 plug_type);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006289 correction = true;
6290 break;
6291 }
6292 }
6293
6294 /* Turn off override */
6295 if (!correction)
6296 tabla_turn_onoff_override(codec, false);
6297
6298 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
6299 pr_debug("%s: leave\n", __func__);
6300 /* unlock sleep */
6301 wcd9xxx_unlock_sleep(tabla->codec->control_data);
6302}
6303
6304/* called under codec_resource_lock acquisition */
6305static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
6306{
Joonwoo Park41956722012-04-18 13:13:07 -07006307 enum tabla_mbhc_plug_type plug_type;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006308 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006309
6310 pr_debug("%s: enter\n", __func__);
6311
6312 tabla_turn_onoff_override(codec, true);
Joonwoo Park41956722012-04-18 13:13:07 -07006313 plug_type = tabla_codec_get_plug_type(codec, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006314 tabla_turn_onoff_override(codec, false);
6315
6316 if (tabla_hs_gpio_level_remove(tabla)) {
6317 pr_debug("%s: GPIO value is low when determining plug\n",
6318 __func__);
6319 return;
6320 }
6321
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006322 if (plug_type == PLUG_TYPE_INVALID ||
6323 plug_type == PLUG_TYPE_GND_MIC_SWAP) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006324 tabla_schedule_hs_detect_plug(tabla);
Joonwoo Park41956722012-04-18 13:13:07 -07006325 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006326 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
6327
6328 tabla_schedule_hs_detect_plug(tabla);
6329 } else {
Joonwoo Park41956722012-04-18 13:13:07 -07006330 pr_debug("%s: Valid plug found, determine plug type %d\n",
6331 __func__, plug_type);
6332 tabla_find_plug_and_report(codec, plug_type);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006333 }
6334}
6335
6336/* called under codec_resource_lock acquisition */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006337static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
6338{
Joonwoo Park41956722012-04-18 13:13:07 -07006339 enum tabla_mbhc_plug_type plug_type;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006340 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6341 const struct tabla_mbhc_plug_detect_cfg *plug_det =
6342 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07006343
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006344 /* Turn on the override,
6345 * tabla_codec_setup_hs_polling requires override on */
6346 tabla_turn_onoff_override(codec, true);
Joonwoo Park03324832012-03-19 19:36:16 -07006347
6348 if (plug_det->t_ins_complete > 20)
6349 msleep(plug_det->t_ins_complete);
6350 else
6351 usleep_range(plug_det->t_ins_complete * 1000,
6352 plug_det->t_ins_complete * 1000);
6353
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006354 if (tabla->mbhc_cfg.gpio) {
6355 /* Turn off the override */
6356 tabla_turn_onoff_override(codec, false);
6357 if (tabla_hs_gpio_level_remove(tabla))
6358 pr_debug("%s: GPIO value is low when determining "
6359 "plug\n", __func__);
6360 else
6361 tabla_codec_decide_gpio_plug(codec);
6362 return;
6363 }
6364
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006365 plug_type = tabla_codec_get_plug_type(codec, false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006366 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006367
Joonwoo Park41956722012-04-18 13:13:07 -07006368 if (plug_type == PLUG_TYPE_INVALID) {
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006369 pr_debug("%s: Invalid plug type detected\n", __func__);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006370 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006371 tabla_codec_cleanup_hs_polling(codec);
6372 tabla_codec_enable_hs_detect(codec, 1,
6373 MBHC_USE_MB_TRIGGER |
6374 MBHC_USE_HPHL_TRIGGER, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006375 } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
6376 pr_debug("%s: GND-MIC swapped plug type detected\n", __func__);
6377 tabla_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
6378 tabla_codec_cleanup_hs_polling(codec);
6379 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park41956722012-04-18 13:13:07 -07006380 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
Joonwoo Park03324832012-03-19 19:36:16 -07006381 pr_debug("%s: Headphone Detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006382 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
6383 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07006384 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park41956722012-04-18 13:13:07 -07006385 } else if (plug_type == PLUG_TYPE_HEADSET) {
Joonwoo Park03324832012-03-19 19:36:16 -07006386 pr_debug("%s: Headset detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006387 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
6388
Joonwoo Park03324832012-03-19 19:36:16 -07006389 /* avoid false button press detect */
6390 msleep(50);
Joonwoo Park03324832012-03-19 19:36:16 -07006391 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07006392 }
6393}
6394
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006395/* called only from interrupt which is under codec_resource_lock acquisition */
6396static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
Bradley Rubincb1e2732011-06-23 16:49:20 -07006397{
Bradley Rubincb1e2732011-06-23 16:49:20 -07006398 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006399
6400 if (!is_removal) {
6401 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
6402
6403 rmb();
6404 if (priv->lpi_enabled)
6405 msleep(100);
6406
6407 rmb();
6408 if (!priv->lpi_enabled) {
6409 pr_debug("%s: lpi is disabled\n", __func__);
6410 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
6411 priv->mbhc_cfg.gpio_level_insert) {
6412 pr_debug("%s: Valid insertion, "
6413 "detect plug type\n", __func__);
6414 tabla_codec_decide_gpio_plug(codec);
6415 } else {
6416 pr_debug("%s: Invalid insertion, "
6417 "stop plug detection\n", __func__);
6418 }
6419 } else {
6420 pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
6421 }
6422}
6423
6424/* called only from interrupt which is under codec_resource_lock acquisition */
6425static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
6426 bool is_mb_trigger)
6427{
Joonwoo Park03324832012-03-19 19:36:16 -07006428 int ret;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006429 struct snd_soc_codec *codec = priv->codec;
6430 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006431
6432 if (is_removal) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006433 /* cancel possiblely running hs detect work */
6434 tabla_cancel_hs_detect_plug(priv);
6435
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006436 /*
6437 * If headphone is removed while playback is in progress,
6438 * it is possible that micbias will be switched to VDDIO.
6439 */
Joonwoo Park03324832012-03-19 19:36:16 -07006440 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006441 if (priv->current_plug == PLUG_TYPE_HEADPHONE)
6442 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
6443 else if (priv->current_plug == PLUG_TYPE_GND_MIC_SWAP)
6444 tabla_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
6445 else
6446 WARN(1, "%s: Unexpected current plug type %d\n",
6447 __func__, priv->current_plug);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006448 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006449 tabla_codec_enable_hs_detect(codec, 1,
6450 MBHC_USE_MB_TRIGGER |
6451 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07006452 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006453 } else if (is_mb_trigger && !is_removal) {
Joonwoo Park03324832012-03-19 19:36:16 -07006454 pr_debug("%s: Waiting for Headphone left trigger\n",
6455 __func__);
6456 wcd9xxx_lock_sleep(core);
6457 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
6458 usecs_to_jiffies(1000000)) == 0) {
6459 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
6460 __func__);
6461 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08006462 }
Joonwoo Park03324832012-03-19 19:36:16 -07006463 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
6464 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006465 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006466 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
6467 if (ret != 0) {
6468 pr_debug("%s: Complete plug insertion, Detecting plug "
6469 "type\n", __func__);
6470 tabla_codec_detect_plug_type(codec);
6471 wcd9xxx_unlock_sleep(core);
6472 } else {
6473 wcd9xxx_enable_irq(codec->control_data,
6474 TABLA_IRQ_MBHC_INSERTION);
6475 pr_err("%s: Error detecting plug insertion\n",
6476 __func__);
6477 }
Joonwoo Park03324832012-03-19 19:36:16 -07006478 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006479}
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08006480
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006481static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
6482{
6483 bool is_mb_trigger, is_removal;
6484 struct tabla_priv *priv = data;
6485 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07006486
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006487 pr_debug("%s: enter\n", __func__);
6488 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
6489 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
6490
6491 is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
6492 0x10);
6493 is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
6494 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
6495
6496 /* Turn off both HPH and MIC line schmitt triggers */
6497 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6498 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
6499 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6500
6501 if (priv->mbhc_cfg.gpio)
6502 tabla_hs_insert_irq_gpio(priv, is_removal);
6503 else
6504 tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
6505
6506 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006507 return IRQ_HANDLED;
6508}
6509
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006510static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
6511{
6512 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006513 const struct tabla_mbhc_plug_type_cfg *plug_type =
6514 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
6515 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006516
6517 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006518 && (mic_mv < v_hs_max)) ? true : false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006519}
6520
6521/* called under codec_resource_lock acquisition
6522 * returns true if mic voltage range is back to normal insertion
6523 * returns false either if timedout or removed */
6524static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
6525{
6526 int i;
6527 bool timedout, settled = false;
6528 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
6529 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
6530 unsigned long retry = 0, timeout;
6531 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006532 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006533
6534 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
6535 while (!(timedout = time_after(jiffies, timeout))) {
6536 retry++;
6537 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6538 pr_debug("%s: GPIO indicates removal\n", __func__);
6539 break;
6540 }
6541
6542 if (tabla->mbhc_cfg.gpio) {
6543 if (retry > 1)
6544 msleep(250);
6545 else
6546 msleep(50);
6547 }
6548
6549 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6550 pr_debug("%s: GPIO indicates removal\n", __func__);
6551 break;
6552 }
6553
6554 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
6555 mb_v[i] = tabla_codec_sta_dce(codec, 1, true);
6556 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
6557 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
6558 __func__, retry, mic_mv[i], mb_v[i]);
6559 }
6560
6561 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6562 pr_debug("%s: GPIO indicates removal\n", __func__);
6563 break;
6564 }
6565
6566 if (tabla->current_plug == PLUG_TYPE_NONE) {
6567 pr_debug("%s : headset/headphone is removed\n",
6568 __func__);
6569 break;
6570 }
6571
6572 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
6573 if (!is_valid_mic_voltage(codec, mic_mv[i]))
6574 break;
6575
6576 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6577 pr_debug("%s: MIC voltage settled\n", __func__);
6578 settled = true;
6579 msleep(200);
6580 break;
6581 }
6582
6583 /* only for non-GPIO remove irq */
6584 if (!tabla->mbhc_cfg.gpio) {
6585 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006586 if (mic_mv[i] < v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006587 break;
6588 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6589 pr_debug("%s: Headset is removed\n", __func__);
6590 break;
6591 }
6592 }
6593 }
6594
6595 if (timedout)
6596 pr_debug("%s: Microphone did not settle in %d seconds\n",
6597 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
6598 return settled;
6599}
6600
6601/* called only from interrupt which is under codec_resource_lock acquisition */
6602static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
6603{
6604 struct snd_soc_codec *codec = priv->codec;
6605
6606 if (tabla_hs_remove_settle(codec))
6607 tabla_codec_start_hs_polling(codec);
6608 pr_debug("%s: remove settle done\n", __func__);
6609}
6610
6611/* called only from interrupt which is under codec_resource_lock acquisition */
6612static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006613{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006614 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006615 bool removed = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006616 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08006617 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006618 TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006619 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006620
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006621 if (priv->current_plug != PLUG_TYPE_HEADSET) {
6622 pr_debug("%s(): Headset is not inserted, ignore removal\n",
6623 __func__);
6624 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6625 0x08, 0x08);
6626 return;
6627 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006628
Joonwoo Park0976d012011-12-22 11:48:18 -08006629 usleep_range(generic->t_shutdown_plug_rem,
6630 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006631
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006632 do {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006633 bias_value = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006634 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
6635 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006636 if (bias_value < tabla_get_current_v_ins(priv, false)) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006637 pr_debug("%s: checking false removal\n", __func__);
6638 msleep(500);
6639 removed = !tabla_hs_remove_settle(codec);
6640 pr_debug("%s: headset %sactually removed\n", __func__,
6641 removed ? "" : "not ");
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006642 break;
6643 }
6644 min_us -= priv->mbhc_data.t_dce;
6645 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07006646
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006647 if (removed) {
6648 /* cancel possiblely running hs detect work */
6649 tabla_cancel_hs_detect_plug(priv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006650 /*
6651 * If this removal is not false, first check the micbias
6652 * switch status and switch it to LDOH if it is already
6653 * switched to VDDIO.
6654 */
Joonwoo Park03324832012-03-19 19:36:16 -07006655 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07006656
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006657 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6658 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006659 tabla_codec_enable_hs_detect(codec, 1,
6660 MBHC_USE_MB_TRIGGER |
6661 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07006662 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006663 } else {
6664 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006665 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006666}
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006667
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006668static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
6669{
6670 struct tabla_priv *priv = data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006671 bool vddio;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006672 pr_debug("%s: enter, removal interrupt\n", __func__);
6673
6674 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006675 vddio = (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
6676 priv->mbhc_micbias_switched);
6677 if (vddio)
6678 __tabla_codec_switch_micbias(priv->codec, 0, false, true);
6679
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006680 if (priv->mbhc_cfg.gpio)
6681 tabla_hs_remove_irq_gpio(priv);
6682 else
6683 tabla_hs_remove_irq_nogpio(priv);
6684
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006685 /* if driver turned off vddio switch and headset is not removed,
6686 * turn on the vddio switch back, if headset is removed then vddio
6687 * switch is off by time now and shouldn't be turn on again from here */
6688 if (vddio && priv->current_plug == PLUG_TYPE_HEADSET)
6689 __tabla_codec_switch_micbias(priv->codec, 1, true, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006690 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006691
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006692 return IRQ_HANDLED;
6693}
6694
Joonwoo Park03324832012-03-19 19:36:16 -07006695void mbhc_insert_work(struct work_struct *work)
6696{
6697 struct delayed_work *dwork;
6698 struct tabla_priv *tabla;
6699 struct snd_soc_codec *codec;
6700 struct wcd9xxx *tabla_core;
6701
6702 dwork = to_delayed_work(work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006703 tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
Joonwoo Park03324832012-03-19 19:36:16 -07006704 codec = tabla->codec;
6705 tabla_core = dev_get_drvdata(codec->dev->parent);
6706
6707 pr_debug("%s:\n", __func__);
6708
6709 /* Turn off both HPH and MIC line schmitt triggers */
6710 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6711 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
6712 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6713 wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
6714 tabla_codec_detect_plug_type(codec);
6715 wcd9xxx_unlock_sleep(tabla_core);
6716}
6717
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006718static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
6719{
6720 bool insert;
6721 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6722 bool is_removed = false;
6723
6724 pr_debug("%s: enter\n", __func__);
6725
6726 tabla->in_gpio_handler = true;
6727 /* Wait here for debounce time */
6728 usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
6729 TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
6730
6731 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
6732
6733 /* cancel pending button press */
6734 if (tabla_cancel_btn_work(tabla))
6735 pr_debug("%s: button press is canceled\n", __func__);
6736
6737 insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
6738 tabla->mbhc_cfg.gpio_level_insert);
6739 if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
6740 tabla->lpi_enabled = false;
6741 wmb();
6742
6743 /* cancel detect plug */
6744 tabla_cancel_hs_detect_plug(tabla);
6745
6746 /* Disable Mic Bias pull down and HPH Switch to GND */
6747 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
6748 0x00);
6749 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
6750 tabla_codec_detect_plug_type(codec);
6751 } else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
6752 tabla->lpi_enabled = false;
6753 wmb();
6754
6755 /* cancel detect plug */
6756 tabla_cancel_hs_detect_plug(tabla);
6757
6758 if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
6759 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
6760 is_removed = true;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006761 } else if (tabla->current_plug == PLUG_TYPE_GND_MIC_SWAP) {
6762 tabla_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
6763 is_removed = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006764 } else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
6765 tabla_codec_pause_hs_polling(codec);
6766 tabla_codec_cleanup_hs_polling(codec);
6767 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6768 is_removed = true;
6769 }
6770
6771 if (is_removed) {
6772 /* Enable Mic Bias pull down and HPH Switch to GND */
6773 snd_soc_update_bits(codec,
6774 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6775 0x01);
6776 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6777 0x01);
6778 /* Make sure mic trigger is turned off */
6779 snd_soc_update_bits(codec,
6780 tabla->mbhc_bias_regs.ctl_reg,
6781 0x01, 0x01);
6782 snd_soc_update_bits(codec,
6783 tabla->mbhc_bias_regs.mbhc_reg,
6784 0x90, 0x00);
6785 /* Reset MBHC State Machine */
6786 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6787 0x08, 0x08);
6788 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6789 0x08, 0x00);
6790 /* Turn off override */
6791 tabla_turn_onoff_override(codec, false);
6792 }
6793 }
6794
6795 tabla->in_gpio_handler = false;
6796 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6797 pr_debug("%s: leave\n", __func__);
6798}
6799
6800static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
6801{
6802 int r = IRQ_HANDLED;
6803 struct snd_soc_codec *codec = data;
6804
6805 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
6806 pr_warn("%s: failed to hold suspend\n", __func__);
6807 r = IRQ_NONE;
6808 } else {
6809 tabla_hs_gpio_handler(codec);
6810 wcd9xxx_unlock_sleep(codec->control_data);
6811 }
6812
6813 return r;
6814}
6815
Joonwoo Park1305bab2012-05-21 15:08:42 -07006816static int tabla_mbhc_init_and_calibrate(struct tabla_priv *tabla)
6817{
6818 int ret = 0;
6819 struct snd_soc_codec *codec = tabla->codec;
6820
6821 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
6822 tabla_mbhc_init(codec);
6823 tabla_mbhc_cal(codec);
6824 tabla_mbhc_calc_thres(codec);
6825 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
6826 tabla_codec_calibrate_hs_polling(codec);
6827 if (!tabla->mbhc_cfg.gpio) {
6828 ret = tabla_codec_enable_hs_detect(codec, 1,
6829 MBHC_USE_MB_TRIGGER |
6830 MBHC_USE_HPHL_TRIGGER,
6831 false);
6832
6833 if (IS_ERR_VALUE(ret))
6834 pr_err("%s: Failed to setup MBHC detection\n",
6835 __func__);
6836 } else {
6837 /* Enable Mic Bias pull down and HPH Switch to GND */
6838 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
6839 0x01, 0x01);
6840 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x01);
6841 INIT_WORK(&tabla->hs_correct_plug_work,
6842 tabla_hs_correct_gpio_plug);
6843 }
6844
6845 if (!IS_ERR_VALUE(ret)) {
6846 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
6847 wcd9xxx_enable_irq(codec->control_data,
6848 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6849 wcd9xxx_enable_irq(codec->control_data,
6850 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6851
6852 if (tabla->mbhc_cfg.gpio) {
6853 ret = request_threaded_irq(tabla->mbhc_cfg.gpio_irq,
6854 NULL,
6855 tabla_mechanical_plug_detect_irq,
6856 (IRQF_TRIGGER_RISING |
6857 IRQF_TRIGGER_FALLING),
6858 "tabla-gpio", codec);
6859 if (!IS_ERR_VALUE(ret)) {
6860 ret = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
6861 /* Bootup time detection */
6862 tabla_hs_gpio_handler(codec);
6863 }
6864 }
6865 }
6866
6867 return ret;
6868}
6869
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006870static void mbhc_fw_read(struct work_struct *work)
6871{
6872 struct delayed_work *dwork;
6873 struct tabla_priv *tabla;
6874 struct snd_soc_codec *codec;
6875 const struct firmware *fw;
Joonwoo Park1305bab2012-05-21 15:08:42 -07006876 int ret = -1, retry = 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006877
6878 dwork = to_delayed_work(work);
Joonwoo Park1305bab2012-05-21 15:08:42 -07006879 tabla = container_of(dwork, struct tabla_priv, mbhc_firmware_dwork);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006880 codec = tabla->codec;
6881
6882 while (retry < MBHC_FW_READ_ATTEMPTS) {
6883 retry++;
6884 pr_info("%s:Attempt %d to request MBHC firmware\n",
6885 __func__, retry);
6886 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
6887 codec->dev);
6888
6889 if (ret != 0) {
6890 usleep_range(MBHC_FW_READ_TIMEOUT,
Joonwoo Park1305bab2012-05-21 15:08:42 -07006891 MBHC_FW_READ_TIMEOUT);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006892 } else {
6893 pr_info("%s: MBHC Firmware read succesful\n", __func__);
6894 break;
6895 }
6896 }
6897
6898 if (ret != 0) {
6899 pr_err("%s: Cannot load MBHC firmware use default cal\n",
6900 __func__);
6901 } else if (tabla_mbhc_fw_validate(fw) == false) {
6902 pr_err("%s: Invalid MBHC cal data size use default cal\n",
6903 __func__);
6904 release_firmware(fw);
6905 } else {
6906 tabla->mbhc_cfg.calibration = (void *)fw->data;
6907 tabla->mbhc_fw = fw;
6908 }
6909
Joonwoo Park1305bab2012-05-21 15:08:42 -07006910 (void) tabla_mbhc_init_and_calibrate(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006911}
6912
Joonwoo Park03324832012-03-19 19:36:16 -07006913int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006914 const struct tabla_mbhc_config *cfg)
Joonwoo Park03324832012-03-19 19:36:16 -07006915{
6916 struct tabla_priv *tabla;
6917 int rc = 0;
6918
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006919 if (!codec || !cfg->calibration) {
Joonwoo Park03324832012-03-19 19:36:16 -07006920 pr_err("Error: no codec or calibration\n");
6921 return -EINVAL;
6922 }
6923
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006924 if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
6925 if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Joonwoo Park03324832012-03-19 19:36:16 -07006926 pr_err("Error: clock rate %dHz is not yet supported\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006927 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006928 else
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006929 pr_err("Error: unsupported clock rate %d\n",
6930 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006931 return -EINVAL;
6932 }
6933
6934 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006935 tabla->mbhc_cfg = *cfg;
6936 tabla->in_gpio_handler = false;
6937 tabla->current_plug = PLUG_TYPE_NONE;
6938 tabla->lpi_enabled = false;
Joonwoo Park03324832012-03-19 19:36:16 -07006939 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
6940
6941 /* Put CFILT in fast mode by default */
6942 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
6943 0x40, TABLA_CFILT_FAST_MODE);
6944 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
6945 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
6946 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
6947 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
6948 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
6949
Joonwoo Park1305bab2012-05-21 15:08:42 -07006950 if (!tabla->mbhc_cfg.read_fw_bin)
6951 rc = tabla_mbhc_init_and_calibrate(tabla);
6952 else
Joonwoo Park03324832012-03-19 19:36:16 -07006953 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
6954 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006955
Joonwoo Park03324832012-03-19 19:36:16 -07006956 return rc;
6957}
6958EXPORT_SYMBOL_GPL(tabla_hs_detect);
6959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006960static unsigned long slimbus_value;
6961
6962static irqreturn_t tabla_slimbus_irq(int irq, void *data)
6963{
6964 struct tabla_priv *priv = data;
6965 struct snd_soc_codec *codec = priv->codec;
6966 int i, j;
6967 u8 val;
6968
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306969 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
6970 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006971 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
6972 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306973 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006974 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
6975 if (val & 0x1)
6976 pr_err_ratelimited("overflow error on port %x,"
6977 " value %x\n", i*8 + j, val);
6978 if (val & 0x2)
6979 pr_err_ratelimited("underflow error on port %x,"
6980 " value %x\n", i*8 + j, val);
6981 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306982 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006983 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
6984 }
6985
6986 return IRQ_HANDLED;
6987}
6988
Patrick Lai3043fba2011-08-01 14:15:57 -07006989static int tabla_handle_pdata(struct tabla_priv *tabla)
6990{
6991 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306992 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07006993 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05306994 u8 leg_mode = pdata->amic_settings.legacy_mode;
6995 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
6996 u8 txfe_buff = pdata->amic_settings.txfe_buff;
6997 u8 flag = pdata->amic_settings.use_pdata;
6998 u8 i = 0, j = 0;
6999 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07007000
7001 if (!pdata) {
7002 rc = -ENODEV;
7003 goto done;
7004 }
7005
7006 /* Make sure settings are correct */
7007 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
7008 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
7009 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
7010 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
7011 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
7012 rc = -EINVAL;
7013 goto done;
7014 }
7015
7016 /* figure out k value */
7017 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
7018 pdata->micbias.cfilt1_mv);
7019 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
7020 pdata->micbias.cfilt2_mv);
7021 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
7022 pdata->micbias.cfilt3_mv);
7023
7024 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
7025 rc = -EINVAL;
7026 goto done;
7027 }
7028
7029 /* Set voltage level and always use LDO */
7030 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
7031 (pdata->micbias.ldoh_v << 2));
7032
7033 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
7034 (k1 << 2));
7035 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
7036 (k2 << 2));
7037 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
7038 (k3 << 2));
7039
7040 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
7041 (pdata->micbias.bias1_cfilt_sel << 5));
7042 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
7043 (pdata->micbias.bias2_cfilt_sel << 5));
7044 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
7045 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007046 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
7047 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07007048
Santosh Mardi22920282011-10-26 02:38:40 +05307049 for (i = 0; i < 6; j++, i += 2) {
7050 if (flag & (0x01 << i)) {
7051 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
7052 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
7053 val_txfe = val_txfe |
7054 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
7055 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
7056 0x10, value);
7057 snd_soc_update_bits(codec,
7058 TABLA_A_TX_1_2_TEST_EN + j * 10,
7059 0x30, val_txfe);
7060 }
7061 if (flag & (0x01 << (i + 1))) {
7062 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
7063 val_txfe = (txfe_bypass &
7064 (0x01 << (i + 1))) ? 0x02 : 0x00;
7065 val_txfe |= (txfe_buff &
7066 (0x01 << (i + 1))) ? 0x01 : 0x00;
7067 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
7068 0x01, value);
7069 snd_soc_update_bits(codec,
7070 TABLA_A_TX_1_2_TEST_EN + j * 10,
7071 0x03, val_txfe);
7072 }
7073 }
7074 if (flag & 0x40) {
7075 value = (leg_mode & 0x40) ? 0x10 : 0x00;
7076 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
7077 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
7078 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
7079 0x13, value);
7080 }
Patrick Lai49efeac2011-11-03 11:01:12 -07007081
7082 if (pdata->ocp.use_pdata) {
7083 /* not defined in CODEC specification */
7084 if (pdata->ocp.hph_ocp_limit == 1 ||
7085 pdata->ocp.hph_ocp_limit == 5) {
7086 rc = -EINVAL;
7087 goto done;
7088 }
7089 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
7090 0x0F, pdata->ocp.num_attempts);
7091 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
7092 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
7093 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
7094 0xE0, (pdata->ocp.hph_ocp_limit << 5));
7095 }
Joonwoo Park03324832012-03-19 19:36:16 -07007096
7097 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
7098 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
7099 if (pdata->regulator[i].min_uV == 1800000 &&
7100 pdata->regulator[i].max_uV == 1800000) {
7101 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
7102 0x1C);
7103 } else if (pdata->regulator[i].min_uV == 2200000 &&
7104 pdata->regulator[i].max_uV == 2200000) {
7105 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
7106 0x1E);
7107 } else {
7108 pr_err("%s: unsupported CDC_VDDA_RX voltage "
7109 "min %d, max %d\n", __func__,
7110 pdata->regulator[i].min_uV,
7111 pdata->regulator[i].max_uV);
7112 rc = -EINVAL;
7113 }
7114 break;
7115 }
7116 }
Patrick Lai3043fba2011-08-01 14:15:57 -07007117done:
7118 return rc;
7119}
7120
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007121static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
7122
7123 /* Tabla 1.1 MICBIAS changes */
7124 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
7125 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
7126 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007127
7128 /* Tabla 1.1 HPH changes */
7129 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
7130 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
7131
7132 /* Tabla 1.1 EAR PA changes */
7133 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
7134 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
7135 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
7136
7137 /* Tabla 1.1 Lineout_5 Changes */
7138 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
7139
7140 /* Tabla 1.1 RX Changes */
7141 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
7142 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
7143 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
7144 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
7145 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
7146 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
7147 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
7148
7149 /* Tabla 1.1 RX1 and RX2 Changes */
7150 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
7151 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
7152
7153 /* Tabla 1.1 RX3 to RX7 Changes */
7154 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
7155 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
7156 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
7157 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
7158 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
7159
7160 /* Tabla 1.1 CLASSG Changes */
7161 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
7162};
7163
7164static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007165 /* Tabla 2.0 MICBIAS changes */
7166 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
7167};
7168
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007169static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
7170 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
7171};
7172
7173static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
7174 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
7175};
7176
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007177static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
7178{
7179 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307180 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007181
7182 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
7183 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
7184 tabla_1_1_reg_defaults[i].val);
7185
7186 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
7187 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
7188 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007189
7190 if (TABLA_IS_1_X(tabla_core->version)) {
7191 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
7192 i++)
7193 snd_soc_write(codec,
7194 tabla_1_x_only_reg_2_0_defaults[i].reg,
7195 tabla_1_x_only_reg_2_0_defaults[i].val);
7196 } else {
7197 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
7198 snd_soc_write(codec,
7199 tabla_2_only_reg_2_0_defaults[i].reg,
7200 tabla_2_only_reg_2_0_defaults[i].val);
7201 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007202}
7203
7204static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08007205 /* Initialize current threshold to 350MA
7206 * number of wait and run cycles to 4096
7207 */
Patrick Lai49efeac2011-11-03 11:01:12 -07007208 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08007209 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007210
Santosh Mardi32171012011-10-28 23:32:06 +05307211 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
7212
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007213 /* Initialize gain registers to use register gain */
7214 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
7215 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
7216 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
7217 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
7218 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
7219 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
7220
7221 /* Initialize mic biases to differential mode */
7222 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
7223 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
7224 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007225
7226 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
7227
7228 /* Use 16 bit sample size for TX1 to TX6 */
7229 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
7230 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
7231 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
7232 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
7233 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
7234 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
7235
7236 /* Use 16 bit sample size for TX7 to TX10 */
7237 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
7238 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
7239 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
7240 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
7241
7242 /* Use 16 bit sample size for RX */
7243 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
7244 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
7245
7246 /*enable HPF filter for TX paths */
7247 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
7248 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
7249 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
7250 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
7251 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
7252 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
7253 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
7254 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
7255 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
7256 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
Kiran Kandi0ba468f2012-05-08 11:45:05 -07007257
7258 /* config Decimator for DMIC CLK_MODE_1(3.072Mhz@12.88Mhz mclk) */
7259 {TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0x1},
7260 {TABLA_A_CDC_TX2_DMIC_CTL, 0x1, 0x1},
7261 {TABLA_A_CDC_TX3_DMIC_CTL, 0x1, 0x1},
7262 {TABLA_A_CDC_TX4_DMIC_CTL, 0x1, 0x1},
7263 {TABLA_A_CDC_TX5_DMIC_CTL, 0x1, 0x1},
7264 {TABLA_A_CDC_TX6_DMIC_CTL, 0x1, 0x1},
7265 {TABLA_A_CDC_TX7_DMIC_CTL, 0x1, 0x1},
7266 {TABLA_A_CDC_TX8_DMIC_CTL, 0x1, 0x1},
7267 {TABLA_A_CDC_TX9_DMIC_CTL, 0x1, 0x1},
7268 {TABLA_A_CDC_TX10_DMIC_CTL, 0x1, 0x1},
7269
7270 /* config DMIC clk to CLK_MODE_1 (3.072Mhz@12.88Mhz mclk) */
7271 {TABLA_A_CDC_CLK_DMIC_CTL, 0x2A, 0x2A},
7272
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007273};
7274
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007275static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
7276 /* Initialize mic biases to differential mode */
7277 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
7278};
7279
7280static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
7281 /* Initialize mic biases to differential mode */
7282 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
7283};
7284
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007285static void tabla_codec_init_reg(struct snd_soc_codec *codec)
7286{
7287 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307288 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007289
7290 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
7291 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
7292 tabla_codec_reg_init_val[i].mask,
7293 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007294 if (TABLA_IS_1_X(tabla_core->version)) {
7295 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
7296 snd_soc_update_bits(codec,
7297 tabla_1_x_codec_reg_init_val[i].reg,
7298 tabla_1_x_codec_reg_init_val[i].mask,
7299 tabla_1_x_codec_reg_init_val[i].val);
7300 } else {
7301 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
7302 i++)
7303 snd_soc_update_bits(codec,
7304 tabla_2_higher_codec_reg_init_val[i].reg,
7305 tabla_2_higher_codec_reg_init_val[i].mask,
7306 tabla_2_higher_codec_reg_init_val[i].val);
7307 }
7308}
7309
7310static void tabla_update_reg_address(struct tabla_priv *priv)
7311{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307312 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007313 struct tabla_reg_address *reg_addr = &priv->reg_addr;
7314
7315 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08007316 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
7317 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007318 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007319 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08007320 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
7321 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007322 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007323 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007324}
7325
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007326#ifdef CONFIG_DEBUG_FS
7327static int codec_debug_open(struct inode *inode, struct file *file)
7328{
7329 file->private_data = inode->i_private;
7330 return 0;
7331}
7332
7333static ssize_t codec_debug_write(struct file *filp,
7334 const char __user *ubuf, size_t cnt, loff_t *ppos)
7335{
7336 char lbuf[32];
7337 char *buf;
7338 int rc;
7339 struct tabla_priv *tabla = filp->private_data;
7340
7341 if (cnt > sizeof(lbuf) - 1)
7342 return -EINVAL;
7343
7344 rc = copy_from_user(lbuf, ubuf, cnt);
7345 if (rc)
7346 return -EFAULT;
7347
7348 lbuf[cnt] = '\0';
7349 buf = (char *)lbuf;
7350 tabla->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
7351 false : true;
7352 return rc;
7353}
7354
7355static ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
7356 size_t count, loff_t *pos)
7357{
7358 const int size = 768;
7359 char buffer[size];
7360 int n = 0;
7361 struct tabla_priv *tabla = file->private_data;
7362 struct snd_soc_codec *codec = tabla->codec;
7363 const struct mbhc_internal_cal_data *p = &tabla->mbhc_data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007364 const s16 v_ins_hu_cur = tabla_get_current_v_ins(tabla, true);
7365 const s16 v_ins_h_cur = tabla_get_current_v_ins(tabla, false);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007366
7367 n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
7368 tabla_codec_sta_dce_v(codec, 1, p->dce_z));
7369 n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
7370 p->dce_mb, tabla_codec_sta_dce_v(codec, 1, p->dce_mb));
7371 n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
7372 p->sta_z, tabla_codec_sta_dce_v(codec, 0, p->sta_z));
7373 n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
7374 p->sta_mb, tabla_codec_sta_dce_v(codec, 0, p->sta_mb));
7375 n += scnprintf(buffer + n, size - n, "t_dce = %x\n", p->t_dce);
7376 n += scnprintf(buffer + n, size - n, "t_sta = %x\n", p->t_sta);
7377 n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
7378 p->micb_mv);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007379 n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007380 p->v_ins_hu,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007381 tabla_codec_sta_dce_v(codec, 0, p->v_ins_hu),
7382 p->v_ins_hu == v_ins_hu_cur ? "*" : "");
7383 n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
7384 p->v_ins_h, tabla_codec_sta_dce_v(codec, 1, p->v_ins_h),
7385 p->v_ins_h == v_ins_h_cur ? "*" : "");
7386 n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
7387 p->adj_v_ins_hu,
7388 tabla_codec_sta_dce_v(codec, 0, p->adj_v_ins_hu),
7389 p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
7390 n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
7391 p->adj_v_ins_h,
7392 tabla_codec_sta_dce_v(codec, 1, p->adj_v_ins_h),
7393 p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007394 n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
7395 p->v_b1_hu, tabla_codec_sta_dce_v(codec, 0, p->v_b1_hu));
7396 n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
7397 p->v_b1_h, tabla_codec_sta_dce_v(codec, 1, p->v_b1_h));
7398 n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
7399 p->v_b1_huc,
7400 tabla_codec_sta_dce_v(codec, 1, p->v_b1_huc));
7401 n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
7402 p->v_brh, tabla_codec_sta_dce_v(codec, 1, p->v_brh));
7403 n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
7404 tabla_codec_sta_dce_v(codec, 0, p->v_brl));
7405 n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
7406 p->v_no_mic,
7407 tabla_codec_sta_dce_v(codec, 0, p->v_no_mic));
7408 n += scnprintf(buffer + n, size - n, "npoll = %d\n", p->npoll);
7409 n += scnprintf(buffer + n, size - n, "nbounce_wait = %d\n",
7410 p->nbounce_wait);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007411 n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
7412 p->v_inval_ins_low);
7413 n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
7414 p->v_inval_ins_high);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007415 if (tabla->mbhc_cfg.gpio)
7416 n += scnprintf(buffer + n, size - n, "GPIO insert = %d\n",
7417 tabla_hs_gpio_level_remove(tabla));
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007418 buffer[n] = 0;
7419
7420 return simple_read_from_buffer(buf, count, pos, buffer, n);
7421}
7422
7423static const struct file_operations codec_debug_ops = {
7424 .open = codec_debug_open,
7425 .write = codec_debug_write,
7426};
7427
7428static const struct file_operations codec_mbhc_debug_ops = {
7429 .open = codec_debug_open,
7430 .read = codec_mbhc_debug_read,
7431};
7432#endif
7433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007434static int tabla_codec_probe(struct snd_soc_codec *codec)
7435{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307436 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007437 struct tabla_priv *tabla;
7438 struct snd_soc_dapm_context *dapm = &codec->dapm;
7439 int ret = 0;
7440 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007441 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007442
7443 codec->control_data = dev_get_drvdata(codec->dev->parent);
7444 control = codec->control_data;
7445
7446 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
7447 if (!tabla) {
7448 dev_err(codec->dev, "Failed to allocate private data\n");
7449 return -ENOMEM;
7450 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08007451 for (i = 0 ; i < NUM_DECIMATORS; i++) {
7452 tx_hpf_work[i].tabla = tabla;
7453 tx_hpf_work[i].decimator = i + 1;
7454 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
7455 tx_hpf_corner_freq_callback);
7456 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007457
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07007458 /* Make sure mbhc micbias register addresses are zeroed out */
7459 memset(&tabla->mbhc_bias_regs, 0,
7460 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07007461 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07007462
Joonwoo Park0976d012011-12-22 11:48:18 -08007463 /* Make sure mbhc intenal calibration data is zeroed out */
7464 memset(&tabla->mbhc_data, 0,
7465 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08007466 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08007467 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
7468 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007469 snd_soc_codec_set_drvdata(codec, tabla);
7470
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07007471 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007472 tabla->bandgap_type = TABLA_BANDGAP_OFF;
7473 tabla->clock_active = false;
7474 tabla->config_mode_active = false;
7475 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08007476 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07007477 tabla->no_mic_headset_override = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007478 tabla->hs_polling_irq_prepared = false;
7479 mutex_init(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007480 tabla->codec = codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007481 tabla->mbhc_state = MBHC_STATE_NONE;
Joonwoo Park03324832012-03-19 19:36:16 -07007482 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08007483 for (i = 0; i < COMPANDER_MAX; i++) {
7484 tabla->comp_enabled[i] = 0;
7485 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
7486 }
Patrick Lai3043fba2011-08-01 14:15:57 -07007487 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307488 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08007489 tabla->aux_pga_cnt = 0;
7490 tabla->aux_l_gain = 0x1F;
7491 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007492 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05307493 tabla_update_reg_defaults(codec);
7494 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05307495 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07007496 if (IS_ERR_VALUE(ret)) {
7497 pr_err("%s: bad pdata\n", __func__);
7498 goto err_pdata;
7499 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007500
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007501 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007502 ARRAY_SIZE(tabla_snd_controls));
7503 if (TABLA_IS_1_X(control->version))
7504 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
7505 ARRAY_SIZE(tabla_1_x_snd_controls));
7506 else
7507 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
7508 ARRAY_SIZE(tabla_2_higher_snd_controls));
7509
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007510 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007511 ARRAY_SIZE(tabla_dapm_widgets));
7512 if (TABLA_IS_1_X(control->version))
7513 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
7514 ARRAY_SIZE(tabla_1_x_dapm_widgets));
7515 else
7516 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
7517 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
7518
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307519 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05307520 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
7521 ARRAY_SIZE(tabla_dapm_i2s_widgets));
7522 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
7523 ARRAY_SIZE(audio_i2s_map));
7524 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007525 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07007526
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007527 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007528 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007529 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
7530 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007531 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007532 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007533 } else {
7534 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307535 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007536 goto err_pdata;
7537 }
7538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007539 snd_soc_dapm_sync(dapm);
7540
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307541 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007542 tabla_hs_insert_irq, "Headset insert detect", tabla);
7543 if (ret) {
7544 pr_err("%s: Failed to request irq %d\n", __func__,
7545 TABLA_IRQ_MBHC_INSERTION);
7546 goto err_insert_irq;
7547 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307548 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007549
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307550 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007551 tabla_hs_remove_irq, "Headset remove detect", tabla);
7552 if (ret) {
7553 pr_err("%s: Failed to request irq %d\n", __func__,
7554 TABLA_IRQ_MBHC_REMOVAL);
7555 goto err_remove_irq;
7556 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007557
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307558 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007559 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007560 if (ret) {
7561 pr_err("%s: Failed to request irq %d\n", __func__,
7562 TABLA_IRQ_MBHC_POTENTIAL);
7563 goto err_potential_irq;
7564 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007565
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307566 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007567 tabla_release_handler, "Button Release detect", tabla);
7568 if (ret) {
7569 pr_err("%s: Failed to request irq %d\n", __func__,
7570 TABLA_IRQ_MBHC_RELEASE);
7571 goto err_release_irq;
7572 }
7573
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307574 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007575 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
7576 if (ret) {
7577 pr_err("%s: Failed to request irq %d\n", __func__,
7578 TABLA_IRQ_SLIMBUS);
7579 goto err_slimbus_irq;
7580 }
7581
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307582 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
7583 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007584 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
7585
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307586 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007587 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
7588 "HPH_L OCP detect", tabla);
7589 if (ret) {
7590 pr_err("%s: Failed to request irq %d\n", __func__,
7591 TABLA_IRQ_HPH_PA_OCPL_FAULT);
7592 goto err_hphl_ocp_irq;
7593 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307594 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07007595
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307596 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007597 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
7598 "HPH_R OCP detect", tabla);
7599 if (ret) {
7600 pr_err("%s: Failed to request irq %d\n", __func__,
7601 TABLA_IRQ_HPH_PA_OCPR_FAULT);
7602 goto err_hphr_ocp_irq;
7603 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307604 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007605 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
7606 switch (tabla_dai[i].id) {
7607 case AIF1_PB:
7608 ch_cnt = tabla_dai[i].playback.channels_max;
7609 break;
7610 case AIF1_CAP:
7611 ch_cnt = tabla_dai[i].capture.channels_max;
7612 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08007613 case AIF2_PB:
7614 ch_cnt = tabla_dai[i].playback.channels_max;
7615 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07007616 case AIF2_CAP:
7617 ch_cnt = tabla_dai[i].capture.channels_max;
7618 break;
Kiran Kandia9fffe92012-05-20 23:42:30 -07007619 case AIF3_PB:
7620 ch_cnt = tabla_dai[i].playback.channels_max;
7621 break;
Neema Shetty3fb1b802012-04-27 13:53:24 -07007622 case AIF3_CAP:
7623 ch_cnt = tabla_dai[i].capture.channels_max;
7624 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007625 default:
7626 continue;
7627 }
7628 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
7629 ch_cnt), GFP_KERNEL);
7630 }
Patrick Lai49efeac2011-11-03 11:01:12 -07007631
Bradley Rubincb3950a2011-08-18 13:07:26 -07007632#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007633 if (ret == 0) {
7634 tabla->debugfs_poke =
7635 debugfs_create_file("TRRS", S_IFREG | S_IRUGO, NULL, tabla,
7636 &codec_debug_ops);
7637 tabla->debugfs_mbhc =
7638 debugfs_create_file("tabla_mbhc", S_IFREG | S_IRUGO,
7639 NULL, tabla, &codec_mbhc_debug_ops);
7640 }
Bradley Rubincb3950a2011-08-18 13:07:26 -07007641#endif
7642
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007643 return ret;
7644
Patrick Lai49efeac2011-11-03 11:01:12 -07007645err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307646 wcd9xxx_free_irq(codec->control_data,
7647 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07007648err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307649 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007650err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307651 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07007652err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307653 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007654err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307655 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007656err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307657 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007658err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07007659err_pdata:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007660 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007661 kfree(tabla);
7662 return ret;
7663}
7664static int tabla_codec_remove(struct snd_soc_codec *codec)
7665{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007666 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007667 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307668 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
7669 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
7670 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
7671 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
7672 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007673 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007674 tabla_codec_disable_clock_block(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007675 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007676 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08007677 if (tabla->mbhc_fw)
7678 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007679 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
7680 kfree(tabla->dai[i].ch_num);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007681 mutex_destroy(&tabla->codec_resource_lock);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007682#ifdef CONFIG_DEBUG_FS
7683 debugfs_remove(tabla->debugfs_poke);
7684 debugfs_remove(tabla->debugfs_mbhc);
7685#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007686 kfree(tabla);
7687 return 0;
7688}
7689static struct snd_soc_codec_driver soc_codec_dev_tabla = {
7690 .probe = tabla_codec_probe,
7691 .remove = tabla_codec_remove,
7692 .read = tabla_read,
7693 .write = tabla_write,
7694
7695 .readable_register = tabla_readable,
7696 .volatile_register = tabla_volatile,
7697
7698 .reg_cache_size = TABLA_CACHE_SIZE,
7699 .reg_cache_default = tabla_reg_defaults,
7700 .reg_word_size = 1,
7701};
Bradley Rubincb3950a2011-08-18 13:07:26 -07007702
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007703#ifdef CONFIG_PM
7704static int tabla_suspend(struct device *dev)
7705{
Joonwoo Park816b8e62012-01-23 16:03:21 -08007706 dev_dbg(dev, "%s: system suspend\n", __func__);
7707 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007708}
7709
7710static int tabla_resume(struct device *dev)
7711{
Joonwoo Park03324832012-03-19 19:36:16 -07007712 struct platform_device *pdev = to_platform_device(dev);
7713 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Park816b8e62012-01-23 16:03:21 -08007714 dev_dbg(dev, "%s: system resume\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07007715 tabla->mbhc_last_resume = jiffies;
Joonwoo Park816b8e62012-01-23 16:03:21 -08007716 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007717}
7718
7719static const struct dev_pm_ops tabla_pm_ops = {
7720 .suspend = tabla_suspend,
7721 .resume = tabla_resume,
7722};
7723#endif
7724
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007725static int __devinit tabla_probe(struct platform_device *pdev)
7726{
Santosh Mardie15e2302011-11-15 10:39:23 +05307727 int ret = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307728 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05307729 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7730 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307731 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05307732 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7733 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
7734 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007735}
7736static int __devexit tabla_remove(struct platform_device *pdev)
7737{
7738 snd_soc_unregister_codec(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007739 return 0;
7740}
7741static struct platform_driver tabla_codec_driver = {
7742 .probe = tabla_probe,
7743 .remove = tabla_remove,
7744 .driver = {
7745 .name = "tabla_codec",
7746 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007747#ifdef CONFIG_PM
7748 .pm = &tabla_pm_ops,
7749#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007750 },
7751};
7752
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007753static struct platform_driver tabla1x_codec_driver = {
7754 .probe = tabla_probe,
7755 .remove = tabla_remove,
7756 .driver = {
7757 .name = "tabla1x_codec",
7758 .owner = THIS_MODULE,
7759#ifdef CONFIG_PM
7760 .pm = &tabla_pm_ops,
7761#endif
7762 },
7763};
7764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007765static int __init tabla_codec_init(void)
7766{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007767 int rtn = platform_driver_register(&tabla_codec_driver);
7768 if (rtn == 0) {
7769 rtn = platform_driver_register(&tabla1x_codec_driver);
7770 if (rtn != 0)
7771 platform_driver_unregister(&tabla_codec_driver);
7772 }
7773 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007774}
7775
7776static void __exit tabla_codec_exit(void)
7777{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007778 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007779 platform_driver_unregister(&tabla_codec_driver);
7780}
7781
7782module_init(tabla_codec_init);
7783module_exit(tabla_codec_exit);
7784
7785MODULE_DESCRIPTION("Tabla codec driver");
7786MODULE_VERSION("1.0");
7787MODULE_LICENSE("GPL v2");