blob: aa4e51474bc1a75c4f3d0e2182a958de3a5b0a10 [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 Kandi1e6371d2012-03-29 11:48:57 -070071
Neema Shetty3fb1b802012-04-27 13:53:24 -070072#define NUM_CODEC_DAIS 5
Kuirong Wang0f8ade32012-02-27 16:29:45 -080073#define TABLA_COMP_DIGITAL_GAIN_OFFSET 3
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080074
75struct tabla_codec_dai_data {
76 u32 rate;
77 u32 *ch_num;
78 u32 ch_act;
79 u32 ch_tot;
80};
81
Joonwoo Park0976d012011-12-22 11:48:18 -080082#define TABLA_MCLK_RATE_12288KHZ 12288000
83#define TABLA_MCLK_RATE_9600KHZ 9600000
84
Joonwoo Parkf4267c22012-01-10 13:25:24 -080085#define TABLA_FAKE_INS_THRESHOLD_MS 2500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -080086#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
Joonwoo Parkf4267c22012-01-10 13:25:24 -080087
Joonwoo Park03324832012-03-19 19:36:16 -070088#define TABLA_MBHC_BUTTON_MIN 0x8000
89
Joonwoo Park03324832012-03-19 19:36:16 -070090#define TABLA_MBHC_FAKE_INSERT_LOW 10
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070091#define TABLA_MBHC_FAKE_INSERT_HIGH 80
92#define TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO 150
Joonwoo Park03324832012-03-19 19:36:16 -070093
94#define TABLA_MBHC_STATUS_REL_DETECTION 0x0C
95
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070096#define TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 200
97
Joonwoo Parkcf473b42012-03-29 19:48:16 -070098#define TABLA_MBHC_FAKE_INS_DELTA_MV 200
99#define TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV 300
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700100
101#define TABLA_HS_DETECT_PLUG_TIME_MS (5 * 1000)
102#define TABLA_HS_DETECT_PLUG_INERVAL_MS 100
103
104#define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
105
Joonwoo Park2cc13f02012-05-09 12:44:25 -0700106#define TABLA_MBHC_GND_MIC_SWAP_THRESHOLD 2
107
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700108#define TABLA_ACQUIRE_LOCK(x) do { mutex_lock(&x); } while (0)
109#define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
110
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700111static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
112static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
113static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800114static struct snd_soc_dai_driver tabla_dai[];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800115static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116
117enum tabla_bandgap_type {
118 TABLA_BANDGAP_OFF = 0,
119 TABLA_BANDGAP_AUDIO_MODE,
120 TABLA_BANDGAP_MBHC_MODE,
121};
122
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700123struct mbhc_micbias_regs {
124 u16 cfilt_val;
125 u16 cfilt_ctl;
126 u16 mbhc_reg;
127 u16 int_rbias;
128 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -0800129 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700130};
131
Ben Romberger1f045a72011-11-04 10:14:57 -0700132/* Codec supports 2 IIR filters */
133enum {
134 IIR1 = 0,
135 IIR2,
136 IIR_MAX,
137};
138/* Codec supports 5 bands */
139enum {
140 BAND1 = 0,
141 BAND2,
142 BAND3,
143 BAND4,
144 BAND5,
145 BAND_MAX,
146};
147
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800148enum {
149 COMPANDER_1 = 0,
150 COMPANDER_2,
151 COMPANDER_MAX,
152};
153
154enum {
155 COMPANDER_FS_8KHZ = 0,
156 COMPANDER_FS_16KHZ,
157 COMPANDER_FS_32KHZ,
158 COMPANDER_FS_48KHZ,
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700159 COMPANDER_FS_96KHZ,
160 COMPANDER_FS_192KHZ,
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800161 COMPANDER_FS_MAX,
162};
163
Joonwoo Parka9444452011-12-08 18:48:27 -0800164/* Flags to track of PA and DAC state.
165 * PA and DAC should be tracked separately as AUXPGA loopback requires
166 * only PA to be turned on without DAC being on. */
167enum tabla_priv_ack_flags {
168 TABLA_HPHL_PA_OFF_ACK = 0,
169 TABLA_HPHR_PA_OFF_ACK,
170 TABLA_HPHL_DAC_OFF_ACK,
171 TABLA_HPHR_DAC_OFF_ACK
172};
173
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800174
175struct comp_sample_dependent_params {
176 u32 peak_det_timeout;
177 u32 rms_meter_div_fact;
178 u32 rms_meter_resamp_fact;
179};
180
Joonwoo Park0976d012011-12-22 11:48:18 -0800181/* Data used by MBHC */
182struct mbhc_internal_cal_data {
183 u16 dce_z;
184 u16 dce_mb;
185 u16 sta_z;
186 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800187 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800188 u32 t_dce;
189 u32 t_sta;
190 u32 micb_mv;
191 u16 v_ins_hu;
192 u16 v_ins_h;
193 u16 v_b1_hu;
194 u16 v_b1_h;
195 u16 v_b1_huc;
196 u16 v_brh;
197 u16 v_brl;
198 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800199 u8 npoll;
200 u8 nbounce_wait;
Joonwoo Parkcf473b42012-03-29 19:48:16 -0700201 s16 adj_v_hs_max;
202 u16 adj_v_ins_hu;
203 u16 adj_v_ins_h;
204 s16 v_inval_ins_low;
205 s16 v_inval_ins_high;
Joonwoo Park0976d012011-12-22 11:48:18 -0800206};
207
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800208struct tabla_reg_address {
209 u16 micb_4_ctl;
210 u16 micb_4_int_rbias;
211 u16 micb_4_mbhc;
212};
213
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700214enum tabla_mbhc_plug_type {
Joonwoo Park41956722012-04-18 13:13:07 -0700215 PLUG_TYPE_INVALID = -1,
216 PLUG_TYPE_NONE,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700217 PLUG_TYPE_HEADSET,
218 PLUG_TYPE_HEADPHONE,
219 PLUG_TYPE_HIGH_HPH,
Joonwoo Park2cc13f02012-05-09 12:44:25 -0700220 PLUG_TYPE_GND_MIC_SWAP,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700221};
222
223enum tabla_mbhc_state {
224 MBHC_STATE_NONE = -1,
225 MBHC_STATE_POTENTIAL,
226 MBHC_STATE_POTENTIAL_RECOVERY,
227 MBHC_STATE_RELEASE,
228};
229
Kiran Kandid8cf5212012-03-02 15:34:53 -0800230struct hpf_work {
231 struct tabla_priv *tabla;
232 u32 decimator;
233 u8 tx_hpf_cut_of_freq;
234 struct delayed_work dwork;
235};
236
237static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
238
Bradley Rubin229c6a52011-07-12 16:18:48 -0700239struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700240 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800241 struct tabla_reg_address reg_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700242 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700243 u32 cfilt1_cnt;
244 u32 cfilt2_cnt;
245 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700246 u32 rx_bias_count;
Kiran Kandi0ba468f2012-05-08 11:45:05 -0700247 s32 dmic_1_2_clk_cnt;
248 s32 dmic_3_4_clk_cnt;
249 s32 dmic_5_6_clk_cnt;
250
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700251 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700252 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700253 bool clock_active;
254 bool config_mode_active;
255 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800256 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700257 int buttons_pressed;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700258 enum tabla_mbhc_state mbhc_state;
259 struct tabla_mbhc_config mbhc_cfg;
Joonwoo Park0976d012011-12-22 11:48:18 -0800260 struct mbhc_internal_cal_data mbhc_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530262 struct wcd9xxx_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700263 u32 anc_slot;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700264
265 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700266 /* Delayed work to report long button press */
Joonwoo Park03324832012-03-19 19:36:16 -0700267 struct delayed_work mbhc_btn_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700268
269 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700270 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700271
Joonwoo Parka9444452011-12-08 18:48:27 -0800272 /* track PA/DAC state */
273 unsigned long hph_pa_dac_state;
274
Santosh Mardie15e2302011-11-15 10:39:23 +0530275 /*track tabla interface type*/
276 u8 intf_type;
277
Patrick Lai49efeac2011-11-03 11:01:12 -0700278 u32 hph_status; /* track headhpone status */
279 /* define separate work for left and right headphone OCP to avoid
280 * additional checking on which OCP event to report so no locking
281 * to ensure synchronization is required
282 */
283 struct work_struct hphlocp_work; /* reporting left hph ocp off */
284 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800285
Patrick Laic7cae882011-11-18 11:52:49 -0800286 u8 hphlocp_cnt; /* headphone left ocp retry */
287 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800288
Patrick Lai64b43262011-12-06 17:29:15 -0800289 /* Work to perform MBHC Firmware Read */
290 struct delayed_work mbhc_firmware_dwork;
291 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800292
293 /* num of slim ports required */
294 struct tabla_codec_dai_data dai[NUM_CODEC_DAIS];
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800295
296 /*compander*/
297 int comp_enabled[COMPANDER_MAX];
298 u32 comp_fs[COMPANDER_MAX];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800299
300 /* Maintain the status of AUX PGA */
301 int aux_pga_cnt;
302 u8 aux_l_gain;
303 u8 aux_r_gain;
Joonwoo Park03324832012-03-19 19:36:16 -0700304
Joonwoo Park03324832012-03-19 19:36:16 -0700305 struct delayed_work mbhc_insert_dwork;
306 unsigned long mbhc_last_resume; /* in jiffies */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700307
308 u8 current_plug;
309 struct work_struct hs_correct_plug_work;
310 bool hs_detect_work_stop;
311 bool hs_polling_irq_prepared;
312 bool lpi_enabled; /* low power insertion detection */
313 bool in_gpio_handler;
314 /* Currently, only used for mbhc purpose, to protect
315 * concurrent execution of mbhc threaded irq handlers and
316 * kill race between DAPM and MBHC.But can serve as a
317 * general lock to protect codec resource
318 */
319 struct mutex codec_resource_lock;
320
Bradley Rubincb3950a2011-08-18 13:07:26 -0700321#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700322 struct dentry *debugfs_poke;
323 struct dentry *debugfs_mbhc;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700324#endif
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700325};
326
Bradley Rubincb3950a2011-08-18 13:07:26 -0700327
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800328static const u32 comp_shift[] = {
329 0,
330 2,
331};
332
333static const int comp_rx_path[] = {
334 COMPANDER_1,
335 COMPANDER_1,
336 COMPANDER_2,
337 COMPANDER_2,
338 COMPANDER_2,
339 COMPANDER_2,
340 COMPANDER_MAX,
341};
342
343static const struct comp_sample_dependent_params comp_samp_params[] = {
344 {
345 .peak_det_timeout = 0x2,
346 .rms_meter_div_fact = 0x8 << 4,
347 .rms_meter_resamp_fact = 0x21,
348 },
349 {
350 .peak_det_timeout = 0x3,
351 .rms_meter_div_fact = 0x9 << 4,
352 .rms_meter_resamp_fact = 0x28,
353 },
354
355 {
356 .peak_det_timeout = 0x5,
357 .rms_meter_div_fact = 0xB << 4,
358 .rms_meter_resamp_fact = 0x28,
359 },
360
361 {
362 .peak_det_timeout = 0x5,
363 .rms_meter_div_fact = 0xB << 4,
364 .rms_meter_resamp_fact = 0x28,
365 },
366};
367
Kuirong Wange9c8a222012-03-28 16:24:09 -0700368static unsigned short rx_digital_gain_reg[] = {
369 TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
370 TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
371 TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
372 TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
373 TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
374 TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
375 TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
376};
377
378
379static unsigned short tx_digital_gain_reg[] = {
380 TABLA_A_CDC_TX1_VOL_CTL_GAIN,
381 TABLA_A_CDC_TX2_VOL_CTL_GAIN,
382 TABLA_A_CDC_TX3_VOL_CTL_GAIN,
383 TABLA_A_CDC_TX4_VOL_CTL_GAIN,
384 TABLA_A_CDC_TX5_VOL_CTL_GAIN,
385 TABLA_A_CDC_TX6_VOL_CTL_GAIN,
386 TABLA_A_CDC_TX7_VOL_CTL_GAIN,
387 TABLA_A_CDC_TX8_VOL_CTL_GAIN,
388 TABLA_A_CDC_TX9_VOL_CTL_GAIN,
389 TABLA_A_CDC_TX10_VOL_CTL_GAIN,
390};
391
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700392static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
393 struct snd_kcontrol *kcontrol, int event)
394{
395 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700396
397 pr_debug("%s %d\n", __func__, event);
398 switch (event) {
399 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
401 0x01);
402 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
403 usleep_range(200, 200);
404 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
405 break;
406 case SND_SOC_DAPM_PRE_PMD:
407 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
408 0x10);
409 usleep_range(20, 20);
410 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
411 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
412 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
413 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
414 0x00);
415 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700416 break;
417 }
418 return 0;
419}
420
Bradley Rubina7096d02011-08-03 18:29:02 -0700421static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
422 struct snd_ctl_elem_value *ucontrol)
423{
424 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
425 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
426 ucontrol->value.integer.value[0] = tabla->anc_slot;
427 return 0;
428}
429
430static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
431 struct snd_ctl_elem_value *ucontrol)
432{
433 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
434 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
435 tabla->anc_slot = ucontrol->value.integer.value[0];
436 return 0;
437}
438
Kiran Kandid2d86b52011-09-09 17:44:28 -0700439static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
440 struct snd_ctl_elem_value *ucontrol)
441{
442 u8 ear_pa_gain;
443 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
444
445 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
446
447 ear_pa_gain = ear_pa_gain >> 5;
448
449 if (ear_pa_gain == 0x00) {
450 ucontrol->value.integer.value[0] = 0;
451 } else if (ear_pa_gain == 0x04) {
452 ucontrol->value.integer.value[0] = 1;
453 } else {
454 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
455 __func__, ear_pa_gain);
456 return -EINVAL;
457 }
458
459 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
460
461 return 0;
462}
463
464static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
465 struct snd_ctl_elem_value *ucontrol)
466{
467 u8 ear_pa_gain;
468 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
469
470 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
471 ucontrol->value.integer.value[0]);
472
473 switch (ucontrol->value.integer.value[0]) {
474 case 0:
475 ear_pa_gain = 0x00;
476 break;
477 case 1:
478 ear_pa_gain = 0x80;
479 break;
480 default:
481 return -EINVAL;
482 }
483
484 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
485 return 0;
486}
487
Ben Romberger1f045a72011-11-04 10:14:57 -0700488static int tabla_get_iir_enable_audio_mixer(
489 struct snd_kcontrol *kcontrol,
490 struct snd_ctl_elem_value *ucontrol)
491{
492 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
493 int iir_idx = ((struct soc_multi_mixer_control *)
494 kcontrol->private_value)->reg;
495 int band_idx = ((struct soc_multi_mixer_control *)
496 kcontrol->private_value)->shift;
497
498 ucontrol->value.integer.value[0] =
499 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
500 (1 << band_idx);
501
502 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
503 iir_idx, band_idx,
504 (uint32_t)ucontrol->value.integer.value[0]);
505 return 0;
506}
507
508static int tabla_put_iir_enable_audio_mixer(
509 struct snd_kcontrol *kcontrol,
510 struct snd_ctl_elem_value *ucontrol)
511{
512 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
513 int iir_idx = ((struct soc_multi_mixer_control *)
514 kcontrol->private_value)->reg;
515 int band_idx = ((struct soc_multi_mixer_control *)
516 kcontrol->private_value)->shift;
517 int value = ucontrol->value.integer.value[0];
518
519 /* Mask first 5 bits, 6-8 are reserved */
520 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
521 (1 << band_idx), (value << band_idx));
522
523 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
524 iir_idx, band_idx, value);
525 return 0;
526}
527static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
528 int iir_idx, int band_idx,
529 int coeff_idx)
530{
531 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800532 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700533 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800534 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700535
536 /* Mask bits top 2 bits since they are reserved */
537 return ((snd_soc_read(codec,
538 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
539 (snd_soc_read(codec,
540 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
541 (snd_soc_read(codec,
542 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
543 (snd_soc_read(codec,
544 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
545 0x3FFFFFFF;
546}
547
548static int tabla_get_iir_band_audio_mixer(
549 struct snd_kcontrol *kcontrol,
550 struct snd_ctl_elem_value *ucontrol)
551{
552 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
553 int iir_idx = ((struct soc_multi_mixer_control *)
554 kcontrol->private_value)->reg;
555 int band_idx = ((struct soc_multi_mixer_control *)
556 kcontrol->private_value)->shift;
557
558 ucontrol->value.integer.value[0] =
559 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
560 ucontrol->value.integer.value[1] =
561 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
562 ucontrol->value.integer.value[2] =
563 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
564 ucontrol->value.integer.value[3] =
565 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
566 ucontrol->value.integer.value[4] =
567 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
568
569 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
570 "%s: IIR #%d band #%d b1 = 0x%x\n"
571 "%s: IIR #%d band #%d b2 = 0x%x\n"
572 "%s: IIR #%d band #%d a1 = 0x%x\n"
573 "%s: IIR #%d band #%d a2 = 0x%x\n",
574 __func__, iir_idx, band_idx,
575 (uint32_t)ucontrol->value.integer.value[0],
576 __func__, iir_idx, band_idx,
577 (uint32_t)ucontrol->value.integer.value[1],
578 __func__, iir_idx, band_idx,
579 (uint32_t)ucontrol->value.integer.value[2],
580 __func__, iir_idx, band_idx,
581 (uint32_t)ucontrol->value.integer.value[3],
582 __func__, iir_idx, band_idx,
583 (uint32_t)ucontrol->value.integer.value[4]);
584 return 0;
585}
586
587static void set_iir_band_coeff(struct snd_soc_codec *codec,
588 int iir_idx, int band_idx,
589 int coeff_idx, uint32_t value)
590{
591 /* Mask top 3 bits, 6-8 are reserved */
592 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800593 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700594 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800595 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700596
597 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800598 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700599 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800600 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700601
602 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800603 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700604 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800605 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700606
Ben Romberger0915aae2012-02-06 23:32:43 -0800607 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700608 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800609 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700610
Ben Romberger0915aae2012-02-06 23:32:43 -0800611 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700612 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800613 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700614}
615
616static int tabla_put_iir_band_audio_mixer(
617 struct snd_kcontrol *kcontrol,
618 struct snd_ctl_elem_value *ucontrol)
619{
620 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
621 int iir_idx = ((struct soc_multi_mixer_control *)
622 kcontrol->private_value)->reg;
623 int band_idx = ((struct soc_multi_mixer_control *)
624 kcontrol->private_value)->shift;
625
626 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
627 ucontrol->value.integer.value[0]);
628 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
629 ucontrol->value.integer.value[1]);
630 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
631 ucontrol->value.integer.value[2]);
632 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
633 ucontrol->value.integer.value[3]);
634 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
635 ucontrol->value.integer.value[4]);
636
637 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
638 "%s: IIR #%d band #%d b1 = 0x%x\n"
639 "%s: IIR #%d band #%d b2 = 0x%x\n"
640 "%s: IIR #%d band #%d a1 = 0x%x\n"
641 "%s: IIR #%d band #%d a2 = 0x%x\n",
642 __func__, iir_idx, band_idx,
643 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
644 __func__, iir_idx, band_idx,
645 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
646 __func__, iir_idx, band_idx,
647 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
648 __func__, iir_idx, band_idx,
649 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
650 __func__, iir_idx, band_idx,
651 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
652 return 0;
653}
654
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800655static int tabla_compander_gain_offset(
656 struct snd_soc_codec *codec, u32 enable,
657 unsigned int reg, int mask, int event)
658{
659 int pa_mode = snd_soc_read(codec, reg) & mask;
660 int gain_offset = 0;
661 /* if PMU && enable is 1-> offset is 3
662 * if PMU && enable is 0-> offset is 0
663 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
664 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
665 */
666
667 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0))
668 gain_offset = TABLA_COMP_DIGITAL_GAIN_OFFSET;
669 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0))
670 gain_offset = -TABLA_COMP_DIGITAL_GAIN_OFFSET;
671 return gain_offset;
672}
673
674
675static int tabla_config_gain_compander(
676 struct snd_soc_codec *codec,
677 u32 compander, u32 enable, int event)
678{
679 int value = 0;
680 int mask = 1 << 4;
681 int gain = 0;
682 int gain_offset;
683 if (compander >= COMPANDER_MAX) {
684 pr_err("%s: Error, invalid compander channel\n", __func__);
685 return -EINVAL;
686 }
687
688 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
689 value = 1 << 4;
690
691 if (compander == COMPANDER_1) {
692 gain_offset = tabla_compander_gain_offset(codec, enable,
693 TABLA_A_RX_HPH_L_GAIN, mask, event);
694 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
695 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
696 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
697 0xFF, gain - gain_offset);
698 gain_offset = tabla_compander_gain_offset(codec, enable,
699 TABLA_A_RX_HPH_R_GAIN, mask, event);
700 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
701 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
702 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
703 0xFF, gain - gain_offset);
704 } else if (compander == COMPANDER_2) {
705 gain_offset = tabla_compander_gain_offset(codec, enable,
706 TABLA_A_RX_LINE_1_GAIN, mask, event);
707 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
708 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
709 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
710 0xFF, gain - gain_offset);
711 gain_offset = tabla_compander_gain_offset(codec, enable,
712 TABLA_A_RX_LINE_3_GAIN, mask, event);
713 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
714 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
715 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
716 0xFF, gain - gain_offset);
717 gain_offset = tabla_compander_gain_offset(codec, enable,
718 TABLA_A_RX_LINE_2_GAIN, mask, event);
719 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
720 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
721 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
722 0xFF, gain - gain_offset);
723 gain_offset = tabla_compander_gain_offset(codec, enable,
724 TABLA_A_RX_LINE_4_GAIN, mask, event);
725 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
726 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
727 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
728 0xFF, gain - gain_offset);
729 }
730 return 0;
731}
732static int tabla_get_compander(struct snd_kcontrol *kcontrol,
733 struct snd_ctl_elem_value *ucontrol)
734{
735
736 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
737 int comp = ((struct soc_multi_mixer_control *)
738 kcontrol->private_value)->max;
739 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
740
741 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
742
743 return 0;
744}
745
746static int tabla_set_compander(struct snd_kcontrol *kcontrol,
747 struct snd_ctl_elem_value *ucontrol)
748{
749 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
750 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
751 int comp = ((struct soc_multi_mixer_control *)
752 kcontrol->private_value)->max;
753 int value = ucontrol->value.integer.value[0];
754
755 if (value == tabla->comp_enabled[comp]) {
756 pr_debug("%s: compander #%d enable %d no change\n",
757 __func__, comp, value);
758 return 0;
759 }
760 tabla->comp_enabled[comp] = value;
761 return 0;
762}
763
764
765static int tabla_config_compander(struct snd_soc_dapm_widget *w,
766 struct snd_kcontrol *kcontrol,
767 int event)
768{
769 struct snd_soc_codec *codec = w->codec;
770 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
771 u32 rate = tabla->comp_fs[w->shift];
772
773 switch (event) {
774 case SND_SOC_DAPM_PRE_PMU:
775 if (tabla->comp_enabled[w->shift] != 0) {
776 /* Enable both L/R compander clocks */
777 snd_soc_update_bits(codec,
778 TABLA_A_CDC_CLK_RX_B2_CTL,
779 0x03 << comp_shift[w->shift],
780 0x03 << comp_shift[w->shift]);
781 /* Clar the HALT for the compander*/
782 snd_soc_update_bits(codec,
783 TABLA_A_CDC_COMP1_B1_CTL +
784 w->shift * 8, 1 << 2, 0);
785 /* Toggle compander reset bits*/
786 snd_soc_update_bits(codec,
787 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
788 0x03 << comp_shift[w->shift],
789 0x03 << comp_shift[w->shift]);
790 snd_soc_update_bits(codec,
791 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
792 0x03 << comp_shift[w->shift], 0);
793 tabla_config_gain_compander(codec, w->shift, 1, event);
794 /* Update the RMS meter resampling*/
795 snd_soc_update_bits(codec,
796 TABLA_A_CDC_COMP1_B3_CTL +
797 w->shift * 8, 0xFF, 0x01);
798 /* Wait for 1ms*/
799 usleep_range(1000, 1000);
800 }
801 break;
802 case SND_SOC_DAPM_POST_PMU:
803 /* Set sample rate dependent paramater*/
804 if (tabla->comp_enabled[w->shift] != 0) {
805 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
806 w->shift * 8, 0x03, rate);
807 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
808 w->shift * 8, 0x0F,
809 comp_samp_params[rate].peak_det_timeout);
810 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
811 w->shift * 8, 0xF0,
812 comp_samp_params[rate].rms_meter_div_fact);
813 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
814 w->shift * 8, 0xFF,
815 comp_samp_params[rate].rms_meter_resamp_fact);
816 /* Compander enable -> 0x370/0x378*/
817 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
818 w->shift * 8, 0x03, 0x03);
819 }
820 break;
821 case SND_SOC_DAPM_PRE_PMD:
822 /* Halt the compander*/
823 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
824 w->shift * 8, 1 << 2, 1 << 2);
825 break;
826 case SND_SOC_DAPM_POST_PMD:
827 /* Restore the gain */
828 tabla_config_gain_compander(codec, w->shift,
829 tabla->comp_enabled[w->shift], event);
830 /* Disable the compander*/
831 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
832 w->shift * 8, 0x03, 0x00);
833 /* Turn off the clock for compander in pair*/
834 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
835 0x03 << comp_shift[w->shift], 0);
836 break;
837 }
838 return 0;
839}
840
Kiran Kandid2d86b52011-09-09 17:44:28 -0700841static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
842static const struct soc_enum tabla_ear_pa_gain_enum[] = {
843 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
844};
845
Santosh Mardi024010f2011-10-18 06:27:21 +0530846/*cut of frequency for high pass filter*/
847static const char *cf_text[] = {
848 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
849};
850
851static const struct soc_enum cf_dec1_enum =
852 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
853
854static const struct soc_enum cf_dec2_enum =
855 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
856
857static const struct soc_enum cf_dec3_enum =
858 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
859
860static const struct soc_enum cf_dec4_enum =
861 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
862
863static const struct soc_enum cf_dec5_enum =
864 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
865
866static const struct soc_enum cf_dec6_enum =
867 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
868
869static const struct soc_enum cf_dec7_enum =
870 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
871
872static const struct soc_enum cf_dec8_enum =
873 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
874
875static const struct soc_enum cf_dec9_enum =
876 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
877
878static const struct soc_enum cf_dec10_enum =
879 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
880
881static const struct soc_enum cf_rxmix1_enum =
882 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
883
884static const struct soc_enum cf_rxmix2_enum =
885 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
886
887static const struct soc_enum cf_rxmix3_enum =
888 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
889
890static const struct soc_enum cf_rxmix4_enum =
891 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
892
893static const struct soc_enum cf_rxmix5_enum =
894 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
895;
896static const struct soc_enum cf_rxmix6_enum =
897 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
898
899static const struct soc_enum cf_rxmix7_enum =
900 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -0700903
904 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
905 tabla_pa_gain_get, tabla_pa_gain_put),
906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
908 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700909 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
910 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
912 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700913 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
914 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -0700915 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
916 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -0700917
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700918 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
919 line_gain),
920 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
921 line_gain),
922
Bradley Rubin410383f2011-07-22 13:44:23 -0700923 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
924 -84, 40, digital_gain),
925 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
926 -84, 40, digital_gain),
927 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
928 -84, 40, digital_gain),
929 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
930 -84, 40, digital_gain),
931 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
932 -84, 40, digital_gain),
933 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
934 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -0800935 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
936 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937
Bradley Rubin410383f2011-07-22 13:44:23 -0700938 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700940 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700941 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -0700942 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
943 digital_gain),
944 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
945 digital_gain),
946 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
947 digital_gain),
948 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
949 digital_gain),
950 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
951 digital_gain),
952 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
953 digital_gain),
954 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
955 digital_gain),
956 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
957 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -0700958 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
959 40, digital_gain),
960 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
961 40, digital_gain),
962 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
963 40, digital_gain),
964 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
965 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700966 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
967 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700968 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
969 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -0700970 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
971 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700972
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800973 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
974 aux_pga_gain),
975 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
976 aux_pga_gain),
977
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -0800979 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -0700980 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -0700981
982 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
983 tabla_put_anc_slot),
Santosh Mardi024010f2011-10-18 06:27:21 +0530984 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
985 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
986 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
987 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
988 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
989 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
990 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
991 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
992 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
993 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
994
995 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
996 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
997 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
998 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
999 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
1000 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
1001 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
1002 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
1003 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
1004 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
1005
1006 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
1007 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
1008 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
1009 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
1010 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
1011 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
1012 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
1013
1014 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1015 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1016 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
1017 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
1018 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
1019 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
1020 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -07001021
1022 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1023 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1024 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1025 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1026 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1027 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1028 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1029 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1030 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1031 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1032 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1033 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1034 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1035 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1036 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1037 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1038 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1039 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1040 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1041 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1042
1043 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1044 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1045 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1046 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1047 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1048 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1049 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1050 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1051 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1052 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1053 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1054 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1055 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1056 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1057 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1058 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1059 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1060 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1061 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1062 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001063 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
1064 tabla_get_compander, tabla_set_compander),
1065 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
1066 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001067};
1068
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001069static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
1070 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
1071};
1072
1073static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
1074 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
1075};
1076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001077static const char *rx_mix1_text[] = {
1078 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1079 "RX5", "RX6", "RX7"
1080};
1081
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001082static const char *rx_mix2_text[] = {
1083 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
1084};
1085
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001086static const char *rx_dsm_text[] = {
1087 "CIC_OUT", "DSM_INV"
1088};
1089
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001090static const char *sb_tx1_mux_text[] = {
1091 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1092 "DEC1"
1093};
1094
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001095static const char *sb_tx2_mux_text[] = {
1096 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1097 "DEC2"
1098};
1099
1100static const char *sb_tx3_mux_text[] = {
1101 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1102 "DEC3"
1103};
1104
1105static const char *sb_tx4_mux_text[] = {
1106 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1107 "DEC4"
1108};
1109
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001110static const char *sb_tx5_mux_text[] = {
1111 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1112 "DEC5"
1113};
1114
1115static const char *sb_tx6_mux_text[] = {
1116 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1117 "DEC6"
1118};
1119
1120static const char const *sb_tx7_to_tx10_mux_text[] = {
1121 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1122 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1123 "DEC9", "DEC10"
1124};
1125
1126static const char *dec1_mux_text[] = {
1127 "ZERO", "DMIC1", "ADC6",
1128};
1129
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001130static const char *dec2_mux_text[] = {
1131 "ZERO", "DMIC2", "ADC5",
1132};
1133
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001134static const char *dec3_mux_text[] = {
1135 "ZERO", "DMIC3", "ADC4",
1136};
1137
1138static const char *dec4_mux_text[] = {
1139 "ZERO", "DMIC4", "ADC3",
1140};
1141
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142static const char *dec5_mux_text[] = {
1143 "ZERO", "DMIC5", "ADC2",
1144};
1145
1146static const char *dec6_mux_text[] = {
1147 "ZERO", "DMIC6", "ADC1",
1148};
1149
1150static const char const *dec7_mux_text[] = {
1151 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1152};
1153
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001154static const char *dec8_mux_text[] = {
1155 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1156};
1157
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001158static const char *dec9_mux_text[] = {
1159 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1160};
1161
1162static const char *dec10_mux_text[] = {
1163 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1164};
1165
Bradley Rubin229c6a52011-07-12 16:18:48 -07001166static const char const *anc_mux_text[] = {
1167 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1168 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1169};
1170
1171static const char const *anc1_fb_mux_text[] = {
1172 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1173};
1174
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175static const char *iir1_inp1_text[] = {
1176 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1177 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1178};
1179
1180static const struct soc_enum rx_mix1_inp1_chain_enum =
1181 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1182
Bradley Rubin229c6a52011-07-12 16:18:48 -07001183static const struct soc_enum rx_mix1_inp2_chain_enum =
1184 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1185
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186static const struct soc_enum rx2_mix1_inp1_chain_enum =
1187 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1188
Bradley Rubin229c6a52011-07-12 16:18:48 -07001189static const struct soc_enum rx2_mix1_inp2_chain_enum =
1190 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001192static const struct soc_enum rx3_mix1_inp1_chain_enum =
1193 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1194
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001195static const struct soc_enum rx3_mix1_inp2_chain_enum =
1196 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1197
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198static const struct soc_enum rx4_mix1_inp1_chain_enum =
1199 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1200
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001201static const struct soc_enum rx4_mix1_inp2_chain_enum =
1202 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1203
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204static const struct soc_enum rx5_mix1_inp1_chain_enum =
1205 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1206
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001207static const struct soc_enum rx5_mix1_inp2_chain_enum =
1208 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1209
1210static const struct soc_enum rx6_mix1_inp1_chain_enum =
1211 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1212
1213static const struct soc_enum rx6_mix1_inp2_chain_enum =
1214 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1215
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001216static const struct soc_enum rx7_mix1_inp1_chain_enum =
1217 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1218
1219static const struct soc_enum rx7_mix1_inp2_chain_enum =
1220 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1221
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001222static const struct soc_enum rx1_mix2_inp1_chain_enum =
1223 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
1224
1225static const struct soc_enum rx1_mix2_inp2_chain_enum =
1226 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
1227
1228static const struct soc_enum rx2_mix2_inp1_chain_enum =
1229 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
1230
1231static const struct soc_enum rx2_mix2_inp2_chain_enum =
1232 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
1233
1234static const struct soc_enum rx3_mix2_inp1_chain_enum =
1235 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B3_CTL, 0, 5, rx_mix2_text);
1236
1237static const struct soc_enum rx3_mix2_inp2_chain_enum =
1238 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B3_CTL, 3, 5, rx_mix2_text);
1239
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001240static const struct soc_enum rx4_dsm_enum =
1241 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1242
1243static const struct soc_enum rx6_dsm_enum =
1244 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1245
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001246static const struct soc_enum sb_tx1_mux_enum =
1247 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1248
1249static const struct soc_enum sb_tx2_mux_enum =
1250 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
1251
1252static const struct soc_enum sb_tx3_mux_enum =
1253 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
1254
1255static const struct soc_enum sb_tx4_mux_enum =
1256 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
1257
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001258static const struct soc_enum sb_tx5_mux_enum =
1259 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1260
1261static const struct soc_enum sb_tx6_mux_enum =
1262 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1263
1264static const struct soc_enum sb_tx7_mux_enum =
1265 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1266 sb_tx7_to_tx10_mux_text);
1267
1268static const struct soc_enum sb_tx8_mux_enum =
1269 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1270 sb_tx7_to_tx10_mux_text);
1271
Kiran Kandi3426e512011-09-13 22:50:10 -07001272static const struct soc_enum sb_tx9_mux_enum =
1273 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1274 sb_tx7_to_tx10_mux_text);
1275
1276static const struct soc_enum sb_tx10_mux_enum =
1277 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1278 sb_tx7_to_tx10_mux_text);
1279
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001280static const struct soc_enum dec1_mux_enum =
1281 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1282
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001283static const struct soc_enum dec2_mux_enum =
1284 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1285
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001286static const struct soc_enum dec3_mux_enum =
1287 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1288
1289static const struct soc_enum dec4_mux_enum =
1290 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1291
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292static const struct soc_enum dec5_mux_enum =
1293 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1294
1295static const struct soc_enum dec6_mux_enum =
1296 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1297
1298static const struct soc_enum dec7_mux_enum =
1299 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1300
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001301static const struct soc_enum dec8_mux_enum =
1302 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1303
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001304static const struct soc_enum dec9_mux_enum =
1305 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1306
1307static const struct soc_enum dec10_mux_enum =
1308 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1309
Bradley Rubin229c6a52011-07-12 16:18:48 -07001310static const struct soc_enum anc1_mux_enum =
1311 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1312
1313static const struct soc_enum anc2_mux_enum =
1314 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1315
1316static const struct soc_enum anc1_fb_mux_enum =
1317 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319static const struct soc_enum iir1_inp1_mux_enum =
1320 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir1_inp1_text);
1321
1322static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1323 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1324
Bradley Rubin229c6a52011-07-12 16:18:48 -07001325static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1326 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1329 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1330
Bradley Rubin229c6a52011-07-12 16:18:48 -07001331static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1332 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1333
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1335 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1336
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001337static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1338 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1341 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1342
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001343static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1344 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1345
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001346static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1347 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1348
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001349static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1350 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1351
1352static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1353 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1354
1355static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1356 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1357
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001358static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1359 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1360
1361static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1362 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1363
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001364static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1365 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1366
1367static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
1368 SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
1369
1370static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1371 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1372
1373static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
1374 SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
1375
1376static const struct snd_kcontrol_new rx3_mix2_inp1_mux =
1377 SOC_DAPM_ENUM("RX3 MIX2 INP1 Mux", rx3_mix2_inp1_chain_enum);
1378
1379static const struct snd_kcontrol_new rx3_mix2_inp2_mux =
1380 SOC_DAPM_ENUM("RX3 MIX2 INP2 Mux", rx3_mix2_inp2_chain_enum);
1381
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001382static const struct snd_kcontrol_new rx4_dsm_mux =
1383 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1384
1385static const struct snd_kcontrol_new rx6_dsm_mux =
1386 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1387
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001388static const struct snd_kcontrol_new sb_tx1_mux =
1389 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1390
1391static const struct snd_kcontrol_new sb_tx2_mux =
1392 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
1393
1394static const struct snd_kcontrol_new sb_tx3_mux =
1395 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
1396
1397static const struct snd_kcontrol_new sb_tx4_mux =
1398 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
1399
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001400static const struct snd_kcontrol_new sb_tx5_mux =
1401 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1402
1403static const struct snd_kcontrol_new sb_tx6_mux =
1404 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1405
1406static const struct snd_kcontrol_new sb_tx7_mux =
1407 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1408
1409static const struct snd_kcontrol_new sb_tx8_mux =
1410 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1411
Kiran Kandi3426e512011-09-13 22:50:10 -07001412static const struct snd_kcontrol_new sb_tx9_mux =
1413 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1414
1415static const struct snd_kcontrol_new sb_tx10_mux =
1416 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418
Kiran Kandi59a96b12012-01-16 02:20:03 -08001419static int wcd9310_put_dec_enum(struct snd_kcontrol *kcontrol,
1420 struct snd_ctl_elem_value *ucontrol)
1421{
1422 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1423 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1424 struct snd_soc_codec *codec = w->codec;
1425 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1426 unsigned int dec_mux, decimator;
1427 char *dec_name = NULL;
1428 char *widget_name = NULL;
1429 char *temp;
1430 u16 tx_mux_ctl_reg;
1431 u8 adc_dmic_sel = 0x0;
1432 int ret = 0;
1433
1434 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1435 return -EINVAL;
1436
1437 dec_mux = ucontrol->value.enumerated.item[0];
1438
1439 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1440 if (!widget_name)
1441 return -ENOMEM;
1442 temp = widget_name;
1443
1444 dec_name = strsep(&widget_name, " ");
1445 widget_name = temp;
1446 if (!dec_name) {
1447 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1448 ret = -EINVAL;
1449 goto out;
1450 }
1451
1452 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
1453 if (ret < 0) {
1454 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1455 ret = -EINVAL;
1456 goto out;
1457 }
1458
1459 dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"
1460 " dec_mux = %u\n", __func__, w->name, dec_name, decimator,
1461 dec_mux);
1462
1463
1464 switch (decimator) {
1465 case 1:
1466 case 2:
1467 case 3:
1468 case 4:
1469 case 5:
1470 case 6:
1471 if (dec_mux == 1)
1472 adc_dmic_sel = 0x1;
1473 else
1474 adc_dmic_sel = 0x0;
1475 break;
1476 case 7:
1477 case 8:
1478 case 9:
1479 case 10:
1480 if ((dec_mux == 1) || (dec_mux == 2))
1481 adc_dmic_sel = 0x1;
1482 else
1483 adc_dmic_sel = 0x0;
1484 break;
1485 default:
1486 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1487 ret = -EINVAL;
1488 goto out;
1489 }
1490
1491 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1492
1493 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1494
1495 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1496
1497out:
1498 kfree(widget_name);
1499 return ret;
1500}
1501
1502#define WCD9310_DEC_ENUM(xname, xenum) \
1503{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1504 .info = snd_soc_info_enum_double, \
1505 .get = snd_soc_dapm_get_enum_double, \
1506 .put = wcd9310_put_dec_enum, \
1507 .private_value = (unsigned long)&xenum }
1508
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509static const struct snd_kcontrol_new dec1_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001510 WCD9310_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001512static const struct snd_kcontrol_new dec2_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001513 WCD9310_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001514
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001515static const struct snd_kcontrol_new dec3_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001516 WCD9310_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001517
1518static const struct snd_kcontrol_new dec4_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001519 WCD9310_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521static const struct snd_kcontrol_new dec5_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001522 WCD9310_DEC_ENUM("DEC5 MUX Mux", dec5_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001523
1524static const struct snd_kcontrol_new dec6_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001525 WCD9310_DEC_ENUM("DEC6 MUX Mux", dec6_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001526
1527static const struct snd_kcontrol_new dec7_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001528 WCD9310_DEC_ENUM("DEC7 MUX Mux", dec7_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001530static const struct snd_kcontrol_new dec8_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001531 WCD9310_DEC_ENUM("DEC8 MUX Mux", dec8_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001532
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001533static const struct snd_kcontrol_new dec9_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001534 WCD9310_DEC_ENUM("DEC9 MUX Mux", dec9_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001535
1536static const struct snd_kcontrol_new dec10_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001537 WCD9310_DEC_ENUM("DEC10 MUX Mux", dec10_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001538
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001539static const struct snd_kcontrol_new iir1_inp1_mux =
1540 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1541
Kiran Kandi59a96b12012-01-16 02:20:03 -08001542static const struct snd_kcontrol_new anc1_mux =
1543 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1544
Bradley Rubin229c6a52011-07-12 16:18:48 -07001545static const struct snd_kcontrol_new anc2_mux =
1546 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547
Bradley Rubin229c6a52011-07-12 16:18:48 -07001548static const struct snd_kcontrol_new anc1_fb_mux =
1549 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550
Bradley Rubin229c6a52011-07-12 16:18:48 -07001551static const struct snd_kcontrol_new dac1_switch[] = {
1552 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1553};
1554static const struct snd_kcontrol_new hphl_switch[] = {
1555 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1556};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001557
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001558static const struct snd_kcontrol_new hphl_pa_mix[] = {
1559 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1560 7, 1, 0),
1561 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1562 7, 1, 0),
1563 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1564 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1565 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1566 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1567};
1568
1569static const struct snd_kcontrol_new hphr_pa_mix[] = {
1570 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1571 6, 1, 0),
1572 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1573 6, 1, 0),
1574 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1575 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1576 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1577 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1578};
1579
1580static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1581 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1582 5, 1, 0),
1583 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1584 5, 1, 0),
1585 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1586 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1587 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1588 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1589};
1590
1591static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1592 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1593 4, 1, 0),
1594 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1595 4, 1, 0),
1596 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1597 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1598 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1599 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1600};
1601
1602static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1603 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1604 3, 1, 0),
1605 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1606 3, 1, 0),
1607 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1608 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1609 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1610 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1611};
1612
1613static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1614 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1615 2, 1, 0),
1616 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1617 2, 1, 0),
1618 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1619 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1620 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1621 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1622};
1623
1624static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1625 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1626 1, 1, 0),
1627 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1628 1, 1, 0),
1629 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1630 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1631 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1632 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1633};
1634
1635static const struct snd_kcontrol_new ear_pa_mix[] = {
1636 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1637 0, 1, 0),
1638 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1639 0, 1, 0),
1640 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1641 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1642 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1643 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1644};
1645
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001646static const struct snd_kcontrol_new lineout3_ground_switch =
1647 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1648
1649static const struct snd_kcontrol_new lineout4_ground_switch =
1650 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001651
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001652static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001653 int enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654{
1655 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1656
1657 pr_debug("%s %d\n", __func__, enable);
1658
1659 if (enable) {
1660 tabla->adc_count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
1662 } else {
1663 tabla->adc_count--;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001664 if (!tabla->adc_count)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001665 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
Joonwoo Park03324832012-03-19 19:36:16 -07001666 0x2, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001667 }
1668}
1669
1670static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
1671 struct snd_kcontrol *kcontrol, int event)
1672{
1673 struct snd_soc_codec *codec = w->codec;
1674 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001675 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676
1677 pr_debug("%s %d\n", __func__, event);
1678
1679 if (w->reg == TABLA_A_TX_1_2_EN)
1680 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
1681 else if (w->reg == TABLA_A_TX_3_4_EN)
1682 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
1683 else if (w->reg == TABLA_A_TX_5_6_EN)
1684 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
1685 else {
1686 pr_err("%s: Error, invalid adc register\n", __func__);
1687 return -EINVAL;
1688 }
1689
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001690 if (w->shift == 3)
1691 init_bit_shift = 6;
1692 else if (w->shift == 7)
1693 init_bit_shift = 7;
1694 else {
1695 pr_err("%s: Error, invalid init bit postion adc register\n",
1696 __func__);
1697 return -EINVAL;
1698 }
1699
1700
1701
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001702 switch (event) {
1703 case SND_SOC_DAPM_PRE_PMU:
1704 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001705 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1706 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 break;
1708 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08001709
1710 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1711
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001712 break;
1713 case SND_SOC_DAPM_POST_PMD:
1714 tabla_codec_enable_adc_block(codec, 0);
1715 break;
1716 }
1717 return 0;
1718}
1719
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001720static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
1721{
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001722 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1723 0x80);
1724 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
1725 0x04);
1726 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1727 0x01);
1728 usleep_range(1000, 1000);
1729 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1730 0x00);
1731}
1732
1733static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
1734 enum tabla_bandgap_type choice)
1735{
1736 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1737
1738 /* TODO lock resources accessed by audio streams and threaded
1739 * interrupt handlers
1740 */
1741
1742 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
1743 tabla->bandgap_type);
1744
1745 if (tabla->bandgap_type == choice)
1746 return;
1747
1748 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
1749 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1750 tabla_codec_enable_audio_mode_bandgap(codec);
1751 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001752 /* bandgap mode becomes fast,
1753 * mclk should be off or clk buff source souldn't be VBG
1754 * Let's turn off mclk always */
1755 WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001756 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
1757 0x2);
1758 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1759 0x80);
1760 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
1761 0x4);
1762 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
1763 0x01);
1764 usleep_range(1000, 1000);
1765 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
1766 0x00);
1767 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
1768 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
1769 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1770 usleep_range(100, 100);
1771 tabla_codec_enable_audio_mode_bandgap(codec);
1772 } else if (choice == TABLA_BANDGAP_OFF) {
1773 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x00);
1774 } else {
1775 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
1776 }
1777 tabla->bandgap_type = choice;
1778}
1779
1780static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
1781{
1782 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1783 pr_debug("%s\n", __func__);
1784 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001785 usleep_range(50, 50);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001786 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
1787 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001788 usleep_range(50, 50);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001789 tabla->clock_active = false;
1790}
1791
1792static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
1793{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001794 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001795 return 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001796 else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001797 return 1;
1798 else {
1799 BUG_ON(1);
1800 return -EINVAL;
1801 }
1802}
1803
1804static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
1805{
1806 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1807
1808 if (enable) {
1809 tabla->rx_bias_count++;
1810 if (tabla->rx_bias_count == 1)
1811 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1812 0x80, 0x80);
1813 } else {
1814 tabla->rx_bias_count--;
1815 if (!tabla->rx_bias_count)
1816 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
1817 0x80, 0x00);
1818 }
1819}
1820
1821static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
1822 int enable)
1823{
1824 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1825
1826 pr_debug("%s: enable = %d\n", __func__, enable);
1827 if (enable) {
1828 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001829 /* bandgap mode to fast */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001830 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
1831 usleep_range(5, 5);
1832 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001833 0x80);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001834 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001835 0x80);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001836 usleep_range(10, 10);
1837 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001838 usleep_range(10000, 10000);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001839 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
1840 } else {
1841 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001842 0);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001843 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001844 /* clk source to ext clk and clk buff ref to VBG */
1845 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x0C, 0x04);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001846 }
1847 tabla->config_mode_active = enable ? true : false;
1848
1849 return 0;
1850}
1851
1852static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001853 int config_mode)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001854{
1855 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1856
1857 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
1858
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001859 /* transit to RCO requires mclk off */
1860 WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001861 if (config_mode) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001862 /* enable RCO and switch to it */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001863 tabla_codec_enable_config_mode(codec, 1);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001864 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001865 usleep_range(1000, 1000);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001866 } else {
1867 /* switch to MCLK */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001868 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
1869
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001870 if (tabla->mbhc_polling_active) {
1871 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
1872 tabla_codec_enable_config_mode(codec, 0);
1873 }
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001874 }
1875
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001876 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x01, 0x01);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001877 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07001878 /* on MCLK */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001879 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
1880 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
1881 usleep_range(50, 50);
1882 tabla->clock_active = true;
1883 return 0;
1884}
1885
1886static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1887 struct snd_kcontrol *kcontrol, int event)
1888{
1889 struct snd_soc_codec *codec = w->codec;
1890 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
1891
1892 pr_debug("%s: %d\n", __func__, event);
1893
1894 switch (event) {
1895 case SND_SOC_DAPM_PRE_PMU:
1896 tabla_codec_enable_bandgap(codec,
1897 TABLA_BANDGAP_AUDIO_MODE);
1898 tabla_enable_rx_bias(codec, 1);
1899
1900 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1901 0x08, 0x08);
1902 /* Enable Zero Cross detect for AUX PGA channel
1903 * and set the initial AUX PGA gain to NEG_0P0_DB
1904 * to avoid glitches.
1905 */
1906 if (w->reg == TABLA_A_AUX_L_EN) {
1907 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1908 0x20, 0x20);
1909 tabla->aux_l_gain = snd_soc_read(codec,
1910 TABLA_A_AUX_L_GAIN);
1911 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1912 } else {
1913 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1914 0x20, 0x20);
1915 tabla->aux_r_gain = snd_soc_read(codec,
1916 TABLA_A_AUX_R_GAIN);
1917 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1918 }
1919 if (tabla->aux_pga_cnt++ == 1
1920 && !tabla->mclk_enabled) {
1921 tabla_codec_enable_clock_block(codec, 1);
1922 pr_debug("AUX PGA enabled RC osc\n");
1923 }
1924 break;
1925
1926 case SND_SOC_DAPM_POST_PMU:
1927 if (w->reg == TABLA_A_AUX_L_EN)
1928 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1929 tabla->aux_l_gain);
1930 else
1931 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1932 tabla->aux_r_gain);
1933 break;
1934
1935 case SND_SOC_DAPM_PRE_PMD:
1936 /* Mute AUX PGA channel in use before disabling AUX PGA */
1937 if (w->reg == TABLA_A_AUX_L_EN) {
1938 tabla->aux_l_gain = snd_soc_read(codec,
1939 TABLA_A_AUX_L_GAIN);
1940 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
1941 } else {
1942 tabla->aux_r_gain = snd_soc_read(codec,
1943 TABLA_A_AUX_R_GAIN);
1944 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
1945 }
1946 break;
1947
1948 case SND_SOC_DAPM_POST_PMD:
1949 tabla_enable_rx_bias(codec, 0);
1950
1951 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
1952 0x08, 0x00);
1953 if (w->reg == TABLA_A_AUX_L_EN) {
1954 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
1955 tabla->aux_l_gain);
1956 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
1957 0x20, 0x00);
1958 } else {
1959 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
1960 tabla->aux_r_gain);
1961 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
1962 0x20, 0x00);
1963 }
1964
1965 if (tabla->aux_pga_cnt-- == 0) {
1966 if (tabla->mbhc_polling_active)
1967 tabla_codec_enable_bandgap(codec,
1968 TABLA_BANDGAP_MBHC_MODE);
1969 else
1970 tabla_codec_enable_bandgap(codec,
1971 TABLA_BANDGAP_OFF);
1972
1973 if (!tabla->mclk_enabled &&
1974 !tabla->mbhc_polling_active) {
1975 tabla_codec_enable_clock_block(codec, 0);
1976 }
1977 }
1978 break;
1979 }
1980 return 0;
1981}
1982
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001983static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1984 struct snd_kcontrol *kcontrol, int event)
1985{
1986 struct snd_soc_codec *codec = w->codec;
1987 u16 lineout_gain_reg;
1988
Kiran Kandidb0a4b02011-08-23 09:32:09 -07001989 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001990
1991 switch (w->shift) {
1992 case 0:
1993 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
1994 break;
1995 case 1:
1996 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
1997 break;
1998 case 2:
1999 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
2000 break;
2001 case 3:
2002 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
2003 break;
2004 case 4:
2005 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
2006 break;
2007 default:
2008 pr_err("%s: Error, incorrect lineout register value\n",
2009 __func__);
2010 return -EINVAL;
2011 }
2012
2013 switch (event) {
2014 case SND_SOC_DAPM_PRE_PMU:
2015 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
2016 break;
2017 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08002018 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002019 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08002020 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 break;
2022 case SND_SOC_DAPM_POST_PMD:
2023 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
2024 break;
2025 }
2026 return 0;
2027}
2028
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002029
2030static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002031 struct snd_kcontrol *kcontrol, int event)
2032{
2033 struct snd_soc_codec *codec = w->codec;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002034 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2035 u8 dmic_clk_en;
2036 s32 *dmic_clk_cnt;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002037 unsigned int dmic;
2038 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002039
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002040 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
2041 if (ret < 0) {
2042 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002043 return -EINVAL;
2044 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002045
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002046 switch (dmic) {
2047 case 1:
2048 case 2:
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002049 dmic_clk_en = 0x01;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002050 dmic_clk_cnt = &(tabla->dmic_1_2_clk_cnt);
2051
2052 pr_debug("%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
2053 __func__, event, dmic, *dmic_clk_cnt);
2054
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002055 break;
2056
2057 case 3:
2058 case 4:
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002059 dmic_clk_en = 0x04;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002060 dmic_clk_cnt = &(tabla->dmic_3_4_clk_cnt);
2061
2062 pr_debug("%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
2063 __func__, event, dmic, *dmic_clk_cnt);
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002064 break;
2065
2066 case 5:
2067 case 6:
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002068 dmic_clk_en = 0x10;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002069 dmic_clk_cnt = &(tabla->dmic_5_6_clk_cnt);
2070
2071 pr_debug("%s() event %d DMIC%d dmic_5_6_clk_cnt %d\n",
2072 __func__, event, dmic, *dmic_clk_cnt);
2073
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002074 break;
2075
2076 default:
2077 pr_err("%s: Invalid DMIC Selection\n", __func__);
2078 return -EINVAL;
2079 }
2080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002081 switch (event) {
2082 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002083
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002084 (*dmic_clk_cnt)++;
2085 if (*dmic_clk_cnt == 1)
2086 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
2087 dmic_clk_en, dmic_clk_en);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002088
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089 break;
2090 case SND_SOC_DAPM_POST_PMD:
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002091
2092 (*dmic_clk_cnt)--;
2093 if (*dmic_clk_cnt == 0)
2094 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
2095 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096 break;
2097 }
2098 return 0;
2099}
2100
Bradley Rubin229c6a52011-07-12 16:18:48 -07002101static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
2102 struct snd_kcontrol *kcontrol, int event)
2103{
2104 struct snd_soc_codec *codec = w->codec;
2105 const char *filename;
2106 const struct firmware *fw;
2107 int i;
2108 int ret;
Bradley Rubina7096d02011-08-03 18:29:02 -07002109 int num_anc_slots;
2110 struct anc_header *anc_head;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002111 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubina7096d02011-08-03 18:29:02 -07002112 u32 anc_writes_size = 0;
2113 int anc_size_remaining;
2114 u32 *anc_ptr;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002115 u16 reg;
2116 u8 mask, val, old_val;
2117
2118 pr_debug("%s %d\n", __func__, event);
2119 switch (event) {
2120 case SND_SOC_DAPM_PRE_PMU:
2121
Bradley Rubin4283a4c2011-07-29 16:18:54 -07002122 filename = "wcd9310/wcd9310_anc.bin";
Bradley Rubin229c6a52011-07-12 16:18:48 -07002123
2124 ret = request_firmware(&fw, filename, codec->dev);
2125 if (ret != 0) {
2126 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
2127 ret);
2128 return -ENODEV;
2129 }
2130
Bradley Rubina7096d02011-08-03 18:29:02 -07002131 if (fw->size < sizeof(struct anc_header)) {
Bradley Rubin229c6a52011-07-12 16:18:48 -07002132 dev_err(codec->dev, "Not enough data\n");
2133 release_firmware(fw);
2134 return -ENOMEM;
2135 }
2136
2137 /* First number is the number of register writes */
Bradley Rubina7096d02011-08-03 18:29:02 -07002138 anc_head = (struct anc_header *)(fw->data);
2139 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
2140 anc_size_remaining = fw->size - sizeof(struct anc_header);
2141 num_anc_slots = anc_head->num_anc_slots;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002142
Bradley Rubina7096d02011-08-03 18:29:02 -07002143 if (tabla->anc_slot >= num_anc_slots) {
2144 dev_err(codec->dev, "Invalid ANC slot selected\n");
2145 release_firmware(fw);
2146 return -EINVAL;
2147 }
2148
2149 for (i = 0; i < num_anc_slots; i++) {
2150
2151 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
2152 dev_err(codec->dev, "Invalid register format\n");
2153 release_firmware(fw);
2154 return -EINVAL;
2155 }
2156 anc_writes_size = (u32)(*anc_ptr);
2157 anc_size_remaining -= sizeof(u32);
2158 anc_ptr += 1;
2159
2160 if (anc_writes_size * TABLA_PACKED_REG_SIZE
2161 > anc_size_remaining) {
2162 dev_err(codec->dev, "Invalid register format\n");
2163 release_firmware(fw);
2164 return -ENOMEM;
2165 }
2166
2167 if (tabla->anc_slot == i)
2168 break;
2169
2170 anc_size_remaining -= (anc_writes_size *
2171 TABLA_PACKED_REG_SIZE);
Bradley Rubin939ff3f2011-08-26 17:19:34 -07002172 anc_ptr += anc_writes_size;
Bradley Rubina7096d02011-08-03 18:29:02 -07002173 }
2174 if (i == num_anc_slots) {
2175 dev_err(codec->dev, "Selected ANC slot not present\n");
Bradley Rubin229c6a52011-07-12 16:18:48 -07002176 release_firmware(fw);
2177 return -ENOMEM;
2178 }
2179
Bradley Rubina7096d02011-08-03 18:29:02 -07002180 for (i = 0; i < anc_writes_size; i++) {
2181 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
Bradley Rubin229c6a52011-07-12 16:18:48 -07002182 mask, val);
2183 old_val = snd_soc_read(codec, reg);
Bradley Rubin4283a4c2011-07-29 16:18:54 -07002184 snd_soc_write(codec, reg, (old_val & ~mask) |
2185 (val & mask));
Bradley Rubin229c6a52011-07-12 16:18:48 -07002186 }
2187 release_firmware(fw);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002188
2189 break;
2190 case SND_SOC_DAPM_POST_PMD:
2191 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
2192 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
2193 break;
2194 }
2195 return 0;
2196}
2197
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002198/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002199static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
2200{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002201 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07002202 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
2203 int mbhc_state = tabla->mbhc_state;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002204
Joonwoo Park03324832012-03-19 19:36:16 -07002205 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002206 if (!tabla->mbhc_polling_active) {
2207 pr_debug("Polling is not active, do not start polling\n");
2208 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002209 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002210 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Joonwoo Park03324832012-03-19 19:36:16 -07002211
2212 if (!tabla->no_mic_headset_override) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002213 if (mbhc_state == MBHC_STATE_POTENTIAL) {
2214 pr_debug("%s recovering MBHC state macine\n", __func__);
2215 tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
Joonwoo Park03324832012-03-19 19:36:16 -07002216 /* set to max button press threshold */
2217 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2218 0x7F);
2219 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2220 0xFF);
2221 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2222 (TABLA_IS_1_X(tabla_core->version) ?
2223 0x07 : 0x7F));
2224 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
2225 0xFF);
2226 /* set to max */
2227 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
2228 0x7F);
2229 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
2230 0xFF);
2231 }
2232 }
2233
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002234 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
2235 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2236 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
Joonwoo Park03324832012-03-19 19:36:16 -07002237 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002238}
2239
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002240/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002241static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
2242{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002243 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2244
Joonwoo Park03324832012-03-19 19:36:16 -07002245 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002246 if (!tabla->mbhc_polling_active) {
2247 pr_debug("polling not active, nothing to pause\n");
2248 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002249 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002250
2251 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Joonwoo Park03324832012-03-19 19:36:16 -07002252 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002253}
2254
Joonwoo Park03324832012-03-19 19:36:16 -07002255static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002256{
2257 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2258 u8 reg_mode_val, cur_mode_val;
2259 bool mbhc_was_polling = false;
2260
2261 if (mode)
2262 reg_mode_val = TABLA_CFILT_FAST_MODE;
2263 else
2264 reg_mode_val = TABLA_CFILT_SLOW_MODE;
2265
2266 cur_mode_val = snd_soc_read(codec,
2267 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
2268
2269 if (cur_mode_val != reg_mode_val) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002270 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002271 if (tabla->mbhc_polling_active) {
2272 tabla_codec_pause_hs_polling(codec);
2273 mbhc_was_polling = true;
2274 }
2275 snd_soc_update_bits(codec,
2276 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
2277 if (mbhc_was_polling)
2278 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002279 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002280 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
2281 cur_mode_val, reg_mode_val);
2282 } else {
2283 pr_debug("%s: CFILT Value is already %x\n",
2284 __func__, cur_mode_val);
2285 }
2286}
2287
2288static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
2289 u8 cfilt_sel, int inc)
2290{
2291 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2292 u32 *cfilt_cnt_ptr = NULL;
2293 u16 micb_cfilt_reg;
2294
2295 switch (cfilt_sel) {
2296 case TABLA_CFILT1_SEL:
2297 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2298 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2299 break;
2300 case TABLA_CFILT2_SEL:
2301 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2302 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2303 break;
2304 case TABLA_CFILT3_SEL:
2305 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2306 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2307 break;
2308 default:
2309 return; /* should not happen */
2310 }
2311
2312 if (inc) {
2313 if (!(*cfilt_cnt_ptr)++) {
2314 /* Switch CFILT to slow mode if MBHC CFILT being used */
2315 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2316 tabla_codec_switch_cfilt_mode(codec, 0);
2317
2318 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2319 }
2320 } else {
2321 /* check if count not zero, decrement
2322 * then check if zero, go ahead disable cfilter
2323 */
2324 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2325 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2326
2327 /* Switch CFILT to fast mode if MBHC CFILT being used */
2328 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2329 tabla_codec_switch_cfilt_mode(codec, 1);
2330 }
2331 }
2332}
2333
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002334static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2335{
2336 int rc = -EINVAL;
2337 unsigned min_mv, max_mv;
2338
2339 switch (ldoh_v) {
2340 case TABLA_LDOH_1P95_V:
2341 min_mv = 160;
2342 max_mv = 1800;
2343 break;
2344 case TABLA_LDOH_2P35_V:
2345 min_mv = 200;
2346 max_mv = 2200;
2347 break;
2348 case TABLA_LDOH_2P75_V:
2349 min_mv = 240;
2350 max_mv = 2600;
2351 break;
2352 case TABLA_LDOH_2P85_V:
2353 min_mv = 250;
2354 max_mv = 2700;
2355 break;
2356 default:
2357 goto done;
2358 }
2359
2360 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2361 goto done;
2362
2363 for (rc = 4; rc <= 44; rc++) {
2364 min_mv = max_mv * (rc) / 44;
2365 if (min_mv >= cfilt_mv) {
2366 rc -= 4;
2367 break;
2368 }
2369 }
2370done:
2371 return rc;
2372}
2373
2374static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2375{
2376 u8 hph_reg_val = 0;
2377 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2378
2379 return (hph_reg_val & 0x30) ? true : false;
2380}
2381
Joonwoo Parka9444452011-12-08 18:48:27 -08002382static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2383{
2384 u8 hph_reg_val = 0;
2385 if (left)
2386 hph_reg_val = snd_soc_read(codec,
2387 TABLA_A_RX_HPH_L_DAC_CTL);
2388 else
2389 hph_reg_val = snd_soc_read(codec,
2390 TABLA_A_RX_HPH_R_DAC_CTL);
2391
2392 return (hph_reg_val & 0xC0) ? true : false;
2393}
2394
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002395static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
2396{
2397 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
2398}
2399
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002400/* called under codec_resource_lock acquisition */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002401static void tabla_codec_drive_v_to_micbias(struct snd_soc_codec *codec,
2402 int usec)
2403{
2404 int cfilt_k_val;
2405 bool set = true;
2406 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2407
2408 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2409 tabla->mbhc_micbias_switched) {
2410 pr_debug("%s: set mic V to micbias V\n", __func__);
2411 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2412 tabla_turn_onoff_override(codec, true);
2413 while (1) {
2414 cfilt_k_val = tabla_find_k_value(
2415 tabla->pdata->micbias.ldoh_v,
2416 set ? tabla->mbhc_data.micb_mv :
2417 VDDIO_MICBIAS_MV);
2418 snd_soc_update_bits(codec,
2419 tabla->mbhc_bias_regs.cfilt_val,
2420 0xFC, (cfilt_k_val << 2));
2421 if (!set)
2422 break;
2423 usleep_range(usec, usec);
2424 set = false;
2425 }
2426 tabla_turn_onoff_override(codec, false);
2427 }
2428}
2429
2430/* called under codec_resource_lock acquisition */
2431static void __tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2432 int vddio_switch, bool restartpolling,
2433 bool checkpolling)
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002434{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002435 int cfilt_k_val;
Joonwoo Park41956722012-04-18 13:13:07 -07002436 bool override;
2437 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002438
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002439 if (vddio_switch && !tabla->mbhc_micbias_switched &&
2440 (!checkpolling || tabla->mbhc_polling_active)) {
2441 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002442 tabla_codec_pause_hs_polling(codec);
Joonwoo Park41956722012-04-18 13:13:07 -07002443 override = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04;
2444 if (!override)
2445 tabla_turn_onoff_override(codec, true);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002446 /* Adjust threshold if Mic Bias voltage changes */
2447 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002448 cfilt_k_val = tabla_find_k_value(
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002449 tabla->pdata->micbias.ldoh_v,
2450 VDDIO_MICBIAS_MV);
2451 usleep_range(10000, 10000);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002452 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002453 tabla->mbhc_bias_regs.cfilt_val,
2454 0xFC, (cfilt_k_val << 2));
2455 usleep_range(10000, 10000);
2456 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2457 tabla->mbhc_data.adj_v_ins_hu & 0xFF);
2458 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2459 (tabla->mbhc_data.adj_v_ins_hu >> 8) &
2460 0xFF);
2461 pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
2462 __func__);
2463 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002464
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002465 /* enable MIC BIAS Switch to VDDIO */
2466 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2467 0x80, 0x80);
2468 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2469 0x10, 0x00);
Joonwoo Park41956722012-04-18 13:13:07 -07002470 if (!override)
2471 tabla_turn_onoff_override(codec, false);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002472 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002473 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002474
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002475 tabla->mbhc_micbias_switched = true;
2476 pr_debug("%s: VDDIO switch enabled\n", __func__);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002477 } else if (!vddio_switch && tabla->mbhc_micbias_switched) {
2478 if ((!checkpolling || tabla->mbhc_polling_active) &&
2479 restartpolling)
2480 tabla_codec_pause_hs_polling(codec);
2481 /* Reprogram thresholds */
2482 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
2483 cfilt_k_val = tabla_find_k_value(
2484 tabla->pdata->micbias.ldoh_v,
2485 tabla->mbhc_data.micb_mv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002486 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002487 tabla->mbhc_bias_regs.cfilt_val,
2488 0xFC, (cfilt_k_val << 2));
2489 usleep_range(10000, 10000);
2490 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2491 tabla->mbhc_data.v_ins_hu & 0xFF);
2492 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2493 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
2494 pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
2495 __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002496 }
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002497
2498 /* Disable MIC BIAS Switch to VDDIO */
2499 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2500 0x80, 0x00);
2501 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2502 0x10, 0x00);
2503
2504 if ((!checkpolling || tabla->mbhc_polling_active) &&
2505 restartpolling)
2506 tabla_codec_start_hs_polling(codec);
2507
2508 tabla->mbhc_micbias_switched = false;
2509 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002510 }
2511}
2512
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002513static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2514 int vddio_switch)
2515{
2516 return __tabla_codec_switch_micbias(codec, vddio_switch, true, true);
2517}
2518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002519static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2520 struct snd_kcontrol *kcontrol, int event)
2521{
2522 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002523 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2524 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002525 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002526 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002527 char *internal1_text = "Internal1";
2528 char *internal2_text = "Internal2";
2529 char *internal3_text = "Internal3";
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002530
2531 pr_debug("%s %d\n", __func__, event);
2532 switch (w->reg) {
2533 case TABLA_A_MICB_1_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002534 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002535 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002536 micb_line = TABLA_MICBIAS1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002537 break;
2538 case TABLA_A_MICB_2_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002539 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002540 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002541 micb_line = TABLA_MICBIAS2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002542 break;
2543 case TABLA_A_MICB_3_CTL:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002544 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002545 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002546 micb_line = TABLA_MICBIAS3;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002547 break;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002548 case TABLA_1_A_MICB_4_CTL:
2549 case TABLA_2_A_MICB_4_CTL:
2550 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002551 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002552 micb_line = TABLA_MICBIAS4;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002553 break;
2554 default:
2555 pr_err("%s: Error, invalid micbias register\n", __func__);
2556 return -EINVAL;
2557 }
2558
2559 switch (event) {
2560 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002561 /* Decide whether to switch the micbias for MBHC */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002562 if (w->reg == tabla->mbhc_bias_regs.ctl_reg) {
2563 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002564 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002565 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2566 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002567
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002568 snd_soc_update_bits(codec, w->reg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002569 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002570
2571 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002572 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002573 else if (strnstr(w->name, internal2_text, 30))
2574 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2575 else if (strnstr(w->name, internal3_text, 30))
2576 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2577
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002578 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002579 case SND_SOC_DAPM_POST_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002580
2581 usleep_range(20000, 20000);
2582
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002583 if (tabla->mbhc_polling_active &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002584 tabla->mbhc_cfg.micbias == micb_line) {
2585 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002586 tabla_codec_pause_hs_polling(codec);
2587 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002588 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002589 }
2590 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002591
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002592 case SND_SOC_DAPM_POST_PMD:
Joonwoo Park03324832012-03-19 19:36:16 -07002593 if ((w->reg == tabla->mbhc_bias_regs.ctl_reg) &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002594 tabla_is_hph_pa_on(codec)) {
2595 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002596 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002597 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2598 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002599
Bradley Rubin229c6a52011-07-12 16:18:48 -07002600 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002601 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002602 else if (strnstr(w->name, internal2_text, 30))
2603 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2604 else if (strnstr(w->name, internal3_text, 30))
2605 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2606
Patrick Lai3043fba2011-08-01 14:15:57 -07002607 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002608 break;
2609 }
2610
2611 return 0;
2612}
2613
Kiran Kandid8cf5212012-03-02 15:34:53 -08002614
2615static void tx_hpf_corner_freq_callback(struct work_struct *work)
2616{
2617 struct delayed_work *hpf_delayed_work;
2618 struct hpf_work *hpf_work;
2619 struct tabla_priv *tabla;
2620 struct snd_soc_codec *codec;
2621 u16 tx_mux_ctl_reg;
2622 u8 hpf_cut_of_freq;
2623
2624 hpf_delayed_work = to_delayed_work(work);
2625 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2626 tabla = hpf_work->tabla;
2627 codec = hpf_work->tabla->codec;
2628 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2629
2630 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL +
2631 (hpf_work->decimator - 1) * 8;
2632
2633 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
2634 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2635
2636 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
2637}
2638
2639#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
2640#define CF_MIN_3DB_4HZ 0x0
2641#define CF_MIN_3DB_75HZ 0x1
2642#define CF_MIN_3DB_150HZ 0x2
2643
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002644static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
2645 struct snd_kcontrol *kcontrol, int event)
2646{
2647 struct snd_soc_codec *codec = w->codec;
Kiran Kandid8cf5212012-03-02 15:34:53 -08002648 unsigned int decimator;
2649 char *dec_name = NULL;
2650 char *widget_name = NULL;
2651 char *temp;
2652 int ret = 0;
2653 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2654 u8 dec_hpf_cut_of_freq;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002655 int offset;
2656
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002657
2658 pr_debug("%s %d\n", __func__, event);
2659
Kiran Kandid8cf5212012-03-02 15:34:53 -08002660 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2661 if (!widget_name)
2662 return -ENOMEM;
2663 temp = widget_name;
2664
2665 dec_name = strsep(&widget_name, " ");
2666 widget_name = temp;
2667 if (!dec_name) {
2668 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2669 ret = -EINVAL;
2670 goto out;
2671 }
2672
2673 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
2674 if (ret < 0) {
2675 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2676 ret = -EINVAL;
2677 goto out;
2678 }
2679
2680 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
2681 w->name, dec_name, decimator);
2682
Kuirong Wange9c8a222012-03-28 16:24:09 -07002683 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002684 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002685 offset = 0;
2686 } else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002687 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002688 offset = 8;
2689 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002690 pr_err("%s: Error, incorrect dec\n", __func__);
2691 return -EINVAL;
2692 }
2693
Kiran Kandid8cf5212012-03-02 15:34:53 -08002694 tx_vol_ctl_reg = TABLA_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator -1);
2695 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2696
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002697 switch (event) {
2698 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08002699
2700 // Enableable TX digital mute */
2701 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2702
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002703 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2704 1 << w->shift);
2705 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Kiran Kandid8cf5212012-03-02 15:34:53 -08002706
2707 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2708
2709 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
2710
2711 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2712 dec_hpf_cut_of_freq;
2713
2714 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2715
2716 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
2717 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2718 CF_MIN_3DB_150HZ << 4);
2719 }
2720
2721 /* enable HPF */
2722 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
2723
2724 break;
2725
2726 case SND_SOC_DAPM_POST_PMU:
2727
2728 /* Disable TX digital mute */
2729 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2730
2731 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2732 CF_MIN_3DB_150HZ) {
2733
2734 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2735 msecs_to_jiffies(300));
2736 }
Kuirong Wange9c8a222012-03-28 16:24:09 -07002737 /* apply the digital gain after the decimator is enabled*/
2738 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2739 snd_soc_write(codec,
2740 tx_digital_gain_reg[w->shift + offset],
2741 snd_soc_read(codec,
2742 tx_digital_gain_reg[w->shift + offset])
2743 );
2744
Kiran Kandid8cf5212012-03-02 15:34:53 -08002745 break;
2746
2747 case SND_SOC_DAPM_PRE_PMD:
2748
2749 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2750 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2751 break;
2752
2753 case SND_SOC_DAPM_POST_PMD:
2754
2755 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2756 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2757 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2758
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002759 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002760 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08002761out:
2762 kfree(widget_name);
2763 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002764}
2765
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002766static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002767 struct snd_kcontrol *kcontrol, int event)
2768{
2769 struct snd_soc_codec *codec = w->codec;
2770
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002771 pr_debug("%s %d %s\n", __func__, event, w->name);
2772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002773 switch (event) {
2774 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07002775 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2776 1 << w->shift, 1 << w->shift);
2777 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
2778 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002779 break;
Kuirong Wange9c8a222012-03-28 16:24:09 -07002780 case SND_SOC_DAPM_POST_PMU:
2781 /* apply the digital gain after the interpolator is enabled*/
2782 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2783 snd_soc_write(codec,
2784 rx_digital_gain_reg[w->shift],
2785 snd_soc_read(codec,
2786 rx_digital_gain_reg[w->shift])
2787 );
2788 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002789 }
2790 return 0;
2791}
2792
Bradley Rubin229c6a52011-07-12 16:18:48 -07002793static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2794 struct snd_kcontrol *kcontrol, int event)
2795{
2796 switch (event) {
2797 case SND_SOC_DAPM_POST_PMU:
2798 case SND_SOC_DAPM_POST_PMD:
2799 usleep_range(1000, 1000);
2800 break;
2801 }
2802 return 0;
2803}
2804
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002805static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2806 struct snd_kcontrol *kcontrol, int event)
2807{
2808 struct snd_soc_codec *codec = w->codec;
2809
2810 pr_debug("%s %d\n", __func__, event);
2811
2812 switch (event) {
2813 case SND_SOC_DAPM_PRE_PMU:
2814 tabla_enable_rx_bias(codec, 1);
2815 break;
2816 case SND_SOC_DAPM_POST_PMD:
2817 tabla_enable_rx_bias(codec, 0);
2818 break;
2819 }
2820 return 0;
2821}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07002822static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
2823 struct snd_kcontrol *kcontrol, int event)
2824{
2825 struct snd_soc_codec *codec = w->codec;
2826
2827 pr_debug("%s %s %d\n", __func__, w->name, event);
2828
2829 switch (event) {
2830 case SND_SOC_DAPM_PRE_PMU:
2831 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2832 break;
2833 case SND_SOC_DAPM_POST_PMD:
2834 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2835 break;
2836 }
2837 return 0;
2838}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07002839
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002840static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
2841 struct snd_soc_jack *jack, int status,
2842 int mask)
2843{
2844 /* XXX: wake_lock_timeout()? */
Joonwoo Park03324832012-03-19 19:36:16 -07002845 snd_soc_jack_report_no_dapm(jack, status, mask);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002846}
2847
Patrick Lai49efeac2011-11-03 11:01:12 -07002848static void hphocp_off_report(struct tabla_priv *tabla,
2849 u32 jack_status, int irq)
2850{
2851 struct snd_soc_codec *codec;
Joonwoo Park03324832012-03-19 19:36:16 -07002852 if (!tabla) {
2853 pr_err("%s: Bad tabla private data\n", __func__);
2854 return;
2855 }
Patrick Lai49efeac2011-11-03 11:01:12 -07002856
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002857 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
Joonwoo Park03324832012-03-19 19:36:16 -07002858 codec = tabla->codec;
2859 if (tabla->hph_status & jack_status) {
Patrick Lai49efeac2011-11-03 11:01:12 -07002860 tabla->hph_status &= ~jack_status;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002861 if (tabla->mbhc_cfg.headset_jack)
2862 tabla_snd_soc_jack_report(tabla,
2863 tabla->mbhc_cfg.headset_jack,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08002864 tabla->hph_status,
2865 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08002866 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
2867 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08002868 /* reset retry counter as PA is turned off signifying
2869 * start of new OCP detection session
2870 */
2871 if (TABLA_IRQ_HPH_PA_OCPL_FAULT)
2872 tabla->hphlocp_cnt = 0;
2873 else
2874 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05302875 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07002876 }
2877}
2878
2879static void hphlocp_off_report(struct work_struct *work)
2880{
2881 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2882 hphlocp_work);
2883 hphocp_off_report(tabla, SND_JACK_OC_HPHL, TABLA_IRQ_HPH_PA_OCPL_FAULT);
2884}
2885
2886static void hphrocp_off_report(struct work_struct *work)
2887{
2888 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
2889 hphrocp_work);
2890 hphocp_off_report(tabla, SND_JACK_OC_HPHR, TABLA_IRQ_HPH_PA_OCPR_FAULT);
2891}
2892
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002893static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
2894 struct snd_kcontrol *kcontrol, int event)
2895{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002896 struct snd_soc_codec *codec = w->codec;
2897 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2898 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002899 pr_debug("%s: event = %d\n", __func__, event);
2900
2901 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002902 case SND_SOC_DAPM_PRE_PMU:
2903 mbhc_micb_ctl_val = snd_soc_read(codec,
2904 tabla->mbhc_bias_regs.ctl_reg);
2905
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002906 if (!(mbhc_micb_ctl_val & 0x80)) {
2907 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002908 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002909 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2910 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002911 break;
2912
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002913 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07002914 /* schedule work is required because at the time HPH PA DAPM
2915 * event callback is called by DAPM framework, CODEC dapm mutex
2916 * would have been locked while snd_soc_jack_report also
2917 * attempts to acquire same lock.
2918 */
Joonwoo Parka9444452011-12-08 18:48:27 -08002919 if (w->shift == 5) {
2920 clear_bit(TABLA_HPHL_PA_OFF_ACK,
2921 &tabla->hph_pa_dac_state);
2922 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
2923 &tabla->hph_pa_dac_state);
2924 if (tabla->hph_status & SND_JACK_OC_HPHL)
2925 schedule_work(&tabla->hphlocp_work);
2926 } else if (w->shift == 4) {
2927 clear_bit(TABLA_HPHR_PA_OFF_ACK,
2928 &tabla->hph_pa_dac_state);
2929 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
2930 &tabla->hph_pa_dac_state);
2931 if (tabla->hph_status & SND_JACK_OC_HPHR)
2932 schedule_work(&tabla->hphrocp_work);
2933 }
2934
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002935 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park03324832012-03-19 19:36:16 -07002936 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002937 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002938
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002939 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
2940 w->name);
2941 usleep_range(10000, 10000);
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07002942 break;
2943 }
2944 return 0;
2945}
2946
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002947static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002948 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002949{
2950 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002951 unsigned int cfilt;
2952
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002953 switch (tabla->mbhc_cfg.micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002954 case TABLA_MICBIAS1:
2955 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
2956 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
2957 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
2958 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
2959 break;
2960 case TABLA_MICBIAS2:
2961 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
2962 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
2963 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
2964 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
2965 break;
2966 case TABLA_MICBIAS3:
2967 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
2968 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
2969 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
2970 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
2971 break;
2972 case TABLA_MICBIAS4:
2973 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002974 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
2975 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
2976 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002977 break;
2978 default:
2979 /* Should never reach here */
2980 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07002981 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002982 }
2983
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002984 micbias_regs->cfilt_sel = cfilt;
2985
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002986 switch (cfilt) {
2987 case TABLA_CFILT1_SEL:
2988 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
2989 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002990 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002991 break;
2992 case TABLA_CFILT2_SEL:
2993 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
2994 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08002995 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07002996 break;
2997 case TABLA_CFILT3_SEL:
2998 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
2999 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08003000 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003001 break;
3002 }
3003}
Santosh Mardie15e2302011-11-15 10:39:23 +05303004static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
3005 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
3006 4, 0, NULL, 0),
3007 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
3008 0, NULL, 0),
3009};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003010
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003011static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
3012 struct snd_kcontrol *kcontrol, int event)
3013{
3014 struct snd_soc_codec *codec = w->codec;
3015
3016 pr_debug("%s %s %d\n", __func__, w->name, event);
3017
3018 switch (event) {
3019 case SND_SOC_DAPM_PRE_PMU:
3020 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
3021 break;
3022
3023 case SND_SOC_DAPM_POST_PMD:
3024 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
3025 break;
3026 }
3027 return 0;
3028}
3029
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003030static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
3031 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_1_A_MICB_4_CTL, 7,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303032 0, tabla_codec_enable_micbias,
3033 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3034 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003035};
3036
3037static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
3038 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", TABLA_2_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
Santosh Mardie15e2302011-11-15 10:39:23 +05303044static const struct snd_soc_dapm_route audio_i2s_map[] = {
3045 {"RX_I2S_CLK", NULL, "CDC_CONN"},
3046 {"SLIM RX1", NULL, "RX_I2S_CLK"},
3047 {"SLIM RX2", NULL, "RX_I2S_CLK"},
3048 {"SLIM RX3", NULL, "RX_I2S_CLK"},
3049 {"SLIM RX4", NULL, "RX_I2S_CLK"},
3050
3051 {"SLIM TX7", NULL, "TX_I2S_CLK"},
3052 {"SLIM TX8", NULL, "TX_I2S_CLK"},
3053 {"SLIM TX9", NULL, "TX_I2S_CLK"},
3054 {"SLIM TX10", NULL, "TX_I2S_CLK"},
3055};
3056
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003057static const struct snd_soc_dapm_route audio_map[] = {
3058 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003059
3060 {"SLIM TX1", NULL, "SLIM TX1 MUX"},
3061 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
3062
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003063 {"SLIM TX2", NULL, "SLIM TX2 MUX"},
3064 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
3065
3066 {"SLIM TX3", NULL, "SLIM TX3 MUX"},
3067 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Neema Shetty3fb1b802012-04-27 13:53:24 -07003068 {"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
3069 {"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
3070 {"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
3071 {"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
3072 {"SLIM TX3 MUX", "RMIX5", "RX5 MIX1"},
3073 {"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
3074 {"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003075
3076 {"SLIM TX4", NULL, "SLIM TX4 MUX"},
3077 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
3078
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003079 {"SLIM TX5", NULL, "SLIM TX5 MUX"},
3080 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
Neema Shetty3fb1b802012-04-27 13:53:24 -07003081 {"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
3082 {"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
3083 {"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
3084 {"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
3085 {"SLIM TX5 MUX", "RMIX5", "RX5 MIX1"},
3086 {"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
3087 {"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088
3089 {"SLIM TX6", NULL, "SLIM TX6 MUX"},
3090 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
3091
3092 {"SLIM TX7", NULL, "SLIM TX7 MUX"},
3093 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07003094 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003095 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
3096 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003097 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
3098 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07003099 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
3100 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003101 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
3102 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Neema Shetty3fb1b802012-04-27 13:53:24 -07003103 {"SLIM TX7 MUX", "RMIX1", "RX1 MIX1"},
3104 {"SLIM TX7 MUX", "RMIX2", "RX2 MIX1"},
3105 {"SLIM TX7 MUX", "RMIX3", "RX3 MIX1"},
3106 {"SLIM TX7 MUX", "RMIX4", "RX4 MIX1"},
3107 {"SLIM TX7 MUX", "RMIX5", "RX5 MIX1"},
3108 {"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
3109 {"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003110
3111 {"SLIM TX8", NULL, "SLIM TX8 MUX"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003112 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
3113 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
3114 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07003115 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003116 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
3117 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003118 {"SLIM TX8 MUX", "DEC7", "DEC7 MUX"},
3119 {"SLIM TX8 MUX", "DEC8", "DEC8 MUX"},
3120 {"SLIM TX8 MUX", "DEC9", "DEC9 MUX"},
3121 {"SLIM TX8 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003122
Kiran Kandi3426e512011-09-13 22:50:10 -07003123 {"SLIM TX9", NULL, "SLIM TX9 MUX"},
3124 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
3125 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
3126 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
3127 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
3128 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
3129 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
3130 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
3131 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
3132 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
3133 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
3134
3135 {"SLIM TX10", NULL, "SLIM TX10 MUX"},
3136 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
3137 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
3138 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
3139 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
3140 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
3141 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
3142 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
3143 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
3144 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
3145 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
3146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003147 /* Earpiece (RX MIX1) */
3148 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003149 {"EAR PA", NULL, "EAR_PA_MIXER"},
3150 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003151 {"DAC1", NULL, "CP"},
3152
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003153 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
3154 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003155 {"ANC", NULL, "ANC1 FB MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003156
3157 /* Headset (RX MIX1 and RX MIX2) */
3158 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003159 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003160
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003161 {"HPHL", NULL, "HPHL_PA_MIXER"},
3162 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
3163
3164 {"HPHR", NULL, "HPHR_PA_MIXER"},
3165 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003166
3167 {"HPHL DAC", NULL, "CP"},
3168 {"HPHR DAC", NULL, "CP"},
3169
3170 {"ANC", NULL, "ANC1 MUX"},
3171 {"ANC", NULL, "ANC2 MUX"},
3172 {"ANC1 MUX", "ADC1", "ADC1"},
3173 {"ANC1 MUX", "ADC2", "ADC2"},
3174 {"ANC1 MUX", "ADC3", "ADC3"},
3175 {"ANC1 MUX", "ADC4", "ADC4"},
3176 {"ANC2 MUX", "ADC1", "ADC1"},
3177 {"ANC2 MUX", "ADC2", "ADC2"},
3178 {"ANC2 MUX", "ADC3", "ADC3"},
3179 {"ANC2 MUX", "ADC4", "ADC4"},
3180
Bradley Rubine1d08622011-07-20 18:01:35 -07003181 {"ANC", NULL, "CDC_CONN"},
3182
Bradley Rubin229c6a52011-07-12 16:18:48 -07003183 {"DAC1", "Switch", "RX1 CHAIN"},
3184 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003185 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003186
Kiran Kandidb0a4b02011-08-23 09:32:09 -07003187 {"LINEOUT1", NULL, "LINEOUT1 PA"},
3188 {"LINEOUT2", NULL, "LINEOUT2 PA"},
3189 {"LINEOUT3", NULL, "LINEOUT3 PA"},
3190 {"LINEOUT4", NULL, "LINEOUT4 PA"},
3191 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003192
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003193 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
3194 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
3195 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
3196 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
3197 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
3198 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
3199 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
3200 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
3201 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
3202 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003203
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003204 {"LINEOUT1 DAC", NULL, "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003205 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
3206
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003207 {"RX1 CHAIN", NULL, "RX1 MIX2"},
3208 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003209 {"RX1 CHAIN", NULL, "ANC"},
3210 {"RX2 CHAIN", NULL, "ANC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003211
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003212 {"CP", NULL, "RX_BIAS"},
3213 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
3214 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
3215 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
3216 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003217 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003218
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003219 {"RX1 MIX1", NULL, "COMP1_CLK"},
3220 {"RX2 MIX1", NULL, "COMP1_CLK"},
3221 {"RX3 MIX1", NULL, "COMP2_CLK"},
3222 {"RX5 MIX1", NULL, "COMP2_CLK"},
3223
3224
Bradley Rubin229c6a52011-07-12 16:18:48 -07003225 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
3226 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
3227 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
3228 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003229 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
3230 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
3231 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
3232 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
3233 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
3234 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
3235 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
3236 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003237 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
3238 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003239 {"RX1 MIX2", NULL, "RX1 MIX1"},
3240 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
3241 {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
3242 {"RX2 MIX2", NULL, "RX2 MIX1"},
3243 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
3244 {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
3245 {"RX3 MIX2", NULL, "RX3 MIX1"},
3246 {"RX3 MIX2", NULL, "RX3 MIX2 INP1"},
3247 {"RX3 MIX2", NULL, "RX3 MIX2 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003248
Bradley Rubin229c6a52011-07-12 16:18:48 -07003249 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
3250 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303251 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
3252 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003253 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
3254 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003255 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
3256 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
3257 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303258 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
3259 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003260 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
3261 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003262 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
3263 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
3264 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303265 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
3266 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003267 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
3268 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003269 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003270 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
3271 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303272 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
3273 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003274 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
3275 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003276 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003277 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
3278 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303279 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
3280 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003281 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
3282 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003283 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003284 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
3285 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303286 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
3287 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003288 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
3289 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003290 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003291 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
3292 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303293 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
3294 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003295 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
3296 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003297 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003298 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
3299 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303300 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
3301 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003302 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
3303 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003304 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003305 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
3306 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303307 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
3308 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003309 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
3310 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003311 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003312 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
3313 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303314 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
3315 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003316 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
3317 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003318 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003319 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
3320 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303321 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
3322 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003323 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
3324 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003325 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003326 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
3327 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303328 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
3329 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003330 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
3331 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003332 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003333 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
3334 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303335 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
3336 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003337 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
3338 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003339 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003340 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
3341 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303342 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
3343 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003344 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
3345 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003346 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003347 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
3348 {"RX1 MIX2 INP2", "IIR1", "IIR1"},
3349 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
3350 {"RX2 MIX2 INP2", "IIR1", "IIR1"},
3351 {"RX3 MIX2 INP1", "IIR1", "IIR1"},
3352 {"RX3 MIX2 INP2", "IIR1", "IIR1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003353
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003354 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003355 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003356 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003357 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003358 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003359 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003360 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003361 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003362 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003363 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003364 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003365 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003366 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003367 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003368 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003369 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07003370 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003371 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003372 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003373 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003374 {"DEC7 MUX", "DMIC6", "DMIC6"},
3375 {"DEC7 MUX", "ADC1", "ADC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003376 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003377 {"DEC7 MUX", NULL, "CDC_CONN"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003378 {"DEC8 MUX", "DMIC2", "DMIC2"},
3379 {"DEC8 MUX", "DMIC5", "DMIC5"},
3380 {"DEC8 MUX", "ADC2", "ADC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003381 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003382 {"DEC8 MUX", NULL, "CDC_CONN"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003383 {"DEC9 MUX", "DMIC4", "DMIC4"},
3384 {"DEC9 MUX", "DMIC5", "DMIC5"},
3385 {"DEC9 MUX", "ADC2", "ADC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003386 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003387 {"DEC9 MUX", NULL, "CDC_CONN"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003388 {"DEC10 MUX", "DMIC3", "DMIC3"},
3389 {"DEC10 MUX", "DMIC6", "DMIC6"},
3390 {"DEC10 MUX", "ADC1", "ADC1"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003391 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07003392 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003393
3394 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003395 {"ADC1", NULL, "AMIC1"},
3396 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003397 {"ADC3", NULL, "AMIC3"},
3398 {"ADC4", NULL, "AMIC4"},
3399 {"ADC5", NULL, "AMIC5"},
3400 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003401
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003402 /* AUX PGA Connections */
3403 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3404 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3405 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3406 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3407 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3408 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3409 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3410 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3411 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3412 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3413 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3414 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3415 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3416 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3417 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3418 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3419 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3420 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3421 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3422 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3423 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3424 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3425 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3426 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3427 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3428 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3429 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3430 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3431 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
3432 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
3433 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
3434 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
3435 {"AUX_PGA_Left", NULL, "AMIC5"},
3436 {"AUX_PGA_Right", NULL, "AMIC6"},
3437
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003438 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003439 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
3440 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
3441 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
3442 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
3443 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003444 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07003445 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
3446 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
3447 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
3448 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003449
3450 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
3451 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
3452 {"MIC BIAS1 External", NULL, "LDO_H"},
3453 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
3454 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
3455 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
3456 {"MIC BIAS2 External", NULL, "LDO_H"},
3457 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
3458 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
3459 {"MIC BIAS3 External", NULL, "LDO_H"},
3460 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003461};
3462
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003463static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
3464
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003465 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003466 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3467
3468 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
3469
3470 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003471 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003472 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
3473
3474 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3475 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3476
3477 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3478 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
3479 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
3480};
3481
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003482
3483static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
3484
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003485 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX2"},
Kiran Kandi7a9fd902011-11-14 13:51:45 -08003486 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
3487
3488 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
3489
3490 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
3491
3492 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
3493 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
3494
3495 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
3496};
3497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003498static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
3499{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003500 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303501 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003502
3503 if (TABLA_IS_1_X(tabla_core->version)) {
3504 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
3505 if (tabla_1_reg_readable[i] == reg)
3506 return 1;
3507 }
3508 } else {
3509 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
3510 if (tabla_2_reg_readable[i] == reg)
3511 return 1;
3512 }
3513 }
3514
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003515 return tabla_reg_readable[reg];
3516}
Kuirong Wange9c8a222012-03-28 16:24:09 -07003517static bool tabla_is_digital_gain_register(unsigned int reg)
3518{
3519 bool rtn = false;
3520 switch (reg) {
3521 case TABLA_A_CDC_RX1_VOL_CTL_B2_CTL:
3522 case TABLA_A_CDC_RX2_VOL_CTL_B2_CTL:
3523 case TABLA_A_CDC_RX3_VOL_CTL_B2_CTL:
3524 case TABLA_A_CDC_RX4_VOL_CTL_B2_CTL:
3525 case TABLA_A_CDC_RX5_VOL_CTL_B2_CTL:
3526 case TABLA_A_CDC_RX6_VOL_CTL_B2_CTL:
3527 case TABLA_A_CDC_RX7_VOL_CTL_B2_CTL:
3528 case TABLA_A_CDC_TX1_VOL_CTL_GAIN:
3529 case TABLA_A_CDC_TX2_VOL_CTL_GAIN:
3530 case TABLA_A_CDC_TX3_VOL_CTL_GAIN:
3531 case TABLA_A_CDC_TX4_VOL_CTL_GAIN:
3532 case TABLA_A_CDC_TX5_VOL_CTL_GAIN:
3533 case TABLA_A_CDC_TX6_VOL_CTL_GAIN:
3534 case TABLA_A_CDC_TX7_VOL_CTL_GAIN:
3535 case TABLA_A_CDC_TX8_VOL_CTL_GAIN:
3536 case TABLA_A_CDC_TX9_VOL_CTL_GAIN:
3537 case TABLA_A_CDC_TX10_VOL_CTL_GAIN:
3538 rtn = true;
3539 break;
3540 default:
3541 break;
3542 }
3543 return rtn;
3544}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003545static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
3546{
3547 /* Registers lower than 0x100 are top level registers which can be
3548 * written by the Tabla core driver.
3549 */
3550
3551 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
3552 return 1;
3553
Ben Romberger1f045a72011-11-04 10:14:57 -07003554 /* IIR Coeff registers are not cacheable */
3555 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
3556 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
3557 return 1;
3558
Kuirong Wange9c8a222012-03-28 16:24:09 -07003559 /* Digital gain register is not cacheable so we have to write
3560 * the setting even it is the same
3561 */
3562 if (tabla_is_digital_gain_register(reg))
3563 return 1;
3564
Joonwoo Parkab2c5872012-05-03 15:16:02 -07003565 /* HPH status registers */
3566 if (reg == TABLA_A_RX_HPH_L_STATUS || reg == TABLA_A_RX_HPH_R_STATUS)
3567 return 1;
3568
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003569 return 0;
3570}
3571
3572#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
3573static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
3574 unsigned int value)
3575{
3576 int ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003577 BUG_ON(reg > TABLA_MAX_REGISTER);
3578
3579 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003580 ret = snd_soc_cache_write(codec, reg, value);
3581 if (ret != 0)
3582 dev_err(codec->dev, "Cache write to %x failed: %d\n",
3583 reg, ret);
3584 }
3585
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303586 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003587}
3588static unsigned int tabla_read(struct snd_soc_codec *codec,
3589 unsigned int reg)
3590{
3591 unsigned int val;
3592 int ret;
3593
3594 BUG_ON(reg > TABLA_MAX_REGISTER);
3595
3596 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
3597 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003598 ret = snd_soc_cache_read(codec, reg, &val);
3599 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003600 return val;
3601 } else
3602 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3603 reg, ret);
3604 }
3605
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303606 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003607 return val;
3608}
3609
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003610static s16 tabla_get_current_v_ins(struct tabla_priv *tabla, bool hu)
3611{
3612 s16 v_ins;
3613 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3614 tabla->mbhc_micbias_switched)
3615 v_ins = hu ? (s16)tabla->mbhc_data.adj_v_ins_hu :
3616 (s16)tabla->mbhc_data.adj_v_ins_h;
3617 else
3618 v_ins = hu ? (s16)tabla->mbhc_data.v_ins_hu :
3619 (s16)tabla->mbhc_data.v_ins_h;
3620 return v_ins;
3621}
3622
3623static s16 tabla_get_current_v_hs_max(struct tabla_priv *tabla)
3624{
3625 s16 v_hs_max;
3626 struct tabla_mbhc_plug_type_cfg *plug_type;
3627
3628 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
3629 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
3630 tabla->mbhc_micbias_switched)
3631 v_hs_max = tabla->mbhc_data.adj_v_hs_max;
3632 else
3633 v_hs_max = plug_type->v_hs_max;
3634 return v_hs_max;
3635}
3636
Bradley Rubincb1e2732011-06-23 16:49:20 -07003637static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
3638{
Joonwoo Parkc0672392012-01-11 11:03:14 -08003639 u8 *n_ready, *n_cic;
Joonwoo Park0976d012011-12-22 11:48:18 -08003640 struct tabla_mbhc_btn_detect_cfg *btn_det;
3641 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003642 const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
3643
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003644 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003645
Joonwoo Park0976d012011-12-22 11:48:18 -08003646 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003647 v_ins_hu & 0xFF);
Joonwoo Park0976d012011-12-22 11:48:18 -08003648 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003649 (v_ins_hu >> 8) & 0xFF);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003650
Joonwoo Park0976d012011-12-22 11:48:18 -08003651 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
3652 tabla->mbhc_data.v_b1_hu & 0xFF);
3653 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
3654 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
3655
3656 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
3657 tabla->mbhc_data.v_b1_h & 0xFF);
3658 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
3659 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
3660
3661 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
3662 tabla->mbhc_data.v_brh & 0xFF);
3663 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
3664 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
3665
3666 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
3667 tabla->mbhc_data.v_brl & 0xFF);
3668 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
3669 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
3670
Joonwoo Parkc0672392012-01-11 11:03:14 -08003671 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08003672 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08003673 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08003674 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
3675 tabla->mbhc_data.npoll);
3676 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
3677 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08003678 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08003679 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
3680 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003681}
3682
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003683static int tabla_startup(struct snd_pcm_substream *substream,
3684 struct snd_soc_dai *dai)
3685{
Kuirong Wanga545e722012-02-06 19:12:54 -08003686 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003687 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3688 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003689 if ((tabla_core != NULL) &&
3690 (tabla_core->dev != NULL) &&
3691 (tabla_core->dev->parent != NULL))
3692 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003693
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003694 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003695}
3696
3697static void tabla_shutdown(struct snd_pcm_substream *substream,
3698 struct snd_soc_dai *dai)
3699{
Kuirong Wanga545e722012-02-06 19:12:54 -08003700 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003701 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
3702 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08003703 if ((tabla_core != NULL) &&
3704 (tabla_core->dev != NULL) &&
3705 (tabla_core->dev->parent != NULL)) {
3706 pm_runtime_mark_last_busy(tabla_core->dev->parent);
3707 pm_runtime_put(tabla_core->dev->parent);
3708 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003709}
3710
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003711int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003712{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003713 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3714
Joonwoo Parkcf473b42012-03-29 19:48:16 -07003715 pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
3716 dapm);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003717 if (dapm)
3718 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003719 if (mclk_enable) {
3720 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003721
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003722 if (tabla->mbhc_polling_active) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07003723 tabla_codec_pause_hs_polling(codec);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003724 tabla_codec_disable_clock_block(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003725 tabla_codec_enable_bandgap(codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003726 TABLA_BANDGAP_AUDIO_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003727 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07003728 tabla_codec_calibrate_hs_polling(codec);
3729 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303730 } else {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003731 tabla_codec_disable_clock_block(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303732 tabla_codec_enable_bandgap(codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003733 TABLA_BANDGAP_AUDIO_MODE);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303734 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003735 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003736 } else {
3737
3738 if (!tabla->mclk_enabled) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003739 if (dapm)
3740 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003741 pr_err("Error, MCLK already diabled\n");
3742 return -EINVAL;
3743 }
3744 tabla->mclk_enabled = false;
3745
3746 if (tabla->mbhc_polling_active) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003747 tabla_codec_pause_hs_polling(codec);
3748 tabla_codec_disable_clock_block(codec);
3749 tabla_codec_enable_bandgap(codec,
3750 TABLA_BANDGAP_MBHC_MODE);
3751 tabla_enable_rx_bias(codec, 1);
3752 tabla_codec_enable_clock_block(codec, 1);
3753 tabla_codec_calibrate_hs_polling(codec);
3754 tabla_codec_start_hs_polling(codec);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003755 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
3756 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05303757 } else {
3758 tabla_codec_disable_clock_block(codec);
3759 tabla_codec_enable_bandgap(codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07003760 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003761 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003762 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003763 if (dapm)
3764 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003765 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003766}
3767
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003768static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
3769 int clk_id, unsigned int freq, int dir)
3770{
3771 pr_debug("%s\n", __func__);
3772 return 0;
3773}
3774
3775static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3776{
Santosh Mardie15e2302011-11-15 10:39:23 +05303777 u8 val = 0;
3778 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3779
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003780 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05303781 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3782 case SND_SOC_DAIFMT_CBS_CFS:
3783 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303784 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003785 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303786 snd_soc_update_bits(dai->codec,
3787 TABLA_A_CDC_CLK_TX_I2S_CTL,
3788 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003789 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303790 snd_soc_update_bits(dai->codec,
3791 TABLA_A_CDC_CLK_RX_I2S_CTL,
3792 TABLA_I2S_MASTER_MODE_MASK, 0);
3793 }
3794 break;
3795 case SND_SOC_DAIFMT_CBM_CFM:
3796 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303797 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303798 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003799 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05303800 snd_soc_update_bits(dai->codec,
3801 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003802 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05303803 snd_soc_update_bits(dai->codec,
3804 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
3805 }
3806 break;
3807 default:
3808 return -EINVAL;
3809 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003810 return 0;
3811}
3812
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003813static int tabla_set_channel_map(struct snd_soc_dai *dai,
3814 unsigned int tx_num, unsigned int *tx_slot,
3815 unsigned int rx_num, unsigned int *rx_slot)
3816
3817{
3818 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
3819 u32 i = 0;
3820 if (!tx_slot && !rx_slot) {
3821 pr_err("%s: Invalid\n", __func__);
3822 return -EINVAL;
3823 }
3824 pr_debug("%s: DAI-ID %x %d %d\n", __func__, dai->id, tx_num, rx_num);
3825
Neema Shettyd3a89262012-02-16 10:23:50 -08003826 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003827 for (i = 0; i < rx_num; i++) {
3828 tabla->dai[dai->id - 1].ch_num[i] = rx_slot[i];
3829 tabla->dai[dai->id - 1].ch_act = 0;
3830 tabla->dai[dai->id - 1].ch_tot = rx_num;
3831 }
Neema Shetty3fb1b802012-04-27 13:53:24 -07003832 } else if (dai->id == AIF1_CAP || dai->id == AIF2_CAP ||
3833 dai->id == AIF3_CAP) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003834 for (i = 0; i < tx_num; i++) {
3835 tabla->dai[dai->id - 1].ch_num[i] = tx_slot[i];
3836 tabla->dai[dai->id - 1].ch_act = 0;
3837 tabla->dai[dai->id - 1].ch_tot = tx_num;
3838 }
3839 }
3840 return 0;
3841}
3842
3843static int tabla_get_channel_map(struct snd_soc_dai *dai,
3844 unsigned int *tx_num, unsigned int *tx_slot,
3845 unsigned int *rx_num, unsigned int *rx_slot)
3846
3847{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303848 struct wcd9xxx *tabla = dev_get_drvdata(dai->codec->control_data);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003849
3850 u32 cnt = 0;
3851 u32 tx_ch[SLIM_MAX_TX_PORTS];
3852 u32 rx_ch[SLIM_MAX_RX_PORTS];
3853
3854 if (!rx_slot && !tx_slot) {
3855 pr_err("%s: Invalid\n", __func__);
3856 return -EINVAL;
3857 }
3858 pr_debug("%s: DAI-ID %x\n", __func__, dai->id);
3859 /* for virtual port, codec driver needs to do
3860 * housekeeping, for now should be ok
3861 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303862 wcd9xxx_get_channel(tabla, rx_ch, tx_ch);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003863 if (dai->id == AIF1_PB) {
3864 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3865 while (cnt < *rx_num) {
3866 rx_slot[cnt] = rx_ch[cnt];
3867 cnt++;
3868 }
3869 } else if (dai->id == AIF1_CAP) {
3870 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3871 while (cnt < *tx_num) {
3872 tx_slot[cnt] = tx_ch[6 + cnt];
3873 cnt++;
3874 }
Neema Shettyd3a89262012-02-16 10:23:50 -08003875 } else if (dai->id == AIF2_PB) {
3876 *rx_num = tabla_dai[dai->id - 1].playback.channels_max;
3877 while (cnt < *rx_num) {
3878 rx_slot[cnt] = rx_ch[5 + cnt];
3879 cnt++;
3880 }
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003881 } else if (dai->id == AIF2_CAP) {
3882 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3883 tx_slot[0] = tx_ch[cnt];
3884 tx_slot[1] = tx_ch[1 + cnt];
Kiran Kandi323d7102012-04-18 19:56:14 -07003885 tx_slot[2] = tx_ch[5 + cnt];
Kiran Kandie408b842012-05-17 19:48:04 -07003886 tx_slot[3] = tx_ch[3 + cnt];
Neema Shetty3fb1b802012-04-27 13:53:24 -07003887 } else if (dai->id == AIF3_CAP) {
3888 *tx_num = tabla_dai[dai->id - 1].capture.channels_max;
3889 tx_slot[cnt] = tx_ch[2 + cnt];
3890 tx_slot[cnt + 1] = tx_ch[4 + cnt];
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003891 }
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003892
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003893 return 0;
3894}
3895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003896static int tabla_hw_params(struct snd_pcm_substream *substream,
3897 struct snd_pcm_hw_params *params,
3898 struct snd_soc_dai *dai)
3899{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003900 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05303901 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Bhalchandra Gajare038bf3a2011-09-02 15:32:30 -07003902 u8 path, shift;
3903 u16 tx_fs_reg, rx_fs_reg;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003904 u8 tx_fs_rate, rx_fs_rate, rx_state, tx_state;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003905 u32 compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003906
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003907 pr_debug("%s: DAI-ID %x rate %d\n", __func__, dai->id,
3908 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003909
3910 switch (params_rate(params)) {
3911 case 8000:
3912 tx_fs_rate = 0x00;
3913 rx_fs_rate = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003914 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003915 break;
3916 case 16000:
3917 tx_fs_rate = 0x01;
3918 rx_fs_rate = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003919 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003920 break;
3921 case 32000:
3922 tx_fs_rate = 0x02;
3923 rx_fs_rate = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003924 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003925 break;
3926 case 48000:
3927 tx_fs_rate = 0x03;
3928 rx_fs_rate = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003929 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003930 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003931 case 96000:
3932 tx_fs_rate = 0x04;
3933 rx_fs_rate = 0x80;
3934 compander_fs = COMPANDER_FS_96KHZ;
3935 break;
3936 case 192000:
3937 tx_fs_rate = 0x05;
3938 rx_fs_rate = 0xA0;
3939 compander_fs = COMPANDER_FS_192KHZ;
3940 break;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003941 default:
3942 pr_err("%s: Invalid sampling rate %d\n", __func__,
3943 params_rate(params));
3944 return -EINVAL;
3945 }
3946
3947
3948 /**
3949 * If current dai is a tx dai, set sample rate to
3950 * all the txfe paths that are currently not active
3951 */
Neema Shetty3fb1b802012-04-27 13:53:24 -07003952 if ((dai->id == AIF1_CAP) || (dai->id == AIF2_CAP) ||
3953 (dai->id == AIF3_CAP)) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003954
3955 tx_state = snd_soc_read(codec,
3956 TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL);
3957
3958 for (path = 1, shift = 0;
3959 path <= NUM_DECIMATORS; path++, shift++) {
3960
3961 if (path == BITS_PER_REG + 1) {
3962 shift = 0;
3963 tx_state = snd_soc_read(codec,
3964 TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL);
3965 }
3966
3967 if (!(tx_state & (1 << shift))) {
3968 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL
3969 + (BITS_PER_REG*(path-1));
3970 snd_soc_update_bits(codec, tx_fs_reg,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003971 0x07, tx_fs_rate);
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003972 }
3973 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303974 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05303975 switch (params_format(params)) {
3976 case SNDRV_PCM_FORMAT_S16_LE:
3977 snd_soc_update_bits(codec,
3978 TABLA_A_CDC_CLK_TX_I2S_CTL,
3979 0x20, 0x20);
3980 break;
3981 case SNDRV_PCM_FORMAT_S32_LE:
3982 snd_soc_update_bits(codec,
3983 TABLA_A_CDC_CLK_TX_I2S_CTL,
3984 0x20, 0x00);
3985 break;
3986 default:
3987 pr_err("invalid format\n");
3988 break;
3989 }
3990 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003991 0x07, tx_fs_rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08003992 } else {
3993 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05303994 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003995 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07003996 /**
3997 * TODO: Need to handle case where same RX chain takes 2 or more inputs
3998 * with varying sample rates
3999 */
4000
4001 /**
4002 * If current dai is a rx dai, set sample rate to
4003 * all the rx paths that are currently not active
4004 */
Neema Shettyd3a89262012-02-16 10:23:50 -08004005 if (dai->id == AIF1_PB || dai->id == AIF2_PB) {
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004006
4007 rx_state = snd_soc_read(codec,
4008 TABLA_A_CDC_CLK_RX_B1_CTL);
4009
4010 for (path = 1, shift = 0;
4011 path <= NUM_INTERPOLATORS; path++, shift++) {
4012
4013 if (!(rx_state & (1 << shift))) {
4014 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL
4015 + (BITS_PER_REG*(path-1));
4016 snd_soc_update_bits(codec, rx_fs_reg,
4017 0xE0, rx_fs_rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004018 if (comp_rx_path[shift] < COMPANDER_MAX)
4019 tabla->comp_fs[comp_rx_path[shift]]
4020 = compander_fs;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004021 }
4022 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304023 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05304024 switch (params_format(params)) {
4025 case SNDRV_PCM_FORMAT_S16_LE:
4026 snd_soc_update_bits(codec,
4027 TABLA_A_CDC_CLK_RX_I2S_CTL,
4028 0x20, 0x20);
4029 break;
4030 case SNDRV_PCM_FORMAT_S32_LE:
4031 snd_soc_update_bits(codec,
4032 TABLA_A_CDC_CLK_RX_I2S_CTL,
4033 0x20, 0x00);
4034 break;
4035 default:
4036 pr_err("invalid format\n");
4037 break;
4038 }
4039 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
4040 0x03, (rx_fs_rate >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004041 } else {
4042 tabla->dai[dai->id - 1].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05304043 }
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004044 }
4045
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004046 return 0;
4047}
4048
4049static struct snd_soc_dai_ops tabla_dai_ops = {
4050 .startup = tabla_startup,
4051 .shutdown = tabla_shutdown,
4052 .hw_params = tabla_hw_params,
4053 .set_sysclk = tabla_set_dai_sysclk,
4054 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004055 .set_channel_map = tabla_set_channel_map,
4056 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004057};
4058
4059static struct snd_soc_dai_driver tabla_dai[] = {
4060 {
4061 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004062 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004063 .playback = {
4064 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004065 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004066 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004067 .rate_max = 192000,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004068 .rate_min = 8000,
4069 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004070 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004071 },
4072 .ops = &tabla_dai_ops,
4073 },
4074 {
4075 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004076 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004077 .capture = {
4078 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004079 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004080 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004081 .rate_max = 192000,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004082 .rate_min = 8000,
4083 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004084 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004085 },
4086 .ops = &tabla_dai_ops,
4087 },
Neema Shettyd3a89262012-02-16 10:23:50 -08004088 {
4089 .name = "tabla_rx2",
4090 .id = AIF2_PB,
4091 .playback = {
4092 .stream_name = "AIF2 Playback",
4093 .rates = WCD9310_RATES,
4094 .formats = TABLA_FORMATS,
4095 .rate_min = 8000,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004096 .rate_max = 192000,
Neema Shettyd3a89262012-02-16 10:23:50 -08004097 .channels_min = 1,
4098 .channels_max = 2,
4099 },
4100 .ops = &tabla_dai_ops,
4101 },
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004102 {
4103 .name = "tabla_tx2",
4104 .id = AIF2_CAP,
4105 .capture = {
4106 .stream_name = "AIF2 Capture",
4107 .rates = WCD9310_RATES,
4108 .formats = TABLA_FORMATS,
4109 .rate_max = 192000,
4110 .rate_min = 8000,
4111 .channels_min = 1,
4112 .channels_max = 4,
4113 },
4114 .ops = &tabla_dai_ops,
4115 },
Neema Shetty3fb1b802012-04-27 13:53:24 -07004116 {
4117 .name = "tabla_tx3",
4118 .id = AIF3_CAP,
4119 .capture = {
4120 .stream_name = "AIF3 Capture",
4121 .rates = WCD9310_RATES,
4122 .formats = TABLA_FORMATS,
4123 .rate_max = 48000,
4124 .rate_min = 8000,
4125 .channels_min = 1,
4126 .channels_max = 2,
4127 },
4128 .ops = &tabla_dai_ops,
4129 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004130};
Santosh Mardie15e2302011-11-15 10:39:23 +05304131
4132static struct snd_soc_dai_driver tabla_i2s_dai[] = {
4133 {
4134 .name = "tabla_i2s_rx1",
4135 .id = 1,
4136 .playback = {
4137 .stream_name = "AIF1 Playback",
4138 .rates = WCD9310_RATES,
4139 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004140 .rate_max = 192000,
Santosh Mardie15e2302011-11-15 10:39:23 +05304141 .rate_min = 8000,
4142 .channels_min = 1,
4143 .channels_max = 4,
4144 },
4145 .ops = &tabla_dai_ops,
4146 },
4147 {
4148 .name = "tabla_i2s_tx1",
4149 .id = 2,
4150 .capture = {
4151 .stream_name = "AIF1 Capture",
4152 .rates = WCD9310_RATES,
4153 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004154 .rate_max = 192000,
Santosh Mardie15e2302011-11-15 10:39:23 +05304155 .rate_min = 8000,
4156 .channels_min = 1,
4157 .channels_max = 4,
4158 },
4159 .ops = &tabla_dai_ops,
4160 },
4161};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004162
4163static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
4164 struct snd_kcontrol *kcontrol, int event)
4165{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304166 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004167 struct snd_soc_codec *codec = w->codec;
4168 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
4169 u32 j = 0;
4170 u32 ret = 0;
4171 codec->control_data = dev_get_drvdata(codec->dev->parent);
4172 tabla = codec->control_data;
4173 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304174 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004175 return 0;
4176 switch (event) {
4177 case SND_SOC_DAPM_POST_PMU:
4178 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004179 if ((tabla_dai[j].id == AIF1_CAP) ||
Neema Shetty3fb1b802012-04-27 13:53:24 -07004180 (tabla_dai[j].id == AIF2_CAP) ||
4181 (tabla_dai[j].id == AIF3_CAP))
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004182 continue;
4183 if (!strncmp(w->sname,
4184 tabla_dai[j].playback.stream_name, 13)) {
4185 ++tabla_p->dai[j].ch_act;
4186 break;
4187 }
4188 }
4189 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304190 ret = wcd9xxx_cfg_slim_sch_rx(tabla,
4191 tabla_p->dai[j].ch_num,
4192 tabla_p->dai[j].ch_tot,
4193 tabla_p->dai[j].rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004194 break;
4195 case SND_SOC_DAPM_POST_PMD:
4196 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004197 if ((tabla_dai[j].id == AIF1_CAP) ||
Neema Shetty3fb1b802012-04-27 13:53:24 -07004198 (tabla_dai[j].id == AIF2_CAP) ||
4199 (tabla_dai[j].id == AIF3_CAP))
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004200 continue;
4201 if (!strncmp(w->sname,
4202 tabla_dai[j].playback.stream_name, 13)) {
4203 --tabla_p->dai[j].ch_act;
4204 break;
4205 }
4206 }
4207 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304208 ret = wcd9xxx_close_slim_sch_rx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004209 tabla_p->dai[j].ch_num,
4210 tabla_p->dai[j].ch_tot);
Bharath Ramachandramurthyda6fa7a2012-03-30 14:35:32 -07004211 usleep_range(5000, 5000);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004212 tabla_p->dai[j].rate = 0;
4213 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304214 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004215 tabla_p->dai[j].ch_tot = 0;
4216 }
4217 }
4218 return ret;
4219}
4220
4221static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
4222 struct snd_kcontrol *kcontrol, int event)
4223{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304224 struct wcd9xxx *tabla;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004225 struct snd_soc_codec *codec = w->codec;
4226 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
4227 /* index to the DAI ID, for now hardcoding */
4228 u32 j = 0;
4229 u32 ret = 0;
4230
4231 codec->control_data = dev_get_drvdata(codec->dev->parent);
4232 tabla = codec->control_data;
4233
4234 /* Execute the callback only if interface type is slimbus */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304235 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004236 return 0;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004237
4238 pr_debug("%s(): %s %d\n", __func__, w->name, event);
4239
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004240 switch (event) {
4241 case SND_SOC_DAPM_POST_PMU:
4242 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08004243 if (tabla_dai[j].id == AIF1_PB ||
4244 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004245 continue;
4246 if (!strncmp(w->sname,
4247 tabla_dai[j].capture.stream_name, 13)) {
4248 ++tabla_p->dai[j].ch_act;
4249 break;
4250 }
4251 }
4252 if (tabla_p->dai[j].ch_act == tabla_p->dai[j].ch_tot)
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304253 ret = wcd9xxx_cfg_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004254 tabla_p->dai[j].ch_num,
4255 tabla_p->dai[j].ch_tot,
4256 tabla_p->dai[j].rate);
4257 break;
4258 case SND_SOC_DAPM_POST_PMD:
4259 for (j = 0; j < ARRAY_SIZE(tabla_dai); j++) {
Neema Shettyd3a89262012-02-16 10:23:50 -08004260 if (tabla_dai[j].id == AIF1_PB ||
4261 tabla_dai[j].id == AIF2_PB)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004262 continue;
4263 if (!strncmp(w->sname,
4264 tabla_dai[j].capture.stream_name, 13)) {
4265 --tabla_p->dai[j].ch_act;
4266 break;
4267 }
4268 }
4269 if (!tabla_p->dai[j].ch_act) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304270 ret = wcd9xxx_close_slim_sch_tx(tabla,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004271 tabla_p->dai[j].ch_num,
4272 tabla_p->dai[j].ch_tot);
4273 tabla_p->dai[j].rate = 0;
4274 memset(tabla_p->dai[j].ch_num, 0, (sizeof(u32)*
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304275 tabla_p->dai[j].ch_tot));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004276 tabla_p->dai[j].ch_tot = 0;
4277 }
4278 }
4279 return ret;
4280}
4281
4282/* Todo: Have seperate dapm widgets for I2S and Slimbus.
4283 * Might Need to have callbacks registered only for slimbus
4284 */
4285static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
4286 /*RX stuff */
4287 SND_SOC_DAPM_OUTPUT("EAR"),
4288
4289 SND_SOC_DAPM_PGA("EAR PA", TABLA_A_RX_EAR_EN, 4, 0, NULL, 0),
4290
4291 SND_SOC_DAPM_MIXER("DAC1", TABLA_A_RX_EAR_EN, 6, 0, dac1_switch,
4292 ARRAY_SIZE(dac1_switch)),
4293
4294 SND_SOC_DAPM_AIF_IN_E("SLIM RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
4295 0, tabla_codec_enable_slimrx,
4296 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4297 SND_SOC_DAPM_AIF_IN_E("SLIM RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0,
4298 0, tabla_codec_enable_slimrx,
4299 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4300
4301 SND_SOC_DAPM_AIF_IN("SLIM RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
4302 SND_SOC_DAPM_AIF_IN("SLIM RX4", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
4303
Neema Shettyd3a89262012-02-16 10:23:50 -08004304 SND_SOC_DAPM_AIF_IN_E("SLIM RX6", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
4305 0, tabla_codec_enable_slimrx,
4306 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4307 SND_SOC_DAPM_AIF_IN_E("SLIM RX7", "AIF2 Playback", 0, SND_SOC_NOPM, 0,
4308 0, tabla_codec_enable_slimrx,
4309 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4310
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004311 /* Headphone */
4312 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
4313 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
4314 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4315 SND_SOC_DAPM_POST_PMD),
4316 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
4317 hphl_switch, ARRAY_SIZE(hphl_switch)),
4318
4319 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
4320 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4321 SND_SOC_DAPM_POST_PMD),
4322
4323 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
4324 tabla_hphr_dac_event,
4325 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4326
4327 /* Speaker */
4328 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
4329 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
4330 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
4331 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
4332 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
4333
4334 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
4335 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4336 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4337 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
4338 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4339 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4340 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
4341 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4342 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4343 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
4344 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4345 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4346 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
4347 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4348 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4349
4350 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
4351 , tabla_lineout_dac_event,
4352 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4353 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
4354 , tabla_lineout_dac_event,
4355 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4356 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
4357 , tabla_lineout_dac_event,
4358 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4359 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
4360 &lineout3_ground_switch),
4361 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
4362 , tabla_lineout_dac_event,
4363 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4364 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
4365 &lineout4_ground_switch),
4366 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
4367 , tabla_lineout_dac_event,
4368 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4369
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004370 SND_SOC_DAPM_MIXER_E("RX1 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004371 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4372 SND_SOC_DAPM_POST_PMU),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004373 SND_SOC_DAPM_MIXER_E("RX2 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004374 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4375 SND_SOC_DAPM_POST_PMU),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004376 SND_SOC_DAPM_MIXER_E("RX3 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004377 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4378 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004379 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004380 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4381 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004382 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004383 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4384 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004385 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004386 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4387 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004388 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07004389 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
4390 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004391
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004392 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4393 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4394 SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4395
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004396 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
4397 &rx4_dsm_mux, tabla_codec_reset_interpolator,
4398 SND_SOC_DAPM_PRE_PMU),
4399
4400 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
4401 &rx6_dsm_mux, tabla_codec_reset_interpolator,
4402 SND_SOC_DAPM_PRE_PMU),
4403
4404 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
4405 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
4406
4407 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4408 &rx_mix1_inp1_mux),
4409 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4410 &rx_mix1_inp2_mux),
4411 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4412 &rx2_mix1_inp1_mux),
4413 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4414 &rx2_mix1_inp2_mux),
4415 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4416 &rx3_mix1_inp1_mux),
4417 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4418 &rx3_mix1_inp2_mux),
4419 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4420 &rx4_mix1_inp1_mux),
4421 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4422 &rx4_mix1_inp2_mux),
4423 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4424 &rx5_mix1_inp1_mux),
4425 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4426 &rx5_mix1_inp2_mux),
4427 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4428 &rx6_mix1_inp1_mux),
4429 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4430 &rx6_mix1_inp2_mux),
4431 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4432 &rx7_mix1_inp1_mux),
4433 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4434 &rx7_mix1_inp2_mux),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004435 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4436 &rx1_mix2_inp1_mux),
4437 SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4438 &rx1_mix2_inp2_mux),
4439 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4440 &rx2_mix2_inp1_mux),
4441 SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4442 &rx2_mix2_inp2_mux),
4443 SND_SOC_DAPM_MUX("RX3 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4444 &rx3_mix2_inp1_mux),
4445 SND_SOC_DAPM_MUX("RX3 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4446 &rx3_mix2_inp2_mux),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004447
4448 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
4449 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
4450 SND_SOC_DAPM_PRE_PMD),
4451
4452 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
4453 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
4454 SND_SOC_DAPM_POST_PMD),
4455
4456 /* TX */
4457
4458 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
4459 0),
4460
4461 SND_SOC_DAPM_SUPPLY("LDO_H", TABLA_A_LDO_H_MODE_1, 7, 0,
4462 tabla_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
4463
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004464 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
4465 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4466 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4467 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
4468 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
4469 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
4470
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004471 SND_SOC_DAPM_INPUT("AMIC1"),
4472 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TABLA_A_MICB_1_CTL, 7, 0,
4473 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4474 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4475 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TABLA_A_MICB_1_CTL, 7, 0,
4476 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4477 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4478 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TABLA_A_MICB_1_CTL, 7, 0,
4479 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4480 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4481 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
4482 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4483 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4484
4485 SND_SOC_DAPM_INPUT("AMIC3"),
4486 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
4487 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4488 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4489
4490 SND_SOC_DAPM_INPUT("AMIC4"),
4491 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
4492 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4493 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4494
4495 SND_SOC_DAPM_INPUT("AMIC5"),
4496 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
4497 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4498
4499 SND_SOC_DAPM_INPUT("AMIC6"),
4500 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
4501 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4502
4503 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 -08004504 &dec1_mux, tabla_codec_enable_dec,
4505 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4506 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004507
4508 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 -08004509 &dec2_mux, tabla_codec_enable_dec,
4510 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4511 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004512
4513 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 -08004514 &dec3_mux, tabla_codec_enable_dec,
4515 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4516 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004517
4518 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 -08004519 &dec4_mux, tabla_codec_enable_dec,
4520 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4521 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004522
4523 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 -08004524 &dec5_mux, tabla_codec_enable_dec,
4525 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4526 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004527
4528 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 -08004529 &dec6_mux, tabla_codec_enable_dec,
4530 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4531 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004532
4533 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 -08004534 &dec7_mux, tabla_codec_enable_dec,
4535 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4536 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004537
4538 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 -08004539 &dec8_mux, tabla_codec_enable_dec,
4540 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4541 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004542
4543 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 -08004544 &dec9_mux, tabla_codec_enable_dec,
4545 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4546 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004547
4548 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 -08004549 &dec10_mux, tabla_codec_enable_dec,
4550 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4551 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004552
4553 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
4554 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
4555
4556 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
4557 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
4558 SND_SOC_DAPM_POST_PMD),
4559
4560 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
4561
4562 SND_SOC_DAPM_INPUT("AMIC2"),
4563 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TABLA_A_MICB_2_CTL, 7, 0,
4564 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4565 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4566 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TABLA_A_MICB_2_CTL, 7, 0,
4567 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4568 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4569 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TABLA_A_MICB_2_CTL, 7, 0,
4570 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4571 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4572 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TABLA_A_MICB_2_CTL, 7, 0,
4573 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4574 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4575 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TABLA_A_MICB_3_CTL, 7, 0,
4576 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4577 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4578 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TABLA_A_MICB_3_CTL, 7, 0,
4579 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4580 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4581 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TABLA_A_MICB_3_CTL, 7, 0,
4582 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4583 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4584 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
4585 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4586 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4587
4588 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, 0, 0, &sb_tx1_mux),
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004589 SND_SOC_DAPM_AIF_OUT_E("SLIM TX1", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
4590 0, tabla_codec_enable_slimtx,
4591 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4592
4593 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, 0, 0, &sb_tx2_mux),
4594 SND_SOC_DAPM_AIF_OUT_E("SLIM TX2", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
4595 0, tabla_codec_enable_slimtx,
4596 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4597
4598 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, 0, 0, &sb_tx3_mux),
Neema Shetty3fb1b802012-04-27 13:53:24 -07004599 SND_SOC_DAPM_AIF_OUT_E("SLIM TX3", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004600 0, tabla_codec_enable_slimtx,
4601 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4602
4603 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, 0, 0, &sb_tx4_mux),
Kiran Kandie408b842012-05-17 19:48:04 -07004604 SND_SOC_DAPM_AIF_OUT_E("SLIM TX4", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004605 0, tabla_codec_enable_slimtx,
4606 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004607
4608 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, 0, 0, &sb_tx5_mux),
Neema Shetty3fb1b802012-04-27 13:53:24 -07004609 SND_SOC_DAPM_AIF_OUT_E("SLIM TX5", "AIF3 Capture", 0, SND_SOC_NOPM, 0,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004610 0, tabla_codec_enable_slimtx,
4611 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004612
4613 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, 0, 0, &sb_tx6_mux),
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004614 SND_SOC_DAPM_AIF_OUT_E("SLIM TX6", "AIF2 Capture", 0, SND_SOC_NOPM, 0,
4615 0, tabla_codec_enable_slimtx,
4616 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004617
4618 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, 0, 0, &sb_tx7_mux),
4619 SND_SOC_DAPM_AIF_OUT_E("SLIM TX7", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4620 0, tabla_codec_enable_slimtx,
4621 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4622
4623 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, 0, 0, &sb_tx8_mux),
4624 SND_SOC_DAPM_AIF_OUT_E("SLIM TX8", "AIF1 Capture", 0, SND_SOC_NOPM, 0,
4625 0, tabla_codec_enable_slimtx,
4626 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4627
4628 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, 0, 0, &sb_tx9_mux),
4629 SND_SOC_DAPM_AIF_OUT_E("SLIM TX9", "AIF1 Capture", NULL, SND_SOC_NOPM,
4630 0, 0, tabla_codec_enable_slimtx,
4631 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4632
4633 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, 0, 0, &sb_tx10_mux),
4634 SND_SOC_DAPM_AIF_OUT_E("SLIM TX10", "AIF1 Capture", NULL, SND_SOC_NOPM,
4635 0, 0, tabla_codec_enable_slimtx,
4636 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4637
4638 /* Digital Mic Inputs */
4639 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
4640 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4641 SND_SOC_DAPM_POST_PMD),
4642
4643 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
4644 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4645 SND_SOC_DAPM_POST_PMD),
4646
4647 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
4648 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4649 SND_SOC_DAPM_POST_PMD),
4650
4651 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
4652 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4653 SND_SOC_DAPM_POST_PMD),
4654
4655 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
4656 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4657 SND_SOC_DAPM_POST_PMD),
4658 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
4659 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4660 SND_SOC_DAPM_POST_PMD),
4661
4662 /* Sidetone */
4663 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
4664 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08004665
4666 /* AUX PGA */
4667 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
4668 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4669 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4670 SND_SOC_DAPM_POST_PMD),
4671
4672 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
4673 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4674 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
4675 SND_SOC_DAPM_POST_PMD),
4676
4677 /* Lineout, ear and HPH PA Mixers */
4678 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
4679 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
4680
4681 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4682 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4683
4684 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4685 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4686
4687 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4688 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
4689
4690 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
4691 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
4692
4693 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
4694 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
4695
4696 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
4697 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
4698
4699 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4700 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004701};
4702
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004703static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004704{
4705 u8 bias_msb, bias_lsb;
4706 short bias_value;
4707
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004708 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
4709 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
4710 bias_value = (bias_msb << 8) | bias_lsb;
4711 return bias_value;
4712}
4713
4714static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
4715{
4716 u8 bias_msb, bias_lsb;
4717 short bias_value;
4718
4719 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
4720 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
4721 bias_value = (bias_msb << 8) | bias_lsb;
4722 return bias_value;
4723}
4724
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004725static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004726{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004727 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
4728}
4729
4730static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4731 bool override_bypass, bool noreldetection)
4732{
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004733 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004734 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4735
4736 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
4737 if (noreldetection)
4738 tabla_turn_onoff_rel_detection(codec, false);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004739
Joonwoo Park925914c2012-01-05 13:35:18 -08004740 /* Turn on the override */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004741 if (!override_bypass)
4742 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004743 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004744 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4745 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
4746 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004747 usleep_range(tabla->mbhc_data.t_sta_dce,
4748 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004749 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08004750 usleep_range(tabla->mbhc_data.t_dce,
4751 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004752 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004753 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004754 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004755 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4756 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08004757 usleep_range(tabla->mbhc_data.t_sta_dce,
4758 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08004759 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
4760 usleep_range(tabla->mbhc_data.t_sta,
4761 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004762 bias_value = tabla_codec_read_sta_result(codec);
4763 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4764 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004765 }
Joonwoo Park925914c2012-01-05 13:35:18 -08004766 /* Turn off the override after measuring mic voltage */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004767 if (!override_bypass)
4768 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
4769
4770 if (noreldetection)
4771 tabla_turn_onoff_rel_detection(codec, true);
4772 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004773
Bradley Rubincb1e2732011-06-23 16:49:20 -07004774 return bias_value;
4775}
4776
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004777static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
4778 bool norel)
4779{
4780 return __tabla_codec_sta_dce(codec, dce, false, norel);
4781}
4782
4783/* called only from interrupt which is under codec_resource_lock acquisition */
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004784static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004785{
4786 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004787 short bias_value;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004788 u8 cfilt_mode;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004789
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004790 pr_debug("%s: enter, mclk_enabled %d\n", __func__, tabla->mclk_enabled);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004791 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004792 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07004793 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004794 }
4795
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004796 if (!tabla->mclk_enabled) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004797 tabla_codec_disable_clock_block(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004798 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004799 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004800 tabla_codec_enable_clock_block(codec, 1);
4801 }
4802
4803 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
4804
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08004805 /* Make sure CFILT is in fast mode, save current mode */
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004806 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
4807 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x70, 0x00);
Patrick Lai3043fba2011-08-01 14:15:57 -07004808
Joonwoo Parkf4267c22012-01-10 13:25:24 -08004809 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004810
4811 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004812 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004813
4814 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
4815 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
4816 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
4817
4818 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004819 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4820 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004821
Joonwoo Park925914c2012-01-05 13:35:18 -08004822 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004823 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
4824
Bradley Rubincb1e2732011-06-23 16:49:20 -07004825 tabla_codec_calibrate_hs_polling(codec);
4826
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004827 /* don't flip override */
4828 bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08004829 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
4830 cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07004831 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004832
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07004833 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004834}
4835
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004836static int tabla_cancel_btn_work(struct tabla_priv *tabla)
4837{
4838 int r = 0;
4839 struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
4840
4841 if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
4842 /* if scheduled mbhc_btn_dwork is canceled from here,
4843 * we have to unlock from here instead btn_work */
4844 wcd9xxx_unlock_sleep(core);
4845 r = 1;
4846 }
4847 return r;
4848}
4849
4850/* called under codec_resource_lock acquisition */
4851void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
Joonwoo Park03324832012-03-19 19:36:16 -07004852{
4853 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004854 u8 wg_time;
4855
4856 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4857 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07004858
4859 /* If headphone PA is on, check if userspace receives
4860 * removal event to sync-up PA's state */
4861 if (tabla_is_hph_pa_on(codec)) {
4862 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
4863 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4864 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
4865 } else {
4866 pr_debug("%s PA is off\n", __func__);
4867 }
4868
4869 if (tabla_is_hph_dac_on(codec, 1))
4870 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
4871 if (tabla_is_hph_dac_on(codec, 0))
4872 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004873
4874 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
4875 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
4876 0xC0, 0x00);
4877 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
4878 0xC0, 0x00);
4879 usleep_range(wg_time * 1000, wg_time * 1000);
4880}
4881
4882static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
4883{
4884 bool pa_turned_on = false;
4885 struct snd_soc_codec *codec = tabla->codec;
4886 u8 wg_time;
4887
4888 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
4889 wg_time += 1;
4890
4891 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
4892 &tabla->hph_pa_dac_state)) {
4893 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
4894 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
4895 0xC0, 0xC0);
4896 }
4897 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
4898 &tabla->hph_pa_dac_state)) {
4899 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
4900 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
4901 0xC0, 0xC0);
4902 }
4903
4904 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
4905 &tabla->hph_pa_dac_state)) {
4906 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
4907 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
4908 1 << 4);
4909 pa_turned_on = true;
4910 }
4911 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
4912 &tabla->hph_pa_dac_state)) {
4913 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
4914 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
4915 1 << 5);
4916 pa_turned_on = true;
4917 }
4918
4919 if (pa_turned_on) {
4920 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
4921 __func__);
4922 usleep_range(wg_time * 1000, wg_time * 1000);
4923 }
4924}
4925
4926/* called under codec_resource_lock acquisition */
4927static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
4928 enum snd_jack_types jack_type)
4929{
4930 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4931
4932 if (!insertion) {
4933 /* Report removal */
4934 tabla->hph_status &= ~jack_type;
4935 if (tabla->mbhc_cfg.headset_jack) {
4936 /* cancel possibly scheduled btn work and
4937 * report release if we reported button press */
4938 if (tabla_cancel_btn_work(tabla)) {
4939 pr_debug("%s: button press is canceled\n",
4940 __func__);
4941 } else if (tabla->buttons_pressed) {
4942 pr_debug("%s: Reporting release for reported "
4943 "button press %d\n", __func__,
4944 jack_type);
4945 tabla_snd_soc_jack_report(tabla,
4946 tabla->mbhc_cfg.button_jack, 0,
4947 tabla->buttons_pressed);
4948 tabla->buttons_pressed &=
4949 ~TABLA_JACK_BUTTON_MASK;
4950 }
Joonwoo Park2cc13f02012-05-09 12:44:25 -07004951 pr_debug("%s: Reporting removal %d(%x)\n", __func__,
4952 jack_type, tabla->hph_status);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004953 tabla_snd_soc_jack_report(tabla,
4954 tabla->mbhc_cfg.headset_jack,
4955 tabla->hph_status,
4956 TABLA_JACK_MASK);
4957 }
4958 tabla_set_and_turnoff_hph_padac(codec);
4959 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
4960 TABLA_IRQ_HPH_PA_OCPR_FAULT);
4961 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
4962 TABLA_IRQ_HPH_PA_OCPL_FAULT);
4963 tabla->current_plug = PLUG_TYPE_NONE;
4964 tabla->mbhc_polling_active = false;
4965 } else {
4966 /* Report insertion */
4967 tabla->hph_status |= jack_type;
4968
4969 if (jack_type == SND_JACK_HEADPHONE)
4970 tabla->current_plug = PLUG_TYPE_HEADPHONE;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07004971 else if (jack_type == SND_JACK_UNSUPPORTED)
4972 tabla->current_plug = PLUG_TYPE_GND_MIC_SWAP;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004973 else if (jack_type == SND_JACK_HEADSET) {
4974 tabla->mbhc_polling_active = true;
4975 tabla->current_plug = PLUG_TYPE_HEADSET;
4976 }
4977 if (tabla->mbhc_cfg.headset_jack) {
Joonwoo Park2cc13f02012-05-09 12:44:25 -07004978 pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
4979 jack_type, tabla->hph_status);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004980 tabla_snd_soc_jack_report(tabla,
4981 tabla->mbhc_cfg.headset_jack,
4982 tabla->hph_status,
4983 TABLA_JACK_MASK);
4984 }
4985 tabla_clr_and_turnon_hph_padac(tabla);
4986 }
Joonwoo Park03324832012-03-19 19:36:16 -07004987}
4988
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004989static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07004990 int insertion, int trigger,
4991 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004992{
4993 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004994 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08004995 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004996 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08004997 const struct tabla_mbhc_plug_detect_cfg *plug_det =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004998 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004999
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005000 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005001 pr_err("Error, no tabla calibration\n");
5002 return -EINVAL;
5003 }
5004
5005 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
5006
Joonwoo Park03324832012-03-19 19:36:16 -07005007 /* Make sure mic bias and Mic line schmitt trigger
5008 * are turned OFF
5009 */
5010 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
5011 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
5012
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005013 if (insertion) {
Joonwoo Park03324832012-03-19 19:36:16 -07005014 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005015
Joonwoo Park03324832012-03-19 19:36:16 -07005016 /* DAPM can manipulate PA/DAC bits concurrently */
5017 if (padac_off == true) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005018 tabla_set_and_turnoff_hph_padac(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005019 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005020
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005021 if (trigger & MBHC_USE_HPHL_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07005022 /* Enable HPH Schmitt Trigger */
5023 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
5024 0x11);
5025 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
5026 plug_det->hph_current << 2);
5027 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
5028 0x02);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005029 }
5030 if (trigger & MBHC_USE_MB_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07005031 /* enable the mic line schmitt trigger */
5032 snd_soc_update_bits(codec,
5033 tabla->mbhc_bias_regs.mbhc_reg,
5034 0x60, plug_det->mic_current << 5);
5035 snd_soc_update_bits(codec,
5036 tabla->mbhc_bias_regs.mbhc_reg,
5037 0x80, 0x80);
5038 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
5039 snd_soc_update_bits(codec,
5040 tabla->mbhc_bias_regs.ctl_reg, 0x01,
5041 0x00);
5042 snd_soc_update_bits(codec,
5043 tabla->mbhc_bias_regs.mbhc_reg,
5044 0x10, 0x10);
5045 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005046
5047 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005048 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005049 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005050 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005051 /* Make sure the HPH schmitt trigger is OFF */
5052 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
5053
5054 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07005055 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
5056 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005057 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08005058 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005059 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
5060 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08005061 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005062 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
5063 0x10, 0x10);
5064
5065 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005066 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07005067 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005068
5069 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005070 /* called called by interrupt */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005071 if (!(tabla->clock_active)) {
5072 tabla_codec_enable_config_mode(codec, 1);
5073 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07005074 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08005075 usleep_range(generic->t_shutdown_plug_rem,
5076 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005077 tabla_codec_enable_config_mode(codec, 0);
5078 } else
5079 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07005080 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005081 }
5082
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07005083 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005084
5085 /* If central bandgap disabled */
5086 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
5087 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08005088 usleep_range(generic->t_bg_fast_settle,
5089 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005090 central_bias_enabled = 1;
5091 }
5092
5093 /* If LDO_H disabled */
5094 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
5095 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
5096 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08005097 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005098 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
5099
5100 if (central_bias_enabled)
5101 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
5102 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005103
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005104 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005105 tabla->mbhc_cfg.micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005106
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305107 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005108 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
5109 return 0;
5110}
5111
Joonwoo Park0976d012011-12-22 11:48:18 -08005112static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
5113 s16 vin_mv)
5114{
Joonwoo Park0976d012011-12-22 11:48:18 -08005115 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07005116 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08005117 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07005118 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08005119
5120 tabla = snd_soc_codec_get_drvdata(codec);
5121 mb_mv = tabla->mbhc_data.micb_mv;
5122
5123 if (mb_mv == 0) {
5124 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
5125 return -EINVAL;
5126 }
5127
5128 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07005129 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
5130 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08005131 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005132 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
5133 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08005134 }
5135 in = (u32) diff * vin_mv;
5136
Joonwoo Park03324832012-03-19 19:36:16 -07005137 value = (u16) (in / mb_mv) + zero;
5138 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08005139}
5140
5141static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
5142 u16 bias_value)
5143{
5144 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07005145 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08005146 s32 mv;
5147
5148 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07005149 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08005150 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07005151 z = (tabla->mbhc_data.dce_z);
5152 mb = (tabla->mbhc_data.dce_mb);
5153 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08005154 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005155 z = (tabla->mbhc_data.sta_z);
5156 mb = (tabla->mbhc_data.sta_mb);
5157 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08005158 }
5159
5160 return mv;
5161}
5162
Joonwoo Park03324832012-03-19 19:36:16 -07005163static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005164{
5165 struct delayed_work *delayed_work;
5166 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08005167 short bias_value;
5168 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07005169 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005170
5171 pr_debug("%s:\n", __func__);
5172
5173 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07005174 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08005175 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005176
5177 if (tabla) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005178 if (tabla->mbhc_cfg.button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005179 bias_value = tabla_codec_read_sta_result(tabla->codec);
5180 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305181 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08005182 bias_value = tabla_codec_read_dce_result(tabla->codec);
5183 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305184 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08005185 pr_debug("%s: Reporting long button press event"
5186 " STA: %d, DCE: %d\n", __func__,
5187 sta_mv, dce_mv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005188 tabla_snd_soc_jack_report(tabla,
5189 tabla->mbhc_cfg.button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07005190 tabla->buttons_pressed,
5191 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005192 }
5193 } else {
5194 pr_err("%s: Bad tabla private data\n", __func__);
5195 }
5196
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005197 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07005198 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005199}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07005200
Joonwoo Park0976d012011-12-22 11:48:18 -08005201void tabla_mbhc_cal(struct snd_soc_codec *codec)
5202{
5203 struct tabla_priv *tabla;
5204 struct tabla_mbhc_btn_detect_cfg *btn_det;
5205 u8 cfilt_mode, bg_mode;
5206 u8 ncic, nmeas, navg;
5207 u32 mclk_rate;
5208 u32 dce_wait, sta_wait;
5209 u8 *n_cic;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005210 void *calibration;
Joonwoo Park0976d012011-12-22 11:48:18 -08005211
5212 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005213 calibration = tabla->mbhc_cfg.calibration;
5214
5215 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
5216 tabla_turn_onoff_rel_detection(codec, false);
Joonwoo Park0976d012011-12-22 11:48:18 -08005217
5218 /* First compute the DCE / STA wait times
5219 * depending on tunable parameters.
5220 * The value is computed in microseconds
5221 */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005222 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005223 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08005224 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005225 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
5226 navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
5227 mclk_rate = tabla->mbhc_cfg.mclk_rate;
Joonwoo Park433149a2012-01-11 09:53:54 -08005228 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
5229 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08005230
5231 tabla->mbhc_data.t_dce = dce_wait;
5232 tabla->mbhc_data.t_sta = sta_wait;
5233
5234 /* LDOH and CFILT are already configured during pdata handling.
5235 * Only need to make sure CFILT and bandgap are in Fast mode.
5236 * Need to restore defaults once calculation is done.
5237 */
5238 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
5239 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40, 0x00);
5240 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
5241 0x02);
5242
5243 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
5244 * to perform ADC calibration
5245 */
5246 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005247 tabla->mbhc_cfg.micbias << 5);
Joonwoo Park0976d012011-12-22 11:48:18 -08005248 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
5249 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
5250 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
5251 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
5252
5253 /* DCE measurement for 0 volts */
5254 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
5255 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
5256 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08005257 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
5258 usleep_range(100, 100);
5259 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
5260 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
5261 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
5262
5263 /* DCE measurment for MB voltage */
5264 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
5265 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
5266 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
5267 usleep_range(100, 100);
5268 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
5269 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
5270 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
5271
5272 /* Sta measuremnt for 0 volts */
5273 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
5274 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
5275 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08005276 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
5277 usleep_range(100, 100);
5278 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
5279 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
5280 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
5281
5282 /* STA Measurement for MB Voltage */
5283 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
5284 usleep_range(100, 100);
5285 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
5286 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
5287 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
5288
5289 /* Restore default settings. */
5290 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
5291 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
5292 cfilt_mode);
5293 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
5294
5295 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
5296 usleep_range(100, 100);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005297
5298 wcd9xxx_enable_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL);
5299 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08005300}
5301
5302void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
5303 const enum tabla_mbhc_btn_det_mem mem)
5304{
5305 void *ret = &btn_det->_v_btn_low;
5306
5307 switch (mem) {
5308 case TABLA_BTN_DET_GAIN:
5309 ret += sizeof(btn_det->_n_cic);
5310 case TABLA_BTN_DET_N_CIC:
5311 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08005312 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08005313 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
5314 case TABLA_BTN_DET_V_BTN_HIGH:
5315 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
5316 case TABLA_BTN_DET_V_BTN_LOW:
5317 /* do nothing */
5318 break;
5319 default:
5320 ret = NULL;
5321 }
5322
5323 return ret;
5324}
5325
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005326static s16 tabla_scale_v_micb_vddio(struct tabla_priv *tabla, int v,
5327 bool tovddio)
5328{
5329 int r;
5330 int vddio_k, mb_k;
5331 vddio_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
5332 VDDIO_MICBIAS_MV);
5333 mb_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
5334 tabla->mbhc_data.micb_mv);
5335 if (tovddio)
5336 r = v * vddio_k / mb_k;
5337 else
5338 r = v * mb_k / vddio_k;
5339 return r;
5340}
5341
Joonwoo Park0976d012011-12-22 11:48:18 -08005342static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
5343{
5344 struct tabla_priv *tabla;
5345 s16 btn_mv = 0, btn_delta_mv;
5346 struct tabla_mbhc_btn_detect_cfg *btn_det;
5347 struct tabla_mbhc_plug_type_cfg *plug_type;
5348 u16 *btn_high;
Joonwoo Parkc0672392012-01-11 11:03:14 -08005349 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08005350 int i;
5351
5352 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005353 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
5354 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005355
Joonwoo Parkc0672392012-01-11 11:03:14 -08005356 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005357 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07005358 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08005359 tabla->mbhc_data.nbounce_wait = 30;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005360 } else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005361 tabla->mbhc_data.npoll = 7;
5362 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08005363 }
Joonwoo Park0976d012011-12-22 11:48:18 -08005364
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005365 tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
5366 (tabla->mbhc_cfg.mclk_rate / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08005367 n_ready[tabla_codec_mclk_index(tabla)]) +
5368 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08005369 tabla->mbhc_data.v_ins_hu =
5370 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
5371 tabla->mbhc_data.v_ins_h =
5372 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
5373
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005374 tabla->mbhc_data.v_inval_ins_low = TABLA_MBHC_FAKE_INSERT_LOW;
5375 if (tabla->mbhc_cfg.gpio)
5376 tabla->mbhc_data.v_inval_ins_high =
5377 TABLA_MBHC_FAKE_INSERT_HIGH;
5378 else
5379 tabla->mbhc_data.v_inval_ins_high =
5380 TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
5381
5382 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
5383 tabla->mbhc_data.adj_v_hs_max =
5384 tabla_scale_v_micb_vddio(tabla, plug_type->v_hs_max, true);
5385 tabla->mbhc_data.adj_v_ins_hu =
5386 tabla_codec_v_sta_dce(codec, STA,
5387 tabla->mbhc_data.adj_v_hs_max);
5388 tabla->mbhc_data.adj_v_ins_h =
5389 tabla_codec_v_sta_dce(codec, DCE,
5390 tabla->mbhc_data.adj_v_hs_max);
5391 tabla->mbhc_data.v_inval_ins_low =
5392 tabla_scale_v_micb_vddio(tabla,
5393 tabla->mbhc_data.v_inval_ins_low,
5394 false);
5395 tabla->mbhc_data.v_inval_ins_high =
5396 tabla_scale_v_micb_vddio(tabla,
5397 tabla->mbhc_data.v_inval_ins_high,
5398 false);
5399 }
5400
Joonwoo Park0976d012011-12-22 11:48:18 -08005401 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
5402 for (i = 0; i < btn_det->num_btn; i++)
5403 btn_mv = btn_high[i] > btn_mv ? btn_high[i] : btn_mv;
5404
5405 tabla->mbhc_data.v_b1_h = tabla_codec_v_sta_dce(codec, DCE, btn_mv);
5406 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_sta;
Joonwoo Park0976d012011-12-22 11:48:18 -08005407 tabla->mbhc_data.v_b1_hu =
5408 tabla_codec_v_sta_dce(codec, STA, btn_delta_mv);
5409
5410 btn_delta_mv = btn_mv + btn_det->v_btn_press_delta_cic;
5411
5412 tabla->mbhc_data.v_b1_huc =
5413 tabla_codec_v_sta_dce(codec, DCE, btn_delta_mv);
5414
5415 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
Joonwoo Park03324832012-03-19 19:36:16 -07005416 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
Joonwoo Park0976d012011-12-22 11:48:18 -08005417
5418 tabla->mbhc_data.v_no_mic =
5419 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
5420}
5421
5422void tabla_mbhc_init(struct snd_soc_codec *codec)
5423{
5424 struct tabla_priv *tabla;
5425 struct tabla_mbhc_general_cfg *generic;
5426 struct tabla_mbhc_btn_detect_cfg *btn_det;
5427 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08005428 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305429 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08005430
5431 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005432 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
5433 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08005434
Joonwoo Park0976d012011-12-22 11:48:18 -08005435 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08005436 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08005437 snd_soc_update_bits(codec,
5438 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
5439 0x07, n);
5440 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
5441 btn_det->c[n]);
5442 }
5443 }
5444 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
5445 btn_det->nc);
5446
5447 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
5448 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08005449 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08005450
5451 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08005452 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
5453 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08005454
5455 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
5456 generic->mbhc_nsa << 4);
5457
5458 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
5459 btn_det->n_meas);
5460
5461 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
5462
5463 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
5464
5465 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
5466 btn_det->mbhc_nsc << 3);
5467
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08005468 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
5469 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08005470
5471 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07005472
5473 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Park0976d012011-12-22 11:48:18 -08005474}
5475
Patrick Lai64b43262011-12-06 17:29:15 -08005476static bool tabla_mbhc_fw_validate(const struct firmware *fw)
5477{
5478 u32 cfg_offset;
5479 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
5480 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
5481
5482 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
5483 return false;
5484
5485 /* previous check guarantees that there is enough fw data up
5486 * to num_btn
5487 */
5488 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
5489 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
5490 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
5491 return false;
5492
5493 /* previous check guarantees that there is enough fw data up
5494 * to start of impedance detection configuration
5495 */
5496 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
5497 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
5498
5499 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
5500 return false;
5501
5502 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
5503 return false;
5504
5505 return true;
5506}
Joonwoo Park03324832012-03-19 19:36:16 -07005507
Joonwoo Parkfee17432012-04-16 16:33:55 -07005508/* called under codec_resource_lock acquisition */
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005509static int tabla_determine_button(const struct tabla_priv *priv,
Joonwoo Parkfee17432012-04-16 16:33:55 -07005510 const s32 micmv)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005511{
5512 s16 *v_btn_low, *v_btn_high;
5513 struct tabla_mbhc_btn_detect_cfg *btn_det;
5514 int i, btn = -1;
5515
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005516 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005517 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
5518 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305519 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Parkfee17432012-04-16 16:33:55 -07005520
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005521 for (i = 0; i < btn_det->num_btn; i++) {
Joonwoo Parkfee17432012-04-16 16:33:55 -07005522 if ((v_btn_low[i] <= micmv) && (v_btn_high[i] >= micmv)) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005523 btn = i;
5524 break;
5525 }
5526 }
5527
5528 if (btn == -1)
5529 pr_debug("%s: couldn't find button number for mic mv %d\n",
Joonwoo Parkfee17432012-04-16 16:33:55 -07005530 __func__, micmv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005531
5532 return btn;
5533}
5534
5535static int tabla_get_button_mask(const int btn)
5536{
5537 int mask = 0;
5538 switch (btn) {
5539 case 0:
5540 mask = SND_JACK_BTN_0;
5541 break;
5542 case 1:
5543 mask = SND_JACK_BTN_1;
5544 break;
5545 case 2:
5546 mask = SND_JACK_BTN_2;
5547 break;
5548 case 3:
5549 mask = SND_JACK_BTN_3;
5550 break;
5551 case 4:
5552 mask = SND_JACK_BTN_4;
5553 break;
5554 case 5:
5555 mask = SND_JACK_BTN_5;
5556 break;
5557 case 6:
5558 mask = SND_JACK_BTN_6;
5559 break;
5560 case 7:
5561 mask = SND_JACK_BTN_7;
5562 break;
5563 }
5564 return mask;
5565}
5566
Bradley Rubincb1e2732011-06-23 16:49:20 -07005567static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005568{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005569 int i, mask;
Joonwoo Parkfee17432012-04-16 16:33:55 -07005570 short dce, sta;
5571 s32 mv, mv_s, stamv_s;
5572 bool vddio;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005573 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005574 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005575 const struct tabla_mbhc_btn_detect_cfg *d =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005576 TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005577 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005578 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305579 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07005580 int n_btn_meas = d->n_btn_meas;
5581 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07005582
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005583 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005584
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005585 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5586 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
5587 pr_debug("%s: mbhc is being recovered, skip button press\n",
5588 __func__);
5589 goto done;
5590 }
5591
5592 priv->mbhc_state = MBHC_STATE_POTENTIAL;
5593
5594 if (!priv->mbhc_polling_active) {
5595 pr_warn("%s: mbhc polling is not active, skip button press\n",
5596 __func__);
5597 goto done;
5598 }
Joonwoo Park03324832012-03-19 19:36:16 -07005599
5600 dce = tabla_codec_read_dce_result(codec);
5601 mv = tabla_codec_sta_dce_v(codec, 1, dce);
5602
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005603 /* If GPIO interrupt already kicked in, ignore button press */
5604 if (priv->in_gpio_handler) {
5605 pr_debug("%s: GPIO State Changed, ignore button press\n",
5606 __func__);
5607 btn = -1;
5608 goto done;
5609 }
5610
Joonwoo Parkfee17432012-04-16 16:33:55 -07005611 vddio = (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
5612 priv->mbhc_micbias_switched);
5613 mv_s = vddio ? tabla_scale_v_micb_vddio(priv, mv, false) : mv;
5614
Joonwoo Park03324832012-03-19 19:36:16 -07005615 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
5616 if (priv->mbhc_last_resume &&
5617 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
5618 pr_debug("%s: Button is already released shortly after "
5619 "resume\n", __func__);
5620 n_btn_meas = 0;
5621 } else {
5622 pr_debug("%s: Button is already released without "
5623 "resume", __func__);
5624 sta = tabla_codec_read_sta_result(codec);
Joonwoo Parkfee17432012-04-16 16:33:55 -07005625 stamv_s = tabla_codec_sta_dce_v(codec, 0, sta);
5626 if (vddio)
5627 stamv_s = tabla_scale_v_micb_vddio(priv,
5628 stamv_s,
5629 false);
5630 btn = tabla_determine_button(priv, mv_s);
5631 if (btn != tabla_determine_button(priv, stamv_s))
Joonwoo Park03324832012-03-19 19:36:16 -07005632 btn = -1;
5633 goto done;
5634 }
5635 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005636
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005637 /* determine pressed button */
Joonwoo Parkfee17432012-04-16 16:33:55 -07005638 btnmeas[meas++] = tabla_determine_button(priv, mv_s);
5639 pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n", __func__,
5640 meas - 1, dce, mv, mv_s, btnmeas[meas - 1]);
Joonwoo Park03324832012-03-19 19:36:16 -07005641 if (n_btn_meas == 0)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005642 btn = btnmeas[0];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005643 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
Joonwoo Parkfee17432012-04-16 16:33:55 -07005644 dce = tabla_codec_sta_dce(codec, 1, false);
5645 mv = tabla_codec_sta_dce_v(codec, 1, dce);
5646 mv_s = vddio ? tabla_scale_v_micb_vddio(priv, mv, false) : mv;
5647
5648 btnmeas[meas] = tabla_determine_button(priv, mv_s);
5649 pr_debug("%s: meas %d - DCE %d,%d,%d button %d\n",
5650 __func__, meas, dce, mv, mv_s, btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005651 /* if large enough measurements are collected,
5652 * start to check if last all n_btn_con measurements were
5653 * in same button low/high range */
5654 if (meas + 1 >= d->n_btn_con) {
5655 for (i = 0; i < d->n_btn_con; i++)
5656 if ((btnmeas[meas] < 0) ||
5657 (btnmeas[meas] != btnmeas[meas - i]))
5658 break;
5659 if (i == d->n_btn_con) {
5660 /* button pressed */
5661 btn = btnmeas[meas];
5662 break;
Joonwoo Park03324832012-03-19 19:36:16 -07005663 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
5664 /* if left measurements are less than n_btn_con,
5665 * it's impossible to find button number */
5666 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005667 }
5668 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005669 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005670
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005671 if (btn >= 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005672 if (priv->in_gpio_handler) {
5673 pr_debug("%s: GPIO already triggered, ignore button "
5674 "press\n", __func__);
5675 goto done;
5676 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005677 mask = tabla_get_button_mask(btn);
5678 priv->buttons_pressed |= mask;
Joonwoo Park03324832012-03-19 19:36:16 -07005679 wcd9xxx_lock_sleep(core);
5680 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
5681 msecs_to_jiffies(400)) == 0) {
5682 WARN(1, "Button pressed twice without release"
5683 "event\n");
5684 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005685 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08005686 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005687 pr_debug("%s: bogus button press, too short press?\n",
5688 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08005689 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005690
Joonwoo Park03324832012-03-19 19:36:16 -07005691 done:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005692 pr_debug("%s: leave\n", __func__);
5693 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005694 return IRQ_HANDLED;
5695}
5696
Joonwoo Park03324832012-03-19 19:36:16 -07005697static int tabla_is_fake_press(struct tabla_priv *priv)
5698{
5699 int i;
5700 int r = 0;
5701 struct snd_soc_codec *codec = priv->codec;
5702 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005703 s16 mb_v, v_ins_hu, v_ins_h;
5704
5705 v_ins_hu = tabla_get_current_v_ins(priv, true);
5706 v_ins_h = tabla_get_current_v_ins(priv, false);
Joonwoo Park03324832012-03-19 19:36:16 -07005707
5708 for (i = 0; i < dces; i++) {
5709 usleep_range(10000, 10000);
5710 if (i == 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005711 mb_v = tabla_codec_sta_dce(codec, 0, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005712 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
5713 tabla_codec_sta_dce_v(codec, 0, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005714 if (mb_v < (s16)priv->mbhc_data.v_b1_hu ||
5715 mb_v > v_ins_hu) {
Joonwoo Park03324832012-03-19 19:36:16 -07005716 r = 1;
5717 break;
5718 }
5719 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005720 mb_v = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park03324832012-03-19 19:36:16 -07005721 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
5722 tabla_codec_sta_dce_v(codec, 1, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005723 if (mb_v < (s16)priv->mbhc_data.v_b1_h ||
5724 mb_v > v_ins_h) {
Joonwoo Park03324832012-03-19 19:36:16 -07005725 r = 1;
5726 break;
5727 }
5728 }
5729 }
5730
5731 return r;
5732}
5733
Bradley Rubincb1e2732011-06-23 16:49:20 -07005734static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005735{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08005736 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08005737 struct tabla_priv *priv = data;
5738 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005739
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005740 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07005741
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005742 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
5743 priv->mbhc_state = MBHC_STATE_RELEASE;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005744
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005745 tabla_codec_drive_v_to_micbias(codec, 10000);
5746
Joonwoo Park03324832012-03-19 19:36:16 -07005747 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005748 ret = tabla_cancel_btn_work(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005749 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07005750 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005751 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005752 if (priv->mbhc_cfg.button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08005753 tabla_snd_soc_jack_report(priv,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005754 priv->mbhc_cfg.button_jack, 0,
5755 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005756 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07005757 if (tabla_is_fake_press(priv)) {
5758 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005759 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005760 } else if (priv->mbhc_cfg.button_jack) {
5761 if (priv->in_gpio_handler) {
5762 pr_debug("%s: GPIO kicked in, ignore\n",
5763 __func__);
5764 } else {
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005765 pr_debug("%s: Reporting short button "
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005766 "press and release\n",
5767 __func__);
5768 tabla_snd_soc_jack_report(priv,
5769 priv->mbhc_cfg.button_jack,
5770 priv->buttons_pressed,
5771 priv->buttons_pressed);
5772 tabla_snd_soc_jack_report(priv,
5773 priv->mbhc_cfg.button_jack, 0,
5774 priv->buttons_pressed);
5775 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07005776 }
5777 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005778
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08005779 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
5780 }
5781
Joonwoo Park03324832012-03-19 19:36:16 -07005782 tabla_codec_calibrate_hs_polling(codec);
5783
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005784 if (priv->mbhc_cfg.gpio)
5785 msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
Joonwoo Park03324832012-03-19 19:36:16 -07005786
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005787 tabla_codec_start_hs_polling(codec);
5788
5789 pr_debug("%s: leave\n", __func__);
5790 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005791 return IRQ_HANDLED;
5792}
5793
Bradley Rubincb1e2732011-06-23 16:49:20 -07005794static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
5795{
5796 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08005797 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005798 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005799
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005800 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005801 tabla_codec_enable_config_mode(codec, 1);
5802
5803 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
5804 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005805
Joonwoo Park0976d012011-12-22 11:48:18 -08005806 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
5807
5808 usleep_range(generic->t_shutdown_plug_rem,
5809 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005810
5811 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005812 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005813 tabla_codec_enable_config_mode(codec, 0);
5814
5815 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
5816}
5817
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005818static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005819{
5820 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005821
5822 tabla_codec_shutdown_hs_removal_detect(codec);
5823
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005824 if (!tabla->mclk_enabled) {
Asish Bhattacharya486745a2012-01-20 06:41:53 +05305825 tabla_codec_disable_clock_block(codec);
5826 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005827 }
5828
5829 tabla->mbhc_polling_active = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005830 tabla->mbhc_state = MBHC_STATE_NONE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005831}
5832
Patrick Lai49efeac2011-11-03 11:01:12 -07005833static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
5834{
5835 struct tabla_priv *tabla = data;
5836 struct snd_soc_codec *codec;
5837
5838 pr_info("%s: received HPHL OCP irq\n", __func__);
5839
5840 if (tabla) {
5841 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005842 if (tabla->hphlocp_cnt++ < TABLA_OCP_ATTEMPT) {
5843 pr_info("%s: retry\n", __func__);
5844 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5845 0x00);
5846 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5847 0x10);
5848 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305849 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005850 TABLA_IRQ_HPH_PA_OCPL_FAULT);
5851 tabla->hphlocp_cnt = 0;
5852 tabla->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005853 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005854 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005855 tabla->mbhc_cfg.headset_jack,
5856 tabla->hph_status,
5857 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005858 }
5859 } else {
5860 pr_err("%s: Bad tabla private data\n", __func__);
5861 }
5862
5863 return IRQ_HANDLED;
5864}
5865
5866static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
5867{
5868 struct tabla_priv *tabla = data;
5869 struct snd_soc_codec *codec;
5870
5871 pr_info("%s: received HPHR OCP irq\n", __func__);
5872
5873 if (tabla) {
5874 codec = tabla->codec;
Patrick Laic7cae882011-11-18 11:52:49 -08005875 if (tabla->hphrocp_cnt++ < TABLA_OCP_ATTEMPT) {
5876 pr_info("%s: retry\n", __func__);
5877 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5878 0x00);
5879 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
5880 0x10);
5881 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05305882 wcd9xxx_disable_irq(codec->control_data,
Patrick Laic7cae882011-11-18 11:52:49 -08005883 TABLA_IRQ_HPH_PA_OCPR_FAULT);
5884 tabla->hphrocp_cnt = 0;
5885 tabla->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005886 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08005887 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005888 tabla->mbhc_cfg.headset_jack,
5889 tabla->hph_status,
5890 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07005891 }
5892 } else {
5893 pr_err("%s: Bad tabla private data\n", __func__);
5894 }
5895
5896 return IRQ_HANDLED;
5897}
5898
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005899static bool tabla_is_inval_ins_range(struct snd_soc_codec *codec,
5900 s32 mic_volt, bool highhph, bool *highv)
Joonwoo Park03324832012-03-19 19:36:16 -07005901{
5902 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005903 bool invalid = false;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005904 s16 v_hs_max;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005905
5906 /* Perform this check only when the high voltage headphone
5907 * needs to be considered as invalid
5908 */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005909 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005910 *highv = mic_volt > v_hs_max;
5911 if (!highhph && *highv)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005912 invalid = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005913 else if (mic_volt < tabla->mbhc_data.v_inval_ins_high &&
5914 (mic_volt > tabla->mbhc_data.v_inval_ins_low))
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005915 invalid = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005916
5917 return invalid;
5918}
5919
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005920static bool tabla_is_inval_ins_delta(struct snd_soc_codec *codec,
5921 int mic_volt, int mic_volt_prev,
5922 int threshold)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005923{
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005924 return abs(mic_volt - mic_volt_prev) > threshold;
Joonwoo Park03324832012-03-19 19:36:16 -07005925}
5926
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005927/* called under codec_resource_lock acquisition */
5928void tabla_find_plug_and_report(struct snd_soc_codec *codec,
5929 enum tabla_mbhc_plug_type plug_type)
Joonwoo Park03324832012-03-19 19:36:16 -07005930{
5931 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005932
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005933 if (plug_type == PLUG_TYPE_HEADPHONE &&
5934 tabla->current_plug == PLUG_TYPE_NONE) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005935 /* Nothing was reported previously
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005936 * report a headphone or unsupported
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005937 */
5938 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5939 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005940 } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
5941 if (tabla->current_plug == PLUG_TYPE_HEADSET)
5942 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
5943 else if (tabla->current_plug == PLUG_TYPE_HEADPHONE)
5944 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
5945
5946 tabla_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
5947 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005948 } else if (plug_type == PLUG_TYPE_HEADSET) {
5949 /* If Headphone was reported previously, this will
5950 * only report the mic line
5951 */
5952 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
5953 msleep(100);
5954 tabla_codec_start_hs_polling(codec);
5955 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
5956 if (tabla->current_plug == PLUG_TYPE_NONE)
5957 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
5958 tabla_codec_cleanup_hs_polling(codec);
5959 pr_debug("setup mic trigger for further detection\n");
5960 tabla->lpi_enabled = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005961 tabla_codec_enable_hs_detect(codec, 1,
5962 MBHC_USE_MB_TRIGGER |
5963 MBHC_USE_HPHL_TRIGGER,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005964 false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005965 } else {
5966 WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
5967 tabla->current_plug, plug_type);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005968 }
5969}
5970
5971/* should be called under interrupt context that hold suspend */
5972static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla)
5973{
5974 pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
5975 tabla->hs_detect_work_stop = false;
5976 wcd9xxx_lock_sleep(tabla->codec->control_data);
5977 schedule_work(&tabla->hs_correct_plug_work);
5978}
5979
5980/* called under codec_resource_lock acquisition */
5981static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla)
5982{
5983 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
5984 tabla->hs_detect_work_stop = true;
5985 wmb();
5986 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5987 if (cancel_work_sync(&tabla->hs_correct_plug_work)) {
5988 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
5989 wcd9xxx_unlock_sleep(tabla->codec->control_data);
5990 }
5991 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5992}
5993
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005994static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
5995{
5996 return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
5997 tabla->mbhc_cfg.gpio_level_insert);
5998}
5999
Joonwoo Park41956722012-04-18 13:13:07 -07006000/* called under codec_resource_lock acquisition */
6001static void tabla_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
6002{
6003 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, on);
6004 if (on)
6005 usleep_range(5000, 5000);
6006}
6007
6008/* called under codec_resource_lock acquisition and mbhc override = 1 */
6009static enum tabla_mbhc_plug_type
6010tabla_codec_get_plug_type(struct snd_soc_codec *codec, bool highhph)
6011{
6012 int i;
6013 bool gndswitch, vddioswitch;
6014 int scaled;
6015 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
6016 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6017 const bool vddio = (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV);
6018 int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
6019 enum tabla_mbhc_plug_type plug_type[num_det];
6020 s16 mb_v[num_det];
6021 s32 mic_mv[num_det];
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006022 bool inval;
6023 bool highdelta;
6024 bool ahighv = false, highv;
Joonwoo Park41956722012-04-18 13:13:07 -07006025
6026 /* make sure override is on */
6027 WARN_ON(!(snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04));
6028
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006029 /* GND and MIC swap detection requires at least 2 rounds of DCE */
6030 BUG_ON(num_det < 2);
6031
6032 plug_type_ptr =
6033 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
6034
6035 plug_type[0] = PLUG_TYPE_INVALID;
6036
Joonwoo Park41956722012-04-18 13:13:07 -07006037 /* performs DCEs for N times
6038 * 1st: check if voltage is in invalid range
6039 * 2nd - N-2nd: check voltage range and delta
6040 * N-1st: check voltage range, delta with HPHR GND switch
6041 * Nth: check voltage range with VDDIO switch if micbias V != vddio V*/
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006042 for (i = 0; i < num_det; i++) {
Joonwoo Park41956722012-04-18 13:13:07 -07006043 gndswitch = (i == (num_det - 1 - vddio));
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006044 vddioswitch = (vddio && ((i == num_det - 1) ||
6045 (i == num_det - 2)));
Joonwoo Park41956722012-04-18 13:13:07 -07006046 if (i == 0) {
6047 mb_v[i] = tabla_codec_setup_hs_polling(codec);
6048 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006049 inval = tabla_is_inval_ins_range(codec, mic_mv[i],
6050 highhph, &highv);
6051 ahighv |= highv;
Joonwoo Park41956722012-04-18 13:13:07 -07006052 scaled = mic_mv[i];
Joonwoo Park41956722012-04-18 13:13:07 -07006053 } else {
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006054 if (vddioswitch)
6055 __tabla_codec_switch_micbias(tabla->codec, 1,
6056 false, false);
Joonwoo Park41956722012-04-18 13:13:07 -07006057 if (gndswitch)
6058 tabla_codec_hphr_gnd_switch(codec, true);
6059 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
6060 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006061 if (vddioswitch)
6062 scaled = tabla_scale_v_micb_vddio(tabla,
Joonwoo Park41956722012-04-18 13:13:07 -07006063 mic_mv[i],
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006064 false);
6065 else
6066 scaled = mic_mv[i];
6067 /* !gndswitch & vddioswitch means the previous DCE
6068 * was done with gndswitch, don't compare with DCE
6069 * with gndswitch */
6070 highdelta = tabla_is_inval_ins_delta(codec, scaled,
6071 mic_mv[i - !gndswitch - vddioswitch],
6072 TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV);
6073 inval = (tabla_is_inval_ins_range(codec, mic_mv[i],
6074 highhph, &highv) ||
6075 highdelta);
6076 ahighv |= highv;
Joonwoo Park41956722012-04-18 13:13:07 -07006077 if (gndswitch)
6078 tabla_codec_hphr_gnd_switch(codec, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006079 if (vddioswitch)
6080 __tabla_codec_switch_micbias(tabla->codec, 0,
6081 false, false);
6082 /* claim UNSUPPORTED plug insertion when
6083 * good headset is detected but HPHR GND switch makes
6084 * delta difference */
6085 if (i == (num_det - 2) && highdelta && !ahighv)
6086 plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
6087 else if (i == (num_det - 1) && inval)
6088 plug_type[0] = PLUG_TYPE_INVALID;
Joonwoo Park41956722012-04-18 13:13:07 -07006089 }
6090 pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006091 "VDDIO %d, inval %d\n", __func__,
Joonwoo Park41956722012-04-18 13:13:07 -07006092 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006093 vddioswitch, inval);
6094 /* don't need to run further DCEs */
6095 if (ahighv && inval)
6096 break;
6097 mic_mv[i] = scaled;
Joonwoo Park41956722012-04-18 13:13:07 -07006098 }
6099
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006100 for (i = 0; (plug_type[0] != PLUG_TYPE_GND_MIC_SWAP && !inval) &&
6101 i < num_det; i++) {
Joonwoo Park41956722012-04-18 13:13:07 -07006102 /*
6103 * If we are here, means none of the all
6104 * measurements are fake, continue plug type detection.
6105 * If all three measurements do not produce same
6106 * plug type, restart insertion detection
6107 */
6108 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
6109 plug_type[i] = PLUG_TYPE_HEADPHONE;
6110 pr_debug("%s: Detect attempt %d, detected Headphone\n",
6111 __func__, i);
6112 } else if (highhph && (mic_mv[i] > plug_type_ptr->v_hs_max)) {
6113 plug_type[i] = PLUG_TYPE_HIGH_HPH;
6114 pr_debug("%s: Detect attempt %d, detected High "
6115 "Headphone\n", __func__, i);
6116 } else {
6117 plug_type[i] = PLUG_TYPE_HEADSET;
6118 pr_debug("%s: Detect attempt %d, detected Headset\n",
6119 __func__, i);
6120 }
6121
6122 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
6123 pr_err("%s: Detect attempt %d and %d are not same",
6124 __func__, i - 1, i);
6125 plug_type[0] = PLUG_TYPE_INVALID;
6126 inval = true;
6127 break;
6128 }
6129 }
6130
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006131 pr_debug("%s: Detected plug type %d\n", __func__, plug_type[0]);
Joonwoo Park41956722012-04-18 13:13:07 -07006132 return plug_type[0];
6133}
6134
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006135static void tabla_hs_correct_gpio_plug(struct work_struct *work)
6136{
6137 struct tabla_priv *tabla;
6138 struct snd_soc_codec *codec;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006139 int retry = 0, pt_gnd_mic_swap_cnt = 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006140 bool correction = false;
Joonwoo Park41956722012-04-18 13:13:07 -07006141 enum tabla_mbhc_plug_type plug_type;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006142 unsigned long timeout;
6143
6144 tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
6145 codec = tabla->codec;
6146
6147 pr_debug("%s: enter\n", __func__);
6148 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
6149
6150 /* Keep override on during entire plug type correction work.
6151 *
6152 * This is okay under the assumption that any GPIO irqs which use
6153 * MBHC block cancel and sync this work so override is off again
6154 * prior to GPIO interrupt handler's MBHC block usage.
6155 * Also while this correction work is running, we can guarantee
6156 * DAPM doesn't use any MBHC block as this work only runs with
6157 * headphone detection.
6158 */
6159 tabla_turn_onoff_override(codec, true);
6160
6161 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
6162 while (!time_after(jiffies, timeout)) {
6163 ++retry;
6164 rmb();
6165 if (tabla->hs_detect_work_stop) {
6166 pr_debug("%s: stop requested\n", __func__);
6167 break;
6168 }
6169
6170 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
6171 if (tabla_hs_gpio_level_remove(tabla)) {
6172 pr_debug("%s: GPIO value is low\n", __func__);
6173 break;
6174 }
6175
6176 /* can race with removal interrupt */
6177 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park41956722012-04-18 13:13:07 -07006178 plug_type = tabla_codec_get_plug_type(codec, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006179 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6180
Joonwoo Park41956722012-04-18 13:13:07 -07006181 if (plug_type == PLUG_TYPE_INVALID) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006182 pr_debug("Invalid plug in attempt # %d\n", retry);
6183 if (retry == NUM_ATTEMPTS_TO_REPORT &&
6184 tabla->current_plug == PLUG_TYPE_NONE) {
6185 tabla_codec_report_plug(codec, 1,
6186 SND_JACK_HEADPHONE);
6187 }
Joonwoo Park41956722012-04-18 13:13:07 -07006188 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006189 pr_debug("Good headphone detected, continue polling mic\n");
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006190 if (tabla->current_plug == PLUG_TYPE_NONE)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006191 tabla_codec_report_plug(codec, 1,
6192 SND_JACK_HEADPHONE);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006193 } else {
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006194 if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
6195 pt_gnd_mic_swap_cnt++;
6196 if (pt_gnd_mic_swap_cnt <
6197 TABLA_MBHC_GND_MIC_SWAP_THRESHOLD)
6198 continue;
6199 else if (pt_gnd_mic_swap_cnt >
6200 TABLA_MBHC_GND_MIC_SWAP_THRESHOLD) {
6201 /* This is due to GND/MIC switch didn't
6202 * work, Report unsupported plug */
6203 } else if (tabla->mbhc_cfg.swap_gnd_mic) {
6204 /* if switch is toggled, check again,
6205 * otherwise report unsupported plug */
6206 if (tabla->mbhc_cfg.swap_gnd_mic(codec))
6207 continue;
6208 }
6209 } else
6210 pt_gnd_mic_swap_cnt = 0;
6211
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006212 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
6213 /* Turn off override */
6214 tabla_turn_onoff_override(codec, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006215 /* The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
6216 */
Joonwoo Park41956722012-04-18 13:13:07 -07006217 tabla_find_plug_and_report(codec, plug_type);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006218 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6219 pr_debug("Attempt %d found correct plug %d\n", retry,
Joonwoo Park41956722012-04-18 13:13:07 -07006220 plug_type);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006221 correction = true;
6222 break;
6223 }
6224 }
6225
6226 /* Turn off override */
6227 if (!correction)
6228 tabla_turn_onoff_override(codec, false);
6229
6230 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
6231 pr_debug("%s: leave\n", __func__);
6232 /* unlock sleep */
6233 wcd9xxx_unlock_sleep(tabla->codec->control_data);
6234}
6235
6236/* called under codec_resource_lock acquisition */
6237static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
6238{
Joonwoo Park41956722012-04-18 13:13:07 -07006239 enum tabla_mbhc_plug_type plug_type;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006240 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006241
6242 pr_debug("%s: enter\n", __func__);
6243
6244 tabla_turn_onoff_override(codec, true);
Joonwoo Park41956722012-04-18 13:13:07 -07006245 plug_type = tabla_codec_get_plug_type(codec, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006246 tabla_turn_onoff_override(codec, false);
6247
6248 if (tabla_hs_gpio_level_remove(tabla)) {
6249 pr_debug("%s: GPIO value is low when determining plug\n",
6250 __func__);
6251 return;
6252 }
6253
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006254 if (plug_type == PLUG_TYPE_INVALID ||
6255 plug_type == PLUG_TYPE_GND_MIC_SWAP) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006256 tabla_schedule_hs_detect_plug(tabla);
Joonwoo Park41956722012-04-18 13:13:07 -07006257 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006258 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
6259
6260 tabla_schedule_hs_detect_plug(tabla);
6261 } else {
Joonwoo Park41956722012-04-18 13:13:07 -07006262 pr_debug("%s: Valid plug found, determine plug type %d\n",
6263 __func__, plug_type);
6264 tabla_find_plug_and_report(codec, plug_type);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006265 }
6266}
6267
6268/* called under codec_resource_lock acquisition */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006269static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
6270{
Joonwoo Park41956722012-04-18 13:13:07 -07006271 enum tabla_mbhc_plug_type plug_type;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006272 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6273 const struct tabla_mbhc_plug_detect_cfg *plug_det =
6274 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park03324832012-03-19 19:36:16 -07006275
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006276 /* Turn on the override,
6277 * tabla_codec_setup_hs_polling requires override on */
6278 tabla_turn_onoff_override(codec, true);
Joonwoo Park03324832012-03-19 19:36:16 -07006279
6280 if (plug_det->t_ins_complete > 20)
6281 msleep(plug_det->t_ins_complete);
6282 else
6283 usleep_range(plug_det->t_ins_complete * 1000,
6284 plug_det->t_ins_complete * 1000);
6285
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006286 if (tabla->mbhc_cfg.gpio) {
6287 /* Turn off the override */
6288 tabla_turn_onoff_override(codec, false);
6289 if (tabla_hs_gpio_level_remove(tabla))
6290 pr_debug("%s: GPIO value is low when determining "
6291 "plug\n", __func__);
6292 else
6293 tabla_codec_decide_gpio_plug(codec);
6294 return;
6295 }
6296
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006297 plug_type = tabla_codec_get_plug_type(codec, false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006298 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006299
Joonwoo Park41956722012-04-18 13:13:07 -07006300 if (plug_type == PLUG_TYPE_INVALID) {
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006301 pr_debug("%s: Invalid plug type detected\n", __func__);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006302 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006303 tabla_codec_cleanup_hs_polling(codec);
6304 tabla_codec_enable_hs_detect(codec, 1,
6305 MBHC_USE_MB_TRIGGER |
6306 MBHC_USE_HPHL_TRIGGER, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006307 } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
6308 pr_debug("%s: GND-MIC swapped plug type detected\n", __func__);
6309 tabla_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
6310 tabla_codec_cleanup_hs_polling(codec);
6311 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park41956722012-04-18 13:13:07 -07006312 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
Joonwoo Park03324832012-03-19 19:36:16 -07006313 pr_debug("%s: Headphone Detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006314 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
6315 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07006316 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park41956722012-04-18 13:13:07 -07006317 } else if (plug_type == PLUG_TYPE_HEADSET) {
Joonwoo Park03324832012-03-19 19:36:16 -07006318 pr_debug("%s: Headset detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006319 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
6320
Joonwoo Park03324832012-03-19 19:36:16 -07006321 /* avoid false button press detect */
6322 msleep(50);
Joonwoo Park03324832012-03-19 19:36:16 -07006323 tabla_codec_start_hs_polling(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07006324 }
6325}
6326
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006327/* called only from interrupt which is under codec_resource_lock acquisition */
6328static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
Bradley Rubincb1e2732011-06-23 16:49:20 -07006329{
Bradley Rubincb1e2732011-06-23 16:49:20 -07006330 struct snd_soc_codec *codec = priv->codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006331
6332 if (!is_removal) {
6333 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
6334
6335 rmb();
6336 if (priv->lpi_enabled)
6337 msleep(100);
6338
6339 rmb();
6340 if (!priv->lpi_enabled) {
6341 pr_debug("%s: lpi is disabled\n", __func__);
6342 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
6343 priv->mbhc_cfg.gpio_level_insert) {
6344 pr_debug("%s: Valid insertion, "
6345 "detect plug type\n", __func__);
6346 tabla_codec_decide_gpio_plug(codec);
6347 } else {
6348 pr_debug("%s: Invalid insertion, "
6349 "stop plug detection\n", __func__);
6350 }
6351 } else {
6352 pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
6353 }
6354}
6355
6356/* called only from interrupt which is under codec_resource_lock acquisition */
6357static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
6358 bool is_mb_trigger)
6359{
Joonwoo Park03324832012-03-19 19:36:16 -07006360 int ret;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006361 struct snd_soc_codec *codec = priv->codec;
6362 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006363
6364 if (is_removal) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006365 /* cancel possiblely running hs detect work */
6366 tabla_cancel_hs_detect_plug(priv);
6367
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006368 /*
6369 * If headphone is removed while playback is in progress,
6370 * it is possible that micbias will be switched to VDDIO.
6371 */
Joonwoo Park03324832012-03-19 19:36:16 -07006372 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006373 if (priv->current_plug == PLUG_TYPE_HEADPHONE)
6374 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
6375 else if (priv->current_plug == PLUG_TYPE_GND_MIC_SWAP)
6376 tabla_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
6377 else
6378 WARN(1, "%s: Unexpected current plug type %d\n",
6379 __func__, priv->current_plug);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006380 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006381 tabla_codec_enable_hs_detect(codec, 1,
6382 MBHC_USE_MB_TRIGGER |
6383 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07006384 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006385 } else if (is_mb_trigger && !is_removal) {
Joonwoo Park03324832012-03-19 19:36:16 -07006386 pr_debug("%s: Waiting for Headphone left trigger\n",
6387 __func__);
6388 wcd9xxx_lock_sleep(core);
6389 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
6390 usecs_to_jiffies(1000000)) == 0) {
6391 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
6392 __func__);
6393 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08006394 }
Joonwoo Park03324832012-03-19 19:36:16 -07006395 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
6396 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006397 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006398 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
6399 if (ret != 0) {
6400 pr_debug("%s: Complete plug insertion, Detecting plug "
6401 "type\n", __func__);
6402 tabla_codec_detect_plug_type(codec);
6403 wcd9xxx_unlock_sleep(core);
6404 } else {
6405 wcd9xxx_enable_irq(codec->control_data,
6406 TABLA_IRQ_MBHC_INSERTION);
6407 pr_err("%s: Error detecting plug insertion\n",
6408 __func__);
6409 }
Joonwoo Park03324832012-03-19 19:36:16 -07006410 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006411}
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08006412
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006413static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
6414{
6415 bool is_mb_trigger, is_removal;
6416 struct tabla_priv *priv = data;
6417 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07006418
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006419 pr_debug("%s: enter\n", __func__);
6420 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
6421 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
6422
6423 is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
6424 0x10);
6425 is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
6426 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
6427
6428 /* Turn off both HPH and MIC line schmitt triggers */
6429 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6430 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
6431 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6432
6433 if (priv->mbhc_cfg.gpio)
6434 tabla_hs_insert_irq_gpio(priv, is_removal);
6435 else
6436 tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
6437
6438 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006439 return IRQ_HANDLED;
6440}
6441
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006442static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
6443{
6444 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006445 const struct tabla_mbhc_plug_type_cfg *plug_type =
6446 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
6447 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006448
6449 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006450 && (mic_mv < v_hs_max)) ? true : false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006451}
6452
6453/* called under codec_resource_lock acquisition
6454 * returns true if mic voltage range is back to normal insertion
6455 * returns false either if timedout or removed */
6456static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
6457{
6458 int i;
6459 bool timedout, settled = false;
6460 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
6461 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
6462 unsigned long retry = 0, timeout;
6463 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006464 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006465
6466 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
6467 while (!(timedout = time_after(jiffies, timeout))) {
6468 retry++;
6469 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6470 pr_debug("%s: GPIO indicates removal\n", __func__);
6471 break;
6472 }
6473
6474 if (tabla->mbhc_cfg.gpio) {
6475 if (retry > 1)
6476 msleep(250);
6477 else
6478 msleep(50);
6479 }
6480
6481 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6482 pr_debug("%s: GPIO indicates removal\n", __func__);
6483 break;
6484 }
6485
6486 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
6487 mb_v[i] = tabla_codec_sta_dce(codec, 1, true);
6488 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
6489 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
6490 __func__, retry, mic_mv[i], mb_v[i]);
6491 }
6492
6493 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
6494 pr_debug("%s: GPIO indicates removal\n", __func__);
6495 break;
6496 }
6497
6498 if (tabla->current_plug == PLUG_TYPE_NONE) {
6499 pr_debug("%s : headset/headphone is removed\n",
6500 __func__);
6501 break;
6502 }
6503
6504 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
6505 if (!is_valid_mic_voltage(codec, mic_mv[i]))
6506 break;
6507
6508 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6509 pr_debug("%s: MIC voltage settled\n", __func__);
6510 settled = true;
6511 msleep(200);
6512 break;
6513 }
6514
6515 /* only for non-GPIO remove irq */
6516 if (!tabla->mbhc_cfg.gpio) {
6517 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006518 if (mic_mv[i] < v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006519 break;
6520 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
6521 pr_debug("%s: Headset is removed\n", __func__);
6522 break;
6523 }
6524 }
6525 }
6526
6527 if (timedout)
6528 pr_debug("%s: Microphone did not settle in %d seconds\n",
6529 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
6530 return settled;
6531}
6532
6533/* called only from interrupt which is under codec_resource_lock acquisition */
6534static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
6535{
6536 struct snd_soc_codec *codec = priv->codec;
6537
6538 if (tabla_hs_remove_settle(codec))
6539 tabla_codec_start_hs_polling(codec);
6540 pr_debug("%s: remove settle done\n", __func__);
6541}
6542
6543/* called only from interrupt which is under codec_resource_lock acquisition */
6544static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006545{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006546 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006547 bool removed = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006548 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08006549 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006550 TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006551 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006552
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006553 if (priv->current_plug != PLUG_TYPE_HEADSET) {
6554 pr_debug("%s(): Headset is not inserted, ignore removal\n",
6555 __func__);
6556 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6557 0x08, 0x08);
6558 return;
6559 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006560
Joonwoo Park0976d012011-12-22 11:48:18 -08006561 usleep_range(generic->t_shutdown_plug_rem,
6562 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006563
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006564 do {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006565 bias_value = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006566 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
6567 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006568 if (bias_value < tabla_get_current_v_ins(priv, false)) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006569 pr_debug("%s: checking false removal\n", __func__);
6570 msleep(500);
6571 removed = !tabla_hs_remove_settle(codec);
6572 pr_debug("%s: headset %sactually removed\n", __func__,
6573 removed ? "" : "not ");
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006574 break;
6575 }
6576 min_us -= priv->mbhc_data.t_dce;
6577 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07006578
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006579 if (removed) {
6580 /* cancel possiblely running hs detect work */
6581 tabla_cancel_hs_detect_plug(priv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006582 /*
6583 * If this removal is not false, first check the micbias
6584 * switch status and switch it to LDOH if it is already
6585 * switched to VDDIO.
6586 */
Joonwoo Park03324832012-03-19 19:36:16 -07006587 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07006588
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006589 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6590 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006591 tabla_codec_enable_hs_detect(codec, 1,
6592 MBHC_USE_MB_TRIGGER |
6593 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07006594 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006595 } else {
6596 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006597 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006598}
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006599
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006600static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
6601{
6602 struct tabla_priv *priv = data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006603 bool vddio;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006604 pr_debug("%s: enter, removal interrupt\n", __func__);
6605
6606 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006607 vddio = (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
6608 priv->mbhc_micbias_switched);
6609 if (vddio)
6610 __tabla_codec_switch_micbias(priv->codec, 0, false, true);
6611
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006612 if (priv->mbhc_cfg.gpio)
6613 tabla_hs_remove_irq_gpio(priv);
6614 else
6615 tabla_hs_remove_irq_nogpio(priv);
6616
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006617 /* if driver turned off vddio switch and headset is not removed,
6618 * turn on the vddio switch back, if headset is removed then vddio
6619 * switch is off by time now and shouldn't be turn on again from here */
6620 if (vddio && priv->current_plug == PLUG_TYPE_HEADSET)
6621 __tabla_codec_switch_micbias(priv->codec, 1, true, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006622 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006623
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006624 return IRQ_HANDLED;
6625}
6626
Joonwoo Park03324832012-03-19 19:36:16 -07006627void mbhc_insert_work(struct work_struct *work)
6628{
6629 struct delayed_work *dwork;
6630 struct tabla_priv *tabla;
6631 struct snd_soc_codec *codec;
6632 struct wcd9xxx *tabla_core;
6633
6634 dwork = to_delayed_work(work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006635 tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
Joonwoo Park03324832012-03-19 19:36:16 -07006636 codec = tabla->codec;
6637 tabla_core = dev_get_drvdata(codec->dev->parent);
6638
6639 pr_debug("%s:\n", __func__);
6640
6641 /* Turn off both HPH and MIC line schmitt triggers */
6642 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6643 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
6644 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6645 wcd9xxx_disable_irq_sync(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
6646 tabla_codec_detect_plug_type(codec);
6647 wcd9xxx_unlock_sleep(tabla_core);
6648}
6649
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006650static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
6651{
6652 bool insert;
6653 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
6654 bool is_removed = false;
6655
6656 pr_debug("%s: enter\n", __func__);
6657
6658 tabla->in_gpio_handler = true;
6659 /* Wait here for debounce time */
6660 usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
6661 TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
6662
6663 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
6664
6665 /* cancel pending button press */
6666 if (tabla_cancel_btn_work(tabla))
6667 pr_debug("%s: button press is canceled\n", __func__);
6668
6669 insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
6670 tabla->mbhc_cfg.gpio_level_insert);
6671 if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
6672 tabla->lpi_enabled = false;
6673 wmb();
6674
6675 /* cancel detect plug */
6676 tabla_cancel_hs_detect_plug(tabla);
6677
6678 /* Disable Mic Bias pull down and HPH Switch to GND */
6679 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
6680 0x00);
6681 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
6682 tabla_codec_detect_plug_type(codec);
6683 } else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
6684 tabla->lpi_enabled = false;
6685 wmb();
6686
6687 /* cancel detect plug */
6688 tabla_cancel_hs_detect_plug(tabla);
6689
6690 if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
6691 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
6692 is_removed = true;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07006693 } else if (tabla->current_plug == PLUG_TYPE_GND_MIC_SWAP) {
6694 tabla_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
6695 is_removed = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006696 } else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
6697 tabla_codec_pause_hs_polling(codec);
6698 tabla_codec_cleanup_hs_polling(codec);
6699 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
6700 is_removed = true;
6701 }
6702
6703 if (is_removed) {
6704 /* Enable Mic Bias pull down and HPH Switch to GND */
6705 snd_soc_update_bits(codec,
6706 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6707 0x01);
6708 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
6709 0x01);
6710 /* Make sure mic trigger is turned off */
6711 snd_soc_update_bits(codec,
6712 tabla->mbhc_bias_regs.ctl_reg,
6713 0x01, 0x01);
6714 snd_soc_update_bits(codec,
6715 tabla->mbhc_bias_regs.mbhc_reg,
6716 0x90, 0x00);
6717 /* Reset MBHC State Machine */
6718 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6719 0x08, 0x08);
6720 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
6721 0x08, 0x00);
6722 /* Turn off override */
6723 tabla_turn_onoff_override(codec, false);
6724 }
6725 }
6726
6727 tabla->in_gpio_handler = false;
6728 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
6729 pr_debug("%s: leave\n", __func__);
6730}
6731
6732static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
6733{
6734 int r = IRQ_HANDLED;
6735 struct snd_soc_codec *codec = data;
6736
6737 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
6738 pr_warn("%s: failed to hold suspend\n", __func__);
6739 r = IRQ_NONE;
6740 } else {
6741 tabla_hs_gpio_handler(codec);
6742 wcd9xxx_unlock_sleep(codec->control_data);
6743 }
6744
6745 return r;
6746}
6747
Joonwoo Park1305bab2012-05-21 15:08:42 -07006748static int tabla_mbhc_init_and_calibrate(struct tabla_priv *tabla)
6749{
6750 int ret = 0;
6751 struct snd_soc_codec *codec = tabla->codec;
6752
6753 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
6754 tabla_mbhc_init(codec);
6755 tabla_mbhc_cal(codec);
6756 tabla_mbhc_calc_thres(codec);
6757 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
6758 tabla_codec_calibrate_hs_polling(codec);
6759 if (!tabla->mbhc_cfg.gpio) {
6760 ret = tabla_codec_enable_hs_detect(codec, 1,
6761 MBHC_USE_MB_TRIGGER |
6762 MBHC_USE_HPHL_TRIGGER,
6763 false);
6764
6765 if (IS_ERR_VALUE(ret))
6766 pr_err("%s: Failed to setup MBHC detection\n",
6767 __func__);
6768 } else {
6769 /* Enable Mic Bias pull down and HPH Switch to GND */
6770 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
6771 0x01, 0x01);
6772 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x01);
6773 INIT_WORK(&tabla->hs_correct_plug_work,
6774 tabla_hs_correct_gpio_plug);
6775 }
6776
6777 if (!IS_ERR_VALUE(ret)) {
6778 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
6779 wcd9xxx_enable_irq(codec->control_data,
6780 TABLA_IRQ_HPH_PA_OCPL_FAULT);
6781 wcd9xxx_enable_irq(codec->control_data,
6782 TABLA_IRQ_HPH_PA_OCPR_FAULT);
6783
6784 if (tabla->mbhc_cfg.gpio) {
6785 ret = request_threaded_irq(tabla->mbhc_cfg.gpio_irq,
6786 NULL,
6787 tabla_mechanical_plug_detect_irq,
6788 (IRQF_TRIGGER_RISING |
6789 IRQF_TRIGGER_FALLING),
6790 "tabla-gpio", codec);
6791 if (!IS_ERR_VALUE(ret)) {
6792 ret = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
6793 /* Bootup time detection */
6794 tabla_hs_gpio_handler(codec);
6795 }
6796 }
6797 }
6798
6799 return ret;
6800}
6801
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006802static void mbhc_fw_read(struct work_struct *work)
6803{
6804 struct delayed_work *dwork;
6805 struct tabla_priv *tabla;
6806 struct snd_soc_codec *codec;
6807 const struct firmware *fw;
Joonwoo Park1305bab2012-05-21 15:08:42 -07006808 int ret = -1, retry = 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006809
6810 dwork = to_delayed_work(work);
Joonwoo Park1305bab2012-05-21 15:08:42 -07006811 tabla = container_of(dwork, struct tabla_priv, mbhc_firmware_dwork);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006812 codec = tabla->codec;
6813
6814 while (retry < MBHC_FW_READ_ATTEMPTS) {
6815 retry++;
6816 pr_info("%s:Attempt %d to request MBHC firmware\n",
6817 __func__, retry);
6818 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
6819 codec->dev);
6820
6821 if (ret != 0) {
6822 usleep_range(MBHC_FW_READ_TIMEOUT,
Joonwoo Park1305bab2012-05-21 15:08:42 -07006823 MBHC_FW_READ_TIMEOUT);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006824 } else {
6825 pr_info("%s: MBHC Firmware read succesful\n", __func__);
6826 break;
6827 }
6828 }
6829
6830 if (ret != 0) {
6831 pr_err("%s: Cannot load MBHC firmware use default cal\n",
6832 __func__);
6833 } else if (tabla_mbhc_fw_validate(fw) == false) {
6834 pr_err("%s: Invalid MBHC cal data size use default cal\n",
6835 __func__);
6836 release_firmware(fw);
6837 } else {
6838 tabla->mbhc_cfg.calibration = (void *)fw->data;
6839 tabla->mbhc_fw = fw;
6840 }
6841
Joonwoo Park1305bab2012-05-21 15:08:42 -07006842 (void) tabla_mbhc_init_and_calibrate(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006843}
6844
Joonwoo Park03324832012-03-19 19:36:16 -07006845int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006846 const struct tabla_mbhc_config *cfg)
Joonwoo Park03324832012-03-19 19:36:16 -07006847{
6848 struct tabla_priv *tabla;
6849 int rc = 0;
6850
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006851 if (!codec || !cfg->calibration) {
Joonwoo Park03324832012-03-19 19:36:16 -07006852 pr_err("Error: no codec or calibration\n");
6853 return -EINVAL;
6854 }
6855
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006856 if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
6857 if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Joonwoo Park03324832012-03-19 19:36:16 -07006858 pr_err("Error: clock rate %dHz is not yet supported\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006859 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006860 else
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006861 pr_err("Error: unsupported clock rate %d\n",
6862 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07006863 return -EINVAL;
6864 }
6865
6866 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006867 tabla->mbhc_cfg = *cfg;
6868 tabla->in_gpio_handler = false;
6869 tabla->current_plug = PLUG_TYPE_NONE;
6870 tabla->lpi_enabled = false;
Joonwoo Park03324832012-03-19 19:36:16 -07006871 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
6872
6873 /* Put CFILT in fast mode by default */
6874 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
6875 0x40, TABLA_CFILT_FAST_MODE);
6876 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
6877 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
6878 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
6879 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
6880 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
6881
Joonwoo Park1305bab2012-05-21 15:08:42 -07006882 if (!tabla->mbhc_cfg.read_fw_bin)
6883 rc = tabla_mbhc_init_and_calibrate(tabla);
6884 else
Joonwoo Park03324832012-03-19 19:36:16 -07006885 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
6886 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006887
Joonwoo Park03324832012-03-19 19:36:16 -07006888 return rc;
6889}
6890EXPORT_SYMBOL_GPL(tabla_hs_detect);
6891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006892static unsigned long slimbus_value;
6893
6894static irqreturn_t tabla_slimbus_irq(int irq, void *data)
6895{
6896 struct tabla_priv *priv = data;
6897 struct snd_soc_codec *codec = priv->codec;
6898 int i, j;
6899 u8 val;
6900
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306901 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
6902 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006903 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
6904 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306905 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006906 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
6907 if (val & 0x1)
6908 pr_err_ratelimited("overflow error on port %x,"
6909 " value %x\n", i*8 + j, val);
6910 if (val & 0x2)
6911 pr_err_ratelimited("underflow error on port %x,"
6912 " value %x\n", i*8 + j, val);
6913 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306914 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006915 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, 0xFF);
6916 }
6917
6918 return IRQ_HANDLED;
6919}
6920
Patrick Lai3043fba2011-08-01 14:15:57 -07006921static int tabla_handle_pdata(struct tabla_priv *tabla)
6922{
6923 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306924 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07006925 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05306926 u8 leg_mode = pdata->amic_settings.legacy_mode;
6927 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
6928 u8 txfe_buff = pdata->amic_settings.txfe_buff;
6929 u8 flag = pdata->amic_settings.use_pdata;
6930 u8 i = 0, j = 0;
6931 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07006932
6933 if (!pdata) {
6934 rc = -ENODEV;
6935 goto done;
6936 }
6937
6938 /* Make sure settings are correct */
6939 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
6940 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
6941 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
6942 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
6943 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
6944 rc = -EINVAL;
6945 goto done;
6946 }
6947
6948 /* figure out k value */
6949 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
6950 pdata->micbias.cfilt1_mv);
6951 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
6952 pdata->micbias.cfilt2_mv);
6953 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
6954 pdata->micbias.cfilt3_mv);
6955
6956 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
6957 rc = -EINVAL;
6958 goto done;
6959 }
6960
6961 /* Set voltage level and always use LDO */
6962 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
6963 (pdata->micbias.ldoh_v << 2));
6964
6965 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
6966 (k1 << 2));
6967 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
6968 (k2 << 2));
6969 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
6970 (k3 << 2));
6971
6972 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
6973 (pdata->micbias.bias1_cfilt_sel << 5));
6974 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
6975 (pdata->micbias.bias2_cfilt_sel << 5));
6976 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
6977 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006978 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
6979 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07006980
Santosh Mardi22920282011-10-26 02:38:40 +05306981 for (i = 0; i < 6; j++, i += 2) {
6982 if (flag & (0x01 << i)) {
6983 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
6984 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
6985 val_txfe = val_txfe |
6986 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
6987 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
6988 0x10, value);
6989 snd_soc_update_bits(codec,
6990 TABLA_A_TX_1_2_TEST_EN + j * 10,
6991 0x30, val_txfe);
6992 }
6993 if (flag & (0x01 << (i + 1))) {
6994 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
6995 val_txfe = (txfe_bypass &
6996 (0x01 << (i + 1))) ? 0x02 : 0x00;
6997 val_txfe |= (txfe_buff &
6998 (0x01 << (i + 1))) ? 0x01 : 0x00;
6999 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
7000 0x01, value);
7001 snd_soc_update_bits(codec,
7002 TABLA_A_TX_1_2_TEST_EN + j * 10,
7003 0x03, val_txfe);
7004 }
7005 }
7006 if (flag & 0x40) {
7007 value = (leg_mode & 0x40) ? 0x10 : 0x00;
7008 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
7009 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
7010 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
7011 0x13, value);
7012 }
Patrick Lai49efeac2011-11-03 11:01:12 -07007013
7014 if (pdata->ocp.use_pdata) {
7015 /* not defined in CODEC specification */
7016 if (pdata->ocp.hph_ocp_limit == 1 ||
7017 pdata->ocp.hph_ocp_limit == 5) {
7018 rc = -EINVAL;
7019 goto done;
7020 }
7021 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
7022 0x0F, pdata->ocp.num_attempts);
7023 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
7024 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
7025 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
7026 0xE0, (pdata->ocp.hph_ocp_limit << 5));
7027 }
Joonwoo Park03324832012-03-19 19:36:16 -07007028
7029 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
7030 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
7031 if (pdata->regulator[i].min_uV == 1800000 &&
7032 pdata->regulator[i].max_uV == 1800000) {
7033 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
7034 0x1C);
7035 } else if (pdata->regulator[i].min_uV == 2200000 &&
7036 pdata->regulator[i].max_uV == 2200000) {
7037 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
7038 0x1E);
7039 } else {
7040 pr_err("%s: unsupported CDC_VDDA_RX voltage "
7041 "min %d, max %d\n", __func__,
7042 pdata->regulator[i].min_uV,
7043 pdata->regulator[i].max_uV);
7044 rc = -EINVAL;
7045 }
7046 break;
7047 }
7048 }
Patrick Lai3043fba2011-08-01 14:15:57 -07007049done:
7050 return rc;
7051}
7052
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007053static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
7054
7055 /* Tabla 1.1 MICBIAS changes */
7056 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
7057 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
7058 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007059
7060 /* Tabla 1.1 HPH changes */
7061 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
7062 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
7063
7064 /* Tabla 1.1 EAR PA changes */
7065 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
7066 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
7067 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
7068
7069 /* Tabla 1.1 Lineout_5 Changes */
7070 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
7071
7072 /* Tabla 1.1 RX Changes */
7073 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
7074 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
7075 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
7076 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
7077 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
7078 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
7079 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
7080
7081 /* Tabla 1.1 RX1 and RX2 Changes */
7082 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
7083 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
7084
7085 /* Tabla 1.1 RX3 to RX7 Changes */
7086 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
7087 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
7088 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
7089 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
7090 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
7091
7092 /* Tabla 1.1 CLASSG Changes */
7093 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
7094};
7095
7096static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007097 /* Tabla 2.0 MICBIAS changes */
7098 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
7099};
7100
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007101static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
7102 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
7103};
7104
7105static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
7106 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
7107};
7108
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007109static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
7110{
7111 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307112 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007113
7114 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
7115 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
7116 tabla_1_1_reg_defaults[i].val);
7117
7118 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
7119 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
7120 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007121
7122 if (TABLA_IS_1_X(tabla_core->version)) {
7123 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
7124 i++)
7125 snd_soc_write(codec,
7126 tabla_1_x_only_reg_2_0_defaults[i].reg,
7127 tabla_1_x_only_reg_2_0_defaults[i].val);
7128 } else {
7129 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
7130 snd_soc_write(codec,
7131 tabla_2_only_reg_2_0_defaults[i].reg,
7132 tabla_2_only_reg_2_0_defaults[i].val);
7133 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007134}
7135
7136static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08007137 /* Initialize current threshold to 350MA
7138 * number of wait and run cycles to 4096
7139 */
Patrick Lai49efeac2011-11-03 11:01:12 -07007140 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08007141 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007142
Santosh Mardi32171012011-10-28 23:32:06 +05307143 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
7144
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007145 /* Initialize gain registers to use register gain */
7146 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
7147 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
7148 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
7149 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
7150 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
7151 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
7152
7153 /* Initialize mic biases to differential mode */
7154 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
7155 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
7156 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007157
7158 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
7159
7160 /* Use 16 bit sample size for TX1 to TX6 */
7161 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
7162 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
7163 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
7164 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
7165 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
7166 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
7167
7168 /* Use 16 bit sample size for TX7 to TX10 */
7169 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
7170 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
7171 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
7172 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
7173
7174 /* Use 16 bit sample size for RX */
7175 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
7176 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
7177
7178 /*enable HPF filter for TX paths */
7179 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
7180 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
7181 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
7182 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
7183 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
7184 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
7185 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
7186 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
7187 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
7188 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
Kiran Kandi0ba468f2012-05-08 11:45:05 -07007189
7190 /* config Decimator for DMIC CLK_MODE_1(3.072Mhz@12.88Mhz mclk) */
7191 {TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0x1},
7192 {TABLA_A_CDC_TX2_DMIC_CTL, 0x1, 0x1},
7193 {TABLA_A_CDC_TX3_DMIC_CTL, 0x1, 0x1},
7194 {TABLA_A_CDC_TX4_DMIC_CTL, 0x1, 0x1},
7195 {TABLA_A_CDC_TX5_DMIC_CTL, 0x1, 0x1},
7196 {TABLA_A_CDC_TX6_DMIC_CTL, 0x1, 0x1},
7197 {TABLA_A_CDC_TX7_DMIC_CTL, 0x1, 0x1},
7198 {TABLA_A_CDC_TX8_DMIC_CTL, 0x1, 0x1},
7199 {TABLA_A_CDC_TX9_DMIC_CTL, 0x1, 0x1},
7200 {TABLA_A_CDC_TX10_DMIC_CTL, 0x1, 0x1},
7201
7202 /* config DMIC clk to CLK_MODE_1 (3.072Mhz@12.88Mhz mclk) */
7203 {TABLA_A_CDC_CLK_DMIC_CTL, 0x2A, 0x2A},
7204
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007205};
7206
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007207static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
7208 /* Initialize mic biases to differential mode */
7209 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
7210};
7211
7212static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
7213 /* Initialize mic biases to differential mode */
7214 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
7215};
7216
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007217static void tabla_codec_init_reg(struct snd_soc_codec *codec)
7218{
7219 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307220 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007221
7222 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
7223 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
7224 tabla_codec_reg_init_val[i].mask,
7225 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007226 if (TABLA_IS_1_X(tabla_core->version)) {
7227 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
7228 snd_soc_update_bits(codec,
7229 tabla_1_x_codec_reg_init_val[i].reg,
7230 tabla_1_x_codec_reg_init_val[i].mask,
7231 tabla_1_x_codec_reg_init_val[i].val);
7232 } else {
7233 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
7234 i++)
7235 snd_soc_update_bits(codec,
7236 tabla_2_higher_codec_reg_init_val[i].reg,
7237 tabla_2_higher_codec_reg_init_val[i].mask,
7238 tabla_2_higher_codec_reg_init_val[i].val);
7239 }
7240}
7241
7242static void tabla_update_reg_address(struct tabla_priv *priv)
7243{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307244 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007245 struct tabla_reg_address *reg_addr = &priv->reg_addr;
7246
7247 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08007248 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
7249 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007250 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007251 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08007252 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
7253 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007254 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007255 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07007256}
7257
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007258#ifdef CONFIG_DEBUG_FS
7259static int codec_debug_open(struct inode *inode, struct file *file)
7260{
7261 file->private_data = inode->i_private;
7262 return 0;
7263}
7264
7265static ssize_t codec_debug_write(struct file *filp,
7266 const char __user *ubuf, size_t cnt, loff_t *ppos)
7267{
7268 char lbuf[32];
7269 char *buf;
7270 int rc;
7271 struct tabla_priv *tabla = filp->private_data;
7272
7273 if (cnt > sizeof(lbuf) - 1)
7274 return -EINVAL;
7275
7276 rc = copy_from_user(lbuf, ubuf, cnt);
7277 if (rc)
7278 return -EFAULT;
7279
7280 lbuf[cnt] = '\0';
7281 buf = (char *)lbuf;
7282 tabla->no_mic_headset_override = (*strsep(&buf, " ") == '0') ?
7283 false : true;
7284 return rc;
7285}
7286
7287static ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
7288 size_t count, loff_t *pos)
7289{
7290 const int size = 768;
7291 char buffer[size];
7292 int n = 0;
7293 struct tabla_priv *tabla = file->private_data;
7294 struct snd_soc_codec *codec = tabla->codec;
7295 const struct mbhc_internal_cal_data *p = &tabla->mbhc_data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007296 const s16 v_ins_hu_cur = tabla_get_current_v_ins(tabla, true);
7297 const s16 v_ins_h_cur = tabla_get_current_v_ins(tabla, false);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007298
7299 n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
7300 tabla_codec_sta_dce_v(codec, 1, p->dce_z));
7301 n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
7302 p->dce_mb, tabla_codec_sta_dce_v(codec, 1, p->dce_mb));
7303 n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
7304 p->sta_z, tabla_codec_sta_dce_v(codec, 0, p->sta_z));
7305 n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
7306 p->sta_mb, tabla_codec_sta_dce_v(codec, 0, p->sta_mb));
7307 n += scnprintf(buffer + n, size - n, "t_dce = %x\n", p->t_dce);
7308 n += scnprintf(buffer + n, size - n, "t_sta = %x\n", p->t_sta);
7309 n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
7310 p->micb_mv);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007311 n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007312 p->v_ins_hu,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007313 tabla_codec_sta_dce_v(codec, 0, p->v_ins_hu),
7314 p->v_ins_hu == v_ins_hu_cur ? "*" : "");
7315 n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
7316 p->v_ins_h, tabla_codec_sta_dce_v(codec, 1, p->v_ins_h),
7317 p->v_ins_h == v_ins_h_cur ? "*" : "");
7318 n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
7319 p->adj_v_ins_hu,
7320 tabla_codec_sta_dce_v(codec, 0, p->adj_v_ins_hu),
7321 p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
7322 n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
7323 p->adj_v_ins_h,
7324 tabla_codec_sta_dce_v(codec, 1, p->adj_v_ins_h),
7325 p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007326 n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
7327 p->v_b1_hu, tabla_codec_sta_dce_v(codec, 0, p->v_b1_hu));
7328 n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
7329 p->v_b1_h, tabla_codec_sta_dce_v(codec, 1, p->v_b1_h));
7330 n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
7331 p->v_b1_huc,
7332 tabla_codec_sta_dce_v(codec, 1, p->v_b1_huc));
7333 n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
7334 p->v_brh, tabla_codec_sta_dce_v(codec, 1, p->v_brh));
7335 n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
7336 tabla_codec_sta_dce_v(codec, 0, p->v_brl));
7337 n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
7338 p->v_no_mic,
7339 tabla_codec_sta_dce_v(codec, 0, p->v_no_mic));
7340 n += scnprintf(buffer + n, size - n, "npoll = %d\n", p->npoll);
7341 n += scnprintf(buffer + n, size - n, "nbounce_wait = %d\n",
7342 p->nbounce_wait);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007343 n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
7344 p->v_inval_ins_low);
7345 n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
7346 p->v_inval_ins_high);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007347 if (tabla->mbhc_cfg.gpio)
7348 n += scnprintf(buffer + n, size - n, "GPIO insert = %d\n",
7349 tabla_hs_gpio_level_remove(tabla));
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007350 buffer[n] = 0;
7351
7352 return simple_read_from_buffer(buf, count, pos, buffer, n);
7353}
7354
7355static const struct file_operations codec_debug_ops = {
7356 .open = codec_debug_open,
7357 .write = codec_debug_write,
7358};
7359
7360static const struct file_operations codec_mbhc_debug_ops = {
7361 .open = codec_debug_open,
7362 .read = codec_mbhc_debug_read,
7363};
7364#endif
7365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007366static int tabla_codec_probe(struct snd_soc_codec *codec)
7367{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307368 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007369 struct tabla_priv *tabla;
7370 struct snd_soc_dapm_context *dapm = &codec->dapm;
7371 int ret = 0;
7372 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007373 int ch_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007374
7375 codec->control_data = dev_get_drvdata(codec->dev->parent);
7376 control = codec->control_data;
7377
7378 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
7379 if (!tabla) {
7380 dev_err(codec->dev, "Failed to allocate private data\n");
7381 return -ENOMEM;
7382 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08007383 for (i = 0 ; i < NUM_DECIMATORS; i++) {
7384 tx_hpf_work[i].tabla = tabla;
7385 tx_hpf_work[i].decimator = i + 1;
7386 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
7387 tx_hpf_corner_freq_callback);
7388 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007389
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07007390 /* Make sure mbhc micbias register addresses are zeroed out */
7391 memset(&tabla->mbhc_bias_regs, 0,
7392 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07007393 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07007394
Joonwoo Park0976d012011-12-22 11:48:18 -08007395 /* Make sure mbhc intenal calibration data is zeroed out */
7396 memset(&tabla->mbhc_data, 0,
7397 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08007398 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08007399 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
7400 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007401 snd_soc_codec_set_drvdata(codec, tabla);
7402
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07007403 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007404 tabla->bandgap_type = TABLA_BANDGAP_OFF;
7405 tabla->clock_active = false;
7406 tabla->config_mode_active = false;
7407 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08007408 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07007409 tabla->no_mic_headset_override = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007410 tabla->hs_polling_irq_prepared = false;
7411 mutex_init(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007412 tabla->codec = codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007413 tabla->mbhc_state = MBHC_STATE_NONE;
Joonwoo Park03324832012-03-19 19:36:16 -07007414 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08007415 for (i = 0; i < COMPANDER_MAX; i++) {
7416 tabla->comp_enabled[i] = 0;
7417 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
7418 }
Patrick Lai3043fba2011-08-01 14:15:57 -07007419 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307420 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08007421 tabla->aux_pga_cnt = 0;
7422 tabla->aux_l_gain = 0x1F;
7423 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007424 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05307425 tabla_update_reg_defaults(codec);
7426 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05307427 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07007428 if (IS_ERR_VALUE(ret)) {
7429 pr_err("%s: bad pdata\n", __func__);
7430 goto err_pdata;
7431 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007432
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007433 snd_soc_add_controls(codec, tabla_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007434 ARRAY_SIZE(tabla_snd_controls));
7435 if (TABLA_IS_1_X(control->version))
7436 snd_soc_add_controls(codec, tabla_1_x_snd_controls,
7437 ARRAY_SIZE(tabla_1_x_snd_controls));
7438 else
7439 snd_soc_add_controls(codec, tabla_2_higher_snd_controls,
7440 ARRAY_SIZE(tabla_2_higher_snd_controls));
7441
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007442 snd_soc_dapm_new_controls(dapm, tabla_dapm_widgets,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007443 ARRAY_SIZE(tabla_dapm_widgets));
7444 if (TABLA_IS_1_X(control->version))
7445 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
7446 ARRAY_SIZE(tabla_1_x_dapm_widgets));
7447 else
7448 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
7449 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
7450
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307451 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05307452 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
7453 ARRAY_SIZE(tabla_dapm_i2s_widgets));
7454 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
7455 ARRAY_SIZE(audio_i2s_map));
7456 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007457 snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
Kiran Kandi8b3a8302011-09-27 16:13:28 -07007458
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007459 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007460 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007461 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
7462 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007463 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08007464 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007465 } else {
7466 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307467 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08007468 goto err_pdata;
7469 }
7470
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007471 snd_soc_dapm_sync(dapm);
7472
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307473 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007474 tabla_hs_insert_irq, "Headset insert detect", tabla);
7475 if (ret) {
7476 pr_err("%s: Failed to request irq %d\n", __func__,
7477 TABLA_IRQ_MBHC_INSERTION);
7478 goto err_insert_irq;
7479 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307480 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007481
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307482 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007483 tabla_hs_remove_irq, "Headset remove detect", tabla);
7484 if (ret) {
7485 pr_err("%s: Failed to request irq %d\n", __func__,
7486 TABLA_IRQ_MBHC_REMOVAL);
7487 goto err_remove_irq;
7488 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007489
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307490 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007491 tabla_dce_handler, "DC Estimation detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007492 if (ret) {
7493 pr_err("%s: Failed to request irq %d\n", __func__,
7494 TABLA_IRQ_MBHC_POTENTIAL);
7495 goto err_potential_irq;
7496 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007497
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307498 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE,
Bradley Rubincb1e2732011-06-23 16:49:20 -07007499 tabla_release_handler, "Button Release detect", tabla);
7500 if (ret) {
7501 pr_err("%s: Failed to request irq %d\n", __func__,
7502 TABLA_IRQ_MBHC_RELEASE);
7503 goto err_release_irq;
7504 }
7505
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307506 ret = wcd9xxx_request_irq(codec->control_data, TABLA_IRQ_SLIMBUS,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007507 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
7508 if (ret) {
7509 pr_err("%s: Failed to request irq %d\n", __func__,
7510 TABLA_IRQ_SLIMBUS);
7511 goto err_slimbus_irq;
7512 }
7513
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307514 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
7515 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007516 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
7517
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307518 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007519 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla_hphl_ocp_irq,
7520 "HPH_L OCP detect", tabla);
7521 if (ret) {
7522 pr_err("%s: Failed to request irq %d\n", __func__,
7523 TABLA_IRQ_HPH_PA_OCPL_FAULT);
7524 goto err_hphl_ocp_irq;
7525 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307526 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07007527
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307528 ret = wcd9xxx_request_irq(codec->control_data,
Patrick Lai49efeac2011-11-03 11:01:12 -07007529 TABLA_IRQ_HPH_PA_OCPR_FAULT, tabla_hphr_ocp_irq,
7530 "HPH_R OCP detect", tabla);
7531 if (ret) {
7532 pr_err("%s: Failed to request irq %d\n", __func__,
7533 TABLA_IRQ_HPH_PA_OCPR_FAULT);
7534 goto err_hphr_ocp_irq;
7535 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307536 wcd9xxx_disable_irq(codec->control_data, TABLA_IRQ_HPH_PA_OCPR_FAULT);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007537 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++) {
7538 switch (tabla_dai[i].id) {
7539 case AIF1_PB:
7540 ch_cnt = tabla_dai[i].playback.channels_max;
7541 break;
7542 case AIF1_CAP:
7543 ch_cnt = tabla_dai[i].capture.channels_max;
7544 break;
Neema Shettyd3a89262012-02-16 10:23:50 -08007545 case AIF2_PB:
7546 ch_cnt = tabla_dai[i].playback.channels_max;
7547 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07007548 case AIF2_CAP:
7549 ch_cnt = tabla_dai[i].capture.channels_max;
7550 break;
Neema Shetty3fb1b802012-04-27 13:53:24 -07007551 case AIF3_CAP:
7552 ch_cnt = tabla_dai[i].capture.channels_max;
7553 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007554 default:
7555 continue;
7556 }
7557 tabla->dai[i].ch_num = kzalloc((sizeof(unsigned int)*
7558 ch_cnt), GFP_KERNEL);
7559 }
Patrick Lai49efeac2011-11-03 11:01:12 -07007560
Bradley Rubincb3950a2011-08-18 13:07:26 -07007561#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007562 if (ret == 0) {
7563 tabla->debugfs_poke =
7564 debugfs_create_file("TRRS", S_IFREG | S_IRUGO, NULL, tabla,
7565 &codec_debug_ops);
7566 tabla->debugfs_mbhc =
7567 debugfs_create_file("tabla_mbhc", S_IFREG | S_IRUGO,
7568 NULL, tabla, &codec_mbhc_debug_ops);
7569 }
Bradley Rubincb3950a2011-08-18 13:07:26 -07007570#endif
7571
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007572 return ret;
7573
Patrick Lai49efeac2011-11-03 11:01:12 -07007574err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307575 wcd9xxx_free_irq(codec->control_data,
7576 TABLA_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07007577err_hphl_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307578 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007579err_slimbus_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307580 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07007581err_release_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307582 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007583err_potential_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307584 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007585err_remove_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307586 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007587err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07007588err_pdata:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007589 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007590 kfree(tabla);
7591 return ret;
7592}
7593static int tabla_codec_remove(struct snd_soc_codec *codec)
7594{
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007595 int i;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007596 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307597 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_SLIMBUS, tabla);
7598 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_RELEASE, tabla);
7599 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_POTENTIAL, tabla);
7600 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_REMOVAL, tabla);
7601 wcd9xxx_free_irq(codec->control_data, TABLA_IRQ_MBHC_INSERTION, tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007602 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007603 tabla_codec_disable_clock_block(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007604 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007605 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08007606 if (tabla->mbhc_fw)
7607 release_firmware(tabla->mbhc_fw);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08007608 for (i = 0; i < ARRAY_SIZE(tabla_dai); i++)
7609 kfree(tabla->dai[i].ch_num);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007610 mutex_destroy(&tabla->codec_resource_lock);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07007611#ifdef CONFIG_DEBUG_FS
7612 debugfs_remove(tabla->debugfs_poke);
7613 debugfs_remove(tabla->debugfs_mbhc);
7614#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007615 kfree(tabla);
7616 return 0;
7617}
7618static struct snd_soc_codec_driver soc_codec_dev_tabla = {
7619 .probe = tabla_codec_probe,
7620 .remove = tabla_codec_remove,
7621 .read = tabla_read,
7622 .write = tabla_write,
7623
7624 .readable_register = tabla_readable,
7625 .volatile_register = tabla_volatile,
7626
7627 .reg_cache_size = TABLA_CACHE_SIZE,
7628 .reg_cache_default = tabla_reg_defaults,
7629 .reg_word_size = 1,
7630};
Bradley Rubincb3950a2011-08-18 13:07:26 -07007631
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007632#ifdef CONFIG_PM
7633static int tabla_suspend(struct device *dev)
7634{
Joonwoo Park816b8e62012-01-23 16:03:21 -08007635 dev_dbg(dev, "%s: system suspend\n", __func__);
7636 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007637}
7638
7639static int tabla_resume(struct device *dev)
7640{
Joonwoo Park03324832012-03-19 19:36:16 -07007641 struct platform_device *pdev = to_platform_device(dev);
7642 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Park816b8e62012-01-23 16:03:21 -08007643 dev_dbg(dev, "%s: system resume\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07007644 tabla->mbhc_last_resume = jiffies;
Joonwoo Park816b8e62012-01-23 16:03:21 -08007645 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007646}
7647
7648static const struct dev_pm_ops tabla_pm_ops = {
7649 .suspend = tabla_suspend,
7650 .resume = tabla_resume,
7651};
7652#endif
7653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007654static int __devinit tabla_probe(struct platform_device *pdev)
7655{
Santosh Mardie15e2302011-11-15 10:39:23 +05307656 int ret = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307657 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05307658 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7659 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05307660 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05307661 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
7662 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
7663 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007664}
7665static int __devexit tabla_remove(struct platform_device *pdev)
7666{
7667 snd_soc_unregister_codec(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007668 return 0;
7669}
7670static struct platform_driver tabla_codec_driver = {
7671 .probe = tabla_probe,
7672 .remove = tabla_remove,
7673 .driver = {
7674 .name = "tabla_codec",
7675 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007676#ifdef CONFIG_PM
7677 .pm = &tabla_pm_ops,
7678#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007679 },
7680};
7681
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007682static struct platform_driver tabla1x_codec_driver = {
7683 .probe = tabla_probe,
7684 .remove = tabla_remove,
7685 .driver = {
7686 .name = "tabla1x_codec",
7687 .owner = THIS_MODULE,
7688#ifdef CONFIG_PM
7689 .pm = &tabla_pm_ops,
7690#endif
7691 },
7692};
7693
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007694static int __init tabla_codec_init(void)
7695{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007696 int rtn = platform_driver_register(&tabla_codec_driver);
7697 if (rtn == 0) {
7698 rtn = platform_driver_register(&tabla1x_codec_driver);
7699 if (rtn != 0)
7700 platform_driver_unregister(&tabla_codec_driver);
7701 }
7702 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007703}
7704
7705static void __exit tabla_codec_exit(void)
7706{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08007707 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007708 platform_driver_unregister(&tabla_codec_driver);
7709}
7710
7711module_init(tabla_codec_init);
7712module_exit(tabla_codec_exit);
7713
7714MODULE_DESCRIPTION("Tabla codec driver");
7715MODULE_VERSION("1.0");
7716MODULE_LICENSE("GPL v2");