blob: b8a4a8689a952a62579beffff5c41d86de5ee4b0 [file] [log] [blame]
Simmi Pateriya1b9a3092013-01-02 11:49:26 +05301/* Copyright (c) 2011-2013, The Linux Foundation. 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>
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -070021#include <linux/wait.h>
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053022#include <linux/mfd/wcd9xxx/core.h>
23#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
24#include <linux/mfd/wcd9xxx/wcd9310_registers.h>
25#include <linux/mfd/wcd9xxx/pdata.h>
Santosh Mardie15e2302011-11-15 10:39:23 +053026#include <sound/pcm.h>
27#include <sound/pcm_params.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028#include <sound/soc.h>
29#include <sound/soc-dapm.h>
30#include <sound/tlv.h>
31#include <linux/bitops.h>
32#include <linux/delay.h>
Kuirong Wanga545e722012-02-06 19:12:54 -080033#include <linux/pm_runtime.h>
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070034#include <linux/kernel.h>
35#include <linux/gpio.h>
Joonwoo Parkecf379c2012-10-04 16:57:52 -070036#include <linux/irq.h>
37#include <linux/wakelock.h>
38#include <linux/suspend.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070039#include "wcd9310.h"
40
Joonwoo Parkc1c67a92012-08-07 16:05:36 -070041static int cfilt_adjust_ms = 10;
42module_param(cfilt_adjust_ms, int, 0644);
43MODULE_PARM_DESC(cfilt_adjust_ms, "delay after adjusting cfilt voltage in ms");
44
Kiran Kandi1e6371d2012-03-29 11:48:57 -070045#define WCD9310_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
46 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
47 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
48
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070049
50#define NUM_DECIMATORS 10
51#define NUM_INTERPOLATORS 7
52#define BITS_PER_REG 8
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -080053#define TABLA_CFILT_FAST_MODE 0x00
54#define TABLA_CFILT_SLOW_MODE 0x40
Patrick Lai64b43262011-12-06 17:29:15 -080055#define MBHC_FW_READ_ATTEMPTS 15
56#define MBHC_FW_READ_TIMEOUT 2000000
Simmi Pateriyad60186a2012-11-27 13:50:11 +053057#define MBHC_VDDIO_SWITCH_WAIT_MS 10
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -070058
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -070059#define SLIM_CLOSE_TIMEOUT 1000
60
Joonwoo Park03324832012-03-19 19:36:16 -070061enum {
62 MBHC_USE_HPHL_TRIGGER = 1,
63 MBHC_USE_MB_TRIGGER = 2
64};
65
66#define MBHC_NUM_DCE_PLUG_DETECT 3
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070067#define NUM_ATTEMPTS_INSERT_DETECT 25
68#define NUM_ATTEMPTS_TO_REPORT 5
Joonwoo Park03324832012-03-19 19:36:16 -070069
Joonwoo Park2cc13f02012-05-09 12:44:25 -070070#define TABLA_JACK_MASK (SND_JACK_HEADSET | SND_JACK_OC_HPHL | \
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -070071 SND_JACK_OC_HPHR | SND_JACK_LINEOUT | \
72 SND_JACK_UNSUPPORTED)
Patrick Lai49efeac2011-11-03 11:01:12 -070073
Santosh Mardie15e2302011-11-15 10:39:23 +053074#define TABLA_I2S_MASTER_MODE_MASK 0x08
75
Patrick Laic7cae882011-11-18 11:52:49 -080076#define TABLA_OCP_ATTEMPT 1
77
Kuirong Wang906ac472012-07-09 12:54:44 -070078enum {
79 AIF1_PB = 0,
80 AIF1_CAP,
81 AIF2_PB,
82 AIF2_CAP,
83 AIF3_PB,
84 AIF3_CAP,
85 NUM_CODEC_DAIS,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080086};
87
Kuirong Wang906ac472012-07-09 12:54:44 -070088enum {
89 RX_MIX1_INP_SEL_ZERO = 0,
90 RX_MIX1_INP_SEL_SRC1,
91 RX_MIX1_INP_SEL_SRC2,
92 RX_MIX1_INP_SEL_IIR1,
93 RX_MIX1_INP_SEL_IIR2,
94 RX_MIX1_INP_SEL_RX1,
95 RX_MIX1_INP_SEL_RX2,
96 RX_MIX1_INP_SEL_RX3,
97 RX_MIX1_INP_SEL_RX4,
98 RX_MIX1_INP_SEL_RX5,
99 RX_MIX1_INP_SEL_RX6,
100 RX_MIX1_INP_SEL_RX7,
101};
102
Kuirong Wang678e4172012-06-26 15:35:22 -0700103#define TABLA_COMP_DIGITAL_GAIN_HP_OFFSET 3
104#define TABLA_COMP_DIGITAL_GAIN_LINEOUT_OFFSET 6
Kuirong Wang906ac472012-07-09 12:54:44 -0700105
Joonwoo Park0976d012011-12-22 11:48:18 -0800106#define TABLA_MCLK_RATE_12288KHZ 12288000
107#define TABLA_MCLK_RATE_9600KHZ 9600000
108
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800109#define TABLA_FAKE_INS_THRESHOLD_MS 2500
Joonwoo Park6b9b03f2012-01-23 18:48:54 -0800110#define TABLA_FAKE_REMOVAL_MIN_PERIOD_MS 50
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800111
Joonwoo Park03324832012-03-19 19:36:16 -0700112#define TABLA_MBHC_BUTTON_MIN 0x8000
113
Joonwoo Park03324832012-03-19 19:36:16 -0700114#define TABLA_MBHC_FAKE_INSERT_LOW 10
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700115#define TABLA_MBHC_FAKE_INSERT_HIGH 80
116#define TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO 150
Joonwoo Park03324832012-03-19 19:36:16 -0700117
118#define TABLA_MBHC_STATUS_REL_DETECTION 0x0C
119
Joonwoo Parkdb606b02012-08-11 13:46:30 -0700120#define TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS 50
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700121
Joonwoo Parkcf473b42012-03-29 19:48:16 -0700122#define TABLA_MBHC_FAKE_INS_DELTA_MV 200
123#define TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV 300
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700124
125#define TABLA_HS_DETECT_PLUG_TIME_MS (5 * 1000)
126#define TABLA_HS_DETECT_PLUG_INERVAL_MS 100
127
128#define TABLA_GPIO_IRQ_DEBOUNCE_TIME_US 5000
129
Joonwoo Park2cc13f02012-05-09 12:44:25 -0700130#define TABLA_MBHC_GND_MIC_SWAP_THRESHOLD 2
131
Joonwoo Park1f9d7fd2013-01-07 12:40:03 -0800132#define TABLA_ACQUIRE_LOCK(x) do { \
133 mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
134} while (0)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700135#define TABLA_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
138static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
139static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800140static struct snd_soc_dai_driver tabla_dai[];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800141static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
Kiran Kandi93923902012-06-20 17:00:25 -0700142static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
143 struct snd_kcontrol *kcontrol, int event);
144static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
145 struct snd_kcontrol *kcontrol, int event);
146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700147
148enum tabla_bandgap_type {
149 TABLA_BANDGAP_OFF = 0,
150 TABLA_BANDGAP_AUDIO_MODE,
151 TABLA_BANDGAP_MBHC_MODE,
152};
153
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700154struct mbhc_micbias_regs {
155 u16 cfilt_val;
156 u16 cfilt_ctl;
157 u16 mbhc_reg;
158 u16 int_rbias;
159 u16 ctl_reg;
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -0800160 u8 cfilt_sel;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700161};
162
Ben Romberger1f045a72011-11-04 10:14:57 -0700163/* Codec supports 2 IIR filters */
164enum {
165 IIR1 = 0,
166 IIR2,
167 IIR_MAX,
168};
169/* Codec supports 5 bands */
170enum {
171 BAND1 = 0,
172 BAND2,
173 BAND3,
174 BAND4,
175 BAND5,
176 BAND_MAX,
177};
178
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800179enum {
180 COMPANDER_1 = 0,
181 COMPANDER_2,
182 COMPANDER_MAX,
183};
184
185enum {
186 COMPANDER_FS_8KHZ = 0,
187 COMPANDER_FS_16KHZ,
188 COMPANDER_FS_32KHZ,
189 COMPANDER_FS_48KHZ,
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700190 COMPANDER_FS_96KHZ,
191 COMPANDER_FS_192KHZ,
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800192 COMPANDER_FS_MAX,
193};
194
Kuirong Wang678e4172012-06-26 15:35:22 -0700195enum {
196 COMP_SHUTDWN_TIMEOUT_PCM_1 = 0,
197 COMP_SHUTDWN_TIMEOUT_PCM_240,
198 COMP_SHUTDWN_TIMEOUT_PCM_480,
199 COMP_SHUTDWN_TIMEOUT_PCM_960,
200 COMP_SHUTDWN_TIMEOUT_PCM_1440,
201 COMP_SHUTDWN_TIMEOUT_PCM_2880,
202 COMP_SHUTDWN_TIMEOUT_PCM_5760,
203};
204
Joonwoo Parka9444452011-12-08 18:48:27 -0800205/* Flags to track of PA and DAC state.
206 * PA and DAC should be tracked separately as AUXPGA loopback requires
207 * only PA to be turned on without DAC being on. */
208enum tabla_priv_ack_flags {
209 TABLA_HPHL_PA_OFF_ACK = 0,
210 TABLA_HPHR_PA_OFF_ACK,
211 TABLA_HPHL_DAC_OFF_ACK,
212 TABLA_HPHR_DAC_OFF_ACK
213};
214
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800215
216struct comp_sample_dependent_params {
217 u32 peak_det_timeout;
218 u32 rms_meter_div_fact;
219 u32 rms_meter_resamp_fact;
Kuirong Wang678e4172012-06-26 15:35:22 -0700220 u32 shutdown_timeout;
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800221};
222
Joonwoo Park0976d012011-12-22 11:48:18 -0800223/* Data used by MBHC */
224struct mbhc_internal_cal_data {
225 u16 dce_z;
226 u16 dce_mb;
227 u16 sta_z;
228 u16 sta_mb;
Joonwoo Park433149a2012-01-11 09:53:54 -0800229 u32 t_sta_dce;
Joonwoo Park0976d012011-12-22 11:48:18 -0800230 u32 t_dce;
231 u32 t_sta;
232 u32 micb_mv;
233 u16 v_ins_hu;
234 u16 v_ins_h;
235 u16 v_b1_hu;
236 u16 v_b1_h;
237 u16 v_b1_huc;
238 u16 v_brh;
239 u16 v_brl;
240 u16 v_no_mic;
Joonwoo Park0976d012011-12-22 11:48:18 -0800241 u8 npoll;
242 u8 nbounce_wait;
Joonwoo Parkcf473b42012-03-29 19:48:16 -0700243 s16 adj_v_hs_max;
244 u16 adj_v_ins_hu;
245 u16 adj_v_ins_h;
246 s16 v_inval_ins_low;
247 s16 v_inval_ins_high;
Joonwoo Park0976d012011-12-22 11:48:18 -0800248};
249
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800250struct tabla_reg_address {
251 u16 micb_4_ctl;
252 u16 micb_4_int_rbias;
253 u16 micb_4_mbhc;
254};
255
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700256enum tabla_mbhc_plug_type {
Joonwoo Park41956722012-04-18 13:13:07 -0700257 PLUG_TYPE_INVALID = -1,
258 PLUG_TYPE_NONE,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700259 PLUG_TYPE_HEADSET,
260 PLUG_TYPE_HEADPHONE,
261 PLUG_TYPE_HIGH_HPH,
Joonwoo Park2cc13f02012-05-09 12:44:25 -0700262 PLUG_TYPE_GND_MIC_SWAP,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700263};
264
265enum tabla_mbhc_state {
266 MBHC_STATE_NONE = -1,
267 MBHC_STATE_POTENTIAL,
268 MBHC_STATE_POTENTIAL_RECOVERY,
269 MBHC_STATE_RELEASE,
270};
271
Kiran Kandid8cf5212012-03-02 15:34:53 -0800272struct hpf_work {
273 struct tabla_priv *tabla;
274 u32 decimator;
275 u8 tx_hpf_cut_of_freq;
276 struct delayed_work dwork;
277};
278
279static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
280
Kuirong Wang906ac472012-07-09 12:54:44 -0700281static const struct wcd9xxx_ch tabla_rx_chs[TABLA_RX_MAX] = {
282 WCD9XXX_CH(10, 0),
283 WCD9XXX_CH(11, 1),
284 WCD9XXX_CH(12, 2),
285 WCD9XXX_CH(13, 3),
286 WCD9XXX_CH(14, 4),
287 WCD9XXX_CH(15, 5),
288 WCD9XXX_CH(16, 6)
289};
290
291static const struct wcd9xxx_ch tabla_tx_chs[TABLA_TX_MAX] = {
292 WCD9XXX_CH(0, 0),
293 WCD9XXX_CH(1, 1),
294 WCD9XXX_CH(2, 2),
295 WCD9XXX_CH(3, 3),
296 WCD9XXX_CH(4, 4),
297 WCD9XXX_CH(5, 5),
298 WCD9XXX_CH(6, 6),
299 WCD9XXX_CH(7, 7),
300 WCD9XXX_CH(8, 8),
301 WCD9XXX_CH(9, 9)
302};
303
304static const u32 vport_check_table[NUM_CODEC_DAIS] = {
305 0, /* AIF1_PB */
306 (1 << AIF2_CAP) | (1 << AIF3_CAP), /* AIF1_CAP */
307 0, /* AIF2_PB */
308 (1 << AIF1_CAP) | (1 << AIF3_CAP), /* AIF2_CAP */
309 0, /* AIF2_PB */
310 (1 << AIF1_CAP) | (1 << AIF2_CAP), /* AIF2_CAP */
311};
312
Venkat Sudhir96dd28c2012-12-04 17:00:19 -0800313static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
314 0, /* AIF1_PB */
315 0, /* AIF1_CAP */
316};
317
Bradley Rubin229c6a52011-07-12 16:18:48 -0700318struct tabla_priv {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700319 struct snd_soc_codec *codec;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -0800320 struct tabla_reg_address reg_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700321 u32 adc_count;
Patrick Lai3043fba2011-08-01 14:15:57 -0700322 u32 cfilt1_cnt;
323 u32 cfilt2_cnt;
324 u32 cfilt3_cnt;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700325 u32 rx_bias_count;
Kiran Kandi0ba468f2012-05-08 11:45:05 -0700326 s32 dmic_1_2_clk_cnt;
327 s32 dmic_3_4_clk_cnt;
328 s32 dmic_5_6_clk_cnt;
329
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700330 enum tabla_bandgap_type bandgap_type;
Kiran Kandi6fae8bf2011-08-15 10:36:42 -0700331 bool mclk_enabled;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332 bool clock_active;
333 bool config_mode_active;
334 bool mbhc_polling_active;
Joonwoo Parkf4267c22012-01-10 13:25:24 -0800335 unsigned long mbhc_fake_ins_start;
Bradley Rubincb1e2732011-06-23 16:49:20 -0700336 int buttons_pressed;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700337 enum tabla_mbhc_state mbhc_state;
338 struct tabla_mbhc_config mbhc_cfg;
Joonwoo Park0976d012011-12-22 11:48:18 -0800339 struct mbhc_internal_cal_data mbhc_data;
Simmi Pateriya71d63872012-11-08 01:06:30 +0530340 u32 ldo_h_count;
341 u32 micbias_enable_count[TABLA_NUM_MICBIAS];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530343 struct wcd9xxx_pdata *pdata;
Bradley Rubina7096d02011-08-03 18:29:02 -0700344 u32 anc_slot;
Damir Didjustoc6f83cb2012-12-03 00:54:14 -0800345 bool anc_func;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700346 bool no_mic_headset_override;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -0700347 /* Delayed work to report long button press */
Joonwoo Park03324832012-03-19 19:36:16 -0700348 struct delayed_work mbhc_btn_dwork;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -0700349
350 struct mbhc_micbias_regs mbhc_bias_regs;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -0700351 bool mbhc_micbias_switched;
Patrick Lai49efeac2011-11-03 11:01:12 -0700352
Joonwoo Parka9444452011-12-08 18:48:27 -0800353 /* track PA/DAC state */
354 unsigned long hph_pa_dac_state;
355
Santosh Mardie15e2302011-11-15 10:39:23 +0530356 /*track tabla interface type*/
357 u8 intf_type;
358
Patrick Lai49efeac2011-11-03 11:01:12 -0700359 u32 hph_status; /* track headhpone status */
360 /* define separate work for left and right headphone OCP to avoid
361 * additional checking on which OCP event to report so no locking
362 * to ensure synchronization is required
363 */
364 struct work_struct hphlocp_work; /* reporting left hph ocp off */
365 struct work_struct hphrocp_work; /* reporting right hph ocp off */
Joonwoo Park8b1f0982011-12-08 17:12:45 -0800366
Patrick Laic7cae882011-11-18 11:52:49 -0800367 u8 hphlocp_cnt; /* headphone left ocp retry */
368 u8 hphrocp_cnt; /* headphone right ocp retry */
Joonwoo Park0976d012011-12-22 11:48:18 -0800369
Patrick Lai64b43262011-12-06 17:29:15 -0800370 /* Work to perform MBHC Firmware Read */
371 struct delayed_work mbhc_firmware_dwork;
372 const struct firmware *mbhc_fw;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800373
374 /* num of slim ports required */
Kuirong Wang906ac472012-07-09 12:54:44 -0700375 struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800376
377 /*compander*/
378 int comp_enabled[COMPANDER_MAX];
379 u32 comp_fs[COMPANDER_MAX];
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -0800380
381 /* Maintain the status of AUX PGA */
382 int aux_pga_cnt;
383 u8 aux_l_gain;
384 u8 aux_r_gain;
Joonwoo Park03324832012-03-19 19:36:16 -0700385
Joonwoo Park03324832012-03-19 19:36:16 -0700386 struct delayed_work mbhc_insert_dwork;
387 unsigned long mbhc_last_resume; /* in jiffies */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700388
389 u8 current_plug;
390 struct work_struct hs_correct_plug_work;
391 bool hs_detect_work_stop;
392 bool hs_polling_irq_prepared;
393 bool lpi_enabled; /* low power insertion detection */
394 bool in_gpio_handler;
395 /* Currently, only used for mbhc purpose, to protect
396 * concurrent execution of mbhc threaded irq handlers and
397 * kill race between DAPM and MBHC.But can serve as a
398 * general lock to protect codec resource
399 */
400 struct mutex codec_resource_lock;
401
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -0700402 /* Work to perform polling on microphone voltage
403 * in order to correct plug type once plug type
404 * is detected as headphone
405 */
406 struct work_struct hs_correct_plug_work_nogpio;
407
Joonwoo Parkecf379c2012-10-04 16:57:52 -0700408 bool gpio_irq_resend;
409 struct wake_lock irq_resend_wlock;
410
Bradley Rubincb3950a2011-08-18 13:07:26 -0700411#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700412 struct dentry *debugfs_poke;
413 struct dentry *debugfs_mbhc;
Bradley Rubincb3950a2011-08-18 13:07:26 -0700414#endif
Joonwoo Park179b9ec2012-03-26 10:56:20 -0700415};
416
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800417static const u32 comp_shift[] = {
418 0,
Kuirong Wang678e4172012-06-26 15:35:22 -0700419 1,
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800420};
421
422static const int comp_rx_path[] = {
423 COMPANDER_1,
424 COMPANDER_1,
425 COMPANDER_2,
426 COMPANDER_2,
427 COMPANDER_2,
428 COMPANDER_2,
429 COMPANDER_MAX,
430};
431
Kuirong Wang678e4172012-06-26 15:35:22 -0700432static const struct comp_sample_dependent_params
433 comp_samp_params[COMPANDER_FS_MAX] = {
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800434 {
Kuirong Wang678e4172012-06-26 15:35:22 -0700435 .peak_det_timeout = 0x6,
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800436 .rms_meter_div_fact = 0x9 << 4,
Kuirong Wang678e4172012-06-26 15:35:22 -0700437 .rms_meter_resamp_fact = 0x06,
438 .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_240 << 3,
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800439 },
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800440 {
Kuirong Wang678e4172012-06-26 15:35:22 -0700441 .peak_det_timeout = 0x7,
442 .rms_meter_div_fact = 0xA << 4,
443 .rms_meter_resamp_fact = 0x0C,
444 .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_480 << 3,
445 },
446 {
447 .peak_det_timeout = 0x8,
448 .rms_meter_div_fact = 0xB << 4,
449 .rms_meter_resamp_fact = 0x30,
450 .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_960 << 3,
451 },
452 {
453 .peak_det_timeout = 0x9,
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800454 .rms_meter_div_fact = 0xB << 4,
455 .rms_meter_resamp_fact = 0x28,
Kuirong Wang678e4172012-06-26 15:35:22 -0700456 .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_1440 << 3,
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800457 },
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800458 {
Kuirong Wang678e4172012-06-26 15:35:22 -0700459 .peak_det_timeout = 0xA,
460 .rms_meter_div_fact = 0xC << 4,
461 .rms_meter_resamp_fact = 0x50,
462 .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_2880 << 3,
463 },
464 {
465 .peak_det_timeout = 0xB,
466 .rms_meter_div_fact = 0xC << 4,
467 .rms_meter_resamp_fact = 0x50,
468 .shutdown_timeout = COMP_SHUTDWN_TIMEOUT_PCM_5760 << 3,
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800469 },
470};
471
Kuirong Wange9c8a222012-03-28 16:24:09 -0700472static unsigned short rx_digital_gain_reg[] = {
473 TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
474 TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
475 TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
476 TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
477 TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
478 TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
479 TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
480};
481
482
483static unsigned short tx_digital_gain_reg[] = {
484 TABLA_A_CDC_TX1_VOL_CTL_GAIN,
485 TABLA_A_CDC_TX2_VOL_CTL_GAIN,
486 TABLA_A_CDC_TX3_VOL_CTL_GAIN,
487 TABLA_A_CDC_TX4_VOL_CTL_GAIN,
488 TABLA_A_CDC_TX5_VOL_CTL_GAIN,
489 TABLA_A_CDC_TX6_VOL_CTL_GAIN,
490 TABLA_A_CDC_TX7_VOL_CTL_GAIN,
491 TABLA_A_CDC_TX8_VOL_CTL_GAIN,
492 TABLA_A_CDC_TX9_VOL_CTL_GAIN,
493 TABLA_A_CDC_TX10_VOL_CTL_GAIN,
494};
495
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700496static int tabla_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
497 struct snd_kcontrol *kcontrol, int event)
498{
499 struct snd_soc_codec *codec = w->codec;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500
501 pr_debug("%s %d\n", __func__, event);
502 switch (event) {
503 case SND_SOC_DAPM_POST_PMU:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
505 0x01);
506 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x08);
507 usleep_range(200, 200);
508 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x00);
509 break;
510 case SND_SOC_DAPM_PRE_PMD:
511 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
512 0x10);
513 usleep_range(20, 20);
514 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x08);
515 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x10, 0x10);
516 snd_soc_update_bits(codec, TABLA_A_CDC_CLSG_CTL, 0x08, 0x00);
517 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x01,
518 0x00);
Fred Oh54d24d72012-11-29 15:57:36 -0800519 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_RESET_CTL, 0x10,
520 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521 snd_soc_update_bits(codec, TABLA_A_CP_STATIC, 0x08, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700522 break;
523 }
524 return 0;
525}
526
Bradley Rubina7096d02011-08-03 18:29:02 -0700527static int tabla_get_anc_slot(struct snd_kcontrol *kcontrol,
528 struct snd_ctl_elem_value *ucontrol)
529{
530 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
531 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
532 ucontrol->value.integer.value[0] = tabla->anc_slot;
533 return 0;
534}
535
536static int tabla_put_anc_slot(struct snd_kcontrol *kcontrol,
537 struct snd_ctl_elem_value *ucontrol)
538{
539 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
540 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
541 tabla->anc_slot = ucontrol->value.integer.value[0];
542 return 0;
543}
544
Damir Didjustoc6f83cb2012-12-03 00:54:14 -0800545static int tabla_get_anc_func(struct snd_kcontrol *kcontrol,
546 struct snd_ctl_elem_value *ucontrol)
547{
548 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
549 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
550 ucontrol->value.integer.value[0] = (tabla->anc_func == true ? 1 : 0);
551 return 0;
552}
553
554static int tabla_put_anc_func(struct snd_kcontrol *kcontrol,
555 struct snd_ctl_elem_value *ucontrol)
556{
557 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
558 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
559 struct snd_soc_dapm_context *dapm = &codec->dapm;
560
561 mutex_lock(&dapm->codec->mutex);
562
563 tabla->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
564
565 dev_dbg(codec->dev, "%s: anc_func %x", __func__, tabla->anc_func);
566
567 if (tabla->anc_func == true) {
568 snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
569 snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
570 snd_soc_dapm_enable_pin(dapm, "ANC HEADPHONE");
571 snd_soc_dapm_disable_pin(dapm, "HPHR");
572 snd_soc_dapm_disable_pin(dapm, "HPHL");
573 snd_soc_dapm_disable_pin(dapm, "HEADPHONE");
574 } else {
575 snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
576 snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
577 snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
578 snd_soc_dapm_enable_pin(dapm, "HPHR");
579 snd_soc_dapm_enable_pin(dapm, "HPHL");
580 snd_soc_dapm_enable_pin(dapm, "HEADPHONE");
581 }
582 snd_soc_dapm_sync(dapm);
583 mutex_unlock(&dapm->codec->mutex);
584 return 0;
585}
586
Kiran Kandid2d86b52011-09-09 17:44:28 -0700587static int tabla_pa_gain_get(struct snd_kcontrol *kcontrol,
588 struct snd_ctl_elem_value *ucontrol)
589{
590 u8 ear_pa_gain;
591 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
592
593 ear_pa_gain = snd_soc_read(codec, TABLA_A_RX_EAR_GAIN);
594
595 ear_pa_gain = ear_pa_gain >> 5;
596
597 if (ear_pa_gain == 0x00) {
598 ucontrol->value.integer.value[0] = 0;
599 } else if (ear_pa_gain == 0x04) {
600 ucontrol->value.integer.value[0] = 1;
601 } else {
602 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
603 __func__, ear_pa_gain);
604 return -EINVAL;
605 }
606
607 pr_debug("%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
608
609 return 0;
610}
611
612static int tabla_pa_gain_put(struct snd_kcontrol *kcontrol,
613 struct snd_ctl_elem_value *ucontrol)
614{
615 u8 ear_pa_gain;
616 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
617
618 pr_debug("%s: ucontrol->value.integer.value[0] = %ld\n", __func__,
619 ucontrol->value.integer.value[0]);
620
621 switch (ucontrol->value.integer.value[0]) {
622 case 0:
623 ear_pa_gain = 0x00;
624 break;
625 case 1:
626 ear_pa_gain = 0x80;
627 break;
628 default:
629 return -EINVAL;
630 }
631
632 snd_soc_update_bits(codec, TABLA_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
633 return 0;
634}
635
Ben Romberger1f045a72011-11-04 10:14:57 -0700636static int tabla_get_iir_enable_audio_mixer(
637 struct snd_kcontrol *kcontrol,
638 struct snd_ctl_elem_value *ucontrol)
639{
640 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
641 int iir_idx = ((struct soc_multi_mixer_control *)
642 kcontrol->private_value)->reg;
643 int band_idx = ((struct soc_multi_mixer_control *)
644 kcontrol->private_value)->shift;
645
646 ucontrol->value.integer.value[0] =
647 snd_soc_read(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx)) &
648 (1 << band_idx);
649
650 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
651 iir_idx, band_idx,
652 (uint32_t)ucontrol->value.integer.value[0]);
653 return 0;
654}
655
656static int tabla_put_iir_enable_audio_mixer(
657 struct snd_kcontrol *kcontrol,
658 struct snd_ctl_elem_value *ucontrol)
659{
660 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
661 int iir_idx = ((struct soc_multi_mixer_control *)
662 kcontrol->private_value)->reg;
663 int band_idx = ((struct soc_multi_mixer_control *)
664 kcontrol->private_value)->shift;
665 int value = ucontrol->value.integer.value[0];
666
667 /* Mask first 5 bits, 6-8 are reserved */
668 snd_soc_update_bits(codec, (TABLA_A_CDC_IIR1_CTL + 16 * iir_idx),
669 (1 << band_idx), (value << band_idx));
670
671 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
672 iir_idx, band_idx, value);
673 return 0;
674}
675static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
676 int iir_idx, int band_idx,
677 int coeff_idx)
678{
679 /* Address does not automatically update if reading */
Ben Romberger0915aae2012-02-06 23:32:43 -0800680 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700681 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800682 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700683
684 /* Mask bits top 2 bits since they are reserved */
685 return ((snd_soc_read(codec,
686 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24) |
687 (snd_soc_read(codec,
688 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx)) << 16) |
689 (snd_soc_read(codec,
690 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx)) << 8) |
691 (snd_soc_read(codec,
692 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx)))) &
693 0x3FFFFFFF;
694}
695
696static int tabla_get_iir_band_audio_mixer(
697 struct snd_kcontrol *kcontrol,
698 struct snd_ctl_elem_value *ucontrol)
699{
700 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
701 int iir_idx = ((struct soc_multi_mixer_control *)
702 kcontrol->private_value)->reg;
703 int band_idx = ((struct soc_multi_mixer_control *)
704 kcontrol->private_value)->shift;
705
706 ucontrol->value.integer.value[0] =
707 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
708 ucontrol->value.integer.value[1] =
709 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
710 ucontrol->value.integer.value[2] =
711 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
712 ucontrol->value.integer.value[3] =
713 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
714 ucontrol->value.integer.value[4] =
715 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
716
717 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
718 "%s: IIR #%d band #%d b1 = 0x%x\n"
719 "%s: IIR #%d band #%d b2 = 0x%x\n"
720 "%s: IIR #%d band #%d a1 = 0x%x\n"
721 "%s: IIR #%d band #%d a2 = 0x%x\n",
722 __func__, iir_idx, band_idx,
723 (uint32_t)ucontrol->value.integer.value[0],
724 __func__, iir_idx, band_idx,
725 (uint32_t)ucontrol->value.integer.value[1],
726 __func__, iir_idx, band_idx,
727 (uint32_t)ucontrol->value.integer.value[2],
728 __func__, iir_idx, band_idx,
729 (uint32_t)ucontrol->value.integer.value[3],
730 __func__, iir_idx, band_idx,
731 (uint32_t)ucontrol->value.integer.value[4]);
732 return 0;
733}
734
735static void set_iir_band_coeff(struct snd_soc_codec *codec,
736 int iir_idx, int band_idx,
737 int coeff_idx, uint32_t value)
738{
739 /* Mask top 3 bits, 6-8 are reserved */
740 /* Update address manually each time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800741 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700742 (TABLA_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800743 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700744
745 /* Mask top 2 bits, 7-8 are reserved */
Ben Romberger0915aae2012-02-06 23:32:43 -0800746 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700747 (TABLA_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800748 (value >> 24) & 0x3F);
Ben Romberger1f045a72011-11-04 10:14:57 -0700749
750 /* Isolate 8bits at a time */
Ben Romberger0915aae2012-02-06 23:32:43 -0800751 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700752 (TABLA_A_CDC_IIR1_COEF_B3_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800753 (value >> 16) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700754
Ben Romberger0915aae2012-02-06 23:32:43 -0800755 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700756 (TABLA_A_CDC_IIR1_COEF_B4_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800757 (value >> 8) & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700758
Ben Romberger0915aae2012-02-06 23:32:43 -0800759 snd_soc_write(codec,
Ben Romberger1f045a72011-11-04 10:14:57 -0700760 (TABLA_A_CDC_IIR1_COEF_B5_CTL + 16 * iir_idx),
Ben Romberger0915aae2012-02-06 23:32:43 -0800761 value & 0xFF);
Ben Romberger1f045a72011-11-04 10:14:57 -0700762}
763
764static int tabla_put_iir_band_audio_mixer(
765 struct snd_kcontrol *kcontrol,
766 struct snd_ctl_elem_value *ucontrol)
767{
768 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
769 int iir_idx = ((struct soc_multi_mixer_control *)
770 kcontrol->private_value)->reg;
771 int band_idx = ((struct soc_multi_mixer_control *)
772 kcontrol->private_value)->shift;
773
774 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
775 ucontrol->value.integer.value[0]);
776 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
777 ucontrol->value.integer.value[1]);
778 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
779 ucontrol->value.integer.value[2]);
780 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
781 ucontrol->value.integer.value[3]);
782 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
783 ucontrol->value.integer.value[4]);
784
785 pr_debug("%s: IIR #%d band #%d b0 = 0x%x\n"
786 "%s: IIR #%d band #%d b1 = 0x%x\n"
787 "%s: IIR #%d band #%d b2 = 0x%x\n"
788 "%s: IIR #%d band #%d a1 = 0x%x\n"
789 "%s: IIR #%d band #%d a2 = 0x%x\n",
790 __func__, iir_idx, band_idx,
791 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
792 __func__, iir_idx, band_idx,
793 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
794 __func__, iir_idx, band_idx,
795 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
796 __func__, iir_idx, band_idx,
797 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
798 __func__, iir_idx, band_idx,
799 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
800 return 0;
801}
802
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800803static int tabla_compander_gain_offset(
804 struct snd_soc_codec *codec, u32 enable,
Kuirong Wang678e4172012-06-26 15:35:22 -0700805 unsigned int reg, int mask, int event, u32 comp)
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800806{
807 int pa_mode = snd_soc_read(codec, reg) & mask;
808 int gain_offset = 0;
809 /* if PMU && enable is 1-> offset is 3
810 * if PMU && enable is 0-> offset is 0
811 * if PMD && pa_mode is PA -> offset is 0: PMU compander is off
812 * if PMD && pa_mode is comp -> offset is -3: PMU compander is on.
813 */
814
Kuirong Wang678e4172012-06-26 15:35:22 -0700815 if (SND_SOC_DAPM_EVENT_ON(event) && (enable != 0)) {
816 if (comp == COMPANDER_1)
817 gain_offset = TABLA_COMP_DIGITAL_GAIN_HP_OFFSET;
818 if (comp == COMPANDER_2)
819 gain_offset = TABLA_COMP_DIGITAL_GAIN_LINEOUT_OFFSET;
820 }
821 if (SND_SOC_DAPM_EVENT_OFF(event) && (pa_mode == 0)) {
822 if (comp == COMPANDER_1)
823 gain_offset = -TABLA_COMP_DIGITAL_GAIN_HP_OFFSET;
824 if (comp == COMPANDER_2)
825 gain_offset = -TABLA_COMP_DIGITAL_GAIN_LINEOUT_OFFSET;
826
827 }
828 pr_debug("%s: compander #%d gain_offset %d\n",
829 __func__, comp + 1, gain_offset);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800830 return gain_offset;
831}
832
833
834static int tabla_config_gain_compander(
835 struct snd_soc_codec *codec,
836 u32 compander, u32 enable, int event)
837{
838 int value = 0;
839 int mask = 1 << 4;
840 int gain = 0;
841 int gain_offset;
842 if (compander >= COMPANDER_MAX) {
843 pr_err("%s: Error, invalid compander channel\n", __func__);
844 return -EINVAL;
845 }
846
847 if ((enable == 0) || SND_SOC_DAPM_EVENT_OFF(event))
848 value = 1 << 4;
849
850 if (compander == COMPANDER_1) {
851 gain_offset = tabla_compander_gain_offset(codec, enable,
Kuirong Wang678e4172012-06-26 15:35:22 -0700852 TABLA_A_RX_HPH_L_GAIN, mask, event, compander);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800853 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_GAIN, mask, value);
854 gain = snd_soc_read(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL);
855 snd_soc_update_bits(codec, TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
856 0xFF, gain - gain_offset);
857 gain_offset = tabla_compander_gain_offset(codec, enable,
Kuirong Wang678e4172012-06-26 15:35:22 -0700858 TABLA_A_RX_HPH_R_GAIN, mask, event, compander);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800859 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_GAIN, mask, value);
860 gain = snd_soc_read(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL);
861 snd_soc_update_bits(codec, TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
862 0xFF, gain - gain_offset);
863 } else if (compander == COMPANDER_2) {
864 gain_offset = tabla_compander_gain_offset(codec, enable,
Kuirong Wang678e4172012-06-26 15:35:22 -0700865 TABLA_A_RX_LINE_1_GAIN, mask, event, compander);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800866 snd_soc_update_bits(codec, TABLA_A_RX_LINE_1_GAIN, mask, value);
867 gain = snd_soc_read(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL);
868 snd_soc_update_bits(codec, TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
869 0xFF, gain - gain_offset);
870 gain_offset = tabla_compander_gain_offset(codec, enable,
Kuirong Wang678e4172012-06-26 15:35:22 -0700871 TABLA_A_RX_LINE_3_GAIN, mask, event, compander);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800872 snd_soc_update_bits(codec, TABLA_A_RX_LINE_3_GAIN, mask, value);
873 gain = snd_soc_read(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL);
874 snd_soc_update_bits(codec, TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
875 0xFF, gain - gain_offset);
876 gain_offset = tabla_compander_gain_offset(codec, enable,
Kuirong Wang678e4172012-06-26 15:35:22 -0700877 TABLA_A_RX_LINE_2_GAIN, mask, event, compander);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800878 snd_soc_update_bits(codec, TABLA_A_RX_LINE_2_GAIN, mask, value);
879 gain = snd_soc_read(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL);
880 snd_soc_update_bits(codec, TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
881 0xFF, gain - gain_offset);
882 gain_offset = tabla_compander_gain_offset(codec, enable,
Kuirong Wang678e4172012-06-26 15:35:22 -0700883 TABLA_A_RX_LINE_4_GAIN, mask, event, compander);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800884 snd_soc_update_bits(codec, TABLA_A_RX_LINE_4_GAIN, mask, value);
885 gain = snd_soc_read(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL);
886 snd_soc_update_bits(codec, TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
887 0xFF, gain - gain_offset);
888 }
889 return 0;
890}
891static int tabla_get_compander(struct snd_kcontrol *kcontrol,
892 struct snd_ctl_elem_value *ucontrol)
893{
894
895 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
896 int comp = ((struct soc_multi_mixer_control *)
897 kcontrol->private_value)->max;
898 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
899
900 ucontrol->value.integer.value[0] = tabla->comp_enabled[comp];
901
902 return 0;
903}
904
905static int tabla_set_compander(struct snd_kcontrol *kcontrol,
906 struct snd_ctl_elem_value *ucontrol)
907{
908 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
909 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
910 int comp = ((struct soc_multi_mixer_control *)
911 kcontrol->private_value)->max;
912 int value = ucontrol->value.integer.value[0];
Kuirong Wang678e4172012-06-26 15:35:22 -0700913 pr_debug("%s: compander #%d enable %d\n",
914 __func__, comp + 1, value);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800915 if (value == tabla->comp_enabled[comp]) {
916 pr_debug("%s: compander #%d enable %d no change\n",
Kuirong Wang678e4172012-06-26 15:35:22 -0700917 __func__, comp + 1, value);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800918 return 0;
919 }
920 tabla->comp_enabled[comp] = value;
921 return 0;
922}
923
924
925static int tabla_config_compander(struct snd_soc_dapm_widget *w,
926 struct snd_kcontrol *kcontrol,
927 int event)
928{
929 struct snd_soc_codec *codec = w->codec;
930 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
931 u32 rate = tabla->comp_fs[w->shift];
Kuirong Wang678e4172012-06-26 15:35:22 -0700932 u32 status;
933 unsigned long timeout;
934 pr_debug("%s: compander #%d enable %d event %d\n",
935 __func__, w->shift + 1,
936 tabla->comp_enabled[w->shift], event);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800937 switch (event) {
938 case SND_SOC_DAPM_PRE_PMU:
939 if (tabla->comp_enabled[w->shift] != 0) {
940 /* Enable both L/R compander clocks */
941 snd_soc_update_bits(codec,
942 TABLA_A_CDC_CLK_RX_B2_CTL,
Kuirong Wang678e4172012-06-26 15:35:22 -0700943 1 << comp_shift[w->shift],
944 1 << comp_shift[w->shift]);
945 /* Clear the HALT for the compander*/
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800946 snd_soc_update_bits(codec,
947 TABLA_A_CDC_COMP1_B1_CTL +
948 w->shift * 8, 1 << 2, 0);
949 /* Toggle compander reset bits*/
950 snd_soc_update_bits(codec,
951 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
Kuirong Wang678e4172012-06-26 15:35:22 -0700952 1 << comp_shift[w->shift],
953 1 << comp_shift[w->shift]);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800954 snd_soc_update_bits(codec,
955 TABLA_A_CDC_CLK_OTHR_RESET_CTL,
Kuirong Wang678e4172012-06-26 15:35:22 -0700956 1 << comp_shift[w->shift], 0);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800957 tabla_config_gain_compander(codec, w->shift, 1, event);
Kuirong Wang678e4172012-06-26 15:35:22 -0700958 /* Compander enable -> 0x370/0x378*/
959 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
960 w->shift * 8, 0x03, 0x03);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800961 /* Update the RMS meter resampling*/
962 snd_soc_update_bits(codec,
963 TABLA_A_CDC_COMP1_B3_CTL +
964 w->shift * 8, 0xFF, 0x01);
Kuirong Wang678e4172012-06-26 15:35:22 -0700965 snd_soc_update_bits(codec,
966 TABLA_A_CDC_COMP1_B2_CTL +
967 w->shift * 8, 0xF0, 0x50);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800968 /* Wait for 1ms*/
Kuirong Wang678e4172012-06-26 15:35:22 -0700969 usleep_range(5000, 5000);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800970 }
971 break;
972 case SND_SOC_DAPM_POST_PMU:
973 /* Set sample rate dependent paramater*/
974 if (tabla->comp_enabled[w->shift] != 0) {
975 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_FS_CFG +
Kuirong Wang4bb1b9f2013-01-28 10:17:13 -0800976 w->shift * 8, 0x07, rate);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800977 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
978 w->shift * 8, 0x0F,
979 comp_samp_params[rate].peak_det_timeout);
980 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B2_CTL +
981 w->shift * 8, 0xF0,
982 comp_samp_params[rate].rms_meter_div_fact);
983 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B3_CTL +
984 w->shift * 8, 0xFF,
985 comp_samp_params[rate].rms_meter_resamp_fact);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800986 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
Kuirong Wang678e4172012-06-26 15:35:22 -0700987 w->shift * 8, 0x38,
988 comp_samp_params[rate].shutdown_timeout);
Kuirong Wang0f8ade32012-02-27 16:29:45 -0800989 }
990 break;
991 case SND_SOC_DAPM_PRE_PMD:
Kuirong Wang678e4172012-06-26 15:35:22 -0700992 if (tabla->comp_enabled[w->shift] != 0) {
993 status = snd_soc_read(codec,
994 TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS +
995 w->shift * 8);
996 pr_debug("%s: compander #%d shutdown status %d in event %d\n",
997 __func__, w->shift + 1, status, event);
998 /* Halt the compander*/
999 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
1000 w->shift * 8, 1 << 2, 1 << 2);
1001 }
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001002 break;
1003 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang678e4172012-06-26 15:35:22 -07001004 if (tabla->comp_enabled[w->shift] != 0) {
1005 /* Wait up to a second for shutdown complete */
1006 timeout = jiffies + HZ;
1007 do {
1008 status = snd_soc_read(codec,
1009 TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS +
1010 w->shift * 8);
1011 if (status == 0x3)
1012 break;
1013 usleep_range(5000, 5000);
1014 } while (!(time_after(jiffies, timeout)));
1015 /* Restore the gain */
1016 tabla_config_gain_compander(codec, w->shift,
1017 tabla->comp_enabled[w->shift],
1018 event);
1019 /* Disable the compander*/
1020 snd_soc_update_bits(codec, TABLA_A_CDC_COMP1_B1_CTL +
1021 w->shift * 8, 0x03, 0x00);
1022 /* Turn off the clock for compander in pair*/
1023 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_B2_CTL,
1024 0x03 << comp_shift[w->shift], 0);
1025 /* Clear the HALT for the compander*/
1026 snd_soc_update_bits(codec,
1027 TABLA_A_CDC_COMP1_B1_CTL +
1028 w->shift * 8, 1 << 2, 0);
1029 }
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001030 break;
1031 }
1032 return 0;
1033}
1034
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08001035static const char *const tabla_anc_func_text[] = {"OFF", "ON"};
1036static const struct soc_enum tabla_anc_func_enum =
1037 SOC_ENUM_SINGLE_EXT(2, tabla_anc_func_text);
1038
Kiran Kandid2d86b52011-09-09 17:44:28 -07001039static const char *tabla_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
1040static const struct soc_enum tabla_ear_pa_gain_enum[] = {
1041 SOC_ENUM_SINGLE_EXT(2, tabla_ear_pa_gain_text),
1042};
1043
Santosh Mardi024010f2011-10-18 06:27:21 +05301044/*cut of frequency for high pass filter*/
1045static const char *cf_text[] = {
1046 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
1047};
1048
1049static const struct soc_enum cf_dec1_enum =
1050 SOC_ENUM_SINGLE(TABLA_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
1051
1052static const struct soc_enum cf_dec2_enum =
1053 SOC_ENUM_SINGLE(TABLA_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
1054
1055static const struct soc_enum cf_dec3_enum =
1056 SOC_ENUM_SINGLE(TABLA_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
1057
1058static const struct soc_enum cf_dec4_enum =
1059 SOC_ENUM_SINGLE(TABLA_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
1060
1061static const struct soc_enum cf_dec5_enum =
1062 SOC_ENUM_SINGLE(TABLA_A_CDC_TX5_MUX_CTL, 4, 3, cf_text);
1063
1064static const struct soc_enum cf_dec6_enum =
1065 SOC_ENUM_SINGLE(TABLA_A_CDC_TX6_MUX_CTL, 4, 3, cf_text);
1066
1067static const struct soc_enum cf_dec7_enum =
1068 SOC_ENUM_SINGLE(TABLA_A_CDC_TX7_MUX_CTL, 4, 3, cf_text);
1069
1070static const struct soc_enum cf_dec8_enum =
1071 SOC_ENUM_SINGLE(TABLA_A_CDC_TX8_MUX_CTL, 4, 3, cf_text);
1072
1073static const struct soc_enum cf_dec9_enum =
1074 SOC_ENUM_SINGLE(TABLA_A_CDC_TX9_MUX_CTL, 4, 3, cf_text);
1075
1076static const struct soc_enum cf_dec10_enum =
1077 SOC_ENUM_SINGLE(TABLA_A_CDC_TX10_MUX_CTL, 4, 3, cf_text);
1078
1079static const struct soc_enum cf_rxmix1_enum =
1080 SOC_ENUM_SINGLE(TABLA_A_CDC_RX1_B4_CTL, 1, 3, cf_text);
1081
1082static const struct soc_enum cf_rxmix2_enum =
1083 SOC_ENUM_SINGLE(TABLA_A_CDC_RX2_B4_CTL, 1, 3, cf_text);
1084
1085static const struct soc_enum cf_rxmix3_enum =
1086 SOC_ENUM_SINGLE(TABLA_A_CDC_RX3_B4_CTL, 1, 3, cf_text);
1087
1088static const struct soc_enum cf_rxmix4_enum =
1089 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B4_CTL, 1, 3, cf_text);
1090
1091static const struct soc_enum cf_rxmix5_enum =
1092 SOC_ENUM_SINGLE(TABLA_A_CDC_RX5_B4_CTL, 1, 3, cf_text)
1093;
1094static const struct soc_enum cf_rxmix6_enum =
1095 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B4_CTL, 1, 3, cf_text);
1096
1097static const struct soc_enum cf_rxmix7_enum =
1098 SOC_ENUM_SINGLE(TABLA_A_CDC_RX7_B4_CTL, 1, 3, cf_text);
1099
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100static const struct snd_kcontrol_new tabla_snd_controls[] = {
Kiran Kandid2d86b52011-09-09 17:44:28 -07001101
1102 SOC_ENUM_EXT("EAR PA Gain", tabla_ear_pa_gain_enum[0],
1103 tabla_pa_gain_get, tabla_pa_gain_put),
1104
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 SOC_SINGLE_TLV("LINEOUT1 Volume", TABLA_A_RX_LINE_1_GAIN, 0, 12, 1,
1106 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001107 SOC_SINGLE_TLV("LINEOUT2 Volume", TABLA_A_RX_LINE_2_GAIN, 0, 12, 1,
1108 line_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001109 SOC_SINGLE_TLV("LINEOUT3 Volume", TABLA_A_RX_LINE_3_GAIN, 0, 12, 1,
1110 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001111 SOC_SINGLE_TLV("LINEOUT4 Volume", TABLA_A_RX_LINE_4_GAIN, 0, 12, 1,
1112 line_gain),
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001113 SOC_SINGLE_TLV("LINEOUT5 Volume", TABLA_A_RX_LINE_5_GAIN, 0, 12, 1,
1114 line_gain),
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001116 SOC_SINGLE_TLV("HPHL Volume", TABLA_A_RX_HPH_L_GAIN, 0, 12, 1,
1117 line_gain),
1118 SOC_SINGLE_TLV("HPHR Volume", TABLA_A_RX_HPH_R_GAIN, 0, 12, 1,
1119 line_gain),
1120
Bradley Rubin410383f2011-07-22 13:44:23 -07001121 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TABLA_A_CDC_RX1_VOL_CTL_B2_CTL,
1122 -84, 40, digital_gain),
1123 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TABLA_A_CDC_RX2_VOL_CTL_B2_CTL,
1124 -84, 40, digital_gain),
1125 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TABLA_A_CDC_RX3_VOL_CTL_B2_CTL,
1126 -84, 40, digital_gain),
1127 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TABLA_A_CDC_RX4_VOL_CTL_B2_CTL,
1128 -84, 40, digital_gain),
1129 SOC_SINGLE_S8_TLV("RX5 Digital Volume", TABLA_A_CDC_RX5_VOL_CTL_B2_CTL,
1130 -84, 40, digital_gain),
1131 SOC_SINGLE_S8_TLV("RX6 Digital Volume", TABLA_A_CDC_RX6_VOL_CTL_B2_CTL,
1132 -84, 40, digital_gain),
Neema Shettyd3a89262012-02-16 10:23:50 -08001133 SOC_SINGLE_S8_TLV("RX7 Digital Volume", TABLA_A_CDC_RX7_VOL_CTL_B2_CTL,
1134 -84, 40, digital_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135
Bradley Rubin410383f2011-07-22 13:44:23 -07001136 SOC_SINGLE_S8_TLV("DEC1 Volume", TABLA_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -07001138 SOC_SINGLE_S8_TLV("DEC2 Volume", TABLA_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 digital_gain),
Bradley Rubin410383f2011-07-22 13:44:23 -07001140 SOC_SINGLE_S8_TLV("DEC3 Volume", TABLA_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
1141 digital_gain),
1142 SOC_SINGLE_S8_TLV("DEC4 Volume", TABLA_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
1143 digital_gain),
1144 SOC_SINGLE_S8_TLV("DEC5 Volume", TABLA_A_CDC_TX5_VOL_CTL_GAIN, -84, 40,
1145 digital_gain),
1146 SOC_SINGLE_S8_TLV("DEC6 Volume", TABLA_A_CDC_TX6_VOL_CTL_GAIN, -84, 40,
1147 digital_gain),
1148 SOC_SINGLE_S8_TLV("DEC7 Volume", TABLA_A_CDC_TX7_VOL_CTL_GAIN, -84, 40,
1149 digital_gain),
1150 SOC_SINGLE_S8_TLV("DEC8 Volume", TABLA_A_CDC_TX8_VOL_CTL_GAIN, -84, 40,
1151 digital_gain),
1152 SOC_SINGLE_S8_TLV("DEC9 Volume", TABLA_A_CDC_TX9_VOL_CTL_GAIN, -84, 40,
1153 digital_gain),
1154 SOC_SINGLE_S8_TLV("DEC10 Volume", TABLA_A_CDC_TX10_VOL_CTL_GAIN, -84,
1155 40, digital_gain),
Patrick Lai29006372011-09-28 17:57:42 -07001156 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TABLA_A_CDC_IIR1_GAIN_B1_CTL, -84,
1157 40, digital_gain),
1158 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TABLA_A_CDC_IIR1_GAIN_B2_CTL, -84,
1159 40, digital_gain),
1160 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TABLA_A_CDC_IIR1_GAIN_B3_CTL, -84,
1161 40, digital_gain),
1162 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TABLA_A_CDC_IIR1_GAIN_B4_CTL, -84,
1163 40, digital_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001164 SOC_SINGLE_TLV("ADC1 Volume", TABLA_A_TX_1_2_EN, 5, 3, 0, analog_gain),
1165 SOC_SINGLE_TLV("ADC2 Volume", TABLA_A_TX_1_2_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001166 SOC_SINGLE_TLV("ADC3 Volume", TABLA_A_TX_3_4_EN, 5, 3, 0, analog_gain),
1167 SOC_SINGLE_TLV("ADC4 Volume", TABLA_A_TX_3_4_EN, 1, 3, 0, analog_gain),
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001168 SOC_SINGLE_TLV("ADC5 Volume", TABLA_A_TX_5_6_EN, 5, 3, 0, analog_gain),
1169 SOC_SINGLE_TLV("ADC6 Volume", TABLA_A_TX_5_6_EN, 1, 3, 0, analog_gain),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001171 SOC_SINGLE_TLV("AUX_PGA_LEFT Volume", TABLA_A_AUX_L_GAIN, 0, 39, 0,
1172 aux_pga_gain),
1173 SOC_SINGLE_TLV("AUX_PGA_RIGHT Volume", TABLA_A_AUX_R_GAIN, 0, 39, 0,
1174 aux_pga_gain),
1175
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176 SOC_SINGLE("MICBIAS1 CAPLESS Switch", TABLA_A_MICB_1_CTL, 4, 1, 1),
Santosh Mardi680b41e2011-11-22 16:51:16 -08001177 SOC_SINGLE("MICBIAS2 CAPLESS Switch", TABLA_A_MICB_2_CTL, 4, 1, 1),
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001178 SOC_SINGLE("MICBIAS3 CAPLESS Switch", TABLA_A_MICB_3_CTL, 4, 1, 1),
Bradley Rubina7096d02011-08-03 18:29:02 -07001179
1180 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tabla_get_anc_slot,
1181 tabla_put_anc_slot),
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08001182 SOC_ENUM_EXT("ANC Function", tabla_anc_func_enum, tabla_get_anc_func,
1183 tabla_put_anc_func),
Santosh Mardi024010f2011-10-18 06:27:21 +05301184 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
1185 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
1186 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
1187 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
1188 SOC_ENUM("TX5 HPF cut off", cf_dec5_enum),
1189 SOC_ENUM("TX6 HPF cut off", cf_dec6_enum),
1190 SOC_ENUM("TX7 HPF cut off", cf_dec7_enum),
1191 SOC_ENUM("TX8 HPF cut off", cf_dec8_enum),
1192 SOC_ENUM("TX9 HPF cut off", cf_dec9_enum),
1193 SOC_ENUM("TX10 HPF cut off", cf_dec10_enum),
1194
1195 SOC_SINGLE("TX1 HPF Switch", TABLA_A_CDC_TX1_MUX_CTL, 3, 1, 0),
1196 SOC_SINGLE("TX2 HPF Switch", TABLA_A_CDC_TX2_MUX_CTL, 3, 1, 0),
1197 SOC_SINGLE("TX3 HPF Switch", TABLA_A_CDC_TX3_MUX_CTL, 3, 1, 0),
1198 SOC_SINGLE("TX4 HPF Switch", TABLA_A_CDC_TX4_MUX_CTL, 3, 1, 0),
1199 SOC_SINGLE("TX5 HPF Switch", TABLA_A_CDC_TX5_MUX_CTL, 3, 1, 0),
1200 SOC_SINGLE("TX6 HPF Switch", TABLA_A_CDC_TX6_MUX_CTL, 3, 1, 0),
1201 SOC_SINGLE("TX7 HPF Switch", TABLA_A_CDC_TX7_MUX_CTL, 3, 1, 0),
1202 SOC_SINGLE("TX8 HPF Switch", TABLA_A_CDC_TX8_MUX_CTL, 3, 1, 0),
1203 SOC_SINGLE("TX9 HPF Switch", TABLA_A_CDC_TX9_MUX_CTL, 3, 1, 0),
1204 SOC_SINGLE("TX10 HPF Switch", TABLA_A_CDC_TX10_MUX_CTL, 3, 1, 0),
1205
1206 SOC_SINGLE("RX1 HPF Switch", TABLA_A_CDC_RX1_B5_CTL, 2, 1, 0),
1207 SOC_SINGLE("RX2 HPF Switch", TABLA_A_CDC_RX2_B5_CTL, 2, 1, 0),
1208 SOC_SINGLE("RX3 HPF Switch", TABLA_A_CDC_RX3_B5_CTL, 2, 1, 0),
1209 SOC_SINGLE("RX4 HPF Switch", TABLA_A_CDC_RX4_B5_CTL, 2, 1, 0),
1210 SOC_SINGLE("RX5 HPF Switch", TABLA_A_CDC_RX5_B5_CTL, 2, 1, 0),
1211 SOC_SINGLE("RX6 HPF Switch", TABLA_A_CDC_RX6_B5_CTL, 2, 1, 0),
1212 SOC_SINGLE("RX7 HPF Switch", TABLA_A_CDC_RX7_B5_CTL, 2, 1, 0),
1213
1214 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1215 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1216 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
1217 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
1218 SOC_ENUM("RX5 HPF cut off", cf_rxmix5_enum),
1219 SOC_ENUM("RX6 HPF cut off", cf_rxmix6_enum),
1220 SOC_ENUM("RX7 HPF cut off", cf_rxmix7_enum),
Ben Romberger1f045a72011-11-04 10:14:57 -07001221
1222 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1223 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1224 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1225 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1226 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1227 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1228 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1229 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1230 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1231 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1232 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1233 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1234 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1235 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1236 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1237 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1238 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1239 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1240 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1241 tabla_get_iir_enable_audio_mixer, tabla_put_iir_enable_audio_mixer),
1242
1243 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1244 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1245 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1246 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1247 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1248 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1249 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1250 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1251 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1252 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1253 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1254 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1255 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1256 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1257 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1258 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1259 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1260 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
1261 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1262 tabla_get_iir_band_audio_mixer, tabla_put_iir_band_audio_mixer),
Kuirong Wang0f8ade32012-02-27 16:29:45 -08001263 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, 1, COMPANDER_1, 0,
1264 tabla_get_compander, tabla_set_compander),
1265 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, 0, COMPANDER_2, 0,
1266 tabla_get_compander, tabla_set_compander),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267};
1268
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08001269static const struct snd_kcontrol_new tabla_1_x_snd_controls[] = {
1270 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_1_A_MICB_4_CTL, 4, 1, 1),
1271};
1272
1273static const struct snd_kcontrol_new tabla_2_higher_snd_controls[] = {
1274 SOC_SINGLE("MICBIAS4 CAPLESS Switch", TABLA_2_A_MICB_4_CTL, 4, 1, 1),
1275};
1276
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001277static const char *rx_mix1_text[] = {
1278 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1279 "RX5", "RX6", "RX7"
1280};
1281
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001282static const char *rx_mix2_text[] = {
1283 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
1284};
1285
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001286static const char *rx_dsm_text[] = {
1287 "CIC_OUT", "DSM_INV"
1288};
1289
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001290static const char *sb_tx1_mux_text[] = {
1291 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1292 "DEC1"
1293};
1294
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001295static const char *sb_tx2_mux_text[] = {
1296 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1297 "DEC2"
1298};
1299
1300static const char *sb_tx3_mux_text[] = {
1301 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1302 "DEC3"
1303};
1304
1305static const char *sb_tx4_mux_text[] = {
1306 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1307 "DEC4"
1308};
1309
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001310static const char *sb_tx5_mux_text[] = {
1311 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1312 "DEC5"
1313};
1314
1315static const char *sb_tx6_mux_text[] = {
1316 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1317 "DEC6"
1318};
1319
1320static const char const *sb_tx7_to_tx10_mux_text[] = {
1321 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4", "RMIX5", "RMIX6", "RMIX7",
1322 "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1323 "DEC9", "DEC10"
1324};
1325
1326static const char *dec1_mux_text[] = {
1327 "ZERO", "DMIC1", "ADC6",
1328};
1329
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001330static const char *dec2_mux_text[] = {
1331 "ZERO", "DMIC2", "ADC5",
1332};
1333
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001334static const char *dec3_mux_text[] = {
1335 "ZERO", "DMIC3", "ADC4",
1336};
1337
1338static const char *dec4_mux_text[] = {
1339 "ZERO", "DMIC4", "ADC3",
1340};
1341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342static const char *dec5_mux_text[] = {
1343 "ZERO", "DMIC5", "ADC2",
1344};
1345
1346static const char *dec6_mux_text[] = {
1347 "ZERO", "DMIC6", "ADC1",
1348};
1349
1350static const char const *dec7_mux_text[] = {
1351 "ZERO", "DMIC1", "DMIC6", "ADC1", "ADC6", "ANC1_FB", "ANC2_FB",
1352};
1353
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001354static const char *dec8_mux_text[] = {
1355 "ZERO", "DMIC2", "DMIC5", "ADC2", "ADC5",
1356};
1357
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001358static const char *dec9_mux_text[] = {
1359 "ZERO", "DMIC4", "DMIC5", "ADC2", "ADC3", "ADCMB", "ANC1_FB", "ANC2_FB",
1360};
1361
1362static const char *dec10_mux_text[] = {
1363 "ZERO", "DMIC3", "DMIC6", "ADC1", "ADC4", "ADCMB", "ANC1_FB", "ANC2_FB",
1364};
1365
Bradley Rubin229c6a52011-07-12 16:18:48 -07001366static const char const *anc_mux_text[] = {
1367 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1368 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1369};
1370
1371static const char const *anc1_fb_mux_text[] = {
1372 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1373};
1374
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07001375static const char *const iir_inp1_text[] = {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4", "DEC5", "DEC6", "DEC7", "DEC8",
1377 "DEC9", "DEC10", "RX1", "RX2", "RX3", "RX4", "RX5", "RX6", "RX7"
1378};
1379
1380static const struct soc_enum rx_mix1_inp1_chain_enum =
1381 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_mix1_text);
1382
Bradley Rubin229c6a52011-07-12 16:18:48 -07001383static const struct soc_enum rx_mix1_inp2_chain_enum =
1384 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_mix1_text);
1385
Kiran Kandia9fffe92012-05-20 23:42:30 -07001386static const struct soc_enum rx_mix1_inp3_chain_enum =
1387 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_mix1_text);
1388
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001389static const struct soc_enum rx2_mix1_inp1_chain_enum =
1390 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_mix1_text);
1391
Bradley Rubin229c6a52011-07-12 16:18:48 -07001392static const struct soc_enum rx2_mix1_inp2_chain_enum =
1393 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_mix1_text);
1394
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395static const struct soc_enum rx3_mix1_inp1_chain_enum =
1396 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 0, 12, rx_mix1_text);
1397
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001398static const struct soc_enum rx3_mix1_inp2_chain_enum =
1399 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B1_CTL, 4, 12, rx_mix1_text);
1400
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401static const struct soc_enum rx4_mix1_inp1_chain_enum =
1402 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 0, 12, rx_mix1_text);
1403
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001404static const struct soc_enum rx4_mix1_inp2_chain_enum =
1405 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX4_B1_CTL, 4, 12, rx_mix1_text);
1406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407static const struct soc_enum rx5_mix1_inp1_chain_enum =
1408 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 0, 12, rx_mix1_text);
1409
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001410static const struct soc_enum rx5_mix1_inp2_chain_enum =
1411 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX5_B1_CTL, 4, 12, rx_mix1_text);
1412
1413static const struct soc_enum rx6_mix1_inp1_chain_enum =
1414 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 0, 12, rx_mix1_text);
1415
1416static const struct soc_enum rx6_mix1_inp2_chain_enum =
1417 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX6_B1_CTL, 4, 12, rx_mix1_text);
1418
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001419static const struct soc_enum rx7_mix1_inp1_chain_enum =
1420 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 0, 12, rx_mix1_text);
1421
1422static const struct soc_enum rx7_mix1_inp2_chain_enum =
1423 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX7_B1_CTL, 4, 12, rx_mix1_text);
1424
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001425static const struct soc_enum rx1_mix2_inp1_chain_enum =
1426 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
1427
1428static const struct soc_enum rx1_mix2_inp2_chain_enum =
1429 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
1430
1431static const struct soc_enum rx2_mix2_inp1_chain_enum =
1432 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
1433
1434static const struct soc_enum rx2_mix2_inp2_chain_enum =
1435 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
1436
1437static const struct soc_enum rx3_mix2_inp1_chain_enum =
1438 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B3_CTL, 0, 5, rx_mix2_text);
1439
1440static const struct soc_enum rx3_mix2_inp2_chain_enum =
1441 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_RX3_B3_CTL, 3, 5, rx_mix2_text);
1442
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001443static const struct soc_enum rx4_dsm_enum =
1444 SOC_ENUM_SINGLE(TABLA_A_CDC_RX4_B6_CTL, 4, 2, rx_dsm_text);
1445
1446static const struct soc_enum rx6_dsm_enum =
1447 SOC_ENUM_SINGLE(TABLA_A_CDC_RX6_B6_CTL, 4, 2, rx_dsm_text);
1448
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001449static const struct soc_enum sb_tx1_mux_enum =
1450 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0, 9, sb_tx1_mux_text);
1451
1452static const struct soc_enum sb_tx2_mux_enum =
1453 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0, 9, sb_tx2_mux_text);
1454
1455static const struct soc_enum sb_tx3_mux_enum =
1456 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0, 9, sb_tx3_mux_text);
1457
1458static const struct soc_enum sb_tx4_mux_enum =
1459 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0, 9, sb_tx4_mux_text);
1460
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461static const struct soc_enum sb_tx5_mux_enum =
1462 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
1463
1464static const struct soc_enum sb_tx6_mux_enum =
1465 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0, 9, sb_tx6_mux_text);
1466
1467static const struct soc_enum sb_tx7_mux_enum =
1468 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0, 18,
1469 sb_tx7_to_tx10_mux_text);
1470
1471static const struct soc_enum sb_tx8_mux_enum =
1472 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0, 18,
1473 sb_tx7_to_tx10_mux_text);
1474
Kiran Kandi3426e512011-09-13 22:50:10 -07001475static const struct soc_enum sb_tx9_mux_enum =
1476 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0, 18,
1477 sb_tx7_to_tx10_mux_text);
1478
1479static const struct soc_enum sb_tx10_mux_enum =
1480 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0, 18,
1481 sb_tx7_to_tx10_mux_text);
1482
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001483static const struct soc_enum dec1_mux_enum =
1484 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 0, 3, dec1_mux_text);
1485
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001486static const struct soc_enum dec2_mux_enum =
1487 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 2, 3, dec2_mux_text);
1488
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001489static const struct soc_enum dec3_mux_enum =
1490 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 4, 3, dec3_mux_text);
1491
1492static const struct soc_enum dec4_mux_enum =
1493 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B1_CTL, 6, 3, dec4_mux_text);
1494
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001495static const struct soc_enum dec5_mux_enum =
1496 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 0, 3, dec5_mux_text);
1497
1498static const struct soc_enum dec6_mux_enum =
1499 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 2, 3, dec6_mux_text);
1500
1501static const struct soc_enum dec7_mux_enum =
1502 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B2_CTL, 4, 7, dec7_mux_text);
1503
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001504static const struct soc_enum dec8_mux_enum =
1505 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 0, 7, dec8_mux_text);
1506
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001507static const struct soc_enum dec9_mux_enum =
1508 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B3_CTL, 3, 8, dec9_mux_text);
1509
1510static const struct soc_enum dec10_mux_enum =
1511 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_TX_B4_CTL, 0, 8, dec10_mux_text);
1512
Bradley Rubin229c6a52011-07-12 16:18:48 -07001513static const struct soc_enum anc1_mux_enum =
1514 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 0, 16, anc_mux_text);
1515
1516static const struct soc_enum anc2_mux_enum =
1517 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B1_CTL, 4, 16, anc_mux_text);
1518
1519static const struct soc_enum anc1_fb_mux_enum =
1520 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1521
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522static const struct soc_enum iir1_inp1_mux_enum =
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07001523 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ1_B1_CTL, 0, 18, iir_inp1_text);
1524
1525static const struct soc_enum iir2_inp1_mux_enum =
1526 SOC_ENUM_SINGLE(TABLA_A_CDC_CONN_EQ2_B1_CTL, 0, 18, iir_inp1_text);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527
1528static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1529 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1530
Bradley Rubin229c6a52011-07-12 16:18:48 -07001531static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1532 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1533
Kiran Kandia9fffe92012-05-20 23:42:30 -07001534static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1535 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1536
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1538 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1539
Bradley Rubin229c6a52011-07-12 16:18:48 -07001540static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1541 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1542
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1544 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1545
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001546static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1547 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1548
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001549static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1550 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1551
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001552static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1553 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555static const struct snd_kcontrol_new rx5_mix1_inp1_mux =
1556 SOC_DAPM_ENUM("RX5 MIX1 INP1 Mux", rx5_mix1_inp1_chain_enum);
1557
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001558static const struct snd_kcontrol_new rx5_mix1_inp2_mux =
1559 SOC_DAPM_ENUM("RX5 MIX1 INP2 Mux", rx5_mix1_inp2_chain_enum);
1560
1561static const struct snd_kcontrol_new rx6_mix1_inp1_mux =
1562 SOC_DAPM_ENUM("RX6 MIX1 INP1 Mux", rx6_mix1_inp1_chain_enum);
1563
1564static const struct snd_kcontrol_new rx6_mix1_inp2_mux =
1565 SOC_DAPM_ENUM("RX6 MIX1 INP2 Mux", rx6_mix1_inp2_chain_enum);
1566
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07001567static const struct snd_kcontrol_new rx7_mix1_inp1_mux =
1568 SOC_DAPM_ENUM("RX7 MIX1 INP1 Mux", rx7_mix1_inp1_chain_enum);
1569
1570static const struct snd_kcontrol_new rx7_mix1_inp2_mux =
1571 SOC_DAPM_ENUM("RX7 MIX1 INP2 Mux", rx7_mix1_inp2_chain_enum);
1572
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08001573static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1574 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1575
1576static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
1577 SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
1578
1579static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1580 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1581
1582static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
1583 SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
1584
1585static const struct snd_kcontrol_new rx3_mix2_inp1_mux =
1586 SOC_DAPM_ENUM("RX3 MIX2 INP1 Mux", rx3_mix2_inp1_chain_enum);
1587
1588static const struct snd_kcontrol_new rx3_mix2_inp2_mux =
1589 SOC_DAPM_ENUM("RX3 MIX2 INP2 Mux", rx3_mix2_inp2_chain_enum);
1590
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001591static const struct snd_kcontrol_new rx4_dsm_mux =
1592 SOC_DAPM_ENUM("RX4 DSM MUX Mux", rx4_dsm_enum);
1593
1594static const struct snd_kcontrol_new rx6_dsm_mux =
1595 SOC_DAPM_ENUM("RX6 DSM MUX Mux", rx6_dsm_enum);
1596
Kiran Kandi1e6371d2012-03-29 11:48:57 -07001597static const struct snd_kcontrol_new sb_tx1_mux =
1598 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1599
1600static const struct snd_kcontrol_new sb_tx2_mux =
1601 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
1602
1603static const struct snd_kcontrol_new sb_tx3_mux =
1604 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
1605
1606static const struct snd_kcontrol_new sb_tx4_mux =
1607 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
1608
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609static const struct snd_kcontrol_new sb_tx5_mux =
1610 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
1611
1612static const struct snd_kcontrol_new sb_tx6_mux =
1613 SOC_DAPM_ENUM("SLIM TX6 MUX Mux", sb_tx6_mux_enum);
1614
1615static const struct snd_kcontrol_new sb_tx7_mux =
1616 SOC_DAPM_ENUM("SLIM TX7 MUX Mux", sb_tx7_mux_enum);
1617
1618static const struct snd_kcontrol_new sb_tx8_mux =
1619 SOC_DAPM_ENUM("SLIM TX8 MUX Mux", sb_tx8_mux_enum);
1620
Kiran Kandi3426e512011-09-13 22:50:10 -07001621static const struct snd_kcontrol_new sb_tx9_mux =
1622 SOC_DAPM_ENUM("SLIM TX9 MUX Mux", sb_tx9_mux_enum);
1623
1624static const struct snd_kcontrol_new sb_tx10_mux =
1625 SOC_DAPM_ENUM("SLIM TX10 MUX Mux", sb_tx10_mux_enum);
1626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001627
Kiran Kandi59a96b12012-01-16 02:20:03 -08001628static int wcd9310_put_dec_enum(struct snd_kcontrol *kcontrol,
1629 struct snd_ctl_elem_value *ucontrol)
1630{
1631 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1632 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1633 struct snd_soc_codec *codec = w->codec;
1634 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1635 unsigned int dec_mux, decimator;
1636 char *dec_name = NULL;
1637 char *widget_name = NULL;
1638 char *temp;
1639 u16 tx_mux_ctl_reg;
1640 u8 adc_dmic_sel = 0x0;
1641 int ret = 0;
1642
1643 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1644 return -EINVAL;
1645
1646 dec_mux = ucontrol->value.enumerated.item[0];
1647
1648 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1649 if (!widget_name)
1650 return -ENOMEM;
1651 temp = widget_name;
1652
1653 dec_name = strsep(&widget_name, " ");
1654 widget_name = temp;
1655 if (!dec_name) {
1656 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1657 ret = -EINVAL;
1658 goto out;
1659 }
1660
1661 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
1662 if (ret < 0) {
1663 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1664 ret = -EINVAL;
1665 goto out;
1666 }
1667
1668 dev_dbg(w->dapm->dev, "%s(): widget = %s dec_name = %s decimator = %u"
1669 " dec_mux = %u\n", __func__, w->name, dec_name, decimator,
1670 dec_mux);
1671
1672
1673 switch (decimator) {
1674 case 1:
1675 case 2:
1676 case 3:
1677 case 4:
1678 case 5:
1679 case 6:
1680 if (dec_mux == 1)
1681 adc_dmic_sel = 0x1;
1682 else
1683 adc_dmic_sel = 0x0;
1684 break;
1685 case 7:
1686 case 8:
1687 case 9:
1688 case 10:
1689 if ((dec_mux == 1) || (dec_mux == 2))
1690 adc_dmic_sel = 0x1;
1691 else
1692 adc_dmic_sel = 0x0;
1693 break;
1694 default:
1695 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1696 ret = -EINVAL;
1697 goto out;
1698 }
1699
1700 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1701
1702 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1703
1704 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1705
1706out:
1707 kfree(widget_name);
1708 return ret;
1709}
1710
1711#define WCD9310_DEC_ENUM(xname, xenum) \
1712{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1713 .info = snd_soc_info_enum_double, \
1714 .get = snd_soc_dapm_get_enum_double, \
1715 .put = wcd9310_put_dec_enum, \
1716 .private_value = (unsigned long)&xenum }
1717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718static const struct snd_kcontrol_new dec1_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001719 WCD9310_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001721static const struct snd_kcontrol_new dec2_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001722 WCD9310_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001723
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001724static const struct snd_kcontrol_new dec3_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001725 WCD9310_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001726
1727static const struct snd_kcontrol_new dec4_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001728 WCD9310_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001729
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730static const struct snd_kcontrol_new dec5_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001731 WCD9310_DEC_ENUM("DEC5 MUX Mux", dec5_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732
1733static const struct snd_kcontrol_new dec6_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001734 WCD9310_DEC_ENUM("DEC6 MUX Mux", dec6_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735
1736static const struct snd_kcontrol_new dec7_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001737 WCD9310_DEC_ENUM("DEC7 MUX Mux", dec7_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001738
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001739static const struct snd_kcontrol_new dec8_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001740 WCD9310_DEC_ENUM("DEC8 MUX Mux", dec8_mux_enum);
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07001741
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001742static const struct snd_kcontrol_new dec9_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001743 WCD9310_DEC_ENUM("DEC9 MUX Mux", dec9_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001744
1745static const struct snd_kcontrol_new dec10_mux =
Kiran Kandi59a96b12012-01-16 02:20:03 -08001746 WCD9310_DEC_ENUM("DEC10 MUX Mux", dec10_mux_enum);
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07001747
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001748static const struct snd_kcontrol_new iir1_inp1_mux =
1749 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1750
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07001751static const struct snd_kcontrol_new iir2_inp1_mux =
1752 SOC_DAPM_ENUM("IIR2 INP1 Mux", iir2_inp1_mux_enum);
1753
Kiran Kandi59a96b12012-01-16 02:20:03 -08001754static const struct snd_kcontrol_new anc1_mux =
1755 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1756
Bradley Rubin229c6a52011-07-12 16:18:48 -07001757static const struct snd_kcontrol_new anc2_mux =
1758 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001759
Bradley Rubin229c6a52011-07-12 16:18:48 -07001760static const struct snd_kcontrol_new anc1_fb_mux =
1761 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762
Bradley Rubin229c6a52011-07-12 16:18:48 -07001763static const struct snd_kcontrol_new dac1_switch[] = {
1764 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_EAR_EN, 5, 1, 0)
1765};
1766static const struct snd_kcontrol_new hphl_switch[] = {
1767 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1768};
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001769
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08001770static const struct snd_kcontrol_new hphl_pa_mix[] = {
1771 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1772 7, 1, 0),
1773 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1774 7, 1, 0),
1775 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1776 TABLA_A_AUX_L_PA_CONN_INV, 7, 1, 0),
1777 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1778 TABLA_A_AUX_R_PA_CONN_INV, 7, 1, 0),
1779};
1780
1781static const struct snd_kcontrol_new hphr_pa_mix[] = {
1782 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1783 6, 1, 0),
1784 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1785 6, 1, 0),
1786 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1787 TABLA_A_AUX_L_PA_CONN_INV, 6, 1, 0),
1788 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1789 TABLA_A_AUX_R_PA_CONN_INV, 6, 1, 0),
1790};
1791
1792static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1793 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1794 5, 1, 0),
1795 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1796 5, 1, 0),
1797 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1798 TABLA_A_AUX_L_PA_CONN_INV, 5, 1, 0),
1799 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1800 TABLA_A_AUX_R_PA_CONN_INV, 5, 1, 0),
1801};
1802
1803static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1804 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1805 4, 1, 0),
1806 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1807 4, 1, 0),
1808 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1809 TABLA_A_AUX_L_PA_CONN_INV, 4, 1, 0),
1810 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1811 TABLA_A_AUX_R_PA_CONN_INV, 4, 1, 0),
1812};
1813
1814static const struct snd_kcontrol_new lineout3_pa_mix[] = {
1815 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1816 3, 1, 0),
1817 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1818 3, 1, 0),
1819 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1820 TABLA_A_AUX_L_PA_CONN_INV, 3, 1, 0),
1821 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1822 TABLA_A_AUX_R_PA_CONN_INV, 3, 1, 0),
1823};
1824
1825static const struct snd_kcontrol_new lineout4_pa_mix[] = {
1826 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1827 2, 1, 0),
1828 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1829 2, 1, 0),
1830 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1831 TABLA_A_AUX_L_PA_CONN_INV, 2, 1, 0),
1832 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1833 TABLA_A_AUX_R_PA_CONN_INV, 2, 1, 0),
1834};
1835
1836static const struct snd_kcontrol_new lineout5_pa_mix[] = {
1837 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1838 1, 1, 0),
1839 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1840 1, 1, 0),
1841 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1842 TABLA_A_AUX_L_PA_CONN_INV, 1, 1, 0),
1843 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1844 TABLA_A_AUX_R_PA_CONN_INV, 1, 1, 0),
1845};
1846
1847static const struct snd_kcontrol_new ear_pa_mix[] = {
1848 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TABLA_A_AUX_L_PA_CONN,
1849 0, 1, 0),
1850 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TABLA_A_AUX_R_PA_CONN,
1851 0, 1, 0),
1852 SOC_DAPM_SINGLE("AUX_PGA_L_INV Switch",
1853 TABLA_A_AUX_L_PA_CONN_INV, 0, 1, 0),
1854 SOC_DAPM_SINGLE("AUX_PGA_R_INV Switch",
1855 TABLA_A_AUX_R_PA_CONN_INV, 0, 1, 0),
1856};
1857
Kiran Kandi8b3a8302011-09-27 16:13:28 -07001858static const struct snd_kcontrol_new lineout3_ground_switch =
1859 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_3_DAC_CTL, 6, 1, 0);
1860
1861static const struct snd_kcontrol_new lineout4_ground_switch =
1862 SOC_DAPM_SINGLE("Switch", TABLA_A_RX_LINE_4_DAC_CTL, 6, 1, 0);
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07001863
Kuirong Wang906ac472012-07-09 12:54:44 -07001864/* virtual port entries */
1865static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
1866 struct snd_ctl_elem_value *ucontrol)
1867{
1868 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1869 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1870
1871 ucontrol->value.integer.value[0] = widget->value;
1872 return 0;
1873}
1874
1875static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
1876 struct snd_ctl_elem_value *ucontrol)
1877{
1878 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1879 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1880 struct snd_soc_codec *codec = widget->codec;
1881 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
1882 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1883 struct soc_multi_mixer_control *mixer =
1884 ((struct soc_multi_mixer_control *)kcontrol->private_value);
1885 u32 dai_id = widget->shift;
1886 u32 port_id = mixer->shift;
1887 u32 enable = ucontrol->value.integer.value[0];
Venkat Sudhir96dd28c2012-12-04 17:00:19 -08001888 u32 vtable = vport_check_table[dai_id];
Kuirong Wang906ac472012-07-09 12:54:44 -07001889
1890 pr_debug("%s: wname %s cname %s value %u shift %d item %ld\n", __func__,
1891 widget->name, ucontrol->id.name, widget->value, widget->shift,
1892 ucontrol->value.integer.value[0]);
1893
1894 mutex_lock(&codec->mutex);
1895 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1896 if (dai_id != AIF1_CAP) {
1897 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1898 __func__);
1899 mutex_unlock(&codec->mutex);
1900 return -EINVAL;
1901 }
1902 }
1903 switch (dai_id) {
1904 case AIF1_CAP:
1905 case AIF2_CAP:
1906 case AIF3_CAP:
1907 /* only add to the list if value not set
1908 */
1909 if (enable && !(widget->value & 1 << port_id)) {
Venkat Sudhir96dd28c2012-12-04 17:00:19 -08001910 if (tabla_p->intf_type ==
1911 WCD9XXX_INTERFACE_TYPE_SLIMBUS)
1912 vtable = vport_check_table[dai_id];
1913 if (tabla_p->intf_type == WCD9XXX_INTERFACE_TYPE_I2C)
1914 vtable = vport_i2s_check_table[dai_id];
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001915 if (wcd9xxx_tx_vport_validation(
Venkat Sudhir96dd28c2012-12-04 17:00:19 -08001916 vtable,
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001917 port_id,
1918 tabla_p->dai)) {
Kuirong Wang906ac472012-07-09 12:54:44 -07001919 pr_info("%s: TX%u is used by other virtual port\n",
1920 __func__, port_id + 1);
1921 mutex_unlock(&codec->mutex);
1922 return -EINVAL;
1923 }
1924 widget->value |= 1 << port_id;
1925 list_add_tail(&core->tx_chs[port_id].list,
1926 &tabla_p->dai[dai_id].wcd9xxx_ch_list
1927 );
1928 } else if (!enable && (widget->value & 1 << port_id)) {
1929 widget->value &= ~(1 << port_id);
1930 list_del_init(&core->tx_chs[port_id].list);
1931 } else {
1932 if (enable)
1933 pr_info("%s: TX%u port is used by this virtual port\n",
1934 __func__, port_id + 1);
1935 else
1936 pr_info("%s: TX%u port is not used by this virtual port\n",
1937 __func__, port_id + 1);
1938 /* avoid update power function */
1939 mutex_unlock(&codec->mutex);
1940 return 0;
1941 }
1942 break;
1943 default:
1944 pr_err("Unknown AIF %d\n", dai_id);
1945 mutex_unlock(&codec->mutex);
1946 return -EINVAL;
1947 }
1948 pr_debug("%s: name %s sname %s updated value %u shift %d\n", __func__,
1949 widget->name, widget->sname, widget->value, widget->shift);
1950
1951 snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
1952
1953 mutex_unlock(&codec->mutex);
1954 return 0;
1955}
1956
1957static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
1958 struct snd_ctl_elem_value *ucontrol)
1959{
1960 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1961 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1962
1963 ucontrol->value.enumerated.item[0] = widget->value;
1964 return 0;
1965}
1966
1967static const char *const slim_rx_mux_text[] = {
1968 "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB"
1969};
1970
1971static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
1972 struct snd_ctl_elem_value *ucontrol)
1973{
1974 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1975 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1976 struct snd_soc_codec *codec = widget->codec;
1977 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
1978 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1979 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1980 u32 port_id = widget->shift;
1981
1982 pr_debug("%s: wname %s cname %s value %u shift %d item %u\n", __func__,
1983 widget->name, ucontrol->id.name, widget->value, widget->shift,
1984 ucontrol->value.enumerated.item[0]);
1985
1986 widget->value = ucontrol->value.enumerated.item[0];
1987
1988 mutex_lock(&codec->mutex);
1989
1990 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1991 if (widget->value > 1) {
1992 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1993 __func__);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07001994 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07001995 }
1996 }
1997 /* value need to match the Virtual port and AIF number
1998 */
1999 switch (widget->value) {
2000 case 0:
2001 list_del_init(&core->rx_chs[port_id].list);
2002 break;
2003 case 1:
Kuirong Wangdcc392e2012-10-19 00:33:38 -07002004 if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
2005 &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list))
2006 goto pr_err;
Kuirong Wang906ac472012-07-09 12:54:44 -07002007 list_add_tail(&core->rx_chs[port_id].list,
2008 &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list);
2009 break;
2010 case 2:
Kuirong Wangdcc392e2012-10-19 00:33:38 -07002011 if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
2012 &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list))
2013 goto pr_err;
Kuirong Wang906ac472012-07-09 12:54:44 -07002014 list_add_tail(&core->rx_chs[port_id].list,
2015 &tabla_p->dai[AIF2_PB].wcd9xxx_ch_list);
2016 break;
2017 case 3:
Kuirong Wangdcc392e2012-10-19 00:33:38 -07002018 if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
2019 &tabla_p->dai[AIF1_PB].wcd9xxx_ch_list))
2020 goto pr_err;
Kuirong Wang906ac472012-07-09 12:54:44 -07002021 list_add_tail(&core->rx_chs[port_id].list,
2022 &tabla_p->dai[AIF3_PB].wcd9xxx_ch_list);
2023 break;
2024 default:
2025 pr_err("Unknown AIF %d\n", widget->value);
Kuirong Wangdcc392e2012-10-19 00:33:38 -07002026 goto err;
Kuirong Wang906ac472012-07-09 12:54:44 -07002027 }
2028
2029 snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
2030
2031 mutex_unlock(&codec->mutex);
2032 return 0;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07002033
2034pr_err:
2035 pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
2036 __func__, port_id + 1);
Santosh Mardi2a831d72012-11-07 20:45:52 +05302037 mutex_unlock(&codec->mutex);
2038 return 0;
Kuirong Wangdcc392e2012-10-19 00:33:38 -07002039err:
2040 mutex_unlock(&codec->mutex);
2041 return -EINVAL;
Kuirong Wang906ac472012-07-09 12:54:44 -07002042}
2043
2044static const struct soc_enum slim_rx_mux_enum =
2045 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
2046
2047static const struct snd_kcontrol_new slim_rx_mux[TABLA_RX_MAX] = {
2048 SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
2049 slim_rx_mux_get, slim_rx_mux_put),
2050 SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
2051 slim_rx_mux_get, slim_rx_mux_put),
2052 SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
2053 slim_rx_mux_get, slim_rx_mux_put),
2054 SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
2055 slim_rx_mux_get, slim_rx_mux_put),
2056 SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
2057 slim_rx_mux_get, slim_rx_mux_put),
2058 SOC_DAPM_ENUM_EXT("SLIM RX6 Mux", slim_rx_mux_enum,
2059 slim_rx_mux_get, slim_rx_mux_put),
2060 SOC_DAPM_ENUM_EXT("SLIM RX7 Mux", slim_rx_mux_enum,
2061 slim_rx_mux_get, slim_rx_mux_put),
2062};
2063
2064static const struct snd_kcontrol_new aif_cap_mixer[] = {
2065 SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TABLA_TX1, 1, 0,
2066 slim_tx_mixer_get, slim_tx_mixer_put),
2067 SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TABLA_TX2, 1, 0,
2068 slim_tx_mixer_get, slim_tx_mixer_put),
2069 SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TABLA_TX3, 1, 0,
2070 slim_tx_mixer_get, slim_tx_mixer_put),
2071 SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TABLA_TX4, 1, 0,
2072 slim_tx_mixer_get, slim_tx_mixer_put),
2073 SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TABLA_TX5, 1, 0,
2074 slim_tx_mixer_get, slim_tx_mixer_put),
2075 SOC_SINGLE_EXT("SLIM TX6", SND_SOC_NOPM, TABLA_TX6, 1, 0,
2076 slim_tx_mixer_get, slim_tx_mixer_put),
2077 SOC_SINGLE_EXT("SLIM TX7", SND_SOC_NOPM, TABLA_TX7, 1, 0,
2078 slim_tx_mixer_get, slim_tx_mixer_put),
2079 SOC_SINGLE_EXT("SLIM TX8", SND_SOC_NOPM, TABLA_TX8, 1, 0,
2080 slim_tx_mixer_get, slim_tx_mixer_put),
2081 SOC_SINGLE_EXT("SLIM TX9", SND_SOC_NOPM, TABLA_TX9, 1, 0,
2082 slim_tx_mixer_get, slim_tx_mixer_put),
2083 SOC_SINGLE_EXT("SLIM TX10", SND_SOC_NOPM, TABLA_TX10, 1, 0,
2084 slim_tx_mixer_get, slim_tx_mixer_put),
2085};
2086
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002087static void tabla_codec_enable_adc_block(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002088 int enable)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002089{
2090 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2091
2092 pr_debug("%s %d\n", __func__, enable);
2093
2094 if (enable) {
2095 tabla->adc_count++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002096 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL, 0x2, 0x2);
2097 } else {
2098 tabla->adc_count--;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002099 if (!tabla->adc_count)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002100 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_OTHR_CTL,
Joonwoo Park03324832012-03-19 19:36:16 -07002101 0x2, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002102 }
2103}
2104
2105static int tabla_codec_enable_adc(struct snd_soc_dapm_widget *w,
2106 struct snd_kcontrol *kcontrol, int event)
2107{
2108 struct snd_soc_codec *codec = w->codec;
2109 u16 adc_reg;
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08002110 u8 init_bit_shift;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002111
2112 pr_debug("%s %d\n", __func__, event);
2113
2114 if (w->reg == TABLA_A_TX_1_2_EN)
2115 adc_reg = TABLA_A_TX_1_2_TEST_CTL;
2116 else if (w->reg == TABLA_A_TX_3_4_EN)
2117 adc_reg = TABLA_A_TX_3_4_TEST_CTL;
2118 else if (w->reg == TABLA_A_TX_5_6_EN)
2119 adc_reg = TABLA_A_TX_5_6_TEST_CTL;
2120 else {
2121 pr_err("%s: Error, invalid adc register\n", __func__);
2122 return -EINVAL;
2123 }
2124
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08002125 if (w->shift == 3)
2126 init_bit_shift = 6;
2127 else if (w->shift == 7)
2128 init_bit_shift = 7;
2129 else {
2130 pr_err("%s: Error, invalid init bit postion adc register\n",
2131 __func__);
2132 return -EINVAL;
2133 }
2134
2135
2136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002137 switch (event) {
2138 case SND_SOC_DAPM_PRE_PMU:
2139 tabla_codec_enable_adc_block(codec, 1);
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08002140 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
2141 1 << init_bit_shift);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142 break;
2143 case SND_SOC_DAPM_POST_PMU:
Kiran Kandi9a2c62a82011-12-07 13:13:26 -08002144
2145 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
2146
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002147 break;
2148 case SND_SOC_DAPM_POST_PMD:
2149 tabla_codec_enable_adc_block(codec, 0);
2150 break;
2151 }
2152 return 0;
2153}
2154
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002155static void tabla_codec_enable_audio_mode_bandgap(struct snd_soc_codec *codec)
2156{
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002157 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2158 0x80);
2159 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x04,
2160 0x04);
2161 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2162 0x01);
2163 usleep_range(1000, 1000);
2164 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2165 0x00);
2166}
2167
2168static void tabla_codec_enable_bandgap(struct snd_soc_codec *codec,
2169 enum tabla_bandgap_type choice)
2170{
2171 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2172
2173 /* TODO lock resources accessed by audio streams and threaded
2174 * interrupt handlers
2175 */
2176
2177 pr_debug("%s, choice is %d, current is %d\n", __func__, choice,
2178 tabla->bandgap_type);
2179
2180 if (tabla->bandgap_type == choice)
2181 return;
2182
2183 if ((tabla->bandgap_type == TABLA_BANDGAP_OFF) &&
2184 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
2185 tabla_codec_enable_audio_mode_bandgap(codec);
2186 } else if (choice == TABLA_BANDGAP_MBHC_MODE) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002187 /* bandgap mode becomes fast,
2188 * mclk should be off or clk buff source souldn't be VBG
2189 * Let's turn off mclk always */
2190 WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002191 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x2,
2192 0x2);
2193 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2194 0x80);
2195 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x4,
2196 0x4);
2197 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x01,
2198 0x01);
2199 usleep_range(1000, 1000);
2200 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x80,
2201 0x00);
2202 } else if ((tabla->bandgap_type == TABLA_BANDGAP_MBHC_MODE) &&
2203 (choice == TABLA_BANDGAP_AUDIO_MODE)) {
Damir Didjusto7c85d712012-08-16 21:22:29 -07002204 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x50);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002205 usleep_range(100, 100);
2206 tabla_codec_enable_audio_mode_bandgap(codec);
2207 } else if (choice == TABLA_BANDGAP_OFF) {
Damir Didjusto7c85d712012-08-16 21:22:29 -07002208 snd_soc_write(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x50);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002209 } else {
2210 pr_err("%s: Error, Invalid bandgap settings\n", __func__);
2211 }
2212 tabla->bandgap_type = choice;
2213}
2214
2215static void tabla_codec_disable_clock_block(struct snd_soc_codec *codec)
2216{
2217 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2218 pr_debug("%s\n", __func__);
2219 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x00);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002220 usleep_range(50, 50);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002221 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x02);
2222 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x00);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002223 usleep_range(50, 50);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002224 tabla->clock_active = false;
2225}
2226
2227static int tabla_codec_mclk_index(const struct tabla_priv *tabla)
2228{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002229 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002230 return 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002231 else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002232 return 1;
2233 else {
2234 BUG_ON(1);
2235 return -EINVAL;
2236 }
2237}
2238
2239static void tabla_enable_rx_bias(struct snd_soc_codec *codec, u32 enable)
2240{
2241 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2242
2243 if (enable) {
2244 tabla->rx_bias_count++;
2245 if (tabla->rx_bias_count == 1)
2246 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
2247 0x80, 0x80);
2248 } else {
2249 tabla->rx_bias_count--;
2250 if (!tabla->rx_bias_count)
2251 snd_soc_update_bits(codec, TABLA_A_RX_COM_BIAS,
2252 0x80, 0x00);
2253 }
2254}
2255
2256static int tabla_codec_enable_config_mode(struct snd_soc_codec *codec,
2257 int enable)
2258{
2259 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2260
2261 pr_debug("%s: enable = %d\n", __func__, enable);
2262 if (enable) {
2263 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x10, 0);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002264 /* bandgap mode to fast */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002265 snd_soc_write(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x17);
2266 usleep_range(5, 5);
2267 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002268 0x80);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002269 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002270 0x80);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002271 usleep_range(10, 10);
2272 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_TEST, 0x80, 0);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002273 usleep_range(10000, 10000);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002274 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x08);
2275 } else {
2276 snd_soc_update_bits(codec, TABLA_A_BIAS_CONFIG_MODE_BG_CTL, 0x1,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002277 0);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002278 snd_soc_update_bits(codec, TABLA_A_CONFIG_MODE_FREQ, 0x80, 0);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002279 /* clk source to ext clk and clk buff ref to VBG */
2280 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x0C, 0x04);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002281 }
2282 tabla->config_mode_active = enable ? true : false;
2283
2284 return 0;
2285}
2286
2287static int tabla_codec_enable_clock_block(struct snd_soc_codec *codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002288 int config_mode)
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002289{
2290 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2291
2292 pr_debug("%s: config_mode = %d\n", __func__, config_mode);
2293
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002294 /* transit to RCO requires mclk off */
2295 WARN_ON(snd_soc_read(codec, TABLA_A_CLK_BUFF_EN2) & (1 << 2));
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002296 if (config_mode) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002297 /* enable RCO and switch to it */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002298 tabla_codec_enable_config_mode(codec, 1);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002299 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002300 usleep_range(1000, 1000);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002301 } else {
2302 /* switch to MCLK */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002303 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x08, 0x00);
2304
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002305 if (tabla->mbhc_polling_active) {
2306 snd_soc_write(codec, TABLA_A_CLK_BUFF_EN2, 0x02);
2307 tabla_codec_enable_config_mode(codec, 0);
2308 }
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002309 }
2310
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002311 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x01, 0x01);
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002312 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x02, 0x00);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07002313 /* on MCLK */
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08002314 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN2, 0x04, 0x04);
2315 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_MCLK_CTL, 0x01, 0x01);
2316 usleep_range(50, 50);
2317 tabla->clock_active = true;
2318 return 0;
2319}
2320
2321static int tabla_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
2322 struct snd_kcontrol *kcontrol, int event)
2323{
2324 struct snd_soc_codec *codec = w->codec;
2325 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2326
2327 pr_debug("%s: %d\n", __func__, event);
2328
2329 switch (event) {
2330 case SND_SOC_DAPM_PRE_PMU:
2331 tabla_codec_enable_bandgap(codec,
2332 TABLA_BANDGAP_AUDIO_MODE);
2333 tabla_enable_rx_bias(codec, 1);
2334
2335 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
2336 0x08, 0x08);
2337 /* Enable Zero Cross detect for AUX PGA channel
2338 * and set the initial AUX PGA gain to NEG_0P0_DB
2339 * to avoid glitches.
2340 */
2341 if (w->reg == TABLA_A_AUX_L_EN) {
2342 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
2343 0x20, 0x20);
2344 tabla->aux_l_gain = snd_soc_read(codec,
2345 TABLA_A_AUX_L_GAIN);
2346 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
2347 } else {
2348 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
2349 0x20, 0x20);
2350 tabla->aux_r_gain = snd_soc_read(codec,
2351 TABLA_A_AUX_R_GAIN);
2352 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
2353 }
2354 if (tabla->aux_pga_cnt++ == 1
2355 && !tabla->mclk_enabled) {
2356 tabla_codec_enable_clock_block(codec, 1);
2357 pr_debug("AUX PGA enabled RC osc\n");
2358 }
2359 break;
2360
2361 case SND_SOC_DAPM_POST_PMU:
2362 if (w->reg == TABLA_A_AUX_L_EN)
2363 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
2364 tabla->aux_l_gain);
2365 else
2366 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
2367 tabla->aux_r_gain);
2368 break;
2369
2370 case SND_SOC_DAPM_PRE_PMD:
2371 /* Mute AUX PGA channel in use before disabling AUX PGA */
2372 if (w->reg == TABLA_A_AUX_L_EN) {
2373 tabla->aux_l_gain = snd_soc_read(codec,
2374 TABLA_A_AUX_L_GAIN);
2375 snd_soc_write(codec, TABLA_A_AUX_L_GAIN, 0x1F);
2376 } else {
2377 tabla->aux_r_gain = snd_soc_read(codec,
2378 TABLA_A_AUX_R_GAIN);
2379 snd_soc_write(codec, TABLA_A_AUX_R_GAIN, 0x1F);
2380 }
2381 break;
2382
2383 case SND_SOC_DAPM_POST_PMD:
2384 tabla_enable_rx_bias(codec, 0);
2385
2386 snd_soc_update_bits(codec, TABLA_A_AUX_COM_CTL,
2387 0x08, 0x00);
2388 if (w->reg == TABLA_A_AUX_L_EN) {
2389 snd_soc_write(codec, TABLA_A_AUX_L_GAIN,
2390 tabla->aux_l_gain);
2391 snd_soc_update_bits(codec, TABLA_A_AUX_L_EN,
2392 0x20, 0x00);
2393 } else {
2394 snd_soc_write(codec, TABLA_A_AUX_R_GAIN,
2395 tabla->aux_r_gain);
2396 snd_soc_update_bits(codec, TABLA_A_AUX_R_EN,
2397 0x20, 0x00);
2398 }
2399
2400 if (tabla->aux_pga_cnt-- == 0) {
2401 if (tabla->mbhc_polling_active)
2402 tabla_codec_enable_bandgap(codec,
2403 TABLA_BANDGAP_MBHC_MODE);
2404 else
2405 tabla_codec_enable_bandgap(codec,
2406 TABLA_BANDGAP_OFF);
2407
2408 if (!tabla->mclk_enabled &&
2409 !tabla->mbhc_polling_active) {
2410 tabla_codec_enable_clock_block(codec, 0);
2411 }
2412 }
2413 break;
2414 }
2415 return 0;
2416}
2417
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002418static int tabla_codec_enable_lineout(struct snd_soc_dapm_widget *w,
2419 struct snd_kcontrol *kcontrol, int event)
2420{
2421 struct snd_soc_codec *codec = w->codec;
2422 u16 lineout_gain_reg;
2423
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002424 pr_debug("%s %d %s\n", __func__, event, w->name);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002425
2426 switch (w->shift) {
2427 case 0:
2428 lineout_gain_reg = TABLA_A_RX_LINE_1_GAIN;
2429 break;
2430 case 1:
2431 lineout_gain_reg = TABLA_A_RX_LINE_2_GAIN;
2432 break;
2433 case 2:
2434 lineout_gain_reg = TABLA_A_RX_LINE_3_GAIN;
2435 break;
2436 case 3:
2437 lineout_gain_reg = TABLA_A_RX_LINE_4_GAIN;
2438 break;
2439 case 4:
2440 lineout_gain_reg = TABLA_A_RX_LINE_5_GAIN;
2441 break;
2442 default:
2443 pr_err("%s: Error, incorrect lineout register value\n",
2444 __func__);
2445 return -EINVAL;
2446 }
2447
2448 switch (event) {
2449 case SND_SOC_DAPM_PRE_PMU:
2450 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
2451 break;
2452 case SND_SOC_DAPM_POST_PMU:
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08002453 pr_debug("%s: sleeping 16 ms after %s PA turn on\n",
Kiran Kandidb0a4b02011-08-23 09:32:09 -07002454 __func__, w->name);
Krishnankutty Kolathappilly31169f42011-11-17 10:33:11 -08002455 usleep_range(16000, 16000);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002456 break;
2457 case SND_SOC_DAPM_POST_PMD:
2458 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
2459 break;
2460 }
2461 return 0;
2462}
2463
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002464
2465static int tabla_codec_enable_dmic(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002466 struct snd_kcontrol *kcontrol, int event)
2467{
2468 struct snd_soc_codec *codec = w->codec;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002469 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2470 u8 dmic_clk_en;
2471 s32 *dmic_clk_cnt;
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002472 unsigned int dmic;
2473 int ret;
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002474
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002475 ret = kstrtouint(strpbrk(w->name, "123456"), 10, &dmic);
2476 if (ret < 0) {
2477 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002478 return -EINVAL;
2479 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002480
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002481 switch (dmic) {
2482 case 1:
2483 case 2:
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002484 dmic_clk_en = 0x01;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002485 dmic_clk_cnt = &(tabla->dmic_1_2_clk_cnt);
2486
2487 pr_debug("%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
2488 __func__, event, dmic, *dmic_clk_cnt);
2489
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002490 break;
2491
2492 case 3:
2493 case 4:
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002494 dmic_clk_en = 0x04;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002495 dmic_clk_cnt = &(tabla->dmic_3_4_clk_cnt);
2496
2497 pr_debug("%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
2498 __func__, event, dmic, *dmic_clk_cnt);
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002499 break;
2500
2501 case 5:
2502 case 6:
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002503 dmic_clk_en = 0x10;
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002504 dmic_clk_cnt = &(tabla->dmic_5_6_clk_cnt);
2505
2506 pr_debug("%s() event %d DMIC%d dmic_5_6_clk_cnt %d\n",
2507 __func__, event, dmic, *dmic_clk_cnt);
2508
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07002509 break;
2510
2511 default:
2512 pr_err("%s: Invalid DMIC Selection\n", __func__);
2513 return -EINVAL;
2514 }
2515
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002516 switch (event) {
2517 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002518
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002519 (*dmic_clk_cnt)++;
2520 if (*dmic_clk_cnt == 1)
2521 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
2522 dmic_clk_en, dmic_clk_en);
Kiran Kandicf45f6a2011-07-17 21:10:19 -07002523
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002524 break;
2525 case SND_SOC_DAPM_POST_PMD:
Kiran Kandi0ba468f2012-05-08 11:45:05 -07002526
2527 (*dmic_clk_cnt)--;
2528 if (*dmic_clk_cnt == 0)
2529 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_DMIC_CTL,
2530 dmic_clk_en, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002531 break;
2532 }
2533 return 0;
2534}
2535
Bradley Rubin229c6a52011-07-12 16:18:48 -07002536
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002537/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002538static void tabla_codec_start_hs_polling(struct snd_soc_codec *codec)
2539{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002540 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07002541 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
2542 int mbhc_state = tabla->mbhc_state;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002543
Joonwoo Park03324832012-03-19 19:36:16 -07002544 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002545 if (!tabla->mbhc_polling_active) {
2546 pr_debug("Polling is not active, do not start polling\n");
2547 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002548 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002549 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Joonwoo Park03324832012-03-19 19:36:16 -07002550
Joonwoo Park5bbcb0c2012-08-07 17:25:52 -07002551 if (tabla->no_mic_headset_override) {
2552 pr_debug("%s setting button threshold to min", __func__);
2553 /* set to min */
2554 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL, 0x80);
2555 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0x00);
2556 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL, 0x80);
2557 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL, 0x00);
2558 } else if (unlikely(mbhc_state == MBHC_STATE_POTENTIAL)) {
2559 pr_debug("%s recovering MBHC state machine\n", __func__);
2560 tabla->mbhc_state = MBHC_STATE_POTENTIAL_RECOVERY;
2561 /* set to max button press threshold */
2562 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL, 0x7F);
2563 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL, 0xFF);
2564 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
2565 (TABLA_IS_1_X(tabla_core->version) ?
2566 0x07 : 0x7F));
2567 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL, 0xFF);
2568 /* set to max */
2569 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL, 0x7F);
2570 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL, 0xFF);
Joonwoo Park03324832012-03-19 19:36:16 -07002571 }
2572
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002573 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
2574 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
2575 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x1);
Joonwoo Park03324832012-03-19 19:36:16 -07002576 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002577}
2578
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002579/* called under codec_resource_lock acquisition */
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002580static void tabla_codec_pause_hs_polling(struct snd_soc_codec *codec)
2581{
Bradley Rubincb3950a2011-08-18 13:07:26 -07002582 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2583
Joonwoo Park03324832012-03-19 19:36:16 -07002584 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002585 if (!tabla->mbhc_polling_active) {
2586 pr_debug("polling not active, nothing to pause\n");
2587 return;
Bradley Rubincb3950a2011-08-18 13:07:26 -07002588 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002589
Simmi Pateriya1b9a3092013-01-02 11:49:26 +05302590 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
2591 msleep(250);
2592 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002593 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Joonwoo Park03324832012-03-19 19:36:16 -07002594 pr_debug("%s: leave\n", __func__);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002595}
2596
Joonwoo Park03324832012-03-19 19:36:16 -07002597static void tabla_codec_switch_cfilt_mode(struct snd_soc_codec *codec, int mode)
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002598{
2599 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2600 u8 reg_mode_val, cur_mode_val;
2601 bool mbhc_was_polling = false;
2602
2603 if (mode)
2604 reg_mode_val = TABLA_CFILT_FAST_MODE;
2605 else
2606 reg_mode_val = TABLA_CFILT_SLOW_MODE;
2607
2608 cur_mode_val = snd_soc_read(codec,
2609 tabla->mbhc_bias_regs.cfilt_ctl) & 0x40;
2610
2611 if (cur_mode_val != reg_mode_val) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002612 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002613 if (tabla->mbhc_polling_active) {
2614 tabla_codec_pause_hs_polling(codec);
2615 mbhc_was_polling = true;
2616 }
2617 snd_soc_update_bits(codec,
2618 tabla->mbhc_bias_regs.cfilt_ctl, 0x40, reg_mode_val);
2619 if (mbhc_was_polling)
2620 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002621 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08002622 pr_debug("%s: CFILT mode change (%x to %x)\n", __func__,
2623 cur_mode_val, reg_mode_val);
2624 } else {
2625 pr_debug("%s: CFILT Value is already %x\n",
2626 __func__, cur_mode_val);
2627 }
2628}
2629
2630static void tabla_codec_update_cfilt_usage(struct snd_soc_codec *codec,
2631 u8 cfilt_sel, int inc)
2632{
2633 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2634 u32 *cfilt_cnt_ptr = NULL;
2635 u16 micb_cfilt_reg;
2636
2637 switch (cfilt_sel) {
2638 case TABLA_CFILT1_SEL:
2639 cfilt_cnt_ptr = &tabla->cfilt1_cnt;
2640 micb_cfilt_reg = TABLA_A_MICB_CFILT_1_CTL;
2641 break;
2642 case TABLA_CFILT2_SEL:
2643 cfilt_cnt_ptr = &tabla->cfilt2_cnt;
2644 micb_cfilt_reg = TABLA_A_MICB_CFILT_2_CTL;
2645 break;
2646 case TABLA_CFILT3_SEL:
2647 cfilt_cnt_ptr = &tabla->cfilt3_cnt;
2648 micb_cfilt_reg = TABLA_A_MICB_CFILT_3_CTL;
2649 break;
2650 default:
2651 return; /* should not happen */
2652 }
2653
2654 if (inc) {
2655 if (!(*cfilt_cnt_ptr)++) {
2656 /* Switch CFILT to slow mode if MBHC CFILT being used */
2657 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2658 tabla_codec_switch_cfilt_mode(codec, 0);
2659
2660 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0x80);
2661 }
2662 } else {
2663 /* check if count not zero, decrement
2664 * then check if zero, go ahead disable cfilter
2665 */
2666 if ((*cfilt_cnt_ptr) && !--(*cfilt_cnt_ptr)) {
2667 snd_soc_update_bits(codec, micb_cfilt_reg, 0x80, 0);
2668
2669 /* Switch CFILT to fast mode if MBHC CFILT being used */
2670 if (cfilt_sel == tabla->mbhc_bias_regs.cfilt_sel)
2671 tabla_codec_switch_cfilt_mode(codec, 1);
2672 }
2673 }
2674}
2675
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002676static int tabla_find_k_value(unsigned int ldoh_v, unsigned int cfilt_mv)
2677{
2678 int rc = -EINVAL;
2679 unsigned min_mv, max_mv;
2680
2681 switch (ldoh_v) {
2682 case TABLA_LDOH_1P95_V:
2683 min_mv = 160;
2684 max_mv = 1800;
2685 break;
2686 case TABLA_LDOH_2P35_V:
2687 min_mv = 200;
2688 max_mv = 2200;
2689 break;
2690 case TABLA_LDOH_2P75_V:
2691 min_mv = 240;
2692 max_mv = 2600;
2693 break;
2694 case TABLA_LDOH_2P85_V:
2695 min_mv = 250;
2696 max_mv = 2700;
2697 break;
2698 default:
2699 goto done;
2700 }
2701
2702 if (cfilt_mv < min_mv || cfilt_mv > max_mv)
2703 goto done;
2704
2705 for (rc = 4; rc <= 44; rc++) {
2706 min_mv = max_mv * (rc) / 44;
2707 if (min_mv >= cfilt_mv) {
2708 rc -= 4;
2709 break;
2710 }
2711 }
2712done:
2713 return rc;
2714}
2715
2716static bool tabla_is_hph_pa_on(struct snd_soc_codec *codec)
2717{
2718 u8 hph_reg_val = 0;
2719 hph_reg_val = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_EN);
2720
2721 return (hph_reg_val & 0x30) ? true : false;
2722}
2723
Joonwoo Parka9444452011-12-08 18:48:27 -08002724static bool tabla_is_hph_dac_on(struct snd_soc_codec *codec, int left)
2725{
2726 u8 hph_reg_val = 0;
2727 if (left)
2728 hph_reg_val = snd_soc_read(codec,
2729 TABLA_A_RX_HPH_L_DAC_CTL);
2730 else
2731 hph_reg_val = snd_soc_read(codec,
2732 TABLA_A_RX_HPH_R_DAC_CTL);
2733
2734 return (hph_reg_val & 0xC0) ? true : false;
2735}
2736
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002737static void tabla_turn_onoff_override(struct snd_soc_codec *codec, bool on)
2738{
2739 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, on << 2);
2740}
2741
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002742/* called under codec_resource_lock acquisition */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002743static void tabla_codec_drive_v_to_micbias(struct snd_soc_codec *codec,
2744 int usec)
2745{
2746 int cfilt_k_val;
2747 bool set = true;
2748 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2749
2750 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
2751 tabla->mbhc_micbias_switched) {
2752 pr_debug("%s: set mic V to micbias V\n", __func__);
2753 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
2754 tabla_turn_onoff_override(codec, true);
2755 while (1) {
2756 cfilt_k_val = tabla_find_k_value(
2757 tabla->pdata->micbias.ldoh_v,
2758 set ? tabla->mbhc_data.micb_mv :
2759 VDDIO_MICBIAS_MV);
2760 snd_soc_update_bits(codec,
2761 tabla->mbhc_bias_regs.cfilt_val,
2762 0xFC, (cfilt_k_val << 2));
2763 if (!set)
2764 break;
2765 usleep_range(usec, usec);
2766 set = false;
2767 }
2768 tabla_turn_onoff_override(codec, false);
2769 }
2770}
2771
2772/* called under codec_resource_lock acquisition */
2773static void __tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2774 int vddio_switch, bool restartpolling,
2775 bool checkpolling)
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002776{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002777 int cfilt_k_val;
Joonwoo Park41956722012-04-18 13:13:07 -07002778 bool override;
2779 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002780
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002781 if (vddio_switch && !tabla->mbhc_micbias_switched &&
2782 (!checkpolling || tabla->mbhc_polling_active)) {
2783 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002784 tabla_codec_pause_hs_polling(codec);
Joonwoo Park41956722012-04-18 13:13:07 -07002785 override = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04;
2786 if (!override)
2787 tabla_turn_onoff_override(codec, true);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002788 /* Adjust threshold if Mic Bias voltage changes */
2789 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002790 cfilt_k_val = tabla_find_k_value(
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002791 tabla->pdata->micbias.ldoh_v,
2792 VDDIO_MICBIAS_MV);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002793 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002794 tabla->mbhc_bias_regs.cfilt_val,
2795 0xFC, (cfilt_k_val << 2));
Joonwoo Parkc1c67a92012-08-07 16:05:36 -07002796 usleep_range(cfilt_adjust_ms * 1000,
2797 cfilt_adjust_ms * 1000);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002798 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2799 tabla->mbhc_data.adj_v_ins_hu & 0xFF);
2800 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2801 (tabla->mbhc_data.adj_v_ins_hu >> 8) &
2802 0xFF);
2803 pr_debug("%s: Programmed MBHC thresholds to VDDIO\n",
2804 __func__);
2805 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002806
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002807 /* enable MIC BIAS Switch to VDDIO */
2808 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2809 0x80, 0x80);
2810 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2811 0x10, 0x00);
Joonwoo Park41956722012-04-18 13:13:07 -07002812 if (!override)
2813 tabla_turn_onoff_override(codec, false);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002814 if (restartpolling)
Bhalchandra Gajarec1e19c42011-11-18 11:22:56 -08002815 tabla_codec_start_hs_polling(codec);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002816
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002817 tabla->mbhc_micbias_switched = true;
2818 pr_debug("%s: VDDIO switch enabled\n", __func__);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002819 } else if (!vddio_switch && tabla->mbhc_micbias_switched) {
2820 if ((!checkpolling || tabla->mbhc_polling_active) &&
2821 restartpolling)
2822 tabla_codec_pause_hs_polling(codec);
2823 /* Reprogram thresholds */
2824 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
2825 cfilt_k_val = tabla_find_k_value(
2826 tabla->pdata->micbias.ldoh_v,
2827 tabla->mbhc_data.micb_mv);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002828 snd_soc_update_bits(codec,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002829 tabla->mbhc_bias_regs.cfilt_val,
2830 0xFC, (cfilt_k_val << 2));
Joonwoo Parkc1c67a92012-08-07 16:05:36 -07002831 usleep_range(cfilt_adjust_ms * 1000,
2832 cfilt_adjust_ms * 1000);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002833 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
2834 tabla->mbhc_data.v_ins_hu & 0xFF);
2835 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
2836 (tabla->mbhc_data.v_ins_hu >> 8) & 0xFF);
2837 pr_debug("%s: Programmed MBHC thresholds to MICBIAS\n",
2838 __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002839 }
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002840
2841 /* Disable MIC BIAS Switch to VDDIO */
2842 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2843 0x80, 0x00);
2844 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
2845 0x10, 0x00);
2846
2847 if ((!checkpolling || tabla->mbhc_polling_active) &&
2848 restartpolling)
2849 tabla_codec_start_hs_polling(codec);
2850
2851 tabla->mbhc_micbias_switched = false;
2852 pr_debug("%s: VDDIO switch disabled\n", __func__);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002853 }
2854}
2855
Joonwoo Parkcf473b42012-03-29 19:48:16 -07002856static void tabla_codec_switch_micbias(struct snd_soc_codec *codec,
2857 int vddio_switch)
2858{
2859 return __tabla_codec_switch_micbias(codec, vddio_switch, true, true);
2860}
2861
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002862static int tabla_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2863 struct snd_kcontrol *kcontrol, int event)
2864{
2865 struct snd_soc_codec *codec = w->codec;
Patrick Lai3043fba2011-08-01 14:15:57 -07002866 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
2867 u16 micb_int_reg;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002868 int micb_line;
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07002869 u8 cfilt_sel_val = 0;
Bradley Rubin229c6a52011-07-12 16:18:48 -07002870 char *internal1_text = "Internal1";
2871 char *internal2_text = "Internal2";
2872 char *internal3_text = "Internal3";
Simmi Pateriya71d63872012-11-08 01:06:30 +05302873 const char *micbias1_text = "MIC BIAS1 ";
2874 const char *micbias2_text = "MIC BIAS2 ";
2875 const char *micbias3_text = "MIC BIAS3 ";
2876 const char *micbias4_text = "MIC BIAS4 ";
2877 u32 *micbias_enable_count;
2878 u16 wreg;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002879
2880 pr_debug("%s %d\n", __func__, event);
Simmi Pateriya71d63872012-11-08 01:06:30 +05302881 if (strnstr(w->name, micbias1_text, strlen(micbias1_text))) {
2882 wreg = TABLA_A_MICB_1_CTL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002883 micb_int_reg = TABLA_A_MICB_1_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002884 cfilt_sel_val = tabla->pdata->micbias.bias1_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002885 micb_line = TABLA_MICBIAS1;
Simmi Pateriya71d63872012-11-08 01:06:30 +05302886 } else if (strnstr(w->name, micbias2_text, strlen(micbias2_text))) {
2887 wreg = TABLA_A_MICB_2_CTL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002888 micb_int_reg = TABLA_A_MICB_2_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002889 cfilt_sel_val = tabla->pdata->micbias.bias2_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002890 micb_line = TABLA_MICBIAS2;
Simmi Pateriya71d63872012-11-08 01:06:30 +05302891 } else if (strnstr(w->name, micbias3_text, strlen(micbias3_text))) {
2892 wreg = TABLA_A_MICB_3_CTL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002893 micb_int_reg = TABLA_A_MICB_3_INT_RBIAS;
Patrick Lai3043fba2011-08-01 14:15:57 -07002894 cfilt_sel_val = tabla->pdata->micbias.bias3_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002895 micb_line = TABLA_MICBIAS3;
Simmi Pateriya71d63872012-11-08 01:06:30 +05302896 } else if (strnstr(w->name, micbias4_text, strlen(micbias4_text))) {
2897 wreg = tabla->reg_addr.micb_4_ctl;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08002898 micb_int_reg = tabla->reg_addr.micb_4_int_rbias;
Patrick Lai3043fba2011-08-01 14:15:57 -07002899 cfilt_sel_val = tabla->pdata->micbias.bias4_cfilt_sel;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002900 micb_line = TABLA_MICBIAS4;
Simmi Pateriya71d63872012-11-08 01:06:30 +05302901 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002902 pr_err("%s: Error, invalid micbias register\n", __func__);
2903 return -EINVAL;
2904 }
2905
Simmi Pateriya71d63872012-11-08 01:06:30 +05302906 micbias_enable_count = &tabla->micbias_enable_count[micb_line];
2907 pr_debug("%s: counter %d\n", __func__, *micbias_enable_count);
2908
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002909 switch (event) {
2910 case SND_SOC_DAPM_PRE_PMU:
Simmi Pateriya71d63872012-11-08 01:06:30 +05302911 if (++*micbias_enable_count > 1) {
2912 pr_debug("%s: do nothing, counter %d\n",
2913 __func__, *micbias_enable_count);
2914 break;
2915 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002916 /* Decide whether to switch the micbias for MBHC */
Simmi Pateriya71d63872012-11-08 01:06:30 +05302917 if (wreg == tabla->mbhc_bias_regs.ctl_reg) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002918 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002919 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002920 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2921 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002922
Simmi Pateriya71d63872012-11-08 01:06:30 +05302923 snd_soc_update_bits(codec, wreg, 0x0E, 0x0A);
Patrick Lai3043fba2011-08-01 14:15:57 -07002924 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 1);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002925
2926 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002927 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002928 else if (strnstr(w->name, internal2_text, 30))
2929 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2930 else if (strnstr(w->name, internal3_text, 30))
2931 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2932
Simmi Pateriya71d63872012-11-08 01:06:30 +05302933 snd_soc_update_bits(codec, wreg, 1 << 7, 1 << 7);
2934
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002935 break;
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002936 case SND_SOC_DAPM_POST_PMU:
Simmi Pateriya71d63872012-11-08 01:06:30 +05302937 if (*micbias_enable_count > 1) {
2938 pr_debug("%s: do nothing, counter %d\n",
2939 __func__, *micbias_enable_count);
2940 break;
2941 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08002942 usleep_range(20000, 20000);
2943
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002944 if (tabla->mbhc_polling_active &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002945 tabla->mbhc_cfg.micbias == micb_line) {
2946 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002947 tabla_codec_pause_hs_polling(codec);
2948 tabla_codec_start_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002949 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bradley Rubin4d09cf42011-08-17 17:59:16 -07002950 }
2951 break;
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002953 case SND_SOC_DAPM_POST_PMD:
Simmi Pateriya71d63872012-11-08 01:06:30 +05302954 if (--*micbias_enable_count > 0) {
2955 pr_debug("%s: do nothing, counter %d\n",
2956 __func__, *micbias_enable_count);
2957 break;
2958 }
2959
2960 snd_soc_update_bits(codec, wreg, 1 << 7, 0);
2961
2962 if ((wreg == tabla->mbhc_bias_regs.ctl_reg) &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002963 tabla_is_hph_pa_on(codec)) {
2964 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002965 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002966 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
2967 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07002968
Bradley Rubin229c6a52011-07-12 16:18:48 -07002969 if (strnstr(w->name, internal1_text, 30))
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002970 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
Bradley Rubin229c6a52011-07-12 16:18:48 -07002971 else if (strnstr(w->name, internal2_text, 30))
2972 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2973 else if (strnstr(w->name, internal3_text, 30))
2974 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2975
Patrick Lai3043fba2011-08-01 14:15:57 -07002976 tabla_codec_update_cfilt_usage(codec, cfilt_sel_val, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002977 break;
2978 }
2979
2980 return 0;
2981}
2982
Kiran Kandid8cf5212012-03-02 15:34:53 -08002983
2984static void tx_hpf_corner_freq_callback(struct work_struct *work)
2985{
2986 struct delayed_work *hpf_delayed_work;
2987 struct hpf_work *hpf_work;
2988 struct tabla_priv *tabla;
2989 struct snd_soc_codec *codec;
2990 u16 tx_mux_ctl_reg;
2991 u8 hpf_cut_of_freq;
2992
2993 hpf_delayed_work = to_delayed_work(work);
2994 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2995 tabla = hpf_work->tabla;
2996 codec = hpf_work->tabla->codec;
2997 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2998
2999 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL +
3000 (hpf_work->decimator - 1) * 8;
3001
3002 pr_debug("%s(): decimator %u hpf_cut_of_freq 0x%x\n", __func__,
3003 hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
3004
3005 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
3006}
3007
3008#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
3009#define CF_MIN_3DB_4HZ 0x0
3010#define CF_MIN_3DB_75HZ 0x1
3011#define CF_MIN_3DB_150HZ 0x2
3012
Simmi Pateriya71d63872012-11-08 01:06:30 +05303013static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
3014 struct snd_kcontrol *kcontrol, int event);
3015
3016static int tabla_codec_enable_micbias_power(struct snd_soc_dapm_widget *w,
3017 struct snd_kcontrol *kcontrol,
3018 int event)
3019{
3020 struct snd_soc_codec *codec = w->codec;
3021 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3022
3023 pr_debug("%s %d\n", __func__, event);
3024
3025 switch (event) {
3026 case SND_SOC_DAPM_PRE_PMU:
3027 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, true);
3028 tabla_codec_enable_ldo_h(w, kcontrol, event);
3029 tabla_codec_enable_micbias(w, kcontrol, event);
3030 break;
3031 case SND_SOC_DAPM_POST_PMU:
3032 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, true);
3033 break;
3034 case SND_SOC_DAPM_POST_PMD:
3035 tabla_codec_enable_micbias(w, kcontrol, event);
3036 tabla_codec_enable_ldo_h(w, kcontrol, event);
3037 break;
3038 }
3039 return 0;
3040}
3041
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003042static int tabla_codec_enable_dec(struct snd_soc_dapm_widget *w,
3043 struct snd_kcontrol *kcontrol, int event)
3044{
3045 struct snd_soc_codec *codec = w->codec;
Kiran Kandid8cf5212012-03-02 15:34:53 -08003046 unsigned int decimator;
3047 char *dec_name = NULL;
3048 char *widget_name = NULL;
3049 char *temp;
3050 int ret = 0;
3051 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
3052 u8 dec_hpf_cut_of_freq;
Kuirong Wange9c8a222012-03-28 16:24:09 -07003053 int offset;
3054
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003055
3056 pr_debug("%s %d\n", __func__, event);
3057
Kiran Kandid8cf5212012-03-02 15:34:53 -08003058 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
3059 if (!widget_name)
3060 return -ENOMEM;
3061 temp = widget_name;
3062
3063 dec_name = strsep(&widget_name, " ");
3064 widget_name = temp;
3065 if (!dec_name) {
3066 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
3067 ret = -EINVAL;
3068 goto out;
3069 }
3070
3071 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
3072 if (ret < 0) {
3073 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
3074 ret = -EINVAL;
3075 goto out;
3076 }
3077
3078 pr_debug("%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
3079 w->name, dec_name, decimator);
3080
Kuirong Wange9c8a222012-03-28 16:24:09 -07003081 if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003082 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B1_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07003083 offset = 0;
3084 } else if (w->reg == TABLA_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003085 dec_reset_reg = TABLA_A_CDC_CLK_TX_RESET_B2_CTL;
Kuirong Wange9c8a222012-03-28 16:24:09 -07003086 offset = 8;
3087 } else {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003088 pr_err("%s: Error, incorrect dec\n", __func__);
3089 return -EINVAL;
3090 }
3091
Kiran Kandid8cf5212012-03-02 15:34:53 -08003092 tx_vol_ctl_reg = TABLA_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator -1);
3093 tx_mux_ctl_reg = TABLA_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
3094
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003095 switch (event) {
3096 case SND_SOC_DAPM_PRE_PMU:
Kiran Kandid8cf5212012-03-02 15:34:53 -08003097
3098 // Enableable TX digital mute */
3099 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
3100
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003101 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
3102 1 << w->shift);
3103 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
Kiran Kandid8cf5212012-03-02 15:34:53 -08003104
3105 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
3106
3107 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
3108
3109 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
3110 dec_hpf_cut_of_freq;
3111
3112 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
3113
3114 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
3115 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
3116 CF_MIN_3DB_150HZ << 4);
3117 }
3118
3119 /* enable HPF */
3120 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
3121
3122 break;
3123
3124 case SND_SOC_DAPM_POST_PMU:
3125
3126 /* Disable TX digital mute */
3127 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
3128
3129 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
3130 CF_MIN_3DB_150HZ) {
3131
3132 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
3133 msecs_to_jiffies(300));
3134 }
Kuirong Wange9c8a222012-03-28 16:24:09 -07003135 /* apply the digital gain after the decimator is enabled*/
Damir Didjustoed406e22012-11-16 15:44:57 -08003136 if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
Kuirong Wange9c8a222012-03-28 16:24:09 -07003137 snd_soc_write(codec,
3138 tx_digital_gain_reg[w->shift + offset],
3139 snd_soc_read(codec,
3140 tx_digital_gain_reg[w->shift + offset])
3141 );
3142
Kiran Kandid8cf5212012-03-02 15:34:53 -08003143 break;
3144
3145 case SND_SOC_DAPM_PRE_PMD:
3146
3147 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
3148 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
3149 break;
3150
3151 case SND_SOC_DAPM_POST_PMD:
3152
3153 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
3154 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
3155 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
3156
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003157 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003158 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08003159out:
3160 kfree(widget_name);
3161 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003162}
3163
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003164static int tabla_codec_reset_interpolator(struct snd_soc_dapm_widget *w,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003165 struct snd_kcontrol *kcontrol, int event)
3166{
3167 struct snd_soc_codec *codec = w->codec;
3168
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003169 pr_debug("%s %d %s\n", __func__, event, w->name);
3170
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003171 switch (event) {
3172 case SND_SOC_DAPM_PRE_PMU:
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003173 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
3174 1 << w->shift, 1 << w->shift);
3175 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_RESET_CTL,
3176 1 << w->shift, 0x0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003177 break;
Kuirong Wange9c8a222012-03-28 16:24:09 -07003178 case SND_SOC_DAPM_POST_PMU:
3179 /* apply the digital gain after the interpolator is enabled*/
3180 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
3181 snd_soc_write(codec,
3182 rx_digital_gain_reg[w->shift],
3183 snd_soc_read(codec,
3184 rx_digital_gain_reg[w->shift])
3185 );
3186 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003187 }
3188 return 0;
3189}
3190
Simmi Pateriya71d63872012-11-08 01:06:30 +05303191static void tabla_enable_ldo_h(struct snd_soc_codec *codec, u32 enable)
3192{
3193 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3194
3195 if (enable) {
3196 if (++tabla->ldo_h_count == 1)
3197 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1,
3198 0x80, 0x80);
3199 } else {
3200 if (--tabla->ldo_h_count == 0)
3201 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1,
3202 0x80, 0x00);
3203 }
3204}
3205
Bradley Rubin229c6a52011-07-12 16:18:48 -07003206static int tabla_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
3207 struct snd_kcontrol *kcontrol, int event)
3208{
Simmi Pateriya71d63872012-11-08 01:06:30 +05303209 struct snd_soc_codec *codec = w->codec;
3210
3211 pr_debug("%s %d\n", __func__, event);
3212
Bradley Rubin229c6a52011-07-12 16:18:48 -07003213 switch (event) {
Simmi Pateriya71d63872012-11-08 01:06:30 +05303214 case SND_SOC_DAPM_PRE_PMU:
3215 tabla_enable_ldo_h(codec, 1);
3216 usleep_range(1000, 1000);
3217 break;
Bradley Rubin229c6a52011-07-12 16:18:48 -07003218 case SND_SOC_DAPM_POST_PMD:
Simmi Pateriya71d63872012-11-08 01:06:30 +05303219 tabla_enable_ldo_h(codec, 0);
Bradley Rubin229c6a52011-07-12 16:18:48 -07003220 usleep_range(1000, 1000);
3221 break;
3222 }
3223 return 0;
3224}
3225
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003226static int tabla_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
3227 struct snd_kcontrol *kcontrol, int event)
3228{
3229 struct snd_soc_codec *codec = w->codec;
3230
3231 pr_debug("%s %d\n", __func__, event);
3232
3233 switch (event) {
3234 case SND_SOC_DAPM_PRE_PMU:
3235 tabla_enable_rx_bias(codec, 1);
3236 break;
3237 case SND_SOC_DAPM_POST_PMD:
3238 tabla_enable_rx_bias(codec, 0);
3239 break;
3240 }
3241 return 0;
3242}
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003243static int tabla_hphr_dac_event(struct snd_soc_dapm_widget *w,
3244 struct snd_kcontrol *kcontrol, int event)
3245{
3246 struct snd_soc_codec *codec = w->codec;
3247
3248 pr_debug("%s %s %d\n", __func__, w->name, event);
3249
3250 switch (event) {
3251 case SND_SOC_DAPM_PRE_PMU:
3252 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
3253 break;
3254 case SND_SOC_DAPM_POST_PMD:
3255 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
3256 break;
3257 }
3258 return 0;
3259}
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003260
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003261static void tabla_snd_soc_jack_report(struct tabla_priv *tabla,
3262 struct snd_soc_jack *jack, int status,
3263 int mask)
3264{
3265 /* XXX: wake_lock_timeout()? */
Joonwoo Park03324832012-03-19 19:36:16 -07003266 snd_soc_jack_report_no_dapm(jack, status, mask);
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003267}
3268
Patrick Lai49efeac2011-11-03 11:01:12 -07003269static void hphocp_off_report(struct tabla_priv *tabla,
3270 u32 jack_status, int irq)
3271{
3272 struct snd_soc_codec *codec;
Joonwoo Park03324832012-03-19 19:36:16 -07003273 if (!tabla) {
3274 pr_err("%s: Bad tabla private data\n", __func__);
3275 return;
3276 }
Patrick Lai49efeac2011-11-03 11:01:12 -07003277
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003278 pr_debug("%s: clear ocp status %x\n", __func__, jack_status);
Joonwoo Park03324832012-03-19 19:36:16 -07003279 codec = tabla->codec;
3280 if (tabla->hph_status & jack_status) {
Patrick Lai49efeac2011-11-03 11:01:12 -07003281 tabla->hph_status &= ~jack_status;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003282 if (tabla->mbhc_cfg.headset_jack)
3283 tabla_snd_soc_jack_report(tabla,
3284 tabla->mbhc_cfg.headset_jack,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08003285 tabla->hph_status,
3286 TABLA_JACK_MASK);
Joonwoo Park0976d012011-12-22 11:48:18 -08003287 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x00);
3288 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
Patrick Laic7cae882011-11-18 11:52:49 -08003289 /* reset retry counter as PA is turned off signifying
3290 * start of new OCP detection session
3291 */
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003292 if (WCD9XXX_IRQ_HPH_PA_OCPL_FAULT)
Patrick Laic7cae882011-11-18 11:52:49 -08003293 tabla->hphlocp_cnt = 0;
3294 else
3295 tabla->hphrocp_cnt = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303296 wcd9xxx_enable_irq(codec->control_data, irq);
Patrick Lai49efeac2011-11-03 11:01:12 -07003297 }
3298}
3299
3300static void hphlocp_off_report(struct work_struct *work)
3301{
3302 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
3303 hphlocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003304 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
3305 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07003306}
3307
3308static void hphrocp_off_report(struct work_struct *work)
3309{
3310 struct tabla_priv *tabla = container_of(work, struct tabla_priv,
3311 hphrocp_work);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07003312 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
3313 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07003314}
3315
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08003316static int tabla_codec_enable_anc(struct snd_soc_dapm_widget *w,
3317 struct snd_kcontrol *kcontrol, int event)
3318{
3319 struct snd_soc_codec *codec = w->codec;
3320 const char *filename;
3321 const struct firmware *fw;
3322 int i;
3323 int ret;
3324 int num_anc_slots;
3325 struct anc_header *anc_head;
3326 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3327 u32 anc_writes_size = 0;
3328 int anc_size_remaining;
3329 u32 *anc_ptr;
3330 u16 reg;
3331 u8 mask, val, old_val;
3332 u8 mbhc_micb_ctl_val;
3333
3334 pr_debug("%s: DAPM Event %d ANC func is %d\n",
3335 __func__, event, tabla->anc_func);
3336
3337 if (tabla->anc_func == 0)
3338 return 0;
3339
3340 switch (event) {
3341 case SND_SOC_DAPM_PRE_PMU:
3342 mbhc_micb_ctl_val = snd_soc_read(codec,
3343 tabla->mbhc_bias_regs.ctl_reg);
3344
3345 if (!(mbhc_micb_ctl_val & 0x80)) {
3346 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
3347 tabla_codec_switch_micbias(codec, 1);
3348 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
3349 }
3350
3351 filename = "wcd9310/wcd9310_anc.bin";
3352
3353 ret = request_firmware(&fw, filename, codec->dev);
3354 if (ret != 0) {
3355 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
3356 ret);
3357 return -ENODEV;
3358 }
3359
3360 if (fw->size < sizeof(struct anc_header)) {
3361 dev_err(codec->dev, "Not enough data\n");
3362 release_firmware(fw);
3363 return -ENOMEM;
3364 }
3365
3366 /* First number is the number of register writes */
3367 anc_head = (struct anc_header *)(fw->data);
3368 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
3369 anc_size_remaining = fw->size - sizeof(struct anc_header);
3370 num_anc_slots = anc_head->num_anc_slots;
3371
3372 if (tabla->anc_slot >= num_anc_slots) {
3373 dev_err(codec->dev, "Invalid ANC slot selected\n");
3374 release_firmware(fw);
3375 return -EINVAL;
3376 }
3377
3378 for (i = 0; i < num_anc_slots; i++) {
3379
3380 if (anc_size_remaining < TABLA_PACKED_REG_SIZE) {
3381 dev_err(codec->dev, "Invalid register format\n");
3382 release_firmware(fw);
3383 return -EINVAL;
3384 }
3385 anc_writes_size = (u32)(*anc_ptr);
3386 anc_size_remaining -= sizeof(u32);
3387 anc_ptr += 1;
3388
3389 if (anc_writes_size * TABLA_PACKED_REG_SIZE
3390 > anc_size_remaining) {
3391 dev_err(codec->dev, "Invalid register format\n");
3392 release_firmware(fw);
3393 return -ENOMEM;
3394 }
3395
3396 if (tabla->anc_slot == i)
3397 break;
3398
3399 anc_size_remaining -= (anc_writes_size *
3400 TABLA_PACKED_REG_SIZE);
3401 anc_ptr += anc_writes_size;
3402 }
3403 if (i == num_anc_slots) {
3404 dev_err(codec->dev, "Selected ANC slot not present\n");
3405 release_firmware(fw);
3406 return -ENOMEM;
3407 }
3408
3409 for (i = 0; i < anc_writes_size; i++) {
3410 TABLA_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
3411 mask, val);
3412 old_val = snd_soc_read(codec, reg);
3413 snd_soc_write(codec, reg, (old_val & ~mask) |
3414 (val & mask));
3415 }
3416 usleep_range(10000, 10000);
3417 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x30);
3418 msleep(30);
3419 release_firmware(fw);
3420 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
3421 /* if MBHC polling is active, set TX7_MBHC_EN bit 7 */
3422 if (tabla->mbhc_polling_active)
3423 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80,
3424 0x80);
3425 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
3426 break;
3427 case SND_SOC_DAPM_POST_PMD:
3428 /* schedule work is required because at the time HPH PA DAPM
3429 * event callback is called by DAPM framework, CODEC dapm mutex
3430 * would have been locked while snd_soc_jack_report also
3431 * attempts to acquire same lock.
3432 */
3433 if (w->shift == 5) {
3434 clear_bit(TABLA_HPHL_PA_OFF_ACK,
3435 &tabla->hph_pa_dac_state);
3436 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
3437 &tabla->hph_pa_dac_state);
3438 if (tabla->hph_status & SND_JACK_OC_HPHL)
3439 schedule_work(&tabla->hphlocp_work);
3440 } else if (w->shift == 4) {
3441 clear_bit(TABLA_HPHR_PA_OFF_ACK,
3442 &tabla->hph_pa_dac_state);
3443 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
3444 &tabla->hph_pa_dac_state);
3445 if (tabla->hph_status & SND_JACK_OC_HPHR)
3446 schedule_work(&tabla->hphrocp_work);
3447 }
3448
3449 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
3450 tabla_codec_switch_micbias(codec, 0);
3451 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
3452
3453 break;
3454 case SND_SOC_DAPM_PRE_PMD:
3455 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
3456 msleep(40);
3457 /* unset TX7_MBHC_EN bit 7 */
3458 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
3459 snd_soc_update_bits(codec, TABLA_A_CDC_ANC1_CTL, 0x01, 0x00);
3460 snd_soc_update_bits(codec, TABLA_A_CDC_ANC2_CTL, 0x01, 0x00);
3461 msleep(20);
3462 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
3463 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
3464 snd_soc_write(codec, TABLA_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
3465 break;
3466 }
3467 return 0;
3468}
3469
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07003470static int tabla_hph_pa_event(struct snd_soc_dapm_widget *w,
3471 struct snd_kcontrol *kcontrol, int event)
3472{
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003473 struct snd_soc_codec *codec = w->codec;
3474 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
3475 u8 mbhc_micb_ctl_val;
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07003476 pr_debug("%s: event = %d\n", __func__, event);
3477
3478 switch (event) {
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003479 case SND_SOC_DAPM_PRE_PMU:
3480 mbhc_micb_ctl_val = snd_soc_read(codec,
3481 tabla->mbhc_bias_regs.ctl_reg);
3482
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003483 if (!(mbhc_micb_ctl_val & 0x80)) {
3484 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003485 tabla_codec_switch_micbias(codec, 1);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003486 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
3487 }
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003488 break;
3489
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07003490 case SND_SOC_DAPM_POST_PMD:
Patrick Lai49efeac2011-11-03 11:01:12 -07003491 /* schedule work is required because at the time HPH PA DAPM
3492 * event callback is called by DAPM framework, CODEC dapm mutex
3493 * would have been locked while snd_soc_jack_report also
3494 * attempts to acquire same lock.
3495 */
Joonwoo Parka9444452011-12-08 18:48:27 -08003496 if (w->shift == 5) {
3497 clear_bit(TABLA_HPHL_PA_OFF_ACK,
3498 &tabla->hph_pa_dac_state);
3499 clear_bit(TABLA_HPHL_DAC_OFF_ACK,
3500 &tabla->hph_pa_dac_state);
3501 if (tabla->hph_status & SND_JACK_OC_HPHL)
3502 schedule_work(&tabla->hphlocp_work);
3503 } else if (w->shift == 4) {
3504 clear_bit(TABLA_HPHR_PA_OFF_ACK,
3505 &tabla->hph_pa_dac_state);
3506 clear_bit(TABLA_HPHR_DAC_OFF_ACK,
3507 &tabla->hph_pa_dac_state);
3508 if (tabla->hph_status & SND_JACK_OC_HPHR)
3509 schedule_work(&tabla->hphrocp_work);
3510 }
3511
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003512 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park03324832012-03-19 19:36:16 -07003513 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003514 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07003515
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07003516 pr_debug("%s: sleep 10 ms after %s PA disable.\n", __func__,
3517 w->name);
3518 usleep_range(10000, 10000);
Kiran Kandibf0b1ff2011-09-15 13:55:21 -07003519 break;
3520 }
3521 return 0;
3522}
3523
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003524static void tabla_get_mbhc_micbias_regs(struct snd_soc_codec *codec,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003525 struct mbhc_micbias_regs *micbias_regs)
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003526{
3527 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003528 unsigned int cfilt;
3529
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07003530 switch (tabla->mbhc_cfg.micbias) {
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003531 case TABLA_MICBIAS1:
3532 cfilt = tabla->pdata->micbias.bias1_cfilt_sel;
3533 micbias_regs->mbhc_reg = TABLA_A_MICB_1_MBHC;
3534 micbias_regs->int_rbias = TABLA_A_MICB_1_INT_RBIAS;
3535 micbias_regs->ctl_reg = TABLA_A_MICB_1_CTL;
3536 break;
3537 case TABLA_MICBIAS2:
3538 cfilt = tabla->pdata->micbias.bias2_cfilt_sel;
3539 micbias_regs->mbhc_reg = TABLA_A_MICB_2_MBHC;
3540 micbias_regs->int_rbias = TABLA_A_MICB_2_INT_RBIAS;
3541 micbias_regs->ctl_reg = TABLA_A_MICB_2_CTL;
3542 break;
3543 case TABLA_MICBIAS3:
3544 cfilt = tabla->pdata->micbias.bias3_cfilt_sel;
3545 micbias_regs->mbhc_reg = TABLA_A_MICB_3_MBHC;
3546 micbias_regs->int_rbias = TABLA_A_MICB_3_INT_RBIAS;
3547 micbias_regs->ctl_reg = TABLA_A_MICB_3_CTL;
3548 break;
3549 case TABLA_MICBIAS4:
3550 cfilt = tabla->pdata->micbias.bias4_cfilt_sel;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003551 micbias_regs->mbhc_reg = tabla->reg_addr.micb_4_mbhc;
3552 micbias_regs->int_rbias = tabla->reg_addr.micb_4_int_rbias;
3553 micbias_regs->ctl_reg = tabla->reg_addr.micb_4_ctl;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003554 break;
3555 default:
3556 /* Should never reach here */
3557 pr_err("%s: Invalid MIC BIAS for MBHC\n", __func__);
Jordan Crouse239d8412011-11-23 11:47:02 -07003558 return;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003559 }
3560
Bhalchandra Gajare19d9c132011-11-18 14:57:08 -08003561 micbias_regs->cfilt_sel = cfilt;
3562
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003563 switch (cfilt) {
3564 case TABLA_CFILT1_SEL:
3565 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_1_VAL;
3566 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_1_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08003567 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt1_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003568 break;
3569 case TABLA_CFILT2_SEL:
3570 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_2_VAL;
3571 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_2_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08003572 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt2_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003573 break;
3574 case TABLA_CFILT3_SEL:
3575 micbias_regs->cfilt_val = TABLA_A_MICB_CFILT_3_VAL;
3576 micbias_regs->cfilt_ctl = TABLA_A_MICB_CFILT_3_CTL;
Joonwoo Park0976d012011-12-22 11:48:18 -08003577 tabla->mbhc_data.micb_mv = tabla->pdata->micbias.cfilt3_mv;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003578 break;
3579 }
3580}
Santosh Mardie15e2302011-11-15 10:39:23 +05303581static const struct snd_soc_dapm_widget tabla_dapm_i2s_widgets[] = {
3582 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", TABLA_A_CDC_CLK_RX_I2S_CTL,
3583 4, 0, NULL, 0),
3584 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", TABLA_A_CDC_CLK_TX_I2S_CTL, 4,
3585 0, NULL, 0),
3586};
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07003587
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003588static int tabla_lineout_dac_event(struct snd_soc_dapm_widget *w,
3589 struct snd_kcontrol *kcontrol, int event)
3590{
3591 struct snd_soc_codec *codec = w->codec;
3592
3593 pr_debug("%s %s %d\n", __func__, w->name, event);
3594
3595 switch (event) {
3596 case SND_SOC_DAPM_PRE_PMU:
3597 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
3598 break;
3599
3600 case SND_SOC_DAPM_POST_PMD:
3601 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
3602 break;
3603 }
3604 return 0;
3605}
3606
Damir Didjusto7c85d712012-08-16 21:22:29 -07003607static int tabla_ear_pa_event(struct snd_soc_dapm_widget *w,
3608 struct snd_kcontrol *kcontrol, int event)
3609{
3610 struct snd_soc_codec *codec = w->codec;
3611
3612 pr_debug("%s %d\n", __func__, event);
3613
3614 switch (event) {
3615 case SND_SOC_DAPM_PRE_PMU:
3616 snd_soc_update_bits(codec, TABLA_A_RX_EAR_EN, 0x50, 0x50);
3617 break;
3618
3619 case SND_SOC_DAPM_PRE_PMD:
3620 snd_soc_update_bits(codec, TABLA_A_RX_EAR_EN, 0x10, 0x00);
3621 snd_soc_update_bits(codec, TABLA_A_RX_EAR_EN, 0x40, 0x00);
3622 break;
3623 }
3624 return 0;
3625}
3626
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003627static const struct snd_soc_dapm_widget tabla_1_x_dapm_widgets[] = {
Simmi Pateriya71d63872012-11-08 01:06:30 +05303628 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", SND_SOC_NOPM, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303629 0, tabla_codec_enable_micbias,
3630 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3631 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003632};
3633
3634static const struct snd_soc_dapm_widget tabla_2_higher_dapm_widgets[] = {
Simmi Pateriya71d63872012-11-08 01:06:30 +05303635 SND_SOC_DAPM_MICBIAS_E("MIC BIAS4 External", SND_SOC_NOPM, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05303636 0, tabla_codec_enable_micbias,
3637 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3638 SND_SOC_DAPM_POST_PMD),
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08003639};
3640
Santosh Mardie15e2302011-11-15 10:39:23 +05303641static const struct snd_soc_dapm_route audio_i2s_map[] = {
3642 {"RX_I2S_CLK", NULL, "CDC_CONN"},
3643 {"SLIM RX1", NULL, "RX_I2S_CLK"},
3644 {"SLIM RX2", NULL, "RX_I2S_CLK"},
3645 {"SLIM RX3", NULL, "RX_I2S_CLK"},
3646 {"SLIM RX4", NULL, "RX_I2S_CLK"},
3647
3648 {"SLIM TX7", NULL, "TX_I2S_CLK"},
3649 {"SLIM TX8", NULL, "TX_I2S_CLK"},
3650 {"SLIM TX9", NULL, "TX_I2S_CLK"},
3651 {"SLIM TX10", NULL, "TX_I2S_CLK"},
3652};
3653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003654static const struct snd_soc_dapm_route audio_map[] = {
3655 /* SLIMBUS Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003656
Kuirong Wang906ac472012-07-09 12:54:44 -07003657 {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
3658 {"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
3659 {"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003660
Kuirong Wang906ac472012-07-09 12:54:44 -07003661 /* SLIM_MIXER("AIF1_CAP Mixer"),*/
3662 {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
3663 {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
3664 {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
3665 {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
3666 {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
3667 {"AIF1_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
3668 {"AIF1_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
3669 {"AIF1_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
3670 {"AIF1_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
3671 {"AIF1_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
3672 /* SLIM_MIXER("AIF2_CAP Mixer"),*/
3673 {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
3674 {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
3675 {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
3676 {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
3677 {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
3678 {"AIF2_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
3679 {"AIF2_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
3680 {"AIF2_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
3681 {"AIF2_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
3682 {"AIF2_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
3683 /* SLIM_MIXER("AIF3_CAP Mixer"),*/
3684 {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
3685 {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
3686 {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
3687 {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
3688 {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
3689 {"AIF3_CAP Mixer", "SLIM TX6", "SLIM TX6 MUX"},
3690 {"AIF3_CAP Mixer", "SLIM TX7", "SLIM TX7 MUX"},
3691 {"AIF3_CAP Mixer", "SLIM TX8", "SLIM TX8 MUX"},
3692 {"AIF3_CAP Mixer", "SLIM TX9", "SLIM TX9 MUX"},
3693 {"AIF3_CAP Mixer", "SLIM TX10", "SLIM TX10 MUX"},
3694
3695 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003696 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
3697
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003698 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Neema Shetty3fb1b802012-04-27 13:53:24 -07003699 {"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
3700 {"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
3701 {"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
3702 {"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
3703 {"SLIM TX3 MUX", "RMIX5", "RX5 MIX1"},
3704 {"SLIM TX3 MUX", "RMIX6", "RX6 MIX1"},
3705 {"SLIM TX3 MUX", "RMIX7", "RX7 MIX1"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003706
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003707 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
3708
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003709 {"SLIM TX5 MUX", "DEC5", "DEC5 MUX"},
Neema Shetty3fb1b802012-04-27 13:53:24 -07003710 {"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
3711 {"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
3712 {"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
3713 {"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
3714 {"SLIM TX5 MUX", "RMIX5", "RX5 MIX1"},
3715 {"SLIM TX5 MUX", "RMIX6", "RX6 MIX1"},
3716 {"SLIM TX5 MUX", "RMIX7", "RX7 MIX1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003717
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003718 {"SLIM TX6 MUX", "DEC6", "DEC6 MUX"},
3719
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003720 {"SLIM TX7 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07003721 {"SLIM TX7 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003722 {"SLIM TX7 MUX", "DEC3", "DEC3 MUX"},
3723 {"SLIM TX7 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003724 {"SLIM TX7 MUX", "DEC5", "DEC5 MUX"},
3725 {"SLIM TX7 MUX", "DEC6", "DEC6 MUX"},
Bhalchandra Gajare0d77e1b2011-07-08 10:54:14 -07003726 {"SLIM TX7 MUX", "DEC7", "DEC7 MUX"},
3727 {"SLIM TX7 MUX", "DEC8", "DEC8 MUX"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07003728 {"SLIM TX7 MUX", "DEC9", "DEC9 MUX"},
3729 {"SLIM TX7 MUX", "DEC10", "DEC10 MUX"},
Neema Shetty3fb1b802012-04-27 13:53:24 -07003730 {"SLIM TX7 MUX", "RMIX1", "RX1 MIX1"},
3731 {"SLIM TX7 MUX", "RMIX2", "RX2 MIX1"},
3732 {"SLIM TX7 MUX", "RMIX3", "RX3 MIX1"},
3733 {"SLIM TX7 MUX", "RMIX4", "RX4 MIX1"},
3734 {"SLIM TX7 MUX", "RMIX5", "RX5 MIX1"},
3735 {"SLIM TX7 MUX", "RMIX6", "RX6 MIX1"},
3736 {"SLIM TX7 MUX", "RMIX7", "RX7 MIX1"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003737
Kiran Kandicf45f6a2011-07-17 21:10:19 -07003738 {"SLIM TX8 MUX", "DEC1", "DEC1 MUX"},
3739 {"SLIM TX8 MUX", "DEC2", "DEC2 MUX"},
3740 {"SLIM TX8 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajare9ec83cd2011-09-23 17:25:07 -07003741 {"SLIM TX8 MUX", "DEC4", "DEC4 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003742 {"SLIM TX8 MUX", "DEC5", "DEC5 MUX"},
3743 {"SLIM TX8 MUX", "DEC6", "DEC6 MUX"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07003744 {"SLIM TX8 MUX", "DEC7", "DEC7 MUX"},
3745 {"SLIM TX8 MUX", "DEC8", "DEC8 MUX"},
3746 {"SLIM TX8 MUX", "DEC9", "DEC9 MUX"},
3747 {"SLIM TX8 MUX", "DEC10", "DEC10 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003748
Kiran Kandi3426e512011-09-13 22:50:10 -07003749 {"SLIM TX9 MUX", "DEC1", "DEC1 MUX"},
3750 {"SLIM TX9 MUX", "DEC2", "DEC2 MUX"},
3751 {"SLIM TX9 MUX", "DEC3", "DEC3 MUX"},
3752 {"SLIM TX9 MUX", "DEC4", "DEC4 MUX"},
3753 {"SLIM TX9 MUX", "DEC5", "DEC5 MUX"},
3754 {"SLIM TX9 MUX", "DEC6", "DEC6 MUX"},
3755 {"SLIM TX9 MUX", "DEC7", "DEC7 MUX"},
3756 {"SLIM TX9 MUX", "DEC8", "DEC8 MUX"},
3757 {"SLIM TX9 MUX", "DEC9", "DEC9 MUX"},
3758 {"SLIM TX9 MUX", "DEC10", "DEC10 MUX"},
3759
Kiran Kandi3426e512011-09-13 22:50:10 -07003760 {"SLIM TX10 MUX", "DEC1", "DEC1 MUX"},
3761 {"SLIM TX10 MUX", "DEC2", "DEC2 MUX"},
3762 {"SLIM TX10 MUX", "DEC3", "DEC3 MUX"},
3763 {"SLIM TX10 MUX", "DEC4", "DEC4 MUX"},
3764 {"SLIM TX10 MUX", "DEC5", "DEC5 MUX"},
3765 {"SLIM TX10 MUX", "DEC6", "DEC6 MUX"},
3766 {"SLIM TX10 MUX", "DEC7", "DEC7 MUX"},
3767 {"SLIM TX10 MUX", "DEC8", "DEC8 MUX"},
3768 {"SLIM TX10 MUX", "DEC9", "DEC9 MUX"},
3769 {"SLIM TX10 MUX", "DEC10", "DEC10 MUX"},
3770
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003771 /* Earpiece (RX MIX1) */
3772 {"EAR", NULL, "EAR PA"},
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003773 {"EAR PA", NULL, "EAR_PA_MIXER"},
3774 {"EAR_PA_MIXER", NULL, "DAC1"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003775 {"DAC1", NULL, "CP"},
3776
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003777 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
3778 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003779
3780 /* Headset (RX MIX1 and RX MIX2) */
3781 {"HEADPHONE", NULL, "HPHL"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003782 {"HEADPHONE", NULL, "HPHR"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003783
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003784 {"HPHL", NULL, "HPHL_PA_MIXER"},
3785 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
3786
3787 {"HPHR", NULL, "HPHR_PA_MIXER"},
3788 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003789
3790 {"HPHL DAC", NULL, "CP"},
3791 {"HPHR DAC", NULL, "CP"},
3792
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08003793 {"ANC HEADPHONE", NULL, "ANC HPHL"},
3794 {"ANC HEADPHONE", NULL, "ANC HPHR"},
3795
3796 {"ANC HPHL", NULL, "HPHL_PA_MIXER"},
3797 {"ANC HPHR", NULL, "HPHR_PA_MIXER"},
3798
Bradley Rubin229c6a52011-07-12 16:18:48 -07003799 {"ANC1 MUX", "ADC1", "ADC1"},
3800 {"ANC1 MUX", "ADC2", "ADC2"},
3801 {"ANC1 MUX", "ADC3", "ADC3"},
3802 {"ANC1 MUX", "ADC4", "ADC4"},
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08003803 {"ANC1 MUX", "DMIC1", "DMIC1"},
3804 {"ANC1 MUX", "DMIC2", "DMIC2"},
3805 {"ANC1 MUX", "DMIC3", "DMIC3"},
3806 {"ANC1 MUX", "DMIC4", "DMIC4"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003807 {"ANC2 MUX", "ADC1", "ADC1"},
3808 {"ANC2 MUX", "ADC2", "ADC2"},
3809 {"ANC2 MUX", "ADC3", "ADC3"},
3810 {"ANC2 MUX", "ADC4", "ADC4"},
3811
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08003812 {"ANC HPHR", NULL, "CDC_CONN"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003813 {"DAC1", "Switch", "RX1 CHAIN"},
3814 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003815 {"HPHR DAC", NULL, "RX2 CHAIN"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07003816
Kiran Kandidb0a4b02011-08-23 09:32:09 -07003817 {"LINEOUT1", NULL, "LINEOUT1 PA"},
3818 {"LINEOUT2", NULL, "LINEOUT2 PA"},
3819 {"LINEOUT3", NULL, "LINEOUT3 PA"},
3820 {"LINEOUT4", NULL, "LINEOUT4 PA"},
3821 {"LINEOUT5", NULL, "LINEOUT5 PA"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003822
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08003823 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
3824 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
3825 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
3826 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
3827 {"LINEOUT3 PA", NULL, "LINEOUT3_PA_MIXER"},
3828 {"LINEOUT3_PA_MIXER", NULL, "LINEOUT3 DAC"},
3829 {"LINEOUT4 PA", NULL, "LINEOUT4_PA_MIXER"},
3830 {"LINEOUT4_PA_MIXER", NULL, "LINEOUT4 DAC"},
3831 {"LINEOUT5 PA", NULL, "LINEOUT5_PA_MIXER"},
3832 {"LINEOUT5_PA_MIXER", NULL, "LINEOUT5 DAC"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003833
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003834 {"LINEOUT1 DAC", NULL, "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003835 {"LINEOUT5 DAC", NULL, "RX7 MIX1"},
3836
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003837 {"RX1 CHAIN", NULL, "RX1 MIX2"},
3838 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08003839 {"RX1 MIX2", NULL, "ANC1 MUX"},
3840 {"RX2 MIX2", NULL, "ANC2 MUX"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003841
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003842 {"CP", NULL, "RX_BIAS"},
3843 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
3844 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
3845 {"LINEOUT3 DAC", NULL, "RX_BIAS"},
3846 {"LINEOUT4 DAC", NULL, "RX_BIAS"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07003847 {"LINEOUT5 DAC", NULL, "RX_BIAS"},
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07003848
Kuirong Wang0f8ade32012-02-27 16:29:45 -08003849 {"RX1 MIX1", NULL, "COMP1_CLK"},
3850 {"RX2 MIX1", NULL, "COMP1_CLK"},
3851 {"RX3 MIX1", NULL, "COMP2_CLK"},
3852 {"RX5 MIX1", NULL, "COMP2_CLK"},
3853
3854
Bradley Rubin229c6a52011-07-12 16:18:48 -07003855 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
3856 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003857 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003858 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
3859 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003860 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
3861 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
3862 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
3863 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
3864 {"RX5 MIX1", NULL, "RX5 MIX1 INP1"},
3865 {"RX5 MIX1", NULL, "RX5 MIX1 INP2"},
3866 {"RX6 MIX1", NULL, "RX6 MIX1 INP1"},
3867 {"RX6 MIX1", NULL, "RX6 MIX1 INP2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07003868 {"RX7 MIX1", NULL, "RX7 MIX1 INP1"},
3869 {"RX7 MIX1", NULL, "RX7 MIX1 INP2"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08003870 {"RX1 MIX2", NULL, "RX1 MIX1"},
3871 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
3872 {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
3873 {"RX2 MIX2", NULL, "RX2 MIX1"},
3874 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
3875 {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
3876 {"RX3 MIX2", NULL, "RX3 MIX1"},
3877 {"RX3 MIX2", NULL, "RX3 MIX2 INP1"},
3878 {"RX3 MIX2", NULL, "RX3 MIX2 INP2"},
Bradley Rubin74a9b4a2011-06-13 15:03:43 -07003879
Kuirong Wang906ac472012-07-09 12:54:44 -07003880 /* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
3881 {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
3882 {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
3883 {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
3884 {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
3885 {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
3886 {"SLIM RX6 MUX", "AIF1_PB", "AIF1 PB"},
3887 {"SLIM RX7 MUX", "AIF1_PB", "AIF1 PB"},
3888 /* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
3889 {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
3890 {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
3891 {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
3892 {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
3893 {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
3894 {"SLIM RX6 MUX", "AIF2_PB", "AIF2 PB"},
3895 {"SLIM RX7 MUX", "AIF2_PB", "AIF2 PB"},
3896 /* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
3897 {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
3898 {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
3899 {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
3900 {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
3901 {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
3902 {"SLIM RX6 MUX", "AIF3_PB", "AIF3 PB"},
3903 {"SLIM RX7 MUX", "AIF3_PB", "AIF3 PB"},
3904
3905 {"SLIM RX1", NULL, "SLIM RX1 MUX"},
3906 {"SLIM RX2", NULL, "SLIM RX2 MUX"},
3907 {"SLIM RX3", NULL, "SLIM RX3 MUX"},
3908 {"SLIM RX4", NULL, "SLIM RX4 MUX"},
3909 {"SLIM RX5", NULL, "SLIM RX5 MUX"},
3910 {"SLIM RX6", NULL, "SLIM RX6 MUX"},
3911 {"SLIM RX7", NULL, "SLIM RX7 MUX"},
3912
3913 /* Mixer control for output path */
Bradley Rubin229c6a52011-07-12 16:18:48 -07003914 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
3915 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303916 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
3917 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003918 {"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003919 {"RX1 MIX1 INP1", "RX6", "SLIM RX6"},
3920 {"RX1 MIX1 INP1", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003921 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07003922 {"RX1 MIX1 INP1", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003923 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
3924 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303925 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
3926 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003927 {"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003928 {"RX1 MIX1 INP2", "RX6", "SLIM RX6"},
3929 {"RX1 MIX1 INP2", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003930 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07003931 {"RX1 MIX1 INP2", "IIR2", "IIR2"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003932 {"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
3933 {"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
3934 {"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
3935 {"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
3936 {"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
3937 {"RX1 MIX1 INP3", "RX6", "SLIM RX6"},
3938 {"RX1 MIX1 INP3", "RX7", "SLIM RX7"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003939 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
3940 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303941 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
3942 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003943 {"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003944 {"RX2 MIX1 INP1", "RX6", "SLIM RX6"},
3945 {"RX2 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003946 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07003947 {"RX2 MIX1 INP1", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003948 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
3949 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303950 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
3951 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003952 {"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003953 {"RX2 MIX1 INP2", "RX6", "SLIM RX6"},
3954 {"RX2 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003955 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07003956 {"RX2 MIX1 INP2", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003957 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
3958 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303959 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
3960 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003961 {"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003962 {"RX3 MIX1 INP1", "RX6", "SLIM RX6"},
3963 {"RX3 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003964 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07003965 {"RX3 MIX1 INP1", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003966 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
3967 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303968 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
3969 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003970 {"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003971 {"RX3 MIX1 INP2", "RX6", "SLIM RX6"},
3972 {"RX3 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003973 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07003974 {"RX3 MIX1 INP2", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003975 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
3976 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303977 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
3978 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003979 {"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003980 {"RX4 MIX1 INP1", "RX6", "SLIM RX6"},
3981 {"RX4 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003982 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07003983 {"RX4 MIX1 INP1", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003984 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
3985 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303986 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003987 {"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303988 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003989 {"RX4 MIX1 INP2", "RX6", "SLIM RX6"},
3990 {"RX4 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07003991 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07003992 {"RX4 MIX1 INP2", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07003993 {"RX5 MIX1 INP1", "RX1", "SLIM RX1"},
3994 {"RX5 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05303995 {"RX5 MIX1 INP1", "RX3", "SLIM RX3"},
3996 {"RX5 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07003997 {"RX5 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08003998 {"RX5 MIX1 INP1", "RX6", "SLIM RX6"},
3999 {"RX5 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07004000 {"RX5 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004001 {"RX5 MIX1 INP1", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07004002 {"RX5 MIX1 INP2", "RX1", "SLIM RX1"},
4003 {"RX5 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05304004 {"RX5 MIX1 INP2", "RX3", "SLIM RX3"},
4005 {"RX5 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07004006 {"RX5 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08004007 {"RX5 MIX1 INP2", "RX6", "SLIM RX6"},
4008 {"RX5 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07004009 {"RX5 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004010 {"RX5 MIX1 INP2", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07004011 {"RX6 MIX1 INP1", "RX1", "SLIM RX1"},
4012 {"RX6 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05304013 {"RX6 MIX1 INP1", "RX3", "SLIM RX3"},
4014 {"RX6 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07004015 {"RX6 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08004016 {"RX6 MIX1 INP1", "RX6", "SLIM RX6"},
4017 {"RX6 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07004018 {"RX6 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004019 {"RX6 MIX1 INP1", "IIR2", "IIR2"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07004020 {"RX6 MIX1 INP2", "RX1", "SLIM RX1"},
4021 {"RX6 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05304022 {"RX6 MIX1 INP2", "RX3", "SLIM RX3"},
4023 {"RX6 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07004024 {"RX6 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08004025 {"RX6 MIX1 INP2", "RX6", "SLIM RX6"},
4026 {"RX6 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07004027 {"RX6 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004028 {"RX6 MIX1 INP2", "IIR2", "IIR2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07004029 {"RX7 MIX1 INP1", "RX1", "SLIM RX1"},
4030 {"RX7 MIX1 INP1", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05304031 {"RX7 MIX1 INP1", "RX3", "SLIM RX3"},
4032 {"RX7 MIX1 INP1", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07004033 {"RX7 MIX1 INP1", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08004034 {"RX7 MIX1 INP1", "RX6", "SLIM RX6"},
4035 {"RX7 MIX1 INP1", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07004036 {"RX7 MIX1 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004037 {"RX7 MIX1 INP1", "IIR2", "IIR2"},
Bhalchandra Gajare0a8ad172011-08-12 13:32:22 -07004038 {"RX7 MIX1 INP2", "RX1", "SLIM RX1"},
4039 {"RX7 MIX1 INP2", "RX2", "SLIM RX2"},
Santosh Mardie15e2302011-11-15 10:39:23 +05304040 {"RX7 MIX1 INP2", "RX3", "SLIM RX3"},
4041 {"RX7 MIX1 INP2", "RX4", "SLIM RX4"},
Kiran Kandia9fffe92012-05-20 23:42:30 -07004042 {"RX7 MIX1 INP2", "RX5", "SLIM RX5"},
Neema Shettyd3a89262012-02-16 10:23:50 -08004043 {"RX7 MIX1 INP2", "RX6", "SLIM RX6"},
4044 {"RX7 MIX1 INP2", "RX7", "SLIM RX7"},
Patrick Lai16261e82011-09-30 13:25:52 -07004045 {"RX7 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004046 {"RX7 MIX1 INP2", "IIR2", "IIR2"},
4047
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004048 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004049 {"RX1 MIX2 INP1", "IIR2", "IIR2"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004050 {"RX1 MIX2 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004051 {"RX1 MIX2 INP2", "IIR2", "IIR2"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004052 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004053 {"RX2 MIX2 INP1", "IIR2", "IIR2"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004054 {"RX2 MIX2 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004055 {"RX2 MIX2 INP2", "IIR2", "IIR2"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004056 {"RX3 MIX2 INP1", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004057 {"RX3 MIX2 INP1", "IIR2", "IIR2"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004058 {"RX3 MIX2 INP2", "IIR1", "IIR1"},
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004059 {"RX3 MIX2 INP2", "IIR2", "IIR2"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004060
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004061 /* Decimator Inputs */
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004062 {"DEC1 MUX", "DMIC1", "DMIC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07004063 {"DEC1 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004064 {"DEC1 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07004065 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004066 {"DEC2 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004067 {"DEC2 MUX", NULL, "CDC_CONN"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07004068 {"DEC3 MUX", "DMIC3", "DMIC3"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004069 {"DEC3 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004070 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07004071 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004072 {"DEC4 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004073 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07004074 {"DEC5 MUX", "DMIC5", "DMIC5"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004075 {"DEC5 MUX", "ADC2", "ADC2"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004076 {"DEC5 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajare7cf018e2011-08-11 18:58:32 -07004077 {"DEC6 MUX", "DMIC6", "DMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004078 {"DEC6 MUX", "ADC1", "ADC1"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004079 {"DEC6 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004080 {"DEC7 MUX", "DMIC1", "DMIC1"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004081 {"DEC7 MUX", "DMIC6", "DMIC6"},
4082 {"DEC7 MUX", "ADC1", "ADC1"},
Kiran Kandicf45f6a2011-07-17 21:10:19 -07004083 {"DEC7 MUX", "ADC6", "ADC6"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004084 {"DEC7 MUX", NULL, "CDC_CONN"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004085 {"DEC8 MUX", "DMIC2", "DMIC2"},
4086 {"DEC8 MUX", "DMIC5", "DMIC5"},
4087 {"DEC8 MUX", "ADC2", "ADC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004088 {"DEC8 MUX", "ADC5", "ADC5"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004089 {"DEC8 MUX", NULL, "CDC_CONN"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004090 {"DEC9 MUX", "DMIC4", "DMIC4"},
4091 {"DEC9 MUX", "DMIC5", "DMIC5"},
4092 {"DEC9 MUX", "ADC2", "ADC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004093 {"DEC9 MUX", "ADC3", "ADC3"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004094 {"DEC9 MUX", NULL, "CDC_CONN"},
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004095 {"DEC10 MUX", "DMIC3", "DMIC3"},
4096 {"DEC10 MUX", "DMIC6", "DMIC6"},
4097 {"DEC10 MUX", "ADC1", "ADC1"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004098 {"DEC10 MUX", "ADC4", "ADC4"},
Bradley Rubine1d08622011-07-20 18:01:35 -07004099 {"DEC10 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004100
4101 /* ADC Connections */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004102 {"ADC1", NULL, "AMIC1"},
4103 {"ADC2", NULL, "AMIC2"},
Bhalchandra Gajarecc6ffa02011-07-14 18:35:41 -07004104 {"ADC3", NULL, "AMIC3"},
4105 {"ADC4", NULL, "AMIC4"},
4106 {"ADC5", NULL, "AMIC5"},
4107 {"ADC6", NULL, "AMIC6"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004108
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08004109 /* AUX PGA Connections */
4110 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
4111 {"HPHL_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
4112 {"HPHL_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
4113 {"HPHL_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
4114 {"HPHR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
4115 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
4116 {"HPHR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
4117 {"HPHR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
4118 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
4119 {"LINEOUT1_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
4120 {"LINEOUT1_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
4121 {"LINEOUT1_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
4122 {"LINEOUT2_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
4123 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
4124 {"LINEOUT2_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
4125 {"LINEOUT2_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
4126 {"LINEOUT3_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
4127 {"LINEOUT3_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
4128 {"LINEOUT3_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
4129 {"LINEOUT3_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
4130 {"LINEOUT4_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
4131 {"LINEOUT4_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
4132 {"LINEOUT4_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
4133 {"LINEOUT4_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
4134 {"LINEOUT5_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
4135 {"LINEOUT5_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
4136 {"LINEOUT5_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
4137 {"LINEOUT5_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
4138 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
4139 {"EAR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
4140 {"EAR_PA_MIXER", "AUX_PGA_L_INV Switch", "AUX_PGA_Left"},
4141 {"EAR_PA_MIXER", "AUX_PGA_R_INV Switch", "AUX_PGA_Right"},
4142 {"AUX_PGA_Left", NULL, "AMIC5"},
4143 {"AUX_PGA_Right", NULL, "AMIC6"},
4144
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004145 {"IIR1", NULL, "IIR1 INP1 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07004146 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
4147 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
4148 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
4149 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
4150 {"IIR1 INP1 MUX", "DEC5", "DEC5 MUX"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004151 {"IIR1 INP1 MUX", "DEC6", "DEC6 MUX"},
Patrick Lai16261e82011-09-30 13:25:52 -07004152 {"IIR1 INP1 MUX", "DEC7", "DEC7 MUX"},
4153 {"IIR1 INP1 MUX", "DEC8", "DEC8 MUX"},
4154 {"IIR1 INP1 MUX", "DEC9", "DEC9 MUX"},
4155 {"IIR1 INP1 MUX", "DEC10", "DEC10 MUX"},
Bradley Rubin229c6a52011-07-12 16:18:48 -07004156
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07004157 {"IIR2", NULL, "IIR2 INP1 MUX"},
4158 {"IIR2 INP1 MUX", "DEC1", "DEC1 MUX"},
4159 {"IIR2 INP1 MUX", "DEC2", "DEC2 MUX"},
4160 {"IIR2 INP1 MUX", "DEC3", "DEC3 MUX"},
4161 {"IIR2 INP1 MUX", "DEC4", "DEC4 MUX"},
4162 {"IIR2 INP1 MUX", "DEC5", "DEC5 MUX"},
4163 {"IIR2 INP1 MUX", "DEC6", "DEC6 MUX"},
4164 {"IIR2 INP1 MUX", "DEC7", "DEC7 MUX"},
4165 {"IIR2 INP1 MUX", "DEC8", "DEC8 MUX"},
4166 {"IIR2 INP1 MUX", "DEC9", "DEC9 MUX"},
4167 {"IIR2 INP1 MUX", "DEC10", "DEC10 MUX"},
4168
Bradley Rubin229c6a52011-07-12 16:18:48 -07004169 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
4170 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
4171 {"MIC BIAS1 External", NULL, "LDO_H"},
4172 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
4173 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
4174 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
4175 {"MIC BIAS2 External", NULL, "LDO_H"},
4176 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
4177 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
4178 {"MIC BIAS3 External", NULL, "LDO_H"},
4179 {"MIC BIAS4 External", NULL, "LDO_H"},
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004180};
4181
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004182static const struct snd_soc_dapm_route tabla_1_x_lineout_2_to_4_map[] = {
4183
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004184 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004185 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
4186
4187 {"LINEOUT2 DAC", NULL, "RX4 DSM MUX"},
4188
4189 {"LINEOUT3 DAC", NULL, "RX5 MIX1"},
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004190 {"LINEOUT3 DAC GROUND", "Switch", "RX3 MIX2"},
Kiran Kandi8b3a8302011-09-27 16:13:28 -07004191 {"LINEOUT3 DAC", NULL, "LINEOUT3 DAC GROUND"},
4192
4193 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
4194 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
4195
4196 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
4197 {"LINEOUT4 DAC GROUND", "Switch", "RX4 DSM MUX"},
4198 {"LINEOUT4 DAC", NULL, "LINEOUT4 DAC GROUND"},
4199};
4200
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004201
4202static const struct snd_soc_dapm_route tabla_2_x_lineout_2_to_4_map[] = {
4203
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08004204 {"RX4 DSM MUX", "DSM_INV", "RX3 MIX2"},
Kiran Kandi7a9fd902011-11-14 13:51:45 -08004205 {"RX4 DSM MUX", "CIC_OUT", "RX4 MIX1"},
4206
4207 {"LINEOUT3 DAC", NULL, "RX4 DSM MUX"},
4208
4209 {"LINEOUT2 DAC", NULL, "RX5 MIX1"},
4210
4211 {"RX6 DSM MUX", "DSM_INV", "RX5 MIX1"},
4212 {"RX6 DSM MUX", "CIC_OUT", "RX6 MIX1"},
4213
4214 {"LINEOUT4 DAC", NULL, "RX6 DSM MUX"},
4215};
4216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004217static int tabla_readable(struct snd_soc_codec *ssc, unsigned int reg)
4218{
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004219 int i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304220 struct wcd9xxx *tabla_core = dev_get_drvdata(ssc->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08004221
4222 if (TABLA_IS_1_X(tabla_core->version)) {
4223 for (i = 0; i < ARRAY_SIZE(tabla_1_reg_readable); i++) {
4224 if (tabla_1_reg_readable[i] == reg)
4225 return 1;
4226 }
4227 } else {
4228 for (i = 0; i < ARRAY_SIZE(tabla_2_reg_readable); i++) {
4229 if (tabla_2_reg_readable[i] == reg)
4230 return 1;
4231 }
4232 }
4233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004234 return tabla_reg_readable[reg];
4235}
Kuirong Wange9c8a222012-03-28 16:24:09 -07004236static bool tabla_is_digital_gain_register(unsigned int reg)
4237{
4238 bool rtn = false;
4239 switch (reg) {
4240 case TABLA_A_CDC_RX1_VOL_CTL_B2_CTL:
4241 case TABLA_A_CDC_RX2_VOL_CTL_B2_CTL:
4242 case TABLA_A_CDC_RX3_VOL_CTL_B2_CTL:
4243 case TABLA_A_CDC_RX4_VOL_CTL_B2_CTL:
4244 case TABLA_A_CDC_RX5_VOL_CTL_B2_CTL:
4245 case TABLA_A_CDC_RX6_VOL_CTL_B2_CTL:
4246 case TABLA_A_CDC_RX7_VOL_CTL_B2_CTL:
4247 case TABLA_A_CDC_TX1_VOL_CTL_GAIN:
4248 case TABLA_A_CDC_TX2_VOL_CTL_GAIN:
4249 case TABLA_A_CDC_TX3_VOL_CTL_GAIN:
4250 case TABLA_A_CDC_TX4_VOL_CTL_GAIN:
4251 case TABLA_A_CDC_TX5_VOL_CTL_GAIN:
4252 case TABLA_A_CDC_TX6_VOL_CTL_GAIN:
4253 case TABLA_A_CDC_TX7_VOL_CTL_GAIN:
4254 case TABLA_A_CDC_TX8_VOL_CTL_GAIN:
4255 case TABLA_A_CDC_TX9_VOL_CTL_GAIN:
4256 case TABLA_A_CDC_TX10_VOL_CTL_GAIN:
4257 rtn = true;
4258 break;
4259 default:
4260 break;
4261 }
4262 return rtn;
4263}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004264static int tabla_volatile(struct snd_soc_codec *ssc, unsigned int reg)
4265{
4266 /* Registers lower than 0x100 are top level registers which can be
4267 * written by the Tabla core driver.
4268 */
4269
4270 if ((reg >= TABLA_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
4271 return 1;
4272
Ben Romberger1f045a72011-11-04 10:14:57 -07004273 /* IIR Coeff registers are not cacheable */
4274 if ((reg >= TABLA_A_CDC_IIR1_COEF_B1_CTL) &&
4275 (reg <= TABLA_A_CDC_IIR2_COEF_B5_CTL))
4276 return 1;
4277
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08004278 /* ANC filter registers are not cacheable */
4279 if ((reg >= TABLA_A_CDC_ANC1_FILT1_B1_CTL) &&
4280 (reg <= TABLA_A_CDC_ANC1_FILT2_B3_CTL))
4281 return 1;
4282 if ((reg >= TABLA_A_CDC_ANC2_FILT1_B1_CTL) &&
4283 (reg <= TABLA_A_CDC_ANC2_FILT2_B3_CTL))
4284 return 1;
4285
Kuirong Wange9c8a222012-03-28 16:24:09 -07004286 /* Digital gain register is not cacheable so we have to write
4287 * the setting even it is the same
4288 */
4289 if (tabla_is_digital_gain_register(reg))
4290 return 1;
4291
Joonwoo Parkab2c5872012-05-03 15:16:02 -07004292 /* HPH status registers */
4293 if (reg == TABLA_A_RX_HPH_L_STATUS || reg == TABLA_A_RX_HPH_R_STATUS)
4294 return 1;
4295
Kuirong Wang678e4172012-06-26 15:35:22 -07004296 if (reg == TABLA_A_CDC_COMP1_SHUT_DOWN_STATUS ||
4297 reg == TABLA_A_CDC_COMP2_SHUT_DOWN_STATUS)
4298 return 1;
4299
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004300 return 0;
4301}
4302
4303#define TABLA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
4304static int tabla_write(struct snd_soc_codec *codec, unsigned int reg,
4305 unsigned int value)
4306{
4307 int ret;
Kuirong Wang906ac472012-07-09 12:54:44 -07004308
4309 if (reg == SND_SOC_NOPM)
4310 return 0;
4311
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004312 BUG_ON(reg > TABLA_MAX_REGISTER);
4313
4314 if (!tabla_volatile(codec, reg)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004315 ret = snd_soc_cache_write(codec, reg, value);
4316 if (ret != 0)
4317 dev_err(codec->dev, "Cache write to %x failed: %d\n",
4318 reg, ret);
4319 }
4320
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304321 return wcd9xxx_reg_write(codec->control_data, reg, value);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004322}
4323static unsigned int tabla_read(struct snd_soc_codec *codec,
4324 unsigned int reg)
4325{
4326 unsigned int val;
4327 int ret;
4328
Kuirong Wang906ac472012-07-09 12:54:44 -07004329 if (reg == SND_SOC_NOPM)
4330 return 0;
4331
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004332 BUG_ON(reg > TABLA_MAX_REGISTER);
4333
4334 if (!tabla_volatile(codec, reg) && tabla_readable(codec, reg) &&
4335 reg < codec->driver->reg_cache_size) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004336 ret = snd_soc_cache_read(codec, reg, &val);
4337 if (ret >= 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004338 return val;
4339 } else
4340 dev_err(codec->dev, "Cache read from %x failed: %d\n",
4341 reg, ret);
4342 }
4343
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304344 val = wcd9xxx_reg_read(codec->control_data, reg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004345 return val;
4346}
4347
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004348static s16 tabla_get_current_v_ins(struct tabla_priv *tabla, bool hu)
4349{
4350 s16 v_ins;
4351 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
4352 tabla->mbhc_micbias_switched)
4353 v_ins = hu ? (s16)tabla->mbhc_data.adj_v_ins_hu :
4354 (s16)tabla->mbhc_data.adj_v_ins_h;
4355 else
4356 v_ins = hu ? (s16)tabla->mbhc_data.v_ins_hu :
4357 (s16)tabla->mbhc_data.v_ins_h;
4358 return v_ins;
4359}
4360
4361static s16 tabla_get_current_v_hs_max(struct tabla_priv *tabla)
4362{
4363 s16 v_hs_max;
4364 struct tabla_mbhc_plug_type_cfg *plug_type;
4365
4366 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
4367 if ((tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) &&
4368 tabla->mbhc_micbias_switched)
4369 v_hs_max = tabla->mbhc_data.adj_v_hs_max;
4370 else
4371 v_hs_max = plug_type->v_hs_max;
4372 return v_hs_max;
4373}
4374
Joonwoo Parkdd9d2962012-07-23 19:24:20 -07004375static void tabla_codec_calibrate_rel(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07004376{
Joonwoo Park0976d012011-12-22 11:48:18 -08004377 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004378
Joonwoo Park0976d012011-12-22 11:48:18 -08004379 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B3_CTL,
4380 tabla->mbhc_data.v_b1_hu & 0xFF);
4381 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B4_CTL,
4382 (tabla->mbhc_data.v_b1_hu >> 8) & 0xFF);
4383
4384 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B5_CTL,
4385 tabla->mbhc_data.v_b1_h & 0xFF);
4386 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B6_CTL,
4387 (tabla->mbhc_data.v_b1_h >> 8) & 0xFF);
4388
4389 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B9_CTL,
4390 tabla->mbhc_data.v_brh & 0xFF);
4391 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B10_CTL,
4392 (tabla->mbhc_data.v_brh >> 8) & 0xFF);
4393
4394 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B11_CTL,
4395 tabla->mbhc_data.v_brl & 0xFF);
4396 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B12_CTL,
4397 (tabla->mbhc_data.v_brl >> 8) & 0xFF);
Joonwoo Parkdd9d2962012-07-23 19:24:20 -07004398}
4399
4400static void tabla_codec_calibrate_hs_polling(struct snd_soc_codec *codec)
4401{
4402 u8 *n_ready, *n_cic;
4403 struct tabla_mbhc_btn_detect_cfg *btn_det;
4404 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4405 const s16 v_ins_hu = tabla_get_current_v_ins(tabla, true);
4406
4407 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
4408
4409 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B1_CTL,
4410 v_ins_hu & 0xFF);
4411 snd_soc_write(codec, TABLA_A_CDC_MBHC_VOLT_B2_CTL,
4412 (v_ins_hu >> 8) & 0xFF);
4413
4414 tabla_codec_calibrate_rel(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08004415
Joonwoo Parkc0672392012-01-11 11:03:14 -08004416 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Park0976d012011-12-22 11:48:18 -08004417 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B1_CTL,
Joonwoo Parkc0672392012-01-11 11:03:14 -08004418 n_ready[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08004419 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B2_CTL,
4420 tabla->mbhc_data.npoll);
4421 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B3_CTL,
4422 tabla->mbhc_data.nbounce_wait);
Joonwoo Park0976d012011-12-22 11:48:18 -08004423 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08004424 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL,
4425 n_cic[tabla_codec_mclk_index(tabla)]);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004426}
4427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004428static int tabla_startup(struct snd_pcm_substream *substream,
4429 struct snd_soc_dai *dai)
4430{
Kuirong Wanga545e722012-02-06 19:12:54 -08004431 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004432 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
4433 substream->name, substream->stream);
Kuirong Wanga545e722012-02-06 19:12:54 -08004434 if ((tabla_core != NULL) &&
4435 (tabla_core->dev != NULL) &&
4436 (tabla_core->dev->parent != NULL))
4437 pm_runtime_get_sync(tabla_core->dev->parent);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004438
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004439 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004440}
4441
Swaminathan Sathappanf95ece62012-08-23 16:01:50 -07004442static void tabla_shutdown(struct snd_pcm_substream *substream,
4443 struct snd_soc_dai *dai)
4444{
4445 struct wcd9xxx *tabla_core = dev_get_drvdata(dai->codec->dev->parent);
4446 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
4447 u32 active = 0;
4448
4449 pr_debug("%s(): substream = %s stream = %d\n" , __func__,
4450 substream->name, substream->stream);
4451 if (tabla->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
4452 return;
4453
4454 if (dai->id <= NUM_CODEC_DAIS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07004455 if (tabla->dai[dai->id].ch_mask) {
Swaminathan Sathappanf95ece62012-08-23 16:01:50 -07004456 active = 1;
Joonwoo Park9bbb4d12012-11-09 19:58:11 -08004457 pr_debug("%s(): Codec DAI: chmask[%d] = 0x%lx\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07004458 __func__, dai->id, tabla->dai[dai->id].ch_mask);
Swaminathan Sathappanf95ece62012-08-23 16:01:50 -07004459 }
4460 }
4461
4462 if ((tabla_core != NULL) &&
4463 (tabla_core->dev != NULL) &&
4464 (tabla_core->dev->parent != NULL) &&
4465 (active == 0)) {
4466 pm_runtime_mark_last_busy(tabla_core->dev->parent);
4467 pm_runtime_put(tabla_core->dev->parent);
4468 }
4469}
4470
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004471int tabla_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004472{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004473 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4474
Joonwoo Parkcf473b42012-03-29 19:48:16 -07004475 pr_debug("%s: mclk_enable = %u, dapm = %d\n", __func__, mclk_enable,
4476 dapm);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004477 if (dapm)
4478 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004479 if (mclk_enable) {
4480 tabla->mclk_enabled = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004481
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004482 if (tabla->mbhc_polling_active) {
Bradley Rubincb1e2732011-06-23 16:49:20 -07004483 tabla_codec_pause_hs_polling(codec);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004484 tabla_codec_disable_clock_block(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004485 tabla_codec_enable_bandgap(codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004486 TABLA_BANDGAP_AUDIO_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004487 tabla_codec_enable_clock_block(codec, 0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07004488 tabla_codec_calibrate_hs_polling(codec);
4489 tabla_codec_start_hs_polling(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05304490 } else {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004491 tabla_codec_disable_clock_block(codec);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05304492 tabla_codec_enable_bandgap(codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004493 TABLA_BANDGAP_AUDIO_MODE);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05304494 tabla_codec_enable_clock_block(codec, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004495 }
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004496 } else {
4497
4498 if (!tabla->mclk_enabled) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004499 if (dapm)
4500 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004501 pr_err("Error, MCLK already diabled\n");
4502 return -EINVAL;
4503 }
4504 tabla->mclk_enabled = false;
4505
4506 if (tabla->mbhc_polling_active) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004507 tabla_codec_pause_hs_polling(codec);
4508 tabla_codec_disable_clock_block(codec);
4509 tabla_codec_enable_bandgap(codec,
Simmi Pateriya71d63872012-11-08 01:06:30 +05304510 TABLA_BANDGAP_MBHC_MODE);
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004511 tabla_enable_rx_bias(codec, 1);
4512 tabla_codec_enable_clock_block(codec, 1);
4513 tabla_codec_calibrate_hs_polling(codec);
4514 tabla_codec_start_hs_polling(codec);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004515 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1,
4516 0x05, 0x01);
Asish Bhattacharya486745a2012-01-20 06:41:53 +05304517 } else {
4518 tabla_codec_disable_clock_block(codec);
4519 tabla_codec_enable_bandgap(codec,
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07004520 TABLA_BANDGAP_OFF);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004521 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004522 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07004523 if (dapm)
4524 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07004525 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004526}
4527
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004528static int tabla_set_dai_sysclk(struct snd_soc_dai *dai,
4529 int clk_id, unsigned int freq, int dir)
4530{
4531 pr_debug("%s\n", __func__);
4532 return 0;
4533}
4534
4535static int tabla_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
4536{
Santosh Mardie15e2302011-11-15 10:39:23 +05304537 u8 val = 0;
4538 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
4539
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004540 pr_debug("%s\n", __func__);
Santosh Mardie15e2302011-11-15 10:39:23 +05304541 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
4542 case SND_SOC_DAIFMT_CBS_CFS:
4543 /* CPU is master */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304544 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004545 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05304546 snd_soc_update_bits(dai->codec,
4547 TABLA_A_CDC_CLK_TX_I2S_CTL,
4548 TABLA_I2S_MASTER_MODE_MASK, 0);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004549 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05304550 snd_soc_update_bits(dai->codec,
4551 TABLA_A_CDC_CLK_RX_I2S_CTL,
4552 TABLA_I2S_MASTER_MODE_MASK, 0);
4553 }
4554 break;
4555 case SND_SOC_DAIFMT_CBM_CFM:
4556 /* CPU is slave */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304557 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05304558 val = TABLA_I2S_MASTER_MODE_MASK;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004559 if (dai->id == AIF1_CAP)
Santosh Mardie15e2302011-11-15 10:39:23 +05304560 snd_soc_update_bits(dai->codec,
4561 TABLA_A_CDC_CLK_TX_I2S_CTL, val, val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004562 else if (dai->id == AIF1_PB)
Santosh Mardie15e2302011-11-15 10:39:23 +05304563 snd_soc_update_bits(dai->codec,
4564 TABLA_A_CDC_CLK_RX_I2S_CTL, val, val);
4565 }
4566 break;
4567 default:
4568 return -EINVAL;
4569 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004570 return 0;
4571}
4572
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004573static int tabla_set_channel_map(struct snd_soc_dai *dai,
4574 unsigned int tx_num, unsigned int *tx_slot,
4575 unsigned int rx_num, unsigned int *rx_slot)
4576
4577{
4578 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07004579 struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
4580
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004581 if (!tx_slot && !rx_slot) {
4582 pr_err("%s: Invalid\n", __func__);
4583 return -EINVAL;
4584 }
Kuirong Wang906ac472012-07-09 12:54:44 -07004585 pr_debug("%s(): dai_name = %s DAI-ID %x tx_ch %d rx_ch %d\n"
4586 "tabla->intf_type %d\n",
4587 __func__, dai->name, dai->id, tx_num, rx_num,
4588 tabla->intf_type);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004589
Kuirong Wang906ac472012-07-09 12:54:44 -07004590 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
4591 wcd9xxx_init_slimslave(core, core->slim->laddr,
4592 tx_num, tx_slot, rx_num, rx_slot);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004593 return 0;
4594}
4595
4596static int tabla_get_channel_map(struct snd_soc_dai *dai,
4597 unsigned int *tx_num, unsigned int *tx_slot,
4598 unsigned int *rx_num, unsigned int *rx_slot)
4599
4600{
Kuirong Wang906ac472012-07-09 12:54:44 -07004601 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(dai->codec);
4602 u32 i = 0;
4603 struct wcd9xxx_ch *ch;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004604
Kuirong Wang906ac472012-07-09 12:54:44 -07004605 switch (dai->id) {
4606 case AIF1_PB:
4607 case AIF2_PB:
4608 case AIF3_PB:
4609 if (!rx_slot || !rx_num) {
4610 pr_err("%s: Invalid rx_slot %d or rx_num %d\n",
4611 __func__, (u32) rx_slot, (u32) rx_num);
4612 return -EINVAL;
4613 }
4614 list_for_each_entry(ch, &tabla_p->dai[dai->id].wcd9xxx_ch_list,
4615 list) {
4616 rx_slot[i++] = ch->ch_num;
4617 }
4618 *rx_num = i;
4619 break;
4620 case AIF1_CAP:
4621 case AIF2_CAP:
4622 case AIF3_CAP:
4623 if (!tx_slot || !tx_num) {
4624 pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
4625 __func__, (u32) tx_slot, (u32) tx_num);
4626 return -EINVAL;
4627 }
4628 list_for_each_entry(ch, &tabla_p->dai[dai->id].wcd9xxx_ch_list,
4629 list) {
4630 tx_slot[i++] = ch->ch_num;
4631 }
4632 *tx_num = i;
4633 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004634
Kuirong Wang906ac472012-07-09 12:54:44 -07004635 default:
4636 pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id);
4637 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004638 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004639 return 0;
4640}
4641
Kiran Kandi93923902012-06-20 17:00:25 -07004642
Kiran Kandi93923902012-06-20 17:00:25 -07004643static int tabla_set_interpolator_rate(struct snd_soc_dai *dai,
Kuirong Wang906ac472012-07-09 12:54:44 -07004644 u8 rx_fs_rate_reg_val,
4645 u32 compander_fs,
4646 u32 sample_rate)
Kiran Kandi93923902012-06-20 17:00:25 -07004647{
Kuirong Wang906ac472012-07-09 12:54:44 -07004648 u32 j;
Kiran Kandi93923902012-06-20 17:00:25 -07004649 u8 rx_mix1_inp;
4650 u16 rx_mix_1_reg_1, rx_mix_1_reg_2;
4651 u16 rx_fs_reg;
4652 u8 rx_mix_1_reg_1_val, rx_mix_1_reg_2_val;
4653 struct snd_soc_codec *codec = dai->codec;
Kuirong Wang906ac472012-07-09 12:54:44 -07004654 struct wcd9xxx_ch *ch;
Kiran Kandi93923902012-06-20 17:00:25 -07004655 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Kiran Kandi93923902012-06-20 17:00:25 -07004656
Kuirong Wang906ac472012-07-09 12:54:44 -07004657 list_for_each_entry(ch, &tabla->dai[dai->id].wcd9xxx_ch_list, list) {
Kiran Kandi93923902012-06-20 17:00:25 -07004658
Kuirong Wang906ac472012-07-09 12:54:44 -07004659 rx_mix1_inp = ch->port - RX_MIX1_INP_SEL_RX1;
Kiran Kandi93923902012-06-20 17:00:25 -07004660
Kuirong Wang906ac472012-07-09 12:54:44 -07004661 if ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
4662 (rx_mix1_inp > RX_MIX1_INP_SEL_RX7)) {
4663 pr_err("%s: Invalid TABLA_RX%u port. Dai ID is %d\n",
4664 __func__, rx_mix1_inp - 5 , dai->id);
Kiran Kandi93923902012-06-20 17:00:25 -07004665 return -EINVAL;
4666 }
4667
4668 rx_mix_1_reg_1 = TABLA_A_CDC_CONN_RX1_B1_CTL;
4669
4670 for (j = 0; j < NUM_INTERPOLATORS; j++) {
Kiran Kandi93923902012-06-20 17:00:25 -07004671 rx_mix_1_reg_2 = rx_mix_1_reg_1 + 1;
4672
4673 rx_mix_1_reg_1_val = snd_soc_read(codec,
Kuirong Wang906ac472012-07-09 12:54:44 -07004674 rx_mix_1_reg_1);
Kiran Kandi93923902012-06-20 17:00:25 -07004675 rx_mix_1_reg_2_val = snd_soc_read(codec,
Kuirong Wang906ac472012-07-09 12:54:44 -07004676 rx_mix_1_reg_2);
Kiran Kandi93923902012-06-20 17:00:25 -07004677
4678 if (((rx_mix_1_reg_1_val & 0x0F) == rx_mix1_inp) ||
Kuirong Wang906ac472012-07-09 12:54:44 -07004679 (((rx_mix_1_reg_1_val >> 4) & 0x0F) == rx_mix1_inp) ||
4680 ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
Kiran Kandi93923902012-06-20 17:00:25 -07004681
4682 rx_fs_reg = TABLA_A_CDC_RX1_B5_CTL + 8 * j;
4683
Kuirong Wang906ac472012-07-09 12:54:44 -07004684 pr_debug("%s: AIF_PB DAI(%d) connected to RX%u\n",
4685 __func__, dai->id, j + 1);
Kiran Kandi93923902012-06-20 17:00:25 -07004686
4687 pr_debug("%s: set RX%u sample rate to %u\n",
4688 __func__, j + 1, sample_rate);
4689
4690 snd_soc_update_bits(codec, rx_fs_reg,
Kuirong Wang906ac472012-07-09 12:54:44 -07004691 0xE0, rx_fs_rate_reg_val);
Kiran Kandi93923902012-06-20 17:00:25 -07004692
4693 if (comp_rx_path[j] < COMPANDER_MAX)
4694 tabla->comp_fs[comp_rx_path[j]]
4695 = compander_fs;
4696 }
4697 if (j <= 2)
4698 rx_mix_1_reg_1 += 3;
4699 else
4700 rx_mix_1_reg_1 += 2;
4701 }
4702 }
4703 return 0;
4704}
4705
4706static int tabla_set_decimator_rate(struct snd_soc_dai *dai,
Kuirong Wang906ac472012-07-09 12:54:44 -07004707 u8 tx_fs_rate_reg_val,
4708 u32 sample_rate)
Kiran Kandi93923902012-06-20 17:00:25 -07004709{
4710 struct snd_soc_codec *codec = dai->codec;
Kuirong Wang906ac472012-07-09 12:54:44 -07004711 struct wcd9xxx_ch *ch;
4712 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
4713 u32 tx_port;
Kiran Kandi93923902012-06-20 17:00:25 -07004714 u16 tx_port_reg, tx_fs_reg;
4715 u8 tx_port_reg_val;
4716 s8 decimator;
4717
Kuirong Wang906ac472012-07-09 12:54:44 -07004718 list_for_each_entry(ch, &tabla->dai[dai->id].wcd9xxx_ch_list, list) {
Kiran Kandi93923902012-06-20 17:00:25 -07004719
Kuirong Wang906ac472012-07-09 12:54:44 -07004720 tx_port = ch->port + 1;
4721 pr_debug("%s: dai->id = %d, tx_port = %d",
4722 __func__, dai->id, tx_port);
Kiran Kandi93923902012-06-20 17:00:25 -07004723
4724 if ((tx_port < 1) || (tx_port > NUM_DECIMATORS)) {
Kuirong Wang906ac472012-07-09 12:54:44 -07004725 pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
4726 __func__, tx_port, dai->id);
Kiran Kandi93923902012-06-20 17:00:25 -07004727 return -EINVAL;
4728 }
4729
4730 tx_port_reg = TABLA_A_CDC_CONN_TX_SB_B1_CTL + (tx_port - 1);
4731 tx_port_reg_val = snd_soc_read(codec, tx_port_reg);
4732
4733 decimator = 0;
4734
4735 if ((tx_port >= 1) && (tx_port <= 6)) {
4736
4737 tx_port_reg_val = tx_port_reg_val & 0x0F;
4738 if (tx_port_reg_val == 0x8)
4739 decimator = tx_port;
4740
4741 } else if ((tx_port >= 7) && (tx_port <= NUM_DECIMATORS)) {
4742
4743 tx_port_reg_val = tx_port_reg_val & 0x1F;
4744
4745 if ((tx_port_reg_val >= 0x8) &&
4746 (tx_port_reg_val <= 0x11)) {
4747
4748 decimator = (tx_port_reg_val - 0x8) + 1;
4749 }
4750 }
4751
4752 if (decimator) { /* SLIM_TX port has a DEC as input */
4753
4754 tx_fs_reg = TABLA_A_CDC_TX1_CLK_FS_CTL +
Kuirong Wang906ac472012-07-09 12:54:44 -07004755 8 * (decimator - 1);
Kiran Kandi93923902012-06-20 17:00:25 -07004756
4757 pr_debug("%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
4758 __func__, decimator, tx_port, sample_rate);
4759
4760 snd_soc_update_bits(codec, tx_fs_reg, 0x07,
Kuirong Wang906ac472012-07-09 12:54:44 -07004761 tx_fs_rate_reg_val);
Kiran Kandi93923902012-06-20 17:00:25 -07004762
4763 } else {
4764 if ((tx_port_reg_val >= 0x1) &&
Kuirong Wang906ac472012-07-09 12:54:44 -07004765 (tx_port_reg_val <= 0x7)) {
Kiran Kandi93923902012-06-20 17:00:25 -07004766
4767 pr_debug("%s: RMIX%u going to SLIM TX%u\n",
4768 __func__, tx_port_reg_val, tx_port);
4769
4770 } else if ((tx_port_reg_val >= 0x8) &&
Kuirong Wang906ac472012-07-09 12:54:44 -07004771 (tx_port_reg_val <= 0x11)) {
Kiran Kandi93923902012-06-20 17:00:25 -07004772
4773 pr_err("%s: ERROR: Should not be here\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07004774 __func__);
4775 pr_err("%s: ERROR: DEC connected to SLIM TX%u\n",
4776 __func__, tx_port);
Kiran Kandi93923902012-06-20 17:00:25 -07004777 return -EINVAL;
4778
4779 } else if (tx_port_reg_val == 0) {
4780 pr_debug("%s: no signal to SLIM TX%u\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07004781 __func__, tx_port);
Kiran Kandi93923902012-06-20 17:00:25 -07004782 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07004783 pr_err("%s: ERROR: wrong signal to SLIM TX%u\n",
4784 __func__, tx_port);
4785 pr_err("%s: ERROR: wrong signal = %u\n",
4786 __func__, tx_port_reg_val);
Kiran Kandi93923902012-06-20 17:00:25 -07004787 return -EINVAL;
4788 }
4789 }
4790 }
4791 return 0;
4792}
4793
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004794static int tabla_hw_params(struct snd_pcm_substream *substream,
Kuirong Wang906ac472012-07-09 12:54:44 -07004795 struct snd_pcm_hw_params *params,
4796 struct snd_soc_dai *dai)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004797{
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004798 struct snd_soc_codec *codec = dai->codec;
Santosh Mardie15e2302011-11-15 10:39:23 +05304799 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(dai->codec);
Kiran Kandi93923902012-06-20 17:00:25 -07004800 u8 tx_fs_rate_reg_val, rx_fs_rate_reg_val;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004801 u32 compander_fs;
Kiran Kandi93923902012-06-20 17:00:25 -07004802 int ret;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004803
Kiran Kandia9fffe92012-05-20 23:42:30 -07004804 pr_debug("%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
Kuirong Wang906ac472012-07-09 12:54:44 -07004805 dai->name, dai->id, params_rate(params),
4806 params_channels(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004807
4808 switch (params_rate(params)) {
4809 case 8000:
Kiran Kandi93923902012-06-20 17:00:25 -07004810 tx_fs_rate_reg_val = 0x00;
4811 rx_fs_rate_reg_val = 0x00;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004812 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004813 break;
4814 case 16000:
Kiran Kandi93923902012-06-20 17:00:25 -07004815 tx_fs_rate_reg_val = 0x01;
4816 rx_fs_rate_reg_val = 0x20;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004817 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004818 break;
4819 case 32000:
Kiran Kandi93923902012-06-20 17:00:25 -07004820 tx_fs_rate_reg_val = 0x02;
4821 rx_fs_rate_reg_val = 0x40;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004822 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004823 break;
4824 case 48000:
Kiran Kandi93923902012-06-20 17:00:25 -07004825 tx_fs_rate_reg_val = 0x03;
4826 rx_fs_rate_reg_val = 0x60;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08004827 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004828 break;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004829 case 96000:
Kiran Kandi93923902012-06-20 17:00:25 -07004830 tx_fs_rate_reg_val = 0x04;
4831 rx_fs_rate_reg_val = 0x80;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004832 compander_fs = COMPANDER_FS_96KHZ;
4833 break;
4834 case 192000:
Kiran Kandi93923902012-06-20 17:00:25 -07004835 tx_fs_rate_reg_val = 0x05;
4836 rx_fs_rate_reg_val = 0xA0;
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004837 compander_fs = COMPANDER_FS_192KHZ;
4838 break;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004839 default:
4840 pr_err("%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang906ac472012-07-09 12:54:44 -07004841 params_rate(params));
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004842 return -EINVAL;
4843 }
4844
Kiran Kandi93923902012-06-20 17:00:25 -07004845 switch (substream->stream) {
4846 case SNDRV_PCM_STREAM_CAPTURE:
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004847
Kiran Kandi93923902012-06-20 17:00:25 -07004848 ret = tabla_set_decimator_rate(dai, tx_fs_rate_reg_val,
Kuirong Wang906ac472012-07-09 12:54:44 -07004849 params_rate(params));
Kiran Kandi93923902012-06-20 17:00:25 -07004850 if (ret < 0) {
4851 pr_err("%s: set decimator rate failed %d\n", __func__,
Kuirong Wang906ac472012-07-09 12:54:44 -07004852 ret);
Kiran Kandi93923902012-06-20 17:00:25 -07004853 return ret;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004854 }
Kiran Kandi93923902012-06-20 17:00:25 -07004855
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304856 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05304857 switch (params_format(params)) {
4858 case SNDRV_PCM_FORMAT_S16_LE:
4859 snd_soc_update_bits(codec,
Kiran Kandi93923902012-06-20 17:00:25 -07004860 TABLA_A_CDC_CLK_TX_I2S_CTL, 0x20, 0x20);
Santosh Mardie15e2302011-11-15 10:39:23 +05304861 break;
4862 case SNDRV_PCM_FORMAT_S32_LE:
4863 snd_soc_update_bits(codec,
Kiran Kandi93923902012-06-20 17:00:25 -07004864 TABLA_A_CDC_CLK_TX_I2S_CTL, 0x20, 0x00);
Santosh Mardie15e2302011-11-15 10:39:23 +05304865 break;
4866 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07004867 pr_err("%s: Invalid format %d\n", __func__,
4868 params_format(params));
Kiran Kandi93923902012-06-20 17:00:25 -07004869 return -EINVAL;
Santosh Mardie15e2302011-11-15 10:39:23 +05304870 }
4871 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_TX_I2S_CTL,
Kuirong Wang906ac472012-07-09 12:54:44 -07004872 0x07, tx_fs_rate_reg_val);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004873 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07004874 switch (params_format(params)) {
4875 case SNDRV_PCM_FORMAT_S16_LE:
4876 tabla->dai[dai->id].bit_width = 16;
4877 break;
4878 default:
4879 pr_err("%s: Invalid TX format %d\n", __func__,
4880 params_format(params));
4881 return -EINVAL;
4882 }
4883 tabla->dai[dai->id].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05304884 }
Kiran Kandi93923902012-06-20 17:00:25 -07004885 break;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004886
Kiran Kandi93923902012-06-20 17:00:25 -07004887 case SNDRV_PCM_STREAM_PLAYBACK:
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004888
Kiran Kandi93923902012-06-20 17:00:25 -07004889 ret = tabla_set_interpolator_rate(dai, rx_fs_rate_reg_val,
Kuirong Wang906ac472012-07-09 12:54:44 -07004890 compander_fs,
4891 params_rate(params));
Kiran Kandi93923902012-06-20 17:00:25 -07004892 if (ret < 0) {
4893 pr_err("%s: set decimator rate failed %d\n", __func__,
Kuirong Wang906ac472012-07-09 12:54:44 -07004894 ret);
Kiran Kandi93923902012-06-20 17:00:25 -07004895 return ret;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004896 }
Kiran Kandi93923902012-06-20 17:00:25 -07004897
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05304898 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05304899 switch (params_format(params)) {
4900 case SNDRV_PCM_FORMAT_S16_LE:
4901 snd_soc_update_bits(codec,
Kiran Kandi93923902012-06-20 17:00:25 -07004902 TABLA_A_CDC_CLK_RX_I2S_CTL, 0x20, 0x20);
Santosh Mardie15e2302011-11-15 10:39:23 +05304903 break;
4904 case SNDRV_PCM_FORMAT_S32_LE:
4905 snd_soc_update_bits(codec,
Kiran Kandi93923902012-06-20 17:00:25 -07004906 TABLA_A_CDC_CLK_RX_I2S_CTL, 0x20, 0x00);
Santosh Mardie15e2302011-11-15 10:39:23 +05304907 break;
4908 default:
Kuirong Wang906ac472012-07-09 12:54:44 -07004909 pr_err("%s: Invalid RX format %d\n", __func__,
4910 params_format(params));
Kiran Kandi93923902012-06-20 17:00:25 -07004911 return -EINVAL;
Santosh Mardie15e2302011-11-15 10:39:23 +05304912 }
4913 snd_soc_update_bits(codec, TABLA_A_CDC_CLK_RX_I2S_CTL,
Kiran Kandi93923902012-06-20 17:00:25 -07004914 0x03, (rx_fs_rate_reg_val >> 0x05));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004915 } else {
Kuirong Wang906ac472012-07-09 12:54:44 -07004916 switch (params_format(params)) {
4917 case SNDRV_PCM_FORMAT_S16_LE:
4918 tabla->dai[dai->id].bit_width = 16;
4919 break;
4920 default:
4921 pr_err("%s: Invalid format %d\n", __func__,
4922 params_format(params));
4923 return -EINVAL;
4924 }
4925 tabla->dai[dai->id].rate = params_rate(params);
Santosh Mardie15e2302011-11-15 10:39:23 +05304926 }
Kiran Kandi93923902012-06-20 17:00:25 -07004927 break;
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004928
Kiran Kandi93923902012-06-20 17:00:25 -07004929 default:
4930 pr_err("%s: Invalid stream type %d\n", __func__,
Kuirong Wang906ac472012-07-09 12:54:44 -07004931 substream->stream);
Kiran Kandi93923902012-06-20 17:00:25 -07004932 return -EINVAL;
4933 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004934 return 0;
4935}
4936
4937static struct snd_soc_dai_ops tabla_dai_ops = {
4938 .startup = tabla_startup,
Swaminathan Sathappanf95ece62012-08-23 16:01:50 -07004939 .shutdown = tabla_shutdown,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004940 .hw_params = tabla_hw_params,
4941 .set_sysclk = tabla_set_dai_sysclk,
4942 .set_fmt = tabla_set_dai_fmt,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004943 .set_channel_map = tabla_set_channel_map,
4944 .get_channel_map = tabla_get_channel_map,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004945};
4946
4947static struct snd_soc_dai_driver tabla_dai[] = {
4948 {
4949 .name = "tabla_rx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004950 .id = AIF1_PB,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004951 .playback = {
4952 .stream_name = "AIF1 Playback",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004953 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004954 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004955 .rate_max = 192000,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004956 .rate_min = 8000,
4957 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004958 .channels_max = 2,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004959 },
4960 .ops = &tabla_dai_ops,
4961 },
4962 {
4963 .name = "tabla_tx1",
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004964 .id = AIF1_CAP,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004965 .capture = {
4966 .stream_name = "AIF1 Capture",
Bhalchandra Gajare9a901fd2011-08-01 10:07:15 -07004967 .rates = WCD9310_RATES,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004968 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004969 .rate_max = 192000,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004970 .rate_min = 8000,
4971 .channels_min = 1,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08004972 .channels_max = 4,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07004973 },
4974 .ops = &tabla_dai_ops,
4975 },
Neema Shettyd3a89262012-02-16 10:23:50 -08004976 {
4977 .name = "tabla_rx2",
4978 .id = AIF2_PB,
4979 .playback = {
4980 .stream_name = "AIF2 Playback",
4981 .rates = WCD9310_RATES,
4982 .formats = TABLA_FORMATS,
4983 .rate_min = 8000,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004984 .rate_max = 192000,
Neema Shettyd3a89262012-02-16 10:23:50 -08004985 .channels_min = 1,
4986 .channels_max = 2,
4987 },
4988 .ops = &tabla_dai_ops,
4989 },
Kiran Kandi1e6371d2012-03-29 11:48:57 -07004990 {
4991 .name = "tabla_tx2",
4992 .id = AIF2_CAP,
4993 .capture = {
4994 .stream_name = "AIF2 Capture",
4995 .rates = WCD9310_RATES,
4996 .formats = TABLA_FORMATS,
4997 .rate_max = 192000,
4998 .rate_min = 8000,
4999 .channels_min = 1,
5000 .channels_max = 4,
5001 },
5002 .ops = &tabla_dai_ops,
5003 },
Neema Shetty3fb1b802012-04-27 13:53:24 -07005004 {
5005 .name = "tabla_tx3",
5006 .id = AIF3_CAP,
5007 .capture = {
5008 .stream_name = "AIF3 Capture",
5009 .rates = WCD9310_RATES,
5010 .formats = TABLA_FORMATS,
5011 .rate_max = 48000,
5012 .rate_min = 8000,
5013 .channels_min = 1,
5014 .channels_max = 2,
5015 },
5016 .ops = &tabla_dai_ops,
5017 },
Kiran Kandia9fffe92012-05-20 23:42:30 -07005018 {
5019 .name = "tabla_rx3",
5020 .id = AIF3_PB,
5021 .playback = {
5022 .stream_name = "AIF3 Playback",
5023 .rates = WCD9310_RATES,
5024 .formats = TABLA_FORMATS,
5025 .rate_min = 8000,
5026 .rate_max = 192000,
5027 .channels_min = 1,
5028 .channels_max = 2,
5029 },
5030 .ops = &tabla_dai_ops,
5031 },
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005032};
Santosh Mardie15e2302011-11-15 10:39:23 +05305033
5034static struct snd_soc_dai_driver tabla_i2s_dai[] = {
5035 {
5036 .name = "tabla_i2s_rx1",
Kuirong Wang906ac472012-07-09 12:54:44 -07005037 .id = AIF1_PB,
Santosh Mardie15e2302011-11-15 10:39:23 +05305038 .playback = {
5039 .stream_name = "AIF1 Playback",
5040 .rates = WCD9310_RATES,
5041 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07005042 .rate_max = 192000,
Santosh Mardie15e2302011-11-15 10:39:23 +05305043 .rate_min = 8000,
5044 .channels_min = 1,
5045 .channels_max = 4,
5046 },
5047 .ops = &tabla_dai_ops,
5048 },
5049 {
5050 .name = "tabla_i2s_tx1",
Kuirong Wang906ac472012-07-09 12:54:44 -07005051 .id = AIF1_CAP,
Santosh Mardie15e2302011-11-15 10:39:23 +05305052 .capture = {
5053 .stream_name = "AIF1 Capture",
5054 .rates = WCD9310_RATES,
5055 .formats = TABLA_FORMATS,
Kiran Kandi1e6371d2012-03-29 11:48:57 -07005056 .rate_max = 192000,
Santosh Mardie15e2302011-11-15 10:39:23 +05305057 .rate_min = 8000,
5058 .channels_min = 1,
5059 .channels_max = 4,
5060 },
5061 .ops = &tabla_dai_ops,
5062 },
5063};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005064
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07005065static int tabla_codec_enable_chmask(struct tabla_priv *tabla_p,
Kuirong Wang906ac472012-07-09 12:54:44 -07005066 int event, int index)
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07005067{
5068 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -07005069 struct wcd9xxx_ch *ch;
5070
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07005071 switch (event) {
5072 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07005073 list_for_each_entry(ch,
5074 &tabla_p->dai[index].wcd9xxx_ch_list, list) {
5075 ret = wcd9xxx_get_slave_port(ch->ch_num);
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07005076 if (ret < 0) {
5077 pr_err("%s: Invalid slave port ID: %d\n",
5078 __func__, ret);
5079 ret = -EINVAL;
5080 break;
5081 }
5082 tabla_p->dai[index].ch_mask |= 1 << ret;
5083 }
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07005084 break;
5085 case SND_SOC_DAPM_POST_PMD:
5086 ret = wait_event_timeout(tabla_p->dai[index].dai_wait,
5087 (tabla_p->dai[index].ch_mask == 0),
5088 msecs_to_jiffies(SLIM_CLOSE_TIMEOUT));
5089 if (!ret) {
5090 pr_err("%s: Slim close tx/rx wait timeout\n",
5091 __func__);
5092 ret = -EINVAL;
Kuirong Wang906ac472012-07-09 12:54:44 -07005093 }
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07005094 break;
5095 }
5096 return ret;
5097}
5098
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005099static int tabla_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
Kuirong Wang906ac472012-07-09 12:54:44 -07005100 struct snd_kcontrol *kcontrol,
5101 int event)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005102{
Kuirong Wang906ac472012-07-09 12:54:44 -07005103 struct wcd9xxx *core;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005104 struct snd_soc_codec *codec = w->codec;
5105 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07005106 u32 ret = 0;
5107 struct wcd9xxx_codec_dai_data *dai;
5108
5109 core = dev_get_drvdata(codec->dev->parent);
5110
5111 pr_debug("%s: event called! codec name %s num_dai %d\n"
5112 "stream name %s event %d\n",
5113 __func__, w->codec->name, w->codec->num_dai,
5114 w->sname, event);
Swaminathan Sathappanb74caaa2012-07-10 17:28:54 -07005115
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005116 /* Execute the callback only if interface type is slimbus */
Swaminathan Sathappanb74caaa2012-07-10 17:28:54 -07005117 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07005118 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL) &&
5119 (core->dev != NULL) &&
5120 (core->dev->parent != NULL)) {
5121 pm_runtime_mark_last_busy(core->dev->parent);
5122 pm_runtime_put(core->dev->parent);
Swaminathan Sathappanb74caaa2012-07-10 17:28:54 -07005123 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005124 return 0;
Swaminathan Sathappanb74caaa2012-07-10 17:28:54 -07005125 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005126 pr_debug("%s: w->name %s w->shift %d event %d\n",
5127 __func__, w->name, w->shift, event);
5128 dai = &tabla_p->dai[w->shift];
Kiran Kandia9fffe92012-05-20 23:42:30 -07005129
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005130 switch (event) {
5131 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07005132 ret = tabla_codec_enable_chmask(tabla_p, SND_SOC_DAPM_POST_PMU,
5133 w->shift);
5134 ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
5135 dai->rate, dai->bit_width,
5136 &dai->grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005137 break;
5138 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07005139 ret = wcd9xxx_close_slim_sch_rx(core,
5140 &dai->wcd9xxx_ch_list,
5141 dai->grph);
5142 ret = tabla_codec_enable_chmask(tabla_p, SND_SOC_DAPM_POST_PMD,
5143 w->shift);
5144 if (ret < 0) {
5145 ret = wcd9xxx_disconnect_port(core,
5146 &dai->wcd9xxx_ch_list,
5147 dai->grph);
5148 pr_info("%s: Disconnect RX port, ret = %d\n",
5149 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005150 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005151 if ((core != NULL) &&
5152 (core->dev != NULL) &&
5153 (core->dev->parent != NULL)) {
5154 pm_runtime_mark_last_busy(core->dev->parent);
5155 pm_runtime_put(core->dev->parent);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005156 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005157 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005158 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005159
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005160 return ret;
5161}
5162
5163static int tabla_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
Kuirong Wang906ac472012-07-09 12:54:44 -07005164 struct snd_kcontrol *kcontrol,
5165 int event)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005166{
Kuirong Wang906ac472012-07-09 12:54:44 -07005167 struct wcd9xxx *core;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005168 struct snd_soc_codec *codec = w->codec;
5169 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
Kuirong Wang906ac472012-07-09 12:54:44 -07005170 u32 ret = 0;
5171 struct wcd9xxx_codec_dai_data *dai;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005172
Kuirong Wang906ac472012-07-09 12:54:44 -07005173 core = dev_get_drvdata(codec->dev->parent);
5174
5175 pr_debug("%s: event called! codec name %s num_dai %d\n"
5176 "stream name %s\n", __func__, w->codec->name,
5177 w->codec->num_dai, w->sname);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005178
5179 /* Execute the callback only if interface type is slimbus */
Swaminathan Sathappanb74caaa2012-07-10 17:28:54 -07005180 if (tabla_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
Kuirong Wang906ac472012-07-09 12:54:44 -07005181 if (event == SND_SOC_DAPM_POST_PMD && (core != NULL) &&
5182 (core->dev != NULL) &&
5183 (core->dev->parent != NULL)) {
5184 pm_runtime_mark_last_busy(core->dev->parent);
5185 pm_runtime_put(core->dev->parent);
Swaminathan Sathappanb74caaa2012-07-10 17:28:54 -07005186 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005187 return 0;
Swaminathan Sathappanb74caaa2012-07-10 17:28:54 -07005188 }
Kiran Kandi1e6371d2012-03-29 11:48:57 -07005189
5190 pr_debug("%s(): %s %d\n", __func__, w->name, event);
5191
Kuirong Wang906ac472012-07-09 12:54:44 -07005192 dai = &tabla_p->dai[w->shift];
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005193 switch (event) {
5194 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang906ac472012-07-09 12:54:44 -07005195 ret = tabla_codec_enable_chmask(tabla_p, SND_SOC_DAPM_POST_PMU,
5196 w->shift);
5197 ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
5198 dai->rate,
5199 dai->bit_width,
5200 &dai->grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005201 break;
5202 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang906ac472012-07-09 12:54:44 -07005203 ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
5204 dai->grph);
5205 ret = tabla_codec_enable_chmask(tabla_p, SND_SOC_DAPM_POST_PMD,
5206 w->shift);
5207 if (ret < 0) {
5208 ret = wcd9xxx_disconnect_port(core,
5209 &dai->wcd9xxx_ch_list,
5210 dai->grph);
5211 pr_info("%s: Disconnect TX port, ret = %d\n",
5212 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005213 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005214 if ((core != NULL) &&
5215 (core->dev != NULL) &&
5216 (core->dev->parent != NULL)) {
5217 pm_runtime_mark_last_busy(core->dev->parent);
5218 pm_runtime_put(core->dev->parent);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005219 }
Kuirong Wang906ac472012-07-09 12:54:44 -07005220 break;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005221 }
5222 return ret;
5223}
5224
5225/* Todo: Have seperate dapm widgets for I2S and Slimbus.
5226 * Might Need to have callbacks registered only for slimbus
5227 */
5228static const struct snd_soc_dapm_widget tabla_dapm_widgets[] = {
5229 /*RX stuff */
5230 SND_SOC_DAPM_OUTPUT("EAR"),
5231
Damir Didjusto7c85d712012-08-16 21:22:29 -07005232 SND_SOC_DAPM_PGA_E("EAR PA", SND_SOC_NOPM, 0, 0, NULL,
5233 0, tabla_ear_pa_event, SND_SOC_DAPM_PRE_PMU |
5234 SND_SOC_DAPM_PRE_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005235
Damir Didjusto7c85d712012-08-16 21:22:29 -07005236 SND_SOC_DAPM_MIXER("DAC1", SND_SOC_NOPM, 0, 0, dac1_switch,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005237 ARRAY_SIZE(dac1_switch)),
5238
Kuirong Wang906ac472012-07-09 12:54:44 -07005239 SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
5240 AIF1_PB, 0, tabla_codec_enable_slimrx,
5241 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5242 SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
5243 AIF2_PB, 0, tabla_codec_enable_slimrx,
5244 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5245 SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
5246 AIF3_PB, 0, tabla_codec_enable_slimrx,
5247 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5248
5249 SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TABLA_RX1, 0,
5250 &slim_rx_mux[TABLA_RX1]),
5251 SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TABLA_RX2, 0,
5252 &slim_rx_mux[TABLA_RX2]),
5253 SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TABLA_RX3, 0,
5254 &slim_rx_mux[TABLA_RX3]),
5255 SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TABLA_RX4, 0,
5256 &slim_rx_mux[TABLA_RX4]),
5257 SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TABLA_RX5, 0,
5258 &slim_rx_mux[TABLA_RX5]),
5259 SND_SOC_DAPM_MUX("SLIM RX6 MUX", SND_SOC_NOPM, TABLA_RX6, 0,
5260 &slim_rx_mux[TABLA_RX6]),
5261 SND_SOC_DAPM_MUX("SLIM RX7 MUX", SND_SOC_NOPM, TABLA_RX7, 0,
5262 &slim_rx_mux[TABLA_RX7]),
5263
5264 SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
5265 SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
5266 SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
5267 SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
5268 SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
5269 SND_SOC_DAPM_MIXER("SLIM RX6", SND_SOC_NOPM, 0, 0, NULL, 0),
5270 SND_SOC_DAPM_MIXER("SLIM RX7", SND_SOC_NOPM, 0, 0, NULL, 0),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005271 /* Headphone */
5272 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
5273 SND_SOC_DAPM_PGA_E("HPHL", TABLA_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
5274 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
5275 SND_SOC_DAPM_POST_PMD),
5276 SND_SOC_DAPM_MIXER("HPHL DAC", TABLA_A_RX_HPH_L_DAC_CTL, 7, 0,
5277 hphl_switch, ARRAY_SIZE(hphl_switch)),
5278
5279 SND_SOC_DAPM_PGA_E("HPHR", TABLA_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
5280 tabla_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
5281 SND_SOC_DAPM_POST_PMD),
5282
5283 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TABLA_A_RX_HPH_R_DAC_CTL, 7, 0,
5284 tabla_hphr_dac_event,
5285 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
5286
5287 /* Speaker */
5288 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
5289 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
5290 SND_SOC_DAPM_OUTPUT("LINEOUT3"),
5291 SND_SOC_DAPM_OUTPUT("LINEOUT4"),
5292 SND_SOC_DAPM_OUTPUT("LINEOUT5"),
5293
5294 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TABLA_A_RX_LINE_CNP_EN, 0, 0, NULL,
5295 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
5296 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5297 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TABLA_A_RX_LINE_CNP_EN, 1, 0, NULL,
5298 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
5299 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5300 SND_SOC_DAPM_PGA_E("LINEOUT3 PA", TABLA_A_RX_LINE_CNP_EN, 2, 0, NULL,
5301 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
5302 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5303 SND_SOC_DAPM_PGA_E("LINEOUT4 PA", TABLA_A_RX_LINE_CNP_EN, 3, 0, NULL,
5304 0, tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
5305 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5306 SND_SOC_DAPM_PGA_E("LINEOUT5 PA", TABLA_A_RX_LINE_CNP_EN, 4, 0, NULL, 0,
5307 tabla_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
5308 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5309
5310 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TABLA_A_RX_LINE_1_DAC_CTL, 7, 0
5311 , tabla_lineout_dac_event,
5312 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
5313 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TABLA_A_RX_LINE_2_DAC_CTL, 7, 0
5314 , tabla_lineout_dac_event,
5315 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
5316 SND_SOC_DAPM_DAC_E("LINEOUT3 DAC", NULL, TABLA_A_RX_LINE_3_DAC_CTL, 7, 0
5317 , tabla_lineout_dac_event,
5318 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
5319 SND_SOC_DAPM_SWITCH("LINEOUT3 DAC GROUND", SND_SOC_NOPM, 0, 0,
5320 &lineout3_ground_switch),
5321 SND_SOC_DAPM_DAC_E("LINEOUT4 DAC", NULL, TABLA_A_RX_LINE_4_DAC_CTL, 7, 0
5322 , tabla_lineout_dac_event,
5323 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
5324 SND_SOC_DAPM_SWITCH("LINEOUT4 DAC GROUND", SND_SOC_NOPM, 0, 0,
5325 &lineout4_ground_switch),
5326 SND_SOC_DAPM_DAC_E("LINEOUT5 DAC", NULL, TABLA_A_RX_LINE_5_DAC_CTL, 7, 0
5327 , tabla_lineout_dac_event,
5328 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
5329
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08005330 SND_SOC_DAPM_MIXER_E("RX1 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07005331 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
5332 SND_SOC_DAPM_POST_PMU),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08005333 SND_SOC_DAPM_MIXER_E("RX2 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07005334 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
5335 SND_SOC_DAPM_POST_PMU),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08005336 SND_SOC_DAPM_MIXER_E("RX3 MIX2", TABLA_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07005337 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
5338 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005339 SND_SOC_DAPM_MIXER_E("RX4 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07005340 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
5341 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005342 SND_SOC_DAPM_MIXER_E("RX5 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 4, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07005343 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
5344 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005345 SND_SOC_DAPM_MIXER_E("RX6 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07005346 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
5347 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005348 SND_SOC_DAPM_MIXER_E("RX7 MIX1", TABLA_A_CDC_CLK_RX_B1_CTL, 6, 0, NULL,
Kuirong Wange9c8a222012-03-28 16:24:09 -07005349 0, tabla_codec_reset_interpolator, SND_SOC_DAPM_PRE_PMU |
5350 SND_SOC_DAPM_POST_PMU),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005351
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08005352 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
5353 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
5354 SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
5355
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005356 SND_SOC_DAPM_MUX_E("RX4 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 3, 0,
5357 &rx4_dsm_mux, tabla_codec_reset_interpolator,
5358 SND_SOC_DAPM_PRE_PMU),
5359
5360 SND_SOC_DAPM_MUX_E("RX6 DSM MUX", TABLA_A_CDC_CLK_RX_B1_CTL, 5, 0,
5361 &rx6_dsm_mux, tabla_codec_reset_interpolator,
5362 SND_SOC_DAPM_PRE_PMU),
5363
5364 SND_SOC_DAPM_MIXER("RX1 CHAIN", TABLA_A_CDC_RX1_B6_CTL, 5, 0, NULL, 0),
5365 SND_SOC_DAPM_MIXER("RX2 CHAIN", TABLA_A_CDC_RX2_B6_CTL, 5, 0, NULL, 0),
5366
5367 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
5368 &rx_mix1_inp1_mux),
5369 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
5370 &rx_mix1_inp2_mux),
Kiran Kandia9fffe92012-05-20 23:42:30 -07005371 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
5372 &rx_mix1_inp3_mux),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005373 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
5374 &rx2_mix1_inp1_mux),
5375 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
5376 &rx2_mix1_inp2_mux),
5377 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
5378 &rx3_mix1_inp1_mux),
5379 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
5380 &rx3_mix1_inp2_mux),
5381 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
5382 &rx4_mix1_inp1_mux),
5383 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
5384 &rx4_mix1_inp2_mux),
5385 SND_SOC_DAPM_MUX("RX5 MIX1 INP1", SND_SOC_NOPM, 0, 0,
5386 &rx5_mix1_inp1_mux),
5387 SND_SOC_DAPM_MUX("RX5 MIX1 INP2", SND_SOC_NOPM, 0, 0,
5388 &rx5_mix1_inp2_mux),
5389 SND_SOC_DAPM_MUX("RX6 MIX1 INP1", SND_SOC_NOPM, 0, 0,
5390 &rx6_mix1_inp1_mux),
5391 SND_SOC_DAPM_MUX("RX6 MIX1 INP2", SND_SOC_NOPM, 0, 0,
5392 &rx6_mix1_inp2_mux),
5393 SND_SOC_DAPM_MUX("RX7 MIX1 INP1", SND_SOC_NOPM, 0, 0,
5394 &rx7_mix1_inp1_mux),
5395 SND_SOC_DAPM_MUX("RX7 MIX1 INP2", SND_SOC_NOPM, 0, 0,
5396 &rx7_mix1_inp2_mux),
Kuirong Wangbfdd6ca2012-02-29 13:06:38 -08005397 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
5398 &rx1_mix2_inp1_mux),
5399 SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
5400 &rx1_mix2_inp2_mux),
5401 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
5402 &rx2_mix2_inp1_mux),
5403 SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
5404 &rx2_mix2_inp2_mux),
5405 SND_SOC_DAPM_MUX("RX3 MIX2 INP1", SND_SOC_NOPM, 0, 0,
5406 &rx3_mix2_inp1_mux),
5407 SND_SOC_DAPM_MUX("RX3 MIX2 INP2", SND_SOC_NOPM, 0, 0,
5408 &rx3_mix2_inp2_mux),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005409
5410 SND_SOC_DAPM_SUPPLY("CP", TABLA_A_CP_EN, 0, 0,
5411 tabla_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
5412 SND_SOC_DAPM_PRE_PMD),
5413
5414 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
5415 tabla_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
5416 SND_SOC_DAPM_POST_PMD),
5417
5418 /* TX */
5419
5420 SND_SOC_DAPM_SUPPLY("CDC_CONN", TABLA_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
5421 0),
5422
Simmi Pateriya71d63872012-11-08 01:06:30 +05305423 SND_SOC_DAPM_SUPPLY("LDO_H", SND_SOC_NOPM, 0, 0,
5424 tabla_codec_enable_ldo_h, SND_SOC_DAPM_PRE_PMU |
5425 SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005426
Kuirong Wang0f8ade32012-02-27 16:29:45 -08005427 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 0, 0,
5428 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
5429 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
5430 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 1, 0,
5431 tabla_config_compander, SND_SOC_DAPM_PRE_PMU |
5432 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
5433
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005434 SND_SOC_DAPM_INPUT("AMIC1"),
Simmi Pateriya71d63872012-11-08 01:06:30 +05305435 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005436 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
5437 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriya71d63872012-11-08 01:06:30 +05305438 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005439 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
5440 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriya71d63872012-11-08 01:06:30 +05305441 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005442 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
5443 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5444 SND_SOC_DAPM_ADC_E("ADC1", NULL, TABLA_A_TX_1_2_EN, 7, 0,
5445 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
5446 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5447
5448 SND_SOC_DAPM_INPUT("AMIC3"),
5449 SND_SOC_DAPM_ADC_E("ADC3", NULL, TABLA_A_TX_3_4_EN, 7, 0,
5450 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
5451 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5452
5453 SND_SOC_DAPM_INPUT("AMIC4"),
5454 SND_SOC_DAPM_ADC_E("ADC4", NULL, TABLA_A_TX_3_4_EN, 3, 0,
5455 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
5456 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5457
5458 SND_SOC_DAPM_INPUT("AMIC5"),
5459 SND_SOC_DAPM_ADC_E("ADC5", NULL, TABLA_A_TX_5_6_EN, 7, 0,
5460 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
5461
5462 SND_SOC_DAPM_INPUT("AMIC6"),
5463 SND_SOC_DAPM_ADC_E("ADC6", NULL, TABLA_A_TX_5_6_EN, 3, 0,
5464 tabla_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
5465
5466 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 -08005467 &dec1_mux, tabla_codec_enable_dec,
5468 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5469 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005470
5471 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 -08005472 &dec2_mux, tabla_codec_enable_dec,
5473 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5474 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005475
5476 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 -08005477 &dec3_mux, tabla_codec_enable_dec,
5478 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5479 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005480
5481 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 -08005482 &dec4_mux, tabla_codec_enable_dec,
5483 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5484 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005485
5486 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 -08005487 &dec5_mux, tabla_codec_enable_dec,
5488 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5489 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005490
5491 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 -08005492 &dec6_mux, tabla_codec_enable_dec,
5493 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5494 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005495
5496 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 -08005497 &dec7_mux, tabla_codec_enable_dec,
5498 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5499 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005500
5501 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 -08005502 &dec8_mux, tabla_codec_enable_dec,
5503 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5504 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005505
5506 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 -08005507 &dec9_mux, tabla_codec_enable_dec,
5508 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5509 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005510
5511 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 -08005512 &dec10_mux, tabla_codec_enable_dec,
5513 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5514 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005515
5516 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
5517 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
5518
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08005519 SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
5520 SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 0, 0, NULL, 0,
5521 tabla_codec_enable_anc,
5522 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
5523 SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 0, 0, NULL, 0,
5524 tabla_codec_enable_anc, SND_SOC_DAPM_PRE_PMU),
5525
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005526
5527 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
5528
5529 SND_SOC_DAPM_INPUT("AMIC2"),
Simmi Pateriya71d63872012-11-08 01:06:30 +05305530 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005531 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
Simmi Pateriya71d63872012-11-08 01:06:30 +05305532 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5533 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Power External",
5534 TABLA_A_MICB_2_CTL, 7, 0,
5535 tabla_codec_enable_micbias_power,
5536 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
5537 SND_SOC_DAPM_POST_PMD),
5538
5539 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005540 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
5541 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriya71d63872012-11-08 01:06:30 +05305542 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005543 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
5544 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriya71d63872012-11-08 01:06:30 +05305545 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005546 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
5547 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriya71d63872012-11-08 01:06:30 +05305548 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005549 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
5550 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriya71d63872012-11-08 01:06:30 +05305551 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005552 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
5553 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriya71d63872012-11-08 01:06:30 +05305554 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", SND_SOC_NOPM, 0, 0,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005555 tabla_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
5556 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5557 SND_SOC_DAPM_ADC_E("ADC2", NULL, TABLA_A_TX_1_2_EN, 3, 0,
5558 tabla_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
5559 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5560
Kuirong Wang906ac472012-07-09 12:54:44 -07005561 SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
5562 AIF1_CAP, 0, tabla_codec_enable_slimtx,
5563 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5564
5565 SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
5566 AIF2_CAP, 0, tabla_codec_enable_slimtx,
5567 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5568
5569 SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
5570 AIF3_CAP, 0, tabla_codec_enable_slimtx,
5571 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
5572
5573 SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
5574 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
5575
5576 SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
5577 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
5578
5579 SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
5580 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
5581
5582 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TABLA_TX1, 0,
5583 &sb_tx1_mux),
5584 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TABLA_TX2, 0,
5585 &sb_tx2_mux),
5586 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TABLA_TX3, 0,
5587 &sb_tx3_mux),
5588 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TABLA_TX4, 0,
5589 &sb_tx4_mux),
5590 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TABLA_TX5, 0,
5591 &sb_tx5_mux),
5592 SND_SOC_DAPM_MUX("SLIM TX6 MUX", SND_SOC_NOPM, TABLA_TX6, 0,
5593 &sb_tx6_mux),
5594 SND_SOC_DAPM_MUX("SLIM TX7 MUX", SND_SOC_NOPM, TABLA_TX7, 0,
5595 &sb_tx7_mux),
5596 SND_SOC_DAPM_MUX("SLIM TX8 MUX", SND_SOC_NOPM, TABLA_TX8, 0,
5597 &sb_tx8_mux),
5598 SND_SOC_DAPM_MUX("SLIM TX9 MUX", SND_SOC_NOPM, TABLA_TX9, 0,
5599 &sb_tx9_mux),
5600 SND_SOC_DAPM_MUX("SLIM TX10 MUX", SND_SOC_NOPM, TABLA_TX10, 0,
5601 &sb_tx10_mux),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005602
5603 /* Digital Mic Inputs */
5604 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
5605 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
5606 SND_SOC_DAPM_POST_PMD),
5607
5608 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
5609 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
5610 SND_SOC_DAPM_POST_PMD),
5611
5612 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
5613 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
5614 SND_SOC_DAPM_POST_PMD),
5615
5616 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
5617 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
5618 SND_SOC_DAPM_POST_PMD),
5619
5620 SND_SOC_DAPM_ADC_E("DMIC5", NULL, SND_SOC_NOPM, 0, 0,
5621 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
5622 SND_SOC_DAPM_POST_PMD),
5623 SND_SOC_DAPM_ADC_E("DMIC6", NULL, SND_SOC_NOPM, 0, 0,
5624 tabla_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
5625 SND_SOC_DAPM_POST_PMD),
5626
5627 /* Sidetone */
5628 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
5629 SND_SOC_DAPM_PGA("IIR1", TABLA_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08005630
Bhalchandra Gajare8ba44462012-07-26 18:08:21 -07005631 SND_SOC_DAPM_MUX("IIR2 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir2_inp1_mux),
5632 SND_SOC_DAPM_PGA("IIR2", TABLA_A_CDC_CLK_SD_CTL, 1, 0, NULL, 0),
5633
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08005634 /* AUX PGA */
5635 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TABLA_A_AUX_L_EN, 7, 0,
5636 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
5637 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
5638 SND_SOC_DAPM_POST_PMD),
5639
5640 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TABLA_A_AUX_R_EN, 7, 0,
5641 tabla_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
5642 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD |
5643 SND_SOC_DAPM_POST_PMD),
5644
5645 /* Lineout, ear and HPH PA Mixers */
5646 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
5647 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
5648
5649 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
5650 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
5651
5652 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
5653 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
5654
5655 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
5656 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
5657
5658 SND_SOC_DAPM_MIXER("LINEOUT3_PA_MIXER", SND_SOC_NOPM, 0, 0,
5659 lineout3_pa_mix, ARRAY_SIZE(lineout3_pa_mix)),
5660
5661 SND_SOC_DAPM_MIXER("LINEOUT4_PA_MIXER", SND_SOC_NOPM, 0, 0,
5662 lineout4_pa_mix, ARRAY_SIZE(lineout4_pa_mix)),
5663
5664 SND_SOC_DAPM_MIXER("LINEOUT5_PA_MIXER", SND_SOC_NOPM, 0, 0,
5665 lineout5_pa_mix, ARRAY_SIZE(lineout5_pa_mix)),
5666
5667 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
5668 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08005669};
5670
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005671static short tabla_codec_read_sta_result(struct snd_soc_codec *codec)
Bradley Rubincb1e2732011-06-23 16:49:20 -07005672{
5673 u8 bias_msb, bias_lsb;
5674 short bias_value;
5675
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005676 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B3_STATUS);
5677 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B2_STATUS);
5678 bias_value = (bias_msb << 8) | bias_lsb;
5679 return bias_value;
5680}
5681
5682static short tabla_codec_read_dce_result(struct snd_soc_codec *codec)
5683{
5684 u8 bias_msb, bias_lsb;
5685 short bias_value;
5686
5687 bias_msb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B5_STATUS);
5688 bias_lsb = snd_soc_read(codec, TABLA_A_CDC_MBHC_B4_STATUS);
5689 bias_value = (bias_msb << 8) | bias_lsb;
5690 return bias_value;
5691}
5692
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005693static void tabla_turn_onoff_rel_detection(struct snd_soc_codec *codec, bool on)
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005694{
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005695 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, on << 1);
5696}
5697
5698static short __tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
5699 bool override_bypass, bool noreldetection)
5700{
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005701 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005702 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5703
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005704 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005705 if (noreldetection)
5706 tabla_turn_onoff_rel_detection(codec, false);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005707
Joonwoo Park925914c2012-01-05 13:35:18 -08005708 /* Turn on the override */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005709 if (!override_bypass)
5710 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x4, 0x4);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005711 if (dce) {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005712 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
5713 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
5714 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08005715 usleep_range(tabla->mbhc_data.t_sta_dce,
5716 tabla->mbhc_data.t_sta_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005717 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x4);
Joonwoo Park0976d012011-12-22 11:48:18 -08005718 usleep_range(tabla->mbhc_data.t_dce,
5719 tabla->mbhc_data.t_dce);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005720 bias_value = tabla_codec_read_dce_result(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005721 } else {
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005722 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005723 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
5724 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x0);
Joonwoo Park433149a2012-01-11 09:53:54 -08005725 usleep_range(tabla->mbhc_data.t_sta_dce,
5726 tabla->mbhc_data.t_sta_dce);
Joonwoo Park0976d012011-12-22 11:48:18 -08005727 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x2);
5728 usleep_range(tabla->mbhc_data.t_sta,
5729 tabla->mbhc_data.t_sta);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005730 bias_value = tabla_codec_read_sta_result(codec);
5731 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
5732 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005733 }
Joonwoo Park925914c2012-01-05 13:35:18 -08005734 /* Turn off the override after measuring mic voltage */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005735 if (!override_bypass)
5736 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
5737
5738 if (noreldetection)
5739 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005740 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005741
Bradley Rubincb1e2732011-06-23 16:49:20 -07005742 return bias_value;
5743}
5744
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005745static short tabla_codec_sta_dce(struct snd_soc_codec *codec, int dce,
5746 bool norel)
5747{
5748 return __tabla_codec_sta_dce(codec, dce, false, norel);
5749}
5750
5751/* called only from interrupt which is under codec_resource_lock acquisition */
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07005752static short tabla_codec_setup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005753{
5754 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07005755 short bias_value;
Simmi Pateriya71d63872012-11-08 01:06:30 +05305756 u8 cfilt_mode = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005757
Joonwoo Parkcf473b42012-03-29 19:48:16 -07005758 pr_debug("%s: enter, mclk_enabled %d\n", __func__, tabla->mclk_enabled);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005759 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005760 pr_err("Error, no tabla calibration\n");
Bradley Rubincb1e2732011-06-23 16:49:20 -07005761 return -ENODEV;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005762 }
5763
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005764 if (!tabla->mclk_enabled) {
Joonwoo Park8a6bccc2012-05-03 15:13:13 -07005765 tabla_codec_disable_clock_block(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005766 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_MBHC_MODE);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07005767 tabla_enable_rx_bias(codec, 1);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005768 tabla_codec_enable_clock_block(codec, 1);
5769 }
5770
5771 snd_soc_update_bits(codec, TABLA_A_CLK_BUFF_EN1, 0x05, 0x01);
Simmi Pateriya71d63872012-11-08 01:06:30 +05305772 if (!tabla->mbhc_cfg.micbias_always_on) {
5773 /* Make sure CFILT is in fast mode, save current mode */
5774 cfilt_mode = snd_soc_read(codec,
5775 tabla->mbhc_bias_regs.cfilt_ctl);
5776 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
5777 0x70, 0x00);
5778 }
Patrick Lai3043fba2011-08-01 14:15:57 -07005779
Joonwoo Parkf4267c22012-01-10 13:25:24 -08005780 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x1F, 0x16);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005781
5782 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005783 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005784
5785 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x80);
5786 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x1F, 0x1C);
5787 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x40, 0x40);
5788
5789 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN, 0x80, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005790 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
5791 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x00);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005792
Joonwoo Park925914c2012-01-05 13:35:18 -08005793 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x2, 0x2);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005794 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x8, 0x8);
5795
Bradley Rubincb1e2732011-06-23 16:49:20 -07005796 tabla_codec_calibrate_hs_polling(codec);
5797
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005798 /* don't flip override */
5799 bias_value = __tabla_codec_sta_dce(codec, 1, true, true);
Simmi Pateriya71d63872012-11-08 01:06:30 +05305800 if (!tabla->mbhc_cfg.micbias_always_on)
5801 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
5802 0x40, cfilt_mode);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07005803 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
Bradley Rubincb1e2732011-06-23 16:49:20 -07005804
Bhalchandra Gajare343cbb02011-09-07 18:58:19 -07005805 return bias_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07005806}
5807
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005808static int tabla_cancel_btn_work(struct tabla_priv *tabla)
5809{
5810 int r = 0;
5811 struct wcd9xxx *core = dev_get_drvdata(tabla->codec->dev->parent);
5812
5813 if (cancel_delayed_work_sync(&tabla->mbhc_btn_dwork)) {
5814 /* if scheduled mbhc_btn_dwork is canceled from here,
5815 * we have to unlock from here instead btn_work */
5816 wcd9xxx_unlock_sleep(core);
5817 r = 1;
5818 }
5819 return r;
5820}
5821
5822/* called under codec_resource_lock acquisition */
5823void tabla_set_and_turnoff_hph_padac(struct snd_soc_codec *codec)
Joonwoo Park03324832012-03-19 19:36:16 -07005824{
5825 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005826 u8 wg_time;
5827
5828 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
5829 wg_time += 1;
Joonwoo Park03324832012-03-19 19:36:16 -07005830
5831 /* If headphone PA is on, check if userspace receives
5832 * removal event to sync-up PA's state */
5833 if (tabla_is_hph_pa_on(codec)) {
5834 pr_debug("%s PA is on, setting PA_OFF_ACK\n", __func__);
5835 set_bit(TABLA_HPHL_PA_OFF_ACK, &tabla->hph_pa_dac_state);
5836 set_bit(TABLA_HPHR_PA_OFF_ACK, &tabla->hph_pa_dac_state);
5837 } else {
5838 pr_debug("%s PA is off\n", __func__);
5839 }
5840
5841 if (tabla_is_hph_dac_on(codec, 1))
5842 set_bit(TABLA_HPHL_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
5843 if (tabla_is_hph_dac_on(codec, 0))
5844 set_bit(TABLA_HPHR_DAC_OFF_ACK, &tabla->hph_pa_dac_state);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005845
5846 snd_soc_update_bits(codec, TABLA_A_RX_HPH_CNP_EN, 0x30, 0x00);
5847 snd_soc_update_bits(codec, TABLA_A_RX_HPH_L_DAC_CTL,
Gopikrishnaiah Anandan3b230b22012-12-07 11:36:58 -05005848 0x80, 0x00);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005849 snd_soc_update_bits(codec, TABLA_A_RX_HPH_R_DAC_CTL,
5850 0xC0, 0x00);
5851 usleep_range(wg_time * 1000, wg_time * 1000);
5852}
5853
5854static void tabla_clr_and_turnon_hph_padac(struct tabla_priv *tabla)
5855{
5856 bool pa_turned_on = false;
5857 struct snd_soc_codec *codec = tabla->codec;
5858 u8 wg_time;
5859
5860 wg_time = snd_soc_read(codec, TABLA_A_RX_HPH_CNP_WG_TIME) ;
5861 wg_time += 1;
5862
5863 if (test_and_clear_bit(TABLA_HPHR_DAC_OFF_ACK,
5864 &tabla->hph_pa_dac_state)) {
5865 pr_debug("%s: HPHR clear flag and enable DAC\n", __func__);
5866 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_R_DAC_CTL,
5867 0xC0, 0xC0);
5868 }
5869 if (test_and_clear_bit(TABLA_HPHL_DAC_OFF_ACK,
5870 &tabla->hph_pa_dac_state)) {
5871 pr_debug("%s: HPHL clear flag and enable DAC\n", __func__);
5872 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_L_DAC_CTL,
5873 0xC0, 0xC0);
5874 }
5875
5876 if (test_and_clear_bit(TABLA_HPHR_PA_OFF_ACK,
5877 &tabla->hph_pa_dac_state)) {
5878 pr_debug("%s: HPHR clear flag and enable PA\n", __func__);
5879 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x10,
5880 1 << 4);
5881 pa_turned_on = true;
5882 }
5883 if (test_and_clear_bit(TABLA_HPHL_PA_OFF_ACK,
5884 &tabla->hph_pa_dac_state)) {
5885 pr_debug("%s: HPHL clear flag and enable PA\n", __func__);
5886 snd_soc_update_bits(tabla->codec, TABLA_A_RX_HPH_CNP_EN, 0x20,
5887 1 << 5);
5888 pa_turned_on = true;
5889 }
5890
5891 if (pa_turned_on) {
5892 pr_debug("%s: PA was turned off by MBHC and not by DAPM\n",
5893 __func__);
5894 usleep_range(wg_time * 1000, wg_time * 1000);
5895 }
5896}
5897
5898/* called under codec_resource_lock acquisition */
Simmi Pateriya71d63872012-11-08 01:06:30 +05305899static void tabla_codec_enable_mbhc_micbias(struct snd_soc_codec *codec,
5900 bool enable)
5901{
5902 int r;
5903 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
5904
5905 if (!tabla->mbhc_cfg.micbias_always_on)
5906 return;
5907 if (enable) {
5908 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5909 tabla_codec_update_cfilt_usage(codec,
5910 tabla->mbhc_bias_regs.cfilt_sel, 1);
5911 r = snd_soc_dapm_force_enable_pin(&codec->dapm,
5912 "MIC BIAS2 Power External");
5913 snd_soc_dapm_sync(&codec->dapm);
5914 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5915 pr_debug("%s: Turning on MICBIAS2 r %d\n", __func__, r);
5916 } else {
5917 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
5918 r = snd_soc_dapm_disable_pin(&codec->dapm,
5919 "MIC BIAS2 Power External");
5920 snd_soc_dapm_sync(&codec->dapm);
5921 tabla_codec_update_cfilt_usage(codec,
5922 tabla->mbhc_bias_regs.cfilt_sel, 0);
5923 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
5924 pr_debug("%s: Turning off MICBIAS2 r %d\n", __func__, r);
5925 }
5926}
5927
5928/* called under codec_resource_lock acquisition */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005929static void tabla_codec_report_plug(struct snd_soc_codec *codec, int insertion,
5930 enum snd_jack_types jack_type)
5931{
5932 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07005933 pr_debug("%s: enter insertion %d hph_status %x\n",
5934 __func__, insertion, tabla->hph_status);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005935 if (!insertion) {
5936 /* Report removal */
5937 tabla->hph_status &= ~jack_type;
5938 if (tabla->mbhc_cfg.headset_jack) {
5939 /* cancel possibly scheduled btn work and
5940 * report release if we reported button press */
5941 if (tabla_cancel_btn_work(tabla)) {
5942 pr_debug("%s: button press is canceled\n",
5943 __func__);
5944 } else if (tabla->buttons_pressed) {
5945 pr_debug("%s: Reporting release for reported "
5946 "button press %d\n", __func__,
5947 jack_type);
5948 tabla_snd_soc_jack_report(tabla,
5949 tabla->mbhc_cfg.button_jack, 0,
5950 tabla->buttons_pressed);
5951 tabla->buttons_pressed &=
5952 ~TABLA_JACK_BUTTON_MASK;
5953 }
Simmi Pateriya71d63872012-11-08 01:06:30 +05305954 if (jack_type == SND_JACK_HEADSET)
5955 tabla_codec_enable_mbhc_micbias(codec, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005956 pr_debug("%s: Reporting removal %d(%x)\n", __func__,
5957 jack_type, tabla->hph_status);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005958 tabla_snd_soc_jack_report(tabla,
5959 tabla->mbhc_cfg.headset_jack,
5960 tabla->hph_status,
5961 TABLA_JACK_MASK);
5962 }
5963 tabla_set_and_turnoff_hph_padac(codec);
5964 hphocp_off_report(tabla, SND_JACK_OC_HPHR,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005965 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005966 hphocp_off_report(tabla, SND_JACK_OC_HPHL,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07005967 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005968 tabla->current_plug = PLUG_TYPE_NONE;
5969 tabla->mbhc_polling_active = false;
5970 } else {
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07005971 if (tabla->mbhc_cfg.detect_extn_cable) {
5972 /* Report removal of current jack type */
5973 if (tabla->hph_status != jack_type &&
5974 tabla->mbhc_cfg.headset_jack) {
5975 pr_debug("%s: Reporting removal (%x)\n",
5976 __func__, tabla->hph_status);
5977 tabla_snd_soc_jack_report(tabla,
5978 tabla->mbhc_cfg.headset_jack,
5979 0, TABLA_JACK_MASK);
5980 tabla->hph_status = 0;
5981 }
5982 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005983 /* Report insertion */
5984 tabla->hph_status |= jack_type;
5985
5986 if (jack_type == SND_JACK_HEADPHONE)
5987 tabla->current_plug = PLUG_TYPE_HEADPHONE;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005988 else if (jack_type == SND_JACK_UNSUPPORTED)
5989 tabla->current_plug = PLUG_TYPE_GND_MIC_SWAP;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005990 else if (jack_type == SND_JACK_HEADSET) {
5991 tabla->mbhc_polling_active = true;
5992 tabla->current_plug = PLUG_TYPE_HEADSET;
Simmi Pateriya71d63872012-11-08 01:06:30 +05305993 tabla_codec_enable_mbhc_micbias(codec, true);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07005994 } else if (jack_type == SND_JACK_LINEOUT)
5995 tabla->current_plug = PLUG_TYPE_HIGH_HPH;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005996 if (tabla->mbhc_cfg.headset_jack) {
Joonwoo Park2cc13f02012-05-09 12:44:25 -07005997 pr_debug("%s: Reporting insertion %d(%x)\n", __func__,
5998 jack_type, tabla->hph_status);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07005999 tabla_snd_soc_jack_report(tabla,
6000 tabla->mbhc_cfg.headset_jack,
6001 tabla->hph_status,
6002 TABLA_JACK_MASK);
6003 }
6004 tabla_clr_and_turnon_hph_padac(tabla);
6005 }
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07006006 pr_debug("%s: leave hph_status %x\n", __func__, tabla->hph_status);
Joonwoo Park03324832012-03-19 19:36:16 -07006007}
6008
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006009static int tabla_codec_enable_hs_detect(struct snd_soc_codec *codec,
Joonwoo Park03324832012-03-19 19:36:16 -07006010 int insertion, int trigger,
6011 bool padac_off)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006012{
6013 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006014 int central_bias_enabled = 0;
Joonwoo Park0976d012011-12-22 11:48:18 -08006015 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006016 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08006017 const struct tabla_mbhc_plug_detect_cfg *plug_det =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006018 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006019
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07006020 pr_debug("%s: enter insertion(%d) trigger(0x%x)\n",
6021 __func__, insertion, trigger);
6022
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006023 if (!tabla->mbhc_cfg.calibration) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006024 pr_err("Error, no tabla calibration\n");
6025 return -EINVAL;
6026 }
6027
6028 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0);
6029
Joonwoo Park03324832012-03-19 19:36:16 -07006030 /* Make sure mic bias and Mic line schmitt trigger
6031 * are turned OFF
6032 */
6033 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x01);
6034 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
6035
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006036 if (insertion) {
Bhalchandra Gajareafc86432012-08-23 13:44:07 -07006037 pr_debug("%s: setup for insertion\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07006038 tabla_codec_switch_micbias(codec, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006039
Joonwoo Park03324832012-03-19 19:36:16 -07006040 /* DAPM can manipulate PA/DAC bits concurrently */
6041 if (padac_off == true) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006042 tabla_set_and_turnoff_hph_padac(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07006043 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006044
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006045 if (trigger & MBHC_USE_HPHL_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07006046 /* Enable HPH Schmitt Trigger */
6047 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x11,
6048 0x11);
6049 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x0C,
6050 plug_det->hph_current << 2);
6051 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x02,
6052 0x02);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006053 }
6054 if (trigger & MBHC_USE_MB_TRIGGER) {
Joonwoo Park03324832012-03-19 19:36:16 -07006055 /* enable the mic line schmitt trigger */
6056 snd_soc_update_bits(codec,
6057 tabla->mbhc_bias_regs.mbhc_reg,
6058 0x60, plug_det->mic_current << 5);
6059 snd_soc_update_bits(codec,
6060 tabla->mbhc_bias_regs.mbhc_reg,
6061 0x80, 0x80);
6062 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
6063 snd_soc_update_bits(codec,
6064 tabla->mbhc_bias_regs.ctl_reg, 0x01,
6065 0x00);
6066 snd_soc_update_bits(codec,
6067 tabla->mbhc_bias_regs.mbhc_reg,
6068 0x10, 0x10);
6069 }
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006070
6071 /* setup for insetion detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006072 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006073 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07006074 pr_debug("setup for removal detection\n");
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006075 /* Make sure the HPH schmitt trigger is OFF */
6076 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x12, 0x00);
6077
6078 /* enable the mic line schmitt trigger */
Joonwoo Park03324832012-03-19 19:36:16 -07006079 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
6080 0x01, 0x00);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006081 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x60,
Joonwoo Park0976d012011-12-22 11:48:18 -08006082 plug_det->mic_current << 5);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006083 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
6084 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08006085 usleep_range(plug_det->t_mic_pid, plug_det->t_mic_pid);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006086 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
6087 0x10, 0x10);
6088
6089 /* Setup for low power removal detection */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006090 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x2, 0x2);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07006091 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006092
6093 if (snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x4) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006094 /* called called by interrupt */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006095 if (!(tabla->clock_active)) {
6096 tabla_codec_enable_config_mode(codec, 1);
6097 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07006098 0x06, 0);
Joonwoo Park0976d012011-12-22 11:48:18 -08006099 usleep_range(generic->t_shutdown_plug_rem,
6100 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006101 tabla_codec_enable_config_mode(codec, 0);
6102 } else
6103 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL,
Bradley Rubincb1e2732011-06-23 16:49:20 -07006104 0x06, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006105 }
6106
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07006107 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.int_rbias, 0x80, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006108
6109 /* If central bandgap disabled */
6110 if (!(snd_soc_read(codec, TABLA_A_PIN_CTL_OE1) & 1)) {
6111 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x3, 0x3);
Joonwoo Park0976d012011-12-22 11:48:18 -08006112 usleep_range(generic->t_bg_fast_settle,
6113 generic->t_bg_fast_settle);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006114 central_bias_enabled = 1;
6115 }
6116
6117 /* If LDO_H disabled */
6118 if (snd_soc_read(codec, TABLA_A_PIN_CTL_OE0) & 0x80) {
6119 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x10, 0);
6120 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0x80);
Joonwoo Park0976d012011-12-22 11:48:18 -08006121 usleep_range(generic->t_ldoh, generic->t_ldoh);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006122 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE0, 0x80, 0);
6123
6124 if (central_bias_enabled)
6125 snd_soc_update_bits(codec, TABLA_A_PIN_CTL_OE1, 0x1, 0);
6126 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006127
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006128 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x3,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006129 tabla->mbhc_cfg.micbias);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006130
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006131 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006132 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x1, 0x1);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07006133 pr_debug("%s: leave\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006134 return 0;
6135}
6136
Joonwoo Park0976d012011-12-22 11:48:18 -08006137static u16 tabla_codec_v_sta_dce(struct snd_soc_codec *codec, bool dce,
6138 s16 vin_mv)
6139{
Joonwoo Park0976d012011-12-22 11:48:18 -08006140 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07006141 s16 diff, zero;
Joonwoo Park0976d012011-12-22 11:48:18 -08006142 u32 mb_mv, in;
Joonwoo Park03324832012-03-19 19:36:16 -07006143 u16 value;
Joonwoo Park0976d012011-12-22 11:48:18 -08006144
6145 tabla = snd_soc_codec_get_drvdata(codec);
6146 mb_mv = tabla->mbhc_data.micb_mv;
6147
6148 if (mb_mv == 0) {
6149 pr_err("%s: Mic Bias voltage is set to zero\n", __func__);
6150 return -EINVAL;
6151 }
6152
6153 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07006154 diff = (tabla->mbhc_data.dce_mb) - (tabla->mbhc_data.dce_z);
6155 zero = (tabla->mbhc_data.dce_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08006156 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07006157 diff = (tabla->mbhc_data.sta_mb) - (tabla->mbhc_data.sta_z);
6158 zero = (tabla->mbhc_data.sta_z);
Joonwoo Park0976d012011-12-22 11:48:18 -08006159 }
6160 in = (u32) diff * vin_mv;
6161
Joonwoo Park03324832012-03-19 19:36:16 -07006162 value = (u16) (in / mb_mv) + zero;
6163 return value;
Joonwoo Park0976d012011-12-22 11:48:18 -08006164}
6165
6166static s32 tabla_codec_sta_dce_v(struct snd_soc_codec *codec, s8 dce,
6167 u16 bias_value)
6168{
6169 struct tabla_priv *tabla;
Joonwoo Park03324832012-03-19 19:36:16 -07006170 s16 value, z, mb;
Joonwoo Park0976d012011-12-22 11:48:18 -08006171 s32 mv;
6172
6173 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park03324832012-03-19 19:36:16 -07006174 value = bias_value;
Joonwoo Park0976d012011-12-22 11:48:18 -08006175 if (dce) {
Joonwoo Park03324832012-03-19 19:36:16 -07006176 z = (tabla->mbhc_data.dce_z);
6177 mb = (tabla->mbhc_data.dce_mb);
6178 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08006179 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07006180 z = (tabla->mbhc_data.sta_z);
6181 mb = (tabla->mbhc_data.sta_mb);
6182 mv = (value - z) * (s32)tabla->mbhc_data.micb_mv / (mb - z);
Joonwoo Park0976d012011-12-22 11:48:18 -08006183 }
6184
6185 return mv;
6186}
6187
Joonwoo Park03324832012-03-19 19:36:16 -07006188static void btn_lpress_fn(struct work_struct *work)
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006189{
6190 struct delayed_work *delayed_work;
6191 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08006192 short bias_value;
6193 int dce_mv, sta_mv;
Joonwoo Park03324832012-03-19 19:36:16 -07006194 struct wcd9xxx *core;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006195
6196 pr_debug("%s:\n", __func__);
6197
6198 delayed_work = to_delayed_work(work);
Joonwoo Park03324832012-03-19 19:36:16 -07006199 tabla = container_of(delayed_work, struct tabla_priv, mbhc_btn_dwork);
Joonwoo Park816b8e62012-01-23 16:03:21 -08006200 core = dev_get_drvdata(tabla->codec->dev->parent);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006201
6202 if (tabla) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006203 if (tabla->mbhc_cfg.button_jack) {
Joonwoo Park0976d012011-12-22 11:48:18 -08006204 bias_value = tabla_codec_read_sta_result(tabla->codec);
6205 sta_mv = tabla_codec_sta_dce_v(tabla->codec, 0,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306206 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08006207 bias_value = tabla_codec_read_dce_result(tabla->codec);
6208 dce_mv = tabla_codec_sta_dce_v(tabla->codec, 1,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306209 bias_value);
Joonwoo Park0976d012011-12-22 11:48:18 -08006210 pr_debug("%s: Reporting long button press event"
6211 " STA: %d, DCE: %d\n", __func__,
6212 sta_mv, dce_mv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006213 tabla_snd_soc_jack_report(tabla,
6214 tabla->mbhc_cfg.button_jack,
Joonwoo Park03324832012-03-19 19:36:16 -07006215 tabla->buttons_pressed,
6216 tabla->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006217 }
6218 } else {
6219 pr_err("%s: Bad tabla private data\n", __func__);
6220 }
6221
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006222 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07006223 wcd9xxx_unlock_sleep(core);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006224}
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07006225
Joonwoo Parke067b232012-06-14 13:11:30 -07006226static u16 tabla_get_cfilt_reg(struct snd_soc_codec *codec, u8 cfilt)
6227{
6228 u16 reg;
6229
6230 switch (cfilt) {
6231 case TABLA_CFILT1_SEL:
6232 reg = TABLA_A_MICB_CFILT_1_CTL;
6233 break;
6234 case TABLA_CFILT2_SEL:
6235 reg = TABLA_A_MICB_CFILT_2_CTL;
6236 break;
6237 case TABLA_CFILT3_SEL:
6238 reg = TABLA_A_MICB_CFILT_3_CTL;
6239 break;
6240 default:
6241 BUG();
6242 }
6243 return reg;
6244}
6245
Joonwoo Park0976d012011-12-22 11:48:18 -08006246void tabla_mbhc_cal(struct snd_soc_codec *codec)
6247{
6248 struct tabla_priv *tabla;
6249 struct tabla_mbhc_btn_detect_cfg *btn_det;
Joonwoo Parke067b232012-06-14 13:11:30 -07006250 u8 cfilt_mode, micbias2_cfilt_mode, bg_mode;
Joonwoo Park0976d012011-12-22 11:48:18 -08006251 u8 ncic, nmeas, navg;
6252 u32 mclk_rate;
6253 u32 dce_wait, sta_wait;
6254 u8 *n_cic;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006255 void *calibration;
Joonwoo Parke067b232012-06-14 13:11:30 -07006256 u16 bias2_ctl;
Joonwoo Park0976d012011-12-22 11:48:18 -08006257
6258 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006259 calibration = tabla->mbhc_cfg.calibration;
6260
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006261 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006262 tabla_turn_onoff_rel_detection(codec, false);
Joonwoo Park0976d012011-12-22 11:48:18 -08006263
6264 /* First compute the DCE / STA wait times
6265 * depending on tunable parameters.
6266 * The value is computed in microseconds
6267 */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006268 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08006269 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
Joonwoo Park107edf02012-01-11 11:42:24 -08006270 ncic = n_cic[tabla_codec_mclk_index(tabla)];
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006271 nmeas = TABLA_MBHC_CAL_BTN_DET_PTR(calibration)->n_meas;
6272 navg = TABLA_MBHC_CAL_GENERAL_PTR(calibration)->mbhc_navg;
6273 mclk_rate = tabla->mbhc_cfg.mclk_rate;
Joonwoo Park433149a2012-01-11 09:53:54 -08006274 dce_wait = (1000 * 512 * ncic * (nmeas + 1)) / (mclk_rate / 1000);
6275 sta_wait = (1000 * 128 * (navg + 1)) / (mclk_rate / 1000);
Joonwoo Park0976d012011-12-22 11:48:18 -08006276
6277 tabla->mbhc_data.t_dce = dce_wait;
6278 tabla->mbhc_data.t_sta = sta_wait;
6279
6280 /* LDOH and CFILT are already configured during pdata handling.
6281 * Only need to make sure CFILT and bandgap are in Fast mode.
6282 * Need to restore defaults once calculation is done.
6283 */
6284 cfilt_mode = snd_soc_read(codec, tabla->mbhc_bias_regs.cfilt_ctl);
Joonwoo Parke067b232012-06-14 13:11:30 -07006285 micbias2_cfilt_mode =
6286 snd_soc_read(codec, tabla_get_cfilt_reg(codec,
6287 tabla->pdata->micbias.bias2_cfilt_sel));
6288 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
6289 TABLA_CFILT_FAST_MODE);
6290 snd_soc_update_bits(codec,
6291 tabla_get_cfilt_reg(codec,
6292 tabla->pdata->micbias.bias2_cfilt_sel),
6293 0x40, TABLA_CFILT_FAST_MODE);
6294
Joonwoo Park0976d012011-12-22 11:48:18 -08006295 bg_mode = snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02,
6296 0x02);
6297
6298 /* Micbias, CFILT, LDOH, MBHC MUX mode settings
6299 * to perform ADC calibration
6300 */
6301 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x60,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006302 tabla->mbhc_cfg.micbias << 5);
Joonwoo Park0976d012011-12-22 11:48:18 -08006303 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
6304 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x60, 0x60);
6305 snd_soc_write(codec, TABLA_A_TX_7_MBHC_TEST_CTL, 0x78);
6306 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x04);
6307
Joonwoo Parke067b232012-06-14 13:11:30 -07006308 /* MICBIAS2 routing for calibration */
6309 bias2_ctl = snd_soc_read(codec, TABLA_A_MICB_2_CTL);
6310 snd_soc_update_bits(codec, TABLA_A_MICB_1_MBHC, 0x03, TABLA_MICBIAS2);
6311 snd_soc_write(codec, TABLA_A_MICB_2_CTL,
6312 snd_soc_read(codec, tabla->mbhc_bias_regs.ctl_reg));
6313
Joonwoo Park0976d012011-12-22 11:48:18 -08006314 /* DCE measurement for 0 volts */
6315 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
6316 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
6317 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08006318 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
6319 usleep_range(100, 100);
6320 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
6321 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
6322 tabla->mbhc_data.dce_z = tabla_codec_read_dce_result(codec);
6323
6324 /* DCE measurment for MB voltage */
6325 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
6326 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
6327 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
6328 usleep_range(100, 100);
6329 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x04);
6330 usleep_range(tabla->mbhc_data.t_dce, tabla->mbhc_data.t_dce);
6331 tabla->mbhc_data.dce_mb = tabla_codec_read_dce_result(codec);
6332
6333 /* Sta measuremnt for 0 volts */
6334 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x0A);
6335 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
6336 snd_soc_write(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x02);
Joonwoo Park0976d012011-12-22 11:48:18 -08006337 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x81);
6338 usleep_range(100, 100);
6339 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
6340 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
6341 tabla->mbhc_data.sta_z = tabla_codec_read_sta_result(codec);
6342
6343 /* STA Measurement for MB Voltage */
6344 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x82);
6345 usleep_range(100, 100);
6346 snd_soc_write(codec, TABLA_A_CDC_MBHC_EN_CTL, 0x02);
6347 usleep_range(tabla->mbhc_data.t_sta, tabla->mbhc_data.t_sta);
6348 tabla->mbhc_data.sta_mb = tabla_codec_read_sta_result(codec);
6349
6350 /* Restore default settings. */
Joonwoo Parke067b232012-06-14 13:11:30 -07006351 snd_soc_write(codec, TABLA_A_MICB_2_CTL, bias2_ctl);
6352 snd_soc_update_bits(codec, TABLA_A_MICB_1_MBHC, 0x03,
6353 tabla->mbhc_cfg.micbias);
6354
Joonwoo Park0976d012011-12-22 11:48:18 -08006355 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x04, 0x00);
Joonwoo Parke067b232012-06-14 13:11:30 -07006356 snd_soc_update_bits(codec,
6357 tabla_get_cfilt_reg(codec,
6358 tabla->pdata->micbias.bias2_cfilt_sel), 0x40,
6359 micbias2_cfilt_mode);
Joonwoo Park0976d012011-12-22 11:48:18 -08006360 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl, 0x40,
6361 cfilt_mode);
6362 snd_soc_update_bits(codec, TABLA_A_BIAS_CENTRAL_BG_CTL, 0x02, bg_mode);
6363
6364 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
6365 usleep_range(100, 100);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006366
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006367 wcd9xxx_enable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006368 tabla_turn_onoff_rel_detection(codec, true);
Joonwoo Park0976d012011-12-22 11:48:18 -08006369}
6370
6371void *tabla_mbhc_cal_btn_det_mp(const struct tabla_mbhc_btn_detect_cfg* btn_det,
6372 const enum tabla_mbhc_btn_det_mem mem)
6373{
6374 void *ret = &btn_det->_v_btn_low;
6375
6376 switch (mem) {
6377 case TABLA_BTN_DET_GAIN:
6378 ret += sizeof(btn_det->_n_cic);
6379 case TABLA_BTN_DET_N_CIC:
6380 ret += sizeof(btn_det->_n_ready);
Joonwoo Parkc0672392012-01-11 11:03:14 -08006381 case TABLA_BTN_DET_N_READY:
Joonwoo Park0976d012011-12-22 11:48:18 -08006382 ret += sizeof(btn_det->_v_btn_high[0]) * btn_det->num_btn;
6383 case TABLA_BTN_DET_V_BTN_HIGH:
6384 ret += sizeof(btn_det->_v_btn_low[0]) * btn_det->num_btn;
6385 case TABLA_BTN_DET_V_BTN_LOW:
6386 /* do nothing */
6387 break;
6388 default:
6389 ret = NULL;
6390 }
6391
6392 return ret;
6393}
6394
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006395static s16 tabla_scale_v_micb_vddio(struct tabla_priv *tabla, int v,
6396 bool tovddio)
6397{
6398 int r;
6399 int vddio_k, mb_k;
6400 vddio_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
6401 VDDIO_MICBIAS_MV);
6402 mb_k = tabla_find_k_value(tabla->pdata->micbias.ldoh_v,
6403 tabla->mbhc_data.micb_mv);
6404 if (tovddio)
6405 r = v * vddio_k / mb_k;
6406 else
6407 r = v * mb_k / vddio_k;
6408 return r;
6409}
6410
Joonwoo Parkdd9d2962012-07-23 19:24:20 -07006411static void tabla_mbhc_calc_rel_thres(struct snd_soc_codec *codec, s16 mv)
6412{
6413 s16 deltamv;
6414 struct tabla_priv *tabla;
6415 struct tabla_mbhc_btn_detect_cfg *btn_det;
6416
6417 tabla = snd_soc_codec_get_drvdata(codec);
6418 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
6419
6420 tabla->mbhc_data.v_b1_h =
6421 tabla_codec_v_sta_dce(codec, DCE,
6422 mv + btn_det->v_btn_press_delta_cic);
6423
6424 tabla->mbhc_data.v_brh = tabla->mbhc_data.v_b1_h;
6425
6426 tabla->mbhc_data.v_brl = TABLA_MBHC_BUTTON_MIN;
6427
6428 deltamv = mv + btn_det->v_btn_press_delta_sta;
6429 tabla->mbhc_data.v_b1_hu = tabla_codec_v_sta_dce(codec, STA, deltamv);
6430
6431 deltamv = mv + btn_det->v_btn_press_delta_cic;
6432 tabla->mbhc_data.v_b1_huc = tabla_codec_v_sta_dce(codec, DCE, deltamv);
6433}
6434
6435static void tabla_mbhc_set_rel_thres(struct snd_soc_codec *codec, s16 mv)
6436{
6437 tabla_mbhc_calc_rel_thres(codec, mv);
6438 tabla_codec_calibrate_rel(codec);
6439}
6440
6441static s16 tabla_mbhc_highest_btn_mv(struct snd_soc_codec *codec)
6442{
6443 struct tabla_priv *tabla;
6444 struct tabla_mbhc_btn_detect_cfg *btn_det;
6445 u16 *btn_high;
6446
6447 tabla = snd_soc_codec_get_drvdata(codec);
6448 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
6449 btn_high = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_HIGH);
6450
6451 return btn_high[btn_det->num_btn - 1];
6452}
6453
Joonwoo Park0976d012011-12-22 11:48:18 -08006454static void tabla_mbhc_calc_thres(struct snd_soc_codec *codec)
6455{
6456 struct tabla_priv *tabla;
Joonwoo Park0976d012011-12-22 11:48:18 -08006457 struct tabla_mbhc_btn_detect_cfg *btn_det;
6458 struct tabla_mbhc_plug_type_cfg *plug_type;
Joonwoo Parkc0672392012-01-11 11:03:14 -08006459 u8 *n_ready;
Joonwoo Park0976d012011-12-22 11:48:18 -08006460
6461 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006462 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
6463 plug_type = TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08006464
Joonwoo Parkc0672392012-01-11 11:03:14 -08006465 n_ready = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_READY);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006466 if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_12288KHZ) {
Joonwoo Park03324832012-03-19 19:36:16 -07006467 tabla->mbhc_data.npoll = 4;
Joonwoo Park0976d012011-12-22 11:48:18 -08006468 tabla->mbhc_data.nbounce_wait = 30;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006469 } else if (tabla->mbhc_cfg.mclk_rate == TABLA_MCLK_RATE_9600KHZ) {
Joonwoo Park0976d012011-12-22 11:48:18 -08006470 tabla->mbhc_data.npoll = 7;
6471 tabla->mbhc_data.nbounce_wait = 23;
Joonwoo Parkc0672392012-01-11 11:03:14 -08006472 }
Joonwoo Park0976d012011-12-22 11:48:18 -08006473
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006474 tabla->mbhc_data.t_sta_dce = ((1000 * 256) /
6475 (tabla->mbhc_cfg.mclk_rate / 1000) *
Joonwoo Parkc0672392012-01-11 11:03:14 -08006476 n_ready[tabla_codec_mclk_index(tabla)]) +
6477 10;
Joonwoo Park0976d012011-12-22 11:48:18 -08006478 tabla->mbhc_data.v_ins_hu =
6479 tabla_codec_v_sta_dce(codec, STA, plug_type->v_hs_max);
6480 tabla->mbhc_data.v_ins_h =
6481 tabla_codec_v_sta_dce(codec, DCE, plug_type->v_hs_max);
6482
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006483 tabla->mbhc_data.v_inval_ins_low = TABLA_MBHC_FAKE_INSERT_LOW;
6484 if (tabla->mbhc_cfg.gpio)
6485 tabla->mbhc_data.v_inval_ins_high =
6486 TABLA_MBHC_FAKE_INSERT_HIGH;
6487 else
6488 tabla->mbhc_data.v_inval_ins_high =
6489 TABLA_MBHC_FAKE_INS_HIGH_NO_GPIO;
6490
6491 if (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV) {
6492 tabla->mbhc_data.adj_v_hs_max =
6493 tabla_scale_v_micb_vddio(tabla, plug_type->v_hs_max, true);
6494 tabla->mbhc_data.adj_v_ins_hu =
6495 tabla_codec_v_sta_dce(codec, STA,
6496 tabla->mbhc_data.adj_v_hs_max);
6497 tabla->mbhc_data.adj_v_ins_h =
6498 tabla_codec_v_sta_dce(codec, DCE,
6499 tabla->mbhc_data.adj_v_hs_max);
6500 tabla->mbhc_data.v_inval_ins_low =
6501 tabla_scale_v_micb_vddio(tabla,
6502 tabla->mbhc_data.v_inval_ins_low,
6503 false);
6504 tabla->mbhc_data.v_inval_ins_high =
6505 tabla_scale_v_micb_vddio(tabla,
6506 tabla->mbhc_data.v_inval_ins_high,
6507 false);
6508 }
6509
Joonwoo Parkdd9d2962012-07-23 19:24:20 -07006510 tabla_mbhc_calc_rel_thres(codec, tabla_mbhc_highest_btn_mv(codec));
Joonwoo Park0976d012011-12-22 11:48:18 -08006511
6512 tabla->mbhc_data.v_no_mic =
6513 tabla_codec_v_sta_dce(codec, STA, plug_type->v_no_mic);
6514}
6515
6516void tabla_mbhc_init(struct snd_soc_codec *codec)
6517{
6518 struct tabla_priv *tabla;
6519 struct tabla_mbhc_general_cfg *generic;
6520 struct tabla_mbhc_btn_detect_cfg *btn_det;
6521 int n;
Joonwoo Park0976d012011-12-22 11:48:18 -08006522 u8 *n_cic, *gain;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306523 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Joonwoo Park0976d012011-12-22 11:48:18 -08006524
6525 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006526 generic = TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
6527 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(tabla->mbhc_cfg.calibration);
Joonwoo Park0976d012011-12-22 11:48:18 -08006528
Joonwoo Park0976d012011-12-22 11:48:18 -08006529 for (n = 0; n < 8; n++) {
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08006530 if ((!TABLA_IS_1_X(tabla_core->version)) || n != 7) {
Joonwoo Park0976d012011-12-22 11:48:18 -08006531 snd_soc_update_bits(codec,
6532 TABLA_A_CDC_MBHC_FEATURE_B1_CFG,
6533 0x07, n);
6534 snd_soc_write(codec, TABLA_A_CDC_MBHC_FEATURE_B2_CFG,
6535 btn_det->c[n]);
6536 }
6537 }
6538 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x07,
6539 btn_det->nc);
6540
6541 n_cic = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_N_CIC);
6542 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B6_CTL, 0xFF,
Joonwoo Park107edf02012-01-11 11:42:24 -08006543 n_cic[tabla_codec_mclk_index(tabla)]);
Joonwoo Park0976d012011-12-22 11:48:18 -08006544
6545 gain = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_GAIN);
Joonwoo Park107edf02012-01-11 11:42:24 -08006546 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B2_CTL, 0x78,
6547 gain[tabla_codec_mclk_index(tabla)] << 3);
Joonwoo Park0976d012011-12-22 11:48:18 -08006548
6549 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x70,
6550 generic->mbhc_nsa << 4);
6551
6552 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_TIMER_B4_CTL, 0x0F,
6553 btn_det->n_meas);
6554
6555 snd_soc_write(codec, TABLA_A_CDC_MBHC_TIMER_B5_CTL, generic->mbhc_navg);
6556
6557 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x80, 0x80);
6558
6559 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x78,
6560 btn_det->mbhc_nsc << 3);
6561
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08006562 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_mbhc, 0x03,
6563 TABLA_MICBIAS2);
Joonwoo Park0976d012011-12-22 11:48:18 -08006564
6565 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Park03324832012-03-19 19:36:16 -07006566
6567 snd_soc_update_bits(codec, TABLA_A_MBHC_SCALING_MUX_2, 0xF0, 0xF0);
Joonwoo Parke067b232012-06-14 13:11:30 -07006568
6569 /* override mbhc's micbias */
6570 snd_soc_update_bits(codec, TABLA_A_MICB_1_MBHC, 0x03,
6571 tabla->mbhc_cfg.micbias);
Joonwoo Park0976d012011-12-22 11:48:18 -08006572}
6573
Patrick Lai64b43262011-12-06 17:29:15 -08006574static bool tabla_mbhc_fw_validate(const struct firmware *fw)
6575{
6576 u32 cfg_offset;
6577 struct tabla_mbhc_imped_detect_cfg *imped_cfg;
6578 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
6579
6580 if (fw->size < TABLA_MBHC_CAL_MIN_SIZE)
6581 return false;
6582
6583 /* previous check guarantees that there is enough fw data up
6584 * to num_btn
6585 */
6586 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(fw->data);
6587 cfg_offset = (u32) ((void *) btn_cfg - (void *) fw->data);
6588 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_BTN_SZ(btn_cfg)))
6589 return false;
6590
6591 /* previous check guarantees that there is enough fw data up
6592 * to start of impedance detection configuration
6593 */
6594 imped_cfg = TABLA_MBHC_CAL_IMPED_DET_PTR(fw->data);
6595 cfg_offset = (u32) ((void *) imped_cfg - (void *) fw->data);
6596
6597 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_MIN_SZ))
6598 return false;
6599
6600 if (fw->size < (cfg_offset + TABLA_MBHC_CAL_IMPED_SZ(imped_cfg)))
6601 return false;
6602
6603 return true;
6604}
Joonwoo Park03324832012-03-19 19:36:16 -07006605
Joonwoo Parkfee17432012-04-16 16:33:55 -07006606/* called under codec_resource_lock acquisition */
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006607static int tabla_determine_button(const struct tabla_priv *priv,
Joonwoo Parkfee17432012-04-16 16:33:55 -07006608 const s32 micmv)
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006609{
6610 s16 *v_btn_low, *v_btn_high;
6611 struct tabla_mbhc_btn_detect_cfg *btn_det;
6612 int i, btn = -1;
6613
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006614 btn_det = TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006615 v_btn_low = tabla_mbhc_cal_btn_det_mp(btn_det, TABLA_BTN_DET_V_BTN_LOW);
6616 v_btn_high = tabla_mbhc_cal_btn_det_mp(btn_det,
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306617 TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Parkfee17432012-04-16 16:33:55 -07006618
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006619 for (i = 0; i < btn_det->num_btn; i++) {
Joonwoo Parkfee17432012-04-16 16:33:55 -07006620 if ((v_btn_low[i] <= micmv) && (v_btn_high[i] >= micmv)) {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006621 btn = i;
6622 break;
6623 }
6624 }
6625
6626 if (btn == -1)
6627 pr_debug("%s: couldn't find button number for mic mv %d\n",
Joonwoo Parkfee17432012-04-16 16:33:55 -07006628 __func__, micmv);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006629
6630 return btn;
6631}
6632
6633static int tabla_get_button_mask(const int btn)
6634{
6635 int mask = 0;
6636 switch (btn) {
6637 case 0:
6638 mask = SND_JACK_BTN_0;
6639 break;
6640 case 1:
6641 mask = SND_JACK_BTN_1;
6642 break;
6643 case 2:
6644 mask = SND_JACK_BTN_2;
6645 break;
6646 case 3:
6647 mask = SND_JACK_BTN_3;
6648 break;
6649 case 4:
6650 mask = SND_JACK_BTN_4;
6651 break;
6652 case 5:
6653 mask = SND_JACK_BTN_5;
6654 break;
6655 case 6:
6656 mask = SND_JACK_BTN_6;
6657 break;
6658 case 7:
6659 mask = SND_JACK_BTN_7;
6660 break;
6661 }
6662 return mask;
6663}
6664
Bradley Rubincb1e2732011-06-23 16:49:20 -07006665static irqreturn_t tabla_dce_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006666{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006667 int i, mask;
Joonwoo Parkfee17432012-04-16 16:33:55 -07006668 short dce, sta;
Joonwoo Park12334832012-07-23 19:27:52 -07006669 s32 mv, mv_s, stamv, stamv_s;
Joonwoo Parkfee17432012-04-16 16:33:55 -07006670 bool vddio;
Joonwoo Parkdd9d2962012-07-23 19:24:20 -07006671 u16 *btn_high;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006672 int btn = -1, meas = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006673 struct tabla_priv *priv = data;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006674 const struct tabla_mbhc_btn_detect_cfg *d =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006675 TABLA_MBHC_CAL_BTN_DET_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006676 short btnmeas[d->n_btn_meas + 1];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006677 struct snd_soc_codec *codec = priv->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306678 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park03324832012-03-19 19:36:16 -07006679 int n_btn_meas = d->n_btn_meas;
6680 u8 mbhc_status = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_STATUS) & 0x3E;
Bradley Rubincb1e2732011-06-23 16:49:20 -07006681
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006682 pr_debug("%s: enter\n", __func__);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006683
Joonwoo Parkdd9d2962012-07-23 19:24:20 -07006684 btn_high = tabla_mbhc_cal_btn_det_mp(d, TABLA_BTN_DET_V_BTN_HIGH);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006685 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
6686 if (priv->mbhc_state == MBHC_STATE_POTENTIAL_RECOVERY) {
6687 pr_debug("%s: mbhc is being recovered, skip button press\n",
6688 __func__);
6689 goto done;
6690 }
6691
6692 priv->mbhc_state = MBHC_STATE_POTENTIAL;
6693
6694 if (!priv->mbhc_polling_active) {
6695 pr_warn("%s: mbhc polling is not active, skip button press\n",
6696 __func__);
6697 goto done;
6698 }
Joonwoo Park03324832012-03-19 19:36:16 -07006699
6700 dce = tabla_codec_read_dce_result(codec);
6701 mv = tabla_codec_sta_dce_v(codec, 1, dce);
6702
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006703 /* If GPIO interrupt already kicked in, ignore button press */
6704 if (priv->in_gpio_handler) {
6705 pr_debug("%s: GPIO State Changed, ignore button press\n",
6706 __func__);
6707 btn = -1;
6708 goto done;
6709 }
Simmi Pateriya71d63872012-11-08 01:06:30 +05306710 vddio = !priv->mbhc_cfg.micbias_always_on &&
6711 (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
Joonwoo Parkfee17432012-04-16 16:33:55 -07006712 priv->mbhc_micbias_switched);
6713 mv_s = vddio ? tabla_scale_v_micb_vddio(priv, mv, false) : mv;
6714
Joonwoo Park03324832012-03-19 19:36:16 -07006715 if (mbhc_status != TABLA_MBHC_STATUS_REL_DETECTION) {
6716 if (priv->mbhc_last_resume &&
6717 !time_after(jiffies, priv->mbhc_last_resume + HZ)) {
6718 pr_debug("%s: Button is already released shortly after "
6719 "resume\n", __func__);
6720 n_btn_meas = 0;
Joonwoo Park03324832012-03-19 19:36:16 -07006721 }
6722 }
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07006723
Joonwoo Park12334832012-07-23 19:27:52 -07006724 /* save hw dce */
Joonwoo Parkfee17432012-04-16 16:33:55 -07006725 btnmeas[meas++] = tabla_determine_button(priv, mv_s);
Joonwoo Park12334832012-07-23 19:27:52 -07006726 pr_debug("%s: meas HW - DCE %x,%d,%d button %d\n", __func__,
6727 dce, mv, mv_s, btnmeas[0]);
6728 if (n_btn_meas == 0) {
6729 sta = tabla_codec_read_sta_result(codec);
6730 stamv_s = stamv = tabla_codec_sta_dce_v(codec, 0, sta);
6731 if (vddio)
6732 stamv_s = tabla_scale_v_micb_vddio(priv, stamv, false);
6733 btn = tabla_determine_button(priv, stamv_s);
6734 pr_debug("%s: meas HW - STA %x,%d,%d button %d\n", __func__,
6735 sta, stamv, stamv_s, btn);
6736 BUG_ON(meas != 1);
6737 if (btnmeas[0] != btn)
6738 btn = -1;
6739 }
6740
6741 /* determine pressed button */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006742 for (; ((d->n_btn_meas) && (meas < (d->n_btn_meas + 1))); meas++) {
Joonwoo Parkfee17432012-04-16 16:33:55 -07006743 dce = tabla_codec_sta_dce(codec, 1, false);
6744 mv = tabla_codec_sta_dce_v(codec, 1, dce);
6745 mv_s = vddio ? tabla_scale_v_micb_vddio(priv, mv, false) : mv;
6746
6747 btnmeas[meas] = tabla_determine_button(priv, mv_s);
Joonwoo Park12334832012-07-23 19:27:52 -07006748 pr_debug("%s: meas %d - DCE %x,%d,%d button %d\n",
Joonwoo Parkfee17432012-04-16 16:33:55 -07006749 __func__, meas, dce, mv, mv_s, btnmeas[meas]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006750 /* if large enough measurements are collected,
6751 * start to check if last all n_btn_con measurements were
6752 * in same button low/high range */
6753 if (meas + 1 >= d->n_btn_con) {
6754 for (i = 0; i < d->n_btn_con; i++)
6755 if ((btnmeas[meas] < 0) ||
6756 (btnmeas[meas] != btnmeas[meas - i]))
6757 break;
6758 if (i == d->n_btn_con) {
6759 /* button pressed */
6760 btn = btnmeas[meas];
6761 break;
Joonwoo Park03324832012-03-19 19:36:16 -07006762 } else if ((n_btn_meas - meas) < (d->n_btn_con - 1)) {
6763 /* if left measurements are less than n_btn_con,
6764 * it's impossible to find button number */
6765 break;
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006766 }
6767 }
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006768 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006769
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006770 if (btn >= 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006771 if (priv->in_gpio_handler) {
6772 pr_debug("%s: GPIO already triggered, ignore button "
6773 "press\n", __func__);
6774 goto done;
6775 }
Joonwoo Parkdd9d2962012-07-23 19:24:20 -07006776 /* narrow down release threshold */
6777 tabla_mbhc_set_rel_thres(codec, btn_high[btn]);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006778 mask = tabla_get_button_mask(btn);
6779 priv->buttons_pressed |= mask;
Joonwoo Park03324832012-03-19 19:36:16 -07006780 wcd9xxx_lock_sleep(core);
6781 if (schedule_delayed_work(&priv->mbhc_btn_dwork,
6782 msecs_to_jiffies(400)) == 0) {
6783 WARN(1, "Button pressed twice without release"
6784 "event\n");
6785 wcd9xxx_unlock_sleep(core);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006786 }
Joonwoo Park816b8e62012-01-23 16:03:21 -08006787 } else {
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006788 pr_debug("%s: bogus button press, too short press?\n",
6789 __func__);
Joonwoo Park816b8e62012-01-23 16:03:21 -08006790 }
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006791
Joonwoo Park03324832012-03-19 19:36:16 -07006792 done:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006793 pr_debug("%s: leave\n", __func__);
6794 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006795 return IRQ_HANDLED;
6796}
6797
Joonwoo Park03324832012-03-19 19:36:16 -07006798static int tabla_is_fake_press(struct tabla_priv *priv)
6799{
6800 int i;
6801 int r = 0;
6802 struct snd_soc_codec *codec = priv->codec;
6803 const int dces = MBHC_NUM_DCE_PLUG_DETECT;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006804 s16 mb_v, v_ins_hu, v_ins_h;
6805
6806 v_ins_hu = tabla_get_current_v_ins(priv, true);
6807 v_ins_h = tabla_get_current_v_ins(priv, false);
Joonwoo Park03324832012-03-19 19:36:16 -07006808
6809 for (i = 0; i < dces; i++) {
6810 usleep_range(10000, 10000);
6811 if (i == 0) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006812 mb_v = tabla_codec_sta_dce(codec, 0, true);
Joonwoo Park03324832012-03-19 19:36:16 -07006813 pr_debug("%s: STA[0]: %d,%d\n", __func__, mb_v,
6814 tabla_codec_sta_dce_v(codec, 0, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006815 if (mb_v < (s16)priv->mbhc_data.v_b1_hu ||
6816 mb_v > v_ins_hu) {
Joonwoo Park03324832012-03-19 19:36:16 -07006817 r = 1;
6818 break;
6819 }
6820 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006821 mb_v = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park03324832012-03-19 19:36:16 -07006822 pr_debug("%s: DCE[%d]: %d,%d\n", __func__, i, mb_v,
6823 tabla_codec_sta_dce_v(codec, 1, mb_v));
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006824 if (mb_v < (s16)priv->mbhc_data.v_b1_h ||
6825 mb_v > v_ins_h) {
Joonwoo Park03324832012-03-19 19:36:16 -07006826 r = 1;
6827 break;
6828 }
6829 }
6830 }
6831
6832 return r;
6833}
6834
Bradley Rubincb1e2732011-06-23 16:49:20 -07006835static irqreturn_t tabla_release_handler(int irq, void *data)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006836{
Joonwoo Parke5d3aa92012-01-11 14:47:15 -08006837 int ret;
Joonwoo Park816b8e62012-01-23 16:03:21 -08006838 struct tabla_priv *priv = data;
6839 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006840
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006841 pr_debug("%s: enter\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07006842
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006843 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
6844 priv->mbhc_state = MBHC_STATE_RELEASE;
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006845
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006846 tabla_codec_drive_v_to_micbias(codec, 10000);
6847
Joonwoo Park03324832012-03-19 19:36:16 -07006848 if (priv->buttons_pressed & TABLA_JACK_BUTTON_MASK) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006849 ret = tabla_cancel_btn_work(priv);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006850 if (ret == 0) {
Joonwoo Park03324832012-03-19 19:36:16 -07006851 pr_debug("%s: Reporting long button release event\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006852 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006853 if (priv->mbhc_cfg.button_jack)
Joonwoo Park8b1f0982011-12-08 17:12:45 -08006854 tabla_snd_soc_jack_report(priv,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006855 priv->mbhc_cfg.button_jack, 0,
6856 priv->buttons_pressed);
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006857 } else {
Joonwoo Park03324832012-03-19 19:36:16 -07006858 if (tabla_is_fake_press(priv)) {
6859 pr_debug("%s: Fake button press interrupt\n",
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006860 __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006861 } else if (priv->mbhc_cfg.button_jack) {
6862 if (priv->in_gpio_handler) {
6863 pr_debug("%s: GPIO kicked in, ignore\n",
6864 __func__);
6865 } else {
Joonwoo Parkcf473b42012-03-29 19:48:16 -07006866 pr_debug("%s: Reporting short button "
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006867 "press and release\n",
6868 __func__);
6869 tabla_snd_soc_jack_report(priv,
6870 priv->mbhc_cfg.button_jack,
6871 priv->buttons_pressed,
6872 priv->buttons_pressed);
6873 tabla_snd_soc_jack_report(priv,
6874 priv->mbhc_cfg.button_jack, 0,
6875 priv->buttons_pressed);
6876 }
Bhalchandra Gajare0a792b12011-09-06 16:36:58 -07006877 }
6878 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006879
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08006880 priv->buttons_pressed &= ~TABLA_JACK_BUTTON_MASK;
6881 }
6882
Joonwoo Parkdd9d2962012-07-23 19:24:20 -07006883 /* revert narrowed release threshold */
6884 tabla_mbhc_calc_rel_thres(codec, tabla_mbhc_highest_btn_mv(codec));
Joonwoo Park03324832012-03-19 19:36:16 -07006885 tabla_codec_calibrate_hs_polling(codec);
6886
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006887 if (priv->mbhc_cfg.gpio)
6888 msleep(TABLA_MBHC_GPIO_REL_DEBOUNCE_TIME_MS);
Joonwoo Park03324832012-03-19 19:36:16 -07006889
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006890 tabla_codec_start_hs_polling(codec);
6891
6892 pr_debug("%s: leave\n", __func__);
6893 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006894 return IRQ_HANDLED;
6895}
6896
Bradley Rubincb1e2732011-06-23 16:49:20 -07006897static void tabla_codec_shutdown_hs_removal_detect(struct snd_soc_codec *codec)
6898{
6899 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park0976d012011-12-22 11:48:18 -08006900 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006901 TABLA_MBHC_CAL_GENERAL_PTR(tabla->mbhc_cfg.calibration);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006902
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07006903 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07006904 tabla_codec_enable_config_mode(codec, 1);
6905
6906 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0x2, 0x2);
6907 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x6, 0x0);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006908
Joonwoo Park0976d012011-12-22 11:48:18 -08006909 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x80, 0x00);
6910
6911 usleep_range(generic->t_shutdown_plug_rem,
6912 generic->t_shutdown_plug_rem);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006913
6914 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL, 0xA, 0x8);
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07006915 if (!tabla->mclk_enabled && !tabla->mbhc_polling_active)
Bradley Rubincb1e2732011-06-23 16:49:20 -07006916 tabla_codec_enable_config_mode(codec, 0);
6917
6918 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x00);
6919}
6920
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006921static void tabla_codec_cleanup_hs_polling(struct snd_soc_codec *codec)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006922{
6923 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Bradley Rubincb1e2732011-06-23 16:49:20 -07006924
6925 tabla_codec_shutdown_hs_removal_detect(codec);
6926
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07006927 if (!tabla->mclk_enabled) {
Asish Bhattacharya486745a2012-01-20 06:41:53 +05306928 tabla_codec_disable_clock_block(codec);
6929 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006930 }
6931
6932 tabla->mbhc_polling_active = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006933 tabla->mbhc_state = MBHC_STATE_NONE;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07006934}
6935
Patrick Lai49efeac2011-11-03 11:01:12 -07006936static irqreturn_t tabla_hphl_ocp_irq(int irq, void *data)
6937{
6938 struct tabla_priv *tabla = data;
6939 struct snd_soc_codec *codec;
6940
6941 pr_info("%s: received HPHL OCP irq\n", __func__);
6942
6943 if (tabla) {
6944 codec = tabla->codec;
Patrick Laic2d833d2012-07-06 22:42:52 -07006945 if ((tabla->hphlocp_cnt < TABLA_OCP_ATTEMPT) &&
6946 (!tabla->hphrocp_cnt)) {
Patrick Laic7cae882011-11-18 11:52:49 -08006947 pr_info("%s: retry\n", __func__);
Patrick Laic2d833d2012-07-06 22:42:52 -07006948 tabla->hphlocp_cnt++;
Patrick Laic7cae882011-11-18 11:52:49 -08006949 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
6950 0x00);
6951 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
6952 0x10);
6953 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306954 wcd9xxx_disable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006955 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Patrick Laic7cae882011-11-18 11:52:49 -08006956 tabla->hph_status |= SND_JACK_OC_HPHL;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006957 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08006958 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006959 tabla->mbhc_cfg.headset_jack,
6960 tabla->hph_status,
6961 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07006962 }
6963 } else {
6964 pr_err("%s: Bad tabla private data\n", __func__);
6965 }
6966
6967 return IRQ_HANDLED;
6968}
6969
6970static irqreturn_t tabla_hphr_ocp_irq(int irq, void *data)
6971{
6972 struct tabla_priv *tabla = data;
6973 struct snd_soc_codec *codec;
6974
6975 pr_info("%s: received HPHR OCP irq\n", __func__);
6976
6977 if (tabla) {
6978 codec = tabla->codec;
Patrick Laic2d833d2012-07-06 22:42:52 -07006979 if ((tabla->hphrocp_cnt < TABLA_OCP_ATTEMPT) &&
6980 (!tabla->hphlocp_cnt)) {
Patrick Laic7cae882011-11-18 11:52:49 -08006981 pr_info("%s: retry\n", __func__);
Patrick Laic2d833d2012-07-06 22:42:52 -07006982 tabla->hphrocp_cnt++;
Patrick Laic7cae882011-11-18 11:52:49 -08006983 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
6984 0x00);
6985 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10,
6986 0x10);
6987 } else {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05306988 wcd9xxx_disable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07006989 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Patrick Laic7cae882011-11-18 11:52:49 -08006990 tabla->hph_status |= SND_JACK_OC_HPHR;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006991 if (tabla->mbhc_cfg.headset_jack)
Patrick Laic7cae882011-11-18 11:52:49 -08006992 tabla_snd_soc_jack_report(tabla,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07006993 tabla->mbhc_cfg.headset_jack,
6994 tabla->hph_status,
6995 TABLA_JACK_MASK);
Patrick Lai49efeac2011-11-03 11:01:12 -07006996 }
6997 } else {
6998 pr_err("%s: Bad tabla private data\n", __func__);
6999 }
7000
7001 return IRQ_HANDLED;
7002}
7003
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007004static bool tabla_is_inval_ins_range(struct snd_soc_codec *codec,
7005 s32 mic_volt, bool highhph, bool *highv)
Joonwoo Park03324832012-03-19 19:36:16 -07007006{
7007 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007008 bool invalid = false;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007009 s16 v_hs_max;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007010
7011 /* Perform this check only when the high voltage headphone
7012 * needs to be considered as invalid
7013 */
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007014 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007015 *highv = mic_volt > v_hs_max;
7016 if (!highhph && *highv)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007017 invalid = true;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007018 else if (mic_volt < tabla->mbhc_data.v_inval_ins_high &&
7019 (mic_volt > tabla->mbhc_data.v_inval_ins_low))
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007020 invalid = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007021
7022 return invalid;
7023}
7024
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007025static bool tabla_is_inval_ins_delta(struct snd_soc_codec *codec,
7026 int mic_volt, int mic_volt_prev,
7027 int threshold)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007028{
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007029 return abs(mic_volt - mic_volt_prev) > threshold;
Joonwoo Park03324832012-03-19 19:36:16 -07007030}
7031
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007032/* called under codec_resource_lock acquisition */
7033void tabla_find_plug_and_report(struct snd_soc_codec *codec,
7034 enum tabla_mbhc_plug_type plug_type)
Joonwoo Park03324832012-03-19 19:36:16 -07007035{
7036 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007037
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007038 pr_debug("%s: enter current_plug(%d) new_plug(%d)\n",
7039 __func__, tabla->current_plug, plug_type);
7040
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007041 if (plug_type == PLUG_TYPE_HEADPHONE &&
7042 tabla->current_plug == PLUG_TYPE_NONE) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007043 /* Nothing was reported previously
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007044 * report a headphone or unsupported
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007045 */
7046 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
7047 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007048 } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007049 if (!tabla->mbhc_cfg.detect_extn_cable) {
7050 if (tabla->current_plug == PLUG_TYPE_HEADSET)
7051 tabla_codec_report_plug(codec, 0,
7052 SND_JACK_HEADSET);
7053 else if (tabla->current_plug == PLUG_TYPE_HEADPHONE)
7054 tabla_codec_report_plug(codec, 0,
7055 SND_JACK_HEADPHONE);
7056 }
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007057 tabla_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
7058 tabla_codec_cleanup_hs_polling(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007059 } else if (plug_type == PLUG_TYPE_HEADSET) {
7060 /* If Headphone was reported previously, this will
7061 * only report the mic line
7062 */
7063 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
Simmi Pateriya21375012012-11-26 23:06:01 +05307064 if (!tabla->mbhc_micbias_switched &&
7065 tabla_is_hph_pa_on(codec)) {
7066 /*If the headphone path is on, switch the micbias
7067 to VDDIO to avoid noise due to button polling */
7068 tabla_codec_switch_micbias(codec, 1);
7069 pr_debug("%s: HPH path is still up\n", __func__);
7070 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007071 msleep(100);
7072 tabla_codec_start_hs_polling(codec);
7073 } else if (plug_type == PLUG_TYPE_HIGH_HPH) {
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007074 if (tabla->mbhc_cfg.detect_extn_cable) {
7075 /* High impedance device found. Report as LINEOUT*/
7076 tabla_codec_report_plug(codec, 1, SND_JACK_LINEOUT);
7077 tabla_codec_cleanup_hs_polling(codec);
7078 pr_debug("%s: setup mic trigger for further detection\n",
7079 __func__);
7080 tabla->lpi_enabled = true;
7081 /*
7082 * Do not enable HPHL trigger. If playback is active,
7083 * it might lead to continuous false HPHL triggers
7084 */
7085 tabla_codec_enable_hs_detect(codec, 1,
7086 MBHC_USE_MB_TRIGGER,
7087 false);
7088 } else {
7089 if (tabla->current_plug == PLUG_TYPE_NONE)
7090 tabla_codec_report_plug(codec, 1,
7091 SND_JACK_HEADPHONE);
7092 tabla_codec_cleanup_hs_polling(codec);
7093 pr_debug("setup mic trigger for further detection\n");
7094 tabla->lpi_enabled = true;
7095 tabla_codec_enable_hs_detect(codec, 1,
7096 MBHC_USE_MB_TRIGGER |
7097 MBHC_USE_HPHL_TRIGGER,
7098 false);
7099 }
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007100 } else {
7101 WARN(1, "Unexpected current plug_type %d, plug_type %d\n",
7102 tabla->current_plug, plug_type);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007103 }
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007104 pr_debug("%s: leave\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007105}
7106
7107/* should be called under interrupt context that hold suspend */
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007108static void tabla_schedule_hs_detect_plug(struct tabla_priv *tabla,
7109 struct work_struct *correct_plug_work)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007110{
7111 pr_debug("%s: scheduling tabla_hs_correct_gpio_plug\n", __func__);
7112 tabla->hs_detect_work_stop = false;
7113 wcd9xxx_lock_sleep(tabla->codec->control_data);
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007114 schedule_work(correct_plug_work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007115}
7116
7117/* called under codec_resource_lock acquisition */
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007118static void tabla_cancel_hs_detect_plug(struct tabla_priv *tabla,
7119 struct work_struct *correct_plug_work)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007120{
7121 pr_debug("%s: canceling hs_correct_plug_work\n", __func__);
7122 tabla->hs_detect_work_stop = true;
7123 wmb();
7124 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007125 if (cancel_work_sync(correct_plug_work)) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007126 pr_debug("%s: hs_correct_plug_work is canceled\n", __func__);
7127 wcd9xxx_unlock_sleep(tabla->codec->control_data);
7128 }
7129 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
7130}
7131
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007132static bool tabla_hs_gpio_level_remove(struct tabla_priv *tabla)
7133{
7134 return (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) !=
7135 tabla->mbhc_cfg.gpio_level_insert);
7136}
7137
Joonwoo Park41956722012-04-18 13:13:07 -07007138/* called under codec_resource_lock acquisition */
7139static void tabla_codec_hphr_gnd_switch(struct snd_soc_codec *codec, bool on)
7140{
7141 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, on);
7142 if (on)
7143 usleep_range(5000, 5000);
7144}
7145
Simmi Pateriyad60186a2012-11-27 13:50:11 +05307146
7147static void tabla_codec_onoff_vddio_switch(struct snd_soc_codec *codec, bool on)
7148{
7149 bool override;
7150 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
7151
7152 pr_debug("%s: enter\n", __func__);
7153 if (on) {
7154 override = snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04;
7155 if (!override)
7156 tabla_turn_onoff_override(codec, true);
7157
7158 /* enable the vddio switch */
7159 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
7160 0x91, 0x81);
7161
7162 /* deroute the override from MicBias2 to MicBias4 */
7163 snd_soc_update_bits(codec, TABLA_A_MICB_1_MBHC,
7164 0x03, 0x03);
7165
7166 usleep_range(MBHC_VDDIO_SWITCH_WAIT_MS * 1000,
7167 MBHC_VDDIO_SWITCH_WAIT_MS * 1000);
7168
7169 if (!override)
7170 tabla_turn_onoff_override(codec, false);
7171 tabla->mbhc_micbias_switched = true;
7172 pr_debug("%s: VDDIO switch enabled\n", __func__);
7173
7174 } else {
7175
7176 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg,
7177 0x91, 0x00);
7178
7179 /* reroute the override to MicBias2 */
7180 snd_soc_update_bits(codec, TABLA_A_MICB_1_MBHC,
7181 0x03, 0x01);
7182
7183 tabla->mbhc_micbias_switched = false;
7184 pr_debug("%s: VDDIO switch disabled\n", __func__);
7185 }
7186}
7187
Joonwoo Park41956722012-04-18 13:13:07 -07007188/* called under codec_resource_lock acquisition and mbhc override = 1 */
7189static enum tabla_mbhc_plug_type
7190tabla_codec_get_plug_type(struct snd_soc_codec *codec, bool highhph)
7191{
7192 int i;
7193 bool gndswitch, vddioswitch;
7194 int scaled;
7195 struct tabla_mbhc_plug_type_cfg *plug_type_ptr;
7196 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Simmi Pateriya71d63872012-11-08 01:06:30 +05307197 const bool vddio = !tabla->mbhc_cfg.micbias_always_on &&
7198 (tabla->mbhc_data.micb_mv != VDDIO_MICBIAS_MV);
7199 int num_det = (MBHC_NUM_DCE_PLUG_DETECT + vddio);
Joonwoo Park41956722012-04-18 13:13:07 -07007200 enum tabla_mbhc_plug_type plug_type[num_det];
7201 s16 mb_v[num_det];
7202 s32 mic_mv[num_det];
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007203 bool inval;
Ravi Kumar Alamanda1c713b22012-09-27 17:14:27 -07007204 bool highdelta = false;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007205 bool ahighv = false, highv;
Joonwoo Park6a5a4f12012-06-15 15:56:25 -07007206 bool gndmicswapped = false;
Joonwoo Park41956722012-04-18 13:13:07 -07007207
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007208 pr_debug("%s: enter\n", __func__);
7209
Joonwoo Park41956722012-04-18 13:13:07 -07007210 /* make sure override is on */
7211 WARN_ON(!(snd_soc_read(codec, TABLA_A_CDC_MBHC_B1_CTL) & 0x04));
7212
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007213 /* GND and MIC swap detection requires at least 2 rounds of DCE */
7214 BUG_ON(num_det < 2);
7215
7216 plug_type_ptr =
7217 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
7218
7219 plug_type[0] = PLUG_TYPE_INVALID;
7220
Joonwoo Park41956722012-04-18 13:13:07 -07007221 /* performs DCEs for N times
7222 * 1st: check if voltage is in invalid range
7223 * 2nd - N-2nd: check voltage range and delta
7224 * N-1st: check voltage range, delta with HPHR GND switch
Joonwoo Park6a5a4f12012-06-15 15:56:25 -07007225 * Nth: check voltage range with VDDIO switch */
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007226 for (i = 0; i < num_det; i++) {
Joonwoo Park6a5a4f12012-06-15 15:56:25 -07007227 gndswitch = (i == (num_det - 2));
Simmi Pateriyad60186a2012-11-27 13:50:11 +05307228 vddioswitch = (i == (num_det - 1));
Joonwoo Park41956722012-04-18 13:13:07 -07007229 if (i == 0) {
7230 mb_v[i] = tabla_codec_setup_hs_polling(codec);
7231 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007232 inval = tabla_is_inval_ins_range(codec, mic_mv[i],
7233 highhph, &highv);
7234 ahighv |= highv;
Joonwoo Park41956722012-04-18 13:13:07 -07007235 scaled = mic_mv[i];
Joonwoo Park41956722012-04-18 13:13:07 -07007236 } else {
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007237 if (vddioswitch)
Simmi Pateriyad60186a2012-11-27 13:50:11 +05307238 tabla_codec_onoff_vddio_switch(codec, true);
7239
Joonwoo Park41956722012-04-18 13:13:07 -07007240 if (gndswitch)
7241 tabla_codec_hphr_gnd_switch(codec, true);
7242 mb_v[i] = __tabla_codec_sta_dce(codec, 1, true, true);
7243 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007244 if (vddioswitch)
7245 scaled = tabla_scale_v_micb_vddio(tabla,
Joonwoo Park41956722012-04-18 13:13:07 -07007246 mic_mv[i],
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007247 false);
7248 else
7249 scaled = mic_mv[i];
7250 /* !gndswitch & vddioswitch means the previous DCE
7251 * was done with gndswitch, don't compare with DCE
7252 * with gndswitch */
7253 highdelta = tabla_is_inval_ins_delta(codec, scaled,
Joonwoo Park6a5a4f12012-06-15 15:56:25 -07007254 mic_mv[i - 1],
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007255 TABLA_MBHC_FAKE_INS_DELTA_SCALED_MV);
7256 inval = (tabla_is_inval_ins_range(codec, mic_mv[i],
7257 highhph, &highv) ||
7258 highdelta);
7259 ahighv |= highv;
Joonwoo Park41956722012-04-18 13:13:07 -07007260 if (gndswitch)
7261 tabla_codec_hphr_gnd_switch(codec, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007262 if (vddioswitch)
Simmi Pateriyad60186a2012-11-27 13:50:11 +05307263 tabla_codec_onoff_vddio_switch(codec, false);
Joonwoo Park41956722012-04-18 13:13:07 -07007264 }
7265 pr_debug("%s: DCE #%d, %04x, V %d, scaled V %d, GND %d, "
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007266 "VDDIO %d, inval %d\n", __func__,
Joonwoo Park41956722012-04-18 13:13:07 -07007267 i + 1, mb_v[i] & 0xffff, mic_mv[i], scaled, gndswitch,
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007268 vddioswitch, inval);
7269 /* don't need to run further DCEs */
Ravi Kumar Alamanda1c713b22012-09-27 17:14:27 -07007270 if ((ahighv || !vddioswitch) && inval)
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007271 break;
7272 mic_mv[i] = scaled;
Ravi Kumar Alamanda1c713b22012-09-27 17:14:27 -07007273
7274 /*
7275 * claim UNSUPPORTED plug insertion when
7276 * good headset is detected but HPHR GND switch makes
7277 * delta difference
7278 */
7279 if (i == (num_det - 2) && highdelta && !ahighv)
7280 gndmicswapped = true;
7281 else if (i == (num_det - 1) && inval) {
7282 if (gndmicswapped)
7283 plug_type[0] = PLUG_TYPE_GND_MIC_SWAP;
7284 else
7285 plug_type[0] = PLUG_TYPE_INVALID;
7286 }
Joonwoo Park41956722012-04-18 13:13:07 -07007287 }
7288
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007289 for (i = 0; (plug_type[0] != PLUG_TYPE_GND_MIC_SWAP && !inval) &&
7290 i < num_det; i++) {
Joonwoo Park41956722012-04-18 13:13:07 -07007291 /*
7292 * If we are here, means none of the all
7293 * measurements are fake, continue plug type detection.
7294 * If all three measurements do not produce same
7295 * plug type, restart insertion detection
7296 */
7297 if (mic_mv[i] < plug_type_ptr->v_no_mic) {
7298 plug_type[i] = PLUG_TYPE_HEADPHONE;
7299 pr_debug("%s: Detect attempt %d, detected Headphone\n",
7300 __func__, i);
7301 } else if (highhph && (mic_mv[i] > plug_type_ptr->v_hs_max)) {
7302 plug_type[i] = PLUG_TYPE_HIGH_HPH;
7303 pr_debug("%s: Detect attempt %d, detected High "
7304 "Headphone\n", __func__, i);
7305 } else {
7306 plug_type[i] = PLUG_TYPE_HEADSET;
7307 pr_debug("%s: Detect attempt %d, detected Headset\n",
7308 __func__, i);
7309 }
7310
7311 if (i > 0 && (plug_type[i - 1] != plug_type[i])) {
7312 pr_err("%s: Detect attempt %d and %d are not same",
7313 __func__, i - 1, i);
7314 plug_type[0] = PLUG_TYPE_INVALID;
7315 inval = true;
7316 break;
7317 }
7318 }
7319
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007320 pr_debug("%s: Detected plug type %d\n", __func__, plug_type[0]);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007321 pr_debug("%s: leave\n", __func__);
Joonwoo Park41956722012-04-18 13:13:07 -07007322 return plug_type[0];
7323}
7324
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007325static void tabla_hs_correct_gpio_plug(struct work_struct *work)
7326{
7327 struct tabla_priv *tabla;
7328 struct snd_soc_codec *codec;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007329 int retry = 0, pt_gnd_mic_swap_cnt = 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007330 bool correction = false;
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007331 enum tabla_mbhc_plug_type plug_type = PLUG_TYPE_INVALID;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007332 unsigned long timeout;
7333
7334 tabla = container_of(work, struct tabla_priv, hs_correct_plug_work);
7335 codec = tabla->codec;
7336
7337 pr_debug("%s: enter\n", __func__);
7338 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
7339
7340 /* Keep override on during entire plug type correction work.
7341 *
7342 * This is okay under the assumption that any GPIO irqs which use
7343 * MBHC block cancel and sync this work so override is off again
7344 * prior to GPIO interrupt handler's MBHC block usage.
7345 * Also while this correction work is running, we can guarantee
7346 * DAPM doesn't use any MBHC block as this work only runs with
7347 * headphone detection.
7348 */
7349 tabla_turn_onoff_override(codec, true);
7350
7351 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
7352 while (!time_after(jiffies, timeout)) {
7353 ++retry;
7354 rmb();
7355 if (tabla->hs_detect_work_stop) {
7356 pr_debug("%s: stop requested\n", __func__);
7357 break;
7358 }
7359
7360 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
7361 if (tabla_hs_gpio_level_remove(tabla)) {
7362 pr_debug("%s: GPIO value is low\n", __func__);
7363 break;
7364 }
7365
7366 /* can race with removal interrupt */
7367 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Park41956722012-04-18 13:13:07 -07007368 plug_type = tabla_codec_get_plug_type(codec, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007369 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
7370
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007371 pr_debug("%s: attempt(%d) current_plug(%d) new_plug(%d)\n",
7372 __func__, retry, tabla->current_plug, plug_type);
Joonwoo Park41956722012-04-18 13:13:07 -07007373 if (plug_type == PLUG_TYPE_INVALID) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007374 pr_debug("Invalid plug in attempt # %d\n", retry);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007375 if (!tabla->mbhc_cfg.detect_extn_cable &&
7376 retry == NUM_ATTEMPTS_TO_REPORT &&
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007377 tabla->current_plug == PLUG_TYPE_NONE) {
7378 tabla_codec_report_plug(codec, 1,
7379 SND_JACK_HEADPHONE);
7380 }
Joonwoo Park41956722012-04-18 13:13:07 -07007381 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007382 pr_debug("Good headphone detected, continue polling mic\n");
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007383 if (tabla->mbhc_cfg.detect_extn_cable) {
7384 if (tabla->current_plug != plug_type)
7385 tabla_codec_report_plug(codec, 1,
7386 SND_JACK_HEADPHONE);
7387 } else if (tabla->current_plug == PLUG_TYPE_NONE)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007388 tabla_codec_report_plug(codec, 1,
7389 SND_JACK_HEADPHONE);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007390 } else {
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007391 if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
7392 pt_gnd_mic_swap_cnt++;
7393 if (pt_gnd_mic_swap_cnt <
7394 TABLA_MBHC_GND_MIC_SWAP_THRESHOLD)
7395 continue;
7396 else if (pt_gnd_mic_swap_cnt >
7397 TABLA_MBHC_GND_MIC_SWAP_THRESHOLD) {
7398 /* This is due to GND/MIC switch didn't
7399 * work, Report unsupported plug */
7400 } else if (tabla->mbhc_cfg.swap_gnd_mic) {
7401 /* if switch is toggled, check again,
7402 * otherwise report unsupported plug */
7403 if (tabla->mbhc_cfg.swap_gnd_mic(codec))
7404 continue;
7405 }
7406 } else
7407 pt_gnd_mic_swap_cnt = 0;
7408
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007409 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
7410 /* Turn off override */
7411 tabla_turn_onoff_override(codec, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007412 /* The valid plug also includes PLUG_TYPE_GND_MIC_SWAP
7413 */
Joonwoo Park41956722012-04-18 13:13:07 -07007414 tabla_find_plug_and_report(codec, plug_type);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007415 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
7416 pr_debug("Attempt %d found correct plug %d\n", retry,
Joonwoo Park41956722012-04-18 13:13:07 -07007417 plug_type);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007418 correction = true;
7419 break;
7420 }
7421 }
7422
7423 /* Turn off override */
7424 if (!correction)
7425 tabla_turn_onoff_override(codec, false);
7426
7427 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007428
7429 if (tabla->mbhc_cfg.detect_extn_cable) {
7430 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
7431 if (tabla->current_plug == PLUG_TYPE_HEADPHONE ||
7432 tabla->current_plug == PLUG_TYPE_GND_MIC_SWAP ||
7433 tabla->current_plug == PLUG_TYPE_INVALID ||
7434 plug_type == PLUG_TYPE_INVALID) {
7435 /* Enable removal detection */
7436 tabla_codec_cleanup_hs_polling(codec);
7437 tabla_codec_enable_hs_detect(codec, 0, 0, false);
7438 }
7439 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
7440 }
7441 pr_debug("%s: leave current_plug(%d)\n",
7442 __func__, tabla->current_plug);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007443 /* unlock sleep */
7444 wcd9xxx_unlock_sleep(tabla->codec->control_data);
7445}
7446
7447/* called under codec_resource_lock acquisition */
7448static void tabla_codec_decide_gpio_plug(struct snd_soc_codec *codec)
7449{
Joonwoo Park41956722012-04-18 13:13:07 -07007450 enum tabla_mbhc_plug_type plug_type;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007451 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007452
7453 pr_debug("%s: enter\n", __func__);
7454
7455 tabla_turn_onoff_override(codec, true);
Joonwoo Park41956722012-04-18 13:13:07 -07007456 plug_type = tabla_codec_get_plug_type(codec, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007457 tabla_turn_onoff_override(codec, false);
7458
7459 if (tabla_hs_gpio_level_remove(tabla)) {
7460 pr_debug("%s: GPIO value is low when determining plug\n",
7461 __func__);
7462 return;
7463 }
7464
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007465 if (plug_type == PLUG_TYPE_INVALID ||
7466 plug_type == PLUG_TYPE_GND_MIC_SWAP) {
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007467 tabla_schedule_hs_detect_plug(tabla,
7468 &tabla->hs_correct_plug_work);
Joonwoo Park41956722012-04-18 13:13:07 -07007469 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007470 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
7471
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007472 tabla_schedule_hs_detect_plug(tabla,
7473 &tabla->hs_correct_plug_work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007474 } else {
Joonwoo Park41956722012-04-18 13:13:07 -07007475 pr_debug("%s: Valid plug found, determine plug type %d\n",
7476 __func__, plug_type);
7477 tabla_find_plug_and_report(codec, plug_type);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007478 }
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007479 pr_debug("%s: leave\n", __func__);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007480}
7481
7482/* called under codec_resource_lock acquisition */
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007483static void tabla_codec_detect_plug_type(struct snd_soc_codec *codec)
7484{
Joonwoo Park41956722012-04-18 13:13:07 -07007485 enum tabla_mbhc_plug_type plug_type;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007486 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
7487 const struct tabla_mbhc_plug_detect_cfg *plug_det =
7488 TABLA_MBHC_CAL_PLUG_DET_PTR(tabla->mbhc_cfg.calibration);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007489 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007490 /* Turn on the override,
7491 * tabla_codec_setup_hs_polling requires override on */
7492 tabla_turn_onoff_override(codec, true);
Joonwoo Park03324832012-03-19 19:36:16 -07007493
7494 if (plug_det->t_ins_complete > 20)
7495 msleep(plug_det->t_ins_complete);
7496 else
7497 usleep_range(plug_det->t_ins_complete * 1000,
7498 plug_det->t_ins_complete * 1000);
7499
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007500 if (tabla->mbhc_cfg.gpio) {
7501 /* Turn off the override */
7502 tabla_turn_onoff_override(codec, false);
7503 if (tabla_hs_gpio_level_remove(tabla))
7504 pr_debug("%s: GPIO value is low when determining "
7505 "plug\n", __func__);
7506 else
7507 tabla_codec_decide_gpio_plug(codec);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007508 pr_debug("%s: leave\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007509 return;
7510 }
7511
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007512 plug_type = tabla_codec_get_plug_type(codec, false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007513 tabla_turn_onoff_override(codec, false);
Joonwoo Park03324832012-03-19 19:36:16 -07007514
Joonwoo Park41956722012-04-18 13:13:07 -07007515 if (plug_type == PLUG_TYPE_INVALID) {
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007516 pr_debug("%s: Invalid plug type detected\n", __func__);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007517 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_B1_CTL, 0x02, 0x02);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007518 tabla_codec_cleanup_hs_polling(codec);
7519 tabla_codec_enable_hs_detect(codec, 1,
7520 MBHC_USE_MB_TRIGGER |
7521 MBHC_USE_HPHL_TRIGGER, false);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007522 } else if (plug_type == PLUG_TYPE_GND_MIC_SWAP) {
7523 pr_debug("%s: GND-MIC swapped plug type detected\n", __func__);
7524 tabla_codec_report_plug(codec, 1, SND_JACK_UNSUPPORTED);
7525 tabla_codec_cleanup_hs_polling(codec);
7526 tabla_codec_enable_hs_detect(codec, 0, 0, false);
Joonwoo Park41956722012-04-18 13:13:07 -07007527 } else if (plug_type == PLUG_TYPE_HEADPHONE) {
Joonwoo Park03324832012-03-19 19:36:16 -07007528 pr_debug("%s: Headphone Detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007529 tabla_codec_report_plug(codec, 1, SND_JACK_HEADPHONE);
7530 tabla_codec_cleanup_hs_polling(codec);
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007531 tabla_schedule_hs_detect_plug(tabla,
7532 &tabla->hs_correct_plug_work_nogpio);
Joonwoo Park41956722012-04-18 13:13:07 -07007533 } else if (plug_type == PLUG_TYPE_HEADSET) {
Joonwoo Park03324832012-03-19 19:36:16 -07007534 pr_debug("%s: Headset detected\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007535 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
Joonwoo Park03324832012-03-19 19:36:16 -07007536 /* avoid false button press detect */
7537 msleep(50);
Joonwoo Park03324832012-03-19 19:36:16 -07007538 tabla_codec_start_hs_polling(codec);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007539 } else if (tabla->mbhc_cfg.detect_extn_cable &&
7540 plug_type == PLUG_TYPE_HIGH_HPH) {
7541 pr_debug("%s: High impedance plug type detected\n", __func__);
7542 tabla_codec_report_plug(codec, 1, SND_JACK_LINEOUT);
7543 /* Enable insertion detection on the other end of cable */
7544 tabla_codec_cleanup_hs_polling(codec);
7545 tabla_codec_enable_hs_detect(codec, 1,
7546 MBHC_USE_MB_TRIGGER, false);
Joonwoo Park03324832012-03-19 19:36:16 -07007547 }
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007548 pr_debug("%s: leave\n", __func__);
Joonwoo Park03324832012-03-19 19:36:16 -07007549}
7550
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007551/* called only from interrupt which is under codec_resource_lock acquisition */
7552static void tabla_hs_insert_irq_gpio(struct tabla_priv *priv, bool is_removal)
Bradley Rubincb1e2732011-06-23 16:49:20 -07007553{
Bradley Rubincb1e2732011-06-23 16:49:20 -07007554 struct snd_soc_codec *codec = priv->codec;
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007555 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007556
7557 if (!is_removal) {
7558 pr_debug("%s: MIC trigger insertion interrupt\n", __func__);
7559
7560 rmb();
7561 if (priv->lpi_enabled)
7562 msleep(100);
7563
7564 rmb();
7565 if (!priv->lpi_enabled) {
7566 pr_debug("%s: lpi is disabled\n", __func__);
7567 } else if (gpio_get_value_cansleep(priv->mbhc_cfg.gpio) ==
7568 priv->mbhc_cfg.gpio_level_insert) {
7569 pr_debug("%s: Valid insertion, "
7570 "detect plug type\n", __func__);
7571 tabla_codec_decide_gpio_plug(codec);
7572 } else {
7573 pr_debug("%s: Invalid insertion, "
7574 "stop plug detection\n", __func__);
7575 }
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007576 } else if (tabla->mbhc_cfg.detect_extn_cable) {
7577 pr_debug("%s: Removal\n", __func__);
7578 if (!tabla_hs_gpio_level_remove(tabla)) {
7579 /*
7580 * gpio says, something is still inserted, could be
7581 * extension cable i.e. headset is removed from
7582 * extension cable
7583 */
7584 /* cancel detect plug */
7585 tabla_cancel_hs_detect_plug(tabla,
7586 &tabla->hs_correct_plug_work);
7587 tabla_codec_decide_gpio_plug(codec);
7588 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007589 } else {
7590 pr_err("%s: GPIO used, invalid MBHC Removal\n", __func__);
7591 }
7592}
7593
7594/* called only from interrupt which is under codec_resource_lock acquisition */
7595static void tabla_hs_insert_irq_nogpio(struct tabla_priv *priv, bool is_removal,
7596 bool is_mb_trigger)
7597{
Joonwoo Park03324832012-03-19 19:36:16 -07007598 int ret;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007599 struct snd_soc_codec *codec = priv->codec;
7600 struct wcd9xxx *core = dev_get_drvdata(priv->codec->dev->parent);
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007601 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
7602
7603 /* Cancel possibly running hs_detect_work */
7604 tabla_cancel_hs_detect_plug(tabla,
7605 &tabla->hs_correct_plug_work_nogpio);
Bhalchandra Gajare7fc72332011-10-13 19:01:55 -07007606
7607 if (is_removal) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007608
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07007609 /*
7610 * If headphone is removed while playback is in progress,
7611 * it is possible that micbias will be switched to VDDIO.
7612 */
Joonwoo Park03324832012-03-19 19:36:16 -07007613 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007614 if (priv->current_plug == PLUG_TYPE_HEADPHONE)
7615 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
7616 else if (priv->current_plug == PLUG_TYPE_GND_MIC_SWAP)
7617 tabla_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
7618 else
7619 WARN(1, "%s: Unexpected current plug type %d\n",
7620 __func__, priv->current_plug);
Bradley Rubincb1e2732011-06-23 16:49:20 -07007621 tabla_codec_shutdown_hs_removal_detect(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007622 tabla_codec_enable_hs_detect(codec, 1,
7623 MBHC_USE_MB_TRIGGER |
7624 MBHC_USE_HPHL_TRIGGER,
Joonwoo Park03324832012-03-19 19:36:16 -07007625 true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007626 } else if (is_mb_trigger && !is_removal) {
Joonwoo Park03324832012-03-19 19:36:16 -07007627 pr_debug("%s: Waiting for Headphone left trigger\n",
7628 __func__);
7629 wcd9xxx_lock_sleep(core);
7630 if (schedule_delayed_work(&priv->mbhc_insert_dwork,
7631 usecs_to_jiffies(1000000)) == 0) {
7632 pr_err("%s: mbhc_insert_dwork is already scheduled\n",
7633 __func__);
7634 wcd9xxx_unlock_sleep(core);
Joonwoo Parkf4267c22012-01-10 13:25:24 -08007635 }
Joonwoo Park03324832012-03-19 19:36:16 -07007636 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
7637 false);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007638 } else {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007639 ret = cancel_delayed_work(&priv->mbhc_insert_dwork);
7640 if (ret != 0) {
7641 pr_debug("%s: Complete plug insertion, Detecting plug "
7642 "type\n", __func__);
7643 tabla_codec_detect_plug_type(codec);
7644 wcd9xxx_unlock_sleep(core);
7645 } else {
7646 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07007647 WCD9XXX_IRQ_MBHC_INSERTION);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007648 pr_err("%s: Error detecting plug insertion\n",
7649 __func__);
7650 }
Joonwoo Park03324832012-03-19 19:36:16 -07007651 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007652}
Bhalchandra Gajare9494fa262011-11-10 19:25:59 -08007653
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007654/* called only from interrupt which is under codec_resource_lock acquisition */
7655static void tabla_hs_insert_irq_extn(struct tabla_priv *priv,
7656 bool is_mb_trigger)
7657{
7658 struct snd_soc_codec *codec = priv->codec;
7659 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
7660
7661 /* Cancel possibly running hs_detect_work */
7662 tabla_cancel_hs_detect_plug(tabla,
7663 &tabla->hs_correct_plug_work);
7664
7665 if (is_mb_trigger) {
7666 pr_debug("%s: Waiting for Headphone left trigger\n",
7667 __func__);
7668 tabla_codec_enable_hs_detect(codec, 1, MBHC_USE_HPHL_TRIGGER,
7669 false);
7670 } else {
7671 pr_debug("%s: HPHL trigger received, detecting plug type\n",
7672 __func__);
7673 tabla_codec_detect_plug_type(codec);
7674 }
7675}
7676
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007677static irqreturn_t tabla_hs_insert_irq(int irq, void *data)
7678{
7679 bool is_mb_trigger, is_removal;
7680 struct tabla_priv *priv = data;
7681 struct snd_soc_codec *codec = priv->codec;
Bradley Rubincb1e2732011-06-23 16:49:20 -07007682
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007683 pr_debug("%s: enter\n", __func__);
7684 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07007685 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007686
7687 is_mb_trigger = !!(snd_soc_read(codec, priv->mbhc_bias_regs.mbhc_reg) &
7688 0x10);
7689 is_removal = !!(snd_soc_read(codec, TABLA_A_CDC_MBHC_INT_CTL) & 0x02);
7690 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_INT_CTL, 0x03, 0x00);
7691
7692 /* Turn off both HPH and MIC line schmitt triggers */
7693 snd_soc_update_bits(codec, priv->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
7694 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
7695 snd_soc_update_bits(codec, priv->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
7696
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007697 if (priv->mbhc_cfg.detect_extn_cable &&
7698 priv->current_plug == PLUG_TYPE_HIGH_HPH)
7699 tabla_hs_insert_irq_extn(priv, is_mb_trigger);
7700 else if (priv->mbhc_cfg.gpio)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007701 tabla_hs_insert_irq_gpio(priv, is_removal);
7702 else
7703 tabla_hs_insert_irq_nogpio(priv, is_removal, is_mb_trigger);
7704
7705 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Bradley Rubincb1e2732011-06-23 16:49:20 -07007706 return IRQ_HANDLED;
7707}
7708
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007709static bool is_valid_mic_voltage(struct snd_soc_codec *codec, s32 mic_mv)
7710{
7711 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007712 const struct tabla_mbhc_plug_type_cfg *plug_type =
7713 TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla->mbhc_cfg.calibration);
7714 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007715
7716 return (!(mic_mv > 10 && mic_mv < 80) && (mic_mv > plug_type->v_no_mic)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007717 && (mic_mv < v_hs_max)) ? true : false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007718}
7719
7720/* called under codec_resource_lock acquisition
7721 * returns true if mic voltage range is back to normal insertion
7722 * returns false either if timedout or removed */
7723static bool tabla_hs_remove_settle(struct snd_soc_codec *codec)
7724{
7725 int i;
7726 bool timedout, settled = false;
7727 s32 mic_mv[MBHC_NUM_DCE_PLUG_DETECT];
7728 short mb_v[MBHC_NUM_DCE_PLUG_DETECT];
7729 unsigned long retry = 0, timeout;
7730 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007731 const s16 v_hs_max = tabla_get_current_v_hs_max(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007732
7733 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
7734 while (!(timedout = time_after(jiffies, timeout))) {
7735 retry++;
7736 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
7737 pr_debug("%s: GPIO indicates removal\n", __func__);
7738 break;
7739 }
7740
7741 if (tabla->mbhc_cfg.gpio) {
7742 if (retry > 1)
7743 msleep(250);
7744 else
7745 msleep(50);
7746 }
7747
7748 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
7749 pr_debug("%s: GPIO indicates removal\n", __func__);
7750 break;
7751 }
7752
7753 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++) {
7754 mb_v[i] = tabla_codec_sta_dce(codec, 1, true);
7755 mic_mv[i] = tabla_codec_sta_dce_v(codec, 1 , mb_v[i]);
7756 pr_debug("%s : DCE run %lu, mic_mv = %d(%x)\n",
7757 __func__, retry, mic_mv[i], mb_v[i]);
7758 }
7759
7760 if (tabla->mbhc_cfg.gpio && tabla_hs_gpio_level_remove(tabla)) {
7761 pr_debug("%s: GPIO indicates removal\n", __func__);
7762 break;
7763 }
7764
7765 if (tabla->current_plug == PLUG_TYPE_NONE) {
7766 pr_debug("%s : headset/headphone is removed\n",
7767 __func__);
7768 break;
7769 }
7770
7771 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
7772 if (!is_valid_mic_voltage(codec, mic_mv[i]))
7773 break;
7774
7775 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
7776 pr_debug("%s: MIC voltage settled\n", __func__);
7777 settled = true;
7778 msleep(200);
7779 break;
7780 }
7781
7782 /* only for non-GPIO remove irq */
7783 if (!tabla->mbhc_cfg.gpio) {
7784 for (i = 0; i < MBHC_NUM_DCE_PLUG_DETECT; i++)
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007785 if (mic_mv[i] < v_hs_max)
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007786 break;
7787 if (i == MBHC_NUM_DCE_PLUG_DETECT) {
7788 pr_debug("%s: Headset is removed\n", __func__);
7789 break;
7790 }
7791 }
7792 }
7793
7794 if (timedout)
7795 pr_debug("%s: Microphone did not settle in %d seconds\n",
7796 __func__, TABLA_HS_DETECT_PLUG_TIME_MS);
7797 return settled;
7798}
7799
7800/* called only from interrupt which is under codec_resource_lock acquisition */
7801static void tabla_hs_remove_irq_gpio(struct tabla_priv *priv)
7802{
7803 struct snd_soc_codec *codec = priv->codec;
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007804 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007805 if (tabla_hs_remove_settle(codec))
7806 tabla_codec_start_hs_polling(codec);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007807 pr_debug("%s: leave\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007808}
7809
7810/* called only from interrupt which is under codec_resource_lock acquisition */
7811static void tabla_hs_remove_irq_nogpio(struct tabla_priv *priv)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007812{
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08007813 short bias_value;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007814 bool removed = true;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007815 struct snd_soc_codec *codec = priv->codec;
Joonwoo Park0976d012011-12-22 11:48:18 -08007816 const struct tabla_mbhc_general_cfg *generic =
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007817 TABLA_MBHC_CAL_GENERAL_PTR(priv->mbhc_cfg.calibration);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08007818 int min_us = TABLA_FAKE_REMOVAL_MIN_PERIOD_MS * 1000;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007819
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007820 pr_debug("%s: enter\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007821 if (priv->current_plug != PLUG_TYPE_HEADSET) {
7822 pr_debug("%s(): Headset is not inserted, ignore removal\n",
7823 __func__);
7824 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
7825 0x08, 0x08);
7826 return;
7827 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007828
Joonwoo Park0976d012011-12-22 11:48:18 -08007829 usleep_range(generic->t_shutdown_plug_rem,
7830 generic->t_shutdown_plug_rem);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007831
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08007832 do {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007833 bias_value = tabla_codec_sta_dce(codec, 1, true);
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08007834 pr_debug("%s: DCE %d,%d, %d us left\n", __func__, bias_value,
7835 tabla_codec_sta_dce_v(codec, 1, bias_value), min_us);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007836 if (bias_value < tabla_get_current_v_ins(priv, false)) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007837 pr_debug("%s: checking false removal\n", __func__);
7838 msleep(500);
7839 removed = !tabla_hs_remove_settle(codec);
7840 pr_debug("%s: headset %sactually removed\n", __func__,
7841 removed ? "" : "not ");
Joonwoo Park6b9b03f2012-01-23 18:48:54 -08007842 break;
7843 }
7844 min_us -= priv->mbhc_data.t_dce;
7845 } while (min_us > 0);
Bradley Rubin89ffd0a2011-07-21 16:04:06 -07007846
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007847 if (removed) {
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007848 if (priv->mbhc_cfg.detect_extn_cable) {
7849 if (!tabla_hs_gpio_level_remove(priv)) {
7850 /*
7851 * extension cable is still plugged in
7852 * report it as LINEOUT device
7853 */
7854 tabla_codec_report_plug(codec, 1,
7855 SND_JACK_LINEOUT);
7856 tabla_codec_cleanup_hs_polling(codec);
7857 tabla_codec_enable_hs_detect(codec, 1,
7858 MBHC_USE_MB_TRIGGER,
7859 false);
7860 }
7861 } else {
7862 /* Cancel possibly running hs_detect_work */
7863 tabla_cancel_hs_detect_plug(priv,
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007864 &priv->hs_correct_plug_work_nogpio);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007865 /*
7866 * If this removal is not false, first check the micbias
7867 * switch status and switch it to LDOH if it is already
7868 * switched to VDDIO.
7869 */
7870 tabla_codec_switch_micbias(codec, 0);
Joonwoo Park03324832012-03-19 19:36:16 -07007871
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007872 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
7873 tabla_codec_cleanup_hs_polling(codec);
7874 tabla_codec_enable_hs_detect(codec, 1,
7875 MBHC_USE_MB_TRIGGER |
7876 MBHC_USE_HPHL_TRIGGER,
7877 true);
7878 }
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007879 } else {
7880 tabla_codec_start_hs_polling(codec);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007881 }
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007882 pr_debug("%s: leave\n", __func__);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007883}
Joonwoo Park8b1f0982011-12-08 17:12:45 -08007884
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007885static irqreturn_t tabla_hs_remove_irq(int irq, void *data)
7886{
7887 struct tabla_priv *priv = data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007888 bool vddio;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007889 pr_debug("%s: enter, removal interrupt\n", __func__);
7890
7891 TABLA_ACQUIRE_LOCK(priv->codec_resource_lock);
Simmi Pateriya71d63872012-11-08 01:06:30 +05307892 vddio = !priv->mbhc_cfg.micbias_always_on &&
7893 (priv->mbhc_data.micb_mv != VDDIO_MICBIAS_MV &&
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007894 priv->mbhc_micbias_switched);
7895 if (vddio)
7896 __tabla_codec_switch_micbias(priv->codec, 0, false, true);
7897
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007898 if ((priv->mbhc_cfg.detect_extn_cable &&
7899 !tabla_hs_gpio_level_remove(priv)) ||
7900 !priv->mbhc_cfg.gpio) {
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007901 tabla_hs_remove_irq_nogpio(priv);
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007902 } else
7903 tabla_hs_remove_irq_gpio(priv);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007904
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007905 /* if driver turned off vddio switch and headset is not removed,
7906 * turn on the vddio switch back, if headset is removed then vddio
7907 * switch is off by time now and shouldn't be turn on again from here */
7908 if (vddio && priv->current_plug == PLUG_TYPE_HEADSET)
7909 __tabla_codec_switch_micbias(priv->codec, 1, true, true);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007910 TABLA_RELEASE_LOCK(priv->codec_resource_lock);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07007911
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007912 return IRQ_HANDLED;
7913}
7914
Joonwoo Park03324832012-03-19 19:36:16 -07007915void mbhc_insert_work(struct work_struct *work)
7916{
7917 struct delayed_work *dwork;
7918 struct tabla_priv *tabla;
7919 struct snd_soc_codec *codec;
7920 struct wcd9xxx *tabla_core;
7921
7922 dwork = to_delayed_work(work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007923 tabla = container_of(dwork, struct tabla_priv, mbhc_insert_dwork);
Joonwoo Park03324832012-03-19 19:36:16 -07007924 codec = tabla->codec;
7925 tabla_core = dev_get_drvdata(codec->dev->parent);
7926
7927 pr_debug("%s:\n", __func__);
7928
7929 /* Turn off both HPH and MIC line schmitt triggers */
7930 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.mbhc_reg, 0x90, 0x00);
7931 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x13, 0x00);
7932 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01, 0x00);
Joonwoo Parkf6574c72012-10-10 17:29:57 -07007933 wcd9xxx_disable_irq_sync(codec->control_data,
7934 WCD9XXX_IRQ_MBHC_INSERTION);
Joonwoo Park03324832012-03-19 19:36:16 -07007935 tabla_codec_detect_plug_type(codec);
7936 wcd9xxx_unlock_sleep(tabla_core);
7937}
7938
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007939static void tabla_hs_gpio_handler(struct snd_soc_codec *codec)
7940{
7941 bool insert;
7942 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Park1f9d7fd2013-01-07 12:40:03 -08007943 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007944 bool is_removed = false;
7945
7946 pr_debug("%s: enter\n", __func__);
7947
7948 tabla->in_gpio_handler = true;
7949 /* Wait here for debounce time */
7950 usleep_range(TABLA_GPIO_IRQ_DEBOUNCE_TIME_US,
7951 TABLA_GPIO_IRQ_DEBOUNCE_TIME_US);
7952
Joonwoo Park1f9d7fd2013-01-07 12:40:03 -08007953 wcd9xxx_nested_irq_lock(core);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007954 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
7955
7956 /* cancel pending button press */
7957 if (tabla_cancel_btn_work(tabla))
7958 pr_debug("%s: button press is canceled\n", __func__);
7959
7960 insert = (gpio_get_value_cansleep(tabla->mbhc_cfg.gpio) ==
7961 tabla->mbhc_cfg.gpio_level_insert);
7962 if ((tabla->current_plug == PLUG_TYPE_NONE) && insert) {
7963 tabla->lpi_enabled = false;
7964 wmb();
7965
7966 /* cancel detect plug */
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007967 tabla_cancel_hs_detect_plug(tabla,
7968 &tabla->hs_correct_plug_work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007969
7970 /* Disable Mic Bias pull down and HPH Switch to GND */
7971 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg, 0x01,
7972 0x00);
7973 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x00);
7974 tabla_codec_detect_plug_type(codec);
7975 } else if ((tabla->current_plug != PLUG_TYPE_NONE) && !insert) {
7976 tabla->lpi_enabled = false;
7977 wmb();
7978
7979 /* cancel detect plug */
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07007980 tabla_cancel_hs_detect_plug(tabla,
7981 &tabla->hs_correct_plug_work);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007982
7983 if (tabla->current_plug == PLUG_TYPE_HEADPHONE) {
7984 tabla_codec_report_plug(codec, 0, SND_JACK_HEADPHONE);
7985 is_removed = true;
Joonwoo Park2cc13f02012-05-09 12:44:25 -07007986 } else if (tabla->current_plug == PLUG_TYPE_GND_MIC_SWAP) {
7987 tabla_codec_report_plug(codec, 0, SND_JACK_UNSUPPORTED);
7988 is_removed = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007989 } else if (tabla->current_plug == PLUG_TYPE_HEADSET) {
7990 tabla_codec_pause_hs_polling(codec);
7991 tabla_codec_cleanup_hs_polling(codec);
7992 tabla_codec_report_plug(codec, 0, SND_JACK_HEADSET);
7993 is_removed = true;
Ravi Kumar Alamanda07b6bd62012-08-15 18:39:47 -07007994 } else if (tabla->current_plug == PLUG_TYPE_HIGH_HPH) {
7995 tabla_codec_report_plug(codec, 0, SND_JACK_LINEOUT);
7996 is_removed = true;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07007997 }
7998
7999 if (is_removed) {
8000 /* Enable Mic Bias pull down and HPH Switch to GND */
8001 snd_soc_update_bits(codec,
8002 tabla->mbhc_bias_regs.ctl_reg, 0x01,
8003 0x01);
8004 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01,
8005 0x01);
8006 /* Make sure mic trigger is turned off */
8007 snd_soc_update_bits(codec,
8008 tabla->mbhc_bias_regs.ctl_reg,
8009 0x01, 0x01);
8010 snd_soc_update_bits(codec,
8011 tabla->mbhc_bias_regs.mbhc_reg,
8012 0x90, 0x00);
8013 /* Reset MBHC State Machine */
8014 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
8015 0x08, 0x08);
8016 snd_soc_update_bits(codec, TABLA_A_CDC_MBHC_CLK_CTL,
8017 0x08, 0x00);
8018 /* Turn off override */
8019 tabla_turn_onoff_override(codec, false);
Simmi Pateriya21375012012-11-26 23:06:01 +05308020 tabla_codec_switch_micbias(codec, 0);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008021 }
8022 }
8023
8024 tabla->in_gpio_handler = false;
8025 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Joonwoo Park1f9d7fd2013-01-07 12:40:03 -08008026 wcd9xxx_nested_irq_unlock(core);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008027 pr_debug("%s: leave\n", __func__);
8028}
8029
8030static irqreturn_t tabla_mechanical_plug_detect_irq(int irq, void *data)
8031{
8032 int r = IRQ_HANDLED;
8033 struct snd_soc_codec *codec = data;
Joonwoo Parkecf379c2012-10-04 16:57:52 -07008034 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008035
8036 if (unlikely(wcd9xxx_lock_sleep(codec->control_data) == false)) {
8037 pr_warn("%s: failed to hold suspend\n", __func__);
Joonwoo Parkecf379c2012-10-04 16:57:52 -07008038 /*
8039 * Give up this IRQ for now and resend this IRQ so IRQ can be
8040 * handled after system resume
8041 */
8042 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
8043 tabla->gpio_irq_resend = true;
8044 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
8045 wake_lock_timeout(&tabla->irq_resend_wlock, HZ);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008046 r = IRQ_NONE;
8047 } else {
8048 tabla_hs_gpio_handler(codec);
8049 wcd9xxx_unlock_sleep(codec->control_data);
8050 }
8051
8052 return r;
8053}
8054
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07008055static void tabla_hs_correct_plug_nogpio(struct work_struct *work)
8056{
8057 struct tabla_priv *tabla;
8058 struct snd_soc_codec *codec;
8059 unsigned long timeout;
8060 int retry = 0;
8061 enum tabla_mbhc_plug_type plug_type;
8062 bool is_headset = false;
8063
8064 pr_debug("%s(): Poll Microphone voltage for %d seconds\n",
8065 __func__, TABLA_HS_DETECT_PLUG_TIME_MS / 1000);
8066
8067 tabla = container_of(work, struct tabla_priv,
8068 hs_correct_plug_work_nogpio);
8069 codec = tabla->codec;
8070
8071 /* Make sure the MBHC mux is connected to MIC Path */
8072 snd_soc_write(codec, TABLA_A_MBHC_SCALING_MUX_1, 0x84);
8073
8074 /* setup for microphone polling */
8075 tabla_turn_onoff_override(codec, true);
8076 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
8077
8078 timeout = jiffies + msecs_to_jiffies(TABLA_HS_DETECT_PLUG_TIME_MS);
8079 while (!time_after(jiffies, timeout)) {
8080 ++retry;
8081
8082 msleep(TABLA_HS_DETECT_PLUG_INERVAL_MS);
8083 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
8084 plug_type = tabla_codec_get_plug_type(codec, false);
8085 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
8086
8087 if (plug_type == PLUG_TYPE_HIGH_HPH
8088 || plug_type == PLUG_TYPE_INVALID) {
8089
8090 /* this means the plug is removed
8091 * End microphone polling and setup
8092 * for low power removal detection.
8093 */
8094 pr_debug("%s(): Plug may be removed, setup removal\n",
8095 __func__);
8096 break;
8097 } else if (plug_type == PLUG_TYPE_HEADSET) {
8098 /* Plug is corrected from headphone to headset,
8099 * report headset and end the polling
8100 */
8101 is_headset = true;
8102 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
8103 tabla_turn_onoff_override(codec, false);
8104 tabla_codec_report_plug(codec, 1, SND_JACK_HEADSET);
8105 tabla_codec_start_hs_polling(codec);
8106 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
8107 pr_debug("%s(): corrected from headphone to headset\n",
8108 __func__);
8109 break;
8110 }
8111 }
8112
8113 /* Undo setup for microphone polling depending
8114 * result from polling
8115 */
8116 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
8117 if (!is_headset) {
Bhalchandra Gajareafc86432012-08-23 13:44:07 -07008118 pr_debug("%s: Inserted headphone is not a headset\n",
8119 __func__);
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07008120 tabla_turn_onoff_override(codec, false);
8121 tabla_codec_cleanup_hs_polling(codec);
8122 tabla_codec_enable_hs_detect(codec, 0, 0, false);
8123 }
8124 wcd9xxx_unlock_sleep(codec->control_data);
8125}
8126
Joonwoo Park1305bab2012-05-21 15:08:42 -07008127static int tabla_mbhc_init_and_calibrate(struct tabla_priv *tabla)
8128{
8129 int ret = 0;
8130 struct snd_soc_codec *codec = tabla->codec;
8131
8132 tabla->mbhc_cfg.mclk_cb_fn(codec, 1, false);
8133 tabla_mbhc_init(codec);
8134 tabla_mbhc_cal(codec);
8135 tabla_mbhc_calc_thres(codec);
8136 tabla->mbhc_cfg.mclk_cb_fn(codec, 0, false);
8137 tabla_codec_calibrate_hs_polling(codec);
8138 if (!tabla->mbhc_cfg.gpio) {
Bhalchandra Gajareac0bddf2012-04-06 12:33:54 -07008139 INIT_WORK(&tabla->hs_correct_plug_work_nogpio,
8140 tabla_hs_correct_plug_nogpio);
Joonwoo Park1305bab2012-05-21 15:08:42 -07008141 ret = tabla_codec_enable_hs_detect(codec, 1,
8142 MBHC_USE_MB_TRIGGER |
8143 MBHC_USE_HPHL_TRIGGER,
8144 false);
8145
8146 if (IS_ERR_VALUE(ret))
8147 pr_err("%s: Failed to setup MBHC detection\n",
8148 __func__);
8149 } else {
8150 /* Enable Mic Bias pull down and HPH Switch to GND */
8151 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.ctl_reg,
8152 0x01, 0x01);
8153 snd_soc_update_bits(codec, TABLA_A_MBHC_HPH, 0x01, 0x01);
8154 INIT_WORK(&tabla->hs_correct_plug_work,
8155 tabla_hs_correct_gpio_plug);
8156 }
8157
8158 if (!IS_ERR_VALUE(ret)) {
8159 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL, 0x10, 0x10);
8160 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008161 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Joonwoo Park1305bab2012-05-21 15:08:42 -07008162 wcd9xxx_enable_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008163 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Joonwoo Park1305bab2012-05-21 15:08:42 -07008164
8165 if (tabla->mbhc_cfg.gpio) {
8166 ret = request_threaded_irq(tabla->mbhc_cfg.gpio_irq,
8167 NULL,
8168 tabla_mechanical_plug_detect_irq,
8169 (IRQF_TRIGGER_RISING |
8170 IRQF_TRIGGER_FALLING),
8171 "tabla-gpio", codec);
8172 if (!IS_ERR_VALUE(ret)) {
8173 ret = enable_irq_wake(tabla->mbhc_cfg.gpio_irq);
8174 /* Bootup time detection */
8175 tabla_hs_gpio_handler(codec);
8176 }
8177 }
8178 }
8179
8180 return ret;
8181}
8182
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008183static void mbhc_fw_read(struct work_struct *work)
8184{
8185 struct delayed_work *dwork;
8186 struct tabla_priv *tabla;
8187 struct snd_soc_codec *codec;
8188 const struct firmware *fw;
Joonwoo Park1305bab2012-05-21 15:08:42 -07008189 int ret = -1, retry = 0;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008190
8191 dwork = to_delayed_work(work);
Joonwoo Park1305bab2012-05-21 15:08:42 -07008192 tabla = container_of(dwork, struct tabla_priv, mbhc_firmware_dwork);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008193 codec = tabla->codec;
8194
8195 while (retry < MBHC_FW_READ_ATTEMPTS) {
8196 retry++;
8197 pr_info("%s:Attempt %d to request MBHC firmware\n",
8198 __func__, retry);
8199 ret = request_firmware(&fw, "wcd9310/wcd9310_mbhc.bin",
8200 codec->dev);
8201
8202 if (ret != 0) {
8203 usleep_range(MBHC_FW_READ_TIMEOUT,
Joonwoo Park1305bab2012-05-21 15:08:42 -07008204 MBHC_FW_READ_TIMEOUT);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008205 } else {
8206 pr_info("%s: MBHC Firmware read succesful\n", __func__);
8207 break;
8208 }
8209 }
8210
8211 if (ret != 0) {
8212 pr_err("%s: Cannot load MBHC firmware use default cal\n",
8213 __func__);
8214 } else if (tabla_mbhc_fw_validate(fw) == false) {
8215 pr_err("%s: Invalid MBHC cal data size use default cal\n",
8216 __func__);
8217 release_firmware(fw);
8218 } else {
8219 tabla->mbhc_cfg.calibration = (void *)fw->data;
8220 tabla->mbhc_fw = fw;
8221 }
8222
Joonwoo Park1305bab2012-05-21 15:08:42 -07008223 (void) tabla_mbhc_init_and_calibrate(tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008224}
8225
Joonwoo Park03324832012-03-19 19:36:16 -07008226int tabla_hs_detect(struct snd_soc_codec *codec,
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008227 const struct tabla_mbhc_config *cfg)
Joonwoo Park03324832012-03-19 19:36:16 -07008228{
8229 struct tabla_priv *tabla;
8230 int rc = 0;
8231
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008232 if (!codec || !cfg->calibration) {
Joonwoo Park03324832012-03-19 19:36:16 -07008233 pr_err("Error: no codec or calibration\n");
8234 return -EINVAL;
8235 }
8236
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008237 if (cfg->mclk_rate != TABLA_MCLK_RATE_12288KHZ) {
8238 if (cfg->mclk_rate == TABLA_MCLK_RATE_9600KHZ)
Joonwoo Park03324832012-03-19 19:36:16 -07008239 pr_err("Error: clock rate %dHz is not yet supported\n",
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008240 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07008241 else
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008242 pr_err("Error: unsupported clock rate %d\n",
8243 cfg->mclk_rate);
Joonwoo Park03324832012-03-19 19:36:16 -07008244 return -EINVAL;
8245 }
8246
8247 tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008248 tabla->mbhc_cfg = *cfg;
8249 tabla->in_gpio_handler = false;
8250 tabla->current_plug = PLUG_TYPE_NONE;
8251 tabla->lpi_enabled = false;
Joonwoo Park03324832012-03-19 19:36:16 -07008252 tabla_get_mbhc_micbias_regs(codec, &tabla->mbhc_bias_regs);
8253
8254 /* Put CFILT in fast mode by default */
Simmi Pateriya71d63872012-11-08 01:06:30 +05308255 if (!tabla->mbhc_cfg.micbias_always_on)
8256 snd_soc_update_bits(codec, tabla->mbhc_bias_regs.cfilt_ctl,
Joonwoo Park03324832012-03-19 19:36:16 -07008257 0x40, TABLA_CFILT_FAST_MODE);
8258 INIT_DELAYED_WORK(&tabla->mbhc_firmware_dwork, mbhc_fw_read);
8259 INIT_DELAYED_WORK(&tabla->mbhc_btn_dwork, btn_lpress_fn);
8260 INIT_WORK(&tabla->hphlocp_work, hphlocp_off_report);
8261 INIT_WORK(&tabla->hphrocp_work, hphrocp_off_report);
8262 INIT_DELAYED_WORK(&tabla->mbhc_insert_dwork, mbhc_insert_work);
8263
Joonwoo Park1305bab2012-05-21 15:08:42 -07008264 if (!tabla->mbhc_cfg.read_fw_bin)
8265 rc = tabla_mbhc_init_and_calibrate(tabla);
8266 else
Joonwoo Park03324832012-03-19 19:36:16 -07008267 schedule_delayed_work(&tabla->mbhc_firmware_dwork,
8268 usecs_to_jiffies(MBHC_FW_READ_TIMEOUT));
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008269
Joonwoo Park03324832012-03-19 19:36:16 -07008270 return rc;
8271}
8272EXPORT_SYMBOL_GPL(tabla_hs_detect);
8273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008274static irqreturn_t tabla_slimbus_irq(int irq, void *data)
8275{
8276 struct tabla_priv *priv = data;
8277 struct snd_soc_codec *codec = priv->codec;
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07008278 struct tabla_priv *tabla_p = snd_soc_codec_get_drvdata(codec);
8279 int i, j, port_id, k, ch_mask_temp;
Swaminathan Sathappan4bd38942012-07-17 11:31:31 -07008280 unsigned long slimbus_value;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008281 u8 val;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308282 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++) {
8283 slimbus_value = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008284 TABLA_SLIM_PGD_PORT_INT_STATUS0 + i);
8285 for_each_set_bit(j, &slimbus_value, BITS_PER_BYTE) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308286 val = wcd9xxx_interface_reg_read(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008287 TABLA_SLIM_PGD_PORT_INT_SOURCE0 + i*8 + j);
8288 if (val & 0x1)
8289 pr_err_ratelimited("overflow error on port %x,"
8290 " value %x\n", i*8 + j, val);
8291 if (val & 0x2)
8292 pr_err_ratelimited("underflow error on port %x,"
8293 " value %x\n", i*8 + j, val);
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07008294 if (val & 0x4) {
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07008295 port_id = i*8 + j;
8296 for (k = 0; k < ARRAY_SIZE(tabla_dai); k++) {
8297 ch_mask_temp = 1 << port_id;
Joonwoo Park9bbb4d12012-11-09 19:58:11 -08008298 pr_debug("%s: tabla_p->dai[%d].ch_mask = 0x%lx\n",
Kuirong Wang906ac472012-07-09 12:54:44 -07008299 __func__, k,
8300 tabla_p->dai[k].ch_mask);
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07008301 if (ch_mask_temp &
8302 tabla_p->dai[k].ch_mask) {
8303 tabla_p->dai[k].ch_mask &=
Kuirong Wang906ac472012-07-09 12:54:44 -07008304 ~ch_mask_temp;
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07008305 if (!tabla_p->dai[k].ch_mask)
Kuirong Wang906ac472012-07-09 12:54:44 -07008306 wake_up(
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -07008307 &tabla_p->dai[k].dai_wait);
8308 }
8309 }
8310 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008311 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308312 wcd9xxx_interface_reg_write(codec->control_data,
Swaminathan Sathappan4bd38942012-07-17 11:31:31 -07008313 TABLA_SLIM_PGD_PORT_INT_CLR0 + i, slimbus_value);
8314 val = 0x0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008315 }
8316
8317 return IRQ_HANDLED;
8318}
8319
Patrick Lai3043fba2011-08-01 14:15:57 -07008320static int tabla_handle_pdata(struct tabla_priv *tabla)
8321{
8322 struct snd_soc_codec *codec = tabla->codec;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308323 struct wcd9xxx_pdata *pdata = tabla->pdata;
Patrick Lai3043fba2011-08-01 14:15:57 -07008324 int k1, k2, k3, rc = 0;
Santosh Mardi22920282011-10-26 02:38:40 +05308325 u8 leg_mode = pdata->amic_settings.legacy_mode;
8326 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
8327 u8 txfe_buff = pdata->amic_settings.txfe_buff;
8328 u8 flag = pdata->amic_settings.use_pdata;
8329 u8 i = 0, j = 0;
8330 u8 val_txfe = 0, value = 0;
Patrick Lai3043fba2011-08-01 14:15:57 -07008331
8332 if (!pdata) {
8333 rc = -ENODEV;
8334 goto done;
8335 }
8336
8337 /* Make sure settings are correct */
8338 if ((pdata->micbias.ldoh_v > TABLA_LDOH_2P85_V) ||
8339 (pdata->micbias.bias1_cfilt_sel > TABLA_CFILT3_SEL) ||
8340 (pdata->micbias.bias2_cfilt_sel > TABLA_CFILT3_SEL) ||
8341 (pdata->micbias.bias3_cfilt_sel > TABLA_CFILT3_SEL) ||
8342 (pdata->micbias.bias4_cfilt_sel > TABLA_CFILT3_SEL)) {
8343 rc = -EINVAL;
8344 goto done;
8345 }
8346
8347 /* figure out k value */
8348 k1 = tabla_find_k_value(pdata->micbias.ldoh_v,
8349 pdata->micbias.cfilt1_mv);
8350 k2 = tabla_find_k_value(pdata->micbias.ldoh_v,
8351 pdata->micbias.cfilt2_mv);
8352 k3 = tabla_find_k_value(pdata->micbias.ldoh_v,
8353 pdata->micbias.cfilt3_mv);
8354
8355 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
8356 rc = -EINVAL;
8357 goto done;
8358 }
8359
8360 /* Set voltage level and always use LDO */
8361 snd_soc_update_bits(codec, TABLA_A_LDO_H_MODE_1, 0x0C,
8362 (pdata->micbias.ldoh_v << 2));
8363
8364 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_1_VAL, 0xFC,
8365 (k1 << 2));
8366 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_2_VAL, 0xFC,
8367 (k2 << 2));
8368 snd_soc_update_bits(codec, TABLA_A_MICB_CFILT_3_VAL, 0xFC,
8369 (k3 << 2));
8370
8371 snd_soc_update_bits(codec, TABLA_A_MICB_1_CTL, 0x60,
8372 (pdata->micbias.bias1_cfilt_sel << 5));
8373 snd_soc_update_bits(codec, TABLA_A_MICB_2_CTL, 0x60,
8374 (pdata->micbias.bias2_cfilt_sel << 5));
8375 snd_soc_update_bits(codec, TABLA_A_MICB_3_CTL, 0x60,
8376 (pdata->micbias.bias3_cfilt_sel << 5));
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008377 snd_soc_update_bits(codec, tabla->reg_addr.micb_4_ctl, 0x60,
8378 (pdata->micbias.bias4_cfilt_sel << 5));
Patrick Lai3043fba2011-08-01 14:15:57 -07008379
Santosh Mardi22920282011-10-26 02:38:40 +05308380 for (i = 0; i < 6; j++, i += 2) {
8381 if (flag & (0x01 << i)) {
8382 value = (leg_mode & (0x01 << i)) ? 0x10 : 0x00;
8383 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
8384 val_txfe = val_txfe |
8385 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
8386 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
8387 0x10, value);
8388 snd_soc_update_bits(codec,
8389 TABLA_A_TX_1_2_TEST_EN + j * 10,
8390 0x30, val_txfe);
8391 }
8392 if (flag & (0x01 << (i + 1))) {
8393 value = (leg_mode & (0x01 << (i + 1))) ? 0x01 : 0x00;
8394 val_txfe = (txfe_bypass &
8395 (0x01 << (i + 1))) ? 0x02 : 0x00;
8396 val_txfe |= (txfe_buff &
8397 (0x01 << (i + 1))) ? 0x01 : 0x00;
8398 snd_soc_update_bits(codec, TABLA_A_TX_1_2_EN + j * 10,
8399 0x01, value);
8400 snd_soc_update_bits(codec,
8401 TABLA_A_TX_1_2_TEST_EN + j * 10,
8402 0x03, val_txfe);
8403 }
8404 }
8405 if (flag & 0x40) {
8406 value = (leg_mode & 0x40) ? 0x10 : 0x00;
8407 value = value | ((txfe_bypass & 0x40) ? 0x02 : 0x00);
8408 value = value | ((txfe_buff & 0x40) ? 0x01 : 0x00);
8409 snd_soc_update_bits(codec, TABLA_A_TX_7_MBHC_EN,
8410 0x13, value);
8411 }
Patrick Lai49efeac2011-11-03 11:01:12 -07008412
8413 if (pdata->ocp.use_pdata) {
8414 /* not defined in CODEC specification */
8415 if (pdata->ocp.hph_ocp_limit == 1 ||
8416 pdata->ocp.hph_ocp_limit == 5) {
8417 rc = -EINVAL;
8418 goto done;
8419 }
8420 snd_soc_update_bits(codec, TABLA_A_RX_COM_OCP_CTL,
8421 0x0F, pdata->ocp.num_attempts);
8422 snd_soc_write(codec, TABLA_A_RX_COM_OCP_COUNT,
8423 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
8424 snd_soc_update_bits(codec, TABLA_A_RX_HPH_OCP_CTL,
8425 0xE0, (pdata->ocp.hph_ocp_limit << 5));
8426 }
Joonwoo Park03324832012-03-19 19:36:16 -07008427
8428 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
8429 if (!strncmp(pdata->regulator[i].name, "CDC_VDDA_RX", 11)) {
8430 if (pdata->regulator[i].min_uV == 1800000 &&
8431 pdata->regulator[i].max_uV == 1800000) {
8432 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
8433 0x1C);
8434 } else if (pdata->regulator[i].min_uV == 2200000 &&
8435 pdata->regulator[i].max_uV == 2200000) {
8436 snd_soc_write(codec, TABLA_A_BIAS_REF_CTL,
8437 0x1E);
8438 } else {
8439 pr_err("%s: unsupported CDC_VDDA_RX voltage "
8440 "min %d, max %d\n", __func__,
8441 pdata->regulator[i].min_uV,
8442 pdata->regulator[i].max_uV);
8443 rc = -EINVAL;
8444 }
8445 break;
8446 }
8447 }
Patrick Lai3043fba2011-08-01 14:15:57 -07008448done:
8449 return rc;
8450}
8451
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008452static const struct tabla_reg_mask_val tabla_1_1_reg_defaults[] = {
8453
8454 /* Tabla 1.1 MICBIAS changes */
8455 TABLA_REG_VAL(TABLA_A_MICB_1_INT_RBIAS, 0x24),
8456 TABLA_REG_VAL(TABLA_A_MICB_2_INT_RBIAS, 0x24),
8457 TABLA_REG_VAL(TABLA_A_MICB_3_INT_RBIAS, 0x24),
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008458
8459 /* Tabla 1.1 HPH changes */
8460 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_PA, 0x57),
8461 TABLA_REG_VAL(TABLA_A_RX_HPH_BIAS_LDO, 0x56),
8462
8463 /* Tabla 1.1 EAR PA changes */
8464 TABLA_REG_VAL(TABLA_A_RX_EAR_BIAS_PA, 0xA6),
8465 TABLA_REG_VAL(TABLA_A_RX_EAR_GAIN, 0x02),
8466 TABLA_REG_VAL(TABLA_A_RX_EAR_VCM, 0x03),
8467
8468 /* Tabla 1.1 Lineout_5 Changes */
8469 TABLA_REG_VAL(TABLA_A_RX_LINE_5_GAIN, 0x10),
8470
8471 /* Tabla 1.1 RX Changes */
8472 TABLA_REG_VAL(TABLA_A_CDC_RX1_B5_CTL, 0x78),
8473 TABLA_REG_VAL(TABLA_A_CDC_RX2_B5_CTL, 0x78),
8474 TABLA_REG_VAL(TABLA_A_CDC_RX3_B5_CTL, 0x78),
8475 TABLA_REG_VAL(TABLA_A_CDC_RX4_B5_CTL, 0x78),
8476 TABLA_REG_VAL(TABLA_A_CDC_RX5_B5_CTL, 0x78),
8477 TABLA_REG_VAL(TABLA_A_CDC_RX6_B5_CTL, 0x78),
8478 TABLA_REG_VAL(TABLA_A_CDC_RX7_B5_CTL, 0x78),
8479
8480 /* Tabla 1.1 RX1 and RX2 Changes */
8481 TABLA_REG_VAL(TABLA_A_CDC_RX1_B6_CTL, 0xA0),
8482 TABLA_REG_VAL(TABLA_A_CDC_RX2_B6_CTL, 0xA0),
8483
8484 /* Tabla 1.1 RX3 to RX7 Changes */
8485 TABLA_REG_VAL(TABLA_A_CDC_RX3_B6_CTL, 0x80),
8486 TABLA_REG_VAL(TABLA_A_CDC_RX4_B6_CTL, 0x80),
8487 TABLA_REG_VAL(TABLA_A_CDC_RX5_B6_CTL, 0x80),
8488 TABLA_REG_VAL(TABLA_A_CDC_RX6_B6_CTL, 0x80),
8489 TABLA_REG_VAL(TABLA_A_CDC_RX7_B6_CTL, 0x80),
8490
8491 /* Tabla 1.1 CLASSG Changes */
8492 TABLA_REG_VAL(TABLA_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1B),
8493};
8494
8495static const struct tabla_reg_mask_val tabla_2_0_reg_defaults[] = {
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008496 /* Tabla 2.0 MICBIAS changes */
8497 TABLA_REG_VAL(TABLA_A_MICB_2_MBHC, 0x02),
8498};
8499
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008500static const struct tabla_reg_mask_val tabla_1_x_only_reg_2_0_defaults[] = {
8501 TABLA_REG_VAL(TABLA_1_A_MICB_4_INT_RBIAS, 0x24),
8502};
8503
8504static const struct tabla_reg_mask_val tabla_2_only_reg_2_0_defaults[] = {
8505 TABLA_REG_VAL(TABLA_2_A_MICB_4_INT_RBIAS, 0x24),
8506};
8507
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008508static void tabla_update_reg_defaults(struct snd_soc_codec *codec)
8509{
8510 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308511 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008512
8513 for (i = 0; i < ARRAY_SIZE(tabla_1_1_reg_defaults); i++)
8514 snd_soc_write(codec, tabla_1_1_reg_defaults[i].reg,
8515 tabla_1_1_reg_defaults[i].val);
8516
8517 for (i = 0; i < ARRAY_SIZE(tabla_2_0_reg_defaults); i++)
8518 snd_soc_write(codec, tabla_2_0_reg_defaults[i].reg,
8519 tabla_2_0_reg_defaults[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008520
8521 if (TABLA_IS_1_X(tabla_core->version)) {
8522 for (i = 0; i < ARRAY_SIZE(tabla_1_x_only_reg_2_0_defaults);
8523 i++)
8524 snd_soc_write(codec,
8525 tabla_1_x_only_reg_2_0_defaults[i].reg,
8526 tabla_1_x_only_reg_2_0_defaults[i].val);
8527 } else {
8528 for (i = 0; i < ARRAY_SIZE(tabla_2_only_reg_2_0_defaults); i++)
8529 snd_soc_write(codec,
8530 tabla_2_only_reg_2_0_defaults[i].reg,
8531 tabla_2_only_reg_2_0_defaults[i].val);
8532 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008533}
8534
8535static const struct tabla_reg_mask_val tabla_codec_reg_init_val[] = {
Patrick Laic7cae882011-11-18 11:52:49 -08008536 /* Initialize current threshold to 350MA
8537 * number of wait and run cycles to 4096
8538 */
Patrick Lai49efeac2011-11-03 11:01:12 -07008539 {TABLA_A_RX_HPH_OCP_CTL, 0xE0, 0x60},
Patrick Laic7cae882011-11-18 11:52:49 -08008540 {TABLA_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008541
Santosh Mardi32171012011-10-28 23:32:06 +05308542 {TABLA_A_QFUSE_CTL, 0xFF, 0x03},
8543
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008544 /* Initialize gain registers to use register gain */
8545 {TABLA_A_RX_HPH_L_GAIN, 0x10, 0x10},
8546 {TABLA_A_RX_HPH_R_GAIN, 0x10, 0x10},
8547 {TABLA_A_RX_LINE_1_GAIN, 0x10, 0x10},
8548 {TABLA_A_RX_LINE_2_GAIN, 0x10, 0x10},
8549 {TABLA_A_RX_LINE_3_GAIN, 0x10, 0x10},
8550 {TABLA_A_RX_LINE_4_GAIN, 0x10, 0x10},
8551
Kuirong Wangccb29c62012-06-15 11:09:07 -07008552 /* Set the MICBIAS default output as pull down*/
8553 {TABLA_A_MICB_1_CTL, 0x01, 0x01},
8554 {TABLA_A_MICB_2_CTL, 0x01, 0x01},
8555 {TABLA_A_MICB_3_CTL, 0x01, 0x01},
8556
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008557 /* Initialize mic biases to differential mode */
8558 {TABLA_A_MICB_1_INT_RBIAS, 0x24, 0x24},
8559 {TABLA_A_MICB_2_INT_RBIAS, 0x24, 0x24},
8560 {TABLA_A_MICB_3_INT_RBIAS, 0x24, 0x24},
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008561
8562 {TABLA_A_CDC_CONN_CLSG_CTL, 0x3C, 0x14},
8563
8564 /* Use 16 bit sample size for TX1 to TX6 */
8565 {TABLA_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
8566 {TABLA_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
8567 {TABLA_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
8568 {TABLA_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
8569 {TABLA_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
8570 {TABLA_A_CDC_CONN_TX_SB_B6_CTL, 0x30, 0x20},
8571
8572 /* Use 16 bit sample size for TX7 to TX10 */
8573 {TABLA_A_CDC_CONN_TX_SB_B7_CTL, 0x60, 0x40},
8574 {TABLA_A_CDC_CONN_TX_SB_B8_CTL, 0x60, 0x40},
8575 {TABLA_A_CDC_CONN_TX_SB_B9_CTL, 0x60, 0x40},
8576 {TABLA_A_CDC_CONN_TX_SB_B10_CTL, 0x60, 0x40},
8577
8578 /* Use 16 bit sample size for RX */
8579 {TABLA_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
8580 {TABLA_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0xAA},
8581
8582 /*enable HPF filter for TX paths */
8583 {TABLA_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
8584 {TABLA_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
8585 {TABLA_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
8586 {TABLA_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
8587 {TABLA_A_CDC_TX5_MUX_CTL, 0x8, 0x0},
8588 {TABLA_A_CDC_TX6_MUX_CTL, 0x8, 0x0},
8589 {TABLA_A_CDC_TX7_MUX_CTL, 0x8, 0x0},
8590 {TABLA_A_CDC_TX8_MUX_CTL, 0x8, 0x0},
8591 {TABLA_A_CDC_TX9_MUX_CTL, 0x8, 0x0},
8592 {TABLA_A_CDC_TX10_MUX_CTL, 0x8, 0x0},
Kiran Kandi0ba468f2012-05-08 11:45:05 -07008593
8594 /* config Decimator for DMIC CLK_MODE_1(3.072Mhz@12.88Mhz mclk) */
8595 {TABLA_A_CDC_TX1_DMIC_CTL, 0x1, 0x1},
8596 {TABLA_A_CDC_TX2_DMIC_CTL, 0x1, 0x1},
8597 {TABLA_A_CDC_TX3_DMIC_CTL, 0x1, 0x1},
8598 {TABLA_A_CDC_TX4_DMIC_CTL, 0x1, 0x1},
8599 {TABLA_A_CDC_TX5_DMIC_CTL, 0x1, 0x1},
8600 {TABLA_A_CDC_TX6_DMIC_CTL, 0x1, 0x1},
8601 {TABLA_A_CDC_TX7_DMIC_CTL, 0x1, 0x1},
8602 {TABLA_A_CDC_TX8_DMIC_CTL, 0x1, 0x1},
8603 {TABLA_A_CDC_TX9_DMIC_CTL, 0x1, 0x1},
8604 {TABLA_A_CDC_TX10_DMIC_CTL, 0x1, 0x1},
8605
8606 /* config DMIC clk to CLK_MODE_1 (3.072Mhz@12.88Mhz mclk) */
8607 {TABLA_A_CDC_CLK_DMIC_CTL, 0x2A, 0x2A},
8608
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008609};
8610
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008611static const struct tabla_reg_mask_val tabla_1_x_codec_reg_init_val[] = {
Kuirong Wangccb29c62012-06-15 11:09:07 -07008612 /* Set the MICBIAS default output as pull down*/
8613 {TABLA_1_A_MICB_4_CTL, 0x01, 0x01},
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008614 /* Initialize mic biases to differential mode */
8615 {TABLA_1_A_MICB_4_INT_RBIAS, 0x24, 0x24},
8616};
8617
8618static const struct tabla_reg_mask_val tabla_2_higher_codec_reg_init_val[] = {
Kuirong Wangccb29c62012-06-15 11:09:07 -07008619
8620 /* Set the MICBIAS default output as pull down*/
8621 {TABLA_2_A_MICB_4_CTL, 0x01, 0x01},
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008622 /* Initialize mic biases to differential mode */
8623 {TABLA_2_A_MICB_4_INT_RBIAS, 0x24, 0x24},
8624};
8625
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008626static void tabla_codec_init_reg(struct snd_soc_codec *codec)
8627{
8628 u32 i;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308629 struct wcd9xxx *tabla_core = dev_get_drvdata(codec->dev->parent);
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008630
8631 for (i = 0; i < ARRAY_SIZE(tabla_codec_reg_init_val); i++)
8632 snd_soc_update_bits(codec, tabla_codec_reg_init_val[i].reg,
8633 tabla_codec_reg_init_val[i].mask,
8634 tabla_codec_reg_init_val[i].val);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008635 if (TABLA_IS_1_X(tabla_core->version)) {
8636 for (i = 0; i < ARRAY_SIZE(tabla_1_x_codec_reg_init_val); i++)
8637 snd_soc_update_bits(codec,
8638 tabla_1_x_codec_reg_init_val[i].reg,
8639 tabla_1_x_codec_reg_init_val[i].mask,
8640 tabla_1_x_codec_reg_init_val[i].val);
8641 } else {
8642 for (i = 0; i < ARRAY_SIZE(tabla_2_higher_codec_reg_init_val);
8643 i++)
8644 snd_soc_update_bits(codec,
8645 tabla_2_higher_codec_reg_init_val[i].reg,
8646 tabla_2_higher_codec_reg_init_val[i].mask,
8647 tabla_2_higher_codec_reg_init_val[i].val);
8648 }
8649}
8650
8651static void tabla_update_reg_address(struct tabla_priv *priv)
8652{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308653 struct wcd9xxx *tabla_core = dev_get_drvdata(priv->codec->dev->parent);
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008654 struct tabla_reg_address *reg_addr = &priv->reg_addr;
8655
8656 if (TABLA_IS_1_X(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08008657 reg_addr->micb_4_mbhc = TABLA_1_A_MICB_4_MBHC;
8658 reg_addr->micb_4_int_rbias = TABLA_1_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008659 reg_addr->micb_4_ctl = TABLA_1_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008660 } else if (TABLA_IS_2_0(tabla_core->version)) {
Joonwoo Parkcb7c8922012-02-16 23:12:59 -08008661 reg_addr->micb_4_mbhc = TABLA_2_A_MICB_4_MBHC;
8662 reg_addr->micb_4_int_rbias = TABLA_2_A_MICB_4_INT_RBIAS;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008663 reg_addr->micb_4_ctl = TABLA_2_A_MICB_4_CTL;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008664 }
Kiran Kandi1f6fd722011-08-11 10:36:11 -07008665}
8666
Joonwoo Park179b9ec2012-03-26 10:56:20 -07008667#ifdef CONFIG_DEBUG_FS
8668static int codec_debug_open(struct inode *inode, struct file *file)
8669{
8670 file->private_data = inode->i_private;
8671 return 0;
8672}
8673
8674static ssize_t codec_debug_write(struct file *filp,
8675 const char __user *ubuf, size_t cnt, loff_t *ppos)
8676{
8677 char lbuf[32];
8678 char *buf;
8679 int rc;
8680 struct tabla_priv *tabla = filp->private_data;
8681
8682 if (cnt > sizeof(lbuf) - 1)
8683 return -EINVAL;
8684
8685 rc = copy_from_user(lbuf, ubuf, cnt);
8686 if (rc)
8687 return -EFAULT;
8688
8689 lbuf[cnt] = '\0';
8690 buf = (char *)lbuf;
Joonwoo Park5bbcb0c2012-08-07 17:25:52 -07008691 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
8692 tabla->no_mic_headset_override =
8693 (*strsep(&buf, " ") == '0') ? false : true;
8694 if (tabla->no_mic_headset_override && tabla->mbhc_polling_active) {
8695 tabla_codec_pause_hs_polling(tabla->codec);
8696 tabla_codec_start_hs_polling(tabla->codec);
8697 }
8698 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
8699 return cnt;
Joonwoo Park179b9ec2012-03-26 10:56:20 -07008700}
8701
8702static ssize_t codec_mbhc_debug_read(struct file *file, char __user *buf,
8703 size_t count, loff_t *pos)
8704{
8705 const int size = 768;
8706 char buffer[size];
8707 int n = 0;
8708 struct tabla_priv *tabla = file->private_data;
8709 struct snd_soc_codec *codec = tabla->codec;
8710 const struct mbhc_internal_cal_data *p = &tabla->mbhc_data;
Joonwoo Parkcf473b42012-03-29 19:48:16 -07008711 const s16 v_ins_hu_cur = tabla_get_current_v_ins(tabla, true);
8712 const s16 v_ins_h_cur = tabla_get_current_v_ins(tabla, false);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07008713
8714 n = scnprintf(buffer, size - n, "dce_z = %x(%dmv)\n", p->dce_z,
8715 tabla_codec_sta_dce_v(codec, 1, p->dce_z));
8716 n += scnprintf(buffer + n, size - n, "dce_mb = %x(%dmv)\n",
8717 p->dce_mb, tabla_codec_sta_dce_v(codec, 1, p->dce_mb));
8718 n += scnprintf(buffer + n, size - n, "sta_z = %x(%dmv)\n",
8719 p->sta_z, tabla_codec_sta_dce_v(codec, 0, p->sta_z));
8720 n += scnprintf(buffer + n, size - n, "sta_mb = %x(%dmv)\n",
8721 p->sta_mb, tabla_codec_sta_dce_v(codec, 0, p->sta_mb));
8722 n += scnprintf(buffer + n, size - n, "t_dce = %x\n", p->t_dce);
8723 n += scnprintf(buffer + n, size - n, "t_sta = %x\n", p->t_sta);
8724 n += scnprintf(buffer + n, size - n, "micb_mv = %dmv\n",
8725 p->micb_mv);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07008726 n += scnprintf(buffer + n, size - n, "v_ins_hu = %x(%dmv)%s\n",
Joonwoo Park179b9ec2012-03-26 10:56:20 -07008727 p->v_ins_hu,
Joonwoo Parkcf473b42012-03-29 19:48:16 -07008728 tabla_codec_sta_dce_v(codec, 0, p->v_ins_hu),
8729 p->v_ins_hu == v_ins_hu_cur ? "*" : "");
8730 n += scnprintf(buffer + n, size - n, "v_ins_h = %x(%dmv)%s\n",
8731 p->v_ins_h, tabla_codec_sta_dce_v(codec, 1, p->v_ins_h),
8732 p->v_ins_h == v_ins_h_cur ? "*" : "");
8733 n += scnprintf(buffer + n, size - n, "adj_v_ins_hu = %x(%dmv)%s\n",
8734 p->adj_v_ins_hu,
8735 tabla_codec_sta_dce_v(codec, 0, p->adj_v_ins_hu),
8736 p->adj_v_ins_hu == v_ins_hu_cur ? "*" : "");
8737 n += scnprintf(buffer + n, size - n, "adj_v_ins_h = %x(%dmv)%s\n",
8738 p->adj_v_ins_h,
8739 tabla_codec_sta_dce_v(codec, 1, p->adj_v_ins_h),
8740 p->adj_v_ins_h == v_ins_h_cur ? "*" : "");
Joonwoo Park179b9ec2012-03-26 10:56:20 -07008741 n += scnprintf(buffer + n, size - n, "v_b1_hu = %x(%dmv)\n",
8742 p->v_b1_hu, tabla_codec_sta_dce_v(codec, 0, p->v_b1_hu));
8743 n += scnprintf(buffer + n, size - n, "v_b1_h = %x(%dmv)\n",
8744 p->v_b1_h, tabla_codec_sta_dce_v(codec, 1, p->v_b1_h));
8745 n += scnprintf(buffer + n, size - n, "v_b1_huc = %x(%dmv)\n",
8746 p->v_b1_huc,
8747 tabla_codec_sta_dce_v(codec, 1, p->v_b1_huc));
8748 n += scnprintf(buffer + n, size - n, "v_brh = %x(%dmv)\n",
8749 p->v_brh, tabla_codec_sta_dce_v(codec, 1, p->v_brh));
8750 n += scnprintf(buffer + n, size - n, "v_brl = %x(%dmv)\n", p->v_brl,
8751 tabla_codec_sta_dce_v(codec, 0, p->v_brl));
8752 n += scnprintf(buffer + n, size - n, "v_no_mic = %x(%dmv)\n",
8753 p->v_no_mic,
8754 tabla_codec_sta_dce_v(codec, 0, p->v_no_mic));
8755 n += scnprintf(buffer + n, size - n, "npoll = %d\n", p->npoll);
8756 n += scnprintf(buffer + n, size - n, "nbounce_wait = %d\n",
8757 p->nbounce_wait);
Joonwoo Parkcf473b42012-03-29 19:48:16 -07008758 n += scnprintf(buffer + n, size - n, "v_inval_ins_low = %d\n",
8759 p->v_inval_ins_low);
8760 n += scnprintf(buffer + n, size - n, "v_inval_ins_high = %d\n",
8761 p->v_inval_ins_high);
Joonwoo Park2cc13f02012-05-09 12:44:25 -07008762 if (tabla->mbhc_cfg.gpio)
8763 n += scnprintf(buffer + n, size - n, "GPIO insert = %d\n",
8764 tabla_hs_gpio_level_remove(tabla));
Joonwoo Park179b9ec2012-03-26 10:56:20 -07008765 buffer[n] = 0;
8766
8767 return simple_read_from_buffer(buf, count, pos, buffer, n);
8768}
8769
8770static const struct file_operations codec_debug_ops = {
8771 .open = codec_debug_open,
8772 .write = codec_debug_write,
8773};
8774
8775static const struct file_operations codec_mbhc_debug_ops = {
8776 .open = codec_debug_open,
8777 .read = codec_mbhc_debug_read,
8778};
8779#endif
8780
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008781static int tabla_codec_probe(struct snd_soc_codec *codec)
8782{
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308783 struct wcd9xxx *control;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008784 struct tabla_priv *tabla;
8785 struct snd_soc_dapm_context *dapm = &codec->dapm;
8786 int ret = 0;
8787 int i;
Kuirong Wang906ac472012-07-09 12:54:44 -07008788 void *ptr = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008789
8790 codec->control_data = dev_get_drvdata(codec->dev->parent);
8791 control = codec->control_data;
8792
8793 tabla = kzalloc(sizeof(struct tabla_priv), GFP_KERNEL);
8794 if (!tabla) {
8795 dev_err(codec->dev, "Failed to allocate private data\n");
8796 return -ENOMEM;
8797 }
Kiran Kandid8cf5212012-03-02 15:34:53 -08008798 for (i = 0 ; i < NUM_DECIMATORS; i++) {
8799 tx_hpf_work[i].tabla = tabla;
8800 tx_hpf_work[i].decimator = i + 1;
8801 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
8802 tx_hpf_corner_freq_callback);
8803 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008804
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07008805 /* Make sure mbhc micbias register addresses are zeroed out */
8806 memset(&tabla->mbhc_bias_regs, 0,
8807 sizeof(struct mbhc_micbias_regs));
Bhalchandra Gajared9ebb6c2011-10-03 19:54:41 -07008808 tabla->mbhc_micbias_switched = false;
Bhalchandra Gajare02d90cd2011-09-30 16:14:00 -07008809
Joonwoo Park0976d012011-12-22 11:48:18 -08008810 /* Make sure mbhc intenal calibration data is zeroed out */
8811 memset(&tabla->mbhc_data, 0,
8812 sizeof(struct mbhc_internal_cal_data));
Joonwoo Park433149a2012-01-11 09:53:54 -08008813 tabla->mbhc_data.t_sta_dce = DEFAULT_DCE_STA_WAIT;
Joonwoo Park0976d012011-12-22 11:48:18 -08008814 tabla->mbhc_data.t_dce = DEFAULT_DCE_WAIT;
8815 tabla->mbhc_data.t_sta = DEFAULT_STA_WAIT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008816 snd_soc_codec_set_drvdata(codec, tabla);
8817
Kiran Kandi6fae8bf2011-08-15 10:36:42 -07008818 tabla->mclk_enabled = false;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008819 tabla->bandgap_type = TABLA_BANDGAP_OFF;
8820 tabla->clock_active = false;
8821 tabla->config_mode_active = false;
8822 tabla->mbhc_polling_active = false;
Joonwoo Parkf4267c22012-01-10 13:25:24 -08008823 tabla->mbhc_fake_ins_start = 0;
Bradley Rubincb3950a2011-08-18 13:07:26 -07008824 tabla->no_mic_headset_override = false;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008825 tabla->hs_polling_irq_prepared = false;
8826 mutex_init(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008827 tabla->codec = codec;
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07008828 tabla->mbhc_state = MBHC_STATE_NONE;
Joonwoo Park03324832012-03-19 19:36:16 -07008829 tabla->mbhc_last_resume = 0;
Kuirong Wang0f8ade32012-02-27 16:29:45 -08008830 for (i = 0; i < COMPANDER_MAX; i++) {
8831 tabla->comp_enabled[i] = 0;
8832 tabla->comp_fs[i] = COMPANDER_FS_48KHZ;
8833 }
Patrick Lai3043fba2011-08-01 14:15:57 -07008834 tabla->pdata = dev_get_platdata(codec->dev->parent);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308835 tabla->intf_type = wcd9xxx_get_intf_type();
Bhalchandra Gajareb0f15132012-02-07 15:00:21 -08008836 tabla->aux_pga_cnt = 0;
8837 tabla->aux_l_gain = 0x1F;
8838 tabla->aux_r_gain = 0x1F;
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008839 tabla_update_reg_address(tabla);
Santosh Mardi22920282011-10-26 02:38:40 +05308840 tabla_update_reg_defaults(codec);
8841 tabla_codec_init_reg(codec);
Santosh Mardi22920282011-10-26 02:38:40 +05308842 ret = tabla_handle_pdata(tabla);
Patrick Lai3043fba2011-08-01 14:15:57 -07008843 if (IS_ERR_VALUE(ret)) {
8844 pr_err("%s: bad pdata\n", __func__);
8845 goto err_pdata;
8846 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008847
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008848 if (TABLA_IS_1_X(control->version))
Steve Mucklef132c6c2012-06-06 18:30:57 -07008849 snd_soc_add_codec_controls(codec, tabla_1_x_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008850 ARRAY_SIZE(tabla_1_x_snd_controls));
8851 else
Steve Mucklef132c6c2012-06-06 18:30:57 -07008852 snd_soc_add_codec_controls(codec, tabla_2_higher_snd_controls,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008853 ARRAY_SIZE(tabla_2_higher_snd_controls));
8854
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008855 if (TABLA_IS_1_X(control->version))
8856 snd_soc_dapm_new_controls(dapm, tabla_1_x_dapm_widgets,
8857 ARRAY_SIZE(tabla_1_x_dapm_widgets));
8858 else
8859 snd_soc_dapm_new_controls(dapm, tabla_2_higher_dapm_widgets,
8860 ARRAY_SIZE(tabla_2_higher_dapm_widgets));
8861
Kuirong Wang906ac472012-07-09 12:54:44 -07008862 ptr = kmalloc((sizeof(tabla_rx_chs) +
8863 sizeof(tabla_tx_chs)), GFP_KERNEL);
8864 if (!ptr) {
8865 pr_err("%s: no mem for slim chan ctl data\n", __func__);
8866 ret = -ENOMEM;
8867 goto err_nomem_slimch;
8868 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308869 if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Santosh Mardie15e2302011-11-15 10:39:23 +05308870 snd_soc_dapm_new_controls(dapm, tabla_dapm_i2s_widgets,
8871 ARRAY_SIZE(tabla_dapm_i2s_widgets));
8872 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
8873 ARRAY_SIZE(audio_i2s_map));
Kuirong Wang906ac472012-07-09 12:54:44 -07008874 for (i = 0; i < ARRAY_SIZE(tabla_i2s_dai); i++)
8875 INIT_LIST_HEAD(&tabla->dai[i].wcd9xxx_ch_list);
8876 } else if (tabla->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
8877 for (i = 0; i < NUM_CODEC_DAIS; i++) {
8878 INIT_LIST_HEAD(&tabla->dai[i].wcd9xxx_ch_list);
8879 init_waitqueue_head(&tabla->dai[i].dai_wait);
8880 }
Santosh Mardie15e2302011-11-15 10:39:23 +05308881 }
Kuirong Wang906ac472012-07-09 12:54:44 -07008882
8883 control->num_rx_port = TABLA_RX_MAX;
8884 control->rx_chs = ptr;
8885 memcpy(control->rx_chs, tabla_rx_chs, sizeof(tabla_rx_chs));
8886 control->num_tx_port = TABLA_TX_MAX;
8887 control->tx_chs = ptr + sizeof(tabla_rx_chs);
8888 memcpy(control->tx_chs, tabla_tx_chs, sizeof(tabla_tx_chs));
8889
Kiran Kandi8b3a8302011-09-27 16:13:28 -07008890
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008891 if (TABLA_IS_1_X(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08008892 snd_soc_dapm_add_routes(dapm, tabla_1_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008893 ARRAY_SIZE(tabla_1_x_lineout_2_to_4_map));
8894 } else if (TABLA_IS_2_0(control->version)) {
Kiran Kandi7a9fd902011-11-14 13:51:45 -08008895 snd_soc_dapm_add_routes(dapm, tabla_2_x_lineout_2_to_4_map,
Joonwoo Park6c1ebb62012-01-16 19:08:43 -08008896 ARRAY_SIZE(tabla_2_x_lineout_2_to_4_map));
Kiran Kandi7a9fd902011-11-14 13:51:45 -08008897 } else {
8898 pr_err("%s : ERROR. Unsupported Tabla version 0x%2x\n",
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308899 __func__, control->version);
Kiran Kandi7a9fd902011-11-14 13:51:45 -08008900 goto err_pdata;
8901 }
8902
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008903 snd_soc_dapm_sync(dapm);
8904
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008905 ret = wcd9xxx_request_irq(codec->control_data,
8906 WCD9XXX_IRQ_MBHC_INSERTION,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008907 tabla_hs_insert_irq, "Headset insert detect", tabla);
8908 if (ret) {
8909 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008910 WCD9XXX_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008911 goto err_insert_irq;
8912 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008913 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008914
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008915 ret = wcd9xxx_request_irq(codec->control_data,
8916 WCD9XXX_IRQ_MBHC_REMOVAL,
8917 tabla_hs_remove_irq,
8918 "Headset remove detect", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008919 if (ret) {
8920 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008921 WCD9XXX_IRQ_MBHC_REMOVAL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008922 goto err_remove_irq;
8923 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008924
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008925 ret = wcd9xxx_request_irq(codec->control_data,
8926 WCD9XXX_IRQ_MBHC_POTENTIAL,
8927 tabla_dce_handler, "DC Estimation detect",
8928 tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008929 if (ret) {
8930 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008931 WCD9XXX_IRQ_MBHC_POTENTIAL);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008932 goto err_potential_irq;
8933 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008934
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008935 ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE,
8936 tabla_release_handler,
8937 "Button Release detect", tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07008938 if (ret) {
8939 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008940 WCD9XXX_IRQ_MBHC_RELEASE);
Bradley Rubincb1e2732011-06-23 16:49:20 -07008941 goto err_release_irq;
8942 }
8943
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008944 ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
8945 tabla_slimbus_irq, "SLIMBUS Slave", tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008946 if (ret) {
8947 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008948 WCD9XXX_IRQ_SLIMBUS);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008949 goto err_slimbus_irq;
8950 }
8951
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308952 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
8953 wcd9xxx_interface_reg_write(codec->control_data,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07008954 TABLA_SLIM_PGD_PORT_INT_EN0 + i, 0xFF);
8955
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308956 ret = wcd9xxx_request_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008957 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT,
8958 tabla_hphl_ocp_irq,
8959 "HPH_L OCP detect", tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07008960 if (ret) {
8961 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008962 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07008963 goto err_hphl_ocp_irq;
8964 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008965 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPL_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07008966
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05308967 ret = wcd9xxx_request_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008968 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT,
8969 tabla_hphr_ocp_irq,
8970 "HPH_R OCP detect", tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07008971 if (ret) {
8972 pr_err("%s: Failed to request irq %d\n", __func__,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008973 WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Patrick Lai49efeac2011-11-03 11:01:12 -07008974 goto err_hphr_ocp_irq;
8975 }
Joonwoo Parkf6574c72012-10-10 17:29:57 -07008976 wcd9xxx_disable_irq(codec->control_data, WCD9XXX_IRQ_HPH_PA_OCPR_FAULT);
Joonwoo Parkecf379c2012-10-04 16:57:52 -07008977
8978 /*
8979 * Register suspend lock and notifier to resend edge triggered
8980 * gpio IRQs
8981 */
8982 wake_lock_init(&tabla->irq_resend_wlock, WAKE_LOCK_SUSPEND,
8983 "tabla_gpio_irq_resend");
8984 tabla->gpio_irq_resend = false;
8985
Damir Didjustoc6f83cb2012-12-03 00:54:14 -08008986 mutex_lock(&dapm->codec->mutex);
8987 snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
8988 snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
8989 snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
8990 snd_soc_dapm_sync(dapm);
8991 mutex_unlock(&dapm->codec->mutex);
Patrick Lai49efeac2011-11-03 11:01:12 -07008992
Bradley Rubincb3950a2011-08-18 13:07:26 -07008993#ifdef CONFIG_DEBUG_FS
Joonwoo Park179b9ec2012-03-26 10:56:20 -07008994 if (ret == 0) {
8995 tabla->debugfs_poke =
8996 debugfs_create_file("TRRS", S_IFREG | S_IRUGO, NULL, tabla,
8997 &codec_debug_ops);
8998 tabla->debugfs_mbhc =
8999 debugfs_create_file("tabla_mbhc", S_IFREG | S_IRUGO,
9000 NULL, tabla, &codec_mbhc_debug_ops);
9001 }
Bradley Rubincb3950a2011-08-18 13:07:26 -07009002#endif
Steve Mucklef132c6c2012-06-06 18:30:57 -07009003 codec->ignore_pmdown_time = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009004 return ret;
9005
Patrick Lai49efeac2011-11-03 11:01:12 -07009006err_hphr_ocp_irq:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05309007 wcd9xxx_free_irq(codec->control_data,
Joonwoo Parkf6574c72012-10-10 17:29:57 -07009008 WCD9XXX_IRQ_HPH_PA_OCPL_FAULT, tabla);
Patrick Lai49efeac2011-11-03 11:01:12 -07009009err_hphl_ocp_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07009010 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009011err_slimbus_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07009012 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
Bradley Rubincb1e2732011-06-23 16:49:20 -07009013err_release_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07009014 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
9015 tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009016err_potential_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07009017 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009018err_remove_irq:
Joonwoo Parkf6574c72012-10-10 17:29:57 -07009019 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
9020 tabla);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009021err_insert_irq:
Patrick Lai3043fba2011-08-01 14:15:57 -07009022err_pdata:
Kuirong Wang906ac472012-07-09 12:54:44 -07009023 kfree(ptr);
9024err_nomem_slimch:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07009025 mutex_destroy(&tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009026 kfree(tabla);
9027 return ret;
9028}
9029static int tabla_codec_remove(struct snd_soc_codec *codec)
9030{
9031 struct tabla_priv *tabla = snd_soc_codec_get_drvdata(codec);
Joonwoo Parkecf379c2012-10-04 16:57:52 -07009032
9033 wake_lock_destroy(&tabla->irq_resend_wlock);
9034
Joonwoo Parkf6574c72012-10-10 17:29:57 -07009035 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tabla);
9036 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_RELEASE, tabla);
9037 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_POTENTIAL,
9038 tabla);
9039 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_REMOVAL, tabla);
9040 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_MBHC_INSERTION,
9041 tabla);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07009042 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009043 tabla_codec_disable_clock_block(codec);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07009044 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009045 tabla_codec_enable_bandgap(codec, TABLA_BANDGAP_OFF);
Patrick Lai64b43262011-12-06 17:29:15 -08009046 if (tabla->mbhc_fw)
9047 release_firmware(tabla->mbhc_fw);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07009048 mutex_destroy(&tabla->codec_resource_lock);
Joonwoo Park179b9ec2012-03-26 10:56:20 -07009049#ifdef CONFIG_DEBUG_FS
9050 debugfs_remove(tabla->debugfs_poke);
9051 debugfs_remove(tabla->debugfs_mbhc);
9052#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009053 kfree(tabla);
9054 return 0;
9055}
9056static struct snd_soc_codec_driver soc_codec_dev_tabla = {
9057 .probe = tabla_codec_probe,
9058 .remove = tabla_codec_remove,
9059 .read = tabla_read,
9060 .write = tabla_write,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009061 .readable_register = tabla_readable,
9062 .volatile_register = tabla_volatile,
9063
9064 .reg_cache_size = TABLA_CACHE_SIZE,
9065 .reg_cache_default = tabla_reg_defaults,
9066 .reg_word_size = 1,
Steve Mucklef132c6c2012-06-06 18:30:57 -07009067 .controls = tabla_snd_controls,
9068 .num_controls = ARRAY_SIZE(tabla_snd_controls),
9069 .dapm_widgets = tabla_dapm_widgets,
9070 .num_dapm_widgets = ARRAY_SIZE(tabla_dapm_widgets),
9071 .dapm_routes = audio_map,
9072 .num_dapm_routes = ARRAY_SIZE(audio_map),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009073};
Bradley Rubincb3950a2011-08-18 13:07:26 -07009074
Joonwoo Park8b1f0982011-12-08 17:12:45 -08009075#ifdef CONFIG_PM
9076static int tabla_suspend(struct device *dev)
9077{
Joonwoo Park816b8e62012-01-23 16:03:21 -08009078 dev_dbg(dev, "%s: system suspend\n", __func__);
9079 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08009080}
9081
9082static int tabla_resume(struct device *dev)
9083{
Joonwoo Parkecf379c2012-10-04 16:57:52 -07009084 int irq;
Joonwoo Park03324832012-03-19 19:36:16 -07009085 struct platform_device *pdev = to_platform_device(dev);
9086 struct tabla_priv *tabla = platform_get_drvdata(pdev);
Joonwoo Parkecf379c2012-10-04 16:57:52 -07009087
Joonwoo Parkd6e48bd2012-09-20 11:14:15 -07009088 dev_dbg(dev, "%s: system resume tabla %p\n", __func__, tabla);
Joonwoo Parkecf379c2012-10-04 16:57:52 -07009089 if (tabla) {
9090 TABLA_ACQUIRE_LOCK(tabla->codec_resource_lock);
Joonwoo Parkd6e48bd2012-09-20 11:14:15 -07009091 tabla->mbhc_last_resume = jiffies;
Joonwoo Parkecf379c2012-10-04 16:57:52 -07009092 if (tabla->gpio_irq_resend) {
9093 WARN_ON(!tabla->mbhc_cfg.gpio_irq);
9094 tabla->gpio_irq_resend = false;
9095
9096 irq = tabla->mbhc_cfg.gpio_irq;
9097 pr_debug("%s: Resending GPIO IRQ %d\n", __func__, irq);
9098 irq_set_pending(irq);
9099 check_irq_resend(irq_to_desc(irq), irq);
9100
9101 /* release suspend lock */
9102 wake_unlock(&tabla->irq_resend_wlock);
9103 }
9104 TABLA_RELEASE_LOCK(tabla->codec_resource_lock);
9105 }
9106
Joonwoo Park816b8e62012-01-23 16:03:21 -08009107 return 0;
Joonwoo Park8b1f0982011-12-08 17:12:45 -08009108}
9109
9110static const struct dev_pm_ops tabla_pm_ops = {
9111 .suspend = tabla_suspend,
9112 .resume = tabla_resume,
9113};
9114#endif
9115
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009116static int __devinit tabla_probe(struct platform_device *pdev)
9117{
Santosh Mardie15e2302011-11-15 10:39:23 +05309118 int ret = 0;
Steve Mucklef132c6c2012-06-06 18:30:57 -07009119 pr_err("tabla_probe\n");
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05309120 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
Santosh Mardie15e2302011-11-15 10:39:23 +05309121 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
9122 tabla_dai, ARRAY_SIZE(tabla_dai));
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +05309123 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
Santosh Mardie15e2302011-11-15 10:39:23 +05309124 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tabla,
9125 tabla_i2s_dai, ARRAY_SIZE(tabla_i2s_dai));
9126 return ret;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009127}
9128static int __devexit tabla_remove(struct platform_device *pdev)
9129{
9130 snd_soc_unregister_codec(&pdev->dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009131 return 0;
9132}
9133static struct platform_driver tabla_codec_driver = {
9134 .probe = tabla_probe,
9135 .remove = tabla_remove,
9136 .driver = {
9137 .name = "tabla_codec",
9138 .owner = THIS_MODULE,
Joonwoo Park8b1f0982011-12-08 17:12:45 -08009139#ifdef CONFIG_PM
9140 .pm = &tabla_pm_ops,
9141#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009142 },
9143};
9144
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08009145static struct platform_driver tabla1x_codec_driver = {
9146 .probe = tabla_probe,
9147 .remove = tabla_remove,
9148 .driver = {
9149 .name = "tabla1x_codec",
9150 .owner = THIS_MODULE,
9151#ifdef CONFIG_PM
9152 .pm = &tabla_pm_ops,
9153#endif
9154 },
9155};
9156
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009157static int __init tabla_codec_init(void)
9158{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08009159 int rtn = platform_driver_register(&tabla_codec_driver);
9160 if (rtn == 0) {
9161 rtn = platform_driver_register(&tabla1x_codec_driver);
9162 if (rtn != 0)
9163 platform_driver_unregister(&tabla_codec_driver);
9164 }
9165 return rtn;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009166}
9167
9168static void __exit tabla_codec_exit(void)
9169{
Kuirong Wangcd4b6da2012-01-16 22:54:45 -08009170 platform_driver_unregister(&tabla1x_codec_driver);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009171 platform_driver_unregister(&tabla_codec_driver);
9172}
9173
9174module_init(tabla_codec_init);
9175module_exit(tabla_codec_exit);
9176
9177MODULE_DESCRIPTION("Tabla codec driver");
9178MODULE_VERSION("1.0");
9179MODULE_LICENSE("GPL v2");