blob: ca8cfaa69354fe81e234cef3701dd54aca66a588 [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
63
Bhalchandra Gajareea898742013-03-05 18:15:53 -080064/* Nummer of TX ports actually connected from Slimbus slave to codec Digital */
65#define TAPAN_SLIM_CODEC_TX_PORTS 5
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080066
Bhalchandra Gajareea898742013-03-05 18:15:53 -080067#define TAPAN_I2S_MASTER_MODE_MASK 0x08
68#define TAPAN_MCLK_CLK_12P288MHZ 12288000
69#define TAPAN_MCLK_CLK_9P6HZ 9600000
70
71#define TAPAN_SLIM_CLOSE_TIMEOUT 1000
72#define TAPAN_SLIM_IRQ_OVERFLOW (1 << 0)
73#define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
74#define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
75#define TAPAN_MCLK_CLK_12P288MHZ 12288000
76#define TAPAN_MCLK_CLK_9P6HZ 9600000
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080077enum {
78 AIF1_PB = 0,
79 AIF1_CAP,
80 AIF2_PB,
81 AIF2_CAP,
82 AIF3_PB,
83 AIF3_CAP,
84 NUM_CODEC_DAIS,
85};
86
87enum {
88 RX_MIX1_INP_SEL_ZERO = 0,
89 RX_MIX1_INP_SEL_SRC1,
90 RX_MIX1_INP_SEL_SRC2,
91 RX_MIX1_INP_SEL_IIR1,
92 RX_MIX1_INP_SEL_IIR2,
93 RX_MIX1_INP_SEL_RX1,
94 RX_MIX1_INP_SEL_RX2,
95 RX_MIX1_INP_SEL_RX3,
96 RX_MIX1_INP_SEL_RX4,
97 RX_MIX1_INP_SEL_RX5,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080098 RX_MIX1_INP_SEL_AUXRX,
99};
100
101#define TAPAN_COMP_DIGITAL_GAIN_OFFSET 3
102
103static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
104static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
105static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
106static struct snd_soc_dai_driver tapan_dai[];
107static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
108
109/* Codec supports 2 IIR filters */
110enum {
111 IIR1 = 0,
112 IIR2,
113 IIR_MAX,
114};
115/* Codec supports 5 bands */
116enum {
117 BAND1 = 0,
118 BAND2,
119 BAND3,
120 BAND4,
121 BAND5,
122 BAND_MAX,
123};
124
125enum {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800126 COMPANDER_0,
127 COMPANDER_1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800128 COMPANDER_2,
129 COMPANDER_MAX,
130};
131
132enum {
133 COMPANDER_FS_8KHZ = 0,
134 COMPANDER_FS_16KHZ,
135 COMPANDER_FS_32KHZ,
136 COMPANDER_FS_48KHZ,
137 COMPANDER_FS_96KHZ,
138 COMPANDER_FS_192KHZ,
139 COMPANDER_FS_MAX,
140};
141
142struct comp_sample_dependent_params {
143 u32 peak_det_timeout;
144 u32 rms_meter_div_fact;
145 u32 rms_meter_resamp_fact;
146};
147
148struct hpf_work {
149 struct tapan_priv *tapan;
150 u32 decimator;
151 u8 tx_hpf_cut_of_freq;
152 struct delayed_work dwork;
153};
154
155static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
156
157static const struct wcd9xxx_ch tapan_rx_chs[TAPAN_RX_MAX] = {
158 WCD9XXX_CH(16, 0),
159 WCD9XXX_CH(17, 1),
160 WCD9XXX_CH(18, 2),
161 WCD9XXX_CH(19, 3),
162 WCD9XXX_CH(20, 4),
163};
164
165static const struct wcd9xxx_ch tapan_tx_chs[TAPAN_TX_MAX] = {
166 WCD9XXX_CH(0, 0),
167 WCD9XXX_CH(1, 1),
168 WCD9XXX_CH(2, 2),
169 WCD9XXX_CH(3, 3),
170 WCD9XXX_CH(4, 4),
171};
172
173static const u32 vport_check_table[NUM_CODEC_DAIS] = {
174 0, /* AIF1_PB */
175 (1 << AIF2_CAP) | (1 << AIF3_CAP), /* AIF1_CAP */
176 0, /* AIF2_PB */
177 (1 << AIF1_CAP) | (1 << AIF3_CAP), /* AIF2_CAP */
178 0, /* AIF2_PB */
179 (1 << AIF1_CAP) | (1 << AIF2_CAP), /* AIF2_CAP */
180};
181
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800182static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
183 0, /* AIF1_PB */
184 0, /* AIF1_CAP */
185};
186
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800187struct tapan_priv {
188 struct snd_soc_codec *codec;
189 u32 adc_count;
190 u32 rx_bias_count;
191 s32 dmic_1_2_clk_cnt;
192 s32 dmic_3_4_clk_cnt;
193 s32 dmic_5_6_clk_cnt;
194
195 u32 anc_slot;
196
197 /*track tapan interface type*/
198 u8 intf_type;
199
200 /* num of slim ports required */
201 struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
202
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800203 /*compander*/
204 int comp_enabled[COMPANDER_MAX];
205 u32 comp_fs[COMPANDER_MAX];
206
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800207 /* Maintain the status of AUX PGA */
208 int aux_pga_cnt;
209 u8 aux_l_gain;
210 u8 aux_r_gain;
211
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800212 bool spkr_pa_widget_on;
213
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800214 /* resmgr module */
215 struct wcd9xxx_resmgr resmgr;
216 /* mbhc module */
217 struct wcd9xxx_mbhc mbhc;
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800218
219 /* class h specific data */
220 struct wcd9xxx_clsh_cdc_data clsh_d;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800221};
222
223static const u32 comp_shift[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800224 4, /* Compander 0's clock source is on interpolator 7 */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800225 0,
226 2,
227};
228
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800229static const int comp_rx_path[] = {
230 COMPANDER_1,
231 COMPANDER_1,
232 COMPANDER_2,
233 COMPANDER_2,
234 COMPANDER_2,
235 COMPANDER_2,
236 COMPANDER_0,
237 COMPANDER_MAX,
238};
239
240static const struct comp_sample_dependent_params comp_samp_params[] = {
241 {
242 /* 8 Khz */
243 .peak_det_timeout = 0x02,
244 .rms_meter_div_fact = 0x09,
245 .rms_meter_resamp_fact = 0x06,
246 },
247 {
248 /* 16 Khz */
249 .peak_det_timeout = 0x03,
250 .rms_meter_div_fact = 0x0A,
251 .rms_meter_resamp_fact = 0x0C,
252 },
253 {
254 /* 32 Khz */
255 .peak_det_timeout = 0x05,
256 .rms_meter_div_fact = 0x0B,
257 .rms_meter_resamp_fact = 0x1E,
258 },
259 {
260 /* 48 Khz */
261 .peak_det_timeout = 0x05,
262 .rms_meter_div_fact = 0x0B,
263 .rms_meter_resamp_fact = 0x28,
264 },
265 {
266 /* 96 Khz */
267 .peak_det_timeout = 0x06,
268 .rms_meter_div_fact = 0x0C,
269 .rms_meter_resamp_fact = 0x50,
270 },
271 {
272 /* 192 Khz */
273 .peak_det_timeout = 0x07,
274 .rms_meter_div_fact = 0xD,
275 .rms_meter_resamp_fact = 0xA0,
276 },
277};
278
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800279static unsigned short rx_digital_gain_reg[] = {
280 TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
281 TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
282 TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL,
283 TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
284};
285
286static unsigned short tx_digital_gain_reg[] = {
287 TAPAN_A_CDC_TX1_VOL_CTL_GAIN,
288 TAPAN_A_CDC_TX2_VOL_CTL_GAIN,
289 TAPAN_A_CDC_TX3_VOL_CTL_GAIN,
290 TAPAN_A_CDC_TX4_VOL_CTL_GAIN,
291};
292
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800293static int spkr_drv_wrnd_param_set(const char *val,
294 const struct kernel_param *kp)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800295{
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800296 struct snd_soc_codec *codec;
297 int ret, old;
298 struct tapan_priv *priv;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800299
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800300 priv = (struct tapan_priv *)atomic_read(&kp_tapan_priv);
301 if (!priv) {
302 pr_debug("%s: codec isn't yet registered\n", __func__);
303 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800304 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800305
306 WCD9XXX_BCL_LOCK(&priv->resmgr);
307 old = spkr_drv_wrnd;
308 ret = param_set_int(val, kp);
309 if (ret) {
310 WCD9XXX_BCL_UNLOCK(&priv->resmgr);
311 return ret;
312 }
313
314 codec = priv->codec;
315 dev_dbg(codec->dev, "%s: spkr_drv_wrnd %d -> %d\n",
316 __func__, old, spkr_drv_wrnd);
317 if (old == 0 && spkr_drv_wrnd == 1) {
318 wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
319 WCD9XXX_BANDGAP_AUDIO_MODE);
320 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
321 } else if (old == 1 && spkr_drv_wrnd == 0) {
322 wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
323 WCD9XXX_BANDGAP_AUDIO_MODE);
324 if (!priv->spkr_pa_widget_on)
325 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
326 0x00);
327 }
328
329 WCD9XXX_BCL_UNLOCK(&priv->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800330 return 0;
331}
332
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800333static int tapan_get_anc_slot(struct snd_kcontrol *kcontrol,
334 struct snd_ctl_elem_value *ucontrol)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800335{
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800336 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
337 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
338 ucontrol->value.integer.value[0] = tapan->anc_slot;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800339 return 0;
340}
341
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800342static int tapan_put_anc_slot(struct snd_kcontrol *kcontrol,
343 struct snd_ctl_elem_value *ucontrol)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800344{
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800345 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
346 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
347 tapan->anc_slot = ucontrol->value.integer.value[0];
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800348 return 0;
349}
350
351static int tapan_pa_gain_get(struct snd_kcontrol *kcontrol,
352 struct snd_ctl_elem_value *ucontrol)
353{
354 u8 ear_pa_gain;
355 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
356
357 ear_pa_gain = snd_soc_read(codec, TAPAN_A_RX_EAR_GAIN);
358
359 ear_pa_gain = ear_pa_gain >> 5;
360
361 if (ear_pa_gain == 0x00) {
362 ucontrol->value.integer.value[0] = 0;
363 } else if (ear_pa_gain == 0x04) {
364 ucontrol->value.integer.value[0] = 1;
365 } else {
366 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
367 __func__, ear_pa_gain);
368 return -EINVAL;
369 }
370
371 dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
372
373 return 0;
374}
375
376static int tapan_pa_gain_put(struct snd_kcontrol *kcontrol,
377 struct snd_ctl_elem_value *ucontrol)
378{
379 u8 ear_pa_gain;
380 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
381
382 dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
383 __func__, ucontrol->value.integer.value[0]);
384
385 switch (ucontrol->value.integer.value[0]) {
386 case 0:
387 ear_pa_gain = 0x00;
388 break;
389 case 1:
390 ear_pa_gain = 0x80;
391 break;
392 default:
393 return -EINVAL;
394 }
395
396 snd_soc_update_bits(codec, TAPAN_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
397 return 0;
398}
399
400static int tapan_get_iir_enable_audio_mixer(
401 struct snd_kcontrol *kcontrol,
402 struct snd_ctl_elem_value *ucontrol)
403{
404 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
405 int iir_idx = ((struct soc_multi_mixer_control *)
406 kcontrol->private_value)->reg;
407 int band_idx = ((struct soc_multi_mixer_control *)
408 kcontrol->private_value)->shift;
409
410 ucontrol->value.integer.value[0] =
411 snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
412 (1 << band_idx);
413
414 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
415 iir_idx, band_idx,
416 (uint32_t)ucontrol->value.integer.value[0]);
417 return 0;
418}
419
420static int tapan_put_iir_enable_audio_mixer(
421 struct snd_kcontrol *kcontrol,
422 struct snd_ctl_elem_value *ucontrol)
423{
424 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
425 int iir_idx = ((struct soc_multi_mixer_control *)
426 kcontrol->private_value)->reg;
427 int band_idx = ((struct soc_multi_mixer_control *)
428 kcontrol->private_value)->shift;
429 int value = ucontrol->value.integer.value[0];
430
431 /* Mask first 5 bits, 6-8 are reserved */
432 snd_soc_update_bits(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx),
433 (1 << band_idx), (value << band_idx));
434
435 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
436 iir_idx, band_idx, value);
437 return 0;
438}
439static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
440 int iir_idx, int band_idx,
441 int coeff_idx)
442{
443 /* Address does not automatically update if reading */
444 snd_soc_write(codec,
445 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
446 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
447
448 /* Mask bits top 2 bits since they are reserved */
449 return ((snd_soc_read(codec,
450 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 24)) &
451 0x3FFFFFFF;
452}
453
454static int tapan_get_iir_band_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] =
465 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
466 ucontrol->value.integer.value[1] =
467 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
468 ucontrol->value.integer.value[2] =
469 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
470 ucontrol->value.integer.value[3] =
471 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
472 ucontrol->value.integer.value[4] =
473 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
474
475 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
476 "%s: IIR #%d band #%d b1 = 0x%x\n"
477 "%s: IIR #%d band #%d b2 = 0x%x\n"
478 "%s: IIR #%d band #%d a1 = 0x%x\n"
479 "%s: IIR #%d band #%d a2 = 0x%x\n",
480 __func__, iir_idx, band_idx,
481 (uint32_t)ucontrol->value.integer.value[0],
482 __func__, iir_idx, band_idx,
483 (uint32_t)ucontrol->value.integer.value[1],
484 __func__, iir_idx, band_idx,
485 (uint32_t)ucontrol->value.integer.value[2],
486 __func__, iir_idx, band_idx,
487 (uint32_t)ucontrol->value.integer.value[3],
488 __func__, iir_idx, band_idx,
489 (uint32_t)ucontrol->value.integer.value[4]);
490 return 0;
491}
492
493static void set_iir_band_coeff(struct snd_soc_codec *codec,
494 int iir_idx, int band_idx,
495 int coeff_idx, uint32_t value)
496{
497 /* Mask top 3 bits, 6-8 are reserved */
498 /* Update address manually each time */
499 snd_soc_write(codec,
500 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
501 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
502
503 /* Mask top 2 bits, 7-8 are reserved */
504 snd_soc_write(codec,
505 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
506 (value >> 24) & 0x3F);
507
508}
509
510static int tapan_put_iir_band_audio_mixer(
511 struct snd_kcontrol *kcontrol,
512 struct snd_ctl_elem_value *ucontrol)
513{
514 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
515 int iir_idx = ((struct soc_multi_mixer_control *)
516 kcontrol->private_value)->reg;
517 int band_idx = ((struct soc_multi_mixer_control *)
518 kcontrol->private_value)->shift;
519
520 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
521 ucontrol->value.integer.value[0]);
522 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
523 ucontrol->value.integer.value[1]);
524 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
525 ucontrol->value.integer.value[2]);
526 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
527 ucontrol->value.integer.value[3]);
528 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
529 ucontrol->value.integer.value[4]);
530
531 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
532 "%s: IIR #%d band #%d b1 = 0x%x\n"
533 "%s: IIR #%d band #%d b2 = 0x%x\n"
534 "%s: IIR #%d band #%d a1 = 0x%x\n"
535 "%s: IIR #%d band #%d a2 = 0x%x\n",
536 __func__, iir_idx, band_idx,
537 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
538 __func__, iir_idx, band_idx,
539 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
540 __func__, iir_idx, band_idx,
541 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
542 __func__, iir_idx, band_idx,
543 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
544 __func__, iir_idx, band_idx,
545 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
546 return 0;
547}
548
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800549static int tapan_get_compander(struct snd_kcontrol *kcontrol,
550 struct snd_ctl_elem_value *ucontrol)
551{
552
553 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
554 int comp = ((struct soc_multi_mixer_control *)
555 kcontrol->private_value)->shift;
556 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
557
558 ucontrol->value.integer.value[0] = tapan->comp_enabled[comp];
559 return 0;
560}
561
562static int tapan_set_compander(struct snd_kcontrol *kcontrol,
563 struct snd_ctl_elem_value *ucontrol)
564{
565 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
566 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
567 int comp = ((struct soc_multi_mixer_control *)
568 kcontrol->private_value)->shift;
569 int value = ucontrol->value.integer.value[0];
570
571 dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n",
572 __func__, comp, tapan->comp_enabled[comp], value);
573 tapan->comp_enabled[comp] = value;
574 return 0;
575}
576
577static int tapan_config_gain_compander(struct snd_soc_codec *codec,
578 int comp, bool enable)
579{
580 int ret = 0;
581
582 switch (comp) {
583 case COMPANDER_0:
584 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_GAIN,
585 1 << 2, !enable << 2);
586 break;
587 case COMPANDER_1:
588 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_L_GAIN,
589 1 << 5, !enable << 5);
590 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_R_GAIN,
591 1 << 5, !enable << 5);
592 break;
593 case COMPANDER_2:
594 snd_soc_update_bits(codec, TAPAN_A_RX_LINE_1_GAIN,
595 1 << 5, !enable << 5);
596 snd_soc_update_bits(codec, TAPAN_A_RX_LINE_2_GAIN,
597 1 << 5, !enable << 5);
598 break;
599 default:
600 WARN_ON(1);
601 ret = -EINVAL;
602 }
603
604 return ret;
605}
606
607static void tapan_discharge_comp(struct snd_soc_codec *codec, int comp)
608{
609 /* Update RSM to 1, DIVF to 5 */
610 snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8), 1);
611 snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8), 0xF0,
612 1 << 5);
613 /* Wait for 1ms */
614 usleep_range(1000, 1000);
615}
616
617static int tapan_config_compander(struct snd_soc_dapm_widget *w,
618 struct snd_kcontrol *kcontrol, int event)
619{
620 int mask, emask;
621 bool timedout;
622 unsigned long timeout;
623 struct snd_soc_codec *codec = w->codec;
624 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
625 const int comp = w->shift;
626 const u32 rate = tapan->comp_fs[comp];
627 const struct comp_sample_dependent_params *comp_params =
628 &comp_samp_params[rate];
629
630 dev_dbg(codec->dev, "%s: %s event %d compander %d, enabled %d",
631 __func__, w->name, event, comp, tapan->comp_enabled[comp]);
632
633 if (!tapan->comp_enabled[comp])
634 return 0;
635
636 /* Compander 0 has single channel */
637 mask = (comp == COMPANDER_0 ? 0x01 : 0x03);
638 emask = (comp == COMPANDER_0 ? 0x02 : 0x03);
639
640 switch (event) {
641 case SND_SOC_DAPM_PRE_PMU:
642 /* Set gain source to compander */
643 tapan_config_gain_compander(codec, comp, true);
644 /* Enable RX interpolation path clocks */
645 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
646 mask << comp_shift[comp],
647 mask << comp_shift[comp]);
648
649 tapan_discharge_comp(codec, comp);
650
651 /* Clear compander halt */
652 snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
653 (comp * 8),
654 1 << 2, 0);
655 /* Toggle compander reset bits */
656 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
657 mask << comp_shift[comp],
658 mask << comp_shift[comp]);
659 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
660 mask << comp_shift[comp], 0);
661 break;
662 case SND_SOC_DAPM_POST_PMU:
663 /* Set sample rate dependent paramater */
664 snd_soc_update_bits(codec,
665 TAPAN_A_CDC_COMP0_FS_CFG + (comp * 8),
666 0x07, rate);
667 snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8),
668 comp_params->rms_meter_resamp_fact);
669 snd_soc_update_bits(codec,
670 TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
671 0x0F, comp_params->peak_det_timeout);
672 snd_soc_update_bits(codec,
673 TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
674 0xF0, comp_params->rms_meter_div_fact << 4);
675 /* Compander enable */
676 snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
677 (comp * 8), emask, emask);
678 break;
679 case SND_SOC_DAPM_PRE_PMD:
680 /* Halt compander */
681 snd_soc_update_bits(codec,
682 TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
683 1 << 2, 1 << 2);
684 /* Wait up to a second for shutdown complete */
685 timeout = jiffies + HZ;
686 do {
687 if ((snd_soc_read(codec,
688 TAPAN_A_CDC_COMP0_SHUT_DOWN_STATUS +
689 (comp * 8)) & mask) == mask)
690 break;
691 } while (!(timedout = time_after(jiffies, timeout)));
692 dev_dbg(codec->dev, "%s: Compander %d shutdown %s in %dms\n",
693 __func__, comp, timedout ? "timedout" : "completed",
694 jiffies_to_msecs(timeout - HZ - jiffies));
695 break;
696 case SND_SOC_DAPM_POST_PMD:
697 /* Disable compander */
698 snd_soc_update_bits(codec,
699 TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
700 emask, 0x00);
701 /* Turn off the clock for compander in pair */
702 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
703 mask << comp_shift[comp], 0);
704 /* Set gain source to register */
705 tapan_config_gain_compander(codec, comp, false);
706 break;
707 }
708 return 0;
709}
710
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800711static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
712static const struct soc_enum tapan_ear_pa_gain_enum[] = {
713 SOC_ENUM_SINGLE_EXT(2, tapan_ear_pa_gain_text),
714};
715
716/*cut of frequency for high pass filter*/
717static const char * const cf_text[] = {
718 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
719};
720
721static const struct soc_enum cf_dec1_enum =
722 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
723
724static const struct soc_enum cf_dec2_enum =
725 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
726
727static const struct soc_enum cf_dec3_enum =
728 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
729
730static const struct soc_enum cf_dec4_enum =
731 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
732
733static const struct soc_enum cf_rxmix1_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800734 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800735
736static const struct soc_enum cf_rxmix2_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800737 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800738
739static const struct soc_enum cf_rxmix3_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800740 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800741
742static const struct soc_enum cf_rxmix4_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800743 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800744
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800745static const char * const class_h_dsm_text[] = {
746 "ZERO", "RX_HPHL", "RX_SPKR"
747};
748
749static const struct soc_enum class_h_dsm_enum =
750 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_CLSH_CTL, 2, 3, class_h_dsm_text);
751
752static const struct snd_kcontrol_new class_h_dsm_mux =
753 SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
754
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800755static const struct snd_kcontrol_new tapan_snd_controls[] = {
756
757 SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
758 tapan_pa_gain_get, tapan_pa_gain_put),
759
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800760 SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800761 line_gain),
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800762 SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800763 line_gain),
764
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800765 SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800766 line_gain),
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800767 SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800768 line_gain),
769
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800770 SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 7, 1,
771 line_gain),
772
773 SOC_SINGLE_TLV("ADC1 Volume", TAPAN_A_TX_1_EN, 2, 13, 0, analog_gain),
774 SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 13, 0, analog_gain),
775 SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 13, 0, analog_gain),
776 SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 13, 0, analog_gain),
777 SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 13, 0, analog_gain),
778
Jay Chokshi83b4f6132013-02-14 16:20:56 -0800779 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
780 -84, 40, digital_gain),
781 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
782 -84, 40, digital_gain),
783 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL,
784 -84, 40, digital_gain),
785 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
786 -84, 40, digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800787
Jay Chokshi83b4f6132013-02-14 16:20:56 -0800788 SOC_SINGLE_S8_TLV("DEC1 Volume", TAPAN_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
789 digital_gain),
790 SOC_SINGLE_S8_TLV("DEC2 Volume", TAPAN_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
791 digital_gain),
792 SOC_SINGLE_S8_TLV("DEC3 Volume", TAPAN_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
793 digital_gain),
794 SOC_SINGLE_S8_TLV("DEC4 Volume", TAPAN_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
795 digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800796
Jay Chokshi83b4f6132013-02-14 16:20:56 -0800797 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TAPAN_A_CDC_IIR1_GAIN_B1_CTL, -84,
798 40, digital_gain),
799 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TAPAN_A_CDC_IIR1_GAIN_B2_CTL, -84,
800 40, digital_gain),
801 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TAPAN_A_CDC_IIR1_GAIN_B3_CTL, -84,
802 40, digital_gain),
803 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAPAN_A_CDC_IIR1_GAIN_B4_CTL, -84,
804 40, digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800805
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800806 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 0, 100, tapan_get_anc_slot,
807 tapan_put_anc_slot),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800808
809 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
810 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
811 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
812 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
813
814 SOC_SINGLE("TX1 HPF Switch", TAPAN_A_CDC_TX1_MUX_CTL, 3, 1, 0),
815 SOC_SINGLE("TX2 HPF Switch", TAPAN_A_CDC_TX2_MUX_CTL, 3, 1, 0),
816 SOC_SINGLE("TX3 HPF Switch", TAPAN_A_CDC_TX3_MUX_CTL, 3, 1, 0),
817 SOC_SINGLE("TX4 HPF Switch", TAPAN_A_CDC_TX4_MUX_CTL, 3, 1, 0),
818
819 SOC_SINGLE("RX1 HPF Switch", TAPAN_A_CDC_RX1_B5_CTL, 2, 1, 0),
820 SOC_SINGLE("RX2 HPF Switch", TAPAN_A_CDC_RX2_B5_CTL, 2, 1, 0),
821 SOC_SINGLE("RX3 HPF Switch", TAPAN_A_CDC_RX3_B5_CTL, 2, 1, 0),
822 SOC_SINGLE("RX4 HPF Switch", TAPAN_A_CDC_RX4_B5_CTL, 2, 1, 0),
823
824 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
825 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
826 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
827 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
828
829 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
830 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
831 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
832 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
833 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
834 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
835 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
836 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
837 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
838 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
839 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
840 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
841 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
842 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
843 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
844 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
845 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
846 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
847 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
848 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
849
850 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
851 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
852 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
853 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
854 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
855 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
856 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
857 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
858 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
859 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
860 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
861 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
862 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
863 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
864 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
865 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
866 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
867 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
868 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
869 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
870
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800871 SOC_SINGLE_EXT("COMP0 Switch", SND_SOC_NOPM, COMPANDER_0, 1, 0,
872 tapan_get_compander, tapan_set_compander),
873 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
874 tapan_get_compander, tapan_set_compander),
875 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
876 tapan_get_compander, tapan_set_compander),
877
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800878};
879
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800880static const char * const rx_1_2_mix1_text[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800881 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800882 "RX5", "AUXRX", "AUXTX1"
883};
884
885static const char * const rx_3_4_mix1_text[] = {
886 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
887 "RX5", "AUXRX", "AUXTX1", "AUXTX2"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800888};
889
890static const char * const rx_mix2_text[] = {
891 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
892};
893
894static const char * const rx_rdac5_text[] = {
895 "DEM4", "DEM3_INV"
896};
897
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800898static const char * const sb_tx_1_2_mux_text[] = {
899 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
900 "RSVD", "RSVD", "RSVD",
901 "DEC1", "DEC2", "DEC3", "DEC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800902};
903
904static const char * const sb_tx3_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800905 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
906 "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
907 "DEC3"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800908};
909
910static const char * const sb_tx4_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800911 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
912 "RSVD", "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
913 "DEC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800914};
915
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800916static const char * const sb_tx5_mux_text[] = {
917 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
918 "RSVD", "RSVD", "RSVD",
919 "DEC1"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800920};
921
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800922static const char * const dec_1_2_mux_text[] = {
923 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADCMB",
924 "DMIC1", "DMIC2", "DMIC3", "DMIC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800925};
926
927static const char * const dec3_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800928 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
929 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
930 "ANCFBTUNE1"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800931};
932
933static const char * const dec4_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800934 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
935 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
936 "ANCFBTUNE2"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800937};
938
939static const char * const anc_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800940 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5",
941 "RSVD", "RSVD", "RSVD",
942 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
943 "RSVD", "RSVD"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800944};
945
946static const char * const iir1_inp1_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800947 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4",
948 "RX1", "RX2", "RX3", "RX4", "RX5"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800949};
950
951static const struct soc_enum rx_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800952 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800953
954static const struct soc_enum rx_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800955 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800956
957static const struct soc_enum rx_mix1_inp3_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800958 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800959
960static const struct soc_enum rx2_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800961 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800962
963static const struct soc_enum rx2_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800964 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800965
966static const struct soc_enum rx3_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800967 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 0, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800968
969static const struct soc_enum rx3_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800970 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 4, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800971
972static const struct soc_enum rx4_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800973 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 0, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800974
975static const struct soc_enum rx4_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800976 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800977
978static const struct soc_enum rx1_mix2_inp1_chain_enum =
979 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
980
981static const struct soc_enum rx1_mix2_inp2_chain_enum =
982 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
983
984static const struct soc_enum rx2_mix2_inp1_chain_enum =
985 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
986
987static const struct soc_enum rx2_mix2_inp2_chain_enum =
988 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
989
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800990static const struct soc_enum rx4_mix2_inp1_chain_enum =
991 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 0, 5, rx_mix2_text);
992
993static const struct soc_enum rx4_mix2_inp2_chain_enum =
994 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 3, 5, rx_mix2_text);
995
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800996static const struct soc_enum rx_rdac5_enum =
997 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
998
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800999static const struct soc_enum sb_tx1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001000 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0, 12,
1001 sb_tx_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001002
1003static const struct soc_enum sb_tx2_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001004 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0, 12,
1005 sb_tx_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001006
1007static const struct soc_enum sb_tx3_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001008 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0, 11, sb_tx3_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001009
1010static const struct soc_enum sb_tx4_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001011 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0, 12, sb_tx4_mux_text);
1012
1013static const struct soc_enum sb_tx5_mux_enum =
1014 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001015
1016static const struct soc_enum dec1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001017 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 0, 10, dec_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001018
1019static const struct soc_enum dec2_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001020 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 4, 10, dec_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001021
1022static const struct soc_enum dec3_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001023 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 0, 12, dec3_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001024
1025static const struct soc_enum dec4_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001026 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 4, 12, dec4_mux_text);
1027
1028static const struct soc_enum anc1_mux_enum =
1029 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 0, 15, anc_mux_text);
1030
1031static const struct soc_enum anc2_mux_enum =
1032 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 4, 15, anc_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001033
1034static const struct soc_enum iir1_inp1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001035 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_EQ1_B1_CTL, 0, 10, iir1_inp1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001036
1037static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1038 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1039
1040static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1041 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1042
1043static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1044 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1045
1046static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1047 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1048
1049static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1050 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1051
1052static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1053 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1054
1055static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1056 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1057
1058static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1059 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1060
1061static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1062 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1063
1064static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1065 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1066
1067static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
1068 SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
1069
1070static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1071 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1072
1073static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
1074 SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
1075
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001076static const struct snd_kcontrol_new rx4_mix2_inp1_mux =
1077 SOC_DAPM_ENUM("RX4 MIX2 INP1 Mux", rx4_mix2_inp1_chain_enum);
1078
1079static const struct snd_kcontrol_new rx4_mix2_inp2_mux =
1080 SOC_DAPM_ENUM("RX4 MIX2 INP2 Mux", rx4_mix2_inp2_chain_enum);
1081
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001082static const struct snd_kcontrol_new rx_dac5_mux =
1083 SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
1084
1085static const struct snd_kcontrol_new sb_tx1_mux =
1086 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1087
1088static const struct snd_kcontrol_new sb_tx2_mux =
1089 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
1090
1091static const struct snd_kcontrol_new sb_tx3_mux =
1092 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
1093
1094static const struct snd_kcontrol_new sb_tx4_mux =
1095 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
1096
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001097static const struct snd_kcontrol_new sb_tx5_mux =
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001098 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001099
1100static int wcd9306_put_dec_enum(struct snd_kcontrol *kcontrol,
1101 struct snd_ctl_elem_value *ucontrol)
1102{
1103 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1104 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1105 struct snd_soc_codec *codec = w->codec;
1106 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1107 unsigned int dec_mux, decimator;
1108 char *dec_name = NULL;
1109 char *widget_name = NULL;
1110 char *temp;
1111 u16 tx_mux_ctl_reg;
1112 u8 adc_dmic_sel = 0x0;
1113 int ret = 0;
1114
1115 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1116 return -EINVAL;
1117
1118 dec_mux = ucontrol->value.enumerated.item[0];
1119
1120 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1121 if (!widget_name)
1122 return -ENOMEM;
1123 temp = widget_name;
1124
1125 dec_name = strsep(&widget_name, " ");
1126 widget_name = temp;
1127 if (!dec_name) {
1128 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1129 ret = -EINVAL;
1130 goto out;
1131 }
1132
1133 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
1134 if (ret < 0) {
1135 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1136 ret = -EINVAL;
1137 goto out;
1138 }
1139
1140 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1141 , __func__, w->name, decimator, dec_mux);
1142
1143 switch (decimator) {
1144 case 1:
1145 case 2:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001146 if ((dec_mux >= 1) && (dec_mux <= 5))
1147 adc_dmic_sel = 0x0;
1148 else if ((dec_mux >= 6) && (dec_mux <= 9))
1149 adc_dmic_sel = 0x1;
1150 break;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001151 case 3:
1152 case 4:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001153 if ((dec_mux >= 1) && (dec_mux <= 6))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001154 adc_dmic_sel = 0x0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001155 else if ((dec_mux >= 7) && (dec_mux <= 10))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001156 adc_dmic_sel = 0x1;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001157 break;
1158 default:
1159 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1160 ret = -EINVAL;
1161 goto out;
1162 }
1163
1164 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1165
1166 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1167
1168 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1169
1170out:
1171 kfree(widget_name);
1172 return ret;
1173}
1174
1175#define WCD9306_DEC_ENUM(xname, xenum) \
1176{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1177 .info = snd_soc_info_enum_double, \
1178 .get = snd_soc_dapm_get_enum_double, \
1179 .put = wcd9306_put_dec_enum, \
1180 .private_value = (unsigned long)&xenum }
1181
1182static const struct snd_kcontrol_new dec1_mux =
1183 WCD9306_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1184
1185static const struct snd_kcontrol_new dec2_mux =
1186 WCD9306_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1187
1188static const struct snd_kcontrol_new dec3_mux =
1189 WCD9306_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1190
1191static const struct snd_kcontrol_new dec4_mux =
1192 WCD9306_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1193
1194static const struct snd_kcontrol_new iir1_inp1_mux =
1195 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1196
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001197static const struct snd_kcontrol_new anc1_mux =
1198 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1199
1200static const struct snd_kcontrol_new anc2_mux =
1201 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
1202
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001203static const struct snd_kcontrol_new dac1_switch[] = {
1204 SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_EAR_EN, 5, 1, 0)
1205};
1206static const struct snd_kcontrol_new hphl_switch[] = {
1207 SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1208};
1209
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001210static const struct snd_kcontrol_new spk_dac_switch[] = {
1211 SOC_DAPM_SINGLE("Switch", TAPAN_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
1212};
1213
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001214static const struct snd_kcontrol_new hphl_pa_mix[] = {
1215 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1216 7, 1, 0),
1217};
1218
1219static const struct snd_kcontrol_new hphr_pa_mix[] = {
1220 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1221 6, 1, 0),
1222};
1223
1224static const struct snd_kcontrol_new ear_pa_mix[] = {
1225 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1226 5, 1, 0),
1227};
1228static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1229 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1230 4, 1, 0),
1231};
1232
1233static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1234 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1235 3, 1, 0),
1236};
1237
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001238
1239/* virtual port entries */
1240static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
1241 struct snd_ctl_elem_value *ucontrol)
1242{
1243 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1244 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1245
1246 ucontrol->value.integer.value[0] = widget->value;
1247 return 0;
1248}
1249
1250static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
1251 struct snd_ctl_elem_value *ucontrol)
1252{
1253 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1254 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1255 struct snd_soc_codec *codec = widget->codec;
1256 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
1257 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1258 struct soc_multi_mixer_control *mixer =
1259 ((struct soc_multi_mixer_control *)kcontrol->private_value);
1260 u32 dai_id = widget->shift;
1261 u32 port_id = mixer->shift;
1262 u32 enable = ucontrol->value.integer.value[0];
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001263 u32 vtable = vport_check_table[dai_id];
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001264
1265 dev_dbg(codec->dev, "%s: wname %s cname %s\n",
1266 __func__, widget->name, ucontrol->id.name);
1267 dev_dbg(codec->dev, "%s: value %u shift %d item %ld\n",
1268 __func__, widget->value, widget->shift,
1269 ucontrol->value.integer.value[0]);
1270
1271 mutex_lock(&codec->mutex);
1272
1273 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1274 if (dai_id != AIF1_CAP) {
1275 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1276 __func__);
1277 mutex_unlock(&codec->mutex);
1278 return -EINVAL;
1279 }
1280 }
1281 switch (dai_id) {
1282 case AIF1_CAP:
1283 case AIF2_CAP:
1284 case AIF3_CAP:
1285 /* only add to the list if value not set
1286 */
1287 if (enable && !(widget->value & 1 << port_id)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001288 if (tapan_p->intf_type ==
1289 WCD9XXX_INTERFACE_TYPE_SLIMBUS)
1290 vtable = vport_check_table[dai_id];
1291 if (tapan_p->intf_type ==
1292 WCD9XXX_INTERFACE_TYPE_I2C)
1293 vtable = vport_i2s_check_table[dai_id];
1294
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001295 if (wcd9xxx_tx_vport_validation(
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001296 vtable,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001297 port_id,
1298 tapan_p->dai)) {
1299 dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
1300 __func__, port_id + 1);
1301 mutex_unlock(&codec->mutex);
1302 return -EINVAL;
1303 }
1304 widget->value |= 1 << port_id;
1305 list_add_tail(&core->tx_chs[port_id].list,
1306 &tapan_p->dai[dai_id].wcd9xxx_ch_list
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001307 );
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001308 } else if (!enable && (widget->value & 1 << port_id)) {
1309 widget->value &= ~(1 << port_id);
1310 list_del_init(&core->tx_chs[port_id].list);
1311 } else {
1312 if (enable)
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001313 dev_dbg(codec->dev, "%s: TX%u port is used by\n"
1314 "this virtual port\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001315 __func__, port_id + 1);
1316 else
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001317 dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
1318 "this virtual port\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001319 __func__, port_id + 1);
1320 /* avoid update power function */
1321 mutex_unlock(&codec->mutex);
1322 return 0;
1323 }
1324 break;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001325 default:
1326 dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
1327 mutex_unlock(&codec->mutex);
1328 return -EINVAL;
1329 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001330 dev_dbg(codec->dev, "%s: name %s sname %s updated value %u shift %d\n",
1331 __func__, widget->name, widget->sname,
1332 widget->value, widget->shift);
1333
1334 snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
1335
1336 mutex_unlock(&codec->mutex);
1337 return 0;
1338}
1339
1340static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
1341 struct snd_ctl_elem_value *ucontrol)
1342{
1343 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1344 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1345
1346 ucontrol->value.enumerated.item[0] = widget->value;
1347 return 0;
1348}
1349
1350static const char *const slim_rx_mux_text[] = {
1351 "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB"
1352};
1353
1354static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
1355 struct snd_ctl_elem_value *ucontrol)
1356{
1357 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1358 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1359 struct snd_soc_codec *codec = widget->codec;
1360 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
1361 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1362 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1363 u32 port_id = widget->shift;
1364
1365 dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n",
1366 __func__, widget->name, ucontrol->id.name, widget->value,
1367 widget->shift, ucontrol->value.integer.value[0]);
1368
1369 widget->value = ucontrol->value.enumerated.item[0];
1370
1371 mutex_lock(&codec->mutex);
1372
1373 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1374 if (widget->value > 1) {
1375 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1376 __func__);
1377 goto err;
1378 }
1379 }
1380 /* value need to match the Virtual port and AIF number
1381 */
1382 switch (widget->value) {
1383 case 0:
1384 list_del_init(&core->rx_chs[port_id].list);
1385 break;
1386 case 1:
1387 if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
1388 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list))
1389 goto pr_err;
1390 list_add_tail(&core->rx_chs[port_id].list,
1391 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list);
1392 break;
1393 case 2:
1394 if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
1395 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list))
1396 goto pr_err;
1397 list_add_tail(&core->rx_chs[port_id].list,
1398 &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list);
1399 break;
1400 case 3:
1401 if (wcd9xxx_rx_vport_validation(port_id + core->num_tx_port,
1402 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list))
1403 goto pr_err;
1404 list_add_tail(&core->rx_chs[port_id].list,
1405 &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list);
1406 break;
1407 default:
1408 pr_err("Unknown AIF %d\n", widget->value);
1409 goto err;
1410 }
1411
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001412 snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001413
1414 mutex_unlock(&codec->mutex);
1415 return 0;
1416pr_err:
1417 pr_err("%s: RX%u is used by current requesting AIF_PB itself\n",
1418 __func__, port_id + 1);
1419err:
1420 mutex_unlock(&codec->mutex);
1421 return -EINVAL;
1422}
1423
1424static const struct soc_enum slim_rx_mux_enum =
1425 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
1426
1427static const struct snd_kcontrol_new slim_rx_mux[TAPAN_RX_MAX] = {
1428 SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
1429 slim_rx_mux_get, slim_rx_mux_put),
1430 SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
1431 slim_rx_mux_get, slim_rx_mux_put),
1432 SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
1433 slim_rx_mux_get, slim_rx_mux_put),
1434 SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
1435 slim_rx_mux_get, slim_rx_mux_put),
1436 SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
1437 slim_rx_mux_get, slim_rx_mux_put),
1438};
1439
1440static const struct snd_kcontrol_new aif_cap_mixer[] = {
1441 SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TAPAN_TX1, 1, 0,
1442 slim_tx_mixer_get, slim_tx_mixer_put),
1443 SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TAPAN_TX2, 1, 0,
1444 slim_tx_mixer_get, slim_tx_mixer_put),
1445 SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TAPAN_TX3, 1, 0,
1446 slim_tx_mixer_get, slim_tx_mixer_put),
1447 SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TAPAN_TX4, 1, 0,
1448 slim_tx_mixer_get, slim_tx_mixer_put),
1449 SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TAPAN_TX5, 1, 0,
1450 slim_tx_mixer_get, slim_tx_mixer_put),
1451};
1452
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001453static int tapan_codec_enable_adc(struct snd_soc_dapm_widget *w,
1454 struct snd_kcontrol *kcontrol, int event)
1455{
1456 struct snd_soc_codec *codec = w->codec;
1457 u16 adc_reg;
1458 u8 init_bit_shift;
1459
1460 dev_dbg(codec->dev, "%s(): %s %d\n", __func__, w->name, event);
1461
1462 if (w->reg == TAPAN_A_TX_1_EN) {
1463 init_bit_shift = 7;
1464 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1465 } else if (w->reg == TAPAN_A_TX_2_EN) {
1466 init_bit_shift = 6;
1467 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1468 } else if (w->reg == TAPAN_A_TX_3_EN) {
1469 init_bit_shift = 6;
1470 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1471 } else if (w->reg == TAPAN_A_TX_4_EN) {
1472 init_bit_shift = 7;
1473 adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
1474 } else if (w->reg == TAPAN_A_TX_5_EN) {
1475 init_bit_shift = 6;
1476 adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
1477 } else {
1478 pr_err("%s: Error, invalid adc register\n", __func__);
1479 return -EINVAL;
1480 }
1481
1482 switch (event) {
1483 case SND_SOC_DAPM_PRE_PMU:
1484 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1485 1 << init_bit_shift);
1486 break;
1487 case SND_SOC_DAPM_POST_PMU:
1488
1489 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1490
1491 break;
1492 }
1493 return 0;
1494}
1495
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001496static int tapan_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1497 struct snd_kcontrol *kcontrol, int event)
1498{
1499 struct snd_soc_codec *codec = w->codec;
1500 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1501
1502 dev_dbg(codec->dev, "%s: %d\n", __func__, event);
1503
1504 switch (event) {
1505 case SND_SOC_DAPM_PRE_PMU:
1506 WCD9XXX_BCL_LOCK(&tapan->resmgr);
1507 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
1508 WCD9XXX_BANDGAP_AUDIO_MODE);
1509 /* AUX PGA requires RCO or MCLK */
1510 wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_RCO);
1511 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 1);
1512 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
1513 break;
1514
1515 case SND_SOC_DAPM_POST_PMD:
1516 WCD9XXX_BCL_LOCK(&tapan->resmgr);
1517 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 0);
1518 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
1519 WCD9XXX_BANDGAP_AUDIO_MODE);
1520 wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_RCO);
1521 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
1522 break;
1523 }
1524 return 0;
1525}
1526
1527static int tapan_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1528 struct snd_kcontrol *kcontrol, int event)
1529{
1530 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001531 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001532 u16 lineout_gain_reg;
1533
1534 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
1535
1536 switch (w->shift) {
1537 case 0:
1538 lineout_gain_reg = TAPAN_A_RX_LINE_1_GAIN;
1539 break;
1540 case 1:
1541 lineout_gain_reg = TAPAN_A_RX_LINE_2_GAIN;
1542 break;
1543 default:
1544 pr_err("%s: Error, incorrect lineout register value\n",
1545 __func__);
1546 return -EINVAL;
1547 }
1548
1549 switch (event) {
1550 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001551 break;
1552 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001553 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
1554 WCD9XXX_CLSH_STATE_LO,
1555 WCD9XXX_CLSH_REQ_ENABLE,
1556 WCD9XXX_CLSH_EVENT_POST_PA);
1557 dev_dbg(codec->dev, "%s: sleeping 3 ms after %s PA turn on\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001558 __func__, w->name);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001559 usleep_range(3000, 3010);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001560 break;
1561 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001562 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
1563 WCD9XXX_CLSH_STATE_LO,
1564 WCD9XXX_CLSH_REQ_DISABLE,
1565 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001566 break;
1567 }
1568 return 0;
1569}
1570
1571static int tapan_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1572 struct snd_kcontrol *kcontrol, int event)
1573{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001574 struct snd_soc_codec *codec = w->codec;
1575 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1576
1577 dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
1578 WCD9XXX_BCL_LOCK(&tapan->resmgr);
1579 switch (event) {
1580 case SND_SOC_DAPM_PRE_PMU:
1581 tapan->spkr_pa_widget_on = true;
1582 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
1583 break;
1584 case SND_SOC_DAPM_POST_PMD:
1585 tapan->spkr_pa_widget_on = false;
1586 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x00);
1587 break;
1588 }
1589 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001590 return 0;
1591}
1592
1593static int tapan_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1594 struct snd_kcontrol *kcontrol, int event)
1595{
1596 struct snd_soc_codec *codec = w->codec;
1597 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1598 u8 dmic_clk_en;
1599 u16 dmic_clk_reg;
1600 s32 *dmic_clk_cnt;
1601 unsigned int dmic;
1602 int ret;
1603
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001604 ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001605 if (ret < 0) {
1606 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
1607 return -EINVAL;
1608 }
1609
1610 switch (dmic) {
1611 case 1:
1612 case 2:
1613 dmic_clk_en = 0x01;
1614 dmic_clk_cnt = &(tapan->dmic_1_2_clk_cnt);
1615 dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B1_CTL;
1616 dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
1617 __func__, event, dmic, *dmic_clk_cnt);
1618
1619 break;
1620
1621 case 3:
1622 case 4:
1623 dmic_clk_en = 0x10;
1624 dmic_clk_cnt = &(tapan->dmic_3_4_clk_cnt);
1625 dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B1_CTL;
1626
1627 dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
1628 __func__, event, dmic, *dmic_clk_cnt);
1629 break;
1630
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001631 default:
1632 pr_err("%s: Invalid DMIC Selection\n", __func__);
1633 return -EINVAL;
1634 }
1635
1636 switch (event) {
1637 case SND_SOC_DAPM_PRE_PMU:
1638
1639 (*dmic_clk_cnt)++;
1640 if (*dmic_clk_cnt == 1)
1641 snd_soc_update_bits(codec, dmic_clk_reg,
1642 dmic_clk_en, dmic_clk_en);
1643
1644 break;
1645 case SND_SOC_DAPM_POST_PMD:
1646
1647 (*dmic_clk_cnt)--;
1648 if (*dmic_clk_cnt == 0)
1649 snd_soc_update_bits(codec, dmic_clk_reg,
1650 dmic_clk_en, 0);
1651 break;
1652 }
1653 return 0;
1654}
1655
1656static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,
1657 struct snd_kcontrol *kcontrol, int event)
1658{
1659 struct snd_soc_codec *codec = w->codec;
1660 const char *filename;
1661 const struct firmware *fw;
1662 int i;
1663 int ret;
1664 int num_anc_slots;
1665 struct anc_header *anc_head;
1666 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1667 u32 anc_writes_size = 0;
1668 int anc_size_remaining;
1669 u32 *anc_ptr;
1670 u16 reg;
1671 u8 mask, val;
1672
1673 dev_dbg(codec->dev, "%s %d\n", __func__, event);
1674 switch (event) {
1675 case SND_SOC_DAPM_PRE_PMU:
1676
1677 filename = "wcd9306/wcd9306_anc.bin";
1678
1679 ret = request_firmware(&fw, filename, codec->dev);
1680 if (ret != 0) {
1681 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1682 ret);
1683 return -ENODEV;
1684 }
1685
1686 if (fw->size < sizeof(struct anc_header)) {
1687 dev_err(codec->dev, "Not enough data\n");
1688 release_firmware(fw);
1689 return -ENOMEM;
1690 }
1691
1692 /* First number is the number of register writes */
1693 anc_head = (struct anc_header *)(fw->data);
1694 anc_ptr = (u32 *)((u32)fw->data + sizeof(struct anc_header));
1695 anc_size_remaining = fw->size - sizeof(struct anc_header);
1696 num_anc_slots = anc_head->num_anc_slots;
1697
1698 if (tapan->anc_slot >= num_anc_slots) {
1699 dev_err(codec->dev, "Invalid ANC slot selected\n");
1700 release_firmware(fw);
1701 return -EINVAL;
1702 }
1703
1704 for (i = 0; i < num_anc_slots; i++) {
1705
1706 if (anc_size_remaining < TAPAN_PACKED_REG_SIZE) {
1707 dev_err(codec->dev, "Invalid register format\n");
1708 release_firmware(fw);
1709 return -EINVAL;
1710 }
1711 anc_writes_size = (u32)(*anc_ptr);
1712 anc_size_remaining -= sizeof(u32);
1713 anc_ptr += 1;
1714
1715 if (anc_writes_size * TAPAN_PACKED_REG_SIZE
1716 > anc_size_remaining) {
1717 dev_err(codec->dev, "Invalid register format\n");
1718 release_firmware(fw);
1719 return -ENOMEM;
1720 }
1721
1722 if (tapan->anc_slot == i)
1723 break;
1724
1725 anc_size_remaining -= (anc_writes_size *
1726 TAPAN_PACKED_REG_SIZE);
1727 anc_ptr += anc_writes_size;
1728 }
1729 if (i == num_anc_slots) {
1730 dev_err(codec->dev, "Selected ANC slot not present\n");
1731 release_firmware(fw);
1732 return -ENOMEM;
1733 }
1734
1735 for (i = 0; i < anc_writes_size; i++) {
1736 TAPAN_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
1737 mask, val);
1738 snd_soc_write(codec, reg, val);
1739 }
1740 release_firmware(fw);
1741
1742 break;
1743 case SND_SOC_DAPM_POST_PMD:
1744 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
1745 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
1746 break;
1747 }
1748 return 0;
1749}
1750
1751static int tapan_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1752 struct snd_kcontrol *kcontrol, int event)
1753{
1754 struct snd_soc_codec *codec = w->codec;
1755 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1756 u16 micb_int_reg;
1757 u8 cfilt_sel_val = 0;
1758 char *internal1_text = "Internal1";
1759 char *internal2_text = "Internal2";
1760 char *internal3_text = "Internal3";
1761 enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
1762
1763 dev_dbg(codec->dev, "%s %d\n", __func__, event);
1764 switch (w->reg) {
1765 case TAPAN_A_MICB_1_CTL:
1766 micb_int_reg = TAPAN_A_MICB_1_INT_RBIAS;
1767 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias1_cfilt_sel;
1768 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
1769 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
1770 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
1771 break;
1772 case TAPAN_A_MICB_2_CTL:
1773 micb_int_reg = TAPAN_A_MICB_2_INT_RBIAS;
1774 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias2_cfilt_sel;
1775 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_2_ON;
1776 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
1777 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
1778 break;
1779 case TAPAN_A_MICB_3_CTL:
1780 micb_int_reg = TAPAN_A_MICB_3_INT_RBIAS;
1781 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias3_cfilt_sel;
1782 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
1783 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
1784 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
1785 break;
1786 default:
1787 pr_err("%s: Error, invalid micbias register\n", __func__);
1788 return -EINVAL;
1789 }
1790
1791 switch (event) {
1792 case SND_SOC_DAPM_PRE_PMU:
1793 /* Let MBHC module know so micbias switch to be off */
1794 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_pre_on);
1795
1796 /* Get cfilt */
1797 wcd9xxx_resmgr_cfilt_get(&tapan->resmgr, cfilt_sel_val);
1798
1799 if (strnstr(w->name, internal1_text, 30))
1800 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
1801 else if (strnstr(w->name, internal2_text, 30))
1802 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
1803 else if (strnstr(w->name, internal3_text, 30))
1804 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
1805
1806 break;
1807 case SND_SOC_DAPM_POST_PMU:
1808 usleep_range(20000, 20000);
1809 /* Let MBHC module know so micbias is on */
1810 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_on);
1811 break;
1812 case SND_SOC_DAPM_POST_PMD:
1813 /* Let MBHC module know so micbias switch to be off */
1814 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
1815
1816 if (strnstr(w->name, internal1_text, 30))
1817 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1818 else if (strnstr(w->name, internal2_text, 30))
1819 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1820 else if (strnstr(w->name, internal3_text, 30))
1821 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1822
1823 /* Put cfilt */
1824 wcd9xxx_resmgr_cfilt_put(&tapan->resmgr, cfilt_sel_val);
1825 break;
1826 }
1827
1828 return 0;
1829}
1830
1831static void tx_hpf_corner_freq_callback(struct work_struct *work)
1832{
1833 struct delayed_work *hpf_delayed_work;
1834 struct hpf_work *hpf_work;
1835 struct tapan_priv *tapan;
1836 struct snd_soc_codec *codec;
1837 u16 tx_mux_ctl_reg;
1838 u8 hpf_cut_of_freq;
1839
1840 hpf_delayed_work = to_delayed_work(work);
1841 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
1842 tapan = hpf_work->tapan;
1843 codec = hpf_work->tapan->codec;
1844 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
1845
1846 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL +
1847 (hpf_work->decimator - 1) * 8;
1848
1849 dev_dbg(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
1850 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
1851
1852 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
1853}
1854
1855#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
1856#define CF_MIN_3DB_4HZ 0x0
1857#define CF_MIN_3DB_75HZ 0x1
1858#define CF_MIN_3DB_150HZ 0x2
1859
1860static int tapan_codec_enable_dec(struct snd_soc_dapm_widget *w,
1861 struct snd_kcontrol *kcontrol, int event)
1862{
1863 struct snd_soc_codec *codec = w->codec;
1864 unsigned int decimator;
1865 char *dec_name = NULL;
1866 char *widget_name = NULL;
1867 char *temp;
1868 int ret = 0;
1869 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
1870 u8 dec_hpf_cut_of_freq;
1871 int offset;
1872
1873 dev_dbg(codec->dev, "%s %d\n", __func__, event);
1874
1875 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1876 if (!widget_name)
1877 return -ENOMEM;
1878 temp = widget_name;
1879
1880 dec_name = strsep(&widget_name, " ");
1881 widget_name = temp;
1882 if (!dec_name) {
1883 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1884 ret = -EINVAL;
1885 goto out;
1886 }
1887
1888 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
1889 if (ret < 0) {
1890 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1891 ret = -EINVAL;
1892 goto out;
1893 }
1894
1895 dev_dbg(codec->dev, "%s(): widget = %s dec_name = %s decimator = %u\n",
1896 __func__, w->name, dec_name, decimator);
1897
1898 if (w->reg == TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
1899 dec_reset_reg = TAPAN_A_CDC_CLK_TX_RESET_B1_CTL;
1900 offset = 0;
1901 } else if (w->reg == TAPAN_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
1902 dec_reset_reg = TAPAN_A_CDC_CLK_TX_RESET_B2_CTL;
1903 offset = 8;
1904 } else {
1905 pr_err("%s: Error, incorrect dec\n", __func__);
1906 ret = -EINVAL;
1907 goto out;
1908 }
1909
1910 tx_vol_ctl_reg = TAPAN_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
1911 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1912
1913 switch (event) {
1914 case SND_SOC_DAPM_PRE_PMU:
1915
1916 /* Enableable TX digital mute */
1917 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1918
1919 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1920 1 << w->shift);
1921 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1922
1923 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
1924
1925 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
1926
1927 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
1928 dec_hpf_cut_of_freq;
1929
1930 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
1931
1932 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
1933 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1934 CF_MIN_3DB_150HZ << 4);
1935 }
1936
1937 /* enable HPF */
1938 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
1939
1940 break;
1941
1942 case SND_SOC_DAPM_POST_PMU:
1943
1944 /* Disable TX digital mute */
1945 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
1946
1947 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
1948 CF_MIN_3DB_150HZ) {
1949
1950 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
1951 msecs_to_jiffies(300));
1952 }
1953 /* apply the digital gain after the decimator is enabled*/
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001954 if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001955 snd_soc_write(codec,
1956 tx_digital_gain_reg[w->shift + offset],
1957 snd_soc_read(codec,
1958 tx_digital_gain_reg[w->shift + offset])
1959 );
1960
1961 break;
1962
1963 case SND_SOC_DAPM_PRE_PMD:
1964
1965 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1966 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
1967 break;
1968
1969 case SND_SOC_DAPM_POST_PMD:
1970
1971 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
1972 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1973 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
1974
1975 break;
1976 }
1977out:
1978 kfree(widget_name);
1979 return ret;
1980}
1981
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001982static int tapan_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
1983 struct snd_kcontrol *kcontrol, int event)
1984{
1985 struct snd_soc_codec *codec = w->codec;
1986 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1987
1988 dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
1989
1990 switch (event) {
1991 case SND_SOC_DAPM_PRE_PMU:
1992
1993 if (spkr_drv_wrnd > 0) {
1994 WARN_ON(!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
1995 0x80));
1996 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
1997 0x00);
1998 }
1999 if (TAPAN_IS_1_0(core->version))
2000 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
2001 0x24, 0x00);
2002 break;
2003 case SND_SOC_DAPM_POST_PMD:
2004 if (TAPAN_IS_1_0(core->version))
2005 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
2006 0x24, 0x24);
2007 if (spkr_drv_wrnd > 0) {
2008 WARN_ON(!!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
2009 0x80));
2010 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
2011 0x80);
2012 }
2013 break;
2014 }
2015 return 0;
2016}
2017
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002018static int tapan_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
2019 struct snd_kcontrol *kcontrol, int event)
2020{
2021 struct snd_soc_codec *codec = w->codec;
2022
2023 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
2024
2025 switch (event) {
2026 case SND_SOC_DAPM_PRE_PMU:
2027 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_RESET_CTL,
2028 1 << w->shift, 1 << w->shift);
2029 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_RESET_CTL,
2030 1 << w->shift, 0x0);
2031 break;
2032 case SND_SOC_DAPM_POST_PMU:
2033 /* apply the digital gain after the interpolator is enabled*/
2034 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2035 snd_soc_write(codec,
2036 rx_digital_gain_reg[w->shift],
2037 snd_soc_read(codec,
2038 rx_digital_gain_reg[w->shift])
2039 );
2040 break;
2041 }
2042 return 0;
2043}
2044
2045static int tapan_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2046 struct snd_kcontrol *kcontrol, int event)
2047{
2048 switch (event) {
2049 case SND_SOC_DAPM_POST_PMU:
2050 case SND_SOC_DAPM_POST_PMD:
2051 usleep_range(1000, 1000);
2052 break;
2053 }
2054 return 0;
2055}
2056
2057static int tapan_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2058 struct snd_kcontrol *kcontrol, int event)
2059{
2060 struct snd_soc_codec *codec = w->codec;
2061 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2062
2063 dev_dbg(codec->dev, "%s %d\n", __func__, event);
2064
2065 switch (event) {
2066 case SND_SOC_DAPM_PRE_PMU:
2067 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 1);
2068 break;
2069 case SND_SOC_DAPM_POST_PMD:
2070 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 0);
2071 break;
2072 }
2073 return 0;
2074}
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002075
2076
2077static int tapan_hphl_dac_event(struct snd_soc_dapm_widget *w,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002078 struct snd_kcontrol *kcontrol, int event)
2079{
2080 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002081 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002082
2083 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2084
2085 switch (event) {
2086 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002087 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2088 0x02, 0x02);
2089 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
2090 WCD9XXX_CLSH_STATE_HPHL,
2091 WCD9XXX_CLSH_REQ_ENABLE,
2092 WCD9XXX_CLSH_EVENT_PRE_DAC);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002093 break;
2094 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002095 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2096 0x02, 0x00);
2097 }
2098 return 0;
2099}
2100
2101static int tapan_hphr_dac_event(struct snd_soc_dapm_widget *w,
2102 struct snd_kcontrol *kcontrol, int event)
2103{
2104 struct snd_soc_codec *codec = w->codec;
2105 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
2106
2107 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2108
2109 switch (event) {
2110 case SND_SOC_DAPM_PRE_PMU:
2111 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2112 0x04, 0x04);
2113 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2114 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
2115 WCD9XXX_CLSH_STATE_HPHR,
2116 WCD9XXX_CLSH_REQ_ENABLE,
2117 WCD9XXX_CLSH_EVENT_PRE_DAC);
2118 break;
2119 case SND_SOC_DAPM_POST_PMD:
2120 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2121 0x04, 0x00);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002122 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2123 break;
2124 }
2125 return 0;
2126}
2127
2128static int tapan_hph_pa_event(struct snd_soc_dapm_widget *w,
2129 struct snd_kcontrol *kcontrol, int event)
2130{
2131 struct snd_soc_codec *codec = w->codec;
2132 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2133 enum wcd9xxx_notify_event e_pre_on, e_post_off;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002134 u8 req_clsh_state;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002135
2136 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
2137 if (w->shift == 5) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002138 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
2139 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
Patrick Lai6ef05902013-03-16 18:14:16 -07002140 req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
2141 } else if (w->shift == 4) {
2142 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
2143 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002144 req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002145 } else {
2146 pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
2147 return -EINVAL;
2148 }
2149
2150 switch (event) {
2151 case SND_SOC_DAPM_PRE_PMU:
2152 /* Let MBHC module know PA is turning on */
2153 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_pre_on);
2154 break;
2155
2156 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002157 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2158 req_clsh_state,
2159 WCD9XXX_CLSH_REQ_ENABLE,
2160 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002161
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002162
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002163 usleep_range(5000, 5010);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002164 break;
2165
2166 case SND_SOC_DAPM_POST_PMD:
2167 /* Let MBHC module know PA turned off */
2168 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
2169
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002170 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2171 req_clsh_state,
2172 WCD9XXX_CLSH_REQ_DISABLE,
2173 WCD9XXX_CLSH_EVENT_POST_PA);
2174
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002175 dev_dbg(codec->dev, "%s: sleep 10 ms after %s PA disable.\n",
2176 __func__, w->name);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002177 usleep_range(5000, 5010);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002178 break;
2179 }
2180 return 0;
2181}
2182
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002183static const struct snd_soc_dapm_widget tapan_dapm_i2s_widgets[] = {
2184 SND_SOC_DAPM_SUPPLY("I2S_CLK", TAPAN_A_CDC_CLK_I2S_CTL,
2185 4, 0, NULL, 0),
2186};
2187
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002188static int tapan_lineout_dac_event(struct snd_soc_dapm_widget *w,
2189 struct snd_kcontrol *kcontrol, int event)
2190{
2191 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002192 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002193
2194 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2195
2196 switch (event) {
2197 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002198 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2199 WCD9XXX_CLSH_STATE_LO,
2200 WCD9XXX_CLSH_REQ_ENABLE,
2201 WCD9XXX_CLSH_EVENT_PRE_DAC);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002202 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2203 break;
2204
2205 case SND_SOC_DAPM_POST_PMD:
2206 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2207 break;
2208 }
2209 return 0;
2210}
2211
2212static int tapan_spk_dac_event(struct snd_soc_dapm_widget *w,
2213 struct snd_kcontrol *kcontrol, int event)
2214{
2215 struct snd_soc_codec *codec = w->codec;
2216
2217 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2218 return 0;
2219}
2220
2221static const struct snd_soc_dapm_route audio_i2s_map[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002222 {"I2S_CLK", NULL, "CDC_CONN"},
2223 {"SLIM RX1", NULL, "I2S_CLK"},
2224 {"SLIM RX2", NULL, "I2S_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002225
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002226 {"SLIM TX1 MUX", NULL, "I2S_CLK"},
2227 {"SLIM TX2 MUX", NULL, "I2S_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002228};
2229
2230static const struct snd_soc_dapm_route audio_map[] = {
2231 /* SLIMBUS Connections */
2232 {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
2233 {"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
2234 {"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
2235
2236 /* SLIM_MIXER("AIF1_CAP Mixer"),*/
2237 {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2238 {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2239 {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2240 {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2241 {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002242 /* SLIM_MIXER("AIF2_CAP Mixer"),*/
2243 {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2244 {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2245 {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2246 {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2247 {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002248 /* SLIM_MIXER("AIF3_CAP Mixer"),*/
2249 {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2250 {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2251 {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2252 {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2253 {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002254
2255 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002256 {"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
2257 {"SLIM TX1 MUX", "DEC3", "DEC3 MUX"},
2258 {"SLIM TX1 MUX", "DEC4", "DEC4 MUX"},
2259 {"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
2260 {"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
2261 {"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
2262 {"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002263
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002264 {"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002265 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002266 {"SLIM TX2 MUX", "DEC3", "DEC3 MUX"},
2267 {"SLIM TX2 MUX", "DEC4", "DEC4 MUX"},
2268 {"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
2269 {"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
2270 {"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
2271 {"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002272
2273 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
2274 {"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
2275 {"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
2276 {"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
2277 {"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002278
2279 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002280 {"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
2281 {"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
2282 {"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
2283 {"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002284
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002285 {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002286 {"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
2287 {"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
2288 {"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
2289 {"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002290
2291 /* Earpiece (RX MIX1) */
2292 {"EAR", NULL, "EAR PA"},
2293 {"EAR PA", NULL, "EAR_PA_MIXER"},
2294 {"EAR_PA_MIXER", NULL, "DAC1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002295 {"DAC1", NULL, "RX_BIAS"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002296
2297 /* Headset (RX MIX1 and RX MIX2) */
2298 {"HEADPHONE", NULL, "HPHL"},
2299 {"HEADPHONE", NULL, "HPHR"},
2300
2301 {"HPHL", NULL, "HPHL_PA_MIXER"},
2302 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002303 {"HPHL DAC", NULL, "RX_BIAS"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002304
2305 {"HPHR", NULL, "HPHR_PA_MIXER"},
2306 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002307 {"HPHR DAC", NULL, "RX_BIAS"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002308
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002309 {"DAC1", "Switch", "CLASS_H_DSM MUX"},
2310 {"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002311 {"HPHR DAC", NULL, "RX2 CHAIN"},
2312
2313 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2314 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002315 {"SPK_OUT", NULL, "SPK PA"},
2316
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002317 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2318 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
2319
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002320 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2321 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2322
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002323 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2324
2325 {"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002326 {"RDAC5 MUX", "DEM4", "RX4 MIX2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002327
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002328 {"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002329
2330 {"SPK PA", NULL, "SPK DAC"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002331 {"SPK DAC", "Switch", "RX4 MIX2"},
2332 {"SPK DAC", NULL, "VDD_SPKDRV"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002333
2334 {"RX1 CHAIN", NULL, "RX1 MIX2"},
2335 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002336 {"CLASS_H_DSM MUX", "RX_HPHL", "RX1 CHAIN"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002337
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002338 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2339 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002340
2341 {"RX1 MIX1", NULL, "COMP1_CLK"},
2342 {"RX2 MIX1", NULL, "COMP1_CLK"},
2343 {"RX3 MIX1", NULL, "COMP2_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002344
2345 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2346 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2347 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
2348 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2349 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2350 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2351 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2352 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2353 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002354 {"RX1 MIX2", NULL, "RX1 MIX1"},
2355 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
2356 {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
2357 {"RX2 MIX2", NULL, "RX2 MIX1"},
2358 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
2359 {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002360 {"RX4 MIX2", NULL, "RX4 MIX1"},
2361 {"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
2362 {"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002363
2364 /* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
2365 {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
2366 {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
2367 {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
2368 {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
2369 {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002370 /* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
2371 {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
2372 {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
2373 {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
2374 {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
2375 {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002376 /* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
2377 {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
2378 {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
2379 {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
2380 {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
2381 {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002382
2383 {"SLIM RX1", NULL, "SLIM RX1 MUX"},
2384 {"SLIM RX2", NULL, "SLIM RX2 MUX"},
2385 {"SLIM RX3", NULL, "SLIM RX3 MUX"},
2386 {"SLIM RX4", NULL, "SLIM RX4 MUX"},
2387 {"SLIM RX5", NULL, "SLIM RX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002388
2389 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2390 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
2391 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2392 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
2393 {"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002394 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2395 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2396 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
2397 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2398 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
2399 {"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002400 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2401 {"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
2402 {"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
2403 {"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
2404 {"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
2405 {"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002406 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2407 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
2408 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2409 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
2410 {"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002411 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
2412 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2413 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
2414 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2415 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
2416 {"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002417 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
2418 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2419 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
2420 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2421 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
2422 {"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002423 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
2424 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2425 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
2426 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2427 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
2428 {"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002429 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
2430 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2431 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
2432 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2433 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
2434 {"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002435 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
2436 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2437 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
2438 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2439 {"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
2440 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002441 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002442
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002443 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
2444 {"RX1 MIX2 INP2", "IIR1", "IIR1"},
2445 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
2446 {"RX2 MIX2 INP2", "IIR1", "IIR1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002447 {"RX4 MIX2 INP1", "IIR1", "IIR1"},
2448 {"RX4 MIX2 INP2", "IIR1", "IIR1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002449
2450 /* Decimator Inputs */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002451 {"DEC1 MUX", "ADC1", "ADC1"},
2452 {"DEC1 MUX", "ADC2", "ADC2"},
2453 {"DEC1 MUX", "ADC3", "ADC3"},
2454 {"DEC1 MUX", "ADC4", "ADC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002455 {"DEC1 MUX", "DMIC1", "DMIC1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002456 {"DEC1 MUX", "DMIC2", "DMIC2"},
2457 {"DEC1 MUX", "DMIC3", "DMIC3"},
2458 {"DEC1 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002459 {"DEC1 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002460
2461 {"DEC2 MUX", "ADC1", "ADC1"},
2462 {"DEC2 MUX", "ADC2", "ADC2"},
2463 {"DEC2 MUX", "ADC3", "ADC3"},
2464 {"DEC2 MUX", "ADC4", "ADC4"},
2465 {"DEC2 MUX", "DMIC1", "DMIC1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002466 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002467 {"DEC2 MUX", "DMIC3", "DMIC3"},
2468 {"DEC2 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002469 {"DEC2 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002470
2471 {"DEC3 MUX", "ADC1", "ADC1"},
2472 {"DEC3 MUX", "ADC2", "ADC2"},
2473 {"DEC3 MUX", "ADC3", "ADC3"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002474 {"DEC3 MUX", "ADC4", "ADC4"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002475 {"DEC3 MUX", "ADC5", "ADC5"},
2476 {"DEC3 MUX", "DMIC1", "DMIC1"},
2477 {"DEC3 MUX", "DMIC2", "DMIC2"},
2478 {"DEC3 MUX", "DMIC3", "DMIC3"},
2479 {"DEC3 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002480 {"DEC3 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002481
2482 {"DEC4 MUX", "ADC1", "ADC1"},
2483 {"DEC4 MUX", "ADC2", "ADC2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002484 {"DEC4 MUX", "ADC3", "ADC3"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002485 {"DEC4 MUX", "ADC4", "ADC4"},
2486 {"DEC4 MUX", "ADC5", "ADC5"},
2487 {"DEC4 MUX", "DMIC1", "DMIC1"},
2488 {"DEC4 MUX", "DMIC2", "DMIC2"},
2489 {"DEC4 MUX", "DMIC3", "DMIC3"},
2490 {"DEC4 MUX", "DMIC4", "DMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002491 {"DEC4 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002492
2493 /* ADC Connections */
2494 {"ADC1", NULL, "AMIC1"},
2495 {"ADC2", NULL, "AMIC2"},
2496 {"ADC3", NULL, "AMIC3"},
2497 {"ADC4", NULL, "AMIC4"},
2498 {"ADC5", NULL, "AMIC5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002499
2500 /* AUX PGA Connections */
2501 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2502 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2503 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2504 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2505 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002506 {"AUX_PGA_Left", NULL, "AMIC5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002507
2508 {"IIR1", NULL, "IIR1 INP1 MUX"},
2509 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2510 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
2511 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2512 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002513
2514 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2515 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2516 {"MIC BIAS1 External", NULL, "LDO_H"},
2517 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2518 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2519 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2520 {"MIC BIAS2 External", NULL, "LDO_H"},
2521 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2522 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2523 {"MIC BIAS3 External", NULL, "LDO_H"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002524};
2525
2526static int tapan_readable(struct snd_soc_codec *ssc, unsigned int reg)
2527{
2528 return tapan_reg_readable[reg];
2529}
2530
2531static bool tapan_is_digital_gain_register(unsigned int reg)
2532{
2533 bool rtn = false;
2534 switch (reg) {
2535 case TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL:
2536 case TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL:
2537 case TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL:
2538 case TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL:
2539 case TAPAN_A_CDC_TX1_VOL_CTL_GAIN:
2540 case TAPAN_A_CDC_TX2_VOL_CTL_GAIN:
2541 case TAPAN_A_CDC_TX3_VOL_CTL_GAIN:
2542 case TAPAN_A_CDC_TX4_VOL_CTL_GAIN:
2543 rtn = true;
2544 break;
2545 default:
2546 break;
2547 }
2548 return rtn;
2549}
2550
2551static int tapan_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2552{
2553 /* Registers lower than 0x100 are top level registers which can be
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002554 * written by the Tapan core driver.
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002555 */
2556
2557 if ((reg >= TAPAN_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2558 return 1;
2559
2560 /* IIR Coeff registers are not cacheable */
2561 if ((reg >= TAPAN_A_CDC_IIR1_COEF_B1_CTL) &&
2562 (reg <= TAPAN_A_CDC_IIR2_COEF_B2_CTL))
2563 return 1;
2564
2565 /* Digital gain register is not cacheable so we have to write
2566 * the setting even it is the same
2567 */
2568 if (tapan_is_digital_gain_register(reg))
2569 return 1;
2570
2571 /* HPH status registers */
2572 if (reg == TAPAN_A_RX_HPH_L_STATUS || reg == TAPAN_A_RX_HPH_R_STATUS)
2573 return 1;
2574
2575 if (reg == TAPAN_A_MBHC_INSERT_DET_STATUS)
2576 return 1;
2577
2578 return 0;
2579}
2580
2581#define TAPAN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2582static int tapan_write(struct snd_soc_codec *codec, unsigned int reg,
2583 unsigned int value)
2584{
2585 int ret;
2586
2587 if (reg == SND_SOC_NOPM)
2588 return 0;
2589
2590 BUG_ON(reg > TAPAN_MAX_REGISTER);
2591
2592 if (!tapan_volatile(codec, reg)) {
2593 ret = snd_soc_cache_write(codec, reg, value);
2594 if (ret != 0)
2595 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2596 reg, ret);
2597 }
2598
2599 return wcd9xxx_reg_write(codec->control_data, reg, value);
2600}
2601static unsigned int tapan_read(struct snd_soc_codec *codec,
2602 unsigned int reg)
2603{
2604 unsigned int val;
2605 int ret;
2606
2607 if (reg == SND_SOC_NOPM)
2608 return 0;
2609
2610 BUG_ON(reg > TAPAN_MAX_REGISTER);
2611
2612 if (!tapan_volatile(codec, reg) && tapan_readable(codec, reg) &&
2613 reg < codec->driver->reg_cache_size) {
2614 ret = snd_soc_cache_read(codec, reg, &val);
2615 if (ret >= 0) {
2616 return val;
2617 } else
2618 dev_err(codec->dev, "Cache read from %x failed: %d\n",
2619 reg, ret);
2620 }
2621
2622 val = wcd9xxx_reg_read(codec->control_data, reg);
2623 return val;
2624}
2625
2626static int tapan_startup(struct snd_pcm_substream *substream,
2627 struct snd_soc_dai *dai)
2628{
2629 struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
2630 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
2631 __func__, substream->name, substream->stream);
2632 if ((tapan_core != NULL) &&
2633 (tapan_core->dev != NULL) &&
2634 (tapan_core->dev->parent != NULL))
2635 pm_runtime_get_sync(tapan_core->dev->parent);
2636
2637 return 0;
2638}
2639
2640static void tapan_shutdown(struct snd_pcm_substream *substream,
2641 struct snd_soc_dai *dai)
2642{
2643 struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
2644 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
2645 __func__, substream->name, substream->stream);
2646 if ((tapan_core != NULL) &&
2647 (tapan_core->dev != NULL) &&
2648 (tapan_core->dev->parent != NULL)) {
2649 pm_runtime_mark_last_busy(tapan_core->dev->parent);
2650 pm_runtime_put(tapan_core->dev->parent);
2651 }
2652}
2653
2654int tapan_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
2655{
2656 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2657
2658 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n", __func__,
2659 mclk_enable, dapm);
2660
2661 WCD9XXX_BCL_LOCK(&tapan->resmgr);
2662 if (mclk_enable) {
2663 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
2664 WCD9XXX_BANDGAP_AUDIO_MODE);
2665 wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
2666 } else {
2667 /* Put clock and BG */
2668 wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
2669 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
2670 WCD9XXX_BANDGAP_AUDIO_MODE);
2671 }
2672 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
2673
2674 return 0;
2675}
2676
2677static int tapan_set_dai_sysclk(struct snd_soc_dai *dai,
2678 int clk_id, unsigned int freq, int dir)
2679{
2680 dev_dbg(dai->codec->dev, "%s\n", __func__);
2681 return 0;
2682}
2683
2684static int tapan_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2685{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002686 u8 val = 0;
2687 struct snd_soc_codec *codec = dai->codec;
2688 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2689
2690 dev_dbg(codec->dev, "%s\n", __func__);
2691 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
2692 case SND_SOC_DAIFMT_CBS_CFS:
2693 /* CPU is master */
2694 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2695 if (dai->id == AIF1_CAP)
2696 snd_soc_update_bits(codec,
2697 TAPAN_A_CDC_CLK_I2S_CTL,
2698 TAPAN_I2S_MASTER_MODE_MASK, 0);
2699 else if (dai->id == AIF1_PB)
2700 snd_soc_update_bits(codec,
2701 TAPAN_A_CDC_CLK_I2S_CTL,
2702 TAPAN_I2S_MASTER_MODE_MASK, 0);
2703 }
2704 break;
2705 case SND_SOC_DAIFMT_CBM_CFM:
2706 /* CPU is slave */
2707 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
2708 val = TAPAN_I2S_MASTER_MODE_MASK;
2709 if (dai->id == AIF1_CAP)
2710 snd_soc_update_bits(codec,
2711 TAPAN_A_CDC_CLK_I2S_CTL, val, val);
2712 else if (dai->id == AIF1_PB)
2713 snd_soc_update_bits(codec,
2714 TAPAN_A_CDC_CLK_I2S_CTL, val, val);
2715 }
2716 break;
2717 default:
2718 return -EINVAL;
2719 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002720 return 0;
2721}
2722
2723static int tapan_set_channel_map(struct snd_soc_dai *dai,
2724 unsigned int tx_num, unsigned int *tx_slot,
2725 unsigned int rx_num, unsigned int *rx_slot)
2726
2727{
2728 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
2729 struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
2730 if (!tx_slot && !rx_slot) {
2731 pr_err("%s: Invalid\n", __func__);
2732 return -EINVAL;
2733 }
2734 dev_dbg(dai->codec->dev, "%s(): dai_name = %s DAI-ID %x\n",
2735 __func__, dai->name, dai->id);
2736 dev_dbg(dai->codec->dev, "%s(): tx_ch %d rx_ch %d\n intf_type %d\n",
2737 __func__, tx_num, rx_num, tapan->intf_type);
2738
2739 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
2740 wcd9xxx_init_slimslave(core, core->slim->laddr,
2741 tx_num, tx_slot, rx_num, rx_slot);
2742 return 0;
2743}
2744
2745static int tapan_get_channel_map(struct snd_soc_dai *dai,
2746 unsigned int *tx_num, unsigned int *tx_slot,
2747 unsigned int *rx_num, unsigned int *rx_slot)
2748
2749{
2750 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(dai->codec);
2751 u32 i = 0;
2752 struct wcd9xxx_ch *ch;
2753
2754 switch (dai->id) {
2755 case AIF1_PB:
2756 case AIF2_PB:
2757 case AIF3_PB:
2758 if (!rx_slot || !rx_num) {
2759 pr_err("%s: Invalid rx_slot %d or rx_num %d\n",
2760 __func__, (u32) rx_slot, (u32) rx_num);
2761 return -EINVAL;
2762 }
2763 list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
2764 list) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002765 dev_dbg(dai->codec->dev, "%s: rx_slot[%d] %d, ch->ch_num %d\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002766 __func__, i, rx_slot[i], ch->ch_num);
2767 rx_slot[i++] = ch->ch_num;
2768 }
2769 dev_dbg(dai->codec->dev, "%s: rx_num %d\n", __func__, i);
2770 *rx_num = i;
2771 break;
2772 case AIF1_CAP:
2773 case AIF2_CAP:
2774 case AIF3_CAP:
2775 if (!tx_slot || !tx_num) {
2776 pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
2777 __func__, (u32) tx_slot, (u32) tx_num);
2778 return -EINVAL;
2779 }
2780 list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
2781 list) {
2782 dev_dbg(dai->codec->dev, "%s: tx_slot[%d] %d, ch->ch_num %d\n",
2783 __func__, i, tx_slot[i], ch->ch_num);
2784 tx_slot[i++] = ch->ch_num;
2785 }
2786 dev_dbg(dai->codec->dev, "%s: tx_num %d\n", __func__, i);
2787 *tx_num = i;
2788 break;
2789
2790 default:
2791 pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id);
2792 break;
2793 }
2794
2795 return 0;
2796}
2797
2798static int tapan_set_interpolator_rate(struct snd_soc_dai *dai,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002799 u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002800{
2801 u32 j;
2802 u8 rx_mix1_inp;
2803 u16 rx_mix_1_reg_1, rx_mix_1_reg_2;
2804 u16 rx_fs_reg;
2805 u8 rx_mix_1_reg_1_val, rx_mix_1_reg_2_val;
2806 struct snd_soc_codec *codec = dai->codec;
2807 struct wcd9xxx_ch *ch;
2808 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2809
2810 list_for_each_entry(ch, &tapan->dai[dai->id].wcd9xxx_ch_list, list) {
2811 /* for RX port starting from 16 instead of 10 like tabla */
2812 rx_mix1_inp = ch->port + RX_MIX1_INP_SEL_RX1 -
2813 TAPAN_TX_PORT_NUMBER;
2814 if ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002815 (rx_mix1_inp > RX_MIX1_INP_SEL_RX5)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002816 pr_err("%s: Invalid TAPAN_RX%u port. Dai ID is %d\n",
2817 __func__, rx_mix1_inp - 5 , dai->id);
2818 return -EINVAL;
2819 }
2820
2821 rx_mix_1_reg_1 = TAPAN_A_CDC_CONN_RX1_B1_CTL;
2822
2823 for (j = 0; j < NUM_INTERPOLATORS; j++) {
2824 rx_mix_1_reg_2 = rx_mix_1_reg_1 + 1;
2825
2826 rx_mix_1_reg_1_val = snd_soc_read(codec,
2827 rx_mix_1_reg_1);
2828 rx_mix_1_reg_2_val = snd_soc_read(codec,
2829 rx_mix_1_reg_2);
2830
2831 if (((rx_mix_1_reg_1_val & 0x0F) == rx_mix1_inp) ||
2832 (((rx_mix_1_reg_1_val >> 4) & 0x0F)
2833 == rx_mix1_inp) ||
2834 ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
2835
2836 rx_fs_reg = TAPAN_A_CDC_RX1_B5_CTL + 8 * j;
2837
2838 dev_dbg(codec->dev, "%s: AIF_PB DAI(%d) connected to RX%u\n",
2839 __func__, dai->id, j + 1);
2840
2841 dev_dbg(codec->dev, "%s: set RX%u sample rate to %u\n",
2842 __func__, j + 1, sample_rate);
2843
2844 snd_soc_update_bits(codec, rx_fs_reg,
2845 0xE0, rx_fs_rate_reg_val);
2846
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002847 if (comp_rx_path[j] < COMPANDER_MAX)
2848 tapan->comp_fs[comp_rx_path[j]]
2849 = compander_fs;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002850 }
2851 if (j <= 2)
2852 rx_mix_1_reg_1 += 3;
2853 else
2854 rx_mix_1_reg_1 += 2;
2855 }
2856 }
2857 return 0;
2858}
2859
2860static int tapan_set_decimator_rate(struct snd_soc_dai *dai,
2861 u8 tx_fs_rate_reg_val, u32 sample_rate)
2862{
2863 struct snd_soc_codec *codec = dai->codec;
2864 struct wcd9xxx_ch *ch;
2865 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2866 u32 tx_port;
2867 u16 tx_port_reg, tx_fs_reg;
2868 u8 tx_port_reg_val;
2869 s8 decimator;
2870
2871 list_for_each_entry(ch, &tapan->dai[dai->id].wcd9xxx_ch_list, list) {
2872
2873 tx_port = ch->port + 1;
2874 dev_dbg(codec->dev, "%s: dai->id = %d, tx_port = %d",
2875 __func__, dai->id, tx_port);
2876
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002877 if ((tx_port < 1) || (tx_port > TAPAN_SLIM_CODEC_TX_PORTS)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002878 pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
2879 __func__, tx_port, dai->id);
2880 return -EINVAL;
2881 }
2882
2883 tx_port_reg = TAPAN_A_CDC_CONN_TX_SB_B1_CTL + (tx_port - 1);
2884 tx_port_reg_val = snd_soc_read(codec, tx_port_reg);
2885
2886 decimator = 0;
2887
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002888 tx_port_reg_val = tx_port_reg_val & 0x0F;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002889
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002890 if ((tx_port_reg_val >= 0x8) &&
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002891 (tx_port_reg_val <= 0x11)) {
2892
2893 decimator = (tx_port_reg_val - 0x8) + 1;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002894 }
2895
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002896
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002897 if (decimator) { /* SLIM_TX port has a DEC as input */
2898
2899 tx_fs_reg = TAPAN_A_CDC_TX1_CLK_FS_CTL +
2900 8 * (decimator - 1);
2901
2902 dev_dbg(codec->dev, "%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
2903 __func__, decimator, tx_port, sample_rate);
2904
2905 snd_soc_update_bits(codec, tx_fs_reg, 0x07,
2906 tx_fs_rate_reg_val);
2907
2908 } else {
2909 if ((tx_port_reg_val >= 0x1) &&
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002910 (tx_port_reg_val <= 0x4)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002911
2912 dev_dbg(codec->dev, "%s: RMIX%u going to SLIM TX%u\n",
2913 __func__, tx_port_reg_val, tx_port);
2914
2915 } else if ((tx_port_reg_val >= 0x8) &&
2916 (tx_port_reg_val <= 0x11)) {
2917
2918 pr_err("%s: ERROR: Should not be here\n",
2919 __func__);
2920 pr_err("%s: ERROR: DEC connected to SLIM TX%u\n",
2921 __func__, tx_port);
2922 return -EINVAL;
2923
2924 } else if (tx_port_reg_val == 0) {
2925 dev_dbg(codec->dev, "%s: no signal to SLIM TX%u\n",
2926 __func__, tx_port);
2927 } else {
2928 pr_err("%s: ERROR: wrong signal to SLIM TX%u\n",
2929 __func__, tx_port);
2930 pr_err("%s: ERROR: wrong signal = %u\n",
2931 __func__, tx_port_reg_val);
2932 return -EINVAL;
2933 }
2934 }
2935 }
2936 return 0;
2937}
2938
2939static int tapan_hw_params(struct snd_pcm_substream *substream,
2940 struct snd_pcm_hw_params *params,
2941 struct snd_soc_dai *dai)
2942{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002943 struct snd_soc_codec *codec = dai->codec;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002944 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
2945 u8 tx_fs_rate, rx_fs_rate;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002946 u32 compander_fs;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002947 int ret;
2948
2949 dev_dbg(dai->codec->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n",
2950 __func__, dai->name, dai->id,
2951 params_rate(params), params_channels(params));
2952
2953 switch (params_rate(params)) {
2954 case 8000:
2955 tx_fs_rate = 0x00;
2956 rx_fs_rate = 0x00;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002957 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002958 break;
2959 case 16000:
2960 tx_fs_rate = 0x01;
2961 rx_fs_rate = 0x20;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002962 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002963 break;
2964 case 32000:
2965 tx_fs_rate = 0x02;
2966 rx_fs_rate = 0x40;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002967 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002968 break;
2969 case 48000:
2970 tx_fs_rate = 0x03;
2971 rx_fs_rate = 0x60;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002972 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002973 break;
2974 case 96000:
2975 tx_fs_rate = 0x04;
2976 rx_fs_rate = 0x80;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002977 compander_fs = COMPANDER_FS_96KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002978 break;
2979 case 192000:
2980 tx_fs_rate = 0x05;
2981 rx_fs_rate = 0xA0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002982 compander_fs = COMPANDER_FS_192KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002983 break;
2984 default:
2985 pr_err("%s: Invalid sampling rate %d\n", __func__,
2986 params_rate(params));
2987 return -EINVAL;
2988 }
2989
2990 switch (substream->stream) {
2991 case SNDRV_PCM_STREAM_CAPTURE:
2992 ret = tapan_set_decimator_rate(dai, tx_fs_rate,
2993 params_rate(params));
2994 if (ret < 0) {
2995 pr_err("%s: set decimator rate failed %d\n", __func__,
2996 ret);
2997 return ret;
2998 }
2999
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003000 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3001 switch (params_format(params)) {
3002 case SNDRV_PCM_FORMAT_S16_LE:
3003 snd_soc_update_bits(codec,
3004 TAPAN_A_CDC_CLK_I2S_CTL,
3005 0x20, 0x20);
3006 break;
3007 case SNDRV_PCM_FORMAT_S32_LE:
3008 snd_soc_update_bits(codec,
3009 TAPAN_A_CDC_CLK_I2S_CTL,
3010 0x20, 0x00);
3011 break;
3012 default:
3013 pr_err("invalid format\n");
3014 break;
3015 }
3016 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
3017 0x07, tx_fs_rate);
3018 } else {
3019 tapan->dai[dai->id].rate = params_rate(params);
3020 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003021 break;
3022
3023 case SNDRV_PCM_STREAM_PLAYBACK:
3024 ret = tapan_set_interpolator_rate(dai, rx_fs_rate,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003025 compander_fs,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003026 params_rate(params));
3027 if (ret < 0) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003028 dev_err(codec->dev, "%s: set decimator rate failed %d\n",
3029 __func__, ret);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003030 return ret;
3031 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003032 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3033 switch (params_format(params)) {
3034 case SNDRV_PCM_FORMAT_S16_LE:
3035 snd_soc_update_bits(codec,
3036 TAPAN_A_CDC_CLK_I2S_CTL,
3037 0x20, 0x20);
3038 break;
3039 case SNDRV_PCM_FORMAT_S32_LE:
3040 snd_soc_update_bits(codec,
3041 TAPAN_A_CDC_CLK_I2S_CTL,
3042 0x20, 0x00);
3043 break;
3044 default:
3045 dev_err(codec->dev, "invalid format\n");
3046 break;
3047 }
3048 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
3049 0x03, (rx_fs_rate >> 0x05));
3050 } else {
3051 switch (params_format(params)) {
3052 case SNDRV_PCM_FORMAT_S16_LE:
3053 snd_soc_update_bits(codec,
3054 TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
3055 0xFF, 0xAA);
3056 snd_soc_update_bits(codec,
3057 TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
3058 0xFF, 0x2A);
3059 tapan->dai[dai->id].bit_width = 16;
3060 break;
3061 case SNDRV_PCM_FORMAT_S24_LE:
3062 snd_soc_update_bits(codec,
3063 TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
3064 0xFF, 0x00);
3065 snd_soc_update_bits(codec,
3066 TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
3067 0xFF, 0x00);
3068 tapan->dai[dai->id].bit_width = 24;
3069 break;
3070 default:
3071 dev_err(codec->dev, "Invalid format\n");
3072 break;
3073 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003074 tapan->dai[dai->id].rate = params_rate(params);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003075 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003076 break;
3077 default:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003078 dev_err(codec->dev, "%s: Invalid stream type %d\n", __func__,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003079 substream->stream);
3080 return -EINVAL;
3081 }
3082
3083 return 0;
3084}
3085
3086static struct snd_soc_dai_ops tapan_dai_ops = {
3087 .startup = tapan_startup,
3088 .shutdown = tapan_shutdown,
3089 .hw_params = tapan_hw_params,
3090 .set_sysclk = tapan_set_dai_sysclk,
3091 .set_fmt = tapan_set_dai_fmt,
3092 .set_channel_map = tapan_set_channel_map,
3093 .get_channel_map = tapan_get_channel_map,
3094};
3095
3096static struct snd_soc_dai_driver tapan_dai[] = {
3097 {
3098 .name = "tapan_rx1",
3099 .id = AIF1_PB,
3100 .playback = {
3101 .stream_name = "AIF1 Playback",
3102 .rates = WCD9306_RATES,
3103 .formats = TAPAN_FORMATS,
3104 .rate_max = 192000,
3105 .rate_min = 8000,
3106 .channels_min = 1,
3107 .channels_max = 2,
3108 },
3109 .ops = &tapan_dai_ops,
3110 },
3111 {
3112 .name = "tapan_tx1",
3113 .id = AIF1_CAP,
3114 .capture = {
3115 .stream_name = "AIF1 Capture",
3116 .rates = WCD9306_RATES,
3117 .formats = TAPAN_FORMATS,
3118 .rate_max = 192000,
3119 .rate_min = 8000,
3120 .channels_min = 1,
3121 .channels_max = 4,
3122 },
3123 .ops = &tapan_dai_ops,
3124 },
3125 {
3126 .name = "tapan_rx2",
3127 .id = AIF2_PB,
3128 .playback = {
3129 .stream_name = "AIF2 Playback",
3130 .rates = WCD9306_RATES,
3131 .formats = TAPAN_FORMATS,
3132 .rate_min = 8000,
3133 .rate_max = 192000,
3134 .channels_min = 1,
3135 .channels_max = 2,
3136 },
3137 .ops = &tapan_dai_ops,
3138 },
3139 {
3140 .name = "tapan_tx2",
3141 .id = AIF2_CAP,
3142 .capture = {
3143 .stream_name = "AIF2 Capture",
3144 .rates = WCD9306_RATES,
3145 .formats = TAPAN_FORMATS,
3146 .rate_max = 192000,
3147 .rate_min = 8000,
3148 .channels_min = 1,
3149 .channels_max = 4,
3150 },
3151 .ops = &tapan_dai_ops,
3152 },
3153 {
3154 .name = "tapan_tx3",
3155 .id = AIF3_CAP,
3156 .capture = {
3157 .stream_name = "AIF3 Capture",
3158 .rates = WCD9306_RATES,
3159 .formats = TAPAN_FORMATS,
3160 .rate_max = 48000,
3161 .rate_min = 8000,
3162 .channels_min = 1,
3163 .channels_max = 2,
3164 },
3165 .ops = &tapan_dai_ops,
3166 },
3167 {
3168 .name = "tapan_rx3",
3169 .id = AIF3_PB,
3170 .playback = {
3171 .stream_name = "AIF3 Playback",
3172 .rates = WCD9306_RATES,
3173 .formats = TAPAN_FORMATS,
3174 .rate_min = 8000,
3175 .rate_max = 192000,
3176 .channels_min = 1,
3177 .channels_max = 2,
3178 },
3179 .ops = &tapan_dai_ops,
3180 },
3181};
3182
3183static struct snd_soc_dai_driver tapan_i2s_dai[] = {
3184 {
3185 .name = "tapan_i2s_rx1",
3186 .id = AIF1_PB,
3187 .playback = {
3188 .stream_name = "AIF1 Playback",
3189 .rates = WCD9306_RATES,
3190 .formats = TAPAN_FORMATS,
3191 .rate_max = 192000,
3192 .rate_min = 8000,
3193 .channels_min = 1,
3194 .channels_max = 4,
3195 },
3196 .ops = &tapan_dai_ops,
3197 },
3198 {
3199 .name = "tapan_i2s_tx1",
3200 .id = AIF1_CAP,
3201 .capture = {
3202 .stream_name = "AIF1 Capture",
3203 .rates = WCD9306_RATES,
3204 .formats = TAPAN_FORMATS,
3205 .rate_max = 192000,
3206 .rate_min = 8000,
3207 .channels_min = 1,
3208 .channels_max = 4,
3209 },
3210 .ops = &tapan_dai_ops,
3211 },
3212};
3213
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003214static int tapan_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai,
3215 bool up)
3216{
3217 int ret = 0;
3218 struct wcd9xxx_ch *ch;
3219
3220 if (up) {
3221 list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
3222 ret = wcd9xxx_get_slave_port(ch->ch_num);
3223 if (ret < 0) {
3224 pr_debug("%s: Invalid slave port ID: %d\n",
3225 __func__, ret);
3226 ret = -EINVAL;
3227 } else {
3228 set_bit(ret, &dai->ch_mask);
3229 }
3230 }
3231 } else {
3232 ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
3233 msecs_to_jiffies(
3234 TAPAN_SLIM_CLOSE_TIMEOUT));
3235 if (!ret) {
3236 pr_debug("%s: Slim close tx/rx wait timeout\n",
3237 __func__);
3238 ret = -ETIMEDOUT;
3239 } else {
3240 ret = 0;
3241 }
3242 }
3243 return ret;
3244}
3245
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003246static int tapan_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3247 struct snd_kcontrol *kcontrol,
3248 int event)
3249{
3250 struct wcd9xxx *core;
3251 struct snd_soc_codec *codec = w->codec;
3252 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003253 int ret = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003254 struct wcd9xxx_codec_dai_data *dai;
3255
3256 core = dev_get_drvdata(codec->dev->parent);
3257
3258 dev_dbg(codec->dev, "%s: event called! codec name %s\n",
3259 __func__, w->codec->name);
3260 dev_dbg(codec->dev, "%s: num_dai %d stream name %s event %d\n",
3261 __func__, w->codec->num_dai, w->sname, event);
3262
3263 /* Execute the callback only if interface type is slimbus */
3264 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3265 return 0;
3266
3267 dai = &tapan_p->dai[w->shift];
3268 dev_dbg(codec->dev, "%s: w->name %s w->shift %d event %d\n",
3269 __func__, w->name, w->shift, event);
3270
3271 switch (event) {
3272 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003273 (void) tapan_codec_enable_slim_chmask(dai, true);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003274 ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3275 dai->rate, dai->bit_width,
3276 &dai->grph);
3277 break;
3278 case SND_SOC_DAPM_POST_PMD:
3279 ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3280 dai->grph);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003281 ret = tapan_codec_enable_slim_chmask(dai, false);
3282 if (ret < 0) {
3283 ret = wcd9xxx_disconnect_port(core,
3284 &dai->wcd9xxx_ch_list,
3285 dai->grph);
3286 dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
3287 __func__, ret);
3288 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003289 break;
3290 }
3291 return ret;
3292}
3293
3294static int tapan_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3295 struct snd_kcontrol *kcontrol,
3296 int event)
3297{
3298 struct wcd9xxx *core;
3299 struct snd_soc_codec *codec = w->codec;
3300 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
3301 u32 ret = 0;
3302 struct wcd9xxx_codec_dai_data *dai;
3303
3304 core = dev_get_drvdata(codec->dev->parent);
3305
3306 dev_dbg(codec->dev, "%s: event called! codec name %s\n",
3307 __func__, w->codec->name);
3308 dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
3309 __func__, w->codec->num_dai, w->sname);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003310 /* Execute the callback only if interface type is slimbus */
3311 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3312 return 0;
3313
3314 dev_dbg(codec->dev, "%s(): w->name %s event %d w->shift %d\n",
3315 __func__, w->name, event, w->shift);
3316
3317 dai = &tapan_p->dai[w->shift];
3318 switch (event) {
3319 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003320 (void) tapan_codec_enable_slim_chmask(dai, true);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003321 ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3322 dai->rate, dai->bit_width,
3323 &dai->grph);
3324 break;
3325 case SND_SOC_DAPM_POST_PMD:
3326 ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3327 dai->grph);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003328 ret = tapan_codec_enable_slim_chmask(dai, false);
3329 if (ret < 0) {
3330 ret = wcd9xxx_disconnect_port(core,
3331 &dai->wcd9xxx_ch_list,
3332 dai->grph);
3333 dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
3334 __func__, ret);
3335 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003336 break;
3337 }
3338 return ret;
3339}
3340
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003341
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003342static int tapan_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
3343 struct snd_kcontrol *kcontrol, int event)
3344{
3345 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003346 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003347
3348 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
3349
3350 switch (event) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003351 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003352 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3353 WCD9XXX_CLSH_STATE_EAR,
3354 WCD9XXX_CLSH_REQ_ENABLE,
3355 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003356
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003357 usleep_range(5000, 5010);
3358 break;
3359 case SND_SOC_DAPM_POST_PMD:
3360 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3361 WCD9XXX_CLSH_STATE_EAR,
3362 WCD9XXX_CLSH_REQ_DISABLE,
3363 WCD9XXX_CLSH_EVENT_POST_PA);
3364 usleep_range(5000, 5010);
3365 }
3366 return 0;
3367}
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003368
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003369static int tapan_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
3370 struct snd_kcontrol *kcontrol, int event)
3371{
3372 struct snd_soc_codec *codec = w->codec;
3373 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
3374
3375 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
3376
3377 switch (event) {
3378 case SND_SOC_DAPM_PRE_PMU:
3379 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3380 WCD9XXX_CLSH_STATE_EAR,
3381 WCD9XXX_CLSH_REQ_ENABLE,
3382 WCD9XXX_CLSH_EVENT_PRE_DAC);
3383 break;
3384 }
3385
3386 return 0;
3387}
3388
3389static int tapan_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
3390 struct snd_kcontrol *kcontrol, int event)
3391{
3392 struct snd_soc_codec *codec = w->codec;
3393 u8 reg_val, zoh_mux_val = 0x00;
3394
3395 dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
3396
3397 switch (event) {
3398 case SND_SOC_DAPM_POST_PMU:
3399 reg_val = snd_soc_read(codec, TAPAN_A_CDC_CONN_CLSH_CTL);
3400
3401 if ((reg_val & 0x30) == 0x10)
3402 zoh_mux_val = 0x04;
3403 else if ((reg_val & 0x30) == 0x20)
3404 zoh_mux_val = 0x08;
3405
3406 if (zoh_mux_val != 0x00)
3407 snd_soc_update_bits(codec,
3408 TAPAN_A_CDC_CONN_CLSH_CTL,
3409 0x0C, zoh_mux_val);
3410 break;
3411
3412 case SND_SOC_DAPM_POST_PMD:
3413 snd_soc_update_bits(codec, TAPAN_A_CDC_CONN_CLSH_CTL,
3414 0x0C, 0x00);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003415 break;
3416 }
3417 return 0;
3418}
3419
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003420
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003421/* Todo: Have seperate dapm widgets for I2S and Slimbus.
3422 * Might Need to have callbacks registered only for slimbus
3423 */
3424static const struct snd_soc_dapm_widget tapan_dapm_widgets[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003425
3426 SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
3427 AIF1_PB, 0, tapan_codec_enable_slimrx,
3428 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3429 SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
3430 AIF2_PB, 0, tapan_codec_enable_slimrx,
3431 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3432 SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
3433 AIF3_PB, 0, tapan_codec_enable_slimrx,
3434 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3435
3436 SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TAPAN_RX1, 0,
3437 &slim_rx_mux[TAPAN_RX1]),
3438 SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TAPAN_RX2, 0,
3439 &slim_rx_mux[TAPAN_RX2]),
3440 SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TAPAN_RX3, 0,
3441 &slim_rx_mux[TAPAN_RX3]),
3442 SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TAPAN_RX4, 0,
3443 &slim_rx_mux[TAPAN_RX4]),
3444 SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TAPAN_RX5, 0,
3445 &slim_rx_mux[TAPAN_RX5]),
3446
3447 SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
3448 SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
3449 SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
3450 SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
3451 SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
3452
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003453
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003454 /* RX1 MIX1 mux inputs */
3455 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3456 &rx_mix1_inp1_mux),
3457 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3458 &rx_mix1_inp2_mux),
3459 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
3460 &rx_mix1_inp3_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003461
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003462 /* RX2 MIX1 mux inputs */
3463 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3464 &rx2_mix1_inp1_mux),
3465 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3466 &rx2_mix1_inp2_mux),
3467 SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
3468 &rx2_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003469
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003470 /* RX3 MIX1 mux inputs */
3471 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3472 &rx3_mix1_inp1_mux),
3473 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3474 &rx3_mix1_inp2_mux),
3475 SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
3476 &rx3_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003477
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003478 /* RX4 MIX1 mux inputs */
3479 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
3480 &rx4_mix1_inp1_mux),
3481 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
3482 &rx4_mix1_inp2_mux),
3483 SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
3484 &rx4_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003485
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003486 /* RX1 MIX2 mux inputs */
3487 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
3488 &rx1_mix2_inp1_mux),
3489 SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
3490 &rx1_mix2_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003491
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003492 /* RX2 MIX2 mux inputs */
3493 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
3494 &rx2_mix2_inp1_mux),
3495 SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
3496 &rx2_mix2_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003497
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003498 /* RX4 MIX2 mux inputs */
3499 SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
3500 &rx4_mix2_inp1_mux),
3501 SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
3502 &rx4_mix2_inp2_mux),
3503
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003504
3505 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
3506 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003507 SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003508
3509 SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
3510 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
3511 SND_SOC_DAPM_POST_PMU),
3512 SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
3513 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
3514 SND_SOC_DAPM_POST_PMU),
3515 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
3516 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
3517 SND_SOC_DAPM_POST_PMU),
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003518 SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003519 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
3520 SND_SOC_DAPM_POST_PMU),
3521
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003522 SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
3523 NULL, 0),
3524 SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0,
3525 NULL, 0),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003526
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003527 SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
3528 &class_h_dsm_mux, tapan_codec_dsm_mux_event,
3529 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003530
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003531 /* RX Bias */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003532 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
3533 tapan_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
3534 SND_SOC_DAPM_POST_PMD),
3535
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003536 /*EAR */
3537 SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
3538 tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
3539 SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003540
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003541 SND_SOC_DAPM_MIXER_E("DAC1", TAPAN_A_RX_EAR_EN, 6, 0, dac1_switch,
3542 ARRAY_SIZE(dac1_switch), tapan_codec_ear_dac_event,
3543 SND_SOC_DAPM_PRE_PMU),
3544
3545 /* Headphone Left */
3546 SND_SOC_DAPM_PGA_E("HPHL", TAPAN_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
3547 tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3548 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3549
3550 SND_SOC_DAPM_MIXER_E("HPHL DAC", TAPAN_A_RX_HPH_L_DAC_CTL, 7, 0,
3551 hphl_switch, ARRAY_SIZE(hphl_switch), tapan_hphl_dac_event,
3552 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3553
3554 /* Headphone Right */
3555 SND_SOC_DAPM_PGA_E("HPHR", TAPAN_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
3556 tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
3557 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3558
3559 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAPAN_A_RX_HPH_R_DAC_CTL, 7, 0,
3560 tapan_hphr_dac_event,
3561 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3562
3563 /* LINEOUT1*/
3564 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TAPAN_A_RX_LINE_1_DAC_CTL, 7, 0
3565 , tapan_lineout_dac_event,
3566 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3567
3568 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TAPAN_A_RX_LINE_CNP_EN, 0, 0, NULL,
3569 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3570 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3571
3572 /* LINEOUT2*/
3573 SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
3574 &rx_dac5_mux),
3575
3576 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
3577 , tapan_lineout_dac_event,
3578 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3579
3580 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TAPAN_A_RX_LINE_CNP_EN, 1, 0, NULL,
3581 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
3582 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3583
3584 /* CLASS-D SPK */
3585 SND_SOC_DAPM_MIXER_E("SPK DAC", SND_SOC_NOPM, 0, 0,
3586 spk_dac_switch, ARRAY_SIZE(spk_dac_switch), tapan_spk_dac_event,
3587 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3588
3589 SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0 , NULL,
3590 0, tapan_codec_enable_spk_pa,
3591 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3592
3593 SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
3594 tapan_codec_enable_vdd_spkr,
3595 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
3596
3597 SND_SOC_DAPM_OUTPUT("EAR"),
3598 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
3599 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
3600 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
3601 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
3602
3603 /* TX Path*/
3604 SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
3605 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
3606
3607 SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
3608 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
3609
3610 SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
3611 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
3612
3613 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TAPAN_TX1, 0,
3614 &sb_tx1_mux),
3615 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TAPAN_TX2, 0,
3616 &sb_tx2_mux),
3617 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TAPAN_TX3, 0,
3618 &sb_tx3_mux),
3619 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TAPAN_TX4, 0,
3620 &sb_tx4_mux),
3621 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TAPAN_TX5, 0,
3622 &sb_tx5_mux),
3623
3624 SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003625 0),
3626
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003627 /* Decimator MUX */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003628 SND_SOC_DAPM_MUX_E("DEC1 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
3629 &dec1_mux, tapan_codec_enable_dec,
3630 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3631 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
3632
3633 SND_SOC_DAPM_MUX_E("DEC2 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
3634 &dec2_mux, tapan_codec_enable_dec,
3635 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3636 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
3637
3638 SND_SOC_DAPM_MUX_E("DEC3 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
3639 &dec3_mux, tapan_codec_enable_dec,
3640 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3641 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
3642
3643 SND_SOC_DAPM_MUX_E("DEC4 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
3644 &dec4_mux, tapan_codec_enable_dec,
3645 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
3646 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
3647
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003648 SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
3649 tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
3650
3651 SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
3652 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
3653 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3654 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
3655 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
3656 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3657 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
3658 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
3659 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_POST_PMD),
3660
3661 SND_SOC_DAPM_INPUT("AMIC1"),
3662 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
3663 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3664 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3665 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAPAN_A_MICB_1_CTL, 7, 0,
3666 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3667 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3668 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAPAN_A_MICB_1_CTL, 7, 0,
3669 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3670 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3671
3672 SND_SOC_DAPM_ADC_E("ADC1", NULL, TAPAN_A_TX_1_EN, 7, 0,
3673 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3674 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3675 SND_SOC_DAPM_ADC_E("ADC2", NULL, TAPAN_A_TX_2_EN, 7, 0,
3676 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3677 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3678
3679 SND_SOC_DAPM_INPUT("AMIC3"),
3680 SND_SOC_DAPM_ADC_E("ADC3", NULL, TAPAN_A_TX_3_EN, 7, 0,
3681 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3682 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3683
3684 SND_SOC_DAPM_INPUT("AMIC4"),
3685 SND_SOC_DAPM_ADC_E("ADC4", NULL, TAPAN_A_TX_4_EN, 7, 0,
3686 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
3687 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3688
3689 SND_SOC_DAPM_INPUT("AMIC5"),
3690 SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
3691 tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
3692
3693 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
3694 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
3695
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003696 SND_SOC_DAPM_MIXER_E("ANC", SND_SOC_NOPM, 0, 0, NULL, 0,
3697 tapan_codec_enable_anc, SND_SOC_DAPM_PRE_PMU |
3698 SND_SOC_DAPM_POST_PMD),
3699
3700 SND_SOC_DAPM_INPUT("AMIC2"),
3701 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAPAN_A_MICB_2_CTL, 7, 0,
3702 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3703 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3704 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TAPAN_A_MICB_2_CTL, 7, 0,
3705 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3706 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3707 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TAPAN_A_MICB_2_CTL, 7, 0,
3708 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3709 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3710 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAPAN_A_MICB_2_CTL, 7, 0,
3711 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3712 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3713 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAPAN_A_MICB_3_CTL, 7, 0,
3714 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3715 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3716 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAPAN_A_MICB_3_CTL, 7, 0,
3717 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3718 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3719 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAPAN_A_MICB_3_CTL, 7, 0,
3720 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
3721 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3722
3723 SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
3724 AIF1_CAP, 0, tapan_codec_enable_slimtx,
3725 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3726
3727 SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
3728 AIF2_CAP, 0, tapan_codec_enable_slimtx,
3729 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3730
3731 SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
3732 AIF3_CAP, 0, tapan_codec_enable_slimtx,
3733 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
3734
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003735 /* Digital Mic Inputs */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003736 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
3737 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3738 SND_SOC_DAPM_POST_PMD),
3739
3740 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
3741 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3742 SND_SOC_DAPM_POST_PMD),
3743
3744 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
3745 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3746 SND_SOC_DAPM_POST_PMD),
3747
3748 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
3749 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
3750 SND_SOC_DAPM_POST_PMD),
3751
3752 /* Sidetone */
3753 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
3754 SND_SOC_DAPM_PGA("IIR1", TAPAN_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
3755
3756 /* AUX PGA */
3757 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TAPAN_A_RX_AUX_SW_CTL, 7, 0,
3758 tapan_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3759 SND_SOC_DAPM_POST_PMD),
3760
3761 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TAPAN_A_RX_AUX_SW_CTL, 6, 0,
3762 tapan_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
3763 SND_SOC_DAPM_POST_PMD),
3764
3765 /* Lineout, ear and HPH PA Mixers */
3766
3767 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
3768 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
3769
3770 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
3771 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
3772
3773 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
3774 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
3775
3776 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
3777 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
3778
3779 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
3780 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003781};
3782
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003783static irqreturn_t tapan_slimbus_irq(int irq, void *data)
3784{
3785 struct tapan_priv *priv = data;
3786 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003787 unsigned long status = 0;
3788 int i, j, port_id, k;
3789 u32 bit;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003790 u8 val;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003791 bool tx, cleared;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003792
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003793 for (i = TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
3794 i <= TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
3795 val = wcd9xxx_interface_reg_read(codec->control_data, i);
3796 status |= ((u32)val << (8 * j));
3797 }
3798
3799 for_each_set_bit(j, &status, 32) {
3800 tx = (j >= 16 ? true : false);
3801 port_id = (tx ? j - 16 : j);
3802 val = wcd9xxx_interface_reg_read(codec->control_data,
3803 TAPAN_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
3804 if (val & TAPAN_SLIM_IRQ_OVERFLOW)
3805 pr_err_ratelimited(
3806 "%s: overflow error on %s port %d, value %x\n",
3807 __func__, (tx ? "TX" : "RX"), port_id, val);
3808 if (val & TAPAN_SLIM_IRQ_UNDERFLOW)
3809 pr_err_ratelimited(
3810 "%s: underflow error on %s port %d, value %x\n",
3811 __func__, (tx ? "TX" : "RX"), port_id, val);
3812 if (val & TAPAN_SLIM_IRQ_PORT_CLOSED) {
3813 /*
3814 * INT SOURCE register starts from RX to TX
3815 * but port number in the ch_mask is in opposite way
3816 */
3817 bit = (tx ? j - 16 : j + 16);
3818 dev_dbg(codec->dev, "%s: %s port %d closed value %x, bit %u\n",
3819 __func__, (tx ? "TX" : "RX"), port_id, val,
3820 bit);
3821 for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
3822 dev_dbg(codec->dev, "%s: priv->dai[%d].ch_mask = 0x%lx\n",
3823 __func__, k, priv->dai[k].ch_mask);
3824 if (test_and_clear_bit(bit,
3825 &priv->dai[k].ch_mask)) {
3826 cleared = true;
3827 if (!priv->dai[k].ch_mask)
3828 wake_up(&priv->dai[k].dai_wait);
3829 /*
3830 * There are cases when multiple DAIs
3831 * might be using the same slimbus
3832 * channel. Hence don't break here.
3833 */
3834 }
3835 }
3836 WARN(!cleared,
3837 "Couldn't find slimbus %s port %d for closing\n",
3838 (tx ? "TX" : "RX"), port_id);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003839 }
3840 wcd9xxx_interface_reg_write(codec->control_data,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003841 TAPAN_SLIM_PGD_PORT_INT_CLR_RX_0 +
3842 (j / 8),
3843 1 << (j % 8));
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003844 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003845
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003846 return IRQ_HANDLED;
3847}
3848
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003849static int tapan_handle_pdata(struct tapan_priv *tapan)
3850{
3851 struct snd_soc_codec *codec = tapan->codec;
3852 struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
3853 int k1, k2, k3, rc = 0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003854 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
3855 u8 txfe_buff = pdata->amic_settings.txfe_buff;
3856 u8 flag = pdata->amic_settings.use_pdata;
3857 u8 i = 0, j = 0;
3858 u8 val_txfe = 0, value = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003859
3860 if (!pdata) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003861 dev_err(codec->dev, "%s: NULL pdata\n", __func__);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003862 rc = -ENODEV;
3863 goto done;
3864 }
3865
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003866 /* Make sure settings are correct */
3867 if ((pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V) ||
3868 (pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
3869 (pdata->micbias.bias2_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
3870 (pdata->micbias.bias3_cfilt_sel > WCD9XXX_CFILT3_SEL)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003871 dev_err(codec->dev, "%s: Invalid ldoh voltage or bias cfilt\n",
3872 __func__);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003873 rc = -EINVAL;
3874 goto done;
3875 }
3876 /* figure out k value */
3877 k1 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt1_mv);
3878 k2 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt2_mv);
3879 k3 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt3_mv);
3880
3881 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003882 dev_err(codec->dev,
3883 "%s: could not get K value. k1 = %d k2 = %d k3 = %d\n",
3884 __func__, k1, k2, k3);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003885 rc = -EINVAL;
3886 goto done;
3887 }
3888 /* Set voltage level and always use LDO */
3889 snd_soc_update_bits(codec, TAPAN_A_LDO_H_MODE_1, 0x0C,
3890 (pdata->micbias.ldoh_v << 2));
3891
3892 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_1_VAL, 0xFC, (k1 << 2));
3893 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_2_VAL, 0xFC, (k2 << 2));
3894 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_3_VAL, 0xFC, (k3 << 2));
3895
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003896 i = 0;
3897 while (i < 5) {
3898 if (flag & (0x01 << i)) {
3899 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
3900 val_txfe = val_txfe |
3901 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
3902 snd_soc_update_bits(codec,
3903 TAPAN_A_TX_1_2_TEST_EN + j * 10,
3904 0x30, val_txfe);
3905 }
3906 if (flag & (0x01 << (i + 1))) {
3907 val_txfe = (txfe_bypass &
3908 (0x01 << (i + 1))) ? 0x02 : 0x00;
3909 val_txfe |= (txfe_buff &
3910 (0x01 << (i + 1))) ? 0x01 : 0x00;
3911 snd_soc_update_bits(codec,
3912 TAPAN_A_TX_1_2_TEST_EN + j * 10,
3913 0x03, val_txfe);
3914 }
3915 /* Tapan only has TAPAN_A_TX_1_2_TEST_EN and
3916 TAPAN_A_TX_4_5_TEST_EN reg */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003917
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003918 if (i == 0) {
3919 i = 3;
3920 continue;
3921 } else if (i == 3) {
3922 break;
3923 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003924 }
3925
3926 if (pdata->ocp.use_pdata) {
3927 /* not defined in CODEC specification */
3928 if (pdata->ocp.hph_ocp_limit == 1 ||
3929 pdata->ocp.hph_ocp_limit == 5) {
3930 rc = -EINVAL;
3931 goto done;
3932 }
3933 snd_soc_update_bits(codec, TAPAN_A_RX_COM_OCP_CTL,
3934 0x0F, pdata->ocp.num_attempts);
3935 snd_soc_write(codec, TAPAN_A_RX_COM_OCP_COUNT,
3936 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
3937 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_OCP_CTL,
3938 0xE0, (pdata->ocp.hph_ocp_limit << 5));
3939 }
3940
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003941 /* Set micbias capless mode with tail current */
3942 value = (pdata->micbias.bias1_cap_mode == MICBIAS_EXT_BYP_CAP ?
3943 0x00 : 0x10);
3944 snd_soc_update_bits(codec, TAPAN_A_MICB_1_CTL, 0x10, value);
3945 value = (pdata->micbias.bias2_cap_mode == MICBIAS_EXT_BYP_CAP ?
3946 0x00 : 0x10);
3947 snd_soc_update_bits(codec, TAPAN_A_MICB_2_CTL, 0x10, value);
3948 value = (pdata->micbias.bias3_cap_mode == MICBIAS_EXT_BYP_CAP ?
3949 0x00 : 0x10);
3950 snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x10, value);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003951
3952done:
3953 return rc;
3954}
3955
3956static const struct tapan_reg_mask_val tapan_reg_defaults[] = {
3957
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003958 /* enable QFUSE for wcd9306 */
3959 TAPAN_REG_VAL(TAPAN_A_QFUSE_CTL, 0x03),
3960
3961 /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
3962 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
3963
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003964 TAPAN_REG_VAL(TAPAN_A_CDC_CLK_POWER_CTL, 0x03),
3965
3966 /* EAR PA deafults */
3967 TAPAN_REG_VAL(TAPAN_A_RX_EAR_CMBUFF, 0x05),
3968
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003969 /* RX1 and RX2 defaults */
3970 TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B6_CTL, 0xA0),
3971 TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0xA0),
3972
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003973 /* Heaset set Right from RX2 */
3974 TAPAN_REG_VAL(TAPAN_A_CDC_CONN_RX2_B2_CTL, 0x10),
3975
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003976
3977 /*
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003978 * The following only need to be written for Tapan 1.0 parts.
3979 * Tapan 2.0 will have appropriate defaults for these registers.
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003980 */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003981
3982 /* Required defaults for class H operation */
3983 /* borrowed from Taiko class-h */
3984 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0xF4),
3985 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x08),
3986 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
3987 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x60),
3988
3989 /* TODO: Check below reg writes conflict with above */
3990 /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
3991 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
3992 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_4, 0x54),
3993 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0x74),
3994 TAPAN_REG_VAL(TAPAN_A_RX_BUCK_BIAS1, 0x62),
3995
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003996 /* Choose max non-overlap time for NCP */
3997 TAPAN_REG_VAL(TAPAN_A_NCP_CLK, 0xFC),
3998 /* Use 25mV/50mV for deltap/m to reduce ripple */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003999 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004000 /*
4001 * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
4002 * Note that the other bits of this register will be changed during
4003 * Rx PA bring up.
4004 */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004005 TAPAN_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004006 /* Reduce HPH DAC bias to 70% */
4007 TAPAN_REG_VAL(TAPAN_A_RX_HPH_BIAS_PA, 0x7A),
4008 /*Reduce EAR DAC bias to 70% */
4009 TAPAN_REG_VAL(TAPAN_A_RX_EAR_BIAS_PA, 0x76),
4010 /* Reduce LINE DAC bias to 70% */
4011 TAPAN_REG_VAL(TAPAN_A_RX_LINE_BIAS_PA, 0x78),
4012
4013 /*
4014 * There is a diode to pull down the micbias while doing
4015 * insertion detection. This diode can cause leakage.
4016 * Set bit 0 to 1 to prevent leakage.
4017 * Setting this bit of micbias 2 prevents leakage for all other micbias.
4018 */
4019 TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
4020
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004021 /* not needed if MBHC is not needed */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004022 /* Disable TX7 internal biasing path which can cause leakage */
4023 TAPAN_REG_VAL(TAPAN_A_TX_SUP_SWITCH_CTRL_1, 0xBF),
4024};
4025
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004026static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
4027
4028 TAPAN_REG_VAL(TAPAN_A_TX_7_MBHC_EN, 0x6C),
4029 TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_4, 0x51),
4030 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CNP_WG_CTL, 0xDA),
4031 TAPAN_REG_VAL(TAPAN_A_RX_EAR_CNP, 0xC0),
4032 TAPAN_REG_VAL(TAPAN_A_RX_LINE_1_TEST, 0x02),
4033 TAPAN_REG_VAL(TAPAN_A_RX_LINE_2_TEST, 0x02),
4034 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_OCP_CTL, 0x97),
4035 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_CLIP_DET, 0x01),
4036 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_IEC, 0x00),
4037 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B1_CTL, 0xE4),
4038 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x00),
4039 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x00),
4040 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
4041 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_EAR, 0x00),
4042 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_HPH, 0x00),
4043 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_EAR, 0x00),
4044 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_HPH, 0x00),
4045};
4046
4047static const struct tapan_reg_mask_val tapan_1_0_reg_defaults[] = {
4048 /* Close leakage on the spkdrv */
4049 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_PWRSTG, 0x24),
4050 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_DAC, 0xE5),
4051
4052};
4053
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004054static void tapan_update_reg_defaults(struct snd_soc_codec *codec)
4055{
4056 u32 i;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004057 struct wcd9xxx *tapan_core = dev_get_drvdata(codec->dev->parent);
4058
4059 if (!TAPAN_IS_1_0(tapan_core->version)) {
4060 for (i = 0; i < ARRAY_SIZE(tapan_2_x_reg_reset_values); i++)
4061 snd_soc_write(codec, tapan_2_x_reg_reset_values[i].reg,
4062 tapan_2_x_reg_reset_values[i].val);
4063 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004064
4065 for (i = 0; i < ARRAY_SIZE(tapan_reg_defaults); i++)
4066 snd_soc_write(codec, tapan_reg_defaults[i].reg,
4067 tapan_reg_defaults[i].val);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004068
4069 if (TAPAN_IS_1_0(tapan_core->version)) {
4070 for (i = 0; i < ARRAY_SIZE(tapan_1_0_reg_defaults); i++)
4071 snd_soc_write(codec, tapan_1_0_reg_defaults[i].reg,
4072 tapan_1_0_reg_defaults[i].val);
4073 }
4074
4075 if (!TAPAN_IS_1_0(tapan_core->version))
4076 spkr_drv_wrnd = -1;
4077 else if (spkr_drv_wrnd == 1)
4078 snd_soc_write(codec, TAPAN_A_SPKR_DRV_EN, 0xEF);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004079}
4080
4081static const struct tapan_reg_mask_val tapan_codec_reg_init_val[] = {
4082 /* Initialize current threshold to 350MA
4083 * number of wait and run cycles to 4096
4084 */
4085 {TAPAN_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
4086 {TAPAN_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
4087
4088 /* Initialize gain registers to use register gain */
4089 {TAPAN_A_RX_HPH_L_GAIN, 0x20, 0x20},
4090 {TAPAN_A_RX_HPH_R_GAIN, 0x20, 0x20},
4091 {TAPAN_A_RX_LINE_1_GAIN, 0x20, 0x20},
4092 {TAPAN_A_RX_LINE_2_GAIN, 0x20, 0x20},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004093 {TAPAN_A_SPKR_DRV_GAIN, 0x04, 0x04},
4094
4095 /* Set RDAC5 MUX to take input from DEM3_INV.
4096 * This sets LO2 DAC to get input from DEM3_INV
4097 * for LO1 and LO2 to work as differential outputs.
4098 */
4099 {TAPAN_A_CDC_CONN_MISC, 0x04, 0x04},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004100
4101 /* CLASS H config */
4102 {TAPAN_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
4103
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004104 /* Use 16 bit sample size for TX1 to TX5 */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004105 {TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
4106 {TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4107 {TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4108 {TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4109 {TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
4110
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004111 /* Disable SPK SWITCH */
4112 {TAPAN_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
4113
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004114 /* Use 16 bit sample size for RX */
4115 {TAPAN_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4116 {TAPAN_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
4117
4118 /*enable HPF filter for TX paths */
4119 {TAPAN_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
4120 {TAPAN_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
4121 {TAPAN_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
4122 {TAPAN_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
4123
4124 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
4125 {TAPAN_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
4126 {TAPAN_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
4127 {TAPAN_A_CDC_TX3_DMIC_CTL, 0x7, 0x1},
4128 {TAPAN_A_CDC_TX4_DMIC_CTL, 0x7, 0x1},
4129
4130 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
4131 {TAPAN_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004132
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004133 /* Compander zone selection */
4134 {TAPAN_A_CDC_COMP0_B4_CTL, 0x3F, 0x37},
4135 {TAPAN_A_CDC_COMP1_B4_CTL, 0x3F, 0x37},
4136 {TAPAN_A_CDC_COMP2_B4_CTL, 0x3F, 0x37},
4137 {TAPAN_A_CDC_COMP0_B5_CTL, 0x7F, 0x7F},
4138 {TAPAN_A_CDC_COMP1_B5_CTL, 0x7F, 0x7F},
4139 {TAPAN_A_CDC_COMP2_B5_CTL, 0x7F, 0x7F},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004140};
4141
4142static void tapan_codec_init_reg(struct snd_soc_codec *codec)
4143{
4144 u32 i;
4145
4146 for (i = 0; i < ARRAY_SIZE(tapan_codec_reg_init_val); i++)
4147 snd_soc_update_bits(codec, tapan_codec_reg_init_val[i].reg,
4148 tapan_codec_reg_init_val[i].mask,
4149 tapan_codec_reg_init_val[i].val);
4150}
4151
4152static int tapan_setup_irqs(struct tapan_priv *tapan)
4153{
4154 int i;
4155 int ret = 0;
4156 struct snd_soc_codec *codec = tapan->codec;
4157
4158 ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
4159 tapan_slimbus_irq, "SLIMBUS Slave", tapan);
4160 if (ret) {
4161 pr_err("%s: Failed to request irq %d\n", __func__,
4162 WCD9XXX_IRQ_SLIMBUS);
4163 goto exit;
4164 }
4165
4166 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
4167 wcd9xxx_interface_reg_write(codec->control_data,
4168 TAPAN_SLIM_PGD_PORT_INT_EN0 + i,
4169 0xFF);
4170exit:
4171 return ret;
4172}
4173
4174int tapan_hs_detect(struct snd_soc_codec *codec,
4175 struct wcd9xxx_mbhc_config *mbhc_cfg)
4176{
4177 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
4178 return wcd9xxx_mbhc_start(&tapan->mbhc, mbhc_cfg);
4179}
4180EXPORT_SYMBOL_GPL(tapan_hs_detect);
4181
4182static struct wcd9xxx_reg_address tapan_reg_address = {
4183};
4184
4185static int tapan_codec_probe(struct snd_soc_codec *codec)
4186{
4187 struct wcd9xxx *control;
4188 struct tapan_priv *tapan;
4189 struct wcd9xxx_pdata *pdata;
4190 struct wcd9xxx *wcd9xxx;
4191 struct snd_soc_dapm_context *dapm = &codec->dapm;
4192 int ret = 0;
4193 int i;
4194 void *ptr = NULL;
4195
4196 codec->control_data = dev_get_drvdata(codec->dev->parent);
4197 control = codec->control_data;
4198
4199 dev_info(codec->dev, "%s()\n", __func__);
4200
4201 tapan = kzalloc(sizeof(struct tapan_priv), GFP_KERNEL);
4202 if (!tapan) {
4203 dev_err(codec->dev, "Failed to allocate private data\n");
4204 return -ENOMEM;
4205 }
4206 for (i = 0 ; i < NUM_DECIMATORS; i++) {
4207 tx_hpf_work[i].tapan = tapan;
4208 tx_hpf_work[i].decimator = i + 1;
4209 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
4210 tx_hpf_corner_freq_callback);
4211 }
4212
4213 snd_soc_codec_set_drvdata(codec, tapan);
4214
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004215 /* TODO: Read buck voltage from DT property */
4216 tapan->clsh_d.buck_mv = WCD9XXX_CDC_BUCK_MV_1P8;
4217 wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
4218
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004219 /* codec resmgr module init */
4220 wcd9xxx = codec->control_data;
4221 pdata = dev_get_platdata(codec->dev->parent);
4222 ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, wcd9xxx, pdata,
4223 &tapan_reg_address);
4224 if (ret) {
4225 pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004226 return ret;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004227 }
4228
Bhalchandra Gajare120bd402013-03-06 15:30:19 -08004229 /* TODO: wcd9xxx_mbhc_init to enable mbhc */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004230
4231 tapan->codec = codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004232 for (i = 0; i < COMPANDER_MAX; i++) {
4233 tapan->comp_enabled[i] = 0;
4234 tapan->comp_fs[i] = COMPANDER_FS_48KHZ;
4235 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004236 tapan->intf_type = wcd9xxx_get_intf_type();
4237 tapan->aux_pga_cnt = 0;
4238 tapan->aux_l_gain = 0x1F;
4239 tapan->aux_r_gain = 0x1F;
4240 tapan_update_reg_defaults(codec);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004241
4242 dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
4243 __func__, wcd9xxx->mclk_rate);
4244
4245 if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
4246 snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
4247 snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
4248 0x01);
4249 } else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6HZ) {
4250 snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
4251 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004252 tapan_codec_init_reg(codec);
4253 ret = tapan_handle_pdata(tapan);
4254 if (IS_ERR_VALUE(ret)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004255 dev_err(codec->dev, "%s: bad pdata\n", __func__);
4256 goto err_pdata;
4257 }
4258
4259 if (spkr_drv_wrnd > 0) {
4260 WCD9XXX_BCL_LOCK(&tapan->resmgr);
4261 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
4262 WCD9XXX_BANDGAP_AUDIO_MODE);
4263 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004264 }
4265
4266 ptr = kmalloc((sizeof(tapan_rx_chs) +
4267 sizeof(tapan_tx_chs)), GFP_KERNEL);
4268 if (!ptr) {
4269 pr_err("%s: no mem for slim chan ctl data\n", __func__);
4270 ret = -ENOMEM;
4271 goto err_nomem_slimch;
4272 }
4273
4274 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004275 snd_soc_dapm_new_controls(dapm, tapan_dapm_i2s_widgets,
4276 ARRAY_SIZE(tapan_dapm_i2s_widgets));
4277 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
4278 ARRAY_SIZE(audio_i2s_map));
4279 for (i = 0; i < ARRAY_SIZE(tapan_i2s_dai); i++)
4280 INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004281 } else if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
4282 for (i = 0; i < NUM_CODEC_DAIS; i++) {
4283 INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
4284 init_waitqueue_head(&tapan->dai[i].dai_wait);
4285 }
4286 }
4287
4288 control->num_rx_port = TAPAN_RX_MAX;
4289 control->rx_chs = ptr;
4290 memcpy(control->rx_chs, tapan_rx_chs, sizeof(tapan_rx_chs));
4291 control->num_tx_port = TAPAN_TX_MAX;
4292 control->tx_chs = ptr + sizeof(tapan_rx_chs);
4293 memcpy(control->tx_chs, tapan_tx_chs, sizeof(tapan_tx_chs));
4294
4295 snd_soc_dapm_sync(dapm);
4296
4297 (void) tapan_setup_irqs(tapan);
4298
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004299 atomic_set(&kp_tapan_priv, (unsigned long)tapan);
4300
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004301 codec->ignore_pmdown_time = 1;
4302 return ret;
4303
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004304err_pdata:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004305 kfree(ptr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004306err_nomem_slimch:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004307 kfree(tapan);
4308 return ret;
4309}
4310
4311static int tapan_codec_remove(struct snd_soc_codec *codec)
4312{
4313 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
4314
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004315 WCD9XXX_BCL_LOCK(&tapan->resmgr);
4316 atomic_set(&kp_tapan_priv, 0);
4317
4318 if (spkr_drv_wrnd > 0)
4319 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
4320 WCD9XXX_BANDGAP_AUDIO_MODE);
4321 WCD9XXX_BCL_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004322 /* cleanup MBHC */
4323 wcd9xxx_mbhc_deinit(&tapan->mbhc);
4324 /* cleanup resmgr */
4325 wcd9xxx_resmgr_deinit(&tapan->resmgr);
4326
4327 kfree(tapan);
4328 return 0;
4329}
4330
4331static struct snd_soc_codec_driver soc_codec_dev_tapan = {
4332 .probe = tapan_codec_probe,
4333 .remove = tapan_codec_remove,
4334
4335 .read = tapan_read,
4336 .write = tapan_write,
4337
4338 .readable_register = tapan_readable,
4339 .volatile_register = tapan_volatile,
4340
4341 .reg_cache_size = TAPAN_CACHE_SIZE,
4342 .reg_cache_default = tapan_reset_reg_defaults,
4343 .reg_word_size = 1,
4344
4345 .controls = tapan_snd_controls,
4346 .num_controls = ARRAY_SIZE(tapan_snd_controls),
4347 .dapm_widgets = tapan_dapm_widgets,
4348 .num_dapm_widgets = ARRAY_SIZE(tapan_dapm_widgets),
4349 .dapm_routes = audio_map,
4350 .num_dapm_routes = ARRAY_SIZE(audio_map),
4351};
4352
4353#ifdef CONFIG_PM
4354static int tapan_suspend(struct device *dev)
4355{
4356 dev_dbg(dev, "%s: system suspend\n", __func__);
4357 return 0;
4358}
4359
4360static int tapan_resume(struct device *dev)
4361{
4362 struct platform_device *pdev = to_platform_device(dev);
4363 struct tapan_priv *tapan = platform_get_drvdata(pdev);
4364 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004365 /* Notify */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004366 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, WCD9XXX_EVENT_POST_RESUME);
4367 return 0;
4368}
4369
4370static const struct dev_pm_ops tapan_pm_ops = {
4371 .suspend = tapan_suspend,
4372 .resume = tapan_resume,
4373};
4374#endif
4375
4376static int __devinit tapan_probe(struct platform_device *pdev)
4377{
4378 int ret = 0;
4379 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
4380 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tapan,
4381 tapan_dai, ARRAY_SIZE(tapan_dai));
4382 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
4383 ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_tapan,
4384 tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
4385 return ret;
4386}
4387static int __devexit tapan_remove(struct platform_device *pdev)
4388{
4389 snd_soc_unregister_codec(&pdev->dev);
4390 return 0;
4391}
4392static struct platform_driver tapan_codec_driver = {
4393 .probe = tapan_probe,
4394 .remove = tapan_remove,
4395 .driver = {
4396 .name = "tapan_codec",
4397 .owner = THIS_MODULE,
4398#ifdef CONFIG_PM
4399 .pm = &tapan_pm_ops,
4400#endif
4401 },
4402};
4403
4404static int __init tapan_codec_init(void)
4405{
4406 return platform_driver_register(&tapan_codec_driver);
4407}
4408
4409static void __exit tapan_codec_exit(void)
4410{
4411 platform_driver_unregister(&tapan_codec_driver);
4412}
4413
4414module_init(tapan_codec_init);
4415module_exit(tapan_codec_exit);
4416
4417MODULE_DESCRIPTION("Tapan codec driver");
4418MODULE_LICENSE("GPL v2");