blob: 083310de2a2fdd9923f9839f45873e9a564c18a8 [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>
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -070027#include <linux/regulator/consumer.h>
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080028#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/soc.h>
31#include <sound/soc-dapm.h>
32#include <sound/tlv.h>
33#include <linux/bitops.h>
34#include <linux/delay.h>
35#include <linux/pm_runtime.h>
36#include <linux/kernel.h>
37#include <linux/gpio.h>
38#include "wcd9306.h"
39#include "wcd9xxx-resmgr.h"
Bhalchandra Gajareea898742013-03-05 18:15:53 -080040#include "wcd9xxx-common.h"
41
Banajit Goswamia7294452013-06-03 12:42:35 -070042#define TAPAN_HPH_PA_SETTLE_COMP_ON 3000
43#define TAPAN_HPH_PA_SETTLE_COMP_OFF 13000
44
Bhalchandra Gajare4e3dd852013-08-19 17:21:23 -070045#define TAPAN_VDD_CX_OPTIMAL_UA 10000
46#define TAPAN_VDD_CX_SLEEP_UA 2000
47
48static struct regulator *tapan_codec_find_regulator(
49 struct snd_soc_codec *codec,
50 const char *name);
51
Bhalchandra Gajareea898742013-03-05 18:15:53 -080052static atomic_t kp_tapan_priv;
53static int spkr_drv_wrnd_param_set(const char *val,
54 const struct kernel_param *kp);
55static int spkr_drv_wrnd = 1;
56
57static struct kernel_param_ops spkr_drv_wrnd_param_ops = {
58 .set = spkr_drv_wrnd_param_set,
59 .get = param_get_int,
60};
61module_param_cb(spkr_drv_wrnd, &spkr_drv_wrnd_param_ops, &spkr_drv_wrnd, 0644);
62MODULE_PARM_DESC(spkr_drv_wrnd,
63 "Run software workaround to avoid leakage on the speaker drive");
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080064
65#define WCD9306_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
66 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
67 SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
68
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -070069#define WCD9302_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
70 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
71
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080072#define NUM_DECIMATORS 4
73#define NUM_INTERPOLATORS 4
74#define BITS_PER_REG 8
Bhalchandra Gajareea898742013-03-05 18:15:53 -080075/* This actual number of TX ports supported in slimbus slave */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080076#define TAPAN_TX_PORT_NUMBER 16
Kuirong Wang80aca0d2013-05-09 14:51:09 -070077#define TAPAN_RX_PORT_START_NUMBER 16
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080078
Bhalchandra Gajareea898742013-03-05 18:15:53 -080079/* Nummer of TX ports actually connected from Slimbus slave to codec Digital */
80#define TAPAN_SLIM_CODEC_TX_PORTS 5
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080081
Bhalchandra Gajareea898742013-03-05 18:15:53 -080082#define TAPAN_I2S_MASTER_MODE_MASK 0x08
83#define TAPAN_MCLK_CLK_12P288MHZ 12288000
Phani Kumar Uppalapati43bc4152013-05-24 00:44:20 -070084#define TAPAN_MCLK_CLK_9P6MHZ 9600000
Bhalchandra Gajareea898742013-03-05 18:15:53 -080085
86#define TAPAN_SLIM_CLOSE_TIMEOUT 1000
87#define TAPAN_SLIM_IRQ_OVERFLOW (1 << 0)
88#define TAPAN_SLIM_IRQ_UNDERFLOW (1 << 1)
89#define TAPAN_SLIM_IRQ_PORT_CLOSED (1 << 2)
Simmi Pateriya95466b12013-05-09 20:08:46 +053090
91#define TAPAN_IRQ_MBHC_JACK_SWITCH 21
92
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -080093enum {
94 AIF1_PB = 0,
95 AIF1_CAP,
96 AIF2_PB,
97 AIF2_CAP,
98 AIF3_PB,
99 AIF3_CAP,
100 NUM_CODEC_DAIS,
101};
102
103enum {
104 RX_MIX1_INP_SEL_ZERO = 0,
105 RX_MIX1_INP_SEL_SRC1,
106 RX_MIX1_INP_SEL_SRC2,
107 RX_MIX1_INP_SEL_IIR1,
108 RX_MIX1_INP_SEL_IIR2,
109 RX_MIX1_INP_SEL_RX1,
110 RX_MIX1_INP_SEL_RX2,
111 RX_MIX1_INP_SEL_RX3,
112 RX_MIX1_INP_SEL_RX4,
113 RX_MIX1_INP_SEL_RX5,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800114 RX_MIX1_INP_SEL_AUXRX,
115};
116
117#define TAPAN_COMP_DIGITAL_GAIN_OFFSET 3
118
119static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
120static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
121static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
122static struct snd_soc_dai_driver tapan_dai[];
123static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
124
125/* Codec supports 2 IIR filters */
126enum {
127 IIR1 = 0,
128 IIR2,
129 IIR_MAX,
130};
131/* Codec supports 5 bands */
132enum {
133 BAND1 = 0,
134 BAND2,
135 BAND3,
136 BAND4,
137 BAND5,
138 BAND_MAX,
139};
140
141enum {
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800142 COMPANDER_0,
143 COMPANDER_1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800144 COMPANDER_2,
145 COMPANDER_MAX,
146};
147
148enum {
149 COMPANDER_FS_8KHZ = 0,
150 COMPANDER_FS_16KHZ,
151 COMPANDER_FS_32KHZ,
152 COMPANDER_FS_48KHZ,
153 COMPANDER_FS_96KHZ,
154 COMPANDER_FS_192KHZ,
155 COMPANDER_FS_MAX,
156};
157
158struct comp_sample_dependent_params {
159 u32 peak_det_timeout;
160 u32 rms_meter_div_fact;
161 u32 rms_meter_resamp_fact;
162};
163
164struct hpf_work {
165 struct tapan_priv *tapan;
166 u32 decimator;
167 u8 tx_hpf_cut_of_freq;
168 struct delayed_work dwork;
169};
170
171static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
172
173static const struct wcd9xxx_ch tapan_rx_chs[TAPAN_RX_MAX] = {
Kuirong Wang80aca0d2013-05-09 14:51:09 -0700174 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER, 0),
175 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 1, 1),
176 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 2, 2),
177 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 3, 3),
178 WCD9XXX_CH(TAPAN_RX_PORT_START_NUMBER + 4, 4),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800179};
180
181static const struct wcd9xxx_ch tapan_tx_chs[TAPAN_TX_MAX] = {
182 WCD9XXX_CH(0, 0),
183 WCD9XXX_CH(1, 1),
184 WCD9XXX_CH(2, 2),
185 WCD9XXX_CH(3, 3),
186 WCD9XXX_CH(4, 4),
187};
188
189static const u32 vport_check_table[NUM_CODEC_DAIS] = {
190 0, /* AIF1_PB */
191 (1 << AIF2_CAP) | (1 << AIF3_CAP), /* AIF1_CAP */
192 0, /* AIF2_PB */
193 (1 << AIF1_CAP) | (1 << AIF3_CAP), /* AIF2_CAP */
194 0, /* AIF2_PB */
195 (1 << AIF1_CAP) | (1 << AIF2_CAP), /* AIF2_CAP */
196};
197
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800198static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
199 0, /* AIF1_PB */
200 0, /* AIF1_CAP */
201};
202
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -0700203enum {
204 CP_REG_BUCK = 0,
205 CP_REG_BHELPER,
206 CP_REG_MAX,
207};
208
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800209struct tapan_priv {
210 struct snd_soc_codec *codec;
211 u32 adc_count;
212 u32 rx_bias_count;
213 s32 dmic_1_2_clk_cnt;
214 s32 dmic_3_4_clk_cnt;
215 s32 dmic_5_6_clk_cnt;
216
217 u32 anc_slot;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700218 bool anc_func;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800219
220 /*track tapan interface type*/
221 u8 intf_type;
222
223 /* num of slim ports required */
224 struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
225
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800226 /*compander*/
227 int comp_enabled[COMPANDER_MAX];
228 u32 comp_fs[COMPANDER_MAX];
229
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800230 /* Maintain the status of AUX PGA */
231 int aux_pga_cnt;
232 u8 aux_l_gain;
233 u8 aux_r_gain;
234
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800235 bool spkr_pa_widget_on;
236
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800237 /* resmgr module */
238 struct wcd9xxx_resmgr resmgr;
239 /* mbhc module */
240 struct wcd9xxx_mbhc mbhc;
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800241
242 /* class h specific data */
243 struct wcd9xxx_clsh_cdc_data clsh_d;
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -0700244
245 /* pointers to regulators required for chargepump */
246 struct regulator *cp_regulators[CP_REG_MAX];
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800247};
248
249static const u32 comp_shift[] = {
250 0,
Banajit Goswamia7294452013-06-03 12:42:35 -0700251 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800252 2,
253};
254
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800255static const int comp_rx_path[] = {
256 COMPANDER_1,
257 COMPANDER_1,
258 COMPANDER_2,
259 COMPANDER_2,
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800260 COMPANDER_MAX,
261};
262
263static const struct comp_sample_dependent_params comp_samp_params[] = {
264 {
265 /* 8 Khz */
Banajit Goswamia7294452013-06-03 12:42:35 -0700266 .peak_det_timeout = 0x06,
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800267 .rms_meter_div_fact = 0x09,
268 .rms_meter_resamp_fact = 0x06,
269 },
270 {
271 /* 16 Khz */
Banajit Goswamia7294452013-06-03 12:42:35 -0700272 .peak_det_timeout = 0x07,
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800273 .rms_meter_div_fact = 0x0A,
274 .rms_meter_resamp_fact = 0x0C,
275 },
276 {
277 /* 32 Khz */
Banajit Goswamia7294452013-06-03 12:42:35 -0700278 .peak_det_timeout = 0x08,
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800279 .rms_meter_div_fact = 0x0B,
280 .rms_meter_resamp_fact = 0x1E,
281 },
282 {
283 /* 48 Khz */
Banajit Goswamia7294452013-06-03 12:42:35 -0700284 .peak_det_timeout = 0x09,
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800285 .rms_meter_div_fact = 0x0B,
286 .rms_meter_resamp_fact = 0x28,
287 },
288 {
289 /* 96 Khz */
Banajit Goswamia7294452013-06-03 12:42:35 -0700290 .peak_det_timeout = 0x0A,
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800291 .rms_meter_div_fact = 0x0C,
292 .rms_meter_resamp_fact = 0x50,
293 },
294 {
295 /* 192 Khz */
Banajit Goswamia7294452013-06-03 12:42:35 -0700296 .peak_det_timeout = 0x0B,
297 .rms_meter_div_fact = 0xC,
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800298 .rms_meter_resamp_fact = 0xA0,
299 },
300};
301
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800302static unsigned short rx_digital_gain_reg[] = {
303 TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
304 TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
305 TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL,
306 TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
307};
308
309static unsigned short tx_digital_gain_reg[] = {
310 TAPAN_A_CDC_TX1_VOL_CTL_GAIN,
311 TAPAN_A_CDC_TX2_VOL_CTL_GAIN,
312 TAPAN_A_CDC_TX3_VOL_CTL_GAIN,
313 TAPAN_A_CDC_TX4_VOL_CTL_GAIN,
314};
315
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800316static int spkr_drv_wrnd_param_set(const char *val,
317 const struct kernel_param *kp)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800318{
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800319 struct snd_soc_codec *codec;
320 int ret, old;
321 struct tapan_priv *priv;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800322
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800323 priv = (struct tapan_priv *)atomic_read(&kp_tapan_priv);
324 if (!priv) {
325 pr_debug("%s: codec isn't yet registered\n", __func__);
326 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800327 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800328
Joonwoo Park973fd352013-06-19 11:38:53 -0700329 codec = priv->codec;
330 mutex_lock(&codec->mutex);
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800331 old = spkr_drv_wrnd;
332 ret = param_set_int(val, kp);
333 if (ret) {
Joonwoo Park973fd352013-06-19 11:38:53 -0700334 mutex_unlock(&codec->mutex);
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800335 return ret;
336 }
337
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800338 dev_dbg(codec->dev, "%s: spkr_drv_wrnd %d -> %d\n",
339 __func__, old, spkr_drv_wrnd);
Joonwoo Park973fd352013-06-19 11:38:53 -0700340 if ((old == -1 || old == 0) && spkr_drv_wrnd == 1) {
Joonwoo Park533b3682013-06-13 11:41:21 -0700341 WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800342 wcd9xxx_resmgr_get_bandgap(&priv->resmgr,
343 WCD9XXX_BANDGAP_AUDIO_MODE);
Joonwoo Park533b3682013-06-13 11:41:21 -0700344 WCD9XXX_BG_CLK_UNLOCK(&priv->resmgr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800345 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
346 } else if (old == 1 && spkr_drv_wrnd == 0) {
Joonwoo Park533b3682013-06-13 11:41:21 -0700347 WCD9XXX_BG_CLK_LOCK(&priv->resmgr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800348 wcd9xxx_resmgr_put_bandgap(&priv->resmgr,
349 WCD9XXX_BANDGAP_AUDIO_MODE);
Joonwoo Park533b3682013-06-13 11:41:21 -0700350 WCD9XXX_BG_CLK_UNLOCK(&priv->resmgr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800351 if (!priv->spkr_pa_widget_on)
352 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
353 0x00);
354 }
Joonwoo Park973fd352013-06-19 11:38:53 -0700355 mutex_unlock(&codec->mutex);
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800356
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800357 return 0;
358}
359
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800360static int tapan_get_anc_slot(struct snd_kcontrol *kcontrol,
361 struct snd_ctl_elem_value *ucontrol)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800362{
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800363 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
364 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
365 ucontrol->value.integer.value[0] = tapan->anc_slot;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800366 return 0;
367}
368
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800369static int tapan_put_anc_slot(struct snd_kcontrol *kcontrol,
370 struct snd_ctl_elem_value *ucontrol)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800371{
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800372 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
373 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
374 tapan->anc_slot = ucontrol->value.integer.value[0];
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800375 return 0;
376}
377
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700378static int tapan_get_anc_func(struct snd_kcontrol *kcontrol,
379 struct snd_ctl_elem_value *ucontrol)
380{
381 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
382 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
383
384 ucontrol->value.integer.value[0] = (tapan->anc_func == true ? 1 : 0);
385 return 0;
386}
387
388static int tapan_put_anc_func(struct snd_kcontrol *kcontrol,
389 struct snd_ctl_elem_value *ucontrol)
390{
391 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
392 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
393 struct snd_soc_dapm_context *dapm = &codec->dapm;
394
395 mutex_lock(&dapm->codec->mutex);
396 tapan->anc_func = (!ucontrol->value.integer.value[0] ? false : true);
397
398 dev_err(codec->dev, "%s: anc_func %x", __func__, tapan->anc_func);
399
400 if (tapan->anc_func == true) {
401 pr_info("enable anc virtual widgets");
402 snd_soc_dapm_enable_pin(dapm, "ANC HPHR");
403 snd_soc_dapm_enable_pin(dapm, "ANC HPHL");
404 snd_soc_dapm_enable_pin(dapm, "ANC HEADPHONE");
405 snd_soc_dapm_enable_pin(dapm, "ANC EAR PA");
406 snd_soc_dapm_enable_pin(dapm, "ANC EAR");
407 snd_soc_dapm_disable_pin(dapm, "HPHR");
408 snd_soc_dapm_disable_pin(dapm, "HPHL");
409 snd_soc_dapm_disable_pin(dapm, "HEADPHONE");
410 snd_soc_dapm_disable_pin(dapm, "EAR PA");
411 snd_soc_dapm_disable_pin(dapm, "EAR");
412 } else {
413 pr_info("disable anc virtual widgets");
414 snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
415 snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
416 snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
417 snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
418 snd_soc_dapm_disable_pin(dapm, "ANC EAR");
419 snd_soc_dapm_enable_pin(dapm, "HPHR");
420 snd_soc_dapm_enable_pin(dapm, "HPHL");
421 snd_soc_dapm_enable_pin(dapm, "HEADPHONE");
422 snd_soc_dapm_enable_pin(dapm, "EAR PA");
423 snd_soc_dapm_enable_pin(dapm, "EAR");
424 }
425 snd_soc_dapm_sync(dapm);
426 mutex_unlock(&dapm->codec->mutex);
427 return 0;
428}
429
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800430static int tapan_pa_gain_get(struct snd_kcontrol *kcontrol,
431 struct snd_ctl_elem_value *ucontrol)
432{
433 u8 ear_pa_gain;
434 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
435
436 ear_pa_gain = snd_soc_read(codec, TAPAN_A_RX_EAR_GAIN);
437
438 ear_pa_gain = ear_pa_gain >> 5;
439
440 if (ear_pa_gain == 0x00) {
441 ucontrol->value.integer.value[0] = 0;
442 } else if (ear_pa_gain == 0x04) {
443 ucontrol->value.integer.value[0] = 1;
444 } else {
445 pr_err("%s: ERROR: Unsupported Ear Gain = 0x%x\n",
446 __func__, ear_pa_gain);
447 return -EINVAL;
448 }
449
450 dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
451
452 return 0;
453}
454
455static int tapan_pa_gain_put(struct snd_kcontrol *kcontrol,
456 struct snd_ctl_elem_value *ucontrol)
457{
458 u8 ear_pa_gain;
459 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
460
461 dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
462 __func__, ucontrol->value.integer.value[0]);
463
464 switch (ucontrol->value.integer.value[0]) {
465 case 0:
466 ear_pa_gain = 0x00;
467 break;
468 case 1:
469 ear_pa_gain = 0x80;
470 break;
471 default:
472 return -EINVAL;
473 }
474
475 snd_soc_update_bits(codec, TAPAN_A_RX_EAR_GAIN, 0xE0, ear_pa_gain);
476 return 0;
477}
478
479static int tapan_get_iir_enable_audio_mixer(
480 struct snd_kcontrol *kcontrol,
481 struct snd_ctl_elem_value *ucontrol)
482{
483 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
484 int iir_idx = ((struct soc_multi_mixer_control *)
485 kcontrol->private_value)->reg;
486 int band_idx = ((struct soc_multi_mixer_control *)
487 kcontrol->private_value)->shift;
488
489 ucontrol->value.integer.value[0] =
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700490 (snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
491 (1 << band_idx)) != 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800492
493 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
494 iir_idx, band_idx,
495 (uint32_t)ucontrol->value.integer.value[0]);
496 return 0;
497}
498
499static int tapan_put_iir_enable_audio_mixer(
500 struct snd_kcontrol *kcontrol,
501 struct snd_ctl_elem_value *ucontrol)
502{
503 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
504 int iir_idx = ((struct soc_multi_mixer_control *)
505 kcontrol->private_value)->reg;
506 int band_idx = ((struct soc_multi_mixer_control *)
507 kcontrol->private_value)->shift;
508 int value = ucontrol->value.integer.value[0];
509
510 /* Mask first 5 bits, 6-8 are reserved */
511 snd_soc_update_bits(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx),
512 (1 << band_idx), (value << band_idx));
513
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700514 pr_debug("%s: IIR #%d band #%d enable %d\n", __func__,
515 iir_idx, band_idx,
516 ((snd_soc_read(codec, (TAPAN_A_CDC_IIR1_CTL + 16 * iir_idx)) &
517 (1 << band_idx)) != 0));
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800518 return 0;
519}
520static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
521 int iir_idx, int band_idx,
522 int coeff_idx)
523{
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700524 uint32_t value = 0;
525
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800526 /* Address does not automatically update if reading */
527 snd_soc_write(codec,
528 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700529 ((band_idx * BAND_MAX + coeff_idx)
530 * sizeof(uint32_t)) & 0x7F);
531
532 value |= snd_soc_read(codec,
533 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx));
534
535 snd_soc_write(codec,
536 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
537 ((band_idx * BAND_MAX + coeff_idx)
538 * sizeof(uint32_t) + 1) & 0x7F);
539
540 value |= (snd_soc_read(codec,
541 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 8);
542
543 snd_soc_write(codec,
544 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
545 ((band_idx * BAND_MAX + coeff_idx)
546 * sizeof(uint32_t) + 2) & 0x7F);
547
548 value |= (snd_soc_read(codec,
549 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) << 16);
550
551 snd_soc_write(codec,
552 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
553 ((band_idx * BAND_MAX + coeff_idx)
554 * sizeof(uint32_t) + 3) & 0x7F);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800555
556 /* Mask bits top 2 bits since they are reserved */
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700557 value |= ((snd_soc_read(codec,
558 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx)) & 0x3F) << 24);
559
560 return value;
561
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800562}
563
564static int tapan_get_iir_band_audio_mixer(
565 struct snd_kcontrol *kcontrol,
566 struct snd_ctl_elem_value *ucontrol)
567{
568 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
569 int iir_idx = ((struct soc_multi_mixer_control *)
570 kcontrol->private_value)->reg;
571 int band_idx = ((struct soc_multi_mixer_control *)
572 kcontrol->private_value)->shift;
573
574 ucontrol->value.integer.value[0] =
575 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
576 ucontrol->value.integer.value[1] =
577 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
578 ucontrol->value.integer.value[2] =
579 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
580 ucontrol->value.integer.value[3] =
581 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
582 ucontrol->value.integer.value[4] =
583 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
584
585 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
586 "%s: IIR #%d band #%d b1 = 0x%x\n"
587 "%s: IIR #%d band #%d b2 = 0x%x\n"
588 "%s: IIR #%d band #%d a1 = 0x%x\n"
589 "%s: IIR #%d band #%d a2 = 0x%x\n",
590 __func__, iir_idx, band_idx,
591 (uint32_t)ucontrol->value.integer.value[0],
592 __func__, iir_idx, band_idx,
593 (uint32_t)ucontrol->value.integer.value[1],
594 __func__, iir_idx, band_idx,
595 (uint32_t)ucontrol->value.integer.value[2],
596 __func__, iir_idx, band_idx,
597 (uint32_t)ucontrol->value.integer.value[3],
598 __func__, iir_idx, band_idx,
599 (uint32_t)ucontrol->value.integer.value[4]);
600 return 0;
601}
602
603static void set_iir_band_coeff(struct snd_soc_codec *codec,
604 int iir_idx, int band_idx,
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700605 uint32_t value)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800606{
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800607 snd_soc_write(codec,
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700608 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
609 (value & 0xFF));
610
611 snd_soc_write(codec,
612 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
613 (value >> 8) & 0xFF);
614
615 snd_soc_write(codec,
616 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
617 (value >> 16) & 0xFF);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800618
619 /* Mask top 2 bits, 7-8 are reserved */
620 snd_soc_write(codec,
621 (TAPAN_A_CDC_IIR1_COEF_B2_CTL + 16 * iir_idx),
622 (value >> 24) & 0x3F);
623
624}
625
626static int tapan_put_iir_band_audio_mixer(
627 struct snd_kcontrol *kcontrol,
628 struct snd_ctl_elem_value *ucontrol)
629{
630 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
631 int iir_idx = ((struct soc_multi_mixer_control *)
632 kcontrol->private_value)->reg;
633 int band_idx = ((struct soc_multi_mixer_control *)
634 kcontrol->private_value)->shift;
635
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700636 /* Mask top bit it is reserved */
637 /* Updates addr automatically for each B2 write */
638 snd_soc_write(codec,
639 (TAPAN_A_CDC_IIR1_COEF_B1_CTL + 16 * iir_idx),
640 (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
641
642 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800643 ucontrol->value.integer.value[0]);
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700644 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800645 ucontrol->value.integer.value[1]);
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700646 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800647 ucontrol->value.integer.value[2]);
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700648 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800649 ucontrol->value.integer.value[3]);
Phani Kumar Uppalapati4a7b76f2013-04-26 13:47:24 -0700650 set_iir_band_coeff(codec, iir_idx, band_idx,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800651 ucontrol->value.integer.value[4]);
652
653 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
654 "%s: IIR #%d band #%d b1 = 0x%x\n"
655 "%s: IIR #%d band #%d b2 = 0x%x\n"
656 "%s: IIR #%d band #%d a1 = 0x%x\n"
657 "%s: IIR #%d band #%d a2 = 0x%x\n",
658 __func__, iir_idx, band_idx,
659 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
660 __func__, iir_idx, band_idx,
661 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
662 __func__, iir_idx, band_idx,
663 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
664 __func__, iir_idx, band_idx,
665 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
666 __func__, iir_idx, band_idx,
667 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
668 return 0;
669}
670
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800671static int tapan_get_compander(struct snd_kcontrol *kcontrol,
672 struct snd_ctl_elem_value *ucontrol)
673{
674
675 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
676 int comp = ((struct soc_multi_mixer_control *)
677 kcontrol->private_value)->shift;
678 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
679
680 ucontrol->value.integer.value[0] = tapan->comp_enabled[comp];
681 return 0;
682}
683
684static int tapan_set_compander(struct snd_kcontrol *kcontrol,
685 struct snd_ctl_elem_value *ucontrol)
686{
687 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
688 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
689 int comp = ((struct soc_multi_mixer_control *)
690 kcontrol->private_value)->shift;
691 int value = ucontrol->value.integer.value[0];
692
693 dev_dbg(codec->dev, "%s: Compander %d enable current %d, new %d\n",
694 __func__, comp, tapan->comp_enabled[comp], value);
695 tapan->comp_enabled[comp] = value;
Banajit Goswamia7294452013-06-03 12:42:35 -0700696
697 if (comp == COMPANDER_1 &&
698 tapan->comp_enabled[comp] == 1) {
699 /* Wavegen to 5 msec */
700 snd_soc_write(codec, TAPAN_A_RX_HPH_CNP_WG_CTL, 0xDA);
701 snd_soc_write(codec, TAPAN_A_RX_HPH_CNP_WG_TIME, 0x15);
702 snd_soc_write(codec, TAPAN_A_RX_HPH_BIAS_WG_OCP, 0x2A);
703
704 /* Enable Chopper */
705 snd_soc_update_bits(codec,
706 TAPAN_A_RX_HPH_CHOP_CTL, 0x80, 0x80);
707
708 snd_soc_write(codec, TAPAN_A_NCP_DTEST, 0x20);
709 pr_debug("%s: Enabled Chopper and set wavegen to 5 msec\n",
710 __func__);
711 } else if (comp == COMPANDER_1 &&
712 tapan->comp_enabled[comp] == 0) {
713 /* Wavegen to 20 msec */
714 snd_soc_write(codec, TAPAN_A_RX_HPH_CNP_WG_CTL, 0xDB);
715 snd_soc_write(codec, TAPAN_A_RX_HPH_CNP_WG_TIME, 0x58);
716 snd_soc_write(codec, TAPAN_A_RX_HPH_BIAS_WG_OCP, 0x1A);
717
718 /* Disable CHOPPER block */
719 snd_soc_update_bits(codec,
720 TAPAN_A_RX_HPH_CHOP_CTL, 0x80, 0x00);
721
722 snd_soc_write(codec, TAPAN_A_NCP_DTEST, 0x10);
723 pr_debug("%s: Disabled Chopper and set wavegen to 20 msec\n",
724 __func__);
725 }
726
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800727 return 0;
728}
729
730static int tapan_config_gain_compander(struct snd_soc_codec *codec,
731 int comp, bool enable)
732{
733 int ret = 0;
734
735 switch (comp) {
736 case COMPANDER_0:
737 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_GAIN,
738 1 << 2, !enable << 2);
739 break;
740 case COMPANDER_1:
741 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_L_GAIN,
742 1 << 5, !enable << 5);
743 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_R_GAIN,
744 1 << 5, !enable << 5);
745 break;
746 case COMPANDER_2:
747 snd_soc_update_bits(codec, TAPAN_A_RX_LINE_1_GAIN,
748 1 << 5, !enable << 5);
749 snd_soc_update_bits(codec, TAPAN_A_RX_LINE_2_GAIN,
750 1 << 5, !enable << 5);
751 break;
752 default:
753 WARN_ON(1);
754 ret = -EINVAL;
755 }
756
757 return ret;
758}
759
760static void tapan_discharge_comp(struct snd_soc_codec *codec, int comp)
761{
Banajit Goswamia7294452013-06-03 12:42:35 -0700762 /* Level meter DIV Factor to 5*/
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800763 snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8), 0xF0,
Banajit Goswamia7294452013-06-03 12:42:35 -0700764 0x05 << 4);
765 /* RMS meter Sampling to 0x01 */
766 snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8), 0x01);
767
768 /* Worst case timeout for compander CnP sleep timeout */
769 usleep_range(3000, 3000);
770}
771
772static enum wcd9xxx_buck_volt tapan_codec_get_buck_mv(
773 struct snd_soc_codec *codec)
774{
775 int buck_volt = WCD9XXX_CDC_BUCK_UNSUPPORTED;
776 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
777 struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
778 int i;
Bhalchandra Gajaref49df622013-08-30 12:42:38 -0700779 bool found_regulator = false;
Banajit Goswamia7294452013-06-03 12:42:35 -0700780
781 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -0700782 if (pdata->regulator[i].name == NULL)
783 continue;
784
Banajit Goswamia7294452013-06-03 12:42:35 -0700785 if (!strncmp(pdata->regulator[i].name,
Bhalchandra Gajaref49df622013-08-30 12:42:38 -0700786 WCD9XXX_SUPPLY_BUCK_NAME,
787 sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
788 found_regulator = true;
Banajit Goswamia7294452013-06-03 12:42:35 -0700789 if ((pdata->regulator[i].min_uV ==
Bhalchandra Gajaref49df622013-08-30 12:42:38 -0700790 WCD9XXX_CDC_BUCK_MV_1P8) ||
791 (pdata->regulator[i].min_uV ==
792 WCD9XXX_CDC_BUCK_MV_2P15))
Banajit Goswamia7294452013-06-03 12:42:35 -0700793 buck_volt = pdata->regulator[i].min_uV;
794 break;
795 }
796 }
Bhalchandra Gajaref49df622013-08-30 12:42:38 -0700797
798 if (!found_regulator)
799 dev_err(codec->dev,
800 "%s: Failed to find regulator for %s\n",
801 __func__, WCD9XXX_SUPPLY_BUCK_NAME);
802 else
803 dev_dbg(codec->dev,
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -0700804 "%s: S4 voltage requested is %d\n",
805 __func__, buck_volt);
Bhalchandra Gajaref49df622013-08-30 12:42:38 -0700806
Banajit Goswamia7294452013-06-03 12:42:35 -0700807 return buck_volt;
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800808}
809
810static int tapan_config_compander(struct snd_soc_dapm_widget *w,
811 struct snd_kcontrol *kcontrol, int event)
812{
Banajit Goswamia7294452013-06-03 12:42:35 -0700813 int mask, enable_mask;
814 u8 rdac5_mux;
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800815 struct snd_soc_codec *codec = w->codec;
816 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
817 const int comp = w->shift;
818 const u32 rate = tapan->comp_fs[comp];
819 const struct comp_sample_dependent_params *comp_params =
820 &comp_samp_params[rate];
Banajit Goswamia7294452013-06-03 12:42:35 -0700821 enum wcd9xxx_buck_volt buck_mv;
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800822
823 dev_dbg(codec->dev, "%s: %s event %d compander %d, enabled %d",
824 __func__, w->name, event, comp, tapan->comp_enabled[comp]);
825
826 if (!tapan->comp_enabled[comp])
827 return 0;
828
829 /* Compander 0 has single channel */
830 mask = (comp == COMPANDER_0 ? 0x01 : 0x03);
Banajit Goswamia7294452013-06-03 12:42:35 -0700831 buck_mv = tapan_codec_get_buck_mv(codec);
832
833 rdac5_mux = snd_soc_read(codec, TAPAN_A_CDC_CONN_MISC);
834 rdac5_mux = (rdac5_mux & 0x04) >> 2;
835
836 if (comp == COMPANDER_0) { /* SPK compander */
837 enable_mask = 0x02;
838 } else if (comp == COMPANDER_1) { /* HPH compander */
839 enable_mask = 0x03;
840 } else if (comp == COMPANDER_2) { /* LO compander */
841
842 if (rdac5_mux == 0) { /* DEM4 */
843
844 /* for LO Stereo SE, enable Compander 2 left
845 * channel on RX3 interpolator Path and Compander 2
846 * rigt channel on RX4 interpolator Path.
847 */
848 enable_mask = 0x03;
849 } else if (rdac5_mux == 1) { /* DEM3_INV */
850
851 /* for LO mono differential only enable Compander 2
852 * left channel on RX3 interpolator Path.
853 */
854 enable_mask = 0x02;
855 } else {
856 dev_err(codec->dev, "%s: invalid rdac5_mux val %d",
857 __func__, rdac5_mux);
858 return -EINVAL;
859 }
860 } else {
861 dev_err(codec->dev, "%s: invalid compander %d", __func__, comp);
862 return -EINVAL;
863 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800864
865 switch (event) {
866 case SND_SOC_DAPM_PRE_PMU:
Banajit Goswamia7294452013-06-03 12:42:35 -0700867 /* Set compander Sample rate */
868 snd_soc_update_bits(codec,
869 TAPAN_A_CDC_COMP0_FS_CFG + (comp * 8),
870 0x07, rate);
871 /* Set the static gain offset for HPH Path */
872 if (comp == COMPANDER_1) {
873 if (buck_mv == WCD9XXX_CDC_BUCK_MV_2P15)
874 snd_soc_update_bits(codec,
875 TAPAN_A_CDC_COMP0_B4_CTL + (comp * 8),
876 0x80, 0x00);
877 else
878 snd_soc_update_bits(codec,
879 TAPAN_A_CDC_COMP0_B4_CTL + (comp * 8),
880 0x80, 0x80);
881 }
882 /* Enable RX interpolation path compander clocks */
883 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
884 0x01 << comp_shift[comp],
885 0x01 << comp_shift[comp]);
886
887 /* Toggle compander reset bits */
888 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
889 0x01 << comp_shift[comp],
890 0x01 << comp_shift[comp]);
891 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
892 0x01 << comp_shift[comp], 0);
893
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800894 /* Set gain source to compander */
895 tapan_config_gain_compander(codec, comp, true);
Banajit Goswamia7294452013-06-03 12:42:35 -0700896
897 /* Compander enable */
898 snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
899 (comp * 8), enable_mask, enable_mask);
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800900
901 tapan_discharge_comp(codec, comp);
902
Banajit Goswamia7294452013-06-03 12:42:35 -0700903 /* Set sample rate dependent paramater */
904 snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8),
905 comp_params->rms_meter_resamp_fact);
906 snd_soc_update_bits(codec,
907 TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
908 0xF0, comp_params->rms_meter_div_fact << 4);
909 snd_soc_update_bits(codec,
910 TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
911 0x0F, comp_params->peak_det_timeout);
912 break;
913 case SND_SOC_DAPM_PRE_PMD:
914 /* Disable compander */
915 snd_soc_update_bits(codec,
916 TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
917 enable_mask, 0x00);
918
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800919 /* Toggle compander reset bits */
920 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
921 mask << comp_shift[comp],
922 mask << comp_shift[comp]);
923 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
924 mask << comp_shift[comp], 0);
Banajit Goswamia7294452013-06-03 12:42:35 -0700925
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800926 /* Turn off the clock for compander in pair */
927 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
928 mask << comp_shift[comp], 0);
Banajit Goswamia7294452013-06-03 12:42:35 -0700929
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800930 /* Set gain source to register */
931 tapan_config_gain_compander(codec, comp, false);
932 break;
933 }
934 return 0;
935}
936
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800937static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
938static const struct soc_enum tapan_ear_pa_gain_enum[] = {
939 SOC_ENUM_SINGLE_EXT(2, tapan_ear_pa_gain_text),
940};
941
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700942static const char *const tapan_anc_func_text[] = {"OFF", "ON"};
943static const struct soc_enum tapan_anc_func_enum =
944 SOC_ENUM_SINGLE_EXT(2, tapan_anc_func_text);
945
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800946/*cut of frequency for high pass filter*/
947static const char * const cf_text[] = {
948 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
949};
950
951static const struct soc_enum cf_dec1_enum =
952 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
953
954static const struct soc_enum cf_dec2_enum =
955 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
956
957static const struct soc_enum cf_dec3_enum =
958 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
959
960static const struct soc_enum cf_dec4_enum =
961 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
962
963static const struct soc_enum cf_rxmix1_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800964 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800965
966static const struct soc_enum cf_rxmix2_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800967 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800968
969static const struct soc_enum cf_rxmix3_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800970 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800971
972static const struct soc_enum cf_rxmix4_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800973 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800974
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800975static const char * const class_h_dsm_text[] = {
976 "ZERO", "RX_HPHL", "RX_SPKR"
977};
978
979static const struct soc_enum class_h_dsm_enum =
980 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_CLSH_CTL, 2, 3, class_h_dsm_text);
981
982static const struct snd_kcontrol_new class_h_dsm_mux =
983 SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
984
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -0700985static const struct snd_kcontrol_new tapan_common_snd_controls[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800986
987 SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
988 tapan_pa_gain_get, tapan_pa_gain_put),
989
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800990 SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800991 line_gain),
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800992 SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800993 line_gain),
994
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800995 SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800996 line_gain),
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800997 SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800998 line_gain),
999
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001000 SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 7, 1,
1001 line_gain),
1002
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001003 SOC_SINGLE_TLV("ADC1 Volume", TAPAN_A_TX_1_EN, 2, 19, 0, analog_gain),
1004 SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 19, 0, analog_gain),
1005 SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 19, 0, analog_gain),
1006 SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 19, 0, analog_gain),
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001007 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
1008 -84, 40, digital_gain),
1009 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
1010 -84, 40, digital_gain),
1011 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL,
1012 -84, 40, digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001013
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001014 SOC_SINGLE_S8_TLV("DEC1 Volume", TAPAN_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
1015 digital_gain),
1016 SOC_SINGLE_S8_TLV("DEC2 Volume", TAPAN_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
1017 digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001018
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001019 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TAPAN_A_CDC_IIR1_GAIN_B1_CTL, -84,
1020 40, digital_gain),
1021 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TAPAN_A_CDC_IIR1_GAIN_B2_CTL, -84,
1022 40, digital_gain),
1023 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TAPAN_A_CDC_IIR1_GAIN_B3_CTL, -84,
1024 40, digital_gain),
1025 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAPAN_A_CDC_IIR1_GAIN_B4_CTL, -84,
1026 40, digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001027
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001028 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
1029 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
1030 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
1031 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
1032
1033 SOC_SINGLE("TX1 HPF Switch", TAPAN_A_CDC_TX1_MUX_CTL, 3, 1, 0),
1034 SOC_SINGLE("TX2 HPF Switch", TAPAN_A_CDC_TX2_MUX_CTL, 3, 1, 0),
1035 SOC_SINGLE("TX3 HPF Switch", TAPAN_A_CDC_TX3_MUX_CTL, 3, 1, 0),
1036 SOC_SINGLE("TX4 HPF Switch", TAPAN_A_CDC_TX4_MUX_CTL, 3, 1, 0),
1037
1038 SOC_SINGLE("RX1 HPF Switch", TAPAN_A_CDC_RX1_B5_CTL, 2, 1, 0),
1039 SOC_SINGLE("RX2 HPF Switch", TAPAN_A_CDC_RX2_B5_CTL, 2, 1, 0),
1040 SOC_SINGLE("RX3 HPF Switch", TAPAN_A_CDC_RX3_B5_CTL, 2, 1, 0),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001041
1042 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1043 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1044 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001045
1046 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1047 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1048 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1049 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1050 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1051 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1052 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1053 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1054 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1055 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1056 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1057 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1058 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1059 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1060 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1061 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1062 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1063 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1064 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1065 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1066
1067 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1068 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1069 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1070 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1071 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1072 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1073 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1074 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1075 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1076 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1077 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1078 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1079 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1080 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1081 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1082 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1083 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1084 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1085 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1086 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07001087};
1088
1089static const struct snd_kcontrol_new tapan_9306_snd_controls[] = {
1090 SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 19, 0, analog_gain),
1091
1092 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
1093 -84, 40, digital_gain),
1094 SOC_SINGLE_S8_TLV("DEC3 Volume", TAPAN_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
1095 digital_gain),
1096 SOC_SINGLE_S8_TLV("DEC4 Volume", TAPAN_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
1097 digital_gain),
1098 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tapan_get_anc_slot,
1099 tapan_put_anc_slot),
1100 SOC_ENUM_EXT("ANC Function", tapan_anc_func_enum, tapan_get_anc_func,
1101 tapan_put_anc_func),
1102 SOC_SINGLE("RX4 HPF Switch", TAPAN_A_CDC_RX4_B5_CTL, 2, 1, 0),
1103 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001104
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001105 SOC_SINGLE_EXT("COMP0 Switch", SND_SOC_NOPM, COMPANDER_0, 1, 0,
1106 tapan_get_compander, tapan_set_compander),
1107 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
1108 tapan_get_compander, tapan_set_compander),
1109 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
1110 tapan_get_compander, tapan_set_compander),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001111};
1112
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001113static const char * const rx_1_2_mix1_text[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001114 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001115 "RX5", "AUXRX", "AUXTX1"
1116};
1117
1118static const char * const rx_3_4_mix1_text[] = {
1119 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1120 "RX5", "AUXRX", "AUXTX1", "AUXTX2"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001121};
1122
1123static const char * const rx_mix2_text[] = {
1124 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
1125};
1126
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07001127static const char * const rx_rdac3_text[] = {
1128 "DEM1", "DEM2"
1129};
1130
1131static const char * const rx_rdac4_text[] = {
1132 "DEM3", "DEM2"
1133};
1134
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001135static const char * const rx_rdac5_text[] = {
1136 "DEM4", "DEM3_INV"
1137};
1138
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001139static const char * const sb_tx_1_2_mux_text[] = {
1140 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1141 "RSVD", "RSVD", "RSVD",
1142 "DEC1", "DEC2", "DEC3", "DEC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001143};
1144
1145static const char * const sb_tx3_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001146 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1147 "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
1148 "DEC3"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001149};
1150
1151static const char * const sb_tx4_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001152 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1153 "RSVD", "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
1154 "DEC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001155};
1156
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001157static const char * const sb_tx5_mux_text[] = {
1158 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1159 "RSVD", "RSVD", "RSVD",
1160 "DEC1"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001161};
1162
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001163static const char * const dec_1_2_mux_text[] = {
1164 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADCMB",
1165 "DMIC1", "DMIC2", "DMIC3", "DMIC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001166};
1167
1168static const char * const dec3_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001169 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
1170 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
1171 "ANCFBTUNE1"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001172};
1173
1174static const char * const dec4_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001175 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
1176 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
1177 "ANCFBTUNE2"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001178};
1179
1180static const char * const anc_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001181 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5",
1182 "RSVD", "RSVD", "RSVD",
1183 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
1184 "RSVD", "RSVD"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001185};
1186
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001187static const char * const anc1_fb_mux_text[] = {
1188 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1189};
1190
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001191static const char * const iir1_inp1_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001192 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4",
1193 "RX1", "RX2", "RX3", "RX4", "RX5"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001194};
1195
1196static const struct soc_enum rx_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001197 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001198
1199static const struct soc_enum rx_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001200 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001201
1202static const struct soc_enum rx_mix1_inp3_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001203 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001204
1205static const struct soc_enum rx2_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001206 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001207
1208static const struct soc_enum rx2_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001209 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001210
1211static const struct soc_enum rx3_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001212 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 0, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001213
1214static const struct soc_enum rx3_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001215 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 4, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001216
1217static const struct soc_enum rx4_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001218 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 0, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001219
1220static const struct soc_enum rx4_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001221 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001222
1223static const struct soc_enum rx1_mix2_inp1_chain_enum =
1224 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
1225
1226static const struct soc_enum rx1_mix2_inp2_chain_enum =
1227 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
1228
1229static const struct soc_enum rx2_mix2_inp1_chain_enum =
1230 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
1231
1232static const struct soc_enum rx2_mix2_inp2_chain_enum =
1233 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
1234
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001235static const struct soc_enum rx4_mix2_inp1_chain_enum =
1236 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 0, 5, rx_mix2_text);
1237
1238static const struct soc_enum rx4_mix2_inp2_chain_enum =
1239 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 3, 5, rx_mix2_text);
1240
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07001241static const struct soc_enum rx_rdac3_enum =
1242 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B2_CTL, 4, 2, rx_rdac3_text);
1243
1244static const struct soc_enum rx_rdac4_enum =
1245 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 1, 2, rx_rdac4_text);
1246
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001247static const struct soc_enum rx_rdac5_enum =
1248 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
1249
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001250static const struct soc_enum sb_tx1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001251 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0, 12,
1252 sb_tx_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001253
1254static const struct soc_enum sb_tx2_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001255 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0, 12,
1256 sb_tx_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001257
1258static const struct soc_enum sb_tx3_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001259 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0, 11, sb_tx3_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001260
1261static const struct soc_enum sb_tx4_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001262 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0, 12, sb_tx4_mux_text);
1263
1264static const struct soc_enum sb_tx5_mux_enum =
1265 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001266
1267static const struct soc_enum dec1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001268 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 0, 10, dec_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001269
1270static const struct soc_enum dec2_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001271 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 4, 10, dec_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001272
1273static const struct soc_enum dec3_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001274 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 0, 12, dec3_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001275
1276static const struct soc_enum dec4_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001277 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 4, 12, dec4_mux_text);
1278
1279static const struct soc_enum anc1_mux_enum =
1280 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 0, 15, anc_mux_text);
1281
1282static const struct soc_enum anc2_mux_enum =
1283 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 4, 15, anc_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001284
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001285static const struct soc_enum anc1_fb_mux_enum =
1286 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1287
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001288static const struct soc_enum iir1_inp1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001289 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_EQ1_B1_CTL, 0, 10, iir1_inp1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001290
1291static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1292 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1293
1294static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1295 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1296
1297static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1298 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1299
1300static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1301 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1302
1303static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1304 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1305
1306static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1307 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1308
1309static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1310 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1311
1312static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1313 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1314
1315static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1316 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1317
1318static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1319 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1320
1321static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
1322 SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
1323
1324static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1325 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1326
1327static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
1328 SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
1329
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001330static const struct snd_kcontrol_new rx4_mix2_inp1_mux =
1331 SOC_DAPM_ENUM("RX4 MIX2 INP1 Mux", rx4_mix2_inp1_chain_enum);
1332
1333static const struct snd_kcontrol_new rx4_mix2_inp2_mux =
1334 SOC_DAPM_ENUM("RX4 MIX2 INP2 Mux", rx4_mix2_inp2_chain_enum);
1335
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07001336static const struct snd_kcontrol_new rx_dac3_mux =
1337 SOC_DAPM_ENUM("RDAC3 MUX Mux", rx_rdac3_enum);
1338
1339static const struct snd_kcontrol_new rx_dac4_mux =
1340 SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
1341
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001342static const struct snd_kcontrol_new rx_dac5_mux =
1343 SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
1344
1345static const struct snd_kcontrol_new sb_tx1_mux =
1346 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1347
1348static const struct snd_kcontrol_new sb_tx2_mux =
1349 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
1350
1351static const struct snd_kcontrol_new sb_tx3_mux =
1352 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
1353
1354static const struct snd_kcontrol_new sb_tx4_mux =
1355 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
1356
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001357static const struct snd_kcontrol_new sb_tx5_mux =
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001358 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001359
1360static int wcd9306_put_dec_enum(struct snd_kcontrol *kcontrol,
1361 struct snd_ctl_elem_value *ucontrol)
1362{
1363 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1364 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1365 struct snd_soc_codec *codec = w->codec;
1366 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1367 unsigned int dec_mux, decimator;
1368 char *dec_name = NULL;
1369 char *widget_name = NULL;
1370 char *temp;
1371 u16 tx_mux_ctl_reg;
1372 u8 adc_dmic_sel = 0x0;
1373 int ret = 0;
1374
1375 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1376 return -EINVAL;
1377
1378 dec_mux = ucontrol->value.enumerated.item[0];
1379
1380 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1381 if (!widget_name)
1382 return -ENOMEM;
1383 temp = widget_name;
1384
1385 dec_name = strsep(&widget_name, " ");
1386 widget_name = temp;
1387 if (!dec_name) {
1388 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1389 ret = -EINVAL;
1390 goto out;
1391 }
1392
1393 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
1394 if (ret < 0) {
1395 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1396 ret = -EINVAL;
1397 goto out;
1398 }
1399
1400 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1401 , __func__, w->name, decimator, dec_mux);
1402
1403 switch (decimator) {
1404 case 1:
1405 case 2:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001406 if ((dec_mux >= 1) && (dec_mux <= 5))
1407 adc_dmic_sel = 0x0;
1408 else if ((dec_mux >= 6) && (dec_mux <= 9))
1409 adc_dmic_sel = 0x1;
1410 break;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001411 case 3:
1412 case 4:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001413 if ((dec_mux >= 1) && (dec_mux <= 6))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001414 adc_dmic_sel = 0x0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001415 else if ((dec_mux >= 7) && (dec_mux <= 10))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001416 adc_dmic_sel = 0x1;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001417 break;
1418 default:
1419 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1420 ret = -EINVAL;
1421 goto out;
1422 }
1423
1424 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1425
1426 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1427
1428 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1429
1430out:
1431 kfree(widget_name);
1432 return ret;
1433}
1434
1435#define WCD9306_DEC_ENUM(xname, xenum) \
1436{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1437 .info = snd_soc_info_enum_double, \
1438 .get = snd_soc_dapm_get_enum_double, \
1439 .put = wcd9306_put_dec_enum, \
1440 .private_value = (unsigned long)&xenum }
1441
1442static const struct snd_kcontrol_new dec1_mux =
1443 WCD9306_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1444
1445static const struct snd_kcontrol_new dec2_mux =
1446 WCD9306_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1447
1448static const struct snd_kcontrol_new dec3_mux =
1449 WCD9306_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1450
1451static const struct snd_kcontrol_new dec4_mux =
1452 WCD9306_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1453
1454static const struct snd_kcontrol_new iir1_inp1_mux =
1455 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1456
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001457static const struct snd_kcontrol_new anc1_mux =
1458 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1459
1460static const struct snd_kcontrol_new anc2_mux =
1461 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
1462
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001463static const struct snd_kcontrol_new anc1_fb_mux =
1464 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
1465
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001466static const struct snd_kcontrol_new dac1_switch[] = {
1467 SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_EAR_EN, 5, 1, 0)
1468};
1469static const struct snd_kcontrol_new hphl_switch[] = {
1470 SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1471};
1472
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001473static const struct snd_kcontrol_new spk_dac_switch[] = {
1474 SOC_DAPM_SINGLE("Switch", TAPAN_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
1475};
1476
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001477static const struct snd_kcontrol_new hphl_pa_mix[] = {
1478 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1479 7, 1, 0),
1480};
1481
1482static const struct snd_kcontrol_new hphr_pa_mix[] = {
1483 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1484 6, 1, 0),
1485};
1486
1487static const struct snd_kcontrol_new ear_pa_mix[] = {
1488 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1489 5, 1, 0),
1490};
1491static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1492 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1493 4, 1, 0),
1494};
1495
1496static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1497 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1498 3, 1, 0),
1499};
1500
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001501
1502/* virtual port entries */
1503static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
1504 struct snd_ctl_elem_value *ucontrol)
1505{
1506 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1507 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1508
1509 ucontrol->value.integer.value[0] = widget->value;
1510 return 0;
1511}
1512
1513static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
1514 struct snd_ctl_elem_value *ucontrol)
1515{
1516 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1517 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1518 struct snd_soc_codec *codec = widget->codec;
1519 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
1520 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1521 struct soc_multi_mixer_control *mixer =
1522 ((struct soc_multi_mixer_control *)kcontrol->private_value);
1523 u32 dai_id = widget->shift;
1524 u32 port_id = mixer->shift;
1525 u32 enable = ucontrol->value.integer.value[0];
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001526 u32 vtable = vport_check_table[dai_id];
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001527
1528 dev_dbg(codec->dev, "%s: wname %s cname %s\n",
1529 __func__, widget->name, ucontrol->id.name);
1530 dev_dbg(codec->dev, "%s: value %u shift %d item %ld\n",
1531 __func__, widget->value, widget->shift,
1532 ucontrol->value.integer.value[0]);
1533
1534 mutex_lock(&codec->mutex);
1535
1536 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1537 if (dai_id != AIF1_CAP) {
1538 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1539 __func__);
1540 mutex_unlock(&codec->mutex);
1541 return -EINVAL;
1542 }
1543 }
1544 switch (dai_id) {
1545 case AIF1_CAP:
1546 case AIF2_CAP:
1547 case AIF3_CAP:
1548 /* only add to the list if value not set
1549 */
1550 if (enable && !(widget->value & 1 << port_id)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001551 if (tapan_p->intf_type ==
1552 WCD9XXX_INTERFACE_TYPE_SLIMBUS)
1553 vtable = vport_check_table[dai_id];
1554 if (tapan_p->intf_type ==
1555 WCD9XXX_INTERFACE_TYPE_I2C)
1556 vtable = vport_i2s_check_table[dai_id];
1557
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001558 if (wcd9xxx_tx_vport_validation(
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001559 vtable,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001560 port_id,
1561 tapan_p->dai)) {
1562 dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
1563 __func__, port_id + 1);
1564 mutex_unlock(&codec->mutex);
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001565 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001566 }
1567 widget->value |= 1 << port_id;
1568 list_add_tail(&core->tx_chs[port_id].list,
1569 &tapan_p->dai[dai_id].wcd9xxx_ch_list
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001570 );
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001571 } else if (!enable && (widget->value & 1 << port_id)) {
1572 widget->value &= ~(1 << port_id);
1573 list_del_init(&core->tx_chs[port_id].list);
1574 } else {
1575 if (enable)
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001576 dev_dbg(codec->dev, "%s: TX%u port is used by\n"
1577 "this virtual port\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001578 __func__, port_id + 1);
1579 else
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001580 dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
1581 "this virtual port\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001582 __func__, port_id + 1);
1583 /* avoid update power function */
1584 mutex_unlock(&codec->mutex);
1585 return 0;
1586 }
1587 break;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001588 default:
1589 dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
1590 mutex_unlock(&codec->mutex);
1591 return -EINVAL;
1592 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001593 dev_dbg(codec->dev, "%s: name %s sname %s updated value %u shift %d\n",
1594 __func__, widget->name, widget->sname,
1595 widget->value, widget->shift);
1596
1597 snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
1598
1599 mutex_unlock(&codec->mutex);
1600 return 0;
1601}
1602
1603static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
1604 struct snd_ctl_elem_value *ucontrol)
1605{
1606 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1607 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1608
1609 ucontrol->value.enumerated.item[0] = widget->value;
1610 return 0;
1611}
1612
1613static const char *const slim_rx_mux_text[] = {
1614 "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB"
1615};
1616
1617static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
1618 struct snd_ctl_elem_value *ucontrol)
1619{
1620 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1621 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1622 struct snd_soc_codec *codec = widget->codec;
1623 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
1624 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1625 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1626 u32 port_id = widget->shift;
1627
1628 dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n",
1629 __func__, widget->name, ucontrol->id.name, widget->value,
1630 widget->shift, ucontrol->value.integer.value[0]);
1631
1632 widget->value = ucontrol->value.enumerated.item[0];
1633
1634 mutex_lock(&codec->mutex);
1635
1636 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1637 if (widget->value > 1) {
1638 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1639 __func__);
1640 goto err;
1641 }
1642 }
1643 /* value need to match the Virtual port and AIF number
1644 */
1645 switch (widget->value) {
1646 case 0:
1647 list_del_init(&core->rx_chs[port_id].list);
1648 break;
1649 case 1:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001650 if (wcd9xxx_rx_vport_validation(port_id +
1651 TAPAN_RX_PORT_START_NUMBER,
1652 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
1653 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1654 __func__, port_id + 1);
1655 goto rtn;
1656 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001657 list_add_tail(&core->rx_chs[port_id].list,
1658 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list);
1659 break;
1660 case 2:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001661 if (wcd9xxx_rx_vport_validation(port_id +
1662 TAPAN_RX_PORT_START_NUMBER,
1663 &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
1664 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1665 __func__, port_id + 1);
1666 goto rtn;
1667 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001668 list_add_tail(&core->rx_chs[port_id].list,
1669 &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list);
1670 break;
1671 case 3:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001672 if (wcd9xxx_rx_vport_validation(port_id +
1673 TAPAN_RX_PORT_START_NUMBER,
1674 &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
1675 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1676 __func__, port_id + 1);
1677 goto rtn;
1678 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001679 list_add_tail(&core->rx_chs[port_id].list,
1680 &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list);
1681 break;
1682 default:
1683 pr_err("Unknown AIF %d\n", widget->value);
1684 goto err;
1685 }
1686
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001687rtn:
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001688 snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001689 mutex_unlock(&codec->mutex);
1690 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001691err:
1692 mutex_unlock(&codec->mutex);
1693 return -EINVAL;
1694}
1695
1696static const struct soc_enum slim_rx_mux_enum =
1697 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
1698
1699static const struct snd_kcontrol_new slim_rx_mux[TAPAN_RX_MAX] = {
1700 SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
1701 slim_rx_mux_get, slim_rx_mux_put),
1702 SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
1703 slim_rx_mux_get, slim_rx_mux_put),
1704 SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
1705 slim_rx_mux_get, slim_rx_mux_put),
1706 SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
1707 slim_rx_mux_get, slim_rx_mux_put),
1708 SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
1709 slim_rx_mux_get, slim_rx_mux_put),
1710};
1711
1712static const struct snd_kcontrol_new aif_cap_mixer[] = {
1713 SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TAPAN_TX1, 1, 0,
1714 slim_tx_mixer_get, slim_tx_mixer_put),
1715 SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TAPAN_TX2, 1, 0,
1716 slim_tx_mixer_get, slim_tx_mixer_put),
1717 SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TAPAN_TX3, 1, 0,
1718 slim_tx_mixer_get, slim_tx_mixer_put),
1719 SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TAPAN_TX4, 1, 0,
1720 slim_tx_mixer_get, slim_tx_mixer_put),
1721 SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TAPAN_TX5, 1, 0,
1722 slim_tx_mixer_get, slim_tx_mixer_put),
1723};
1724
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001725static int tapan_codec_enable_adc(struct snd_soc_dapm_widget *w,
1726 struct snd_kcontrol *kcontrol, int event)
1727{
1728 struct snd_soc_codec *codec = w->codec;
1729 u16 adc_reg;
1730 u8 init_bit_shift;
1731
1732 dev_dbg(codec->dev, "%s(): %s %d\n", __func__, w->name, event);
1733
1734 if (w->reg == TAPAN_A_TX_1_EN) {
1735 init_bit_shift = 7;
1736 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1737 } else if (w->reg == TAPAN_A_TX_2_EN) {
1738 init_bit_shift = 6;
1739 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1740 } else if (w->reg == TAPAN_A_TX_3_EN) {
1741 init_bit_shift = 6;
1742 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1743 } else if (w->reg == TAPAN_A_TX_4_EN) {
1744 init_bit_shift = 7;
1745 adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
1746 } else if (w->reg == TAPAN_A_TX_5_EN) {
1747 init_bit_shift = 6;
1748 adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
1749 } else {
1750 pr_err("%s: Error, invalid adc register\n", __func__);
1751 return -EINVAL;
1752 }
1753
1754 switch (event) {
1755 case SND_SOC_DAPM_PRE_PMU:
1756 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1757 1 << init_bit_shift);
1758 break;
1759 case SND_SOC_DAPM_POST_PMU:
1760
1761 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1762
1763 break;
1764 }
1765 return 0;
1766}
1767
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001768static int tapan_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1769 struct snd_kcontrol *kcontrol, int event)
1770{
1771 struct snd_soc_codec *codec = w->codec;
1772 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1773
1774 dev_dbg(codec->dev, "%s: %d\n", __func__, event);
1775
1776 switch (event) {
1777 case SND_SOC_DAPM_PRE_PMU:
Joonwoo Park533b3682013-06-13 11:41:21 -07001778 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001779 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
1780 WCD9XXX_BANDGAP_AUDIO_MODE);
1781 /* AUX PGA requires RCO or MCLK */
1782 wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_RCO);
Joonwoo Park533b3682013-06-13 11:41:21 -07001783 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001784 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 1);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001785 break;
1786
1787 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001788 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 0);
Joonwoo Park533b3682013-06-13 11:41:21 -07001789 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001790 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
1791 WCD9XXX_BANDGAP_AUDIO_MODE);
1792 wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_RCO);
Joonwoo Park533b3682013-06-13 11:41:21 -07001793 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001794 break;
1795 }
1796 return 0;
1797}
1798
1799static int tapan_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1800 struct snd_kcontrol *kcontrol, int event)
1801{
1802 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001803 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001804 u16 lineout_gain_reg;
1805
1806 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
1807
1808 switch (w->shift) {
1809 case 0:
1810 lineout_gain_reg = TAPAN_A_RX_LINE_1_GAIN;
1811 break;
1812 case 1:
1813 lineout_gain_reg = TAPAN_A_RX_LINE_2_GAIN;
1814 break;
1815 default:
1816 pr_err("%s: Error, incorrect lineout register value\n",
1817 __func__);
1818 return -EINVAL;
1819 }
1820
1821 switch (event) {
1822 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001823 break;
1824 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001825 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
1826 WCD9XXX_CLSH_STATE_LO,
1827 WCD9XXX_CLSH_REQ_ENABLE,
1828 WCD9XXX_CLSH_EVENT_POST_PA);
1829 dev_dbg(codec->dev, "%s: sleeping 3 ms after %s PA turn on\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001830 __func__, w->name);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001831 usleep_range(3000, 3010);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001832 break;
1833 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001834 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
1835 WCD9XXX_CLSH_STATE_LO,
1836 WCD9XXX_CLSH_REQ_DISABLE,
1837 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001838 break;
1839 }
1840 return 0;
1841}
1842
1843static int tapan_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1844 struct snd_kcontrol *kcontrol, int event)
1845{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001846 struct snd_soc_codec *codec = w->codec;
1847 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1848
1849 dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001850 switch (event) {
1851 case SND_SOC_DAPM_PRE_PMU:
1852 tapan->spkr_pa_widget_on = true;
1853 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
1854 break;
1855 case SND_SOC_DAPM_POST_PMD:
1856 tapan->spkr_pa_widget_on = false;
1857 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x00);
1858 break;
1859 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001860 return 0;
1861}
1862
1863static int tapan_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1864 struct snd_kcontrol *kcontrol, int event)
1865{
1866 struct snd_soc_codec *codec = w->codec;
1867 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1868 u8 dmic_clk_en;
1869 u16 dmic_clk_reg;
1870 s32 *dmic_clk_cnt;
1871 unsigned int dmic;
1872 int ret;
1873
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001874 ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001875 if (ret < 0) {
1876 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
1877 return -EINVAL;
1878 }
1879
1880 switch (dmic) {
1881 case 1:
1882 case 2:
1883 dmic_clk_en = 0x01;
1884 dmic_clk_cnt = &(tapan->dmic_1_2_clk_cnt);
1885 dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B1_CTL;
1886 dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
1887 __func__, event, dmic, *dmic_clk_cnt);
1888
1889 break;
1890
1891 case 3:
1892 case 4:
1893 dmic_clk_en = 0x10;
1894 dmic_clk_cnt = &(tapan->dmic_3_4_clk_cnt);
1895 dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B1_CTL;
1896
1897 dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
1898 __func__, event, dmic, *dmic_clk_cnt);
1899 break;
1900
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001901 default:
1902 pr_err("%s: Invalid DMIC Selection\n", __func__);
1903 return -EINVAL;
1904 }
1905
1906 switch (event) {
1907 case SND_SOC_DAPM_PRE_PMU:
1908
1909 (*dmic_clk_cnt)++;
1910 if (*dmic_clk_cnt == 1)
1911 snd_soc_update_bits(codec, dmic_clk_reg,
1912 dmic_clk_en, dmic_clk_en);
1913
1914 break;
1915 case SND_SOC_DAPM_POST_PMD:
1916
1917 (*dmic_clk_cnt)--;
1918 if (*dmic_clk_cnt == 0)
1919 snd_soc_update_bits(codec, dmic_clk_reg,
1920 dmic_clk_en, 0);
1921 break;
1922 }
1923 return 0;
1924}
1925
1926static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,
1927 struct snd_kcontrol *kcontrol, int event)
1928{
1929 struct snd_soc_codec *codec = w->codec;
1930 const char *filename;
1931 const struct firmware *fw;
1932 int i;
1933 int ret;
1934 int num_anc_slots;
Simmi Pateriyadf675e92013-04-05 01:15:54 +05301935 struct wcd9xxx_anc_header *anc_head;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001936 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1937 u32 anc_writes_size = 0;
1938 int anc_size_remaining;
1939 u32 *anc_ptr;
1940 u16 reg;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001941 u8 mask, val, old_val;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001942
1943 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001944 if (tapan->anc_func == 0)
1945 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001946 switch (event) {
1947 case SND_SOC_DAPM_PRE_PMU:
1948
1949 filename = "wcd9306/wcd9306_anc.bin";
1950
1951 ret = request_firmware(&fw, filename, codec->dev);
1952 if (ret != 0) {
1953 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1954 ret);
1955 return -ENODEV;
1956 }
1957
Simmi Pateriyadf675e92013-04-05 01:15:54 +05301958 if (fw->size < sizeof(struct wcd9xxx_anc_header)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001959 dev_err(codec->dev, "Not enough data\n");
1960 release_firmware(fw);
1961 return -ENOMEM;
1962 }
1963
1964 /* First number is the number of register writes */
Simmi Pateriyadf675e92013-04-05 01:15:54 +05301965 anc_head = (struct wcd9xxx_anc_header *)(fw->data);
1966 anc_ptr = (u32 *)((u32)fw->data +
1967 sizeof(struct wcd9xxx_anc_header));
1968 anc_size_remaining = fw->size -
1969 sizeof(struct wcd9xxx_anc_header);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001970 num_anc_slots = anc_head->num_anc_slots;
1971
1972 if (tapan->anc_slot >= num_anc_slots) {
1973 dev_err(codec->dev, "Invalid ANC slot selected\n");
1974 release_firmware(fw);
1975 return -EINVAL;
1976 }
1977
1978 for (i = 0; i < num_anc_slots; i++) {
1979
1980 if (anc_size_remaining < TAPAN_PACKED_REG_SIZE) {
1981 dev_err(codec->dev, "Invalid register format\n");
1982 release_firmware(fw);
1983 return -EINVAL;
1984 }
1985 anc_writes_size = (u32)(*anc_ptr);
1986 anc_size_remaining -= sizeof(u32);
1987 anc_ptr += 1;
1988
1989 if (anc_writes_size * TAPAN_PACKED_REG_SIZE
1990 > anc_size_remaining) {
1991 dev_err(codec->dev, "Invalid register format\n");
1992 release_firmware(fw);
1993 return -ENOMEM;
1994 }
1995
1996 if (tapan->anc_slot == i)
1997 break;
1998
1999 anc_size_remaining -= (anc_writes_size *
2000 TAPAN_PACKED_REG_SIZE);
2001 anc_ptr += anc_writes_size;
2002 }
2003 if (i == num_anc_slots) {
2004 dev_err(codec->dev, "Selected ANC slot not present\n");
2005 release_firmware(fw);
2006 return -ENOMEM;
2007 }
2008
2009 for (i = 0; i < anc_writes_size; i++) {
2010 TAPAN_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
2011 mask, val);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002012 old_val = snd_soc_read(codec, reg);
2013 snd_soc_write(codec, reg, (old_val & ~mask) |
2014 (val & mask));
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002015 }
2016 release_firmware(fw);
2017
2018 break;
Damir Didjusto1ede84a2013-05-23 16:38:11 -07002019 case SND_SOC_DAPM_PRE_PMD:
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002020 msleep(40);
2021 snd_soc_update_bits(codec, TAPAN_A_CDC_ANC1_B1_CTL, 0x01, 0x00);
2022 snd_soc_update_bits(codec, TAPAN_A_CDC_ANC2_B1_CTL, 0x02, 0x00);
2023 msleep(20);
2024 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002025 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002026 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002027 break;
2028 }
2029 return 0;
2030}
2031
2032static int tapan_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2033 struct snd_kcontrol *kcontrol, int event)
2034{
2035 struct snd_soc_codec *codec = w->codec;
2036 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2037 u16 micb_int_reg;
2038 u8 cfilt_sel_val = 0;
2039 char *internal1_text = "Internal1";
2040 char *internal2_text = "Internal2";
2041 char *internal3_text = "Internal3";
2042 enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
2043
2044 dev_dbg(codec->dev, "%s %d\n", __func__, event);
2045 switch (w->reg) {
2046 case TAPAN_A_MICB_1_CTL:
2047 micb_int_reg = TAPAN_A_MICB_1_INT_RBIAS;
2048 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias1_cfilt_sel;
2049 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
2050 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
2051 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
2052 break;
2053 case TAPAN_A_MICB_2_CTL:
2054 micb_int_reg = TAPAN_A_MICB_2_INT_RBIAS;
2055 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias2_cfilt_sel;
2056 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_2_ON;
2057 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
2058 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
2059 break;
2060 case TAPAN_A_MICB_3_CTL:
2061 micb_int_reg = TAPAN_A_MICB_3_INT_RBIAS;
2062 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias3_cfilt_sel;
2063 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
2064 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
2065 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
2066 break;
2067 default:
2068 pr_err("%s: Error, invalid micbias register\n", __func__);
2069 return -EINVAL;
2070 }
2071
2072 switch (event) {
2073 case SND_SOC_DAPM_PRE_PMU:
2074 /* Let MBHC module know so micbias switch to be off */
2075 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_pre_on);
2076
2077 /* Get cfilt */
2078 wcd9xxx_resmgr_cfilt_get(&tapan->resmgr, cfilt_sel_val);
2079
2080 if (strnstr(w->name, internal1_text, 30))
2081 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
2082 else if (strnstr(w->name, internal2_text, 30))
2083 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2084 else if (strnstr(w->name, internal3_text, 30))
2085 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2086
2087 break;
2088 case SND_SOC_DAPM_POST_PMU:
2089 usleep_range(20000, 20000);
2090 /* Let MBHC module know so micbias is on */
2091 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_on);
2092 break;
2093 case SND_SOC_DAPM_POST_PMD:
2094 /* Let MBHC module know so micbias switch to be off */
2095 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
2096
2097 if (strnstr(w->name, internal1_text, 30))
2098 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
2099 else if (strnstr(w->name, internal2_text, 30))
2100 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2101 else if (strnstr(w->name, internal3_text, 30))
2102 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2103
2104 /* Put cfilt */
2105 wcd9xxx_resmgr_cfilt_put(&tapan->resmgr, cfilt_sel_val);
2106 break;
2107 }
2108
2109 return 0;
2110}
2111
2112static void tx_hpf_corner_freq_callback(struct work_struct *work)
2113{
2114 struct delayed_work *hpf_delayed_work;
2115 struct hpf_work *hpf_work;
2116 struct tapan_priv *tapan;
2117 struct snd_soc_codec *codec;
2118 u16 tx_mux_ctl_reg;
2119 u8 hpf_cut_of_freq;
2120
2121 hpf_delayed_work = to_delayed_work(work);
2122 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2123 tapan = hpf_work->tapan;
2124 codec = hpf_work->tapan->codec;
2125 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2126
2127 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL +
2128 (hpf_work->decimator - 1) * 8;
2129
2130 dev_dbg(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
2131 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2132
2133 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
2134}
2135
2136#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
2137#define CF_MIN_3DB_4HZ 0x0
2138#define CF_MIN_3DB_75HZ 0x1
2139#define CF_MIN_3DB_150HZ 0x2
2140
2141static int tapan_codec_enable_dec(struct snd_soc_dapm_widget *w,
2142 struct snd_kcontrol *kcontrol, int event)
2143{
2144 struct snd_soc_codec *codec = w->codec;
2145 unsigned int decimator;
2146 char *dec_name = NULL;
2147 char *widget_name = NULL;
2148 char *temp;
2149 int ret = 0;
2150 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2151 u8 dec_hpf_cut_of_freq;
2152 int offset;
2153
2154 dev_dbg(codec->dev, "%s %d\n", __func__, event);
2155
2156 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2157 if (!widget_name)
2158 return -ENOMEM;
2159 temp = widget_name;
2160
2161 dec_name = strsep(&widget_name, " ");
2162 widget_name = temp;
2163 if (!dec_name) {
2164 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2165 ret = -EINVAL;
2166 goto out;
2167 }
2168
2169 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
2170 if (ret < 0) {
2171 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2172 ret = -EINVAL;
2173 goto out;
2174 }
2175
2176 dev_dbg(codec->dev, "%s(): widget = %s dec_name = %s decimator = %u\n",
2177 __func__, w->name, dec_name, decimator);
2178
2179 if (w->reg == TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
2180 dec_reset_reg = TAPAN_A_CDC_CLK_TX_RESET_B1_CTL;
2181 offset = 0;
2182 } else if (w->reg == TAPAN_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
2183 dec_reset_reg = TAPAN_A_CDC_CLK_TX_RESET_B2_CTL;
2184 offset = 8;
2185 } else {
2186 pr_err("%s: Error, incorrect dec\n", __func__);
2187 ret = -EINVAL;
2188 goto out;
2189 }
2190
2191 tx_vol_ctl_reg = TAPAN_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
2192 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2193
2194 switch (event) {
2195 case SND_SOC_DAPM_PRE_PMU:
2196
2197 /* Enableable TX digital mute */
2198 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2199
2200 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2201 1 << w->shift);
2202 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
2203
2204 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2205
2206 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
2207
2208 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2209 dec_hpf_cut_of_freq;
2210
2211 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2212
2213 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
2214 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2215 CF_MIN_3DB_150HZ << 4);
2216 }
2217
2218 /* enable HPF */
2219 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
2220
2221 break;
2222
2223 case SND_SOC_DAPM_POST_PMU:
2224
2225 /* Disable TX digital mute */
2226 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2227
2228 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2229 CF_MIN_3DB_150HZ) {
2230
2231 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2232 msecs_to_jiffies(300));
2233 }
2234 /* apply the digital gain after the decimator is enabled*/
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002235 if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002236 snd_soc_write(codec,
2237 tx_digital_gain_reg[w->shift + offset],
2238 snd_soc_read(codec,
2239 tx_digital_gain_reg[w->shift + offset])
2240 );
2241
2242 break;
2243
2244 case SND_SOC_DAPM_PRE_PMD:
2245
2246 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2247 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2248 break;
2249
2250 case SND_SOC_DAPM_POST_PMD:
2251
2252 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2253 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2254 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2255
2256 break;
2257 }
2258out:
2259 kfree(widget_name);
2260 return ret;
2261}
2262
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002263static int tapan_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
2264 struct snd_kcontrol *kcontrol, int event)
2265{
2266 struct snd_soc_codec *codec = w->codec;
2267 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
2268
2269 dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
2270
2271 switch (event) {
2272 case SND_SOC_DAPM_PRE_PMU:
2273
2274 if (spkr_drv_wrnd > 0) {
2275 WARN_ON(!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
2276 0x80));
2277 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
2278 0x00);
2279 }
2280 if (TAPAN_IS_1_0(core->version))
2281 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
2282 0x24, 0x00);
2283 break;
2284 case SND_SOC_DAPM_POST_PMD:
2285 if (TAPAN_IS_1_0(core->version))
2286 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
2287 0x24, 0x24);
2288 if (spkr_drv_wrnd > 0) {
2289 WARN_ON(!!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
2290 0x80));
2291 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
2292 0x80);
2293 }
2294 break;
2295 }
2296 return 0;
2297}
2298
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002299static int tapan_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
2300 struct snd_kcontrol *kcontrol, int event)
2301{
2302 struct snd_soc_codec *codec = w->codec;
2303
2304 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
2305
2306 switch (event) {
2307 case SND_SOC_DAPM_PRE_PMU:
2308 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_RESET_CTL,
2309 1 << w->shift, 1 << w->shift);
2310 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_RESET_CTL,
2311 1 << w->shift, 0x0);
2312 break;
2313 case SND_SOC_DAPM_POST_PMU:
2314 /* apply the digital gain after the interpolator is enabled*/
2315 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2316 snd_soc_write(codec,
2317 rx_digital_gain_reg[w->shift],
2318 snd_soc_read(codec,
2319 rx_digital_gain_reg[w->shift])
2320 );
2321 break;
2322 }
2323 return 0;
2324}
2325
2326static int tapan_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2327 struct snd_kcontrol *kcontrol, int event)
2328{
2329 switch (event) {
2330 case SND_SOC_DAPM_POST_PMU:
2331 case SND_SOC_DAPM_POST_PMD:
2332 usleep_range(1000, 1000);
2333 break;
2334 }
2335 return 0;
2336}
2337
2338static int tapan_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2339 struct snd_kcontrol *kcontrol, int event)
2340{
2341 struct snd_soc_codec *codec = w->codec;
2342 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2343
2344 dev_dbg(codec->dev, "%s %d\n", __func__, event);
2345
2346 switch (event) {
2347 case SND_SOC_DAPM_PRE_PMU:
2348 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 1);
2349 break;
2350 case SND_SOC_DAPM_POST_PMD:
2351 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 0);
2352 break;
2353 }
2354 return 0;
2355}
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002356
2357
2358static int tapan_hphl_dac_event(struct snd_soc_dapm_widget *w,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002359 struct snd_kcontrol *kcontrol, int event)
2360{
2361 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002362 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002363
2364 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2365
2366 switch (event) {
2367 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002368 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2369 0x02, 0x02);
2370 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
2371 WCD9XXX_CLSH_STATE_HPHL,
2372 WCD9XXX_CLSH_REQ_ENABLE,
2373 WCD9XXX_CLSH_EVENT_PRE_DAC);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002374 break;
2375 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002376 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2377 0x02, 0x00);
2378 }
2379 return 0;
2380}
2381
2382static int tapan_hphr_dac_event(struct snd_soc_dapm_widget *w,
2383 struct snd_kcontrol *kcontrol, int event)
2384{
2385 struct snd_soc_codec *codec = w->codec;
2386 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
2387
2388 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2389
2390 switch (event) {
2391 case SND_SOC_DAPM_PRE_PMU:
2392 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2393 0x04, 0x04);
2394 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2395 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
2396 WCD9XXX_CLSH_STATE_HPHR,
2397 WCD9XXX_CLSH_REQ_ENABLE,
2398 WCD9XXX_CLSH_EVENT_PRE_DAC);
2399 break;
2400 case SND_SOC_DAPM_POST_PMD:
2401 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2402 0x04, 0x00);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002403 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2404 break;
2405 }
2406 return 0;
2407}
2408
2409static int tapan_hph_pa_event(struct snd_soc_dapm_widget *w,
2410 struct snd_kcontrol *kcontrol, int event)
2411{
2412 struct snd_soc_codec *codec = w->codec;
2413 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2414 enum wcd9xxx_notify_event e_pre_on, e_post_off;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002415 u8 req_clsh_state;
Banajit Goswamia7294452013-06-03 12:42:35 -07002416 u32 pa_settle_time = TAPAN_HPH_PA_SETTLE_COMP_OFF;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002417
2418 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
2419 if (w->shift == 5) {
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002420 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
2421 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002422 req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
Phani Kumar Uppalapatieca9a102013-06-18 11:02:38 -07002423 } else if (w->shift == 4) {
2424 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
2425 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
2426 req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002427 } else {
2428 pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
2429 return -EINVAL;
2430 }
2431
Banajit Goswamia7294452013-06-03 12:42:35 -07002432 if (tapan->comp_enabled[COMPANDER_1])
2433 pa_settle_time = TAPAN_HPH_PA_SETTLE_COMP_ON;
2434
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002435 switch (event) {
2436 case SND_SOC_DAPM_PRE_PMU:
2437 /* Let MBHC module know PA is turning on */
2438 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_pre_on);
2439 break;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002440 case SND_SOC_DAPM_POST_PMU:
Banajit Goswamia7294452013-06-03 12:42:35 -07002441 dev_dbg(codec->dev, "%s: sleep %d ms after %s PA enable.\n",
2442 __func__, pa_settle_time / 1000, w->name);
2443 /* Time needed for PA to settle */
2444 usleep_range(pa_settle_time, pa_settle_time + 1000);
2445
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002446 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2447 req_clsh_state,
2448 WCD9XXX_CLSH_REQ_ENABLE,
2449 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002450
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002451 break;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002452 case SND_SOC_DAPM_POST_PMD:
Banajit Goswamia7294452013-06-03 12:42:35 -07002453 dev_dbg(codec->dev, "%s: sleep %d ms after %s PA disable.\n",
2454 __func__, pa_settle_time / 1000, w->name);
2455 /* Time needed for PA to settle */
2456 usleep_range(pa_settle_time, pa_settle_time + 1000);
2457
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002458 /* Let MBHC module know PA turned off */
2459 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
2460
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002461 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2462 req_clsh_state,
2463 WCD9XXX_CLSH_REQ_DISABLE,
2464 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002465 break;
2466 }
2467 return 0;
2468}
2469
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002470static int tapan_codec_enable_anc_hph(struct snd_soc_dapm_widget *w,
2471 struct snd_kcontrol *kcontrol, int event)
2472{
2473 struct snd_soc_codec *codec = w->codec;
2474 int ret = 0;
2475
2476 switch (event) {
2477 case SND_SOC_DAPM_PRE_PMU:
2478 ret = tapan_hph_pa_event(w, kcontrol, event);
2479 if (w->shift == 4) {
2480 ret |= tapan_codec_enable_anc(w, kcontrol, event);
2481 msleep(50);
2482 }
2483 break;
2484 case SND_SOC_DAPM_POST_PMU:
2485 if (w->shift == 4) {
2486 snd_soc_update_bits(codec,
2487 TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x30);
2488 msleep(30);
2489 }
2490 ret = tapan_hph_pa_event(w, kcontrol, event);
2491 break;
2492 case SND_SOC_DAPM_PRE_PMD:
2493 if (w->shift == 5) {
2494 snd_soc_update_bits(codec,
2495 TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x00);
2496 msleep(40);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002497 snd_soc_update_bits(codec,
2498 TAPAN_A_TX_7_MBHC_EN, 0x80, 00);
2499 ret |= tapan_codec_enable_anc(w, kcontrol, event);
2500 }
Damir Didjusto1ede84a2013-05-23 16:38:11 -07002501 break;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002502 case SND_SOC_DAPM_POST_PMD:
2503 ret = tapan_hph_pa_event(w, kcontrol, event);
2504 break;
2505 }
2506 return ret;
2507}
2508
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002509static const struct snd_soc_dapm_widget tapan_dapm_i2s_widgets[] = {
2510 SND_SOC_DAPM_SUPPLY("I2S_CLK", TAPAN_A_CDC_CLK_I2S_CTL,
2511 4, 0, NULL, 0),
2512};
2513
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002514static int tapan_lineout_dac_event(struct snd_soc_dapm_widget *w,
2515 struct snd_kcontrol *kcontrol, int event)
2516{
2517 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002518 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002519
2520 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2521
2522 switch (event) {
2523 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002524 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2525 WCD9XXX_CLSH_STATE_LO,
2526 WCD9XXX_CLSH_REQ_ENABLE,
2527 WCD9XXX_CLSH_EVENT_PRE_DAC);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002528 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2529 break;
2530
2531 case SND_SOC_DAPM_POST_PMD:
2532 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2533 break;
2534 }
2535 return 0;
2536}
2537
2538static int tapan_spk_dac_event(struct snd_soc_dapm_widget *w,
2539 struct snd_kcontrol *kcontrol, int event)
2540{
2541 struct snd_soc_codec *codec = w->codec;
2542
2543 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2544 return 0;
2545}
2546
2547static const struct snd_soc_dapm_route audio_i2s_map[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002548 {"I2S_CLK", NULL, "CDC_CONN"},
2549 {"SLIM RX1", NULL, "I2S_CLK"},
2550 {"SLIM RX2", NULL, "I2S_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002551
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002552 {"SLIM TX1 MUX", NULL, "I2S_CLK"},
2553 {"SLIM TX2 MUX", NULL, "I2S_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002554};
2555
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07002556static const struct snd_soc_dapm_route wcd9306_map[] = {
2557 {"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
2558 {"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
2559 {"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
2560 {"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
2561 {"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002562 {"SLIM TX1 MUX", "DEC3", "DEC3 MUX"},
2563 {"SLIM TX1 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002564 {"SLIM TX2 MUX", "DEC3", "DEC3 MUX"},
2565 {"SLIM TX2 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002566 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002567 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002568
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002569 {"ANC EAR", NULL, "ANC EAR PA"},
2570 {"ANC EAR PA", NULL, "EAR_PA_MIXER"},
2571 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
2572 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
2573
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002574 {"ANC HEADPHONE", NULL, "ANC HPHL"},
2575 {"ANC HEADPHONE", NULL, "ANC HPHR"},
2576
2577 {"ANC HPHL", NULL, "HPHL_PA_MIXER"},
2578 {"ANC HPHR", NULL, "HPHR_PA_MIXER"},
2579
2580 {"ANC1 MUX", "ADC1", "ADC1"},
2581 {"ANC1 MUX", "ADC2", "ADC2"},
2582 {"ANC1 MUX", "ADC3", "ADC3"},
2583 {"ANC1 MUX", "ADC4", "ADC4"},
2584 {"ANC1 MUX", "ADC5", "ADC5"},
2585 {"ANC1 MUX", "DMIC1", "DMIC1"},
2586 {"ANC1 MUX", "DMIC2", "DMIC2"},
2587 {"ANC1 MUX", "DMIC3", "DMIC3"},
2588 {"ANC1 MUX", "DMIC4", "DMIC4"},
2589 {"ANC2 MUX", "ADC1", "ADC1"},
2590 {"ANC2 MUX", "ADC2", "ADC2"},
2591 {"ANC2 MUX", "ADC3", "ADC3"},
2592 {"ANC2 MUX", "ADC4", "ADC4"},
2593 {"ANC2 MUX", "ADC5", "ADC5"},
2594 {"ANC2 MUX", "DMIC1", "DMIC1"},
2595 {"ANC2 MUX", "DMIC2", "DMIC2"},
2596 {"ANC2 MUX", "DMIC3", "DMIC3"},
2597 {"ANC2 MUX", "DMIC4", "DMIC4"},
2598
2599 {"ANC HPHR", NULL, "CDC_CONN"},
2600
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07002601 {"RDAC5 MUX", "DEM4", "RX4 MIX2"},
2602 {"SPK DAC", "Switch", "RX4 MIX2"},
2603
2604 {"RX1 MIX2", NULL, "ANC1 MUX"},
2605 {"RX2 MIX2", NULL, "ANC2 MUX"},
2606
2607 {"RX1 MIX1", NULL, "COMP1_CLK"},
2608 {"RX2 MIX1", NULL, "COMP1_CLK"},
2609 {"RX3 MIX1", NULL, "COMP2_CLK"},
2610 {"RX4 MIX1", NULL, "COMP0_CLK"},
2611
2612 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2613 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2614 {"RX4 MIX2", NULL, "RX4 MIX1"},
2615 {"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
2616 {"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
2617
2618 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2619 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
2620 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2621 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
2622 {"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
2623 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
2624 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2625 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
2626 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2627 {"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
2628 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
2629 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
2630 {"RX4 MIX2 INP1", "IIR1", "IIR1"},
2631 {"RX4 MIX2 INP2", "IIR1", "IIR1"},
2632
2633 {"DEC1 MUX", "DMIC3", "DMIC3"},
2634 {"DEC1 MUX", "DMIC4", "DMIC4"},
2635 {"DEC2 MUX", "DMIC3", "DMIC3"},
2636 {"DEC2 MUX", "DMIC4", "DMIC4"},
2637
2638 {"DEC3 MUX", "ADC1", "ADC1"},
2639 {"DEC3 MUX", "ADC2", "ADC2"},
2640 {"DEC3 MUX", "ADC3", "ADC3"},
2641 {"DEC3 MUX", "ADC4", "ADC4"},
2642 {"DEC3 MUX", "ADC5", "ADC5"},
2643 {"DEC3 MUX", "DMIC1", "DMIC1"},
2644 {"DEC3 MUX", "DMIC2", "DMIC2"},
2645 {"DEC3 MUX", "DMIC3", "DMIC3"},
2646 {"DEC3 MUX", "DMIC4", "DMIC4"},
2647 {"DEC3 MUX", NULL, "CDC_CONN"},
2648
2649 {"DEC4 MUX", "ADC1", "ADC1"},
2650 {"DEC4 MUX", "ADC2", "ADC2"},
2651 {"DEC4 MUX", "ADC3", "ADC3"},
2652 {"DEC4 MUX", "ADC4", "ADC4"},
2653 {"DEC4 MUX", "ADC5", "ADC5"},
2654 {"DEC4 MUX", "DMIC1", "DMIC1"},
2655 {"DEC4 MUX", "DMIC2", "DMIC2"},
2656 {"DEC4 MUX", "DMIC3", "DMIC3"},
2657 {"DEC4 MUX", "DMIC4", "DMIC4"},
2658 {"DEC4 MUX", NULL, "CDC_CONN"},
2659
2660 {"ADC5", NULL, "AMIC5"},
2661
2662 {"AUX_PGA_Left", NULL, "AMIC5"},
2663
2664 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2665 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2666
2667 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2668 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2669 {"MIC BIAS3 External", NULL, "LDO_H"},
2670};
2671
2672static const struct snd_soc_dapm_route audio_map[] = {
2673 /* SLIMBUS Connections */
2674 {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
2675 {"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
2676 {"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
2677
2678 /* SLIM_MIXER("AIF1_CAP Mixer"),*/
2679 {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2680 {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2681 {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2682 {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2683 {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
2684 /* SLIM_MIXER("AIF2_CAP Mixer"),*/
2685 {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2686 {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2687 {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2688 {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2689 {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
2690 /* SLIM_MIXER("AIF3_CAP Mixer"),*/
2691 {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2692 {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2693 {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2694 {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2695 {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
2696
2697 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2698 {"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
2699 {"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
2700 {"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
2701 {"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
2702
2703 {"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
2704 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
2705 {"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
2706 {"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
2707 {"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
2708
2709 {"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
2710 {"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
2711 {"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
2712
2713 {"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
2714 {"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
2715 {"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
2716
2717 {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
2718 {"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
2719 {"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
2720 {"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
2721
2722 /* Earpiece (RX MIX1) */
2723 {"EAR", NULL, "EAR PA"},
2724 {"EAR PA", NULL, "EAR_PA_MIXER"},
2725 {"EAR_PA_MIXER", NULL, "DAC1"},
2726 {"DAC1", NULL, "RX_BIAS"},
2727 {"DAC1", NULL, "CDC_CP_VDD"},
2728
2729
2730 /* Headset (RX MIX1 and RX MIX2) */
2731 {"HEADPHONE", NULL, "HPHL"},
2732 {"HEADPHONE", NULL, "HPHR"},
2733
2734 {"HPHL", NULL, "HPHL_PA_MIXER"},
2735 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
2736 {"HPHL DAC", NULL, "RX_BIAS"},
2737 {"HPHL DAC", NULL, "CDC_CP_VDD"},
2738
2739 {"HPHR", NULL, "HPHR_PA_MIXER"},
2740 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
2741 {"HPHR DAC", NULL, "RX_BIAS"},
2742 {"HPHR DAC", NULL, "CDC_CP_VDD"},
2743
2744
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002745 {"DAC1", "Switch", "CLASS_H_DSM MUX"},
2746 {"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002747 {"HPHR DAC", NULL, "RX2 CHAIN"},
2748
2749 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2750 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002751 {"SPK_OUT", NULL, "SPK PA"},
2752
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002753 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2754 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002755 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2756 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2757
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002758 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2759
2760 {"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002761 {"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002762
2763 {"SPK PA", NULL, "SPK DAC"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002764 {"SPK DAC", NULL, "VDD_SPKDRV"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002765
2766 {"RX1 CHAIN", NULL, "RX1 MIX2"},
2767 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002768 {"CLASS_H_DSM MUX", "RX_HPHL", "RX1 CHAIN"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002769
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002770 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2771 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07002772 {"LINEOUT1 DAC", NULL, "CDC_CP_VDD"},
2773 {"LINEOUT2 DAC", NULL, "CDC_CP_VDD"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002774
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07002775 {"RDAC3 MUX", "DEM2", "RX2 MIX1"},
2776 {"RDAC3 MUX", "DEM1", "RX1 CHAIN"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002777
2778 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2779 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2780 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
2781 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2782 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2783 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2784 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002785 {"RX1 MIX2", NULL, "RX1 MIX1"},
2786 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
2787 {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
2788 {"RX2 MIX2", NULL, "RX2 MIX1"},
2789 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
2790 {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002791
2792 /* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
2793 {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
2794 {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
2795 {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
2796 {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
2797 {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002798 /* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
2799 {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
2800 {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
2801 {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
2802 {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
2803 {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002804 /* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
2805 {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
2806 {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
2807 {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
2808 {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
2809 {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002810
2811 {"SLIM RX1", NULL, "SLIM RX1 MUX"},
2812 {"SLIM RX2", NULL, "SLIM RX2 MUX"},
2813 {"SLIM RX3", NULL, "SLIM RX3 MUX"},
2814 {"SLIM RX4", NULL, "SLIM RX4 MUX"},
2815 {"SLIM RX5", NULL, "SLIM RX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002816
2817 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2818 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
2819 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2820 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
2821 {"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002822 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2823 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2824 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
2825 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2826 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
2827 {"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002828 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2829 {"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
2830 {"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
2831 {"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
2832 {"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
2833 {"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002834 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2835 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
2836 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2837 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
2838 {"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002839 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
2840 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2841 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
2842 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2843 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
2844 {"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002845 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
2846 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2847 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
2848 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2849 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
2850 {"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002851 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
2852 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2853 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
2854 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2855 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
2856 {"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002857 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002858
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002859 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
2860 {"RX1 MIX2 INP2", "IIR1", "IIR1"},
2861 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
2862 {"RX2 MIX2 INP2", "IIR1", "IIR1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002863
2864 /* Decimator Inputs */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002865 {"DEC1 MUX", "ADC1", "ADC1"},
2866 {"DEC1 MUX", "ADC2", "ADC2"},
2867 {"DEC1 MUX", "ADC3", "ADC3"},
2868 {"DEC1 MUX", "ADC4", "ADC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002869 {"DEC1 MUX", "DMIC1", "DMIC1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002870 {"DEC1 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002871 {"DEC1 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002872
2873 {"DEC2 MUX", "ADC1", "ADC1"},
2874 {"DEC2 MUX", "ADC2", "ADC2"},
2875 {"DEC2 MUX", "ADC3", "ADC3"},
2876 {"DEC2 MUX", "ADC4", "ADC4"},
2877 {"DEC2 MUX", "DMIC1", "DMIC1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002878 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002879 {"DEC2 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002880
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002881 /* ADC Connections */
2882 {"ADC1", NULL, "AMIC1"},
2883 {"ADC2", NULL, "AMIC2"},
2884 {"ADC3", NULL, "AMIC3"},
2885 {"ADC4", NULL, "AMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002886
2887 /* AUX PGA Connections */
2888 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2889 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2890 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2891 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2892 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002893
2894 {"IIR1", NULL, "IIR1 INP1 MUX"},
2895 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2896 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002897
2898 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2899 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2900 {"MIC BIAS1 External", NULL, "LDO_H"},
2901 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2902 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2903 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2904 {"MIC BIAS2 External", NULL, "LDO_H"},
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07002905};
2906
2907static const struct snd_soc_dapm_route wcd9302_map[] = {
2908 {"SPK DAC", "Switch", "RX3 MIX1"},
2909
2910 {"RDAC4 MUX", "DEM3", "RX3 MIX1"},
2911 {"RDAC4 MUX", "DEM2", "RX2 CHAIN"},
2912 {"LINEOUT1 DAC", NULL, "RDAC4 MUX"},
2913
2914 {"RDAC5 MUX", "DEM4", "RX3 MIX1"},
2915 {"RDAC5 MUX", "DEM3_INV", "RDAC4 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002916};
2917
2918static int tapan_readable(struct snd_soc_codec *ssc, unsigned int reg)
2919{
2920 return tapan_reg_readable[reg];
2921}
2922
2923static bool tapan_is_digital_gain_register(unsigned int reg)
2924{
2925 bool rtn = false;
2926 switch (reg) {
2927 case TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL:
2928 case TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL:
2929 case TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL:
2930 case TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL:
2931 case TAPAN_A_CDC_TX1_VOL_CTL_GAIN:
2932 case TAPAN_A_CDC_TX2_VOL_CTL_GAIN:
2933 case TAPAN_A_CDC_TX3_VOL_CTL_GAIN:
2934 case TAPAN_A_CDC_TX4_VOL_CTL_GAIN:
2935 rtn = true;
2936 break;
2937 default:
2938 break;
2939 }
2940 return rtn;
2941}
2942
2943static int tapan_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2944{
2945 /* Registers lower than 0x100 are top level registers which can be
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002946 * written by the Tapan core driver.
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002947 */
2948
2949 if ((reg >= TAPAN_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2950 return 1;
2951
2952 /* IIR Coeff registers are not cacheable */
2953 if ((reg >= TAPAN_A_CDC_IIR1_COEF_B1_CTL) &&
2954 (reg <= TAPAN_A_CDC_IIR2_COEF_B2_CTL))
2955 return 1;
2956
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002957 /* ANC filter registers are not cacheable */
2958 if ((reg >= TAPAN_A_CDC_ANC1_IIR_B1_CTL) &&
2959 (reg <= TAPAN_A_CDC_ANC1_LPF_B2_CTL))
2960 return 1;
2961 if ((reg >= TAPAN_A_CDC_ANC2_IIR_B1_CTL) &&
2962 (reg <= TAPAN_A_CDC_ANC2_LPF_B2_CTL))
2963 return 1;
2964
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002965 /* Digital gain register is not cacheable so we have to write
2966 * the setting even it is the same
2967 */
2968 if (tapan_is_digital_gain_register(reg))
2969 return 1;
2970
2971 /* HPH status registers */
2972 if (reg == TAPAN_A_RX_HPH_L_STATUS || reg == TAPAN_A_RX_HPH_R_STATUS)
2973 return 1;
2974
2975 if (reg == TAPAN_A_MBHC_INSERT_DET_STATUS)
2976 return 1;
2977
2978 return 0;
2979}
2980
2981#define TAPAN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2982static int tapan_write(struct snd_soc_codec *codec, unsigned int reg,
2983 unsigned int value)
2984{
2985 int ret;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07002986 struct wcd9xxx *wcd9xxx = codec->control_data;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002987
2988 if (reg == SND_SOC_NOPM)
2989 return 0;
2990
2991 BUG_ON(reg > TAPAN_MAX_REGISTER);
2992
2993 if (!tapan_volatile(codec, reg)) {
2994 ret = snd_soc_cache_write(codec, reg, value);
2995 if (ret != 0)
2996 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2997 reg, ret);
2998 }
2999
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07003000 return wcd9xxx_reg_write(&wcd9xxx->core_res, reg, value);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003001}
3002static unsigned int tapan_read(struct snd_soc_codec *codec,
3003 unsigned int reg)
3004{
3005 unsigned int val;
3006 int ret;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07003007 struct wcd9xxx *wcd9xxx = codec->control_data;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003008
3009 if (reg == SND_SOC_NOPM)
3010 return 0;
3011
3012 BUG_ON(reg > TAPAN_MAX_REGISTER);
3013
3014 if (!tapan_volatile(codec, reg) && tapan_readable(codec, reg) &&
3015 reg < codec->driver->reg_cache_size) {
3016 ret = snd_soc_cache_read(codec, reg, &val);
3017 if (ret >= 0) {
3018 return val;
3019 } else
3020 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3021 reg, ret);
3022 }
3023
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07003024 val = wcd9xxx_reg_read(&wcd9xxx->core_res, reg);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003025 return val;
3026}
3027
3028static int tapan_startup(struct snd_pcm_substream *substream,
3029 struct snd_soc_dai *dai)
3030{
3031 struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
3032 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
3033 __func__, substream->name, substream->stream);
3034 if ((tapan_core != NULL) &&
3035 (tapan_core->dev != NULL) &&
3036 (tapan_core->dev->parent != NULL))
3037 pm_runtime_get_sync(tapan_core->dev->parent);
3038
3039 return 0;
3040}
3041
3042static void tapan_shutdown(struct snd_pcm_substream *substream,
3043 struct snd_soc_dai *dai)
3044{
3045 struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
3046 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
3047 __func__, substream->name, substream->stream);
3048 if ((tapan_core != NULL) &&
3049 (tapan_core->dev != NULL) &&
3050 (tapan_core->dev->parent != NULL)) {
3051 pm_runtime_mark_last_busy(tapan_core->dev->parent);
3052 pm_runtime_put(tapan_core->dev->parent);
3053 }
3054}
3055
Bhalchandra Gajare4e3dd852013-08-19 17:21:23 -07003056static void tapan_set_vdd_cx_current(struct snd_soc_codec *codec,
3057 int current_uA)
3058{
3059 struct regulator *cx_regulator;
3060 int ret;
3061
3062 cx_regulator = tapan_codec_find_regulator(codec,
3063 "cdc-vdd-cx");
3064
3065 if (!cx_regulator) {
3066 dev_err(codec->dev, "%s: Regulator %s not defined\n",
3067 __func__, "cdc-vdd-cx-supply");
3068 return;
3069 }
3070
3071 ret = regulator_set_optimum_mode(cx_regulator, current_uA);
3072 if (ret < 0)
3073 dev_err(codec->dev,
3074 "%s: Failed to set vdd_cx current to %d\n",
3075 __func__, current_uA);
3076}
3077
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003078int tapan_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
3079{
3080 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3081
3082 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n", __func__,
3083 mclk_enable, dapm);
3084
Joonwoo Park533b3682013-06-13 11:41:21 -07003085 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003086 if (mclk_enable) {
Bhalchandra Gajare4e3dd852013-08-19 17:21:23 -07003087 tapan_set_vdd_cx_current(codec, TAPAN_VDD_CX_OPTIMAL_UA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003088 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
3089 WCD9XXX_BANDGAP_AUDIO_MODE);
3090 wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
3091 } else {
3092 /* Put clock and BG */
3093 wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
3094 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
3095 WCD9XXX_BANDGAP_AUDIO_MODE);
Bhalchandra Gajare4e3dd852013-08-19 17:21:23 -07003096 /* Set the vdd cx power rail sleep mode current */
3097 tapan_set_vdd_cx_current(codec, TAPAN_VDD_CX_SLEEP_UA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003098 }
Joonwoo Park533b3682013-06-13 11:41:21 -07003099 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003100
3101 return 0;
3102}
3103
3104static int tapan_set_dai_sysclk(struct snd_soc_dai *dai,
3105 int clk_id, unsigned int freq, int dir)
3106{
3107 dev_dbg(dai->codec->dev, "%s\n", __func__);
3108 return 0;
3109}
3110
3111static int tapan_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3112{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003113 u8 val = 0;
3114 struct snd_soc_codec *codec = dai->codec;
3115 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3116
3117 dev_dbg(codec->dev, "%s\n", __func__);
3118 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3119 case SND_SOC_DAIFMT_CBS_CFS:
3120 /* CPU is master */
3121 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3122 if (dai->id == AIF1_CAP)
3123 snd_soc_update_bits(codec,
3124 TAPAN_A_CDC_CLK_I2S_CTL,
3125 TAPAN_I2S_MASTER_MODE_MASK, 0);
3126 else if (dai->id == AIF1_PB)
3127 snd_soc_update_bits(codec,
3128 TAPAN_A_CDC_CLK_I2S_CTL,
3129 TAPAN_I2S_MASTER_MODE_MASK, 0);
3130 }
3131 break;
3132 case SND_SOC_DAIFMT_CBM_CFM:
3133 /* CPU is slave */
3134 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3135 val = TAPAN_I2S_MASTER_MODE_MASK;
3136 if (dai->id == AIF1_CAP)
3137 snd_soc_update_bits(codec,
3138 TAPAN_A_CDC_CLK_I2S_CTL, val, val);
3139 else if (dai->id == AIF1_PB)
3140 snd_soc_update_bits(codec,
3141 TAPAN_A_CDC_CLK_I2S_CTL, val, val);
3142 }
3143 break;
3144 default:
3145 return -EINVAL;
3146 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003147 return 0;
3148}
3149
3150static int tapan_set_channel_map(struct snd_soc_dai *dai,
3151 unsigned int tx_num, unsigned int *tx_slot,
3152 unsigned int rx_num, unsigned int *rx_slot)
3153
3154{
3155 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
3156 struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
3157 if (!tx_slot && !rx_slot) {
3158 pr_err("%s: Invalid\n", __func__);
3159 return -EINVAL;
3160 }
3161 dev_dbg(dai->codec->dev, "%s(): dai_name = %s DAI-ID %x\n",
3162 __func__, dai->name, dai->id);
3163 dev_dbg(dai->codec->dev, "%s(): tx_ch %d rx_ch %d\n intf_type %d\n",
3164 __func__, tx_num, rx_num, tapan->intf_type);
3165
3166 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3167 wcd9xxx_init_slimslave(core, core->slim->laddr,
3168 tx_num, tx_slot, rx_num, rx_slot);
3169 return 0;
3170}
3171
3172static int tapan_get_channel_map(struct snd_soc_dai *dai,
3173 unsigned int *tx_num, unsigned int *tx_slot,
3174 unsigned int *rx_num, unsigned int *rx_slot)
3175
3176{
3177 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(dai->codec);
3178 u32 i = 0;
3179 struct wcd9xxx_ch *ch;
3180
3181 switch (dai->id) {
3182 case AIF1_PB:
3183 case AIF2_PB:
3184 case AIF3_PB:
3185 if (!rx_slot || !rx_num) {
3186 pr_err("%s: Invalid rx_slot %d or rx_num %d\n",
3187 __func__, (u32) rx_slot, (u32) rx_num);
3188 return -EINVAL;
3189 }
3190 list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
3191 list) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003192 dev_dbg(dai->codec->dev, "%s: rx_slot[%d] %d, ch->ch_num %d\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003193 __func__, i, rx_slot[i], ch->ch_num);
3194 rx_slot[i++] = ch->ch_num;
3195 }
3196 dev_dbg(dai->codec->dev, "%s: rx_num %d\n", __func__, i);
3197 *rx_num = i;
3198 break;
3199 case AIF1_CAP:
3200 case AIF2_CAP:
3201 case AIF3_CAP:
3202 if (!tx_slot || !tx_num) {
3203 pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
3204 __func__, (u32) tx_slot, (u32) tx_num);
3205 return -EINVAL;
3206 }
3207 list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
3208 list) {
3209 dev_dbg(dai->codec->dev, "%s: tx_slot[%d] %d, ch->ch_num %d\n",
3210 __func__, i, tx_slot[i], ch->ch_num);
3211 tx_slot[i++] = ch->ch_num;
3212 }
3213 dev_dbg(dai->codec->dev, "%s: tx_num %d\n", __func__, i);
3214 *tx_num = i;
3215 break;
3216
3217 default:
3218 pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id);
3219 break;
3220 }
3221
3222 return 0;
3223}
3224
3225static int tapan_set_interpolator_rate(struct snd_soc_dai *dai,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003226 u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003227{
3228 u32 j;
3229 u8 rx_mix1_inp;
3230 u16 rx_mix_1_reg_1, rx_mix_1_reg_2;
3231 u16 rx_fs_reg;
3232 u8 rx_mix_1_reg_1_val, rx_mix_1_reg_2_val;
Banajit Goswamia7294452013-06-03 12:42:35 -07003233 u8 rdac5_mux;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003234 struct snd_soc_codec *codec = dai->codec;
3235 struct wcd9xxx_ch *ch;
3236 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3237
3238 list_for_each_entry(ch, &tapan->dai[dai->id].wcd9xxx_ch_list, list) {
3239 /* for RX port starting from 16 instead of 10 like tabla */
3240 rx_mix1_inp = ch->port + RX_MIX1_INP_SEL_RX1 -
3241 TAPAN_TX_PORT_NUMBER;
3242 if ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003243 (rx_mix1_inp > RX_MIX1_INP_SEL_RX5)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003244 pr_err("%s: Invalid TAPAN_RX%u port. Dai ID is %d\n",
3245 __func__, rx_mix1_inp - 5 , dai->id);
3246 return -EINVAL;
3247 }
3248
3249 rx_mix_1_reg_1 = TAPAN_A_CDC_CONN_RX1_B1_CTL;
3250
Banajit Goswamia7294452013-06-03 12:42:35 -07003251 rdac5_mux = snd_soc_read(codec, TAPAN_A_CDC_CONN_MISC);
3252 rdac5_mux = (rdac5_mux & 0x04) >> 2;
3253
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003254 for (j = 0; j < NUM_INTERPOLATORS; j++) {
3255 rx_mix_1_reg_2 = rx_mix_1_reg_1 + 1;
3256
3257 rx_mix_1_reg_1_val = snd_soc_read(codec,
3258 rx_mix_1_reg_1);
3259 rx_mix_1_reg_2_val = snd_soc_read(codec,
3260 rx_mix_1_reg_2);
3261
3262 if (((rx_mix_1_reg_1_val & 0x0F) == rx_mix1_inp) ||
3263 (((rx_mix_1_reg_1_val >> 4) & 0x0F)
3264 == rx_mix1_inp) ||
3265 ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
3266
3267 rx_fs_reg = TAPAN_A_CDC_RX1_B5_CTL + 8 * j;
3268
3269 dev_dbg(codec->dev, "%s: AIF_PB DAI(%d) connected to RX%u\n",
3270 __func__, dai->id, j + 1);
3271
3272 dev_dbg(codec->dev, "%s: set RX%u sample rate to %u\n",
3273 __func__, j + 1, sample_rate);
3274
3275 snd_soc_update_bits(codec, rx_fs_reg,
3276 0xE0, rx_fs_rate_reg_val);
3277
Banajit Goswamia7294452013-06-03 12:42:35 -07003278 if (comp_rx_path[j] < COMPANDER_MAX) {
3279 if ((j == 3) && (rdac5_mux == 1))
3280 tapan->comp_fs[COMPANDER_0] =
3281 compander_fs;
3282 else
3283 tapan->comp_fs[comp_rx_path[j]]
3284 = compander_fs;
3285 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003286 }
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07003287 if (j <= 1)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003288 rx_mix_1_reg_1 += 3;
3289 else
3290 rx_mix_1_reg_1 += 2;
3291 }
3292 }
3293 return 0;
3294}
3295
3296static int tapan_set_decimator_rate(struct snd_soc_dai *dai,
3297 u8 tx_fs_rate_reg_val, u32 sample_rate)
3298{
3299 struct snd_soc_codec *codec = dai->codec;
3300 struct wcd9xxx_ch *ch;
3301 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3302 u32 tx_port;
3303 u16 tx_port_reg, tx_fs_reg;
3304 u8 tx_port_reg_val;
3305 s8 decimator;
3306
3307 list_for_each_entry(ch, &tapan->dai[dai->id].wcd9xxx_ch_list, list) {
3308
3309 tx_port = ch->port + 1;
3310 dev_dbg(codec->dev, "%s: dai->id = %d, tx_port = %d",
3311 __func__, dai->id, tx_port);
3312
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003313 if ((tx_port < 1) || (tx_port > TAPAN_SLIM_CODEC_TX_PORTS)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003314 pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
3315 __func__, tx_port, dai->id);
3316 return -EINVAL;
3317 }
3318
3319 tx_port_reg = TAPAN_A_CDC_CONN_TX_SB_B1_CTL + (tx_port - 1);
3320 tx_port_reg_val = snd_soc_read(codec, tx_port_reg);
3321
3322 decimator = 0;
3323
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003324 tx_port_reg_val = tx_port_reg_val & 0x0F;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003325
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003326 if ((tx_port_reg_val >= 0x8) &&
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003327 (tx_port_reg_val <= 0x11)) {
3328
3329 decimator = (tx_port_reg_val - 0x8) + 1;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003330 }
3331
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003332
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003333 if (decimator) { /* SLIM_TX port has a DEC as input */
3334
3335 tx_fs_reg = TAPAN_A_CDC_TX1_CLK_FS_CTL +
3336 8 * (decimator - 1);
3337
3338 dev_dbg(codec->dev, "%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
3339 __func__, decimator, tx_port, sample_rate);
3340
3341 snd_soc_update_bits(codec, tx_fs_reg, 0x07,
3342 tx_fs_rate_reg_val);
3343
3344 } else {
3345 if ((tx_port_reg_val >= 0x1) &&
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003346 (tx_port_reg_val <= 0x4)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003347
3348 dev_dbg(codec->dev, "%s: RMIX%u going to SLIM TX%u\n",
3349 __func__, tx_port_reg_val, tx_port);
3350
3351 } else if ((tx_port_reg_val >= 0x8) &&
3352 (tx_port_reg_val <= 0x11)) {
3353
3354 pr_err("%s: ERROR: Should not be here\n",
3355 __func__);
3356 pr_err("%s: ERROR: DEC connected to SLIM TX%u\n",
3357 __func__, tx_port);
3358 return -EINVAL;
3359
3360 } else if (tx_port_reg_val == 0) {
3361 dev_dbg(codec->dev, "%s: no signal to SLIM TX%u\n",
3362 __func__, tx_port);
3363 } else {
3364 pr_err("%s: ERROR: wrong signal to SLIM TX%u\n",
3365 __func__, tx_port);
3366 pr_err("%s: ERROR: wrong signal = %u\n",
3367 __func__, tx_port_reg_val);
3368 return -EINVAL;
3369 }
3370 }
3371 }
3372 return 0;
3373}
3374
3375static int tapan_hw_params(struct snd_pcm_substream *substream,
3376 struct snd_pcm_hw_params *params,
3377 struct snd_soc_dai *dai)
3378{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003379 struct snd_soc_codec *codec = dai->codec;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003380 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
3381 u8 tx_fs_rate, rx_fs_rate;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003382 u32 compander_fs;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003383 int ret;
3384
3385 dev_dbg(dai->codec->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n",
3386 __func__, dai->name, dai->id,
3387 params_rate(params), params_channels(params));
3388
3389 switch (params_rate(params)) {
3390 case 8000:
3391 tx_fs_rate = 0x00;
3392 rx_fs_rate = 0x00;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003393 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003394 break;
3395 case 16000:
3396 tx_fs_rate = 0x01;
3397 rx_fs_rate = 0x20;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003398 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003399 break;
3400 case 32000:
3401 tx_fs_rate = 0x02;
3402 rx_fs_rate = 0x40;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003403 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003404 break;
3405 case 48000:
3406 tx_fs_rate = 0x03;
3407 rx_fs_rate = 0x60;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003408 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003409 break;
3410 case 96000:
3411 tx_fs_rate = 0x04;
3412 rx_fs_rate = 0x80;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003413 compander_fs = COMPANDER_FS_96KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003414 break;
3415 case 192000:
3416 tx_fs_rate = 0x05;
3417 rx_fs_rate = 0xA0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003418 compander_fs = COMPANDER_FS_192KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003419 break;
3420 default:
3421 pr_err("%s: Invalid sampling rate %d\n", __func__,
3422 params_rate(params));
3423 return -EINVAL;
3424 }
3425
3426 switch (substream->stream) {
3427 case SNDRV_PCM_STREAM_CAPTURE:
3428 ret = tapan_set_decimator_rate(dai, tx_fs_rate,
3429 params_rate(params));
3430 if (ret < 0) {
3431 pr_err("%s: set decimator rate failed %d\n", __func__,
3432 ret);
3433 return ret;
3434 }
3435
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003436 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3437 switch (params_format(params)) {
3438 case SNDRV_PCM_FORMAT_S16_LE:
3439 snd_soc_update_bits(codec,
3440 TAPAN_A_CDC_CLK_I2S_CTL,
3441 0x20, 0x20);
3442 break;
3443 case SNDRV_PCM_FORMAT_S32_LE:
3444 snd_soc_update_bits(codec,
3445 TAPAN_A_CDC_CLK_I2S_CTL,
3446 0x20, 0x00);
3447 break;
3448 default:
3449 pr_err("invalid format\n");
3450 break;
3451 }
3452 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
3453 0x07, tx_fs_rate);
3454 } else {
3455 tapan->dai[dai->id].rate = params_rate(params);
3456 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003457 break;
3458
3459 case SNDRV_PCM_STREAM_PLAYBACK:
3460 ret = tapan_set_interpolator_rate(dai, rx_fs_rate,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003461 compander_fs,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003462 params_rate(params));
3463 if (ret < 0) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003464 dev_err(codec->dev, "%s: set decimator rate failed %d\n",
3465 __func__, ret);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003466 return ret;
3467 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003468 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3469 switch (params_format(params)) {
3470 case SNDRV_PCM_FORMAT_S16_LE:
3471 snd_soc_update_bits(codec,
3472 TAPAN_A_CDC_CLK_I2S_CTL,
3473 0x20, 0x20);
3474 break;
3475 case SNDRV_PCM_FORMAT_S32_LE:
3476 snd_soc_update_bits(codec,
3477 TAPAN_A_CDC_CLK_I2S_CTL,
3478 0x20, 0x00);
3479 break;
3480 default:
3481 dev_err(codec->dev, "invalid format\n");
3482 break;
3483 }
3484 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
3485 0x03, (rx_fs_rate >> 0x05));
3486 } else {
3487 switch (params_format(params)) {
3488 case SNDRV_PCM_FORMAT_S16_LE:
3489 snd_soc_update_bits(codec,
3490 TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
3491 0xFF, 0xAA);
3492 snd_soc_update_bits(codec,
3493 TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
3494 0xFF, 0x2A);
3495 tapan->dai[dai->id].bit_width = 16;
3496 break;
3497 case SNDRV_PCM_FORMAT_S24_LE:
3498 snd_soc_update_bits(codec,
3499 TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
3500 0xFF, 0x00);
3501 snd_soc_update_bits(codec,
3502 TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
3503 0xFF, 0x00);
3504 tapan->dai[dai->id].bit_width = 24;
3505 break;
3506 default:
3507 dev_err(codec->dev, "Invalid format\n");
3508 break;
3509 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003510 tapan->dai[dai->id].rate = params_rate(params);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003511 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003512 break;
3513 default:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003514 dev_err(codec->dev, "%s: Invalid stream type %d\n", __func__,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003515 substream->stream);
3516 return -EINVAL;
3517 }
3518
3519 return 0;
3520}
3521
3522static struct snd_soc_dai_ops tapan_dai_ops = {
3523 .startup = tapan_startup,
3524 .shutdown = tapan_shutdown,
3525 .hw_params = tapan_hw_params,
3526 .set_sysclk = tapan_set_dai_sysclk,
3527 .set_fmt = tapan_set_dai_fmt,
3528 .set_channel_map = tapan_set_channel_map,
3529 .get_channel_map = tapan_get_channel_map,
3530};
3531
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07003532static struct snd_soc_dai_driver tapan9302_dai[] = {
3533 {
3534 .name = "tapan9302_rx1",
3535 .id = AIF1_PB,
3536 .playback = {
3537 .stream_name = "AIF1 Playback",
3538 .rates = WCD9302_RATES,
3539 .formats = TAPAN_FORMATS,
3540 .rate_max = 48000,
3541 .rate_min = 8000,
3542 .channels_min = 1,
3543 .channels_max = 2,
3544 },
3545 .ops = &tapan_dai_ops,
3546 },
3547 {
3548 .name = "tapan9302_tx1",
3549 .id = AIF1_CAP,
3550 .capture = {
3551 .stream_name = "AIF1 Capture",
3552 .rates = WCD9302_RATES,
3553 .formats = TAPAN_FORMATS,
3554 .rate_max = 48000,
3555 .rate_min = 8000,
3556 .channels_min = 1,
3557 .channels_max = 4,
3558 },
3559 .ops = &tapan_dai_ops,
3560 },
3561 {
3562 .name = "tapan9302_rx2",
3563 .id = AIF2_PB,
3564 .playback = {
3565 .stream_name = "AIF2 Playback",
3566 .rates = WCD9302_RATES,
3567 .formats = TAPAN_FORMATS,
3568 .rate_min = 8000,
3569 .rate_max = 48000,
3570 .channels_min = 1,
3571 .channels_max = 2,
3572 },
3573 .ops = &tapan_dai_ops,
3574 },
3575 {
3576 .name = "tapan9302_tx2",
3577 .id = AIF2_CAP,
3578 .capture = {
3579 .stream_name = "AIF2 Capture",
3580 .rates = WCD9302_RATES,
3581 .formats = TAPAN_FORMATS,
3582 .rate_max = 48000,
3583 .rate_min = 8000,
3584 .channels_min = 1,
3585 .channels_max = 4,
3586 },
3587 .ops = &tapan_dai_ops,
3588 },
3589 {
3590 .name = "tapan9302_tx3",
3591 .id = AIF3_CAP,
3592 .capture = {
3593 .stream_name = "AIF3 Capture",
3594 .rates = WCD9302_RATES,
3595 .formats = TAPAN_FORMATS,
3596 .rate_max = 48000,
3597 .rate_min = 8000,
3598 .channels_min = 1,
3599 .channels_max = 2,
3600 },
3601 .ops = &tapan_dai_ops,
3602 },
3603 {
3604 .name = "tapan9302_rx3",
3605 .id = AIF3_PB,
3606 .playback = {
3607 .stream_name = "AIF3 Playback",
3608 .rates = WCD9302_RATES,
3609 .formats = TAPAN_FORMATS,
3610 .rate_min = 8000,
3611 .rate_max = 48000,
3612 .channels_min = 1,
3613 .channels_max = 2,
3614 },
3615 .ops = &tapan_dai_ops,
3616 },
3617};
3618
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003619static struct snd_soc_dai_driver tapan_dai[] = {
3620 {
3621 .name = "tapan_rx1",
3622 .id = AIF1_PB,
3623 .playback = {
3624 .stream_name = "AIF1 Playback",
3625 .rates = WCD9306_RATES,
3626 .formats = TAPAN_FORMATS,
3627 .rate_max = 192000,
3628 .rate_min = 8000,
3629 .channels_min = 1,
3630 .channels_max = 2,
3631 },
3632 .ops = &tapan_dai_ops,
3633 },
3634 {
3635 .name = "tapan_tx1",
3636 .id = AIF1_CAP,
3637 .capture = {
3638 .stream_name = "AIF1 Capture",
3639 .rates = WCD9306_RATES,
3640 .formats = TAPAN_FORMATS,
3641 .rate_max = 192000,
3642 .rate_min = 8000,
3643 .channels_min = 1,
3644 .channels_max = 4,
3645 },
3646 .ops = &tapan_dai_ops,
3647 },
3648 {
3649 .name = "tapan_rx2",
3650 .id = AIF2_PB,
3651 .playback = {
3652 .stream_name = "AIF2 Playback",
3653 .rates = WCD9306_RATES,
3654 .formats = TAPAN_FORMATS,
3655 .rate_min = 8000,
3656 .rate_max = 192000,
3657 .channels_min = 1,
3658 .channels_max = 2,
3659 },
3660 .ops = &tapan_dai_ops,
3661 },
3662 {
3663 .name = "tapan_tx2",
3664 .id = AIF2_CAP,
3665 .capture = {
3666 .stream_name = "AIF2 Capture",
3667 .rates = WCD9306_RATES,
3668 .formats = TAPAN_FORMATS,
3669 .rate_max = 192000,
3670 .rate_min = 8000,
3671 .channels_min = 1,
3672 .channels_max = 4,
3673 },
3674 .ops = &tapan_dai_ops,
3675 },
3676 {
3677 .name = "tapan_tx3",
3678 .id = AIF3_CAP,
3679 .capture = {
3680 .stream_name = "AIF3 Capture",
3681 .rates = WCD9306_RATES,
3682 .formats = TAPAN_FORMATS,
3683 .rate_max = 48000,
3684 .rate_min = 8000,
3685 .channels_min = 1,
3686 .channels_max = 2,
3687 },
3688 .ops = &tapan_dai_ops,
3689 },
3690 {
3691 .name = "tapan_rx3",
3692 .id = AIF3_PB,
3693 .playback = {
3694 .stream_name = "AIF3 Playback",
3695 .rates = WCD9306_RATES,
3696 .formats = TAPAN_FORMATS,
3697 .rate_min = 8000,
3698 .rate_max = 192000,
3699 .channels_min = 1,
3700 .channels_max = 2,
3701 },
3702 .ops = &tapan_dai_ops,
3703 },
3704};
3705
3706static struct snd_soc_dai_driver tapan_i2s_dai[] = {
3707 {
3708 .name = "tapan_i2s_rx1",
3709 .id = AIF1_PB,
3710 .playback = {
3711 .stream_name = "AIF1 Playback",
3712 .rates = WCD9306_RATES,
3713 .formats = TAPAN_FORMATS,
3714 .rate_max = 192000,
3715 .rate_min = 8000,
3716 .channels_min = 1,
3717 .channels_max = 4,
3718 },
3719 .ops = &tapan_dai_ops,
3720 },
3721 {
3722 .name = "tapan_i2s_tx1",
3723 .id = AIF1_CAP,
3724 .capture = {
3725 .stream_name = "AIF1 Capture",
3726 .rates = WCD9306_RATES,
3727 .formats = TAPAN_FORMATS,
3728 .rate_max = 192000,
3729 .rate_min = 8000,
3730 .channels_min = 1,
3731 .channels_max = 4,
3732 },
3733 .ops = &tapan_dai_ops,
3734 },
3735};
3736
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003737static int tapan_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai,
3738 bool up)
3739{
3740 int ret = 0;
3741 struct wcd9xxx_ch *ch;
3742
3743 if (up) {
3744 list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
3745 ret = wcd9xxx_get_slave_port(ch->ch_num);
3746 if (ret < 0) {
3747 pr_debug("%s: Invalid slave port ID: %d\n",
3748 __func__, ret);
3749 ret = -EINVAL;
3750 } else {
3751 set_bit(ret, &dai->ch_mask);
3752 }
3753 }
3754 } else {
3755 ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
3756 msecs_to_jiffies(
3757 TAPAN_SLIM_CLOSE_TIMEOUT));
3758 if (!ret) {
3759 pr_debug("%s: Slim close tx/rx wait timeout\n",
3760 __func__);
3761 ret = -ETIMEDOUT;
3762 } else {
3763 ret = 0;
3764 }
3765 }
3766 return ret;
3767}
3768
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003769static int tapan_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3770 struct snd_kcontrol *kcontrol,
3771 int event)
3772{
3773 struct wcd9xxx *core;
3774 struct snd_soc_codec *codec = w->codec;
3775 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003776 int ret = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003777 struct wcd9xxx_codec_dai_data *dai;
3778
3779 core = dev_get_drvdata(codec->dev->parent);
3780
3781 dev_dbg(codec->dev, "%s: event called! codec name %s\n",
3782 __func__, w->codec->name);
3783 dev_dbg(codec->dev, "%s: num_dai %d stream name %s event %d\n",
3784 __func__, w->codec->num_dai, w->sname, event);
3785
3786 /* Execute the callback only if interface type is slimbus */
3787 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3788 return 0;
3789
3790 dai = &tapan_p->dai[w->shift];
3791 dev_dbg(codec->dev, "%s: w->name %s w->shift %d event %d\n",
3792 __func__, w->name, w->shift, event);
3793
3794 switch (event) {
3795 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003796 (void) tapan_codec_enable_slim_chmask(dai, true);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003797 ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3798 dai->rate, dai->bit_width,
3799 &dai->grph);
3800 break;
3801 case SND_SOC_DAPM_POST_PMD:
3802 ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3803 dai->grph);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003804 ret = tapan_codec_enable_slim_chmask(dai, false);
3805 if (ret < 0) {
3806 ret = wcd9xxx_disconnect_port(core,
3807 &dai->wcd9xxx_ch_list,
3808 dai->grph);
3809 dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
3810 __func__, ret);
3811 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003812 break;
3813 }
3814 return ret;
3815}
3816
3817static int tapan_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3818 struct snd_kcontrol *kcontrol,
3819 int event)
3820{
3821 struct wcd9xxx *core;
3822 struct snd_soc_codec *codec = w->codec;
3823 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
3824 u32 ret = 0;
3825 struct wcd9xxx_codec_dai_data *dai;
3826
3827 core = dev_get_drvdata(codec->dev->parent);
3828
3829 dev_dbg(codec->dev, "%s: event called! codec name %s\n",
3830 __func__, w->codec->name);
3831 dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
3832 __func__, w->codec->num_dai, w->sname);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003833 /* Execute the callback only if interface type is slimbus */
3834 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3835 return 0;
3836
3837 dev_dbg(codec->dev, "%s(): w->name %s event %d w->shift %d\n",
3838 __func__, w->name, event, w->shift);
3839
3840 dai = &tapan_p->dai[w->shift];
3841 switch (event) {
3842 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003843 (void) tapan_codec_enable_slim_chmask(dai, true);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003844 ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3845 dai->rate, dai->bit_width,
3846 &dai->grph);
3847 break;
3848 case SND_SOC_DAPM_POST_PMD:
3849 ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3850 dai->grph);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003851 ret = tapan_codec_enable_slim_chmask(dai, false);
3852 if (ret < 0) {
3853 ret = wcd9xxx_disconnect_port(core,
3854 &dai->wcd9xxx_ch_list,
3855 dai->grph);
3856 dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
3857 __func__, ret);
3858 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003859 break;
3860 }
3861 return ret;
3862}
3863
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003864
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003865static int tapan_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
3866 struct snd_kcontrol *kcontrol, int event)
3867{
3868 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003869 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003870
3871 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
3872
3873 switch (event) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003874 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003875 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3876 WCD9XXX_CLSH_STATE_EAR,
3877 WCD9XXX_CLSH_REQ_ENABLE,
3878 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003879
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003880 usleep_range(5000, 5010);
3881 break;
3882 case SND_SOC_DAPM_POST_PMD:
3883 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3884 WCD9XXX_CLSH_STATE_EAR,
3885 WCD9XXX_CLSH_REQ_DISABLE,
3886 WCD9XXX_CLSH_EVENT_POST_PA);
3887 usleep_range(5000, 5010);
3888 }
3889 return 0;
3890}
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003891
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003892static int tapan_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
3893 struct snd_kcontrol *kcontrol, int event)
3894{
3895 struct snd_soc_codec *codec = w->codec;
3896 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
3897
3898 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
3899
3900 switch (event) {
3901 case SND_SOC_DAPM_PRE_PMU:
3902 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3903 WCD9XXX_CLSH_STATE_EAR,
3904 WCD9XXX_CLSH_REQ_ENABLE,
3905 WCD9XXX_CLSH_EVENT_PRE_DAC);
3906 break;
3907 }
3908
3909 return 0;
3910}
3911
3912static int tapan_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
3913 struct snd_kcontrol *kcontrol, int event)
3914{
3915 struct snd_soc_codec *codec = w->codec;
3916 u8 reg_val, zoh_mux_val = 0x00;
3917
3918 dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
3919
3920 switch (event) {
3921 case SND_SOC_DAPM_POST_PMU:
3922 reg_val = snd_soc_read(codec, TAPAN_A_CDC_CONN_CLSH_CTL);
3923
3924 if ((reg_val & 0x30) == 0x10)
3925 zoh_mux_val = 0x04;
3926 else if ((reg_val & 0x30) == 0x20)
3927 zoh_mux_val = 0x08;
3928
3929 if (zoh_mux_val != 0x00)
3930 snd_soc_update_bits(codec,
3931 TAPAN_A_CDC_CONN_CLSH_CTL,
3932 0x0C, zoh_mux_val);
3933 break;
3934
3935 case SND_SOC_DAPM_POST_PMD:
3936 snd_soc_update_bits(codec, TAPAN_A_CDC_CONN_CLSH_CTL,
3937 0x0C, 0x00);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003938 break;
3939 }
3940 return 0;
3941}
3942
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07003943static int tapan_codec_enable_anc_ear(struct snd_soc_dapm_widget *w,
3944 struct snd_kcontrol *kcontrol, int event)
3945{
3946 struct snd_soc_codec *codec = w->codec;
3947 int ret = 0;
3948
3949 switch (event) {
3950 case SND_SOC_DAPM_PRE_PMU:
3951 ret = tapan_codec_enable_anc(w, kcontrol, event);
3952 msleep(50);
3953 snd_soc_update_bits(codec, TAPAN_A_RX_EAR_EN, 0x10, 0x10);
3954 break;
3955 case SND_SOC_DAPM_POST_PMU:
3956 ret = tapan_codec_enable_ear_pa(w, kcontrol, event);
3957 break;
3958 case SND_SOC_DAPM_PRE_PMD:
3959 snd_soc_update_bits(codec, TAPAN_A_RX_EAR_EN, 0x10, 0x00);
3960 msleep(40);
3961 ret |= tapan_codec_enable_anc(w, kcontrol, event);
3962 break;
3963 case SND_SOC_DAPM_POST_PMD:
3964 ret = tapan_codec_enable_ear_pa(w, kcontrol, event);
3965 break;
3966 }
3967 return ret;
3968}
3969
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07003970static int tapan_codec_chargepump_vdd_event(struct snd_soc_dapm_widget *w,
3971 struct snd_kcontrol *kcontrol, int event)
3972{
3973 struct snd_soc_codec *codec = w->codec;
3974 struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
3975 int ret = 0, i;
3976
3977 pr_info("%s: event = %d\n", __func__, event);
3978
3979
3980 if (!priv->cp_regulators[CP_REG_BUCK]
3981 && !priv->cp_regulators[CP_REG_BHELPER]) {
3982 pr_err("%s: No power supply defined for ChargePump\n",
3983 __func__);
3984 return -EINVAL;
3985 }
3986
3987 switch (event) {
3988 case SND_SOC_DAPM_PRE_PMU:
3989 for (i = 0; i < CP_REG_MAX ; i++) {
3990 if (!priv->cp_regulators[i])
3991 continue;
3992
3993 ret = regulator_enable(priv->cp_regulators[i]);
3994 if (ret) {
3995 pr_err("%s: CP Regulator enable failed, index = %d\n",
3996 __func__, i);
3997 continue;
3998 } else {
3999 pr_debug("%s: Enabled CP regulator, index %d\n",
4000 __func__, i);
4001 }
4002 }
4003 break;
4004 case SND_SOC_DAPM_POST_PMD:
4005 for (i = 0; i < CP_REG_MAX; i++) {
4006 if (!priv->cp_regulators[i])
4007 continue;
4008
4009 ret = regulator_disable(priv->cp_regulators[i]);
4010 if (ret) {
4011 pr_err("%s: CP Regulator disable failed, index = %d\n",
4012 __func__, i);
4013 return ret;
4014 } else {
4015 pr_debug("%s: Disabled CP regulator %d\n",
4016 __func__, i);
4017 }
4018 }
4019 break;
4020 }
4021 return 0;
4022}
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004023
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07004024static const struct snd_soc_dapm_widget tapan_9306_dapm_widgets[] = {
4025 /* RX4 MIX1 mux inputs */
4026 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4027 &rx4_mix1_inp1_mux),
4028 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4029 &rx4_mix1_inp2_mux),
4030 SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
4031 &rx4_mix1_inp2_mux),
4032
4033 /* RX4 MIX2 mux inputs */
4034 SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4035 &rx4_mix2_inp1_mux),
4036 SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4037 &rx4_mix2_inp2_mux),
4038
4039 SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4040
4041 SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
4042 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
4043 SND_SOC_DAPM_POST_PMU),
4044
4045 SND_SOC_DAPM_MUX_E("DEC3 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
4046 &dec3_mux, tapan_codec_enable_dec,
4047 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4048 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
4049
4050 SND_SOC_DAPM_MUX_E("DEC4 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
4051 &dec4_mux, tapan_codec_enable_dec,
4052 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4053 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
4054
4055 SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
4056 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
4057 SND_SOC_DAPM_PRE_PMD),
4058 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
4059 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
4060 SND_SOC_DAPM_PRE_PMD),
4061 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
4062 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
4063 SND_SOC_DAPM_PRE_PMD),
4064
4065 SND_SOC_DAPM_INPUT("AMIC5"),
4066 SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
4067 tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4068
4069 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
4070 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
4071
4072 SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
4073 SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 5, 0, NULL, 0,
4074 tapan_codec_enable_anc_hph,
4075 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
4076 SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
4077 SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 4, 0, NULL, 0,
4078 tapan_codec_enable_anc_hph, SND_SOC_DAPM_PRE_PMU |
4079 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
4080 SND_SOC_DAPM_POST_PMU),
4081 SND_SOC_DAPM_OUTPUT("ANC EAR"),
4082 SND_SOC_DAPM_PGA_E("ANC EAR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
4083 tapan_codec_enable_anc_ear,
4084 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
4085 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4086 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
4087
4088 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAPAN_A_MICB_3_CTL, 7, 0,
4089 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4090 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4091 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAPAN_A_MICB_3_CTL, 7, 0,
4092 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4093 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4094 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAPAN_A_MICB_3_CTL, 7, 0,
4095 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4096 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4097
4098 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
4099 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4100 SND_SOC_DAPM_POST_PMD),
4101
4102 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
4103 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4104 SND_SOC_DAPM_POST_PMD),
4105};
4106
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004107/* Todo: Have seperate dapm widgets for I2S and Slimbus.
4108 * Might Need to have callbacks registered only for slimbus
4109 */
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07004110static const struct snd_soc_dapm_widget tapan_common_dapm_widgets[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004111
4112 SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
4113 AIF1_PB, 0, tapan_codec_enable_slimrx,
4114 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4115 SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
4116 AIF2_PB, 0, tapan_codec_enable_slimrx,
4117 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4118 SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
4119 AIF3_PB, 0, tapan_codec_enable_slimrx,
4120 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4121
4122 SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TAPAN_RX1, 0,
4123 &slim_rx_mux[TAPAN_RX1]),
4124 SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TAPAN_RX2, 0,
4125 &slim_rx_mux[TAPAN_RX2]),
4126 SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TAPAN_RX3, 0,
4127 &slim_rx_mux[TAPAN_RX3]),
4128 SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TAPAN_RX4, 0,
4129 &slim_rx_mux[TAPAN_RX4]),
4130 SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TAPAN_RX5, 0,
4131 &slim_rx_mux[TAPAN_RX5]),
4132
4133 SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4134 SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
4135 SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
4136 SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
4137 SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
4138
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004139
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004140 /* RX1 MIX1 mux inputs */
4141 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4142 &rx_mix1_inp1_mux),
4143 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4144 &rx_mix1_inp2_mux),
4145 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
4146 &rx_mix1_inp3_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004147
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004148 /* RX2 MIX1 mux inputs */
4149 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4150 &rx2_mix1_inp1_mux),
4151 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4152 &rx2_mix1_inp2_mux),
4153 SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
4154 &rx2_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004155
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004156 /* RX3 MIX1 mux inputs */
4157 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4158 &rx3_mix1_inp1_mux),
4159 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4160 &rx3_mix1_inp2_mux),
4161 SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
4162 &rx3_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004163
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004164 /* RX1 MIX2 mux inputs */
4165 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4166 &rx1_mix2_inp1_mux),
4167 SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4168 &rx1_mix2_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004169
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004170 /* RX2 MIX2 mux inputs */
4171 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4172 &rx2_mix2_inp1_mux),
4173 SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4174 &rx2_mix2_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004175
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004176 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4177 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4178
4179 SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
4180 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
4181 SND_SOC_DAPM_POST_PMU),
4182 SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
4183 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
4184 SND_SOC_DAPM_POST_PMU),
4185 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
4186 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
4187 SND_SOC_DAPM_POST_PMU),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004188
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004189 SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
4190 NULL, 0),
4191 SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0,
4192 NULL, 0),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004193
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004194 SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
4195 &class_h_dsm_mux, tapan_codec_dsm_mux_event,
4196 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004197
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004198 /* RX Bias */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004199 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
4200 tapan_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
4201 SND_SOC_DAPM_POST_PMD),
4202
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07004203 /* CDC_CP_VDD */
4204 SND_SOC_DAPM_SUPPLY("CDC_CP_VDD", SND_SOC_NOPM, 0, 0,
4205 tapan_codec_chargepump_vdd_event, SND_SOC_DAPM_PRE_PMU |
4206 SND_SOC_DAPM_POST_PMD),
4207
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004208 /*EAR */
4209 SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
4210 tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
4211 SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004212
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004213 SND_SOC_DAPM_MIXER_E("DAC1", TAPAN_A_RX_EAR_EN, 6, 0, dac1_switch,
4214 ARRAY_SIZE(dac1_switch), tapan_codec_ear_dac_event,
4215 SND_SOC_DAPM_PRE_PMU),
4216
4217 /* Headphone Left */
4218 SND_SOC_DAPM_PGA_E("HPHL", TAPAN_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
4219 tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4220 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4221
4222 SND_SOC_DAPM_MIXER_E("HPHL DAC", TAPAN_A_RX_HPH_L_DAC_CTL, 7, 0,
4223 hphl_switch, ARRAY_SIZE(hphl_switch), tapan_hphl_dac_event,
4224 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4225
4226 /* Headphone Right */
4227 SND_SOC_DAPM_PGA_E("HPHR", TAPAN_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
4228 tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4229 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4230
4231 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAPAN_A_RX_HPH_R_DAC_CTL, 7, 0,
4232 tapan_hphr_dac_event,
4233 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4234
4235 /* LINEOUT1*/
4236 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TAPAN_A_RX_LINE_1_DAC_CTL, 7, 0
4237 , tapan_lineout_dac_event,
4238 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4239
4240 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TAPAN_A_RX_LINE_CNP_EN, 0, 0, NULL,
4241 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4242 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4243
4244 /* LINEOUT2*/
4245 SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
4246 &rx_dac5_mux),
4247
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07004248 /* LINEOUT1*/
4249 SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
4250 &rx_dac4_mux),
4251
4252 SND_SOC_DAPM_MUX("RDAC3 MUX", SND_SOC_NOPM, 0, 0,
4253 &rx_dac3_mux),
4254
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004255 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
4256 , tapan_lineout_dac_event,
4257 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4258
4259 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TAPAN_A_RX_LINE_CNP_EN, 1, 0, NULL,
4260 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4261 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4262
4263 /* CLASS-D SPK */
4264 SND_SOC_DAPM_MIXER_E("SPK DAC", SND_SOC_NOPM, 0, 0,
4265 spk_dac_switch, ARRAY_SIZE(spk_dac_switch), tapan_spk_dac_event,
4266 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4267
4268 SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0 , NULL,
4269 0, tapan_codec_enable_spk_pa,
4270 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4271
4272 SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
4273 tapan_codec_enable_vdd_spkr,
4274 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4275
4276 SND_SOC_DAPM_OUTPUT("EAR"),
4277 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
4278 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
4279 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
4280 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
4281
4282 /* TX Path*/
4283 SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
4284 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
4285
4286 SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
4287 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
4288
4289 SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
4290 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
4291
4292 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TAPAN_TX1, 0,
4293 &sb_tx1_mux),
4294 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TAPAN_TX2, 0,
4295 &sb_tx2_mux),
4296 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TAPAN_TX3, 0,
4297 &sb_tx3_mux),
4298 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TAPAN_TX4, 0,
4299 &sb_tx4_mux),
4300 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TAPAN_TX5, 0,
4301 &sb_tx5_mux),
4302
4303 SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004304 0),
4305
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004306 /* Decimator MUX */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004307 SND_SOC_DAPM_MUX_E("DEC1 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
4308 &dec1_mux, tapan_codec_enable_dec,
4309 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4310 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
4311
4312 SND_SOC_DAPM_MUX_E("DEC2 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
4313 &dec2_mux, tapan_codec_enable_dec,
4314 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4315 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
4316
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004317 SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
4318 tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
4319
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004320 SND_SOC_DAPM_INPUT("AMIC1"),
4321 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
4322 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4323 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4324 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAPAN_A_MICB_1_CTL, 7, 0,
4325 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4326 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4327 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAPAN_A_MICB_1_CTL, 7, 0,
4328 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4329 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4330
4331 SND_SOC_DAPM_ADC_E("ADC1", NULL, TAPAN_A_TX_1_EN, 7, 0,
4332 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4333 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4334 SND_SOC_DAPM_ADC_E("ADC2", NULL, TAPAN_A_TX_2_EN, 7, 0,
4335 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4336 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4337
4338 SND_SOC_DAPM_INPUT("AMIC3"),
4339 SND_SOC_DAPM_ADC_E("ADC3", NULL, TAPAN_A_TX_3_EN, 7, 0,
4340 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4341 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4342
4343 SND_SOC_DAPM_INPUT("AMIC4"),
4344 SND_SOC_DAPM_ADC_E("ADC4", NULL, TAPAN_A_TX_4_EN, 7, 0,
4345 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4346 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4347
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004348 SND_SOC_DAPM_INPUT("AMIC2"),
4349 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAPAN_A_MICB_2_CTL, 7, 0,
4350 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4351 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4352 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TAPAN_A_MICB_2_CTL, 7, 0,
4353 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4354 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4355 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TAPAN_A_MICB_2_CTL, 7, 0,
4356 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4357 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4358 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAPAN_A_MICB_2_CTL, 7, 0,
4359 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4360 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004361
4362 SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
4363 AIF1_CAP, 0, tapan_codec_enable_slimtx,
4364 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4365
4366 SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
4367 AIF2_CAP, 0, tapan_codec_enable_slimtx,
4368 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4369
4370 SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
4371 AIF3_CAP, 0, tapan_codec_enable_slimtx,
4372 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4373
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004374 /* Digital Mic Inputs */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004375 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
4376 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4377 SND_SOC_DAPM_POST_PMD),
4378
4379 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
4380 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4381 SND_SOC_DAPM_POST_PMD),
4382
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004383 /* Sidetone */
4384 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
4385 SND_SOC_DAPM_PGA("IIR1", TAPAN_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
4386
4387 /* AUX PGA */
4388 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TAPAN_A_RX_AUX_SW_CTL, 7, 0,
4389 tapan_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4390 SND_SOC_DAPM_POST_PMD),
4391
4392 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TAPAN_A_RX_AUX_SW_CTL, 6, 0,
4393 tapan_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4394 SND_SOC_DAPM_POST_PMD),
4395
4396 /* Lineout, ear and HPH PA Mixers */
4397
4398 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4399 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
4400
4401 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
4402 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
4403
4404 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4405 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4406
4407 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4408 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4409
4410 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4411 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004412};
4413
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004414static irqreturn_t tapan_slimbus_irq(int irq, void *data)
4415{
4416 struct tapan_priv *priv = data;
4417 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004418 unsigned long status = 0;
4419 int i, j, port_id, k;
4420 u32 bit;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004421 u8 val;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004422 bool tx, cleared;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004423
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004424 for (i = TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
4425 i <= TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
4426 val = wcd9xxx_interface_reg_read(codec->control_data, i);
4427 status |= ((u32)val << (8 * j));
4428 }
4429
4430 for_each_set_bit(j, &status, 32) {
4431 tx = (j >= 16 ? true : false);
4432 port_id = (tx ? j - 16 : j);
4433 val = wcd9xxx_interface_reg_read(codec->control_data,
4434 TAPAN_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
4435 if (val & TAPAN_SLIM_IRQ_OVERFLOW)
4436 pr_err_ratelimited(
4437 "%s: overflow error on %s port %d, value %x\n",
4438 __func__, (tx ? "TX" : "RX"), port_id, val);
4439 if (val & TAPAN_SLIM_IRQ_UNDERFLOW)
4440 pr_err_ratelimited(
4441 "%s: underflow error on %s port %d, value %x\n",
4442 __func__, (tx ? "TX" : "RX"), port_id, val);
4443 if (val & TAPAN_SLIM_IRQ_PORT_CLOSED) {
4444 /*
4445 * INT SOURCE register starts from RX to TX
4446 * but port number in the ch_mask is in opposite way
4447 */
4448 bit = (tx ? j - 16 : j + 16);
4449 dev_dbg(codec->dev, "%s: %s port %d closed value %x, bit %u\n",
4450 __func__, (tx ? "TX" : "RX"), port_id, val,
4451 bit);
4452 for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
4453 dev_dbg(codec->dev, "%s: priv->dai[%d].ch_mask = 0x%lx\n",
4454 __func__, k, priv->dai[k].ch_mask);
4455 if (test_and_clear_bit(bit,
4456 &priv->dai[k].ch_mask)) {
4457 cleared = true;
4458 if (!priv->dai[k].ch_mask)
4459 wake_up(&priv->dai[k].dai_wait);
4460 /*
4461 * There are cases when multiple DAIs
4462 * might be using the same slimbus
4463 * channel. Hence don't break here.
4464 */
4465 }
4466 }
4467 WARN(!cleared,
4468 "Couldn't find slimbus %s port %d for closing\n",
4469 (tx ? "TX" : "RX"), port_id);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004470 }
4471 wcd9xxx_interface_reg_write(codec->control_data,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004472 TAPAN_SLIM_PGD_PORT_INT_CLR_RX_0 +
4473 (j / 8),
4474 1 << (j % 8));
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004475 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004476
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004477 return IRQ_HANDLED;
4478}
4479
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004480static int tapan_handle_pdata(struct tapan_priv *tapan)
4481{
4482 struct snd_soc_codec *codec = tapan->codec;
4483 struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
4484 int k1, k2, k3, rc = 0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004485 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4486 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4487 u8 flag = pdata->amic_settings.use_pdata;
4488 u8 i = 0, j = 0;
4489 u8 val_txfe = 0, value = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004490
4491 if (!pdata) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004492 dev_err(codec->dev, "%s: NULL pdata\n", __func__);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004493 rc = -ENODEV;
4494 goto done;
4495 }
4496
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004497 /* Make sure settings are correct */
4498 if ((pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V) ||
4499 (pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
4500 (pdata->micbias.bias2_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
4501 (pdata->micbias.bias3_cfilt_sel > WCD9XXX_CFILT3_SEL)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004502 dev_err(codec->dev, "%s: Invalid ldoh voltage or bias cfilt\n",
4503 __func__);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004504 rc = -EINVAL;
4505 goto done;
4506 }
4507 /* figure out k value */
4508 k1 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt1_mv);
4509 k2 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt2_mv);
4510 k3 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt3_mv);
4511
4512 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004513 dev_err(codec->dev,
4514 "%s: could not get K value. k1 = %d k2 = %d k3 = %d\n",
4515 __func__, k1, k2, k3);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004516 rc = -EINVAL;
4517 goto done;
4518 }
4519 /* Set voltage level and always use LDO */
4520 snd_soc_update_bits(codec, TAPAN_A_LDO_H_MODE_1, 0x0C,
4521 (pdata->micbias.ldoh_v << 2));
4522
4523 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_1_VAL, 0xFC, (k1 << 2));
4524 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_2_VAL, 0xFC, (k2 << 2));
4525 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_3_VAL, 0xFC, (k3 << 2));
4526
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004527 i = 0;
4528 while (i < 5) {
4529 if (flag & (0x01 << i)) {
4530 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4531 val_txfe = val_txfe |
4532 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4533 snd_soc_update_bits(codec,
4534 TAPAN_A_TX_1_2_TEST_EN + j * 10,
4535 0x30, val_txfe);
4536 }
4537 if (flag & (0x01 << (i + 1))) {
4538 val_txfe = (txfe_bypass &
4539 (0x01 << (i + 1))) ? 0x02 : 0x00;
4540 val_txfe |= (txfe_buff &
4541 (0x01 << (i + 1))) ? 0x01 : 0x00;
4542 snd_soc_update_bits(codec,
4543 TAPAN_A_TX_1_2_TEST_EN + j * 10,
4544 0x03, val_txfe);
4545 }
4546 /* Tapan only has TAPAN_A_TX_1_2_TEST_EN and
4547 TAPAN_A_TX_4_5_TEST_EN reg */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004548
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004549 if (i == 0) {
4550 i = 3;
4551 continue;
4552 } else if (i == 3) {
4553 break;
4554 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004555 }
4556
4557 if (pdata->ocp.use_pdata) {
4558 /* not defined in CODEC specification */
4559 if (pdata->ocp.hph_ocp_limit == 1 ||
4560 pdata->ocp.hph_ocp_limit == 5) {
4561 rc = -EINVAL;
4562 goto done;
4563 }
4564 snd_soc_update_bits(codec, TAPAN_A_RX_COM_OCP_CTL,
4565 0x0F, pdata->ocp.num_attempts);
4566 snd_soc_write(codec, TAPAN_A_RX_COM_OCP_COUNT,
4567 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4568 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_OCP_CTL,
4569 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4570 }
4571
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004572 /* Set micbias capless mode with tail current */
4573 value = (pdata->micbias.bias1_cap_mode == MICBIAS_EXT_BYP_CAP ?
4574 0x00 : 0x10);
4575 snd_soc_update_bits(codec, TAPAN_A_MICB_1_CTL, 0x10, value);
4576 value = (pdata->micbias.bias2_cap_mode == MICBIAS_EXT_BYP_CAP ?
4577 0x00 : 0x10);
4578 snd_soc_update_bits(codec, TAPAN_A_MICB_2_CTL, 0x10, value);
4579 value = (pdata->micbias.bias3_cap_mode == MICBIAS_EXT_BYP_CAP ?
4580 0x00 : 0x10);
4581 snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x10, value);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004582
4583done:
4584 return rc;
4585}
4586
4587static const struct tapan_reg_mask_val tapan_reg_defaults[] = {
4588
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004589 /* enable QFUSE for wcd9306 */
4590 TAPAN_REG_VAL(TAPAN_A_QFUSE_CTL, 0x03),
4591
4592 /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
4593 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
4594
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004595 TAPAN_REG_VAL(TAPAN_A_CDC_CLK_POWER_CTL, 0x03),
4596
4597 /* EAR PA deafults */
4598 TAPAN_REG_VAL(TAPAN_A_RX_EAR_CMBUFF, 0x05),
4599
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004600 /* RX1 and RX2 defaults */
4601 TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B6_CTL, 0xA0),
4602 TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0xA0),
4603
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004604 /* Heaset set Right from RX2 */
4605 TAPAN_REG_VAL(TAPAN_A_CDC_CONN_RX2_B2_CTL, 0x10),
4606
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004607
4608 /*
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004609 * The following only need to be written for Tapan 1.0 parts.
4610 * Tapan 2.0 will have appropriate defaults for these registers.
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004611 */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004612
4613 /* Required defaults for class H operation */
4614 /* borrowed from Taiko class-h */
4615 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0xF4),
4616 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x08),
4617 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
Banajit Goswamia7294452013-06-03 12:42:35 -07004618 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x6F),
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004619
4620 /* TODO: Check below reg writes conflict with above */
4621 /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
4622 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004623 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0x74),
4624 TAPAN_REG_VAL(TAPAN_A_RX_BUCK_BIAS1, 0x62),
4625
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004626 /* Choose max non-overlap time for NCP */
4627 TAPAN_REG_VAL(TAPAN_A_NCP_CLK, 0xFC),
4628 /* Use 25mV/50mV for deltap/m to reduce ripple */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004629 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004630 /*
4631 * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
4632 * Note that the other bits of this register will be changed during
4633 * Rx PA bring up.
4634 */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004635 TAPAN_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004636 /* Reduce HPH DAC bias to 70% */
4637 TAPAN_REG_VAL(TAPAN_A_RX_HPH_BIAS_PA, 0x7A),
4638 /*Reduce EAR DAC bias to 70% */
4639 TAPAN_REG_VAL(TAPAN_A_RX_EAR_BIAS_PA, 0x76),
4640 /* Reduce LINE DAC bias to 70% */
4641 TAPAN_REG_VAL(TAPAN_A_RX_LINE_BIAS_PA, 0x78),
4642
4643 /*
4644 * There is a diode to pull down the micbias while doing
4645 * insertion detection. This diode can cause leakage.
4646 * Set bit 0 to 1 to prevent leakage.
4647 * Setting this bit of micbias 2 prevents leakage for all other micbias.
4648 */
4649 TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
4650
Bhalchandra Gajare7c739522013-06-20 15:31:02 -07004651 /*
4652 * Default register settings to support dynamic change of
4653 * vdd_buck between 1.8 volts and 2.15 volts.
4654 */
4655 TAPAN_REG_VAL(TAPAN_A_BUCK_MODE_2, 0xAA),
4656
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004657};
4658
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004659static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
4660
4661 TAPAN_REG_VAL(TAPAN_A_TX_7_MBHC_EN, 0x6C),
4662 TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_4, 0x51),
4663 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CNP_WG_CTL, 0xDA),
4664 TAPAN_REG_VAL(TAPAN_A_RX_EAR_CNP, 0xC0),
4665 TAPAN_REG_VAL(TAPAN_A_RX_LINE_1_TEST, 0x02),
4666 TAPAN_REG_VAL(TAPAN_A_RX_LINE_2_TEST, 0x02),
4667 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_OCP_CTL, 0x97),
4668 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_CLIP_DET, 0x01),
4669 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_IEC, 0x00),
4670 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B1_CTL, 0xE4),
4671 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x00),
4672 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x00),
4673 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
4674 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_EAR, 0x00),
4675 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_HPH, 0x00),
4676 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_EAR, 0x00),
4677 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_HPH, 0x00),
4678};
4679
4680static const struct tapan_reg_mask_val tapan_1_0_reg_defaults[] = {
4681 /* Close leakage on the spkdrv */
4682 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_PWRSTG, 0x24),
4683 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_DAC, 0xE5),
4684
4685};
4686
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004687static void tapan_update_reg_defaults(struct snd_soc_codec *codec)
4688{
4689 u32 i;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004690 struct wcd9xxx *tapan_core = dev_get_drvdata(codec->dev->parent);
4691
4692 if (!TAPAN_IS_1_0(tapan_core->version)) {
4693 for (i = 0; i < ARRAY_SIZE(tapan_2_x_reg_reset_values); i++)
4694 snd_soc_write(codec, tapan_2_x_reg_reset_values[i].reg,
4695 tapan_2_x_reg_reset_values[i].val);
4696 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004697
4698 for (i = 0; i < ARRAY_SIZE(tapan_reg_defaults); i++)
4699 snd_soc_write(codec, tapan_reg_defaults[i].reg,
4700 tapan_reg_defaults[i].val);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004701
4702 if (TAPAN_IS_1_0(tapan_core->version)) {
4703 for (i = 0; i < ARRAY_SIZE(tapan_1_0_reg_defaults); i++)
4704 snd_soc_write(codec, tapan_1_0_reg_defaults[i].reg,
4705 tapan_1_0_reg_defaults[i].val);
4706 }
4707
4708 if (!TAPAN_IS_1_0(tapan_core->version))
4709 spkr_drv_wrnd = -1;
4710 else if (spkr_drv_wrnd == 1)
4711 snd_soc_write(codec, TAPAN_A_SPKR_DRV_EN, 0xEF);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004712}
4713
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004714static void tapan_update_reg_mclk_rate(struct wcd9xxx *wcd9xxx)
4715{
4716 struct snd_soc_codec *codec;
4717
4718 codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
4719 dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
4720 __func__, wcd9xxx->mclk_rate);
4721
4722 if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
4723 snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
4724 snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
4725 0x01);
4726 } else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6MHZ) {
4727 snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
4728 }
4729}
4730
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004731static const struct tapan_reg_mask_val tapan_codec_reg_init_val[] = {
Phani Kumar Uppalapatieca9a102013-06-18 11:02:38 -07004732 /* Initialize current threshold to 365MA
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004733 * number of wait and run cycles to 4096
4734 */
Phani Kumar Uppalapatieca9a102013-06-18 11:02:38 -07004735 {TAPAN_A_RX_HPH_OCP_CTL, 0xE9, 0x69},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004736 {TAPAN_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Phani Kumar Uppalapatieca9a102013-06-18 11:02:38 -07004737 {TAPAN_A_RX_HPH_L_TEST, 0x01, 0x01},
4738 {TAPAN_A_RX_HPH_R_TEST, 0x01, 0x01},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004739
4740 /* Initialize gain registers to use register gain */
4741 {TAPAN_A_RX_HPH_L_GAIN, 0x20, 0x20},
4742 {TAPAN_A_RX_HPH_R_GAIN, 0x20, 0x20},
4743 {TAPAN_A_RX_LINE_1_GAIN, 0x20, 0x20},
4744 {TAPAN_A_RX_LINE_2_GAIN, 0x20, 0x20},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004745 {TAPAN_A_SPKR_DRV_GAIN, 0x04, 0x04},
4746
4747 /* Set RDAC5 MUX to take input from DEM3_INV.
4748 * This sets LO2 DAC to get input from DEM3_INV
4749 * for LO1 and LO2 to work as differential outputs.
4750 */
4751 {TAPAN_A_CDC_CONN_MISC, 0x04, 0x04},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004752
4753 /* CLASS H config */
4754 {TAPAN_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
4755
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004756 /* Use 16 bit sample size for TX1 to TX5 */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004757 {TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
4758 {TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4759 {TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4760 {TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4761 {TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
4762
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004763 /* Disable SPK SWITCH */
4764 {TAPAN_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
4765
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004766 /* Use 16 bit sample size for RX */
4767 {TAPAN_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4768 {TAPAN_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
4769
4770 /*enable HPF filter for TX paths */
4771 {TAPAN_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
4772 {TAPAN_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
4773 {TAPAN_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
4774 {TAPAN_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
4775
4776 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
4777 {TAPAN_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
4778 {TAPAN_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
4779 {TAPAN_A_CDC_TX3_DMIC_CTL, 0x7, 0x1},
4780 {TAPAN_A_CDC_TX4_DMIC_CTL, 0x7, 0x1},
4781
4782 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
4783 {TAPAN_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004784
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004785 /* Compander zone selection */
4786 {TAPAN_A_CDC_COMP0_B4_CTL, 0x3F, 0x37},
4787 {TAPAN_A_CDC_COMP1_B4_CTL, 0x3F, 0x37},
4788 {TAPAN_A_CDC_COMP2_B4_CTL, 0x3F, 0x37},
4789 {TAPAN_A_CDC_COMP0_B5_CTL, 0x7F, 0x7F},
4790 {TAPAN_A_CDC_COMP1_B5_CTL, 0x7F, 0x7F},
4791 {TAPAN_A_CDC_COMP2_B5_CTL, 0x7F, 0x7F},
Banajit Goswamia7294452013-06-03 12:42:35 -07004792
4793 /*
4794 * Setup wavegen timer to 20msec and disable chopper
4795 * as default. This corresponds to Compander OFF
4796 */
4797 {TAPAN_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDB},
4798 {TAPAN_A_RX_HPH_CNP_WG_TIME, 0xFF, 0x58},
4799 {TAPAN_A_RX_HPH_BIAS_WG_OCP, 0xFF, 0x1A},
4800 {TAPAN_A_RX_HPH_CHOP_CTL, 0xFF, 0x24},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004801};
4802
4803static void tapan_codec_init_reg(struct snd_soc_codec *codec)
4804{
4805 u32 i;
4806
4807 for (i = 0; i < ARRAY_SIZE(tapan_codec_reg_init_val); i++)
4808 snd_soc_update_bits(codec, tapan_codec_reg_init_val[i].reg,
4809 tapan_codec_reg_init_val[i].mask,
4810 tapan_codec_reg_init_val[i].val);
4811}
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004812static void tapan_slim_interface_init_reg(struct snd_soc_codec *codec)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004813{
4814 int i;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004815
4816 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
4817 wcd9xxx_interface_reg_write(codec->control_data,
4818 TAPAN_SLIM_PGD_PORT_INT_EN0 + i,
4819 0xFF);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004820}
4821
4822static int tapan_setup_irqs(struct tapan_priv *tapan)
4823{
4824 int ret = 0;
4825 struct snd_soc_codec *codec = tapan->codec;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004826 struct wcd9xxx *wcd9xxx = codec->control_data;
4827 struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004828
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004829 ret = wcd9xxx_request_irq(core_res, WCD9XXX_IRQ_SLIMBUS,
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004830 tapan_slimbus_irq, "SLIMBUS Slave", tapan);
4831 if (ret)
4832 pr_err("%s: Failed to request irq %d\n", __func__,
4833 WCD9XXX_IRQ_SLIMBUS);
4834 else
4835 tapan_slim_interface_init_reg(codec);
4836
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004837 return ret;
4838}
4839
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07004840static void tapan_cleanup_irqs(struct tapan_priv *tapan)
4841{
4842 struct snd_soc_codec *codec = tapan->codec;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004843 struct wcd9xxx *wcd9xxx = codec->control_data;
4844 struct wcd9xxx_core_resource *core_res = &wcd9xxx->core_res;
4845 wcd9xxx_free_irq(core_res, WCD9XXX_IRQ_SLIMBUS, tapan);
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07004846}
4847
Simmi Pateriya95466b12013-05-09 20:08:46 +05304848
4849static void tapan_enable_mux_bias_block(struct snd_soc_codec *codec)
4850{
4851 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
4852 0x80, 0x00);
4853}
4854
4855static void tapan_put_cfilt_fast_mode(struct snd_soc_codec *codec,
4856 struct wcd9xxx_mbhc *mbhc)
4857{
4858 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
4859 0x30, 0x30);
4860}
4861
4862static void tapan_codec_specific_cal_setup(struct snd_soc_codec *codec,
4863 struct wcd9xxx_mbhc *mbhc)
4864{
4865 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
Phani Kumar Uppalapati10754402013-07-12 22:48:45 -07004866 0x04, 0x04);
Simmi Pateriya95466b12013-05-09 20:08:46 +05304867 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
4868}
4869
4870static int tapan_get_jack_detect_irq(struct snd_soc_codec *codec)
4871{
4872 return TAPAN_IRQ_MBHC_JACK_SWITCH;
4873}
4874
4875static struct wcd9xxx_cfilt_mode tapan_codec_switch_cfilt_mode(
4876 struct wcd9xxx_mbhc *mbhc,
4877 bool fast)
4878{
4879 struct snd_soc_codec *codec = mbhc->codec;
4880 struct wcd9xxx_cfilt_mode cfilt_mode;
4881
4882 if (fast)
4883 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
4884 else
4885 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
4886
4887 cfilt_mode.cur_mode_val =
4888 snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07004889 cfilt_mode.reg_mask = 0x30;
4890
Simmi Pateriya95466b12013-05-09 20:08:46 +05304891 return cfilt_mode;
4892}
4893
4894static void tapan_select_cfilt(struct snd_soc_codec *codec,
4895 struct wcd9xxx_mbhc *mbhc)
4896{
4897 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
4898}
4899
4900static void tapan_free_irq(struct wcd9xxx_mbhc *mbhc)
4901{
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07004902 struct wcd9xxx *wcd9xxx = mbhc->codec->control_data;
4903 struct wcd9xxx_core_resource *core_res =
4904 &wcd9xxx->core_res;
4905 wcd9xxx_free_irq(core_res, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
4906}
4907
4908enum wcd9xxx_cdc_type tapan_get_cdc_type(void)
4909{
4910 return WCD9XXX_CDC_TYPE_TAPAN;
Simmi Pateriya95466b12013-05-09 20:08:46 +05304911}
4912
4913static const struct wcd9xxx_mbhc_cb mbhc_cb = {
4914 .enable_mux_bias_block = tapan_enable_mux_bias_block,
4915 .cfilt_fast_mode = tapan_put_cfilt_fast_mode,
4916 .codec_specific_cal = tapan_codec_specific_cal_setup,
4917 .jack_detect_irq = tapan_get_jack_detect_irq,
4918 .switch_cfilt_mode = tapan_codec_switch_cfilt_mode,
4919 .select_cfilt = tapan_select_cfilt,
4920 .free_irq = tapan_free_irq,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07004921 .get_cdc_type = tapan_get_cdc_type,
Simmi Pateriya95466b12013-05-09 20:08:46 +05304922};
4923
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004924int tapan_hs_detect(struct snd_soc_codec *codec,
4925 struct wcd9xxx_mbhc_config *mbhc_cfg)
4926{
4927 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
4928 return wcd9xxx_mbhc_start(&tapan->mbhc, mbhc_cfg);
4929}
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07004930EXPORT_SYMBOL(tapan_hs_detect);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004931
Joonwoo Park8ffa2812013-08-07 19:01:30 -07004932static int tapan_device_down(struct wcd9xxx *wcd9xxx)
4933{
4934 struct snd_soc_codec *codec;
4935
4936 codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
4937 snd_soc_card_change_online_state(codec->card, 0);
4938
4939 return 0;
4940}
4941
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004942static int tapan_post_reset_cb(struct wcd9xxx *wcd9xxx)
4943{
4944 int ret = 0;
4945 int rco_clk_rate;
4946 struct snd_soc_codec *codec;
4947 struct tapan_priv *tapan;
4948
4949 codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
4950 tapan = snd_soc_codec_get_drvdata(codec);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004951
Joonwoo Park8ffa2812013-08-07 19:01:30 -07004952 snd_soc_card_change_online_state(codec->card, 1);
4953
4954 mutex_lock(&codec->mutex);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004955 if (codec->reg_def_copy) {
4956 pr_debug("%s: Update ASOC cache", __func__);
4957 kfree(codec->reg_cache);
4958 codec->reg_cache = kmemdup(codec->reg_def_copy,
4959 codec->reg_size, GFP_KERNEL);
4960 if (!codec->reg_cache) {
4961 pr_err("%s: Cache update failed!\n", __func__);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004962 mutex_unlock(&codec->mutex);
4963 return -ENOMEM;
4964 }
4965 }
4966
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004967 if (spkr_drv_wrnd == 1)
4968 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004969
4970 tapan_update_reg_defaults(codec);
4971 tapan_update_reg_mclk_rate(wcd9xxx);
4972 tapan_codec_init_reg(codec);
4973 ret = tapan_handle_pdata(tapan);
4974 if (IS_ERR_VALUE(ret))
4975 pr_err("%s: bad pdata\n", __func__);
4976
4977 tapan_slim_interface_init_reg(codec);
4978
Joonwoo Park865bcf02013-07-15 14:05:32 -07004979 wcd9xxx_resmgr_post_ssr(&tapan->resmgr);
4980
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004981 wcd9xxx_mbhc_deinit(&tapan->mbhc);
4982
4983 if (TAPAN_IS_1_0(wcd9xxx->version))
4984 rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
4985 else
4986 rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
4987
4988 ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
Phani Kumar Uppalapatid7549e12013-07-12 22:22:03 -07004989 &mbhc_cb, rco_clk_rate, false);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004990 if (ret)
4991 pr_err("%s: mbhc init failed %d\n", __func__, ret);
4992 else
4993 wcd9xxx_mbhc_start(&tapan->mbhc, tapan->mbhc.mbhc_cfg);
Joonwoo Parkc98049a2013-07-30 16:43:34 -07004994
4995 tapan_cleanup_irqs(tapan);
4996 ret = tapan_setup_irqs(tapan);
4997 if (ret)
4998 pr_err("%s: Failed to setup irq: %d\n", __func__, ret);
4999
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07005000 mutex_unlock(&codec->mutex);
5001 return ret;
5002}
5003
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005004static struct wcd9xxx_reg_address tapan_reg_address = {
5005};
5006
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07005007static int wcd9xxx_ssr_register(struct wcd9xxx *control,
Joonwoo Park8ffa2812013-08-07 19:01:30 -07005008 int (*device_down_cb)(struct wcd9xxx *wcd9xxx),
5009 int (*device_up_cb)(struct wcd9xxx *wcd9xxx),
5010 void *priv)
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07005011{
Joonwoo Park8ffa2812013-08-07 19:01:30 -07005012 control->dev_down = device_down_cb;
5013 control->post_reset = device_up_cb;
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07005014 control->ssr_priv = priv;
5015 return 0;
5016}
5017
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07005018static struct regulator *tapan_codec_find_regulator(
5019 struct snd_soc_codec *codec,
5020 const char *name)
5021{
5022 int i;
5023 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
5024
5025 for (i = 0; i < core->num_of_supplies; i++) {
5026 if (core->supplies[i].supply &&
5027 !strcmp(core->supplies[i].supply, name))
5028 return core->supplies[i].consumer;
5029 }
5030 return NULL;
5031}
5032
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005033static void tapan_enable_config_rco(struct wcd9xxx *core, bool enable)
5034{
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005035 struct wcd9xxx_core_resource *core_res = &core->core_res;
5036
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005037 if (enable) {
5038 /* Enable RC Oscillator */
5039 wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0x00);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005040 wcd9xxx_reg_write(core_res, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17);
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005041 usleep_range(5, 5);
5042 wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x80);
5043 wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x80);
5044 usleep_range(10, 10);
5045 wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x00);
5046 usleep_range(20, 20);
5047 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x08);
5048 /* Enable MCLK and wait 1ms till it gets enabled */
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005049 wcd9xxx_reg_write(core_res, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005050 usleep_range(1000, 1000);
5051 /* Enable CLK BUFF and wait for 1.2ms */
5052 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
5053 usleep_range(1000, 1200);
5054
5055 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
5056 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
5057 wcd9xxx_reg_update(core, WCD9XXX_A_CDC_CLK_MCLK_CTL,
5058 0x01, 0x01);
5059 usleep_range(50, 50);
5060 } else {
5061 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
5062 usleep_range(50, 50);
5063 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
5064 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
5065 usleep_range(50, 50);
5066 }
5067
5068}
5069
5070static bool tapan_check_wcd9306(struct device *cdc_dev, bool sensed)
5071{
5072 struct wcd9xxx *core = dev_get_drvdata(cdc_dev->parent);
5073 u8 reg_val;
5074 bool ret = true;
5075 unsigned long timeout;
5076 bool timedout;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005077 struct wcd9xxx_core_resource *core_res = &core->core_res;
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005078
5079 if (!core) {
5080 dev_err(cdc_dev, "%s: core not initialized\n", __func__);
5081 return -EINVAL;
5082 }
5083
5084 tapan_enable_config_rco(core, 1);
5085
5086 if (sensed == false) {
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005087 reg_val = wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_CTL);
5088 wcd9xxx_reg_write(core_res, TAPAN_A_QFUSE_CTL,
5089 (reg_val | 0x03));
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005090 }
5091
5092 timeout = jiffies + HZ;
5093 do {
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005094 if ((wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_STATUS)))
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005095 break;
5096 } while (!(timedout = time_after(jiffies, timeout)));
5097
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005098 if (wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_DATA_OUT1) ||
5099 wcd9xxx_reg_read(core_res, TAPAN_A_QFUSE_DATA_OUT2)) {
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005100 dev_info(cdc_dev, "%s: wcd9302 detected\n", __func__);
5101 ret = false;
5102 } else
5103 dev_info(cdc_dev, "%s: wcd9306 detected\n", __func__);
5104
5105 tapan_enable_config_rco(core, 0);
5106 return ret;
5107};
5108
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005109static int tapan_codec_probe(struct snd_soc_codec *codec)
5110{
5111 struct wcd9xxx *control;
5112 struct tapan_priv *tapan;
5113 struct wcd9xxx_pdata *pdata;
5114 struct wcd9xxx *wcd9xxx;
5115 struct snd_soc_dapm_context *dapm = &codec->dapm;
5116 int ret = 0;
Phani Kumar Uppalapati43bc4152013-05-24 00:44:20 -07005117 int i, rco_clk_rate;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005118 void *ptr = NULL;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005119 struct wcd9xxx_core_resource *core_res;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005120
5121 codec->control_data = dev_get_drvdata(codec->dev->parent);
5122 control = codec->control_data;
5123
Joonwoo Park8ffa2812013-08-07 19:01:30 -07005124 wcd9xxx_ssr_register(control, tapan_device_down,
5125 tapan_post_reset_cb, (void *)codec);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07005126
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005127 dev_info(codec->dev, "%s()\n", __func__);
5128
5129 tapan = kzalloc(sizeof(struct tapan_priv), GFP_KERNEL);
5130 if (!tapan) {
5131 dev_err(codec->dev, "Failed to allocate private data\n");
5132 return -ENOMEM;
5133 }
5134 for (i = 0 ; i < NUM_DECIMATORS; i++) {
5135 tx_hpf_work[i].tapan = tapan;
5136 tx_hpf_work[i].decimator = i + 1;
5137 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
5138 tx_hpf_corner_freq_callback);
5139 }
5140
5141 snd_soc_codec_set_drvdata(codec, tapan);
5142
5143 /* codec resmgr module init */
5144 wcd9xxx = codec->control_data;
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005145 core_res = &wcd9xxx->core_res;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005146 pdata = dev_get_platdata(codec->dev->parent);
Bhalchandra Gajare9b4eb3b2013-04-30 12:00:41 -07005147 ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, core_res, pdata,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07005148 &tapan_reg_address, WCD9XXX_CDC_TYPE_TAPAN);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005149 if (ret) {
5150 pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005151 return ret;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005152 }
5153
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07005154 tapan->cp_regulators[CP_REG_BUCK] = tapan_codec_find_regulator(codec,
5155 WCD9XXX_SUPPLY_BUCK_NAME);
5156 tapan->cp_regulators[CP_REG_BHELPER] = tapan_codec_find_regulator(codec,
5157 "cdc-vdd-buckhelper");
5158
Bhalchandra Gajare7c739522013-06-20 15:31:02 -07005159 tapan->clsh_d.buck_mv = tapan_codec_get_buck_mv(codec);
5160 /*
5161 * If 1.8 volts is requested on the vdd_cp line, then
5162 * assume that S4 is in a dynamically switchable state
5163 * and can switch between 1.8 volts and 2.15 volts
5164 */
5165 if (tapan->clsh_d.buck_mv == WCD9XXX_CDC_BUCK_MV_1P8)
5166 tapan->clsh_d.is_dynamic_vdd_cp = true;
5167 wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
5168
Phani Kumar Uppalapati43bc4152013-05-24 00:44:20 -07005169 if (TAPAN_IS_1_0(control->version))
5170 rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
5171 else
5172 rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
5173
Joonwoo Parkccccba72013-04-26 11:19:46 -07005174 ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
Phani Kumar Uppalapatid7549e12013-07-12 22:22:03 -07005175 &mbhc_cb, rco_clk_rate, false);
Simmi Pateriya95466b12013-05-09 20:08:46 +05305176
Simmi Pateriya0a44d842013-04-03 01:12:42 +05305177 if (ret) {
5178 pr_err("%s: mbhc init failed %d\n", __func__, ret);
5179 return ret;
5180 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005181
5182 tapan->codec = codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005183 for (i = 0; i < COMPANDER_MAX; i++) {
5184 tapan->comp_enabled[i] = 0;
5185 tapan->comp_fs[i] = COMPANDER_FS_48KHZ;
5186 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005187 tapan->intf_type = wcd9xxx_get_intf_type();
5188 tapan->aux_pga_cnt = 0;
5189 tapan->aux_l_gain = 0x1F;
5190 tapan->aux_r_gain = 0x1F;
5191 tapan_update_reg_defaults(codec);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07005192 tapan_update_reg_mclk_rate(wcd9xxx);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005193 tapan_codec_init_reg(codec);
5194 ret = tapan_handle_pdata(tapan);
5195 if (IS_ERR_VALUE(ret)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005196 dev_err(codec->dev, "%s: bad pdata\n", __func__);
5197 goto err_pdata;
5198 }
5199
5200 if (spkr_drv_wrnd > 0) {
Joonwoo Park533b3682013-06-13 11:41:21 -07005201 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005202 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
5203 WCD9XXX_BANDGAP_AUDIO_MODE);
Joonwoo Park533b3682013-06-13 11:41:21 -07005204 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005205 }
5206
5207 ptr = kmalloc((sizeof(tapan_rx_chs) +
5208 sizeof(tapan_tx_chs)), GFP_KERNEL);
5209 if (!ptr) {
5210 pr_err("%s: no mem for slim chan ctl data\n", __func__);
5211 ret = -ENOMEM;
5212 goto err_nomem_slimch;
5213 }
5214
5215 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005216 snd_soc_dapm_new_controls(dapm, tapan_dapm_i2s_widgets,
5217 ARRAY_SIZE(tapan_dapm_i2s_widgets));
5218 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
5219 ARRAY_SIZE(audio_i2s_map));
5220 for (i = 0; i < ARRAY_SIZE(tapan_i2s_dai); i++)
5221 INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005222 } else if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
5223 for (i = 0; i < NUM_CODEC_DAIS; i++) {
5224 INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
5225 init_waitqueue_head(&tapan->dai[i].dai_wait);
5226 }
5227 }
5228
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005229 if (tapan_check_wcd9306(codec->dev, false) == true) {
5230 snd_soc_add_codec_controls(codec, tapan_9306_snd_controls,
5231 ARRAY_SIZE(tapan_9306_snd_controls));
5232 snd_soc_dapm_new_controls(dapm, tapan_9306_dapm_widgets,
5233 ARRAY_SIZE(tapan_9306_dapm_widgets));
5234 snd_soc_dapm_add_routes(dapm, wcd9306_map,
5235 ARRAY_SIZE(wcd9306_map));
5236 } else {
5237 snd_soc_dapm_add_routes(dapm, wcd9302_map,
5238 ARRAY_SIZE(wcd9302_map));
5239 }
5240
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005241 control->num_rx_port = TAPAN_RX_MAX;
5242 control->rx_chs = ptr;
5243 memcpy(control->rx_chs, tapan_rx_chs, sizeof(tapan_rx_chs));
5244 control->num_tx_port = TAPAN_TX_MAX;
5245 control->tx_chs = ptr + sizeof(tapan_rx_chs);
5246 memcpy(control->tx_chs, tapan_tx_chs, sizeof(tapan_tx_chs));
5247
5248 snd_soc_dapm_sync(dapm);
5249
5250 (void) tapan_setup_irqs(tapan);
5251
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005252 atomic_set(&kp_tapan_priv, (unsigned long)tapan);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07005253 mutex_lock(&dapm->codec->mutex);
5254 snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
5255 snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
5256 snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
5257 snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
5258 snd_soc_dapm_disable_pin(dapm, "ANC EAR");
5259 snd_soc_dapm_sync(dapm);
5260 mutex_unlock(&dapm->codec->mutex);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005261
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005262 codec->ignore_pmdown_time = 1;
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07005263
5264 if (ret)
5265 tapan_cleanup_irqs(tapan);
5266
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005267 return ret;
5268
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005269err_pdata:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005270 kfree(ptr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005271err_nomem_slimch:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005272 kfree(tapan);
5273 return ret;
5274}
5275
5276static int tapan_codec_remove(struct snd_soc_codec *codec)
5277{
5278 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07005279 int index = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005280
Joonwoo Park533b3682013-06-13 11:41:21 -07005281 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005282 atomic_set(&kp_tapan_priv, 0);
5283
5284 if (spkr_drv_wrnd > 0)
5285 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
5286 WCD9XXX_BANDGAP_AUDIO_MODE);
Joonwoo Park533b3682013-06-13 11:41:21 -07005287 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07005288
5289 tapan_cleanup_irqs(tapan);
5290
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005291 /* cleanup MBHC */
5292 wcd9xxx_mbhc_deinit(&tapan->mbhc);
5293 /* cleanup resmgr */
5294 wcd9xxx_resmgr_deinit(&tapan->resmgr);
5295
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07005296 for (index = 0; index < CP_REG_MAX; index++)
5297 tapan->cp_regulators[index] = NULL;
5298
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005299 kfree(tapan);
5300 return 0;
5301}
5302
5303static struct snd_soc_codec_driver soc_codec_dev_tapan = {
5304 .probe = tapan_codec_probe,
5305 .remove = tapan_codec_remove,
5306
5307 .read = tapan_read,
5308 .write = tapan_write,
5309
5310 .readable_register = tapan_readable,
5311 .volatile_register = tapan_volatile,
5312
5313 .reg_cache_size = TAPAN_CACHE_SIZE,
5314 .reg_cache_default = tapan_reset_reg_defaults,
5315 .reg_word_size = 1,
5316
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005317 .controls = tapan_common_snd_controls,
5318 .num_controls = ARRAY_SIZE(tapan_common_snd_controls),
5319 .dapm_widgets = tapan_common_dapm_widgets,
5320 .num_dapm_widgets = ARRAY_SIZE(tapan_common_dapm_widgets),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005321 .dapm_routes = audio_map,
5322 .num_dapm_routes = ARRAY_SIZE(audio_map),
5323};
5324
5325#ifdef CONFIG_PM
5326static int tapan_suspend(struct device *dev)
5327{
5328 dev_dbg(dev, "%s: system suspend\n", __func__);
5329 return 0;
5330}
5331
5332static int tapan_resume(struct device *dev)
5333{
5334 struct platform_device *pdev = to_platform_device(dev);
5335 struct tapan_priv *tapan = platform_get_drvdata(pdev);
5336 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005337 /* Notify */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005338 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, WCD9XXX_EVENT_POST_RESUME);
5339 return 0;
5340}
5341
5342static const struct dev_pm_ops tapan_pm_ops = {
5343 .suspend = tapan_suspend,
5344 .resume = tapan_resume,
5345};
5346#endif
5347
5348static int __devinit tapan_probe(struct platform_device *pdev)
5349{
5350 int ret = 0;
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005351 bool is_wcd9306;
5352
5353 is_wcd9306 = tapan_check_wcd9306(&pdev->dev, false);
5354 if (is_wcd9306 < 0) {
5355 dev_info(&pdev->dev, "%s: cannot find codec type, default to 9306\n",
5356 __func__);
5357 is_wcd9306 = true;
5358 }
5359
5360 if (!is_wcd9306) {
5361 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
5362 ret = snd_soc_register_codec(&pdev->dev,
5363 &soc_codec_dev_tapan,
5364 tapan9302_dai, ARRAY_SIZE(tapan9302_dai));
5365 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
5366 ret = snd_soc_register_codec(&pdev->dev,
5367 &soc_codec_dev_tapan,
5368 tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
5369 } else {
5370 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
5371 ret = snd_soc_register_codec(&pdev->dev,
5372 &soc_codec_dev_tapan,
5373 tapan_dai, ARRAY_SIZE(tapan_dai));
5374 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
5375 ret = snd_soc_register_codec(&pdev->dev,
5376 &soc_codec_dev_tapan,
5377 tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
5378 }
5379
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005380 return ret;
5381}
5382static int __devexit tapan_remove(struct platform_device *pdev)
5383{
5384 snd_soc_unregister_codec(&pdev->dev);
5385 return 0;
5386}
5387static struct platform_driver tapan_codec_driver = {
5388 .probe = tapan_probe,
5389 .remove = tapan_remove,
5390 .driver = {
5391 .name = "tapan_codec",
5392 .owner = THIS_MODULE,
5393#ifdef CONFIG_PM
5394 .pm = &tapan_pm_ops,
5395#endif
5396 },
5397};
5398
5399static int __init tapan_codec_init(void)
5400{
5401 return platform_driver_register(&tapan_codec_driver);
5402}
5403
5404static void __exit tapan_codec_exit(void)
5405{
5406 platform_driver_unregister(&tapan_codec_driver);
5407}
5408
5409module_init(tapan_codec_init);
5410module_exit(tapan_codec_exit);
5411
5412MODULE_DESCRIPTION("Tapan codec driver");
5413MODULE_LICENSE("GPL v2");