blob: 669f8e3a0b00dd94edbb464fb3ba5542a52f4031 [file] [log] [blame]
Banajit Goswamieb1fa162013-02-05 15:11:27 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002 *
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>
14#include <linux/firmware.h>
15#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/device.h>
18#include <linux/printk.h>
19#include <linux/ratelimit.h>
20#include <linux/debugfs.h>
Bhalchandra Gajareea898742013-03-05 18:15:53 -080021#include <linux/wait.h>
22#include <linux/bitops.h>
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080023#include <linux/mfd/wcd9xxx/core.h>
24#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
25#include <linux/mfd/wcd9xxx/wcd9306_registers.h>
26#include <linux/mfd/wcd9xxx/pdata.h>
27#include <sound/pcm.h>
28#include <sound/pcm_params.h>
29#include <sound/soc.h>
30#include <sound/soc-dapm.h>
31#include <sound/tlv.h>
32#include <linux/bitops.h>
33#include <linux/delay.h>
34#include <linux/pm_runtime.h>
35#include <linux/kernel.h>
36#include <linux/gpio.h>
37#include "wcd9306.h"
38#include "wcd9xxx-resmgr.h"
Bhalchandra Gajareea898742013-03-05 18:15:53 -080039#include "wcd9xxx-common.h"
40
41static atomic_t kp_tapan_priv;
42static int spkr_drv_wrnd_param_set(const char *val,
43 const struct kernel_param *kp);
44static int spkr_drv_wrnd = 1;
45
46static struct kernel_param_ops spkr_drv_wrnd_param_ops = {
47 .set = spkr_drv_wrnd_param_set,
48 .get = param_get_int,
49};
50module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
51MODULE_PARM_DESC(spkr_drv_wrnd,
52 "Run software workaround to avoid leakage on the speaker drive");
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080053
54#define WCD9306_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
55 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
56 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
57
58#define NUM_DECIMATORS 4
59#define NUM_INTERPOLATORS 4
60#define BITS_PER_REG 8
Bhalchandra Gajareea898742013-03-05 18:15:53 -080061/* This actual number of TX ports supported in slimbus slave */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080062#define TAPAN_TX_PORT_NUMBER 16
Kuirong Wang80aca0d2013-05-09 14:51:09 -070063#define TAPAN_RX_PORT_START_NUMBER 16
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080064
Bhalchandra Gajareea898742013-03-05 18:15:53 -080065/* Nummer of TX ports actually connected from Slimbus slave to codec Digital */
66#define TAPAN_SLIM_CODEC_TX_PORTS 5
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080067
Bhalchandra Gajareea898742013-03-05 18:15:53 -080068#define TAPAN_I2S_MASTER_MODE_MASK 0x08
69#define TAPAN_MCLK_CLK_12P288MHZ 12288000
70#define TAPAN_MCLK_CLK_9P6HZ 9600000
71
72#define TAPAN_SLIM_CLOSE_TIMEOUT 1000
73#define TAPAN_SLIM_IRQ_OVERFLOW (1 << 0)
74#define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
75#define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
76#define TAPAN_MCLK_CLK_12P288MHZ 12288000
77#define TAPAN_MCLK_CLK_9P6HZ 9600000
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080078enum {
79 AIF1_PB = 0,
80 AIF1_CAP,
81 AIF2_PB,
82 AIF2_CAP,
83 AIF3_PB,
84 AIF3_CAP,
85 NUM_CODEC_DAIS,
86};
87
88enum {
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,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080099 RX_MIX1_INP_SEL_AUXRX,
100};
101
102#define TAPAN_COMP_DIGITAL_GAIN_OFFSET 3
103
104static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
105static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
106static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
107static struct snd_soc_dai_driver tapan_dai[];
108static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
109
110/* Codec supports 2 IIR filters */
111enum {
112 IIR1 = 0,
113 IIR2,
114 IIR_MAX,
115};
116/* Codec supports 5 bands */
117enum {
118 BAND1 = 0,
119 BAND2,
120 BAND3,
121 BAND4,
122 BAND5,
123 BAND_MAX,
124};
125
126enum {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800127 COMPANDER_0,
128 COMPANDER_1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800129 COMPANDER_2,
130 COMPANDER_MAX,
131};
132
133enum {
134 COMPANDER_FS_8KHZ = 0,
135 COMPANDER_FS_16KHZ,
136 COMPANDER_FS_32KHZ,
137 COMPANDER_FS_48KHZ,
138 COMPANDER_FS_96KHZ,
139 COMPANDER_FS_192KHZ,
140 COMPANDER_FS_MAX,
141};
142
143struct comp_sample_dependent_params {
144 u32 peak_det_timeout;
145 u32 rms_meter_div_fact;
146 u32 rms_meter_resamp_fact;
147};
148
149struct hpf_work {
150 struct tapan_priv *tapan;
151 u32 decimator;
152 u8 tx_hpf_cut_of_freq;
153 struct delayed_work dwork;
154};
155
156static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
157
158static const struct wcd9xxx_ch tapan_rx_chs[TAPAN_RX_MAX] = {
Kuirong Wang80aca0d2013-05-09 14:51:09 -0700159 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER, 0),
160 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 1, 1),
161 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 2, 2),
162 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 3, 3),
163 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 4, 4),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800164};
165
166static const struct wcd9xxx_ch tapan_tx_chs[TAPAN_TX_MAX] = {
167 WCD9XXX_CH(0, 0),
168 WCD9XXX_CH(1, 1),
169 WCD9XXX_CH(2, 2),
170 WCD9XXX_CH(3, 3),
171 WCD9XXX_CH(4, 4),
172};
173
174static const u32 vport_check_table[NUM_CODEC_DAIS] = {
175 0, /* AIF1_PB */
176 (1 << AIF2_CAP) | (1 << AIF3_CAP), /* AIF1_CAP */
177 0, /* AIF2_PB */
178 (1 << AIF1_CAP) | (1 << AIF3_CAP), /* AIF2_CAP */
179 0, /* AIF2_PB */
180 (1 << AIF1_CAP) | (1 << AIF2_CAP), /* AIF2_CAP */
181};
182
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800183static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
184 0, /* AIF1_PB */
185 0, /* AIF1_CAP */
186};
187
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800188struct tapan_priv {
189 struct snd_soc_codec *codec;
190 u32 adc_count;
191 u32 rx_bias_count;
192 s32 dmic_1_2_clk_cnt;
193 s32 dmic_3_4_clk_cnt;
194 s32 dmic_5_6_clk_cnt;
195
196 u32 anc_slot;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700197 bool anc_func;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800198
199 /*track tapan interface type*/
200 u8 intf_type;
201
202 /* num of slim ports required */
203 struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
204
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800205 /*compander*/
206 int comp_enabled[COMPANDER_MAX];
207 u32 comp_fs[COMPANDER_MAX];
208
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800209 /* Maintain the status of AUX PGA */
210 int aux_pga_cnt;
211 u8 aux_l_gain;
212 u8 aux_r_gain;
213
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800214 bool spkr_pa_widget_on;
215
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800216 /* resmgr module */
217 struct wcd9xxx_resmgr resmgr;
218 /* mbhc module */
219 struct wcd9xxx_mbhc mbhc;
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800220
221 /* class h specific data */
222 struct wcd9xxx_clsh_cdc_data clsh_d;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800223};
224
225static const u32 comp_shift[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800226 4, /* Compander 0's clock source is on interpolator 7 */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800227 0,
228 2,
229};
230
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800231static const int comp_rx_path[] = {
232 COMPANDER_1,
233 COMPANDER_1,
234 COMPANDER_2,
235 COMPANDER_2,
236 COMPANDER_2,
237 COMPANDER_2,
238 COMPANDER_0,
239 COMPANDER_MAX,
240};
241
242static const struct comp_sample_dependent_params comp_samp_params[] = {
243 {
244 /* 8 Khz */
245 .peak_det_timeout = 0x02,
246 .rms_meter_div_fact = 0x09,
247 .rms_meter_resamp_fact = 0x06,
248 },
249 {
250 /* 16 Khz */
251 .peak_det_timeout = 0x03,
252 .rms_meter_div_fact = 0x0A,
253 .rms_meter_resamp_fact = 0x0C,
254 },
255 {
256 /* 32 Khz */
257 .peak_det_timeout = 0x05,
258 .rms_meter_div_fact = 0x0B,
259 .rms_meter_resamp_fact = 0x1E,
260 },
261 {
262 /* 48 Khz */
263 .peak_det_timeout = 0x05,
264 .rms_meter_div_fact = 0x0B,
265 .rms_meter_resamp_fact = 0x28,
266 },
267 {
268 /* 96 Khz */
269 .peak_det_timeout = 0x06,
270 .rms_meter_div_fact = 0x0C,
271 .rms_meter_resamp_fact = 0x50,
272 },
273 {
274 /* 192 Khz */
275 .peak_det_timeout = 0x07,
276 .rms_meter_div_fact = 0xD,
277 .rms_meter_resamp_fact = 0xA0,
278 },
279};
280
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800281static unsigned short rx_digital_gain_reg[] = {
282 TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
283 TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
284 TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL,
285 TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
286};
287
288static unsigned short tx_digital_gain_reg[] = {
289 TAPAN_A_CDC_TX1_VOL_CTL_GAIN,
290 TAPAN_A_CDC_TX2_VOL_CTL_GAIN,
291 TAPAN_A_CDC_TX3_VOL_CTL_GAIN,
292 TAPAN_A_CDC_TX4_VOL_CTL_GAIN,
293};
294
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800295static int spkr_drv_wrnd_param_set(const char *val,
296 const struct kernel_param *kp)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800297{
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800298 struct snd_soc_codec *codec;
299 int ret, old;
300 struct tapan_priv *priv;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800301
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800302 priv = (struct tapan_priv *)atomic_read(&kp_tapan_priv);
303 if (!priv) {
304 pr_debug("%s: codec isn't yet registered\n", __func__);
305 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800306 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800307
308 WCD9XXX_BCL_LOCK(&priv->resmgr);
309 old = spkr_drv_wrnd;
310 ret = param_set_int(val, kp);
311 if (ret) {
312 WCD9XXX_BCL_UNLOCK(&priv->resmgr);
313 return ret;
314 }
315
316 codec = priv->codec;
317 dev_dbg(codec->dev, "%s: spkr_drv_wrnd %d -> %d\n",
318 __func__, old, spkr_drv_wrnd);
319 if (old == 0 && spkr_drv_wrnd == 1) {
320 wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
321 WCD9XXX_BANDGAP_AUDIO_MODE);
322 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
323 } else if (old == 1 && spkr_drv_wrnd == 0) {
324 wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
325 WCD9XXX_BANDGAP_AUDIO_MODE);
326 if (!priv->spkr_pa_widget_on)
327 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
328 0x00);
329 }
330
331 WCD9XXX_BCL_UNLOCK(&priv->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800332 return 0;
333}
334
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800335static int tapan_get_anc_slot(struct snd_kcontrol *kcontrol,
336 struct snd_ctl_elem_value *ucontrol)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800337{
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800338 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
339 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
340 ucontrol->value.integer.value[0] = tapan->anc_slot;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800341 return 0;
342}
343
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800344static int tapan_put_anc_slot(struct snd_kcontrol *kcontrol,
345 struct snd_ctl_elem_value *ucontrol)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800346{
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800347 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
348 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
349 tapan->anc_slot = ucontrol->value.integer.value[0];
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800350 return 0;
351}
352
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700353static int tapan_get_anc_func(struct snd_kcontrol *kcontrol,
354 struct snd_ctl_elem_value *ucontrol)
355{
356 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
357 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
358
359 ucontrol->value.integer.value[0] = (tapan->anc_func == true ? 1 : 0);
360 return 0;
361}
362
363static int tapan_put_anc_func(struct snd_kcontrol *kcontrol,
364 struct snd_ctl_elem_value *ucontrol)
365{
366 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
367 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
368 struct snd_soc_dapm_context *dapm = &codec->dapm;
369
370 mutex_lock(&dapm->codec->mutex);
371 tapan->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
372
373 dev_err(codec->dev, "%s: anc_func %x", __func__, tapan->anc_func);
374
375 if (tapan->anc_func == true) {
376 pr_info("enable anc virtual widgets");
377 snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
378 snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
379 snd_soc_dapm_enable_pin(dapm, "ANC HEADPHONE");
380 snd_soc_dapm_enable_pin(dapm, "ANC EAR PA");
381 snd_soc_dapm_enable_pin(dapm, "ANC EAR");
382 snd_soc_dapm_disable_pin(dapm, "HPHR");
383 snd_soc_dapm_disable_pin(dapm, "HPHL");
384 snd_soc_dapm_disable_pin(dapm, "HEADPHONE");
385 snd_soc_dapm_disable_pin(dapm, "EAR PA");
386 snd_soc_dapm_disable_pin(dapm, "EAR");
387 } else {
388 pr_info("disable anc virtual widgets");
389 snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
390 snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
391 snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
392 snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
393 snd_soc_dapm_disable_pin(dapm, "ANC EAR");
394 snd_soc_dapm_enable_pin(dapm, "HPHR");
395 snd_soc_dapm_enable_pin(dapm, "HPHL");
396 snd_soc_dapm_enable_pin(dapm, "HEADPHONE");
397 snd_soc_dapm_enable_pin(dapm, "EAR PA");
398 snd_soc_dapm_enable_pin(dapm, "EAR");
399 }
400 snd_soc_dapm_sync(dapm);
401 mutex_unlock(&dapm->codec->mutex);
402 return 0;
403}
404
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800405static int tapan_pa_gain_get(struct snd_kcontrol *kcontrol,
406 struct snd_ctl_elem_value *ucontrol)
407{
408 u8 ear_pa_gain;
409 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
410
411 ear_pa_gain = snd_soc_read(codec, TAPAN_A_RX_EAR_GAIN);
412
413 ear_pa_gain = ear_pa_gain >> 5;
414
415 if (ear_pa_gain == 0x00) {
416 ucontrol->value.integer.value[0] = 0;
417 } else if (ear_pa_gain == 0x04) {
418 ucontrol->value.integer.value[0] = 1;
419 } else {
420 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
421 __func__, ear_pa_gain);
422 return -EINVAL;
423 }
424
425 dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
426
427 return 0;
428}
429
430static int tapan_pa_gain_put(struct snd_kcontrol *kcontrol,
431 struct snd_ctl_elem_value *ucontrol)
432{
433 u8 ear_pa_gain;
434 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
435
436 dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
437 __func__, ucontrol->value.integer.value[0]);
438
439 switch (ucontrol->value.integer.value[0]) {
440 case 0:
441 ear_pa_gain = 0x00;
442 break;
443 case 1:
444 ear_pa_gain = 0x80;
445 break;
446 default:
447 return -EINVAL;
448 }
449
450 snd_soc_update_bits(codec, TAPAN_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
451 return 0;
452}
453
454static int tapan_get_iir_enable_audio_mixer(
455 struct snd_kcontrol *kcontrol,
456 struct snd_ctl_elem_value *ucontrol)
457{
458 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
459 int iir_idx = ((struct soc_multi_mixer_control *)
460 kcontrol->private_value)->reg;
461 int band_idx = ((struct soc_multi_mixer_control *)
462 kcontrol->private_value)->shift;
463
464 ucontrol->value.integer.value[0] =
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700465 (snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
466 (1 << band_idx)) != 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800467
468 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
469 iir_idx, band_idx,
470 (uint32_t)ucontrol->value.integer.value[0]);
471 return 0;
472}
473
474static int tapan_put_iir_enable_audio_mixer(
475 struct snd_kcontrol *kcontrol,
476 struct snd_ctl_elem_value *ucontrol)
477{
478 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
479 int iir_idx = ((struct soc_multi_mixer_control *)
480 kcontrol->private_value)->reg;
481 int band_idx = ((struct soc_multi_mixer_control *)
482 kcontrol->private_value)->shift;
483 int value = ucontrol->value.integer.value[0];
484
485 /* Mask first 5 bits, 6-8 are reserved */
486 snd_soc_update_bits(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx),
487 (1 << band_idx), (value << band_idx));
488
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700489 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
490 iir_idx, band_idx,
491 ((snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
492 (1 << band_idx)) != 0));
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800493 return 0;
494}
495static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
496 int iir_idx, int band_idx,
497 int coeff_idx)
498{
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700499 uint32_t value = 0;
500
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800501 /* Address does not automatically update if reading */
502 snd_soc_write(codec,
503 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700504 ((band_idx * BAND_MAX + coeff_idx)
505 * sizeof(uint32_t)) & 0x7F);
506
507 value |= snd_soc_read(codec,
508 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx));
509
510 snd_soc_write(codec,
511 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
512 ((band_idx * BAND_MAX + coeff_idx)
513 * sizeof(uint32_t) + 1) & 0x7F);
514
515 value |= (snd_soc_read(codec,
516 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 8);
517
518 snd_soc_write(codec,
519 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
520 ((band_idx * BAND_MAX + coeff_idx)
521 * sizeof(uint32_t) + 2) & 0x7F);
522
523 value |= (snd_soc_read(codec,
524 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 16);
525
526 snd_soc_write(codec,
527 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
528 ((band_idx * BAND_MAX + coeff_idx)
529 * sizeof(uint32_t) + 3) & 0x7F);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800530
531 /* Mask bits top 2 bits since they are reserved */
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700532 value |= ((snd_soc_read(codec,
533 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) & 0x3F) << 24);
534
535 return value;
536
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800537}
538
539static int tapan_get_iir_band_audio_mixer(
540 struct snd_kcontrol *kcontrol,
541 struct snd_ctl_elem_value *ucontrol)
542{
543 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
544 int iir_idx = ((struct soc_multi_mixer_control *)
545 kcontrol->private_value)->reg;
546 int band_idx = ((struct soc_multi_mixer_control *)
547 kcontrol->private_value)->shift;
548
549 ucontrol->value.integer.value[0] =
550 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
551 ucontrol->value.integer.value[1] =
552 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
553 ucontrol->value.integer.value[2] =
554 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
555 ucontrol->value.integer.value[3] =
556 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
557 ucontrol->value.integer.value[4] =
558 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
559
560 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
561 "%s: IIR #%d band #%d b1 = 0x%x\n"
562 "%s: IIR #%d band #%d b2 = 0x%x\n"
563 "%s: IIR #%d band #%d a1 = 0x%x\n"
564 "%s: IIR #%d band #%d a2 = 0x%x\n",
565 __func__, iir_idx, band_idx,
566 (uint32_t)ucontrol->value.integer.value[0],
567 __func__, iir_idx, band_idx,
568 (uint32_t)ucontrol->value.integer.value[1],
569 __func__, iir_idx, band_idx,
570 (uint32_t)ucontrol->value.integer.value[2],
571 __func__, iir_idx, band_idx,
572 (uint32_t)ucontrol->value.integer.value[3],
573 __func__, iir_idx, band_idx,
574 (uint32_t)ucontrol->value.integer.value[4]);
575 return 0;
576}
577
578static void set_iir_band_coeff(struct snd_soc_codec *codec,
579 int iir_idx, int band_idx,
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700580 uint32_t value)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800581{
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800582 snd_soc_write(codec,
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700583 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
584 (value & 0xFF));
585
586 snd_soc_write(codec,
587 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
588 (value >> 8) & 0xFF);
589
590 snd_soc_write(codec,
591 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
592 (value >> 16) & 0xFF);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800593
594 /* Mask top 2 bits, 7-8 are reserved */
595 snd_soc_write(codec,
596 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
597 (value >> 24) & 0x3F);
598
599}
600
601static int tapan_put_iir_band_audio_mixer(
602 struct snd_kcontrol *kcontrol,
603 struct snd_ctl_elem_value *ucontrol)
604{
605 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
606 int iir_idx = ((struct soc_multi_mixer_control *)
607 kcontrol->private_value)->reg;
608 int band_idx = ((struct soc_multi_mixer_control *)
609 kcontrol->private_value)->shift;
610
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700611 /* Mask top bit it is reserved */
612 /* Updates addr automatically for each B2 write */
613 snd_soc_write(codec,
614 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
615 (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
616
617 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800618 ucontrol->value.integer.value[0]);
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700619 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800620 ucontrol->value.integer.value[1]);
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700621 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800622 ucontrol->value.integer.value[2]);
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700623 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800624 ucontrol->value.integer.value[3]);
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700625 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800626 ucontrol->value.integer.value[4]);
627
628 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
629 "%s: IIR #%d band #%d b1 = 0x%x\n"
630 "%s: IIR #%d band #%d b2 = 0x%x\n"
631 "%s: IIR #%d band #%d a1 = 0x%x\n"
632 "%s: IIR #%d band #%d a2 = 0x%x\n",
633 __func__, iir_idx, band_idx,
634 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
635 __func__, iir_idx, band_idx,
636 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
637 __func__, iir_idx, band_idx,
638 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
639 __func__, iir_idx, band_idx,
640 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
641 __func__, iir_idx, band_idx,
642 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
643 return 0;
644}
645
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800646static int tapan_get_compander(struct snd_kcontrol *kcontrol,
647 struct snd_ctl_elem_value *ucontrol)
648{
649
650 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
651 int comp = ((struct soc_multi_mixer_control *)
652 kcontrol->private_value)->shift;
653 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
654
655 ucontrol->value.integer.value[0] = tapan->comp_enabled[comp];
656 return 0;
657}
658
659static int tapan_set_compander(struct snd_kcontrol *kcontrol,
660 struct snd_ctl_elem_value *ucontrol)
661{
662 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
663 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
664 int comp = ((struct soc_multi_mixer_control *)
665 kcontrol->private_value)->shift;
666 int value = ucontrol->value.integer.value[0];
667
668 dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n",
669 __func__, comp, tapan->comp_enabled[comp], value);
670 tapan->comp_enabled[comp] = value;
671 return 0;
672}
673
674static int tapan_config_gain_compander(struct snd_soc_codec *codec,
675 int comp, bool enable)
676{
677 int ret = 0;
678
679 switch (comp) {
680 case COMPANDER_0:
681 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_GAIN,
682 1 << 2, !enable << 2);
683 break;
684 case COMPANDER_1:
685 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_L_GAIN,
686 1 << 5, !enable << 5);
687 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_R_GAIN,
688 1 << 5, !enable << 5);
689 break;
690 case COMPANDER_2:
691 snd_soc_update_bits(codec, TAPAN_A_RX_LINE_1_GAIN,
692 1 << 5, !enable << 5);
693 snd_soc_update_bits(codec, TAPAN_A_RX_LINE_2_GAIN,
694 1 << 5, !enable << 5);
695 break;
696 default:
697 WARN_ON(1);
698 ret = -EINVAL;
699 }
700
701 return ret;
702}
703
704static void tapan_discharge_comp(struct snd_soc_codec *codec, int comp)
705{
706 /* Update RSM to 1, DIVF to 5 */
707 snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8), 1);
708 snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8), 0xF0,
709 1 << 5);
710 /* Wait for 1ms */
711 usleep_range(1000, 1000);
712}
713
714static int tapan_config_compander(struct snd_soc_dapm_widget *w,
715 struct snd_kcontrol *kcontrol, int event)
716{
717 int mask, emask;
718 bool timedout;
719 unsigned long timeout;
720 struct snd_soc_codec *codec = w->codec;
721 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
722 const int comp = w->shift;
723 const u32 rate = tapan->comp_fs[comp];
724 const struct comp_sample_dependent_params *comp_params =
725 &comp_samp_params[rate];
726
727 dev_dbg(codec->dev, "%s: %s event %d compander %d, enabled %d",
728 __func__, w->name, event, comp, tapan->comp_enabled[comp]);
729
730 if (!tapan->comp_enabled[comp])
731 return 0;
732
733 /* Compander 0 has single channel */
734 mask = (comp == COMPANDER_0 ? 0x01 : 0x03);
735 emask = (comp == COMPANDER_0 ? 0x02 : 0x03);
736
737 switch (event) {
738 case SND_SOC_DAPM_PRE_PMU:
739 /* Set gain source to compander */
740 tapan_config_gain_compander(codec, comp, true);
741 /* Enable RX interpolation path clocks */
742 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
743 mask << comp_shift[comp],
744 mask << comp_shift[comp]);
745
746 tapan_discharge_comp(codec, comp);
747
748 /* Clear compander halt */
749 snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
750 (comp * 8),
751 1 << 2, 0);
752 /* Toggle compander reset bits */
753 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
754 mask << comp_shift[comp],
755 mask << comp_shift[comp]);
756 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
757 mask << comp_shift[comp], 0);
758 break;
759 case SND_SOC_DAPM_POST_PMU:
760 /* Set sample rate dependent paramater */
761 snd_soc_update_bits(codec,
762 TAPAN_A_CDC_COMP0_FS_CFG + (comp * 8),
763 0x07, rate);
764 snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8),
765 comp_params->rms_meter_resamp_fact);
766 snd_soc_update_bits(codec,
767 TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
768 0x0F, comp_params->peak_det_timeout);
769 snd_soc_update_bits(codec,
770 TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
771 0xF0, comp_params->rms_meter_div_fact << 4);
772 /* Compander enable */
773 snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
774 (comp * 8), emask, emask);
775 break;
776 case SND_SOC_DAPM_PRE_PMD:
777 /* Halt compander */
778 snd_soc_update_bits(codec,
779 TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
780 1 << 2, 1 << 2);
781 /* Wait up to a second for shutdown complete */
782 timeout = jiffies + HZ;
783 do {
784 if ((snd_soc_read(codec,
785 TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS +
786 (comp * 8)) & mask) == mask)
787 break;
788 } while (!(timedout = time_after(jiffies, timeout)));
789 dev_dbg(codec->dev, "%s: Compander %d shutdown %s in %dms\n",
790 __func__, comp, timedout ? "timedout" : "completed",
791 jiffies_to_msecs(timeout - HZ - jiffies));
792 break;
793 case SND_SOC_DAPM_POST_PMD:
794 /* Disable compander */
795 snd_soc_update_bits(codec,
796 TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
797 emask, 0x00);
798 /* Turn off the clock for compander in pair */
799 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
800 mask << comp_shift[comp], 0);
801 /* Set gain source to register */
802 tapan_config_gain_compander(codec, comp, false);
803 break;
804 }
805 return 0;
806}
807
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800808static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
809static const struct soc_enum tapan_ear_pa_gain_enum[] = {
810 SOC_ENUM_SINGLE_EXT(2, tapan_ear_pa_gain_text),
811};
812
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700813static const char *const tapan_anc_func_text[] = {"OFF", "ON"};
814static const struct soc_enum tapan_anc_func_enum =
815 SOC_ENUM_SINGLE_EXT(2, tapan_anc_func_text);
816
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800817/*cut of frequency for high pass filter*/
818static const char * const cf_text[] = {
819 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
820};
821
822static const struct soc_enum cf_dec1_enum =
823 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
824
825static const struct soc_enum cf_dec2_enum =
826 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
827
828static const struct soc_enum cf_dec3_enum =
829 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
830
831static const struct soc_enum cf_dec4_enum =
832 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
833
834static const struct soc_enum cf_rxmix1_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800835 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800836
837static const struct soc_enum cf_rxmix2_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800838 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800839
840static const struct soc_enum cf_rxmix3_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800841 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800842
843static const struct soc_enum cf_rxmix4_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800844 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800845
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800846static const char * const class_h_dsm_text[] = {
847 "ZERO", "RX_HPHL", "RX_SPKR"
848};
849
850static const struct soc_enum class_h_dsm_enum =
851 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_CLSH_CTL, 2, 3, class_h_dsm_text);
852
853static const struct snd_kcontrol_new class_h_dsm_mux =
854 SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
855
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800856static const struct snd_kcontrol_new tapan_snd_controls[] = {
857
858 SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
859 tapan_pa_gain_get, tapan_pa_gain_put),
860
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800861 SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800862 line_gain),
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800863 SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800864 line_gain),
865
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800866 SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800867 line_gain),
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800868 SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800869 line_gain),
870
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800871 SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 7, 1,
872 line_gain),
873
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700874 SOC_SINGLE_TLV("ADC1 Volume", TAPAN_A_TX_1_EN, 2, 19, 0, analog_gain),
875 SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 19, 0, analog_gain),
876 SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 19, 0, analog_gain),
877 SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 19, 0, analog_gain),
878 SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 19, 0, analog_gain),
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800879
Jay Chokshi83b4f6132013-02-14 16:20:56 -0800880 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
881 -84, 40, digital_gain),
882 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
883 -84, 40, digital_gain),
884 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL,
885 -84, 40, digital_gain),
886 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
887 -84, 40, digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800888
Jay Chokshi83b4f6132013-02-14 16:20:56 -0800889 SOC_SINGLE_S8_TLV("DEC1 Volume", TAPAN_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
890 digital_gain),
891 SOC_SINGLE_S8_TLV("DEC2 Volume", TAPAN_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
892 digital_gain),
893 SOC_SINGLE_S8_TLV("DEC3 Volume", TAPAN_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
894 digital_gain),
895 SOC_SINGLE_S8_TLV("DEC4 Volume", TAPAN_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
896 digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800897
Jay Chokshi83b4f6132013-02-14 16:20:56 -0800898 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TAPAN_A_CDC_IIR1_GAIN_B1_CTL, -84,
899 40, digital_gain),
900 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TAPAN_A_CDC_IIR1_GAIN_B2_CTL, -84,
901 40, digital_gain),
902 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TAPAN_A_CDC_IIR1_GAIN_B3_CTL, -84,
903 40, digital_gain),
904 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAPAN_A_CDC_IIR1_GAIN_B4_CTL, -84,
905 40, digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800906
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700907 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tapan_get_anc_slot,
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800908 tapan_put_anc_slot),
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700909 SOC_ENUM_EXT("ANC Function", tapan_anc_func_enum, tapan_get_anc_func,
910 tapan_put_anc_func),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800911 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
912 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
913 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
914 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
915
916 SOC_SINGLE("TX1 HPF Switch", TAPAN_A_CDC_TX1_MUX_CTL, 3, 1, 0),
917 SOC_SINGLE("TX2 HPF Switch", TAPAN_A_CDC_TX2_MUX_CTL, 3, 1, 0),
918 SOC_SINGLE("TX3 HPF Switch", TAPAN_A_CDC_TX3_MUX_CTL, 3, 1, 0),
919 SOC_SINGLE("TX4 HPF Switch", TAPAN_A_CDC_TX4_MUX_CTL, 3, 1, 0),
920
921 SOC_SINGLE("RX1 HPF Switch", TAPAN_A_CDC_RX1_B5_CTL, 2, 1, 0),
922 SOC_SINGLE("RX2 HPF Switch", TAPAN_A_CDC_RX2_B5_CTL, 2, 1, 0),
923 SOC_SINGLE("RX3 HPF Switch", TAPAN_A_CDC_RX3_B5_CTL, 2, 1, 0),
924 SOC_SINGLE("RX4 HPF Switch", TAPAN_A_CDC_RX4_B5_CTL, 2, 1, 0),
925
926 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
927 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
928 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
929 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
930
931 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
932 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
933 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
934 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
935 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
936 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
937 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
938 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
939 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
940 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
941 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
942 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
943 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
944 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
945 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
946 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
947 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
948 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
949 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
950 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
951
952 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
953 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
954 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
955 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
956 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
957 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
958 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
959 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
960 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
961 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
962 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
963 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
964 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
965 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
966 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
967 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
968 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
969 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
970 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
971 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
972
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800973 SOC_SINGLE_EXT("COMP0 Switch", SND_SOC_NOPM, COMPANDER_0, 1, 0,
974 tapan_get_compander, tapan_set_compander),
975 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
976 tapan_get_compander, tapan_set_compander),
977 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
978 tapan_get_compander, tapan_set_compander),
979
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800980};
981
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800982static const char * const rx_1_2_mix1_text[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800983 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800984 "RX5", "AUXRX", "AUXTX1"
985};
986
987static const char * const rx_3_4_mix1_text[] = {
988 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
989 "RX5", "AUXRX", "AUXTX1", "AUXTX2"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800990};
991
992static const char * const rx_mix2_text[] = {
993 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
994};
995
996static const char * const rx_rdac5_text[] = {
997 "DEM4", "DEM3_INV"
998};
999
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001000static const char * const sb_tx_1_2_mux_text[] = {
1001 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1002 "RSVD", "RSVD", "RSVD",
1003 "DEC1", "DEC2", "DEC3", "DEC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001004};
1005
1006static const char * const sb_tx3_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001007 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1008 "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
1009 "DEC3"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001010};
1011
1012static const char * const sb_tx4_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001013 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1014 "RSVD", "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
1015 "DEC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001016};
1017
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001018static const char * const sb_tx5_mux_text[] = {
1019 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1020 "RSVD", "RSVD", "RSVD",
1021 "DEC1"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001022};
1023
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001024static const char * const dec_1_2_mux_text[] = {
1025 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADCMB",
1026 "DMIC1", "DMIC2", "DMIC3", "DMIC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001027};
1028
1029static const char * const dec3_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001030 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
1031 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
1032 "ANCFBTUNE1"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001033};
1034
1035static const char * const dec4_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001036 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
1037 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
1038 "ANCFBTUNE2"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001039};
1040
1041static const char * const anc_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001042 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5",
1043 "RSVD", "RSVD", "RSVD",
1044 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
1045 "RSVD", "RSVD"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001046};
1047
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001048static const char * const anc1_fb_mux_text[] = {
1049 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1050};
1051
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001052static const char * const iir1_inp1_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001053 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4",
1054 "RX1", "RX2", "RX3", "RX4", "RX5"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001055};
1056
1057static const struct soc_enum rx_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001058 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001059
1060static const struct soc_enum rx_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001061 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001062
1063static const struct soc_enum rx_mix1_inp3_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001064 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001065
1066static const struct soc_enum rx2_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001067 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001068
1069static const struct soc_enum rx2_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001070 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001071
1072static const struct soc_enum rx3_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001073 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 0, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001074
1075static const struct soc_enum rx3_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001076 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 4, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001077
1078static const struct soc_enum rx4_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001079 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 0, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001080
1081static const struct soc_enum rx4_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001082 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001083
1084static const struct soc_enum rx1_mix2_inp1_chain_enum =
1085 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
1086
1087static const struct soc_enum rx1_mix2_inp2_chain_enum =
1088 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
1089
1090static const struct soc_enum rx2_mix2_inp1_chain_enum =
1091 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
1092
1093static const struct soc_enum rx2_mix2_inp2_chain_enum =
1094 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
1095
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001096static const struct soc_enum rx4_mix2_inp1_chain_enum =
1097 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 0, 5, rx_mix2_text);
1098
1099static const struct soc_enum rx4_mix2_inp2_chain_enum =
1100 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 3, 5, rx_mix2_text);
1101
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001102static const struct soc_enum rx_rdac5_enum =
1103 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
1104
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001105static const struct soc_enum sb_tx1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001106 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0, 12,
1107 sb_tx_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001108
1109static const struct soc_enum sb_tx2_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001110 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0, 12,
1111 sb_tx_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001112
1113static const struct soc_enum sb_tx3_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001114 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0, 11, sb_tx3_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001115
1116static const struct soc_enum sb_tx4_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001117 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0, 12, sb_tx4_mux_text);
1118
1119static const struct soc_enum sb_tx5_mux_enum =
1120 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001121
1122static const struct soc_enum dec1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001123 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 0, 10, dec_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001124
1125static const struct soc_enum dec2_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001126 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 4, 10, dec_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001127
1128static const struct soc_enum dec3_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001129 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 0, 12, dec3_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001130
1131static const struct soc_enum dec4_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001132 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 4, 12, dec4_mux_text);
1133
1134static const struct soc_enum anc1_mux_enum =
1135 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 0, 15, anc_mux_text);
1136
1137static const struct soc_enum anc2_mux_enum =
1138 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 4, 15, anc_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001139
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001140static const struct soc_enum anc1_fb_mux_enum =
1141 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1142
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001143static const struct soc_enum iir1_inp1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001144 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_EQ1_B1_CTL, 0, 10, iir1_inp1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001145
1146static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1147 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1148
1149static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1150 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1151
1152static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1153 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1154
1155static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1156 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1157
1158static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1159 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1160
1161static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1162 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1163
1164static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1165 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1166
1167static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1168 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1169
1170static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1171 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1172
1173static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1174 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1175
1176static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
1177 SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
1178
1179static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1180 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1181
1182static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
1183 SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
1184
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001185static const struct snd_kcontrol_new rx4_mix2_inp1_mux =
1186 SOC_DAPM_ENUM("RX4 MIX2 INP1 Mux", rx4_mix2_inp1_chain_enum);
1187
1188static const struct snd_kcontrol_new rx4_mix2_inp2_mux =
1189 SOC_DAPM_ENUM("RX4 MIX2 INP2 Mux", rx4_mix2_inp2_chain_enum);
1190
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001191static const struct snd_kcontrol_new rx_dac5_mux =
1192 SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
1193
1194static const struct snd_kcontrol_new sb_tx1_mux =
1195 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1196
1197static const struct snd_kcontrol_new sb_tx2_mux =
1198 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
1199
1200static const struct snd_kcontrol_new sb_tx3_mux =
1201 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
1202
1203static const struct snd_kcontrol_new sb_tx4_mux =
1204 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
1205
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001206static const struct snd_kcontrol_new sb_tx5_mux =
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001207 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001208
1209static int wcd9306_put_dec_enum(struct snd_kcontrol *kcontrol,
1210 struct snd_ctl_elem_value *ucontrol)
1211{
1212 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1213 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1214 struct snd_soc_codec *codec = w->codec;
1215 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1216 unsigned int dec_mux, decimator;
1217 char *dec_name = NULL;
1218 char *widget_name = NULL;
1219 char *temp;
1220 u16 tx_mux_ctl_reg;
1221 u8 adc_dmic_sel = 0x0;
1222 int ret = 0;
1223
1224 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1225 return -EINVAL;
1226
1227 dec_mux = ucontrol->value.enumerated.item[0];
1228
1229 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1230 if (!widget_name)
1231 return -ENOMEM;
1232 temp = widget_name;
1233
1234 dec_name = strsep(&widget_name, " ");
1235 widget_name = temp;
1236 if (!dec_name) {
1237 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1238 ret = -EINVAL;
1239 goto out;
1240 }
1241
1242 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
1243 if (ret < 0) {
1244 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1245 ret = -EINVAL;
1246 goto out;
1247 }
1248
1249 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1250 , __func__, w->name, decimator, dec_mux);
1251
1252 switch (decimator) {
1253 case 1:
1254 case 2:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001255 if ((dec_mux >= 1) && (dec_mux <= 5))
1256 adc_dmic_sel = 0x0;
1257 else if ((dec_mux >= 6) && (dec_mux <= 9))
1258 adc_dmic_sel = 0x1;
1259 break;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001260 case 3:
1261 case 4:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001262 if ((dec_mux >= 1) && (dec_mux <= 6))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001263 adc_dmic_sel = 0x0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001264 else if ((dec_mux >= 7) && (dec_mux <= 10))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001265 adc_dmic_sel = 0x1;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001266 break;
1267 default:
1268 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1269 ret = -EINVAL;
1270 goto out;
1271 }
1272
1273 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1274
1275 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1276
1277 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1278
1279out:
1280 kfree(widget_name);
1281 return ret;
1282}
1283
1284#define WCD9306_DEC_ENUM(xname, xenum) \
1285{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1286 .info = snd_soc_info_enum_double, \
1287 .get = snd_soc_dapm_get_enum_double, \
1288 .put = wcd9306_put_dec_enum, \
1289 .private_value = (unsigned long)&xenum }
1290
1291static const struct snd_kcontrol_new dec1_mux =
1292 WCD9306_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1293
1294static const struct snd_kcontrol_new dec2_mux =
1295 WCD9306_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1296
1297static const struct snd_kcontrol_new dec3_mux =
1298 WCD9306_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1299
1300static const struct snd_kcontrol_new dec4_mux =
1301 WCD9306_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1302
1303static const struct snd_kcontrol_new iir1_inp1_mux =
1304 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1305
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001306static const struct snd_kcontrol_new anc1_mux =
1307 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1308
1309static const struct snd_kcontrol_new anc2_mux =
1310 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
1311
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001312static const struct snd_kcontrol_new anc1_fb_mux =
1313 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
1314
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001315static const struct snd_kcontrol_new dac1_switch[] = {
1316 SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_EAR_EN, 5, 1, 0)
1317};
1318static const struct snd_kcontrol_new hphl_switch[] = {
1319 SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1320};
1321
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001322static const struct snd_kcontrol_new spk_dac_switch[] = {
1323 SOC_DAPM_SINGLE("Switch", TAPAN_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
1324};
1325
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001326static const struct snd_kcontrol_new hphl_pa_mix[] = {
1327 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1328 7, 1, 0),
1329};
1330
1331static const struct snd_kcontrol_new hphr_pa_mix[] = {
1332 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1333 6, 1, 0),
1334};
1335
1336static const struct snd_kcontrol_new ear_pa_mix[] = {
1337 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1338 5, 1, 0),
1339};
1340static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1341 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1342 4, 1, 0),
1343};
1344
1345static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1346 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1347 3, 1, 0),
1348};
1349
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001350
1351/* virtual port entries */
1352static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
1353 struct snd_ctl_elem_value *ucontrol)
1354{
1355 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1356 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1357
1358 ucontrol->value.integer.value[0] = widget->value;
1359 return 0;
1360}
1361
1362static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
1363 struct snd_ctl_elem_value *ucontrol)
1364{
1365 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1366 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1367 struct snd_soc_codec *codec = widget->codec;
1368 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
1369 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1370 struct soc_multi_mixer_control *mixer =
1371 ((struct soc_multi_mixer_control *)kcontrol->private_value);
1372 u32 dai_id = widget->shift;
1373 u32 port_id = mixer->shift;
1374 u32 enable = ucontrol->value.integer.value[0];
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001375 u32 vtable = vport_check_table[dai_id];
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001376
1377 dev_dbg(codec->dev, "%s: wname %s cname %s\n",
1378 __func__, widget->name, ucontrol->id.name);
1379 dev_dbg(codec->dev, "%s: value %u shift %d item %ld\n",
1380 __func__, widget->value, widget->shift,
1381 ucontrol->value.integer.value[0]);
1382
1383 mutex_lock(&codec->mutex);
1384
1385 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1386 if (dai_id != AIF1_CAP) {
1387 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1388 __func__);
1389 mutex_unlock(&codec->mutex);
1390 return -EINVAL;
1391 }
1392 }
1393 switch (dai_id) {
1394 case AIF1_CAP:
1395 case AIF2_CAP:
1396 case AIF3_CAP:
1397 /* only add to the list if value not set
1398 */
1399 if (enable && !(widget->value & 1 << port_id)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001400 if (tapan_p->intf_type ==
1401 WCD9XXX_INTERFACE_TYPE_SLIMBUS)
1402 vtable = vport_check_table[dai_id];
1403 if (tapan_p->intf_type ==
1404 WCD9XXX_INTERFACE_TYPE_I2C)
1405 vtable = vport_i2s_check_table[dai_id];
1406
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001407 if (wcd9xxx_tx_vport_validation(
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001408 vtable,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001409 port_id,
1410 tapan_p->dai)) {
1411 dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
1412 __func__, port_id + 1);
1413 mutex_unlock(&codec->mutex);
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001414 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001415 }
1416 widget->value |= 1 << port_id;
1417 list_add_tail(&core->tx_chs[port_id].list,
1418 &tapan_p->dai[dai_id].wcd9xxx_ch_list
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001419 );
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001420 } else if (!enable && (widget->value & 1 << port_id)) {
1421 widget->value &= ~(1 << port_id);
1422 list_del_init(&core->tx_chs[port_id].list);
1423 } else {
1424 if (enable)
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001425 dev_dbg(codec->dev, "%s: TX%u port is used by\n"
1426 "this virtual port\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001427 __func__, port_id + 1);
1428 else
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001429 dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
1430 "this virtual port\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001431 __func__, port_id + 1);
1432 /* avoid update power function */
1433 mutex_unlock(&codec->mutex);
1434 return 0;
1435 }
1436 break;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001437 default:
1438 dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
1439 mutex_unlock(&codec->mutex);
1440 return -EINVAL;
1441 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001442 dev_dbg(codec->dev, "%s: name %s sname %s updated value %u shift %d\n",
1443 __func__, widget->name, widget->sname,
1444 widget->value, widget->shift);
1445
1446 snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
1447
1448 mutex_unlock(&codec->mutex);
1449 return 0;
1450}
1451
1452static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
1453 struct snd_ctl_elem_value *ucontrol)
1454{
1455 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1456 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1457
1458 ucontrol->value.enumerated.item[0] = widget->value;
1459 return 0;
1460}
1461
1462static const char *const slim_rx_mux_text[] = {
1463 "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB"
1464};
1465
1466static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
1467 struct snd_ctl_elem_value *ucontrol)
1468{
1469 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1470 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1471 struct snd_soc_codec *codec = widget->codec;
1472 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
1473 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1474 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1475 u32 port_id = widget->shift;
1476
1477 dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n",
1478 __func__, widget->name, ucontrol->id.name, widget->value,
1479 widget->shift, ucontrol->value.integer.value[0]);
1480
1481 widget->value = ucontrol->value.enumerated.item[0];
1482
1483 mutex_lock(&codec->mutex);
1484
1485 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1486 if (widget->value > 1) {
1487 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1488 __func__);
1489 goto err;
1490 }
1491 }
1492 /* value need to match the Virtual port and AIF number
1493 */
1494 switch (widget->value) {
1495 case 0:
1496 list_del_init(&core->rx_chs[port_id].list);
1497 break;
1498 case 1:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001499 if (wcd9xxx_rx_vport_validation(port_id +
1500 TAPAN_RX_PORT_START_NUMBER,
1501 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
1502 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1503 __func__, port_id + 1);
1504 goto rtn;
1505 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001506 list_add_tail(&core->rx_chs[port_id].list,
1507 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list);
1508 break;
1509 case 2:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001510 if (wcd9xxx_rx_vport_validation(port_id +
1511 TAPAN_RX_PORT_START_NUMBER,
1512 &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
1513 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1514 __func__, port_id + 1);
1515 goto rtn;
1516 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001517 list_add_tail(&core->rx_chs[port_id].list,
1518 &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list);
1519 break;
1520 case 3:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001521 if (wcd9xxx_rx_vport_validation(port_id +
1522 TAPAN_RX_PORT_START_NUMBER,
1523 &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
1524 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1525 __func__, port_id + 1);
1526 goto rtn;
1527 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001528 list_add_tail(&core->rx_chs[port_id].list,
1529 &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list);
1530 break;
1531 default:
1532 pr_err("Unknown AIF %d\n", widget->value);
1533 goto err;
1534 }
1535
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001536rtn:
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001537 snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001538 mutex_unlock(&codec->mutex);
1539 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001540err:
1541 mutex_unlock(&codec->mutex);
1542 return -EINVAL;
1543}
1544
1545static const struct soc_enum slim_rx_mux_enum =
1546 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
1547
1548static const struct snd_kcontrol_new slim_rx_mux[TAPAN_RX_MAX] = {
1549 SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
1550 slim_rx_mux_get, slim_rx_mux_put),
1551 SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
1552 slim_rx_mux_get, slim_rx_mux_put),
1553 SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
1554 slim_rx_mux_get, slim_rx_mux_put),
1555 SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
1556 slim_rx_mux_get, slim_rx_mux_put),
1557 SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
1558 slim_rx_mux_get, slim_rx_mux_put),
1559};
1560
1561static const struct snd_kcontrol_new aif_cap_mixer[] = {
1562 SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TAPAN_TX1, 1, 0,
1563 slim_tx_mixer_get, slim_tx_mixer_put),
1564 SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TAPAN_TX2, 1, 0,
1565 slim_tx_mixer_get, slim_tx_mixer_put),
1566 SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TAPAN_TX3, 1, 0,
1567 slim_tx_mixer_get, slim_tx_mixer_put),
1568 SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TAPAN_TX4, 1, 0,
1569 slim_tx_mixer_get, slim_tx_mixer_put),
1570 SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TAPAN_TX5, 1, 0,
1571 slim_tx_mixer_get, slim_tx_mixer_put),
1572};
1573
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001574static int tapan_codec_enable_adc(struct snd_soc_dapm_widget *w,
1575 struct snd_kcontrol *kcontrol, int event)
1576{
1577 struct snd_soc_codec *codec = w->codec;
1578 u16 adc_reg;
1579 u8 init_bit_shift;
1580
1581 dev_dbg(codec->dev, "%s(): %s %d\n", __func__, w->name, event);
1582
1583 if (w->reg == TAPAN_A_TX_1_EN) {
1584 init_bit_shift = 7;
1585 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1586 } else if (w->reg == TAPAN_A_TX_2_EN) {
1587 init_bit_shift = 6;
1588 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1589 } else if (w->reg == TAPAN_A_TX_3_EN) {
1590 init_bit_shift = 6;
1591 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1592 } else if (w->reg == TAPAN_A_TX_4_EN) {
1593 init_bit_shift = 7;
1594 adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
1595 } else if (w->reg == TAPAN_A_TX_5_EN) {
1596 init_bit_shift = 6;
1597 adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
1598 } else {
1599 pr_err("%s: Error, invalid adc register\n", __func__);
1600 return -EINVAL;
1601 }
1602
1603 switch (event) {
1604 case SND_SOC_DAPM_PRE_PMU:
1605 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1606 1 << init_bit_shift);
1607 break;
1608 case SND_SOC_DAPM_POST_PMU:
1609
1610 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1611
1612 break;
1613 }
1614 return 0;
1615}
1616
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001617static int tapan_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1618 struct snd_kcontrol *kcontrol, int event)
1619{
1620 struct snd_soc_codec *codec = w->codec;
1621 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1622
1623 dev_dbg(codec->dev, "%s: %d\n", __func__, event);
1624
1625 switch (event) {
1626 case SND_SOC_DAPM_PRE_PMU:
1627 WCD9XXX_BCL_LOCK(&tapan->resmgr);
1628 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
1629 WCD9XXX_BANDGAP_AUDIO_MODE);
1630 /* AUX PGA requires RCO or MCLK */
1631 wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_RCO);
1632 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 1);
1633 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
1634 break;
1635
1636 case SND_SOC_DAPM_POST_PMD:
1637 WCD9XXX_BCL_LOCK(&tapan->resmgr);
1638 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 0);
1639 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
1640 WCD9XXX_BANDGAP_AUDIO_MODE);
1641 wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_RCO);
1642 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
1643 break;
1644 }
1645 return 0;
1646}
1647
1648static int tapan_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1649 struct snd_kcontrol *kcontrol, int event)
1650{
1651 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001652 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001653 u16 lineout_gain_reg;
1654
1655 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
1656
1657 switch (w->shift) {
1658 case 0:
1659 lineout_gain_reg = TAPAN_A_RX_LINE_1_GAIN;
1660 break;
1661 case 1:
1662 lineout_gain_reg = TAPAN_A_RX_LINE_2_GAIN;
1663 break;
1664 default:
1665 pr_err("%s: Error, incorrect lineout register value\n",
1666 __func__);
1667 return -EINVAL;
1668 }
1669
1670 switch (event) {
1671 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001672 break;
1673 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001674 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
1675 WCD9XXX_CLSH_STATE_LO,
1676 WCD9XXX_CLSH_REQ_ENABLE,
1677 WCD9XXX_CLSH_EVENT_POST_PA);
1678 dev_dbg(codec->dev, "%s: sleeping 3 ms after %s PA turn on\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001679 __func__, w->name);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001680 usleep_range(3000, 3010);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001681 break;
1682 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001683 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
1684 WCD9XXX_CLSH_STATE_LO,
1685 WCD9XXX_CLSH_REQ_DISABLE,
1686 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001687 break;
1688 }
1689 return 0;
1690}
1691
1692static int tapan_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1693 struct snd_kcontrol *kcontrol, int event)
1694{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001695 struct snd_soc_codec *codec = w->codec;
1696 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1697
1698 dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
1699 WCD9XXX_BCL_LOCK(&tapan->resmgr);
1700 switch (event) {
1701 case SND_SOC_DAPM_PRE_PMU:
1702 tapan->spkr_pa_widget_on = true;
1703 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
1704 break;
1705 case SND_SOC_DAPM_POST_PMD:
1706 tapan->spkr_pa_widget_on = false;
1707 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x00);
1708 break;
1709 }
1710 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001711 return 0;
1712}
1713
1714static int tapan_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1715 struct snd_kcontrol *kcontrol, int event)
1716{
1717 struct snd_soc_codec *codec = w->codec;
1718 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1719 u8 dmic_clk_en;
1720 u16 dmic_clk_reg;
1721 s32 *dmic_clk_cnt;
1722 unsigned int dmic;
1723 int ret;
1724
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001725 ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001726 if (ret < 0) {
1727 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
1728 return -EINVAL;
1729 }
1730
1731 switch (dmic) {
1732 case 1:
1733 case 2:
1734 dmic_clk_en = 0x01;
1735 dmic_clk_cnt = &(tapan->dmic_1_2_clk_cnt);
1736 dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B1_CTL;
1737 dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
1738 __func__, event, dmic, *dmic_clk_cnt);
1739
1740 break;
1741
1742 case 3:
1743 case 4:
1744 dmic_clk_en = 0x10;
1745 dmic_clk_cnt = &(tapan->dmic_3_4_clk_cnt);
1746 dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B1_CTL;
1747
1748 dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
1749 __func__, event, dmic, *dmic_clk_cnt);
1750 break;
1751
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001752 default:
1753 pr_err("%s: Invalid DMIC Selection\n", __func__);
1754 return -EINVAL;
1755 }
1756
1757 switch (event) {
1758 case SND_SOC_DAPM_PRE_PMU:
1759
1760 (*dmic_clk_cnt)++;
1761 if (*dmic_clk_cnt == 1)
1762 snd_soc_update_bits(codec, dmic_clk_reg,
1763 dmic_clk_en, dmic_clk_en);
1764
1765 break;
1766 case SND_SOC_DAPM_POST_PMD:
1767
1768 (*dmic_clk_cnt)--;
1769 if (*dmic_clk_cnt == 0)
1770 snd_soc_update_bits(codec, dmic_clk_reg,
1771 dmic_clk_en, 0);
1772 break;
1773 }
1774 return 0;
1775}
1776
1777static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,
1778 struct snd_kcontrol *kcontrol, int event)
1779{
1780 struct snd_soc_codec *codec = w->codec;
1781 const char *filename;
1782 const struct firmware *fw;
1783 int i;
1784 int ret;
1785 int num_anc_slots;
Simmi Pateriyadf675e92013-04-05 01:15:54 +05301786 struct wcd9xxx_anc_header *anc_head;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001787 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1788 u32 anc_writes_size = 0;
1789 int anc_size_remaining;
1790 u32 *anc_ptr;
1791 u16 reg;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001792 u8 mask, val, old_val;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001793
1794 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001795 if (tapan->anc_func == 0)
1796 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001797 switch (event) {
1798 case SND_SOC_DAPM_PRE_PMU:
1799
1800 filename = "wcd9306/wcd9306_anc.bin";
1801
1802 ret = request_firmware(&fw, filename, codec->dev);
1803 if (ret != 0) {
1804 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1805 ret);
1806 return -ENODEV;
1807 }
1808
Simmi Pateriyadf675e92013-04-05 01:15:54 +05301809 if (fw->size < sizeof(struct wcd9xxx_anc_header)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001810 dev_err(codec->dev, "Not enough data\n");
1811 release_firmware(fw);
1812 return -ENOMEM;
1813 }
1814
1815 /* First number is the number of register writes */
Simmi Pateriyadf675e92013-04-05 01:15:54 +05301816 anc_head = (struct wcd9xxx_anc_header *)(fw->data);
1817 anc_ptr = (u32 *)((u32)fw->data +
1818 sizeof(struct wcd9xxx_anc_header));
1819 anc_size_remaining = fw->size -
1820 sizeof(struct wcd9xxx_anc_header);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001821 num_anc_slots = anc_head->num_anc_slots;
1822
1823 if (tapan->anc_slot >= num_anc_slots) {
1824 dev_err(codec->dev, "Invalid ANC slot selected\n");
1825 release_firmware(fw);
1826 return -EINVAL;
1827 }
1828
1829 for (i = 0; i < num_anc_slots; i++) {
1830
1831 if (anc_size_remaining < TAPAN_PACKED_REG_SIZE) {
1832 dev_err(codec->dev, "Invalid register format\n");
1833 release_firmware(fw);
1834 return -EINVAL;
1835 }
1836 anc_writes_size = (u32)(*anc_ptr);
1837 anc_size_remaining -= sizeof(u32);
1838 anc_ptr += 1;
1839
1840 if (anc_writes_size * TAPAN_PACKED_REG_SIZE
1841 > anc_size_remaining) {
1842 dev_err(codec->dev, "Invalid register format\n");
1843 release_firmware(fw);
1844 return -ENOMEM;
1845 }
1846
1847 if (tapan->anc_slot == i)
1848 break;
1849
1850 anc_size_remaining -= (anc_writes_size *
1851 TAPAN_PACKED_REG_SIZE);
1852 anc_ptr += anc_writes_size;
1853 }
1854 if (i == num_anc_slots) {
1855 dev_err(codec->dev, "Selected ANC slot not present\n");
1856 release_firmware(fw);
1857 return -ENOMEM;
1858 }
1859
1860 for (i = 0; i < anc_writes_size; i++) {
1861 TAPAN_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
1862 mask, val);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001863 old_val = snd_soc_read(codec, reg);
1864 snd_soc_write(codec, reg, (old_val & ~mask) |
1865 (val & mask));
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001866 }
1867 release_firmware(fw);
1868
1869 break;
1870 case SND_SOC_DAPM_POST_PMD:
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001871 msleep(40);
1872 snd_soc_update_bits(codec, TAPAN_A_CDC_ANC1_B1_CTL, 0x01, 0x00);
1873 snd_soc_update_bits(codec, TAPAN_A_CDC_ANC2_B1_CTL, 0x02, 0x00);
1874 msleep(20);
1875 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001876 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001877 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001878 break;
1879 }
1880 return 0;
1881}
1882
1883static int tapan_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1884 struct snd_kcontrol *kcontrol, int event)
1885{
1886 struct snd_soc_codec *codec = w->codec;
1887 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1888 u16 micb_int_reg;
1889 u8 cfilt_sel_val = 0;
1890 char *internal1_text = "Internal1";
1891 char *internal2_text = "Internal2";
1892 char *internal3_text = "Internal3";
1893 enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
1894
1895 dev_dbg(codec->dev, "%s %d\n", __func__, event);
1896 switch (w->reg) {
1897 case TAPAN_A_MICB_1_CTL:
1898 micb_int_reg = TAPAN_A_MICB_1_INT_RBIAS;
1899 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias1_cfilt_sel;
1900 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
1901 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
1902 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
1903 break;
1904 case TAPAN_A_MICB_2_CTL:
1905 micb_int_reg = TAPAN_A_MICB_2_INT_RBIAS;
1906 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias2_cfilt_sel;
1907 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_2_ON;
1908 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
1909 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
1910 break;
1911 case TAPAN_A_MICB_3_CTL:
1912 micb_int_reg = TAPAN_A_MICB_3_INT_RBIAS;
1913 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias3_cfilt_sel;
1914 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
1915 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
1916 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
1917 break;
1918 default:
1919 pr_err("%s: Error, invalid micbias register\n", __func__);
1920 return -EINVAL;
1921 }
1922
1923 switch (event) {
1924 case SND_SOC_DAPM_PRE_PMU:
1925 /* Let MBHC module know so micbias switch to be off */
1926 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_pre_on);
1927
1928 /* Get cfilt */
1929 wcd9xxx_resmgr_cfilt_get(&tapan->resmgr, cfilt_sel_val);
1930
1931 if (strnstr(w->name, internal1_text, 30))
1932 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
1933 else if (strnstr(w->name, internal2_text, 30))
1934 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1935 else if (strnstr(w->name, internal3_text, 30))
1936 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
1937
1938 break;
1939 case SND_SOC_DAPM_POST_PMU:
1940 usleep_range(20000, 20000);
1941 /* Let MBHC module know so micbias is on */
1942 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_on);
1943 break;
1944 case SND_SOC_DAPM_POST_PMD:
1945 /* Let MBHC module know so micbias switch to be off */
1946 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
1947
1948 if (strnstr(w->name, internal1_text, 30))
1949 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1950 else if (strnstr(w->name, internal2_text, 30))
1951 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1952 else if (strnstr(w->name, internal3_text, 30))
1953 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1954
1955 /* Put cfilt */
1956 wcd9xxx_resmgr_cfilt_put(&tapan->resmgr, cfilt_sel_val);
1957 break;
1958 }
1959
1960 return 0;
1961}
1962
1963static void tx_hpf_corner_freq_callback(struct work_struct *work)
1964{
1965 struct delayed_work *hpf_delayed_work;
1966 struct hpf_work *hpf_work;
1967 struct tapan_priv *tapan;
1968 struct snd_soc_codec *codec;
1969 u16 tx_mux_ctl_reg;
1970 u8 hpf_cut_of_freq;
1971
1972 hpf_delayed_work = to_delayed_work(work);
1973 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
1974 tapan = hpf_work->tapan;
1975 codec = hpf_work->tapan->codec;
1976 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
1977
1978 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL +
1979 (hpf_work->decimator - 1) * 8;
1980
1981 dev_dbg(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
1982 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
1983
1984 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
1985}
1986
1987#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
1988#define CF_MIN_3DB_4HZ 0x0
1989#define CF_MIN_3DB_75HZ 0x1
1990#define CF_MIN_3DB_150HZ 0x2
1991
1992static int tapan_codec_enable_dec(struct snd_soc_dapm_widget *w,
1993 struct snd_kcontrol *kcontrol, int event)
1994{
1995 struct snd_soc_codec *codec = w->codec;
1996 unsigned int decimator;
1997 char *dec_name = NULL;
1998 char *widget_name = NULL;
1999 char *temp;
2000 int ret = 0;
2001 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2002 u8 dec_hpf_cut_of_freq;
2003 int offset;
2004
2005 dev_dbg(codec->dev, "%s %d\n", __func__, event);
2006
2007 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2008 if (!widget_name)
2009 return -ENOMEM;
2010 temp = widget_name;
2011
2012 dec_name = strsep(&widget_name, " ");
2013 widget_name = temp;
2014 if (!dec_name) {
2015 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2016 ret = -EINVAL;
2017 goto out;
2018 }
2019
2020 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
2021 if (ret < 0) {
2022 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2023 ret = -EINVAL;
2024 goto out;
2025 }
2026
2027 dev_dbg(codec->dev, "%s(): widget = %s dec_name = %s decimator = %u\n",
2028 __func__, w->name, dec_name, decimator);
2029
2030 if (w->reg == TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
2031 dec_reset_reg = TAPAN_A_CDC_CLK_TX_RESET_B1_CTL;
2032 offset = 0;
2033 } else if (w->reg == TAPAN_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
2034 dec_reset_reg = TAPAN_A_CDC_CLK_TX_RESET_B2_CTL;
2035 offset = 8;
2036 } else {
2037 pr_err("%s: Error, incorrect dec\n", __func__);
2038 ret = -EINVAL;
2039 goto out;
2040 }
2041
2042 tx_vol_ctl_reg = TAPAN_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
2043 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2044
2045 switch (event) {
2046 case SND_SOC_DAPM_PRE_PMU:
2047
2048 /* Enableable TX digital mute */
2049 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2050
2051 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2052 1 << w->shift);
2053 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
2054
2055 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2056
2057 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
2058
2059 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2060 dec_hpf_cut_of_freq;
2061
2062 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2063
2064 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
2065 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2066 CF_MIN_3DB_150HZ << 4);
2067 }
2068
2069 /* enable HPF */
2070 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
2071
2072 break;
2073
2074 case SND_SOC_DAPM_POST_PMU:
2075
2076 /* Disable TX digital mute */
2077 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2078
2079 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2080 CF_MIN_3DB_150HZ) {
2081
2082 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2083 msecs_to_jiffies(300));
2084 }
2085 /* apply the digital gain after the decimator is enabled*/
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002086 if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002087 snd_soc_write(codec,
2088 tx_digital_gain_reg[w->shift + offset],
2089 snd_soc_read(codec,
2090 tx_digital_gain_reg[w->shift + offset])
2091 );
2092
2093 break;
2094
2095 case SND_SOC_DAPM_PRE_PMD:
2096
2097 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2098 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2099 break;
2100
2101 case SND_SOC_DAPM_POST_PMD:
2102
2103 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2104 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2105 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2106
2107 break;
2108 }
2109out:
2110 kfree(widget_name);
2111 return ret;
2112}
2113
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002114static int tapan_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
2115 struct snd_kcontrol *kcontrol, int event)
2116{
2117 struct snd_soc_codec *codec = w->codec;
2118 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
2119
2120 dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
2121
2122 switch (event) {
2123 case SND_SOC_DAPM_PRE_PMU:
2124
2125 if (spkr_drv_wrnd > 0) {
2126 WARN_ON(!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
2127 0x80));
2128 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
2129 0x00);
2130 }
2131 if (TAPAN_IS_1_0(core->version))
2132 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
2133 0x24, 0x00);
2134 break;
2135 case SND_SOC_DAPM_POST_PMD:
2136 if (TAPAN_IS_1_0(core->version))
2137 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
2138 0x24, 0x24);
2139 if (spkr_drv_wrnd > 0) {
2140 WARN_ON(!!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
2141 0x80));
2142 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
2143 0x80);
2144 }
2145 break;
2146 }
2147 return 0;
2148}
2149
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002150static int tapan_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
2151 struct snd_kcontrol *kcontrol, int event)
2152{
2153 struct snd_soc_codec *codec = w->codec;
2154
2155 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
2156
2157 switch (event) {
2158 case SND_SOC_DAPM_PRE_PMU:
2159 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_RESET_CTL,
2160 1 << w->shift, 1 << w->shift);
2161 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_RESET_CTL,
2162 1 << w->shift, 0x0);
2163 break;
2164 case SND_SOC_DAPM_POST_PMU:
2165 /* apply the digital gain after the interpolator is enabled*/
2166 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2167 snd_soc_write(codec,
2168 rx_digital_gain_reg[w->shift],
2169 snd_soc_read(codec,
2170 rx_digital_gain_reg[w->shift])
2171 );
2172 break;
2173 }
2174 return 0;
2175}
2176
2177static int tapan_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2178 struct snd_kcontrol *kcontrol, int event)
2179{
2180 switch (event) {
2181 case SND_SOC_DAPM_POST_PMU:
2182 case SND_SOC_DAPM_POST_PMD:
2183 usleep_range(1000, 1000);
2184 break;
2185 }
2186 return 0;
2187}
2188
2189static int tapan_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2190 struct snd_kcontrol *kcontrol, int event)
2191{
2192 struct snd_soc_codec *codec = w->codec;
2193 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2194
2195 dev_dbg(codec->dev, "%s %d\n", __func__, event);
2196
2197 switch (event) {
2198 case SND_SOC_DAPM_PRE_PMU:
2199 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 1);
2200 break;
2201 case SND_SOC_DAPM_POST_PMD:
2202 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 0);
2203 break;
2204 }
2205 return 0;
2206}
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002207
2208
2209static int tapan_hphl_dac_event(struct snd_soc_dapm_widget *w,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002210 struct snd_kcontrol *kcontrol, int event)
2211{
2212 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002213 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002214
2215 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2216
2217 switch (event) {
2218 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002219 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2220 0x02, 0x02);
2221 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
2222 WCD9XXX_CLSH_STATE_HPHL,
2223 WCD9XXX_CLSH_REQ_ENABLE,
2224 WCD9XXX_CLSH_EVENT_PRE_DAC);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002225 break;
2226 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002227 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2228 0x02, 0x00);
2229 }
2230 return 0;
2231}
2232
2233static int tapan_hphr_dac_event(struct snd_soc_dapm_widget *w,
2234 struct snd_kcontrol *kcontrol, int event)
2235{
2236 struct snd_soc_codec *codec = w->codec;
2237 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
2238
2239 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2240
2241 switch (event) {
2242 case SND_SOC_DAPM_PRE_PMU:
2243 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2244 0x04, 0x04);
2245 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2246 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
2247 WCD9XXX_CLSH_STATE_HPHR,
2248 WCD9XXX_CLSH_REQ_ENABLE,
2249 WCD9XXX_CLSH_EVENT_PRE_DAC);
2250 break;
2251 case SND_SOC_DAPM_POST_PMD:
2252 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2253 0x04, 0x00);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002254 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2255 break;
2256 }
2257 return 0;
2258}
2259
2260static int tapan_hph_pa_event(struct snd_soc_dapm_widget *w,
2261 struct snd_kcontrol *kcontrol, int event)
2262{
2263 struct snd_soc_codec *codec = w->codec;
2264 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2265 enum wcd9xxx_notify_event e_pre_on, e_post_off;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002266 u8 req_clsh_state;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002267
2268 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
2269 if (w->shift == 5) {
Patrick Lai6ef05902013-03-16 18:14:16 -07002270 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
2271 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002272 req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
2273 } else if (w->shift == 4) {
2274 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
2275 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002276 req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002277 } else {
2278 pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
2279 return -EINVAL;
2280 }
2281
2282 switch (event) {
2283 case SND_SOC_DAPM_PRE_PMU:
2284 /* Let MBHC module know PA is turning on */
2285 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_pre_on);
2286 break;
2287
2288 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002289 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2290 req_clsh_state,
2291 WCD9XXX_CLSH_REQ_ENABLE,
2292 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002293
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002294
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002295 usleep_range(5000, 5010);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002296 break;
2297
2298 case SND_SOC_DAPM_POST_PMD:
2299 /* Let MBHC module know PA turned off */
2300 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
2301
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002302 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2303 req_clsh_state,
2304 WCD9XXX_CLSH_REQ_DISABLE,
2305 WCD9XXX_CLSH_EVENT_POST_PA);
2306
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002307 dev_dbg(codec->dev, "%s: sleep 10 ms after %s PA disable.\n",
2308 __func__, w->name);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002309 usleep_range(5000, 5010);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002310 break;
2311 }
2312 return 0;
2313}
2314
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002315static int tapan_codec_enable_anc_hph(struct snd_soc_dapm_widget *w,
2316 struct snd_kcontrol *kcontrol, int event)
2317{
2318 struct snd_soc_codec *codec = w->codec;
2319 int ret = 0;
2320
2321 switch (event) {
2322 case SND_SOC_DAPM_PRE_PMU:
2323 ret = tapan_hph_pa_event(w, kcontrol, event);
2324 if (w->shift == 4) {
2325 ret |= tapan_codec_enable_anc(w, kcontrol, event);
2326 msleep(50);
2327 }
2328 break;
2329 case SND_SOC_DAPM_POST_PMU:
2330 if (w->shift == 4) {
2331 snd_soc_update_bits(codec,
2332 TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x30);
2333 msleep(30);
2334 }
2335 ret = tapan_hph_pa_event(w, kcontrol, event);
2336 break;
2337 case SND_SOC_DAPM_PRE_PMD:
2338 if (w->shift == 5) {
2339 snd_soc_update_bits(codec,
2340 TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x00);
2341 msleep(40);
2342 }
2343 if (w->shift == 5) {
2344 snd_soc_update_bits(codec,
2345 TAPAN_A_TX_7_MBHC_EN, 0x80, 00);
2346 ret |= tapan_codec_enable_anc(w, kcontrol, event);
2347 }
2348 case SND_SOC_DAPM_POST_PMD:
2349 ret = tapan_hph_pa_event(w, kcontrol, event);
2350 break;
2351 }
2352 return ret;
2353}
2354
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002355static const struct snd_soc_dapm_widget tapan_dapm_i2s_widgets[] = {
2356 SND_SOC_DAPM_SUPPLY("I2S_CLK", TAPAN_A_CDC_CLK_I2S_CTL,
2357 4, 0, NULL, 0),
2358};
2359
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002360static int tapan_lineout_dac_event(struct snd_soc_dapm_widget *w,
2361 struct snd_kcontrol *kcontrol, int event)
2362{
2363 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002364 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002365
2366 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2367
2368 switch (event) {
2369 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002370 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2371 WCD9XXX_CLSH_STATE_LO,
2372 WCD9XXX_CLSH_REQ_ENABLE,
2373 WCD9XXX_CLSH_EVENT_PRE_DAC);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002374 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2375 break;
2376
2377 case SND_SOC_DAPM_POST_PMD:
2378 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2379 break;
2380 }
2381 return 0;
2382}
2383
2384static int tapan_spk_dac_event(struct snd_soc_dapm_widget *w,
2385 struct snd_kcontrol *kcontrol, int event)
2386{
2387 struct snd_soc_codec *codec = w->codec;
2388
2389 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2390 return 0;
2391}
2392
2393static const struct snd_soc_dapm_route audio_i2s_map[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002394 {"I2S_CLK", NULL, "CDC_CONN"},
2395 {"SLIM RX1", NULL, "I2S_CLK"},
2396 {"SLIM RX2", NULL, "I2S_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002397
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002398 {"SLIM TX1 MUX", NULL, "I2S_CLK"},
2399 {"SLIM TX2 MUX", NULL, "I2S_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002400};
2401
2402static const struct snd_soc_dapm_route audio_map[] = {
2403 /* SLIMBUS Connections */
2404 {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
2405 {"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
2406 {"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
2407
2408 /* SLIM_MIXER("AIF1_CAP Mixer"),*/
2409 {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2410 {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2411 {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2412 {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2413 {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002414 /* SLIM_MIXER("AIF2_CAP Mixer"),*/
2415 {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2416 {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2417 {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2418 {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2419 {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002420 /* SLIM_MIXER("AIF3_CAP Mixer"),*/
2421 {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2422 {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2423 {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2424 {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2425 {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002426
2427 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002428 {"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
2429 {"SLIM TX1 MUX", "DEC3", "DEC3 MUX"},
2430 {"SLIM TX1 MUX", "DEC4", "DEC4 MUX"},
2431 {"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
2432 {"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
2433 {"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
2434 {"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002435
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002436 {"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002437 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002438 {"SLIM TX2 MUX", "DEC3", "DEC3 MUX"},
2439 {"SLIM TX2 MUX", "DEC4", "DEC4 MUX"},
2440 {"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
2441 {"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
2442 {"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
2443 {"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002444
2445 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
2446 {"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
2447 {"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
2448 {"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
2449 {"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002450
2451 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002452 {"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
2453 {"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
2454 {"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
2455 {"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002456
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002457 {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002458 {"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
2459 {"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
2460 {"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
2461 {"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002462
2463 /* Earpiece (RX MIX1) */
2464 {"EAR", NULL, "EAR PA"},
2465 {"EAR PA", NULL, "EAR_PA_MIXER"},
2466 {"EAR_PA_MIXER", NULL, "DAC1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002467 {"DAC1", NULL, "RX_BIAS"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002468
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002469 {"ANC EAR", NULL, "ANC EAR PA"},
2470 {"ANC EAR PA", NULL, "EAR_PA_MIXER"},
2471 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
2472 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
2473
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002474 /* Headset (RX MIX1 and RX MIX2) */
2475 {"HEADPHONE", NULL, "HPHL"},
2476 {"HEADPHONE", NULL, "HPHR"},
2477
2478 {"HPHL", NULL, "HPHL_PA_MIXER"},
2479 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002480 {"HPHL DAC", NULL, "RX_BIAS"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002481
2482 {"HPHR", NULL, "HPHR_PA_MIXER"},
2483 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002484 {"HPHR DAC", NULL, "RX_BIAS"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002485
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002486 {"ANC HEADPHONE", NULL, "ANC HPHL"},
2487 {"ANC HEADPHONE", NULL, "ANC HPHR"},
2488
2489 {"ANC HPHL", NULL, "HPHL_PA_MIXER"},
2490 {"ANC HPHR", NULL, "HPHR_PA_MIXER"},
2491
2492 {"ANC1 MUX", "ADC1", "ADC1"},
2493 {"ANC1 MUX", "ADC2", "ADC2"},
2494 {"ANC1 MUX", "ADC3", "ADC3"},
2495 {"ANC1 MUX", "ADC4", "ADC4"},
2496 {"ANC1 MUX", "ADC5", "ADC5"},
2497 {"ANC1 MUX", "DMIC1", "DMIC1"},
2498 {"ANC1 MUX", "DMIC2", "DMIC2"},
2499 {"ANC1 MUX", "DMIC3", "DMIC3"},
2500 {"ANC1 MUX", "DMIC4", "DMIC4"},
2501 {"ANC2 MUX", "ADC1", "ADC1"},
2502 {"ANC2 MUX", "ADC2", "ADC2"},
2503 {"ANC2 MUX", "ADC3", "ADC3"},
2504 {"ANC2 MUX", "ADC4", "ADC4"},
2505 {"ANC2 MUX", "ADC5", "ADC5"},
2506 {"ANC2 MUX", "DMIC1", "DMIC1"},
2507 {"ANC2 MUX", "DMIC2", "DMIC2"},
2508 {"ANC2 MUX", "DMIC3", "DMIC3"},
2509 {"ANC2 MUX", "DMIC4", "DMIC4"},
2510
2511 {"ANC HPHR", NULL, "CDC_CONN"},
2512
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002513 {"DAC1", "Switch", "CLASS_H_DSM MUX"},
2514 {"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002515 {"HPHR DAC", NULL, "RX2 CHAIN"},
2516
2517 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2518 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002519 {"SPK_OUT", NULL, "SPK PA"},
2520
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002521 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2522 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
2523
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002524 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2525 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2526
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002527 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2528
2529 {"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002530 {"RDAC5 MUX", "DEM4", "RX4 MIX2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002531
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002532 {"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002533
2534 {"SPK PA", NULL, "SPK DAC"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002535 {"SPK DAC", "Switch", "RX4 MIX2"},
2536 {"SPK DAC", NULL, "VDD_SPKDRV"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002537
2538 {"RX1 CHAIN", NULL, "RX1 MIX2"},
2539 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002540 {"CLASS_H_DSM MUX", "RX_HPHL", "RX1 CHAIN"},
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002541 {"RX1 MIX2", NULL, "ANC1 MUX"},
2542 {"RX2 MIX2", NULL, "ANC2 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002543
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002544 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2545 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002546
2547 {"RX1 MIX1", NULL, "COMP1_CLK"},
2548 {"RX2 MIX1", NULL, "COMP1_CLK"},
2549 {"RX3 MIX1", NULL, "COMP2_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002550
2551 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2552 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2553 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
2554 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2555 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2556 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2557 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2558 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2559 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002560 {"RX1 MIX2", NULL, "RX1 MIX1"},
2561 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
2562 {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
2563 {"RX2 MIX2", NULL, "RX2 MIX1"},
2564 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
2565 {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002566 {"RX4 MIX2", NULL, "RX4 MIX1"},
2567 {"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
2568 {"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002569
2570 /* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
2571 {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
2572 {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
2573 {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
2574 {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
2575 {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002576 /* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
2577 {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
2578 {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
2579 {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
2580 {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
2581 {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002582 /* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
2583 {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
2584 {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
2585 {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
2586 {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
2587 {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002588
2589 {"SLIM RX1", NULL, "SLIM RX1 MUX"},
2590 {"SLIM RX2", NULL, "SLIM RX2 MUX"},
2591 {"SLIM RX3", NULL, "SLIM RX3 MUX"},
2592 {"SLIM RX4", NULL, "SLIM RX4 MUX"},
2593 {"SLIM RX5", NULL, "SLIM RX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002594
2595 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2596 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
2597 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2598 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
2599 {"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002600 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2601 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2602 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
2603 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2604 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
2605 {"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002606 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2607 {"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
2608 {"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
2609 {"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
2610 {"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
2611 {"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002612 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2613 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
2614 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2615 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
2616 {"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002617 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
2618 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2619 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
2620 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2621 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
2622 {"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002623 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
2624 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2625 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
2626 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2627 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
2628 {"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002629 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
2630 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2631 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
2632 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2633 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
2634 {"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002635 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
2636 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2637 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
2638 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2639 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
2640 {"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002641 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
2642 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2643 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
2644 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2645 {"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
2646 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002647 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002648
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002649 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
2650 {"RX1 MIX2 INP2", "IIR1", "IIR1"},
2651 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
2652 {"RX2 MIX2 INP2", "IIR1", "IIR1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002653 {"RX4 MIX2 INP1", "IIR1", "IIR1"},
2654 {"RX4 MIX2 INP2", "IIR1", "IIR1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002655
2656 /* Decimator Inputs */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002657 {"DEC1 MUX", "ADC1", "ADC1"},
2658 {"DEC1 MUX", "ADC2", "ADC2"},
2659 {"DEC1 MUX", "ADC3", "ADC3"},
2660 {"DEC1 MUX", "ADC4", "ADC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002661 {"DEC1 MUX", "DMIC1", "DMIC1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002662 {"DEC1 MUX", "DMIC2", "DMIC2"},
2663 {"DEC1 MUX", "DMIC3", "DMIC3"},
2664 {"DEC1 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002665 {"DEC1 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002666
2667 {"DEC2 MUX", "ADC1", "ADC1"},
2668 {"DEC2 MUX", "ADC2", "ADC2"},
2669 {"DEC2 MUX", "ADC3", "ADC3"},
2670 {"DEC2 MUX", "ADC4", "ADC4"},
2671 {"DEC2 MUX", "DMIC1", "DMIC1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002672 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002673 {"DEC2 MUX", "DMIC3", "DMIC3"},
2674 {"DEC2 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002675 {"DEC2 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002676
2677 {"DEC3 MUX", "ADC1", "ADC1"},
2678 {"DEC3 MUX", "ADC2", "ADC2"},
2679 {"DEC3 MUX", "ADC3", "ADC3"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002680 {"DEC3 MUX", "ADC4", "ADC4"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002681 {"DEC3 MUX", "ADC5", "ADC5"},
2682 {"DEC3 MUX", "DMIC1", "DMIC1"},
2683 {"DEC3 MUX", "DMIC2", "DMIC2"},
2684 {"DEC3 MUX", "DMIC3", "DMIC3"},
2685 {"DEC3 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002686 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002687
2688 {"DEC4 MUX", "ADC1", "ADC1"},
2689 {"DEC4 MUX", "ADC2", "ADC2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002690 {"DEC4 MUX", "ADC3", "ADC3"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002691 {"DEC4 MUX", "ADC4", "ADC4"},
2692 {"DEC4 MUX", "ADC5", "ADC5"},
2693 {"DEC4 MUX", "DMIC1", "DMIC1"},
2694 {"DEC4 MUX", "DMIC2", "DMIC2"},
2695 {"DEC4 MUX", "DMIC3", "DMIC3"},
2696 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002697 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002698
2699 /* ADC Connections */
2700 {"ADC1", NULL, "AMIC1"},
2701 {"ADC2", NULL, "AMIC2"},
2702 {"ADC3", NULL, "AMIC3"},
2703 {"ADC4", NULL, "AMIC4"},
2704 {"ADC5", NULL, "AMIC5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002705
2706 /* AUX PGA Connections */
2707 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2708 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2709 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2710 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2711 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002712 {"AUX_PGA_Left", NULL, "AMIC5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002713
2714 {"IIR1", NULL, "IIR1 INP1 MUX"},
2715 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2716 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2717 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2718 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002719
2720 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2721 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2722 {"MIC BIAS1 External", NULL, "LDO_H"},
2723 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2724 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2725 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2726 {"MIC BIAS2 External", NULL, "LDO_H"},
2727 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2728 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2729 {"MIC BIAS3 External", NULL, "LDO_H"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002730};
2731
2732static int tapan_readable(struct snd_soc_codec *ssc, unsigned int reg)
2733{
2734 return tapan_reg_readable[reg];
2735}
2736
2737static bool tapan_is_digital_gain_register(unsigned int reg)
2738{
2739 bool rtn = false;
2740 switch (reg) {
2741 case TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL:
2742 case TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL:
2743 case TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL:
2744 case TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL:
2745 case TAPAN_A_CDC_TX1_VOL_CTL_GAIN:
2746 case TAPAN_A_CDC_TX2_VOL_CTL_GAIN:
2747 case TAPAN_A_CDC_TX3_VOL_CTL_GAIN:
2748 case TAPAN_A_CDC_TX4_VOL_CTL_GAIN:
2749 rtn = true;
2750 break;
2751 default:
2752 break;
2753 }
2754 return rtn;
2755}
2756
2757static int tapan_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2758{
2759 /* Registers lower than 0x100 are top level registers which can be
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002760 * written by the Tapan core driver.
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002761 */
2762
2763 if ((reg >= TAPAN_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2764 return 1;
2765
2766 /* IIR Coeff registers are not cacheable */
2767 if ((reg >= TAPAN_A_CDC_IIR1_COEF_B1_CTL) &&
2768 (reg <= TAPAN_A_CDC_IIR2_COEF_B2_CTL))
2769 return 1;
2770
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002771 /* ANC filter registers are not cacheable */
2772 if ((reg >= TAPAN_A_CDC_ANC1_IIR_B1_CTL) &&
2773 (reg <= TAPAN_A_CDC_ANC1_LPF_B2_CTL))
2774 return 1;
2775 if ((reg >= TAPAN_A_CDC_ANC2_IIR_B1_CTL) &&
2776 (reg <= TAPAN_A_CDC_ANC2_LPF_B2_CTL))
2777 return 1;
2778
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002779 /* Digital gain register is not cacheable so we have to write
2780 * the setting even it is the same
2781 */
2782 if (tapan_is_digital_gain_register(reg))
2783 return 1;
2784
2785 /* HPH status registers */
2786 if (reg == TAPAN_A_RX_HPH_L_STATUS || reg == TAPAN_A_RX_HPH_R_STATUS)
2787 return 1;
2788
2789 if (reg == TAPAN_A_MBHC_INSERT_DET_STATUS)
2790 return 1;
2791
2792 return 0;
2793}
2794
2795#define TAPAN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2796static int tapan_write(struct snd_soc_codec *codec, unsigned int reg,
2797 unsigned int value)
2798{
2799 int ret;
2800
2801 if (reg == SND_SOC_NOPM)
2802 return 0;
2803
2804 BUG_ON(reg > TAPAN_MAX_REGISTER);
2805
2806 if (!tapan_volatile(codec, reg)) {
2807 ret = snd_soc_cache_write(codec, reg, value);
2808 if (ret != 0)
2809 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2810 reg, ret);
2811 }
2812
2813 return wcd9xxx_reg_write(codec->control_data, reg, value);
2814}
2815static unsigned int tapan_read(struct snd_soc_codec *codec,
2816 unsigned int reg)
2817{
2818 unsigned int val;
2819 int ret;
2820
2821 if (reg == SND_SOC_NOPM)
2822 return 0;
2823
2824 BUG_ON(reg > TAPAN_MAX_REGISTER);
2825
2826 if (!tapan_volatile(codec, reg) && tapan_readable(codec, reg) &&
2827 reg < codec->driver->reg_cache_size) {
2828 ret = snd_soc_cache_read(codec, reg, &val);
2829 if (ret >= 0) {
2830 return val;
2831 } else
2832 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2833 reg, ret);
2834 }
2835
2836 val = wcd9xxx_reg_read(codec->control_data, reg);
2837 return val;
2838}
2839
2840static int tapan_startup(struct snd_pcm_substream *substream,
2841 struct snd_soc_dai *dai)
2842{
2843 struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
2844 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
2845 __func__, substream->name, substream->stream);
2846 if ((tapan_core != NULL) &&
2847 (tapan_core->dev != NULL) &&
2848 (tapan_core->dev->parent != NULL))
2849 pm_runtime_get_sync(tapan_core->dev->parent);
2850
2851 return 0;
2852}
2853
2854static void tapan_shutdown(struct snd_pcm_substream *substream,
2855 struct snd_soc_dai *dai)
2856{
2857 struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
2858 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
2859 __func__, substream->name, substream->stream);
2860 if ((tapan_core != NULL) &&
2861 (tapan_core->dev != NULL) &&
2862 (tapan_core->dev->parent != NULL)) {
2863 pm_runtime_mark_last_busy(tapan_core->dev->parent);
2864 pm_runtime_put(tapan_core->dev->parent);
2865 }
2866}
2867
2868int tapan_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
2869{
2870 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2871
2872 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n", __func__,
2873 mclk_enable, dapm);
2874
2875 WCD9XXX_BCL_LOCK(&tapan->resmgr);
2876 if (mclk_enable) {
2877 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
2878 WCD9XXX_BANDGAP_AUDIO_MODE);
2879 wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
2880 } else {
2881 /* Put clock and BG */
2882 wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
2883 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
2884 WCD9XXX_BANDGAP_AUDIO_MODE);
2885 }
2886 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
2887
2888 return 0;
2889}
2890
2891static int tapan_set_dai_sysclk(struct snd_soc_dai *dai,
2892 int clk_id, unsigned int freq, int dir)
2893{
2894 dev_dbg(dai->codec->dev, "%s\n", __func__);
2895 return 0;
2896}
2897
2898static int tapan_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2899{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002900 u8 val = 0;
2901 struct snd_soc_codec *codec = dai->codec;
2902 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2903
2904 dev_dbg(codec->dev, "%s\n", __func__);
2905 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2906 case SND_SOC_DAIFMT_CBS_CFS:
2907 /* CPU is master */
2908 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2909 if (dai->id == AIF1_CAP)
2910 snd_soc_update_bits(codec,
2911 TAPAN_A_CDC_CLK_I2S_CTL,
2912 TAPAN_I2S_MASTER_MODE_MASK, 0);
2913 else if (dai->id == AIF1_PB)
2914 snd_soc_update_bits(codec,
2915 TAPAN_A_CDC_CLK_I2S_CTL,
2916 TAPAN_I2S_MASTER_MODE_MASK, 0);
2917 }
2918 break;
2919 case SND_SOC_DAIFMT_CBM_CFM:
2920 /* CPU is slave */
2921 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2922 val = TAPAN_I2S_MASTER_MODE_MASK;
2923 if (dai->id == AIF1_CAP)
2924 snd_soc_update_bits(codec,
2925 TAPAN_A_CDC_CLK_I2S_CTL, val, val);
2926 else if (dai->id == AIF1_PB)
2927 snd_soc_update_bits(codec,
2928 TAPAN_A_CDC_CLK_I2S_CTL, val, val);
2929 }
2930 break;
2931 default:
2932 return -EINVAL;
2933 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002934 return 0;
2935}
2936
2937static int tapan_set_channel_map(struct snd_soc_dai *dai,
2938 unsigned int tx_num, unsigned int *tx_slot,
2939 unsigned int rx_num, unsigned int *rx_slot)
2940
2941{
2942 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
2943 struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
2944 if (!tx_slot && !rx_slot) {
2945 pr_err("%s: Invalid\n", __func__);
2946 return -EINVAL;
2947 }
2948 dev_dbg(dai->codec->dev, "%s(): dai_name = %s DAI-ID %x\n",
2949 __func__, dai->name, dai->id);
2950 dev_dbg(dai->codec->dev, "%s(): tx_ch %d rx_ch %d\n intf_type %d\n",
2951 __func__, tx_num, rx_num, tapan->intf_type);
2952
2953 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
2954 wcd9xxx_init_slimslave(core, core->slim->laddr,
2955 tx_num, tx_slot, rx_num, rx_slot);
2956 return 0;
2957}
2958
2959static int tapan_get_channel_map(struct snd_soc_dai *dai,
2960 unsigned int *tx_num, unsigned int *tx_slot,
2961 unsigned int *rx_num, unsigned int *rx_slot)
2962
2963{
2964 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(dai->codec);
2965 u32 i = 0;
2966 struct wcd9xxx_ch *ch;
2967
2968 switch (dai->id) {
2969 case AIF1_PB:
2970 case AIF2_PB:
2971 case AIF3_PB:
2972 if (!rx_slot || !rx_num) {
2973 pr_err("%s: Invalid rx_slot %d or rx_num %d\n",
2974 __func__, (u32) rx_slot, (u32) rx_num);
2975 return -EINVAL;
2976 }
2977 list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
2978 list) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002979 dev_dbg(dai->codec->dev, "%s: rx_slot[%d] %d, ch->ch_num %d\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002980 __func__, i, rx_slot[i], ch->ch_num);
2981 rx_slot[i++] = ch->ch_num;
2982 }
2983 dev_dbg(dai->codec->dev, "%s: rx_num %d\n", __func__, i);
2984 *rx_num = i;
2985 break;
2986 case AIF1_CAP:
2987 case AIF2_CAP:
2988 case AIF3_CAP:
2989 if (!tx_slot || !tx_num) {
2990 pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
2991 __func__, (u32) tx_slot, (u32) tx_num);
2992 return -EINVAL;
2993 }
2994 list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
2995 list) {
2996 dev_dbg(dai->codec->dev, "%s: tx_slot[%d] %d, ch->ch_num %d\n",
2997 __func__, i, tx_slot[i], ch->ch_num);
2998 tx_slot[i++] = ch->ch_num;
2999 }
3000 dev_dbg(dai->codec->dev, "%s: tx_num %d\n", __func__, i);
3001 *tx_num = i;
3002 break;
3003
3004 default:
3005 pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id);
3006 break;
3007 }
3008
3009 return 0;
3010}
3011
3012static int tapan_set_interpolator_rate(struct snd_soc_dai *dai,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003013 u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003014{
3015 u32 j;
3016 u8 rx_mix1_inp;
3017 u16 rx_mix_1_reg_1, rx_mix_1_reg_2;
3018 u16 rx_fs_reg;
3019 u8 rx_mix_1_reg_1_val, rx_mix_1_reg_2_val;
3020 struct snd_soc_codec *codec = dai->codec;
3021 struct wcd9xxx_ch *ch;
3022 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3023
3024 list_for_each_entry(ch, &tapan->dai[dai->id].wcd9xxx_ch_list, list) {
3025 /* for RX port starting from 16 instead of 10 like tabla */
3026 rx_mix1_inp = ch->port + RX_MIX1_INP_SEL_RX1 -
3027 TAPAN_TX_PORT_NUMBER;
3028 if ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003029 (rx_mix1_inp > RX_MIX1_INP_SEL_RX5)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003030 pr_err("%s: Invalid TAPAN_RX%u port. Dai ID is %d\n",
3031 __func__, rx_mix1_inp - 5 , dai->id);
3032 return -EINVAL;
3033 }
3034
3035 rx_mix_1_reg_1 = TAPAN_A_CDC_CONN_RX1_B1_CTL;
3036
3037 for (j = 0; j < NUM_INTERPOLATORS; j++) {
3038 rx_mix_1_reg_2 = rx_mix_1_reg_1 + 1;
3039
3040 rx_mix_1_reg_1_val = snd_soc_read(codec,
3041 rx_mix_1_reg_1);
3042 rx_mix_1_reg_2_val = snd_soc_read(codec,
3043 rx_mix_1_reg_2);
3044
3045 if (((rx_mix_1_reg_1_val & 0x0F) == rx_mix1_inp) ||
3046 (((rx_mix_1_reg_1_val >> 4) & 0x0F)
3047 == rx_mix1_inp) ||
3048 ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
3049
3050 rx_fs_reg = TAPAN_A_CDC_RX1_B5_CTL + 8 * j;
3051
3052 dev_dbg(codec->dev, "%s: AIF_PB DAI(%d) connected to RX%u\n",
3053 __func__, dai->id, j + 1);
3054
3055 dev_dbg(codec->dev, "%s: set RX%u sample rate to %u\n",
3056 __func__, j + 1, sample_rate);
3057
3058 snd_soc_update_bits(codec, rx_fs_reg,
3059 0xE0, rx_fs_rate_reg_val);
3060
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003061 if (comp_rx_path[j] < COMPANDER_MAX)
3062 tapan->comp_fs[comp_rx_path[j]]
3063 = compander_fs;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003064 }
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07003065 if (j <= 1)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003066 rx_mix_1_reg_1 += 3;
3067 else
3068 rx_mix_1_reg_1 += 2;
3069 }
3070 }
3071 return 0;
3072}
3073
3074static int tapan_set_decimator_rate(struct snd_soc_dai *dai,
3075 u8 tx_fs_rate_reg_val, u32 sample_rate)
3076{
3077 struct snd_soc_codec *codec = dai->codec;
3078 struct wcd9xxx_ch *ch;
3079 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3080 u32 tx_port;
3081 u16 tx_port_reg, tx_fs_reg;
3082 u8 tx_port_reg_val;
3083 s8 decimator;
3084
3085 list_for_each_entry(ch, &tapan->dai[dai->id].wcd9xxx_ch_list, list) {
3086
3087 tx_port = ch->port + 1;
3088 dev_dbg(codec->dev, "%s: dai->id = %d, tx_port = %d",
3089 __func__, dai->id, tx_port);
3090
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003091 if ((tx_port < 1) || (tx_port > TAPAN_SLIM_CODEC_TX_PORTS)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003092 pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
3093 __func__, tx_port, dai->id);
3094 return -EINVAL;
3095 }
3096
3097 tx_port_reg = TAPAN_A_CDC_CONN_TX_SB_B1_CTL + (tx_port - 1);
3098 tx_port_reg_val = snd_soc_read(codec, tx_port_reg);
3099
3100 decimator = 0;
3101
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003102 tx_port_reg_val = tx_port_reg_val & 0x0F;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003103
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003104 if ((tx_port_reg_val >= 0x8) &&
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003105 (tx_port_reg_val <= 0x11)) {
3106
3107 decimator = (tx_port_reg_val - 0x8) + 1;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003108 }
3109
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003110
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003111 if (decimator) { /* SLIM_TX port has a DEC as input */
3112
3113 tx_fs_reg = TAPAN_A_CDC_TX1_CLK_FS_CTL +
3114 8 * (decimator - 1);
3115
3116 dev_dbg(codec->dev, "%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
3117 __func__, decimator, tx_port, sample_rate);
3118
3119 snd_soc_update_bits(codec, tx_fs_reg, 0x07,
3120 tx_fs_rate_reg_val);
3121
3122 } else {
3123 if ((tx_port_reg_val >= 0x1) &&
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003124 (tx_port_reg_val <= 0x4)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003125
3126 dev_dbg(codec->dev, "%s: RMIX%u going to SLIM TX%u\n",
3127 __func__, tx_port_reg_val, tx_port);
3128
3129 } else if ((tx_port_reg_val >= 0x8) &&
3130 (tx_port_reg_val <= 0x11)) {
3131
3132 pr_err("%s: ERROR: Should not be here\n",
3133 __func__);
3134 pr_err("%s: ERROR: DEC connected to SLIM TX%u\n",
3135 __func__, tx_port);
3136 return -EINVAL;
3137
3138 } else if (tx_port_reg_val == 0) {
3139 dev_dbg(codec->dev, "%s: no signal to SLIM TX%u\n",
3140 __func__, tx_port);
3141 } else {
3142 pr_err("%s: ERROR: wrong signal to SLIM TX%u\n",
3143 __func__, tx_port);
3144 pr_err("%s: ERROR: wrong signal = %u\n",
3145 __func__, tx_port_reg_val);
3146 return -EINVAL;
3147 }
3148 }
3149 }
3150 return 0;
3151}
3152
3153static int tapan_hw_params(struct snd_pcm_substream *substream,
3154 struct snd_pcm_hw_params *params,
3155 struct snd_soc_dai *dai)
3156{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003157 struct snd_soc_codec *codec = dai->codec;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003158 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
3159 u8 tx_fs_rate, rx_fs_rate;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003160 u32 compander_fs;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003161 int ret;
3162
3163 dev_dbg(dai->codec->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n",
3164 __func__, dai->name, dai->id,
3165 params_rate(params), params_channels(params));
3166
3167 switch (params_rate(params)) {
3168 case 8000:
3169 tx_fs_rate = 0x00;
3170 rx_fs_rate = 0x00;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003171 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003172 break;
3173 case 16000:
3174 tx_fs_rate = 0x01;
3175 rx_fs_rate = 0x20;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003176 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003177 break;
3178 case 32000:
3179 tx_fs_rate = 0x02;
3180 rx_fs_rate = 0x40;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003181 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003182 break;
3183 case 48000:
3184 tx_fs_rate = 0x03;
3185 rx_fs_rate = 0x60;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003186 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003187 break;
3188 case 96000:
3189 tx_fs_rate = 0x04;
3190 rx_fs_rate = 0x80;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003191 compander_fs = COMPANDER_FS_96KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003192 break;
3193 case 192000:
3194 tx_fs_rate = 0x05;
3195 rx_fs_rate = 0xA0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003196 compander_fs = COMPANDER_FS_192KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003197 break;
3198 default:
3199 pr_err("%s: Invalid sampling rate %d\n", __func__,
3200 params_rate(params));
3201 return -EINVAL;
3202 }
3203
3204 switch (substream->stream) {
3205 case SNDRV_PCM_STREAM_CAPTURE:
3206 ret = tapan_set_decimator_rate(dai, tx_fs_rate,
3207 params_rate(params));
3208 if (ret < 0) {
3209 pr_err("%s: set decimator rate failed %d\n", __func__,
3210 ret);
3211 return ret;
3212 }
3213
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003214 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3215 switch (params_format(params)) {
3216 case SNDRV_PCM_FORMAT_S16_LE:
3217 snd_soc_update_bits(codec,
3218 TAPAN_A_CDC_CLK_I2S_CTL,
3219 0x20, 0x20);
3220 break;
3221 case SNDRV_PCM_FORMAT_S32_LE:
3222 snd_soc_update_bits(codec,
3223 TAPAN_A_CDC_CLK_I2S_CTL,
3224 0x20, 0x00);
3225 break;
3226 default:
3227 pr_err("invalid format\n");
3228 break;
3229 }
3230 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
3231 0x07, tx_fs_rate);
3232 } else {
3233 tapan->dai[dai->id].rate = params_rate(params);
3234 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003235 break;
3236
3237 case SNDRV_PCM_STREAM_PLAYBACK:
3238 ret = tapan_set_interpolator_rate(dai, rx_fs_rate,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003239 compander_fs,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003240 params_rate(params));
3241 if (ret < 0) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003242 dev_err(codec->dev, "%s: set decimator rate failed %d\n",
3243 __func__, ret);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003244 return ret;
3245 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003246 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3247 switch (params_format(params)) {
3248 case SNDRV_PCM_FORMAT_S16_LE:
3249 snd_soc_update_bits(codec,
3250 TAPAN_A_CDC_CLK_I2S_CTL,
3251 0x20, 0x20);
3252 break;
3253 case SNDRV_PCM_FORMAT_S32_LE:
3254 snd_soc_update_bits(codec,
3255 TAPAN_A_CDC_CLK_I2S_CTL,
3256 0x20, 0x00);
3257 break;
3258 default:
3259 dev_err(codec->dev, "invalid format\n");
3260 break;
3261 }
3262 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
3263 0x03, (rx_fs_rate >> 0x05));
3264 } else {
3265 switch (params_format(params)) {
3266 case SNDRV_PCM_FORMAT_S16_LE:
3267 snd_soc_update_bits(codec,
3268 TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
3269 0xFF, 0xAA);
3270 snd_soc_update_bits(codec,
3271 TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
3272 0xFF, 0x2A);
3273 tapan->dai[dai->id].bit_width = 16;
3274 break;
3275 case SNDRV_PCM_FORMAT_S24_LE:
3276 snd_soc_update_bits(codec,
3277 TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
3278 0xFF, 0x00);
3279 snd_soc_update_bits(codec,
3280 TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
3281 0xFF, 0x00);
3282 tapan->dai[dai->id].bit_width = 24;
3283 break;
3284 default:
3285 dev_err(codec->dev, "Invalid format\n");
3286 break;
3287 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003288 tapan->dai[dai->id].rate = params_rate(params);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003289 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003290 break;
3291 default:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003292 dev_err(codec->dev, "%s: Invalid stream type %d\n", __func__,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003293 substream->stream);
3294 return -EINVAL;
3295 }
3296
3297 return 0;
3298}
3299
3300static struct snd_soc_dai_ops tapan_dai_ops = {
3301 .startup = tapan_startup,
3302 .shutdown = tapan_shutdown,
3303 .hw_params = tapan_hw_params,
3304 .set_sysclk = tapan_set_dai_sysclk,
3305 .set_fmt = tapan_set_dai_fmt,
3306 .set_channel_map = tapan_set_channel_map,
3307 .get_channel_map = tapan_get_channel_map,
3308};
3309
3310static struct snd_soc_dai_driver tapan_dai[] = {
3311 {
3312 .name = "tapan_rx1",
3313 .id = AIF1_PB,
3314 .playback = {
3315 .stream_name = "AIF1 Playback",
3316 .rates = WCD9306_RATES,
3317 .formats = TAPAN_FORMATS,
3318 .rate_max = 192000,
3319 .rate_min = 8000,
3320 .channels_min = 1,
3321 .channels_max = 2,
3322 },
3323 .ops = &tapan_dai_ops,
3324 },
3325 {
3326 .name = "tapan_tx1",
3327 .id = AIF1_CAP,
3328 .capture = {
3329 .stream_name = "AIF1 Capture",
3330 .rates = WCD9306_RATES,
3331 .formats = TAPAN_FORMATS,
3332 .rate_max = 192000,
3333 .rate_min = 8000,
3334 .channels_min = 1,
3335 .channels_max = 4,
3336 },
3337 .ops = &tapan_dai_ops,
3338 },
3339 {
3340 .name = "tapan_rx2",
3341 .id = AIF2_PB,
3342 .playback = {
3343 .stream_name = "AIF2 Playback",
3344 .rates = WCD9306_RATES,
3345 .formats = TAPAN_FORMATS,
3346 .rate_min = 8000,
3347 .rate_max = 192000,
3348 .channels_min = 1,
3349 .channels_max = 2,
3350 },
3351 .ops = &tapan_dai_ops,
3352 },
3353 {
3354 .name = "tapan_tx2",
3355 .id = AIF2_CAP,
3356 .capture = {
3357 .stream_name = "AIF2 Capture",
3358 .rates = WCD9306_RATES,
3359 .formats = TAPAN_FORMATS,
3360 .rate_max = 192000,
3361 .rate_min = 8000,
3362 .channels_min = 1,
3363 .channels_max = 4,
3364 },
3365 .ops = &tapan_dai_ops,
3366 },
3367 {
3368 .name = "tapan_tx3",
3369 .id = AIF3_CAP,
3370 .capture = {
3371 .stream_name = "AIF3 Capture",
3372 .rates = WCD9306_RATES,
3373 .formats = TAPAN_FORMATS,
3374 .rate_max = 48000,
3375 .rate_min = 8000,
3376 .channels_min = 1,
3377 .channels_max = 2,
3378 },
3379 .ops = &tapan_dai_ops,
3380 },
3381 {
3382 .name = "tapan_rx3",
3383 .id = AIF3_PB,
3384 .playback = {
3385 .stream_name = "AIF3 Playback",
3386 .rates = WCD9306_RATES,
3387 .formats = TAPAN_FORMATS,
3388 .rate_min = 8000,
3389 .rate_max = 192000,
3390 .channels_min = 1,
3391 .channels_max = 2,
3392 },
3393 .ops = &tapan_dai_ops,
3394 },
3395};
3396
3397static struct snd_soc_dai_driver tapan_i2s_dai[] = {
3398 {
3399 .name = "tapan_i2s_rx1",
3400 .id = AIF1_PB,
3401 .playback = {
3402 .stream_name = "AIF1 Playback",
3403 .rates = WCD9306_RATES,
3404 .formats = TAPAN_FORMATS,
3405 .rate_max = 192000,
3406 .rate_min = 8000,
3407 .channels_min = 1,
3408 .channels_max = 4,
3409 },
3410 .ops = &tapan_dai_ops,
3411 },
3412 {
3413 .name = "tapan_i2s_tx1",
3414 .id = AIF1_CAP,
3415 .capture = {
3416 .stream_name = "AIF1 Capture",
3417 .rates = WCD9306_RATES,
3418 .formats = TAPAN_FORMATS,
3419 .rate_max = 192000,
3420 .rate_min = 8000,
3421 .channels_min = 1,
3422 .channels_max = 4,
3423 },
3424 .ops = &tapan_dai_ops,
3425 },
3426};
3427
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003428static int tapan_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai,
3429 bool up)
3430{
3431 int ret = 0;
3432 struct wcd9xxx_ch *ch;
3433
3434 if (up) {
3435 list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
3436 ret = wcd9xxx_get_slave_port(ch->ch_num);
3437 if (ret < 0) {
3438 pr_debug("%s: Invalid slave port ID: %d\n",
3439 __func__, ret);
3440 ret = -EINVAL;
3441 } else {
3442 set_bit(ret, &dai->ch_mask);
3443 }
3444 }
3445 } else {
3446 ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
3447 msecs_to_jiffies(
3448 TAPAN_SLIM_CLOSE_TIMEOUT));
3449 if (!ret) {
3450 pr_debug("%s: Slim close tx/rx wait timeout\n",
3451 __func__);
3452 ret = -ETIMEDOUT;
3453 } else {
3454 ret = 0;
3455 }
3456 }
3457 return ret;
3458}
3459
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003460static int tapan_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3461 struct snd_kcontrol *kcontrol,
3462 int event)
3463{
3464 struct wcd9xxx *core;
3465 struct snd_soc_codec *codec = w->codec;
3466 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003467 int ret = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003468 struct wcd9xxx_codec_dai_data *dai;
3469
3470 core = dev_get_drvdata(codec->dev->parent);
3471
3472 dev_dbg(codec->dev, "%s: event called! codec name %s\n",
3473 __func__, w->codec->name);
3474 dev_dbg(codec->dev, "%s: num_dai %d stream name %s event %d\n",
3475 __func__, w->codec->num_dai, w->sname, event);
3476
3477 /* Execute the callback only if interface type is slimbus */
3478 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3479 return 0;
3480
3481 dai = &tapan_p->dai[w->shift];
3482 dev_dbg(codec->dev, "%s: w->name %s w->shift %d event %d\n",
3483 __func__, w->name, w->shift, event);
3484
3485 switch (event) {
3486 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003487 (void) tapan_codec_enable_slim_chmask(dai, true);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003488 ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3489 dai->rate, dai->bit_width,
3490 &dai->grph);
3491 break;
3492 case SND_SOC_DAPM_POST_PMD:
3493 ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3494 dai->grph);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003495 ret = tapan_codec_enable_slim_chmask(dai, false);
3496 if (ret < 0) {
3497 ret = wcd9xxx_disconnect_port(core,
3498 &dai->wcd9xxx_ch_list,
3499 dai->grph);
3500 dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
3501 __func__, ret);
3502 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003503 break;
3504 }
3505 return ret;
3506}
3507
3508static int tapan_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3509 struct snd_kcontrol *kcontrol,
3510 int event)
3511{
3512 struct wcd9xxx *core;
3513 struct snd_soc_codec *codec = w->codec;
3514 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
3515 u32 ret = 0;
3516 struct wcd9xxx_codec_dai_data *dai;
3517
3518 core = dev_get_drvdata(codec->dev->parent);
3519
3520 dev_dbg(codec->dev, "%s: event called! codec name %s\n",
3521 __func__, w->codec->name);
3522 dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
3523 __func__, w->codec->num_dai, w->sname);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003524 /* Execute the callback only if interface type is slimbus */
3525 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3526 return 0;
3527
3528 dev_dbg(codec->dev, "%s(): w->name %s event %d w->shift %d\n",
3529 __func__, w->name, event, w->shift);
3530
3531 dai = &tapan_p->dai[w->shift];
3532 switch (event) {
3533 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003534 (void) tapan_codec_enable_slim_chmask(dai, true);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003535 ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3536 dai->rate, dai->bit_width,
3537 &dai->grph);
3538 break;
3539 case SND_SOC_DAPM_POST_PMD:
3540 ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3541 dai->grph);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003542 ret = tapan_codec_enable_slim_chmask(dai, false);
3543 if (ret < 0) {
3544 ret = wcd9xxx_disconnect_port(core,
3545 &dai->wcd9xxx_ch_list,
3546 dai->grph);
3547 dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
3548 __func__, ret);
3549 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003550 break;
3551 }
3552 return ret;
3553}
3554
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003555
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003556static int tapan_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
3557 struct snd_kcontrol *kcontrol, int event)
3558{
3559 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003560 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003561
3562 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
3563
3564 switch (event) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003565 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003566 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3567 WCD9XXX_CLSH_STATE_EAR,
3568 WCD9XXX_CLSH_REQ_ENABLE,
3569 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003570
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003571 usleep_range(5000, 5010);
3572 break;
3573 case SND_SOC_DAPM_POST_PMD:
3574 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3575 WCD9XXX_CLSH_STATE_EAR,
3576 WCD9XXX_CLSH_REQ_DISABLE,
3577 WCD9XXX_CLSH_EVENT_POST_PA);
3578 usleep_range(5000, 5010);
3579 }
3580 return 0;
3581}
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003582
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003583static int tapan_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
3584 struct snd_kcontrol *kcontrol, int event)
3585{
3586 struct snd_soc_codec *codec = w->codec;
3587 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
3588
3589 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
3590
3591 switch (event) {
3592 case SND_SOC_DAPM_PRE_PMU:
3593 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3594 WCD9XXX_CLSH_STATE_EAR,
3595 WCD9XXX_CLSH_REQ_ENABLE,
3596 WCD9XXX_CLSH_EVENT_PRE_DAC);
3597 break;
3598 }
3599
3600 return 0;
3601}
3602
3603static int tapan_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
3604 struct snd_kcontrol *kcontrol, int event)
3605{
3606 struct snd_soc_codec *codec = w->codec;
3607 u8 reg_val, zoh_mux_val = 0x00;
3608
3609 dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
3610
3611 switch (event) {
3612 case SND_SOC_DAPM_POST_PMU:
3613 reg_val = snd_soc_read(codec, TAPAN_A_CDC_CONN_CLSH_CTL);
3614
3615 if ((reg_val & 0x30) == 0x10)
3616 zoh_mux_val = 0x04;
3617 else if ((reg_val & 0x30) == 0x20)
3618 zoh_mux_val = 0x08;
3619
3620 if (zoh_mux_val != 0x00)
3621 snd_soc_update_bits(codec,
3622 TAPAN_A_CDC_CONN_CLSH_CTL,
3623 0x0C, zoh_mux_val);
3624 break;
3625
3626 case SND_SOC_DAPM_POST_PMD:
3627 snd_soc_update_bits(codec, TAPAN_A_CDC_CONN_CLSH_CTL,
3628 0x0C, 0x00);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003629 break;
3630 }
3631 return 0;
3632}
3633
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07003634static int tapan_codec_enable_anc_ear(struct snd_soc_dapm_widget *w,
3635 struct snd_kcontrol *kcontrol, int event)
3636{
3637 struct snd_soc_codec *codec = w->codec;
3638 int ret = 0;
3639
3640 switch (event) {
3641 case SND_SOC_DAPM_PRE_PMU:
3642 ret = tapan_codec_enable_anc(w, kcontrol, event);
3643 msleep(50);
3644 snd_soc_update_bits(codec, TAPAN_A_RX_EAR_EN, 0x10, 0x10);
3645 break;
3646 case SND_SOC_DAPM_POST_PMU:
3647 ret = tapan_codec_enable_ear_pa(w, kcontrol, event);
3648 break;
3649 case SND_SOC_DAPM_PRE_PMD:
3650 snd_soc_update_bits(codec, TAPAN_A_RX_EAR_EN, 0x10, 0x00);
3651 msleep(40);
3652 ret |= tapan_codec_enable_anc(w, kcontrol, event);
3653 break;
3654 case SND_SOC_DAPM_POST_PMD:
3655 ret = tapan_codec_enable_ear_pa(w, kcontrol, event);
3656 break;
3657 }
3658 return ret;
3659}
3660
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003661
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003662/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3663 * Might Need to have callbacks registered only for slimbus
3664 */
3665static const struct snd_soc_dapm_widget tapan_dapm_widgets[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003666
3667 SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
3668 AIF1_PB, 0, tapan_codec_enable_slimrx,
3669 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3670 SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
3671 AIF2_PB, 0, tapan_codec_enable_slimrx,
3672 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3673 SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
3674 AIF3_PB, 0, tapan_codec_enable_slimrx,
3675 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3676
3677 SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TAPAN_RX1, 0,
3678 &slim_rx_mux[TAPAN_RX1]),
3679 SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TAPAN_RX2, 0,
3680 &slim_rx_mux[TAPAN_RX2]),
3681 SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TAPAN_RX3, 0,
3682 &slim_rx_mux[TAPAN_RX3]),
3683 SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TAPAN_RX4, 0,
3684 &slim_rx_mux[TAPAN_RX4]),
3685 SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TAPAN_RX5, 0,
3686 &slim_rx_mux[TAPAN_RX5]),
3687
3688 SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
3689 SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
3690 SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
3691 SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
3692 SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
3693
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003694
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003695 /* RX1 MIX1 mux inputs */
3696 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3697 &rx_mix1_inp1_mux),
3698 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3699 &rx_mix1_inp2_mux),
3700 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
3701 &rx_mix1_inp3_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003702
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003703 /* RX2 MIX1 mux inputs */
3704 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3705 &rx2_mix1_inp1_mux),
3706 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3707 &rx2_mix1_inp2_mux),
3708 SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
3709 &rx2_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003710
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003711 /* RX3 MIX1 mux inputs */
3712 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3713 &rx3_mix1_inp1_mux),
3714 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3715 &rx3_mix1_inp2_mux),
3716 SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
3717 &rx3_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003718
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003719 /* RX4 MIX1 mux inputs */
3720 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3721 &rx4_mix1_inp1_mux),
3722 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3723 &rx4_mix1_inp2_mux),
3724 SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
3725 &rx4_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003726
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003727 /* RX1 MIX2 mux inputs */
3728 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
3729 &rx1_mix2_inp1_mux),
3730 SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
3731 &rx1_mix2_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003732
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003733 /* RX2 MIX2 mux inputs */
3734 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
3735 &rx2_mix2_inp1_mux),
3736 SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
3737 &rx2_mix2_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003738
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003739 /* RX4 MIX2 mux inputs */
3740 SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
3741 &rx4_mix2_inp1_mux),
3742 SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
3743 &rx4_mix2_inp2_mux),
3744
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003745
3746 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
3747 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003748 SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003749
3750 SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
3751 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
3752 SND_SOC_DAPM_POST_PMU),
3753 SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
3754 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
3755 SND_SOC_DAPM_POST_PMU),
3756 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
3757 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
3758 SND_SOC_DAPM_POST_PMU),
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003759 SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003760 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
3761 SND_SOC_DAPM_POST_PMU),
3762
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003763 SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
3764 NULL, 0),
3765 SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0,
3766 NULL, 0),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003767
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003768 SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
3769 &class_h_dsm_mux, tapan_codec_dsm_mux_event,
3770 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003771
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003772 /* RX Bias */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003773 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
3774 tapan_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
3775 SND_SOC_DAPM_POST_PMD),
3776
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003777 /*EAR */
3778 SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
3779 tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
3780 SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003781
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003782 SND_SOC_DAPM_MIXER_E("DAC1", TAPAN_A_RX_EAR_EN, 6, 0, dac1_switch,
3783 ARRAY_SIZE(dac1_switch), tapan_codec_ear_dac_event,
3784 SND_SOC_DAPM_PRE_PMU),
3785
3786 /* Headphone Left */
3787 SND_SOC_DAPM_PGA_E("HPHL", TAPAN_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3788 tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3789 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3790
3791 SND_SOC_DAPM_MIXER_E("HPHL DAC", TAPAN_A_RX_HPH_L_DAC_CTL, 7, 0,
3792 hphl_switch, ARRAY_SIZE(hphl_switch), tapan_hphl_dac_event,
3793 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3794
3795 /* Headphone Right */
3796 SND_SOC_DAPM_PGA_E("HPHR", TAPAN_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
3797 tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3798 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3799
3800 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAPAN_A_RX_HPH_R_DAC_CTL, 7, 0,
3801 tapan_hphr_dac_event,
3802 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3803
3804 /* LINEOUT1*/
3805 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TAPAN_A_RX_LINE_1_DAC_CTL, 7, 0
3806 , tapan_lineout_dac_event,
3807 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3808
3809 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TAPAN_A_RX_LINE_CNP_EN, 0, 0, NULL,
3810 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3811 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3812
3813 /* LINEOUT2*/
3814 SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
3815 &rx_dac5_mux),
3816
3817 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
3818 , tapan_lineout_dac_event,
3819 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3820
3821 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TAPAN_A_RX_LINE_CNP_EN, 1, 0, NULL,
3822 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3823 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3824
3825 /* CLASS-D SPK */
3826 SND_SOC_DAPM_MIXER_E("SPK DAC", SND_SOC_NOPM, 0, 0,
3827 spk_dac_switch, ARRAY_SIZE(spk_dac_switch), tapan_spk_dac_event,
3828 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3829
3830 SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0 , NULL,
3831 0, tapan_codec_enable_spk_pa,
3832 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3833
3834 SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
3835 tapan_codec_enable_vdd_spkr,
3836 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3837
3838 SND_SOC_DAPM_OUTPUT("EAR"),
3839 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3840 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
3841 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
3842 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
3843
3844 /* TX Path*/
3845 SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
3846 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
3847
3848 SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
3849 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
3850
3851 SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
3852 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
3853
3854 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TAPAN_TX1, 0,
3855 &sb_tx1_mux),
3856 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TAPAN_TX2, 0,
3857 &sb_tx2_mux),
3858 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TAPAN_TX3, 0,
3859 &sb_tx3_mux),
3860 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TAPAN_TX4, 0,
3861 &sb_tx4_mux),
3862 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TAPAN_TX5, 0,
3863 &sb_tx5_mux),
3864
3865 SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003866 0),
3867
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003868 /* Decimator MUX */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003869 SND_SOC_DAPM_MUX_E("DEC1 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
3870 &dec1_mux, tapan_codec_enable_dec,
3871 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3872 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
3873
3874 SND_SOC_DAPM_MUX_E("DEC2 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
3875 &dec2_mux, tapan_codec_enable_dec,
3876 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3877 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
3878
3879 SND_SOC_DAPM_MUX_E("DEC3 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
3880 &dec3_mux, tapan_codec_enable_dec,
3881 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3882 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
3883
3884 SND_SOC_DAPM_MUX_E("DEC4 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
3885 &dec4_mux, tapan_codec_enable_dec,
3886 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3887 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
3888
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003889 SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
3890 tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
3891
3892 SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
3893 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
3894 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3895 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
3896 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
3897 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3898 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
3899 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
3900 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3901
3902 SND_SOC_DAPM_INPUT("AMIC1"),
3903 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
3904 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3905 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3906 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAPAN_A_MICB_1_CTL, 7, 0,
3907 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3908 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3909 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAPAN_A_MICB_1_CTL, 7, 0,
3910 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3911 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3912
3913 SND_SOC_DAPM_ADC_E("ADC1", NULL, TAPAN_A_TX_1_EN, 7, 0,
3914 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3915 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3916 SND_SOC_DAPM_ADC_E("ADC2", NULL, TAPAN_A_TX_2_EN, 7, 0,
3917 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3918 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3919
3920 SND_SOC_DAPM_INPUT("AMIC3"),
3921 SND_SOC_DAPM_ADC_E("ADC3", NULL, TAPAN_A_TX_3_EN, 7, 0,
3922 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3923 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3924
3925 SND_SOC_DAPM_INPUT("AMIC4"),
3926 SND_SOC_DAPM_ADC_E("ADC4", NULL, TAPAN_A_TX_4_EN, 7, 0,
3927 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3928 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3929
3930 SND_SOC_DAPM_INPUT("AMIC5"),
3931 SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
3932 tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3933
3934 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
3935 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
3936
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07003937 SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
3938 SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 5, 0, NULL, 0,
3939 tapan_codec_enable_anc_hph,
3940 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
3941 SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
3942 SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 4, 0, NULL, 0,
3943 tapan_codec_enable_anc_hph, SND_SOC_DAPM_PRE_PMU |
3944 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
3945 SND_SOC_DAPM_POST_PMU),
3946 SND_SOC_DAPM_OUTPUT("ANC EAR"),
3947 SND_SOC_DAPM_PGA_E("ANC EAR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
3948 tapan_codec_enable_anc_ear,
3949 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
3950 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3951 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003952
3953 SND_SOC_DAPM_INPUT("AMIC2"),
3954 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAPAN_A_MICB_2_CTL, 7, 0,
3955 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3956 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3957 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TAPAN_A_MICB_2_CTL, 7, 0,
3958 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3959 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3960 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TAPAN_A_MICB_2_CTL, 7, 0,
3961 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3962 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3963 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAPAN_A_MICB_2_CTL, 7, 0,
3964 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3965 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3966 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAPAN_A_MICB_3_CTL, 7, 0,
3967 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3968 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3969 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAPAN_A_MICB_3_CTL, 7, 0,
3970 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3971 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3972 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAPAN_A_MICB_3_CTL, 7, 0,
3973 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3974 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3975
3976 SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
3977 AIF1_CAP, 0, tapan_codec_enable_slimtx,
3978 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3979
3980 SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
3981 AIF2_CAP, 0, tapan_codec_enable_slimtx,
3982 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3983
3984 SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
3985 AIF3_CAP, 0, tapan_codec_enable_slimtx,
3986 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3987
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003988 /* Digital Mic Inputs */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003989 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
3990 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3991 SND_SOC_DAPM_POST_PMD),
3992
3993 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
3994 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3995 SND_SOC_DAPM_POST_PMD),
3996
3997 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
3998 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3999 SND_SOC_DAPM_POST_PMD),
4000
4001 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
4002 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4003 SND_SOC_DAPM_POST_PMD),
4004
4005 /* Sidetone */
4006 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
4007 SND_SOC_DAPM_PGA("IIR1", TAPAN_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
4008
4009 /* AUX PGA */
4010 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TAPAN_A_RX_AUX_SW_CTL, 7, 0,
4011 tapan_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4012 SND_SOC_DAPM_POST_PMD),
4013
4014 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TAPAN_A_RX_AUX_SW_CTL, 6, 0,
4015 tapan_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4016 SND_SOC_DAPM_POST_PMD),
4017
4018 /* Lineout, ear and HPH PA Mixers */
4019
4020 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4021 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
4022
4023 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
4024 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
4025
4026 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4027 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4028
4029 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4030 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4031
4032 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4033 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004034};
4035
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004036static irqreturn_t tapan_slimbus_irq(int irq, void *data)
4037{
4038 struct tapan_priv *priv = data;
4039 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004040 unsigned long status = 0;
4041 int i, j, port_id, k;
4042 u32 bit;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004043 u8 val;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004044 bool tx, cleared;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004045
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004046 for (i = TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
4047 i <= TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
4048 val = wcd9xxx_interface_reg_read(codec->control_data, i);
4049 status |= ((u32)val << (8 * j));
4050 }
4051
4052 for_each_set_bit(j, &status, 32) {
4053 tx = (j >= 16 ? true : false);
4054 port_id = (tx ? j - 16 : j);
4055 val = wcd9xxx_interface_reg_read(codec->control_data,
4056 TAPAN_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
4057 if (val & TAPAN_SLIM_IRQ_OVERFLOW)
4058 pr_err_ratelimited(
4059 "%s: overflow error on %s port %d, value %x\n",
4060 __func__, (tx ? "TX" : "RX"), port_id, val);
4061 if (val & TAPAN_SLIM_IRQ_UNDERFLOW)
4062 pr_err_ratelimited(
4063 "%s: underflow error on %s port %d, value %x\n",
4064 __func__, (tx ? "TX" : "RX"), port_id, val);
4065 if (val & TAPAN_SLIM_IRQ_PORT_CLOSED) {
4066 /*
4067 * INT SOURCE register starts from RX to TX
4068 * but port number in the ch_mask is in opposite way
4069 */
4070 bit = (tx ? j - 16 : j + 16);
4071 dev_dbg(codec->dev, "%s: %s port %d closed value %x, bit %u\n",
4072 __func__, (tx ? "TX" : "RX"), port_id, val,
4073 bit);
4074 for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
4075 dev_dbg(codec->dev, "%s: priv->dai[%d].ch_mask = 0x%lx\n",
4076 __func__, k, priv->dai[k].ch_mask);
4077 if (test_and_clear_bit(bit,
4078 &priv->dai[k].ch_mask)) {
4079 cleared = true;
4080 if (!priv->dai[k].ch_mask)
4081 wake_up(&priv->dai[k].dai_wait);
4082 /*
4083 * There are cases when multiple DAIs
4084 * might be using the same slimbus
4085 * channel. Hence don't break here.
4086 */
4087 }
4088 }
4089 WARN(!cleared,
4090 "Couldn't find slimbus %s port %d for closing\n",
4091 (tx ? "TX" : "RX"), port_id);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004092 }
4093 wcd9xxx_interface_reg_write(codec->control_data,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004094 TAPAN_SLIM_PGD_PORT_INT_CLR_RX_0 +
4095 (j / 8),
4096 1 << (j % 8));
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004097 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004098
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004099 return IRQ_HANDLED;
4100}
4101
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004102static int tapan_handle_pdata(struct tapan_priv *tapan)
4103{
4104 struct snd_soc_codec *codec = tapan->codec;
4105 struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
4106 int k1, k2, k3, rc = 0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004107 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4108 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4109 u8 flag = pdata->amic_settings.use_pdata;
4110 u8 i = 0, j = 0;
4111 u8 val_txfe = 0, value = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004112
4113 if (!pdata) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004114 dev_err(codec->dev, "%s: NULL pdata\n", __func__);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004115 rc = -ENODEV;
4116 goto done;
4117 }
4118
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004119 /* Make sure settings are correct */
4120 if ((pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V) ||
4121 (pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
4122 (pdata->micbias.bias2_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
4123 (pdata->micbias.bias3_cfilt_sel > WCD9XXX_CFILT3_SEL)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004124 dev_err(codec->dev, "%s: Invalid ldoh voltage or bias cfilt\n",
4125 __func__);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004126 rc = -EINVAL;
4127 goto done;
4128 }
4129 /* figure out k value */
4130 k1 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt1_mv);
4131 k2 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt2_mv);
4132 k3 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt3_mv);
4133
4134 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004135 dev_err(codec->dev,
4136 "%s: could not get K value. k1 = %d k2 = %d k3 = %d\n",
4137 __func__, k1, k2, k3);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004138 rc = -EINVAL;
4139 goto done;
4140 }
4141 /* Set voltage level and always use LDO */
4142 snd_soc_update_bits(codec, TAPAN_A_LDO_H_MODE_1, 0x0C,
4143 (pdata->micbias.ldoh_v << 2));
4144
4145 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_1_VAL, 0xFC, (k1 << 2));
4146 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_2_VAL, 0xFC, (k2 << 2));
4147 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_3_VAL, 0xFC, (k3 << 2));
4148
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004149 i = 0;
4150 while (i < 5) {
4151 if (flag & (0x01 << i)) {
4152 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4153 val_txfe = val_txfe |
4154 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4155 snd_soc_update_bits(codec,
4156 TAPAN_A_TX_1_2_TEST_EN + j * 10,
4157 0x30, val_txfe);
4158 }
4159 if (flag & (0x01 << (i + 1))) {
4160 val_txfe = (txfe_bypass &
4161 (0x01 << (i + 1))) ? 0x02 : 0x00;
4162 val_txfe |= (txfe_buff &
4163 (0x01 << (i + 1))) ? 0x01 : 0x00;
4164 snd_soc_update_bits(codec,
4165 TAPAN_A_TX_1_2_TEST_EN + j * 10,
4166 0x03, val_txfe);
4167 }
4168 /* Tapan only has TAPAN_A_TX_1_2_TEST_EN and
4169 TAPAN_A_TX_4_5_TEST_EN reg */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004170
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004171 if (i == 0) {
4172 i = 3;
4173 continue;
4174 } else if (i == 3) {
4175 break;
4176 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004177 }
4178
4179 if (pdata->ocp.use_pdata) {
4180 /* not defined in CODEC specification */
4181 if (pdata->ocp.hph_ocp_limit == 1 ||
4182 pdata->ocp.hph_ocp_limit == 5) {
4183 rc = -EINVAL;
4184 goto done;
4185 }
4186 snd_soc_update_bits(codec, TAPAN_A_RX_COM_OCP_CTL,
4187 0x0F, pdata->ocp.num_attempts);
4188 snd_soc_write(codec, TAPAN_A_RX_COM_OCP_COUNT,
4189 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4190 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_OCP_CTL,
4191 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4192 }
4193
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004194 /* Set micbias capless mode with tail current */
4195 value = (pdata->micbias.bias1_cap_mode == MICBIAS_EXT_BYP_CAP ?
4196 0x00 : 0x10);
4197 snd_soc_update_bits(codec, TAPAN_A_MICB_1_CTL, 0x10, value);
4198 value = (pdata->micbias.bias2_cap_mode == MICBIAS_EXT_BYP_CAP ?
4199 0x00 : 0x10);
4200 snd_soc_update_bits(codec, TAPAN_A_MICB_2_CTL, 0x10, value);
4201 value = (pdata->micbias.bias3_cap_mode == MICBIAS_EXT_BYP_CAP ?
4202 0x00 : 0x10);
4203 snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x10, value);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004204
4205done:
4206 return rc;
4207}
4208
4209static const struct tapan_reg_mask_val tapan_reg_defaults[] = {
4210
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004211 /* enable QFUSE for wcd9306 */
4212 TAPAN_REG_VAL(TAPAN_A_QFUSE_CTL, 0x03),
4213
4214 /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
4215 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
4216
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004217 TAPAN_REG_VAL(TAPAN_A_CDC_CLK_POWER_CTL, 0x03),
4218
4219 /* EAR PA deafults */
4220 TAPAN_REG_VAL(TAPAN_A_RX_EAR_CMBUFF, 0x05),
4221
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004222 /* RX1 and RX2 defaults */
4223 TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B6_CTL, 0xA0),
4224 TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0xA0),
4225
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004226 /* Heaset set Right from RX2 */
4227 TAPAN_REG_VAL(TAPAN_A_CDC_CONN_RX2_B2_CTL, 0x10),
4228
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004229
4230 /*
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004231 * The following only need to be written for Tapan 1.0 parts.
4232 * Tapan 2.0 will have appropriate defaults for these registers.
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004233 */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004234
4235 /* Required defaults for class H operation */
4236 /* borrowed from Taiko class-h */
4237 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0xF4),
4238 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x08),
4239 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
4240 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
4241
4242 /* TODO: Check below reg writes conflict with above */
4243 /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
4244 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
4245 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x54),
4246 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0x74),
4247 TAPAN_REG_VAL(TAPAN_A_RX_BUCK_BIAS1, 0x62),
4248
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004249 /* Choose max non-overlap time for NCP */
4250 TAPAN_REG_VAL(TAPAN_A_NCP_CLK, 0xFC),
4251 /* Use 25mV/50mV for deltap/m to reduce ripple */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004252 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004253 /*
4254 * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
4255 * Note that the other bits of this register will be changed during
4256 * Rx PA bring up.
4257 */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004258 TAPAN_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004259 /* Reduce HPH DAC bias to 70% */
4260 TAPAN_REG_VAL(TAPAN_A_RX_HPH_BIAS_PA, 0x7A),
4261 /*Reduce EAR DAC bias to 70% */
4262 TAPAN_REG_VAL(TAPAN_A_RX_EAR_BIAS_PA, 0x76),
4263 /* Reduce LINE DAC bias to 70% */
4264 TAPAN_REG_VAL(TAPAN_A_RX_LINE_BIAS_PA, 0x78),
4265
4266 /*
4267 * There is a diode to pull down the micbias while doing
4268 * insertion detection. This diode can cause leakage.
4269 * Set bit 0 to 1 to prevent leakage.
4270 * Setting this bit of micbias 2 prevents leakage for all other micbias.
4271 */
4272 TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
4273
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004274 /* not needed if MBHC is not needed */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004275 /* Disable TX7 internal biasing path which can cause leakage */
4276 TAPAN_REG_VAL(TAPAN_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
4277};
4278
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004279static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
4280
4281 TAPAN_REG_VAL(TAPAN_A_TX_7_MBHC_EN, 0x6C),
4282 TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_4, 0x51),
4283 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CNP_WG_CTL, 0xDA),
4284 TAPAN_REG_VAL(TAPAN_A_RX_EAR_CNP, 0xC0),
4285 TAPAN_REG_VAL(TAPAN_A_RX_LINE_1_TEST, 0x02),
4286 TAPAN_REG_VAL(TAPAN_A_RX_LINE_2_TEST, 0x02),
4287 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_OCP_CTL, 0x97),
4288 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_CLIP_DET, 0x01),
4289 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_IEC, 0x00),
4290 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B1_CTL, 0xE4),
4291 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x00),
4292 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x00),
4293 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
4294 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_EAR, 0x00),
4295 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_HPH, 0x00),
4296 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_EAR, 0x00),
4297 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_HPH, 0x00),
4298};
4299
4300static const struct tapan_reg_mask_val tapan_1_0_reg_defaults[] = {
4301 /* Close leakage on the spkdrv */
4302 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_PWRSTG, 0x24),
4303 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_DAC, 0xE5),
4304
4305};
4306
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004307static void tapan_update_reg_defaults(struct snd_soc_codec *codec)
4308{
4309 u32 i;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004310 struct wcd9xxx *tapan_core = dev_get_drvdata(codec->dev->parent);
4311
4312 if (!TAPAN_IS_1_0(tapan_core->version)) {
4313 for (i = 0; i < ARRAY_SIZE(tapan_2_x_reg_reset_values); i++)
4314 snd_soc_write(codec, tapan_2_x_reg_reset_values[i].reg,
4315 tapan_2_x_reg_reset_values[i].val);
4316 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004317
4318 for (i = 0; i < ARRAY_SIZE(tapan_reg_defaults); i++)
4319 snd_soc_write(codec, tapan_reg_defaults[i].reg,
4320 tapan_reg_defaults[i].val);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004321
4322 if (TAPAN_IS_1_0(tapan_core->version)) {
4323 for (i = 0; i < ARRAY_SIZE(tapan_1_0_reg_defaults); i++)
4324 snd_soc_write(codec, tapan_1_0_reg_defaults[i].reg,
4325 tapan_1_0_reg_defaults[i].val);
4326 }
4327
4328 if (!TAPAN_IS_1_0(tapan_core->version))
4329 spkr_drv_wrnd = -1;
4330 else if (spkr_drv_wrnd == 1)
4331 snd_soc_write(codec, TAPAN_A_SPKR_DRV_EN, 0xEF);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004332}
4333
4334static const struct tapan_reg_mask_val tapan_codec_reg_init_val[] = {
4335 /* Initialize current threshold to 350MA
4336 * number of wait and run cycles to 4096
4337 */
4338 {TAPAN_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
4339 {TAPAN_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
4340
4341 /* Initialize gain registers to use register gain */
4342 {TAPAN_A_RX_HPH_L_GAIN, 0x20, 0x20},
4343 {TAPAN_A_RX_HPH_R_GAIN, 0x20, 0x20},
4344 {TAPAN_A_RX_LINE_1_GAIN, 0x20, 0x20},
4345 {TAPAN_A_RX_LINE_2_GAIN, 0x20, 0x20},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004346 {TAPAN_A_SPKR_DRV_GAIN, 0x04, 0x04},
4347
4348 /* Set RDAC5 MUX to take input from DEM3_INV.
4349 * This sets LO2 DAC to get input from DEM3_INV
4350 * for LO1 and LO2 to work as differential outputs.
4351 */
4352 {TAPAN_A_CDC_CONN_MISC, 0x04, 0x04},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004353
4354 /* CLASS H config */
4355 {TAPAN_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
4356
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004357 /* Use 16 bit sample size for TX1 to TX5 */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004358 {TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
4359 {TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4360 {TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4361 {TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4362 {TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
4363
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004364 /* Disable SPK SWITCH */
4365 {TAPAN_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
4366
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004367 /* Use 16 bit sample size for RX */
4368 {TAPAN_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4369 {TAPAN_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
4370
4371 /*enable HPF filter for TX paths */
4372 {TAPAN_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
4373 {TAPAN_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
4374 {TAPAN_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
4375 {TAPAN_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
4376
4377 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
4378 {TAPAN_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
4379 {TAPAN_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
4380 {TAPAN_A_CDC_TX3_DMIC_CTL, 0x7, 0x1},
4381 {TAPAN_A_CDC_TX4_DMIC_CTL, 0x7, 0x1},
4382
4383 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
4384 {TAPAN_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004385
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004386 /* Compander zone selection */
4387 {TAPAN_A_CDC_COMP0_B4_CTL, 0x3F, 0x37},
4388 {TAPAN_A_CDC_COMP1_B4_CTL, 0x3F, 0x37},
4389 {TAPAN_A_CDC_COMP2_B4_CTL, 0x3F, 0x37},
4390 {TAPAN_A_CDC_COMP0_B5_CTL, 0x7F, 0x7F},
4391 {TAPAN_A_CDC_COMP1_B5_CTL, 0x7F, 0x7F},
4392 {TAPAN_A_CDC_COMP2_B5_CTL, 0x7F, 0x7F},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004393};
4394
4395static void tapan_codec_init_reg(struct snd_soc_codec *codec)
4396{
4397 u32 i;
4398
4399 for (i = 0; i < ARRAY_SIZE(tapan_codec_reg_init_val); i++)
4400 snd_soc_update_bits(codec, tapan_codec_reg_init_val[i].reg,
4401 tapan_codec_reg_init_val[i].mask,
4402 tapan_codec_reg_init_val[i].val);
4403}
4404
4405static int tapan_setup_irqs(struct tapan_priv *tapan)
4406{
4407 int i;
4408 int ret = 0;
4409 struct snd_soc_codec *codec = tapan->codec;
4410
4411 ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
4412 tapan_slimbus_irq, "SLIMBUS Slave", tapan);
4413 if (ret) {
4414 pr_err("%s: Failed to request irq %d\n", __func__,
4415 WCD9XXX_IRQ_SLIMBUS);
4416 goto exit;
4417 }
4418
4419 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
4420 wcd9xxx_interface_reg_write(codec->control_data,
4421 TAPAN_SLIM_PGD_PORT_INT_EN0 + i,
4422 0xFF);
4423exit:
4424 return ret;
4425}
4426
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07004427static void tapan_cleanup_irqs(struct tapan_priv *tapan)
4428{
4429 struct snd_soc_codec *codec = tapan->codec;
4430 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tapan);
4431}
4432
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004433int tapan_hs_detect(struct snd_soc_codec *codec,
4434 struct wcd9xxx_mbhc_config *mbhc_cfg)
4435{
4436 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
4437 return wcd9xxx_mbhc_start(&tapan->mbhc, mbhc_cfg);
4438}
4439EXPORT_SYMBOL_GPL(tapan_hs_detect);
4440
4441static struct wcd9xxx_reg_address tapan_reg_address = {
4442};
4443
4444static int tapan_codec_probe(struct snd_soc_codec *codec)
4445{
4446 struct wcd9xxx *control;
4447 struct tapan_priv *tapan;
4448 struct wcd9xxx_pdata *pdata;
4449 struct wcd9xxx *wcd9xxx;
4450 struct snd_soc_dapm_context *dapm = &codec->dapm;
4451 int ret = 0;
4452 int i;
4453 void *ptr = NULL;
4454
4455 codec->control_data = dev_get_drvdata(codec->dev->parent);
4456 control = codec->control_data;
4457
4458 dev_info(codec->dev, "%s()\n", __func__);
4459
4460 tapan = kzalloc(sizeof(struct tapan_priv), GFP_KERNEL);
4461 if (!tapan) {
4462 dev_err(codec->dev, "Failed to allocate private data\n");
4463 return -ENOMEM;
4464 }
4465 for (i = 0 ; i < NUM_DECIMATORS; i++) {
4466 tx_hpf_work[i].tapan = tapan;
4467 tx_hpf_work[i].decimator = i + 1;
4468 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
4469 tx_hpf_corner_freq_callback);
4470 }
4471
4472 snd_soc_codec_set_drvdata(codec, tapan);
4473
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004474 /* TODO: Read buck voltage from DT property */
4475 tapan->clsh_d.buck_mv = WCD9XXX_CDC_BUCK_MV_1P8;
4476 wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
4477
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004478 /* codec resmgr module init */
4479 wcd9xxx = codec->control_data;
4480 pdata = dev_get_platdata(codec->dev->parent);
4481 ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, wcd9xxx, pdata,
4482 &tapan_reg_address);
4483 if (ret) {
4484 pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004485 return ret;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004486 }
4487
Simmi Pateriya0a44d842013-04-03 01:12:42 +05304488 ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec,
4489 WCD9XXX_MBHC_VERSION_TAPAN);
4490 if (ret) {
4491 pr_err("%s: mbhc init failed %d\n", __func__, ret);
4492 return ret;
4493 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004494
4495 tapan->codec = codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004496 for (i = 0; i < COMPANDER_MAX; i++) {
4497 tapan->comp_enabled[i] = 0;
4498 tapan->comp_fs[i] = COMPANDER_FS_48KHZ;
4499 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004500 tapan->intf_type = wcd9xxx_get_intf_type();
4501 tapan->aux_pga_cnt = 0;
4502 tapan->aux_l_gain = 0x1F;
4503 tapan->aux_r_gain = 0x1F;
4504 tapan_update_reg_defaults(codec);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004505
4506 dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
4507 __func__, wcd9xxx->mclk_rate);
4508
4509 if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
4510 snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
4511 snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
4512 0x01);
4513 } else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6HZ) {
4514 snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
4515 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004516 tapan_codec_init_reg(codec);
4517 ret = tapan_handle_pdata(tapan);
4518 if (IS_ERR_VALUE(ret)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004519 dev_err(codec->dev, "%s: bad pdata\n", __func__);
4520 goto err_pdata;
4521 }
4522
4523 if (spkr_drv_wrnd > 0) {
4524 WCD9XXX_BCL_LOCK(&tapan->resmgr);
4525 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
4526 WCD9XXX_BANDGAP_AUDIO_MODE);
4527 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004528 }
4529
4530 ptr = kmalloc((sizeof(tapan_rx_chs) +
4531 sizeof(tapan_tx_chs)), GFP_KERNEL);
4532 if (!ptr) {
4533 pr_err("%s: no mem for slim chan ctl data\n", __func__);
4534 ret = -ENOMEM;
4535 goto err_nomem_slimch;
4536 }
4537
4538 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004539 snd_soc_dapm_new_controls(dapm, tapan_dapm_i2s_widgets,
4540 ARRAY_SIZE(tapan_dapm_i2s_widgets));
4541 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
4542 ARRAY_SIZE(audio_i2s_map));
4543 for (i = 0; i < ARRAY_SIZE(tapan_i2s_dai); i++)
4544 INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004545 } else if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
4546 for (i = 0; i < NUM_CODEC_DAIS; i++) {
4547 INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
4548 init_waitqueue_head(&tapan->dai[i].dai_wait);
4549 }
4550 }
4551
4552 control->num_rx_port = TAPAN_RX_MAX;
4553 control->rx_chs = ptr;
4554 memcpy(control->rx_chs, tapan_rx_chs, sizeof(tapan_rx_chs));
4555 control->num_tx_port = TAPAN_TX_MAX;
4556 control->tx_chs = ptr + sizeof(tapan_rx_chs);
4557 memcpy(control->tx_chs, tapan_tx_chs, sizeof(tapan_tx_chs));
4558
4559 snd_soc_dapm_sync(dapm);
4560
4561 (void) tapan_setup_irqs(tapan);
4562
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004563 atomic_set(&kp_tapan_priv, (unsigned long)tapan);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07004564 mutex_lock(&dapm->codec->mutex);
4565 snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
4566 snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
4567 snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
4568 snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
4569 snd_soc_dapm_disable_pin(dapm, "ANC EAR");
4570 snd_soc_dapm_sync(dapm);
4571 mutex_unlock(&dapm->codec->mutex);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004572
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004573 codec->ignore_pmdown_time = 1;
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07004574
4575 if (ret)
4576 tapan_cleanup_irqs(tapan);
4577
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004578 return ret;
4579
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004580err_pdata:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004581 kfree(ptr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004582err_nomem_slimch:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004583 kfree(tapan);
4584 return ret;
4585}
4586
4587static int tapan_codec_remove(struct snd_soc_codec *codec)
4588{
4589 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
4590
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004591 WCD9XXX_BCL_LOCK(&tapan->resmgr);
4592 atomic_set(&kp_tapan_priv, 0);
4593
4594 if (spkr_drv_wrnd > 0)
4595 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
4596 WCD9XXX_BANDGAP_AUDIO_MODE);
4597 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07004598
4599 tapan_cleanup_irqs(tapan);
4600
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004601 /* cleanup MBHC */
4602 wcd9xxx_mbhc_deinit(&tapan->mbhc);
4603 /* cleanup resmgr */
4604 wcd9xxx_resmgr_deinit(&tapan->resmgr);
4605
4606 kfree(tapan);
4607 return 0;
4608}
4609
4610static struct snd_soc_codec_driver soc_codec_dev_tapan = {
4611 .probe = tapan_codec_probe,
4612 .remove = tapan_codec_remove,
4613
4614 .read = tapan_read,
4615 .write = tapan_write,
4616
4617 .readable_register = tapan_readable,
4618 .volatile_register = tapan_volatile,
4619
4620 .reg_cache_size = TAPAN_CACHE_SIZE,
4621 .reg_cache_default = tapan_reset_reg_defaults,
4622 .reg_word_size = 1,
4623
4624 .controls = tapan_snd_controls,
4625 .num_controls = ARRAY_SIZE(tapan_snd_controls),
4626 .dapm_widgets = tapan_dapm_widgets,
4627 .num_dapm_widgets = ARRAY_SIZE(tapan_dapm_widgets),
4628 .dapm_routes = audio_map,
4629 .num_dapm_routes = ARRAY_SIZE(audio_map),
4630};
4631
4632#ifdef CONFIG_PM
4633static int tapan_suspend(struct device *dev)
4634{
4635 dev_dbg(dev, "%s: system suspend\n", __func__);
4636 return 0;
4637}
4638
4639static int tapan_resume(struct device *dev)
4640{
4641 struct platform_device *pdev = to_platform_device(dev);
4642 struct tapan_priv *tapan = platform_get_drvdata(pdev);
4643 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004644 /* Notify */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004645 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, WCD9XXX_EVENT_POST_RESUME);
4646 return 0;
4647}
4648
4649static const struct dev_pm_ops tapan_pm_ops = {
4650 .suspend = tapan_suspend,
4651 .resume = tapan_resume,
4652};
4653#endif
4654
4655static int __devinit tapan_probe(struct platform_device *pdev)
4656{
4657 int ret = 0;
4658 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
4659 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tapan,
4660 tapan_dai, ARRAY_SIZE(tapan_dai));
4661 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
4662 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tapan,
4663 tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
4664 return ret;
4665}
4666static int __devexit tapan_remove(struct platform_device *pdev)
4667{
4668 snd_soc_unregister_codec(&pdev->dev);
4669 return 0;
4670}
4671static struct platform_driver tapan_codec_driver = {
4672 .probe = tapan_probe,
4673 .remove = tapan_remove,
4674 .driver = {
4675 .name = "tapan_codec",
4676 .owner = THIS_MODULE,
4677#ifdef CONFIG_PM
4678 .pm = &tapan_pm_ops,
4679#endif
4680 },
4681};
4682
4683static int __init tapan_codec_init(void)
4684{
4685 return platform_driver_register(&tapan_codec_driver);
4686}
4687
4688static void __exit tapan_codec_exit(void)
4689{
4690 platform_driver_unregister(&tapan_codec_driver);
4691}
4692
4693module_init(tapan_codec_init);
4694module_exit(tapan_codec_exit);
4695
4696MODULE_DESCRIPTION("Tapan codec driver");
4697MODULE_LICENSE("GPL v2");