blob: fc3035614e0d1bc69112c74907f833a4c6a6c173 [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;
779
780 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -0700781 if (pdata->regulator[i].name == NULL)
782 continue;
783
Banajit Goswamia7294452013-06-03 12:42:35 -0700784 if (!strncmp(pdata->regulator[i].name,
785 WCD9XXX_SUPPLY_BUCK_NAME,
786 sizeof(WCD9XXX_SUPPLY_BUCK_NAME))) {
787 if ((pdata->regulator[i].min_uV ==
788 WCD9XXX_CDC_BUCK_MV_1P8) ||
789 (pdata->regulator[i].min_uV ==
790 WCD9XXX_CDC_BUCK_MV_2P15))
791 buck_volt = pdata->regulator[i].min_uV;
792 break;
793 }
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -0700794 dev_err(codec->dev,
795 "%s: Failed to find regulator for %s\n",
796 __func__, WCD9XXX_SUPPLY_BUCK_NAME);
Banajit Goswamia7294452013-06-03 12:42:35 -0700797 }
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -0700798 dev_dbg(codec->dev,
799 "%s: S4 voltage requested is %d\n",
800 __func__, buck_volt);
Banajit Goswamia7294452013-06-03 12:42:35 -0700801 return buck_volt;
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800802}
803
804static int tapan_config_compander(struct snd_soc_dapm_widget *w,
805 struct snd_kcontrol *kcontrol, int event)
806{
Banajit Goswamia7294452013-06-03 12:42:35 -0700807 int mask, enable_mask;
808 u8 rdac5_mux;
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800809 struct snd_soc_codec *codec = w->codec;
810 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
811 const int comp = w->shift;
812 const u32 rate = tapan->comp_fs[comp];
813 const struct comp_sample_dependent_params *comp_params =
814 &comp_samp_params[rate];
Banajit Goswamia7294452013-06-03 12:42:35 -0700815 enum wcd9xxx_buck_volt buck_mv;
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800816
817 dev_dbg(codec->dev, "%s: %s event %d compander %d, enabled %d",
818 __func__, w->name, event, comp, tapan->comp_enabled[comp]);
819
820 if (!tapan->comp_enabled[comp])
821 return 0;
822
823 /* Compander 0 has single channel */
824 mask = (comp == COMPANDER_0 ? 0x01 : 0x03);
Banajit Goswamia7294452013-06-03 12:42:35 -0700825 buck_mv = tapan_codec_get_buck_mv(codec);
826
827 rdac5_mux = snd_soc_read(codec, TAPAN_A_CDC_CONN_MISC);
828 rdac5_mux = (rdac5_mux & 0x04) >> 2;
829
830 if (comp == COMPANDER_0) { /* SPK compander */
831 enable_mask = 0x02;
832 } else if (comp == COMPANDER_1) { /* HPH compander */
833 enable_mask = 0x03;
834 } else if (comp == COMPANDER_2) { /* LO compander */
835
836 if (rdac5_mux == 0) { /* DEM4 */
837
838 /* for LO Stereo SE, enable Compander 2 left
839 * channel on RX3 interpolator Path and Compander 2
840 * rigt channel on RX4 interpolator Path.
841 */
842 enable_mask = 0x03;
843 } else if (rdac5_mux == 1) { /* DEM3_INV */
844
845 /* for LO mono differential only enable Compander 2
846 * left channel on RX3 interpolator Path.
847 */
848 enable_mask = 0x02;
849 } else {
850 dev_err(codec->dev, "%s: invalid rdac5_mux val %d",
851 __func__, rdac5_mux);
852 return -EINVAL;
853 }
854 } else {
855 dev_err(codec->dev, "%s: invalid compander %d", __func__, comp);
856 return -EINVAL;
857 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800858
859 switch (event) {
860 case SND_SOC_DAPM_PRE_PMU:
Banajit Goswamia7294452013-06-03 12:42:35 -0700861 /* Set compander Sample rate */
862 snd_soc_update_bits(codec,
863 TAPAN_A_CDC_COMP0_FS_CFG + (comp * 8),
864 0x07, rate);
865 /* Set the static gain offset for HPH Path */
866 if (comp == COMPANDER_1) {
867 if (buck_mv == WCD9XXX_CDC_BUCK_MV_2P15)
868 snd_soc_update_bits(codec,
869 TAPAN_A_CDC_COMP0_B4_CTL + (comp * 8),
870 0x80, 0x00);
871 else
872 snd_soc_update_bits(codec,
873 TAPAN_A_CDC_COMP0_B4_CTL + (comp * 8),
874 0x80, 0x80);
875 }
876 /* Enable RX interpolation path compander clocks */
877 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
878 0x01 << comp_shift[comp],
879 0x01 << comp_shift[comp]);
880
881 /* Toggle compander reset bits */
882 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
883 0x01 << comp_shift[comp],
884 0x01 << comp_shift[comp]);
885 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
886 0x01 << comp_shift[comp], 0);
887
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800888 /* Set gain source to compander */
889 tapan_config_gain_compander(codec, comp, true);
Banajit Goswamia7294452013-06-03 12:42:35 -0700890
891 /* Compander enable */
892 snd_soc_update_bits(codec, TAPAN_A_CDC_COMP0_B1_CTL +
893 (comp * 8), enable_mask, enable_mask);
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800894
895 tapan_discharge_comp(codec, comp);
896
Banajit Goswamia7294452013-06-03 12:42:35 -0700897 /* Set sample rate dependent paramater */
898 snd_soc_write(codec, TAPAN_A_CDC_COMP0_B3_CTL + (comp * 8),
899 comp_params->rms_meter_resamp_fact);
900 snd_soc_update_bits(codec,
901 TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
902 0xF0, comp_params->rms_meter_div_fact << 4);
903 snd_soc_update_bits(codec,
904 TAPAN_A_CDC_COMP0_B2_CTL + (comp * 8),
905 0x0F, comp_params->peak_det_timeout);
906 break;
907 case SND_SOC_DAPM_PRE_PMD:
908 /* Disable compander */
909 snd_soc_update_bits(codec,
910 TAPAN_A_CDC_COMP0_B1_CTL + (comp * 8),
911 enable_mask, 0x00);
912
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800913 /* Toggle compander reset bits */
914 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
915 mask << comp_shift[comp],
916 mask << comp_shift[comp]);
917 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_OTHR_RESET_B2_CTL,
918 mask << comp_shift[comp], 0);
Banajit Goswamia7294452013-06-03 12:42:35 -0700919
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800920 /* Turn off the clock for compander in pair */
921 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_B2_CTL,
922 mask << comp_shift[comp], 0);
Banajit Goswamia7294452013-06-03 12:42:35 -0700923
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800924 /* Set gain source to register */
925 tapan_config_gain_compander(codec, comp, false);
926 break;
927 }
928 return 0;
929}
930
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800931static const char * const tapan_ear_pa_gain_text[] = {"POS_6_DB", "POS_2_DB"};
932static const struct soc_enum tapan_ear_pa_gain_enum[] = {
933 SOC_ENUM_SINGLE_EXT(2, tapan_ear_pa_gain_text),
934};
935
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700936static const char *const tapan_anc_func_text[] = {"OFF", "ON"};
937static const struct soc_enum tapan_anc_func_enum =
938 SOC_ENUM_SINGLE_EXT(2, tapan_anc_func_text);
939
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800940/*cut of frequency for high pass filter*/
941static const char * const cf_text[] = {
942 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
943};
944
945static const struct soc_enum cf_dec1_enum =
946 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
947
948static const struct soc_enum cf_dec2_enum =
949 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
950
951static const struct soc_enum cf_dec3_enum =
952 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX3_MUX_CTL, 4, 3, cf_text);
953
954static const struct soc_enum cf_dec4_enum =
955 SOC_ENUM_SINGLE(TAPAN_A_CDC_TX4_MUX_CTL, 4, 3, cf_text);
956
957static const struct soc_enum cf_rxmix1_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800958 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800959
960static const struct soc_enum cf_rxmix2_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800961 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800962
963static const struct soc_enum cf_rxmix3_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800964 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800965
966static const struct soc_enum cf_rxmix4_enum =
Joonwoo Park2000a982013-03-01 14:50:31 -0800967 SOC_ENUM_SINGLE(TAPAN_A_CDC_RX4_B4_CTL, 0, 3, cf_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800968
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800969static const char * const class_h_dsm_text[] = {
970 "ZERO", "RX_HPHL", "RX_SPKR"
971};
972
973static const struct soc_enum class_h_dsm_enum =
974 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_CLSH_CTL, 2, 3, class_h_dsm_text);
975
976static const struct snd_kcontrol_new class_h_dsm_mux =
977 SOC_DAPM_ENUM("CLASS_H_DSM MUX Mux", class_h_dsm_enum);
978
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -0700979static const struct snd_kcontrol_new tapan_common_snd_controls[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800980
981 SOC_ENUM_EXT("EAR PA Gain", tapan_ear_pa_gain_enum[0],
982 tapan_pa_gain_get, tapan_pa_gain_put),
983
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800984 SOC_SINGLE_TLV("HPHL Volume", TAPAN_A_RX_HPH_L_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800985 line_gain),
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800986 SOC_SINGLE_TLV("HPHR Volume", TAPAN_A_RX_HPH_R_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800987 line_gain),
988
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800989 SOC_SINGLE_TLV("LINEOUT1 Volume", TAPAN_A_RX_LINE_1_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800990 line_gain),
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800991 SOC_SINGLE_TLV("LINEOUT2 Volume", TAPAN_A_RX_LINE_2_GAIN, 0, 14, 1,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -0800992 line_gain),
993
Bhalchandra Gajareea898742013-03-05 18:15:53 -0800994 SOC_SINGLE_TLV("SPK DRV Volume", TAPAN_A_SPKR_DRV_GAIN, 3, 7, 1,
995 line_gain),
996
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -0700997 SOC_SINGLE_TLV("ADC1 Volume", TAPAN_A_TX_1_EN, 2, 19, 0, analog_gain),
998 SOC_SINGLE_TLV("ADC2 Volume", TAPAN_A_TX_2_EN, 2, 19, 0, analog_gain),
999 SOC_SINGLE_TLV("ADC3 Volume", TAPAN_A_TX_3_EN, 2, 19, 0, analog_gain),
1000 SOC_SINGLE_TLV("ADC4 Volume", TAPAN_A_TX_4_EN, 2, 19, 0, analog_gain),
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001001 SOC_SINGLE_S8_TLV("RX1 Digital Volume", TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL,
1002 -84, 40, digital_gain),
1003 SOC_SINGLE_S8_TLV("RX2 Digital Volume", TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL,
1004 -84, 40, digital_gain),
1005 SOC_SINGLE_S8_TLV("RX3 Digital Volume", TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL,
1006 -84, 40, digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001007
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001008 SOC_SINGLE_S8_TLV("DEC1 Volume", TAPAN_A_CDC_TX1_VOL_CTL_GAIN, -84, 40,
1009 digital_gain),
1010 SOC_SINGLE_S8_TLV("DEC2 Volume", TAPAN_A_CDC_TX2_VOL_CTL_GAIN, -84, 40,
1011 digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001012
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001013 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume", TAPAN_A_CDC_IIR1_GAIN_B1_CTL, -84,
1014 40, digital_gain),
1015 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume", TAPAN_A_CDC_IIR1_GAIN_B2_CTL, -84,
1016 40, digital_gain),
1017 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume", TAPAN_A_CDC_IIR1_GAIN_B3_CTL, -84,
1018 40, digital_gain),
1019 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume", TAPAN_A_CDC_IIR1_GAIN_B4_CTL, -84,
1020 40, digital_gain),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001021
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001022 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
1023 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
1024 SOC_ENUM("TX3 HPF cut off", cf_dec3_enum),
1025 SOC_ENUM("TX4 HPF cut off", cf_dec4_enum),
1026
1027 SOC_SINGLE("TX1 HPF Switch", TAPAN_A_CDC_TX1_MUX_CTL, 3, 1, 0),
1028 SOC_SINGLE("TX2 HPF Switch", TAPAN_A_CDC_TX2_MUX_CTL, 3, 1, 0),
1029 SOC_SINGLE("TX3 HPF Switch", TAPAN_A_CDC_TX3_MUX_CTL, 3, 1, 0),
1030 SOC_SINGLE("TX4 HPF Switch", TAPAN_A_CDC_TX4_MUX_CTL, 3, 1, 0),
1031
1032 SOC_SINGLE("RX1 HPF Switch", TAPAN_A_CDC_RX1_B5_CTL, 2, 1, 0),
1033 SOC_SINGLE("RX2 HPF Switch", TAPAN_A_CDC_RX2_B5_CTL, 2, 1, 0),
1034 SOC_SINGLE("RX3 HPF Switch", TAPAN_A_CDC_RX3_B5_CTL, 2, 1, 0),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001035
1036 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1037 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1038 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001039
1040 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1041 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1042 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1043 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1044 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1045 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1046 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1047 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1048 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1049 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1050 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1051 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1052 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1053 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1054 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1055 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1056 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1057 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1058 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1059 tapan_get_iir_enable_audio_mixer, tapan_put_iir_enable_audio_mixer),
1060
1061 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1062 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1063 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1064 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1065 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1066 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1067 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1068 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1069 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1070 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1071 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1072 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1073 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1074 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1075 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1076 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1077 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1078 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
1079 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1080 tapan_get_iir_band_audio_mixer, tapan_put_iir_band_audio_mixer),
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07001081};
1082
1083static const struct snd_kcontrol_new tapan_9306_snd_controls[] = {
1084 SOC_SINGLE_TLV("ADC5 Volume", TAPAN_A_TX_5_EN, 2, 19, 0, analog_gain),
1085
1086 SOC_SINGLE_S8_TLV("RX4 Digital Volume", TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL,
1087 -84, 40, digital_gain),
1088 SOC_SINGLE_S8_TLV("DEC3 Volume", TAPAN_A_CDC_TX3_VOL_CTL_GAIN, -84, 40,
1089 digital_gain),
1090 SOC_SINGLE_S8_TLV("DEC4 Volume", TAPAN_A_CDC_TX4_VOL_CTL_GAIN, -84, 40,
1091 digital_gain),
1092 SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tapan_get_anc_slot,
1093 tapan_put_anc_slot),
1094 SOC_ENUM_EXT("ANC Function", tapan_anc_func_enum, tapan_get_anc_func,
1095 tapan_put_anc_func),
1096 SOC_SINGLE("RX4 HPF Switch", TAPAN_A_CDC_RX4_B5_CTL, 2, 1, 0),
1097 SOC_ENUM("RX4 HPF cut off", cf_rxmix4_enum),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001098
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001099 SOC_SINGLE_EXT("COMP0 Switch", SND_SOC_NOPM, COMPANDER_0, 1, 0,
1100 tapan_get_compander, tapan_set_compander),
1101 SOC_SINGLE_EXT("COMP1 Switch", SND_SOC_NOPM, COMPANDER_1, 1, 0,
1102 tapan_get_compander, tapan_set_compander),
1103 SOC_SINGLE_EXT("COMP2 Switch", SND_SOC_NOPM, COMPANDER_2, 1, 0,
1104 tapan_get_compander, tapan_set_compander),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001105};
1106
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001107static const char * const rx_1_2_mix1_text[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001108 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001109 "RX5", "AUXRX", "AUXTX1"
1110};
1111
1112static const char * const rx_3_4_mix1_text[] = {
1113 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2", "RX1", "RX2", "RX3", "RX4",
1114 "RX5", "AUXRX", "AUXTX1", "AUXTX2"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001115};
1116
1117static const char * const rx_mix2_text[] = {
1118 "ZERO", "SRC1", "SRC2", "IIR1", "IIR2"
1119};
1120
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07001121static const char * const rx_rdac3_text[] = {
1122 "DEM1", "DEM2"
1123};
1124
1125static const char * const rx_rdac4_text[] = {
1126 "DEM3", "DEM2"
1127};
1128
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001129static const char * const rx_rdac5_text[] = {
1130 "DEM4", "DEM3_INV"
1131};
1132
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001133static const char * const sb_tx_1_2_mux_text[] = {
1134 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1135 "RSVD", "RSVD", "RSVD",
1136 "DEC1", "DEC2", "DEC3", "DEC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001137};
1138
1139static const char * const sb_tx3_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001140 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1141 "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
1142 "DEC3"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001143};
1144
1145static const char * const sb_tx4_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001146 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1147 "RSVD", "RSVD", "RSVD", "RSVD", "RSVD", "RSVD",
1148 "DEC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001149};
1150
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001151static const char * const sb_tx5_mux_text[] = {
1152 "ZERO", "RMIX1", "RMIX2", "RMIX3", "RMIX4",
1153 "RSVD", "RSVD", "RSVD",
1154 "DEC1"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001155};
1156
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001157static const char * const dec_1_2_mux_text[] = {
1158 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADCMB",
1159 "DMIC1", "DMIC2", "DMIC3", "DMIC4"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001160};
1161
1162static const char * const dec3_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001163 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
1164 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
1165 "ANCFBTUNE1"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001166};
1167
1168static const char * const dec4_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001169 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADCMB",
1170 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
1171 "ANCFBTUNE2"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001172};
1173
1174static const char * const anc_mux_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001175 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5",
1176 "RSVD", "RSVD", "RSVD",
1177 "DMIC1", "DMIC2", "DMIC3", "DMIC4",
1178 "RSVD", "RSVD"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001179};
1180
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001181static const char * const anc1_fb_mux_text[] = {
1182 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1183};
1184
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001185static const char * const iir1_inp1_text[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001186 "ZERO", "DEC1", "DEC2", "DEC3", "DEC4",
1187 "RX1", "RX2", "RX3", "RX4", "RX5"
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001188};
1189
1190static const struct soc_enum rx_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001191 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001192
1193static const struct soc_enum rx_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001194 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B1_CTL, 4, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001195
1196static const struct soc_enum rx_mix1_inp3_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001197 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B2_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001198
1199static const struct soc_enum rx2_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001200 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 0, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001201
1202static const struct soc_enum rx2_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001203 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B1_CTL, 4, 12, rx_1_2_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001204
1205static const struct soc_enum rx3_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001206 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 0, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001207
1208static const struct soc_enum rx3_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001209 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX3_B1_CTL, 4, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001210
1211static const struct soc_enum rx4_mix1_inp1_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001212 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 0, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001213
1214static const struct soc_enum rx4_mix1_inp2_chain_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001215 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B1_CTL, 4, 13, rx_3_4_mix1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001216
1217static const struct soc_enum rx1_mix2_inp1_chain_enum =
1218 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 0, 5, rx_mix2_text);
1219
1220static const struct soc_enum rx1_mix2_inp2_chain_enum =
1221 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX1_B3_CTL, 3, 5, rx_mix2_text);
1222
1223static const struct soc_enum rx2_mix2_inp1_chain_enum =
1224 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 0, 5, rx_mix2_text);
1225
1226static const struct soc_enum rx2_mix2_inp2_chain_enum =
1227 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B3_CTL, 3, 5, rx_mix2_text);
1228
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001229static const struct soc_enum rx4_mix2_inp1_chain_enum =
1230 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 0, 5, rx_mix2_text);
1231
1232static const struct soc_enum rx4_mix2_inp2_chain_enum =
1233 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX4_B3_CTL, 3, 5, rx_mix2_text);
1234
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07001235static const struct soc_enum rx_rdac3_enum =
1236 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_RX2_B2_CTL, 4, 2, rx_rdac3_text);
1237
1238static const struct soc_enum rx_rdac4_enum =
1239 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 1, 2, rx_rdac4_text);
1240
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001241static const struct soc_enum rx_rdac5_enum =
1242 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_MISC, 2, 2, rx_rdac5_text);
1243
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001244static const struct soc_enum sb_tx1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001245 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0, 12,
1246 sb_tx_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001247
1248static const struct soc_enum sb_tx2_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001249 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0, 12,
1250 sb_tx_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001251
1252static const struct soc_enum sb_tx3_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001253 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0, 11, sb_tx3_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001254
1255static const struct soc_enum sb_tx4_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001256 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0, 12, sb_tx4_mux_text);
1257
1258static const struct soc_enum sb_tx5_mux_enum =
1259 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0, 9, sb_tx5_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001260
1261static const struct soc_enum dec1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001262 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 0, 10, dec_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001263
1264static const struct soc_enum dec2_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001265 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B1_CTL, 4, 10, dec_1_2_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001266
1267static const struct soc_enum dec3_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001268 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 0, 12, dec3_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001269
1270static const struct soc_enum dec4_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001271 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_TX_B2_CTL, 4, 12, dec4_mux_text);
1272
1273static const struct soc_enum anc1_mux_enum =
1274 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 0, 15, anc_mux_text);
1275
1276static const struct soc_enum anc2_mux_enum =
1277 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B1_CTL, 4, 15, anc_mux_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001278
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001279static const struct soc_enum anc1_fb_mux_enum =
1280 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_ANC_B2_CTL, 0, 3, anc1_fb_mux_text);
1281
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001282static const struct soc_enum iir1_inp1_mux_enum =
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001283 SOC_ENUM_SINGLE(TAPAN_A_CDC_CONN_EQ1_B1_CTL, 0, 10, iir1_inp1_text);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001284
1285static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1286 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1287
1288static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1289 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1290
1291static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1292 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1293
1294static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1295 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1296
1297static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1298 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1299
1300static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1301 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1302
1303static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1304 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1305
1306static const struct snd_kcontrol_new rx4_mix1_inp1_mux =
1307 SOC_DAPM_ENUM("RX4 MIX1 INP1 Mux", rx4_mix1_inp1_chain_enum);
1308
1309static const struct snd_kcontrol_new rx4_mix1_inp2_mux =
1310 SOC_DAPM_ENUM("RX4 MIX1 INP2 Mux", rx4_mix1_inp2_chain_enum);
1311
1312static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1313 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1314
1315static const struct snd_kcontrol_new rx1_mix2_inp2_mux =
1316 SOC_DAPM_ENUM("RX1 MIX2 INP2 Mux", rx1_mix2_inp2_chain_enum);
1317
1318static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1319 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1320
1321static const struct snd_kcontrol_new rx2_mix2_inp2_mux =
1322 SOC_DAPM_ENUM("RX2 MIX2 INP2 Mux", rx2_mix2_inp2_chain_enum);
1323
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001324static const struct snd_kcontrol_new rx4_mix2_inp1_mux =
1325 SOC_DAPM_ENUM("RX4 MIX2 INP1 Mux", rx4_mix2_inp1_chain_enum);
1326
1327static const struct snd_kcontrol_new rx4_mix2_inp2_mux =
1328 SOC_DAPM_ENUM("RX4 MIX2 INP2 Mux", rx4_mix2_inp2_chain_enum);
1329
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07001330static const struct snd_kcontrol_new rx_dac3_mux =
1331 SOC_DAPM_ENUM("RDAC3 MUX Mux", rx_rdac3_enum);
1332
1333static const struct snd_kcontrol_new rx_dac4_mux =
1334 SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
1335
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001336static const struct snd_kcontrol_new rx_dac5_mux =
1337 SOC_DAPM_ENUM("RDAC5 MUX Mux", rx_rdac5_enum);
1338
1339static const struct snd_kcontrol_new sb_tx1_mux =
1340 SOC_DAPM_ENUM("SLIM TX1 MUX Mux", sb_tx1_mux_enum);
1341
1342static const struct snd_kcontrol_new sb_tx2_mux =
1343 SOC_DAPM_ENUM("SLIM TX2 MUX Mux", sb_tx2_mux_enum);
1344
1345static const struct snd_kcontrol_new sb_tx3_mux =
1346 SOC_DAPM_ENUM("SLIM TX3 MUX Mux", sb_tx3_mux_enum);
1347
1348static const struct snd_kcontrol_new sb_tx4_mux =
1349 SOC_DAPM_ENUM("SLIM TX4 MUX Mux", sb_tx4_mux_enum);
1350
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001351static const struct snd_kcontrol_new sb_tx5_mux =
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001352 SOC_DAPM_ENUM("SLIM TX5 MUX Mux", sb_tx5_mux_enum);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001353
1354static int wcd9306_put_dec_enum(struct snd_kcontrol *kcontrol,
1355 struct snd_ctl_elem_value *ucontrol)
1356{
1357 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1358 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1359 struct snd_soc_codec *codec = w->codec;
1360 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1361 unsigned int dec_mux, decimator;
1362 char *dec_name = NULL;
1363 char *widget_name = NULL;
1364 char *temp;
1365 u16 tx_mux_ctl_reg;
1366 u8 adc_dmic_sel = 0x0;
1367 int ret = 0;
1368
1369 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1370 return -EINVAL;
1371
1372 dec_mux = ucontrol->value.enumerated.item[0];
1373
1374 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1375 if (!widget_name)
1376 return -ENOMEM;
1377 temp = widget_name;
1378
1379 dec_name = strsep(&widget_name, " ");
1380 widget_name = temp;
1381 if (!dec_name) {
1382 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
1383 ret = -EINVAL;
1384 goto out;
1385 }
1386
1387 ret = kstrtouint(strpbrk(dec_name, "1234"), 10, &decimator);
1388 if (ret < 0) {
1389 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
1390 ret = -EINVAL;
1391 goto out;
1392 }
1393
1394 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1395 , __func__, w->name, decimator, dec_mux);
1396
1397 switch (decimator) {
1398 case 1:
1399 case 2:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001400 if ((dec_mux >= 1) && (dec_mux <= 5))
1401 adc_dmic_sel = 0x0;
1402 else if ((dec_mux >= 6) && (dec_mux <= 9))
1403 adc_dmic_sel = 0x1;
1404 break;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001405 case 3:
1406 case 4:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001407 if ((dec_mux >= 1) && (dec_mux <= 6))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001408 adc_dmic_sel = 0x0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001409 else if ((dec_mux >= 7) && (dec_mux <= 10))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001410 adc_dmic_sel = 0x1;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001411 break;
1412 default:
1413 pr_err("%s: Invalid Decimator = %u\n", __func__, decimator);
1414 ret = -EINVAL;
1415 goto out;
1416 }
1417
1418 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
1419
1420 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1421
1422 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1423
1424out:
1425 kfree(widget_name);
1426 return ret;
1427}
1428
1429#define WCD9306_DEC_ENUM(xname, xenum) \
1430{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1431 .info = snd_soc_info_enum_double, \
1432 .get = snd_soc_dapm_get_enum_double, \
1433 .put = wcd9306_put_dec_enum, \
1434 .private_value = (unsigned long)&xenum }
1435
1436static const struct snd_kcontrol_new dec1_mux =
1437 WCD9306_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1438
1439static const struct snd_kcontrol_new dec2_mux =
1440 WCD9306_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1441
1442static const struct snd_kcontrol_new dec3_mux =
1443 WCD9306_DEC_ENUM("DEC3 MUX Mux", dec3_mux_enum);
1444
1445static const struct snd_kcontrol_new dec4_mux =
1446 WCD9306_DEC_ENUM("DEC4 MUX Mux", dec4_mux_enum);
1447
1448static const struct snd_kcontrol_new iir1_inp1_mux =
1449 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1450
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001451static const struct snd_kcontrol_new anc1_mux =
1452 SOC_DAPM_ENUM("ANC1 MUX Mux", anc1_mux_enum);
1453
1454static const struct snd_kcontrol_new anc2_mux =
1455 SOC_DAPM_ENUM("ANC2 MUX Mux", anc2_mux_enum);
1456
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001457static const struct snd_kcontrol_new anc1_fb_mux =
1458 SOC_DAPM_ENUM("ANC1 FB MUX Mux", anc1_fb_mux_enum);
1459
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001460static const struct snd_kcontrol_new dac1_switch[] = {
1461 SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_EAR_EN, 5, 1, 0)
1462};
1463static const struct snd_kcontrol_new hphl_switch[] = {
1464 SOC_DAPM_SINGLE("Switch", TAPAN_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1465};
1466
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001467static const struct snd_kcontrol_new spk_dac_switch[] = {
1468 SOC_DAPM_SINGLE("Switch", TAPAN_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
1469};
1470
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001471static const struct snd_kcontrol_new hphl_pa_mix[] = {
1472 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1473 7, 1, 0),
1474};
1475
1476static const struct snd_kcontrol_new hphr_pa_mix[] = {
1477 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1478 6, 1, 0),
1479};
1480
1481static const struct snd_kcontrol_new ear_pa_mix[] = {
1482 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1483 5, 1, 0),
1484};
1485static const struct snd_kcontrol_new lineout1_pa_mix[] = {
1486 SOC_DAPM_SINGLE("AUX_PGA_L Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1487 4, 1, 0),
1488};
1489
1490static const struct snd_kcontrol_new lineout2_pa_mix[] = {
1491 SOC_DAPM_SINGLE("AUX_PGA_R Switch", TAPAN_A_RX_PA_AUX_IN_CONN,
1492 3, 1, 0),
1493};
1494
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001495
1496/* virtual port entries */
1497static int slim_tx_mixer_get(struct snd_kcontrol *kcontrol,
1498 struct snd_ctl_elem_value *ucontrol)
1499{
1500 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1501 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1502
1503 ucontrol->value.integer.value[0] = widget->value;
1504 return 0;
1505}
1506
1507static int slim_tx_mixer_put(struct snd_kcontrol *kcontrol,
1508 struct snd_ctl_elem_value *ucontrol)
1509{
1510 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1511 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1512 struct snd_soc_codec *codec = widget->codec;
1513 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
1514 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1515 struct soc_multi_mixer_control *mixer =
1516 ((struct soc_multi_mixer_control *)kcontrol->private_value);
1517 u32 dai_id = widget->shift;
1518 u32 port_id = mixer->shift;
1519 u32 enable = ucontrol->value.integer.value[0];
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001520 u32 vtable = vport_check_table[dai_id];
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001521
1522 dev_dbg(codec->dev, "%s: wname %s cname %s\n",
1523 __func__, widget->name, ucontrol->id.name);
1524 dev_dbg(codec->dev, "%s: value %u shift %d item %ld\n",
1525 __func__, widget->value, widget->shift,
1526 ucontrol->value.integer.value[0]);
1527
1528 mutex_lock(&codec->mutex);
1529
1530 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1531 if (dai_id != AIF1_CAP) {
1532 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1533 __func__);
1534 mutex_unlock(&codec->mutex);
1535 return -EINVAL;
1536 }
1537 }
1538 switch (dai_id) {
1539 case AIF1_CAP:
1540 case AIF2_CAP:
1541 case AIF3_CAP:
1542 /* only add to the list if value not set
1543 */
1544 if (enable && !(widget->value & 1 << port_id)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001545 if (tapan_p->intf_type ==
1546 WCD9XXX_INTERFACE_TYPE_SLIMBUS)
1547 vtable = vport_check_table[dai_id];
1548 if (tapan_p->intf_type ==
1549 WCD9XXX_INTERFACE_TYPE_I2C)
1550 vtable = vport_i2s_check_table[dai_id];
1551
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001552 if (wcd9xxx_tx_vport_validation(
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001553 vtable,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001554 port_id,
1555 tapan_p->dai)) {
1556 dev_dbg(codec->dev, "%s: TX%u is used by other virtual port\n",
1557 __func__, port_id + 1);
1558 mutex_unlock(&codec->mutex);
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001559 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001560 }
1561 widget->value |= 1 << port_id;
1562 list_add_tail(&core->tx_chs[port_id].list,
1563 &tapan_p->dai[dai_id].wcd9xxx_ch_list
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001564 );
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001565 } else if (!enable && (widget->value & 1 << port_id)) {
1566 widget->value &= ~(1 << port_id);
1567 list_del_init(&core->tx_chs[port_id].list);
1568 } else {
1569 if (enable)
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001570 dev_dbg(codec->dev, "%s: TX%u port is used by\n"
1571 "this virtual port\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001572 __func__, port_id + 1);
1573 else
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001574 dev_dbg(codec->dev, "%s: TX%u port is not used by\n"
1575 "this virtual port\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001576 __func__, port_id + 1);
1577 /* avoid update power function */
1578 mutex_unlock(&codec->mutex);
1579 return 0;
1580 }
1581 break;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001582 default:
1583 dev_err(codec->dev, "Unknown AIF %d\n", dai_id);
1584 mutex_unlock(&codec->mutex);
1585 return -EINVAL;
1586 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001587 dev_dbg(codec->dev, "%s: name %s sname %s updated value %u shift %d\n",
1588 __func__, widget->name, widget->sname,
1589 widget->value, widget->shift);
1590
1591 snd_soc_dapm_mixer_update_power(widget, kcontrol, enable);
1592
1593 mutex_unlock(&codec->mutex);
1594 return 0;
1595}
1596
1597static int slim_rx_mux_get(struct snd_kcontrol *kcontrol,
1598 struct snd_ctl_elem_value *ucontrol)
1599{
1600 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1601 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1602
1603 ucontrol->value.enumerated.item[0] = widget->value;
1604 return 0;
1605}
1606
1607static const char *const slim_rx_mux_text[] = {
1608 "ZERO", "AIF1_PB", "AIF2_PB", "AIF3_PB"
1609};
1610
1611static int slim_rx_mux_put(struct snd_kcontrol *kcontrol,
1612 struct snd_ctl_elem_value *ucontrol)
1613{
1614 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1615 struct snd_soc_dapm_widget *widget = wlist->widgets[0];
1616 struct snd_soc_codec *codec = widget->codec;
1617 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
1618 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
1619 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1620 u32 port_id = widget->shift;
1621
1622 dev_dbg(codec->dev, "%s: wname %s cname %s value %u shift %d item %ld\n",
1623 __func__, widget->name, ucontrol->id.name, widget->value,
1624 widget->shift, ucontrol->value.integer.value[0]);
1625
1626 widget->value = ucontrol->value.enumerated.item[0];
1627
1628 mutex_lock(&codec->mutex);
1629
1630 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
1631 if (widget->value > 1) {
1632 dev_err(codec->dev, "%s: invalid AIF for I2C mode\n",
1633 __func__);
1634 goto err;
1635 }
1636 }
1637 /* value need to match the Virtual port and AIF number
1638 */
1639 switch (widget->value) {
1640 case 0:
1641 list_del_init(&core->rx_chs[port_id].list);
1642 break;
1643 case 1:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001644 if (wcd9xxx_rx_vport_validation(port_id +
1645 TAPAN_RX_PORT_START_NUMBER,
1646 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list)) {
1647 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1648 __func__, port_id + 1);
1649 goto rtn;
1650 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001651 list_add_tail(&core->rx_chs[port_id].list,
1652 &tapan_p->dai[AIF1_PB].wcd9xxx_ch_list);
1653 break;
1654 case 2:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001655 if (wcd9xxx_rx_vport_validation(port_id +
1656 TAPAN_RX_PORT_START_NUMBER,
1657 &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list)) {
1658 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1659 __func__, port_id + 1);
1660 goto rtn;
1661 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001662 list_add_tail(&core->rx_chs[port_id].list,
1663 &tapan_p->dai[AIF2_PB].wcd9xxx_ch_list);
1664 break;
1665 case 3:
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001666 if (wcd9xxx_rx_vport_validation(port_id +
1667 TAPAN_RX_PORT_START_NUMBER,
1668 &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list)) {
1669 dev_dbg(codec->dev, "%s: RX%u is used by current requesting AIF_PB itself\n",
1670 __func__, port_id + 1);
1671 goto rtn;
1672 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001673 list_add_tail(&core->rx_chs[port_id].list,
1674 &tapan_p->dai[AIF3_PB].wcd9xxx_ch_list);
1675 break;
1676 default:
1677 pr_err("Unknown AIF %d\n", widget->value);
1678 goto err;
1679 }
1680
Kuirong Wang80aca0d2013-05-09 14:51:09 -07001681rtn:
Jay Chokshi83b4f6132013-02-14 16:20:56 -08001682 snd_soc_dapm_mux_update_power(widget, kcontrol, 1, widget->value, e);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001683 mutex_unlock(&codec->mutex);
1684 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001685err:
1686 mutex_unlock(&codec->mutex);
1687 return -EINVAL;
1688}
1689
1690static const struct soc_enum slim_rx_mux_enum =
1691 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(slim_rx_mux_text), slim_rx_mux_text);
1692
1693static const struct snd_kcontrol_new slim_rx_mux[TAPAN_RX_MAX] = {
1694 SOC_DAPM_ENUM_EXT("SLIM RX1 Mux", slim_rx_mux_enum,
1695 slim_rx_mux_get, slim_rx_mux_put),
1696 SOC_DAPM_ENUM_EXT("SLIM RX2 Mux", slim_rx_mux_enum,
1697 slim_rx_mux_get, slim_rx_mux_put),
1698 SOC_DAPM_ENUM_EXT("SLIM RX3 Mux", slim_rx_mux_enum,
1699 slim_rx_mux_get, slim_rx_mux_put),
1700 SOC_DAPM_ENUM_EXT("SLIM RX4 Mux", slim_rx_mux_enum,
1701 slim_rx_mux_get, slim_rx_mux_put),
1702 SOC_DAPM_ENUM_EXT("SLIM RX5 Mux", slim_rx_mux_enum,
1703 slim_rx_mux_get, slim_rx_mux_put),
1704};
1705
1706static const struct snd_kcontrol_new aif_cap_mixer[] = {
1707 SOC_SINGLE_EXT("SLIM TX1", SND_SOC_NOPM, TAPAN_TX1, 1, 0,
1708 slim_tx_mixer_get, slim_tx_mixer_put),
1709 SOC_SINGLE_EXT("SLIM TX2", SND_SOC_NOPM, TAPAN_TX2, 1, 0,
1710 slim_tx_mixer_get, slim_tx_mixer_put),
1711 SOC_SINGLE_EXT("SLIM TX3", SND_SOC_NOPM, TAPAN_TX3, 1, 0,
1712 slim_tx_mixer_get, slim_tx_mixer_put),
1713 SOC_SINGLE_EXT("SLIM TX4", SND_SOC_NOPM, TAPAN_TX4, 1, 0,
1714 slim_tx_mixer_get, slim_tx_mixer_put),
1715 SOC_SINGLE_EXT("SLIM TX5", SND_SOC_NOPM, TAPAN_TX5, 1, 0,
1716 slim_tx_mixer_get, slim_tx_mixer_put),
1717};
1718
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001719static int tapan_codec_enable_adc(struct snd_soc_dapm_widget *w,
1720 struct snd_kcontrol *kcontrol, int event)
1721{
1722 struct snd_soc_codec *codec = w->codec;
1723 u16 adc_reg;
1724 u8 init_bit_shift;
1725
1726 dev_dbg(codec->dev, "%s(): %s %d\n", __func__, w->name, event);
1727
1728 if (w->reg == TAPAN_A_TX_1_EN) {
1729 init_bit_shift = 7;
1730 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1731 } else if (w->reg == TAPAN_A_TX_2_EN) {
1732 init_bit_shift = 6;
1733 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1734 } else if (w->reg == TAPAN_A_TX_3_EN) {
1735 init_bit_shift = 6;
1736 adc_reg = TAPAN_A_TX_1_2_TEST_CTL;
1737 } else if (w->reg == TAPAN_A_TX_4_EN) {
1738 init_bit_shift = 7;
1739 adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
1740 } else if (w->reg == TAPAN_A_TX_5_EN) {
1741 init_bit_shift = 6;
1742 adc_reg = TAPAN_A_TX_4_5_TEST_CTL;
1743 } else {
1744 pr_err("%s: Error, invalid adc register\n", __func__);
1745 return -EINVAL;
1746 }
1747
1748 switch (event) {
1749 case SND_SOC_DAPM_PRE_PMU:
1750 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1751 1 << init_bit_shift);
1752 break;
1753 case SND_SOC_DAPM_POST_PMU:
1754
1755 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1756
1757 break;
1758 }
1759 return 0;
1760}
1761
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001762static int tapan_codec_enable_aux_pga(struct snd_soc_dapm_widget *w,
1763 struct snd_kcontrol *kcontrol, int event)
1764{
1765 struct snd_soc_codec *codec = w->codec;
1766 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1767
1768 dev_dbg(codec->dev, "%s: %d\n", __func__, event);
1769
1770 switch (event) {
1771 case SND_SOC_DAPM_PRE_PMU:
Joonwoo Park533b3682013-06-13 11:41:21 -07001772 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001773 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
1774 WCD9XXX_BANDGAP_AUDIO_MODE);
1775 /* AUX PGA requires RCO or MCLK */
1776 wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_RCO);
Joonwoo Park533b3682013-06-13 11:41:21 -07001777 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001778 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 1);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001779 break;
1780
1781 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001782 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 0);
Joonwoo Park533b3682013-06-13 11:41:21 -07001783 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001784 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
1785 WCD9XXX_BANDGAP_AUDIO_MODE);
1786 wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_RCO);
Joonwoo Park533b3682013-06-13 11:41:21 -07001787 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001788 break;
1789 }
1790 return 0;
1791}
1792
1793static int tapan_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1794 struct snd_kcontrol *kcontrol, int event)
1795{
1796 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001797 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001798 u16 lineout_gain_reg;
1799
1800 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
1801
1802 switch (w->shift) {
1803 case 0:
1804 lineout_gain_reg = TAPAN_A_RX_LINE_1_GAIN;
1805 break;
1806 case 1:
1807 lineout_gain_reg = TAPAN_A_RX_LINE_2_GAIN;
1808 break;
1809 default:
1810 pr_err("%s: Error, incorrect lineout register value\n",
1811 __func__);
1812 return -EINVAL;
1813 }
1814
1815 switch (event) {
1816 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001817 break;
1818 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001819 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
1820 WCD9XXX_CLSH_STATE_LO,
1821 WCD9XXX_CLSH_REQ_ENABLE,
1822 WCD9XXX_CLSH_EVENT_POST_PA);
1823 dev_dbg(codec->dev, "%s: sleeping 3 ms after %s PA turn on\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001824 __func__, w->name);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001825 usleep_range(3000, 3010);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001826 break;
1827 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001828 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
1829 WCD9XXX_CLSH_STATE_LO,
1830 WCD9XXX_CLSH_REQ_DISABLE,
1831 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001832 break;
1833 }
1834 return 0;
1835}
1836
1837static int tapan_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1838 struct snd_kcontrol *kcontrol, int event)
1839{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001840 struct snd_soc_codec *codec = w->codec;
1841 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1842
1843 dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001844 switch (event) {
1845 case SND_SOC_DAPM_PRE_PMU:
1846 tapan->spkr_pa_widget_on = true;
1847 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
1848 break;
1849 case SND_SOC_DAPM_POST_PMD:
1850 tapan->spkr_pa_widget_on = false;
1851 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x00);
1852 break;
1853 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001854 return 0;
1855}
1856
1857static int tapan_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1858 struct snd_kcontrol *kcontrol, int event)
1859{
1860 struct snd_soc_codec *codec = w->codec;
1861 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1862 u8 dmic_clk_en;
1863 u16 dmic_clk_reg;
1864 s32 *dmic_clk_cnt;
1865 unsigned int dmic;
1866 int ret;
1867
Bhalchandra Gajareea898742013-03-05 18:15:53 -08001868 ret = kstrtouint(strpbrk(w->name, "1234"), 10, &dmic);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001869 if (ret < 0) {
1870 pr_err("%s: Invalid DMIC line on the codec\n", __func__);
1871 return -EINVAL;
1872 }
1873
1874 switch (dmic) {
1875 case 1:
1876 case 2:
1877 dmic_clk_en = 0x01;
1878 dmic_clk_cnt = &(tapan->dmic_1_2_clk_cnt);
1879 dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B1_CTL;
1880 dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
1881 __func__, event, dmic, *dmic_clk_cnt);
1882
1883 break;
1884
1885 case 3:
1886 case 4:
1887 dmic_clk_en = 0x10;
1888 dmic_clk_cnt = &(tapan->dmic_3_4_clk_cnt);
1889 dmic_clk_reg = TAPAN_A_CDC_CLK_DMIC_B1_CTL;
1890
1891 dev_dbg(codec->dev, "%s() event %d DMIC%d dmic_3_4_clk_cnt %d\n",
1892 __func__, event, dmic, *dmic_clk_cnt);
1893 break;
1894
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001895 default:
1896 pr_err("%s: Invalid DMIC Selection\n", __func__);
1897 return -EINVAL;
1898 }
1899
1900 switch (event) {
1901 case SND_SOC_DAPM_PRE_PMU:
1902
1903 (*dmic_clk_cnt)++;
1904 if (*dmic_clk_cnt == 1)
1905 snd_soc_update_bits(codec, dmic_clk_reg,
1906 dmic_clk_en, dmic_clk_en);
1907
1908 break;
1909 case SND_SOC_DAPM_POST_PMD:
1910
1911 (*dmic_clk_cnt)--;
1912 if (*dmic_clk_cnt == 0)
1913 snd_soc_update_bits(codec, dmic_clk_reg,
1914 dmic_clk_en, 0);
1915 break;
1916 }
1917 return 0;
1918}
1919
1920static int tapan_codec_enable_anc(struct snd_soc_dapm_widget *w,
1921 struct snd_kcontrol *kcontrol, int event)
1922{
1923 struct snd_soc_codec *codec = w->codec;
1924 const char *filename;
1925 const struct firmware *fw;
1926 int i;
1927 int ret;
1928 int num_anc_slots;
Simmi Pateriyadf675e92013-04-05 01:15:54 +05301929 struct wcd9xxx_anc_header *anc_head;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001930 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
1931 u32 anc_writes_size = 0;
1932 int anc_size_remaining;
1933 u32 *anc_ptr;
1934 u16 reg;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001935 u8 mask, val, old_val;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001936
1937 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07001938 if (tapan->anc_func == 0)
1939 return 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001940 switch (event) {
1941 case SND_SOC_DAPM_PRE_PMU:
1942
1943 filename = "wcd9306/wcd9306_anc.bin";
1944
1945 ret = request_firmware(&fw, filename, codec->dev);
1946 if (ret != 0) {
1947 dev_err(codec->dev, "Failed to acquire ANC data: %d\n",
1948 ret);
1949 return -ENODEV;
1950 }
1951
Simmi Pateriyadf675e92013-04-05 01:15:54 +05301952 if (fw->size < sizeof(struct wcd9xxx_anc_header)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001953 dev_err(codec->dev, "Not enough data\n");
1954 release_firmware(fw);
1955 return -ENOMEM;
1956 }
1957
1958 /* First number is the number of register writes */
Simmi Pateriyadf675e92013-04-05 01:15:54 +05301959 anc_head = (struct wcd9xxx_anc_header *)(fw->data);
1960 anc_ptr = (u32 *)((u32)fw->data +
1961 sizeof(struct wcd9xxx_anc_header));
1962 anc_size_remaining = fw->size -
1963 sizeof(struct wcd9xxx_anc_header);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08001964 num_anc_slots = anc_head->num_anc_slots;
1965
1966 if (tapan->anc_slot >= num_anc_slots) {
1967 dev_err(codec->dev, "Invalid ANC slot selected\n");
1968 release_firmware(fw);
1969 return -EINVAL;
1970 }
1971
1972 for (i = 0; i < num_anc_slots; i++) {
1973
1974 if (anc_size_remaining < TAPAN_PACKED_REG_SIZE) {
1975 dev_err(codec->dev, "Invalid register format\n");
1976 release_firmware(fw);
1977 return -EINVAL;
1978 }
1979 anc_writes_size = (u32)(*anc_ptr);
1980 anc_size_remaining -= sizeof(u32);
1981 anc_ptr += 1;
1982
1983 if (anc_writes_size * TAPAN_PACKED_REG_SIZE
1984 > anc_size_remaining) {
1985 dev_err(codec->dev, "Invalid register format\n");
1986 release_firmware(fw);
1987 return -ENOMEM;
1988 }
1989
1990 if (tapan->anc_slot == i)
1991 break;
1992
1993 anc_size_remaining -= (anc_writes_size *
1994 TAPAN_PACKED_REG_SIZE);
1995 anc_ptr += anc_writes_size;
1996 }
1997 if (i == num_anc_slots) {
1998 dev_err(codec->dev, "Selected ANC slot not present\n");
1999 release_firmware(fw);
2000 return -ENOMEM;
2001 }
2002
2003 for (i = 0; i < anc_writes_size; i++) {
2004 TAPAN_CODEC_UNPACK_ENTRY(anc_ptr[i], reg,
2005 mask, val);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002006 old_val = snd_soc_read(codec, reg);
2007 snd_soc_write(codec, reg, (old_val & ~mask) |
2008 (val & mask));
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002009 }
2010 release_firmware(fw);
2011
2012 break;
Damir Didjusto1ede84a2013-05-23 16:38:11 -07002013 case SND_SOC_DAPM_PRE_PMD:
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002014 msleep(40);
2015 snd_soc_update_bits(codec, TAPAN_A_CDC_ANC1_B1_CTL, 0x01, 0x00);
2016 snd_soc_update_bits(codec, TAPAN_A_CDC_ANC2_B1_CTL, 0x02, 0x00);
2017 msleep(20);
2018 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0x0F);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002019 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_CLK_EN_CTL, 0);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002020 snd_soc_write(codec, TAPAN_A_CDC_CLK_ANC_RESET_CTL, 0xFF);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002021 break;
2022 }
2023 return 0;
2024}
2025
2026static int tapan_codec_enable_micbias(struct snd_soc_dapm_widget *w,
2027 struct snd_kcontrol *kcontrol, int event)
2028{
2029 struct snd_soc_codec *codec = w->codec;
2030 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2031 u16 micb_int_reg;
2032 u8 cfilt_sel_val = 0;
2033 char *internal1_text = "Internal1";
2034 char *internal2_text = "Internal2";
2035 char *internal3_text = "Internal3";
2036 enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
2037
2038 dev_dbg(codec->dev, "%s %d\n", __func__, event);
2039 switch (w->reg) {
2040 case TAPAN_A_MICB_1_CTL:
2041 micb_int_reg = TAPAN_A_MICB_1_INT_RBIAS;
2042 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias1_cfilt_sel;
2043 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
2044 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
2045 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
2046 break;
2047 case TAPAN_A_MICB_2_CTL:
2048 micb_int_reg = TAPAN_A_MICB_2_INT_RBIAS;
2049 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias2_cfilt_sel;
2050 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_2_ON;
2051 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_2_ON;
2052 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_2_OFF;
2053 break;
2054 case TAPAN_A_MICB_3_CTL:
2055 micb_int_reg = TAPAN_A_MICB_3_INT_RBIAS;
2056 cfilt_sel_val = tapan->resmgr.pdata->micbias.bias3_cfilt_sel;
2057 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_3_ON;
2058 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_3_ON;
2059 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_3_OFF;
2060 break;
2061 default:
2062 pr_err("%s: Error, invalid micbias register\n", __func__);
2063 return -EINVAL;
2064 }
2065
2066 switch (event) {
2067 case SND_SOC_DAPM_PRE_PMU:
2068 /* Let MBHC module know so micbias switch to be off */
2069 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_pre_on);
2070
2071 /* Get cfilt */
2072 wcd9xxx_resmgr_cfilt_get(&tapan->resmgr, cfilt_sel_val);
2073
2074 if (strnstr(w->name, internal1_text, 30))
2075 snd_soc_update_bits(codec, micb_int_reg, 0xE0, 0xE0);
2076 else if (strnstr(w->name, internal2_text, 30))
2077 snd_soc_update_bits(codec, micb_int_reg, 0x1C, 0x1C);
2078 else if (strnstr(w->name, internal3_text, 30))
2079 snd_soc_update_bits(codec, micb_int_reg, 0x3, 0x3);
2080
2081 break;
2082 case SND_SOC_DAPM_POST_PMU:
2083 usleep_range(20000, 20000);
2084 /* Let MBHC module know so micbias is on */
2085 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_on);
2086 break;
2087 case SND_SOC_DAPM_POST_PMD:
2088 /* Let MBHC module know so micbias switch to be off */
2089 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
2090
2091 if (strnstr(w->name, internal1_text, 30))
2092 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
2093 else if (strnstr(w->name, internal2_text, 30))
2094 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
2095 else if (strnstr(w->name, internal3_text, 30))
2096 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
2097
2098 /* Put cfilt */
2099 wcd9xxx_resmgr_cfilt_put(&tapan->resmgr, cfilt_sel_val);
2100 break;
2101 }
2102
2103 return 0;
2104}
2105
2106static void tx_hpf_corner_freq_callback(struct work_struct *work)
2107{
2108 struct delayed_work *hpf_delayed_work;
2109 struct hpf_work *hpf_work;
2110 struct tapan_priv *tapan;
2111 struct snd_soc_codec *codec;
2112 u16 tx_mux_ctl_reg;
2113 u8 hpf_cut_of_freq;
2114
2115 hpf_delayed_work = to_delayed_work(work);
2116 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
2117 tapan = hpf_work->tapan;
2118 codec = hpf_work->tapan->codec;
2119 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
2120
2121 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL +
2122 (hpf_work->decimator - 1) * 8;
2123
2124 dev_dbg(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
2125 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
2126
2127 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
2128}
2129
2130#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
2131#define CF_MIN_3DB_4HZ 0x0
2132#define CF_MIN_3DB_75HZ 0x1
2133#define CF_MIN_3DB_150HZ 0x2
2134
2135static int tapan_codec_enable_dec(struct snd_soc_dapm_widget *w,
2136 struct snd_kcontrol *kcontrol, int event)
2137{
2138 struct snd_soc_codec *codec = w->codec;
2139 unsigned int decimator;
2140 char *dec_name = NULL;
2141 char *widget_name = NULL;
2142 char *temp;
2143 int ret = 0;
2144 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
2145 u8 dec_hpf_cut_of_freq;
2146 int offset;
2147
2148 dev_dbg(codec->dev, "%s %d\n", __func__, event);
2149
2150 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
2151 if (!widget_name)
2152 return -ENOMEM;
2153 temp = widget_name;
2154
2155 dec_name = strsep(&widget_name, " ");
2156 widget_name = temp;
2157 if (!dec_name) {
2158 pr_err("%s: Invalid decimator = %s\n", __func__, w->name);
2159 ret = -EINVAL;
2160 goto out;
2161 }
2162
2163 ret = kstrtouint(strpbrk(dec_name, "123456789"), 10, &decimator);
2164 if (ret < 0) {
2165 pr_err("%s: Invalid decimator = %s\n", __func__, dec_name);
2166 ret = -EINVAL;
2167 goto out;
2168 }
2169
2170 dev_dbg(codec->dev, "%s(): widget = %s dec_name = %s decimator = %u\n",
2171 __func__, w->name, dec_name, decimator);
2172
2173 if (w->reg == TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
2174 dec_reset_reg = TAPAN_A_CDC_CLK_TX_RESET_B1_CTL;
2175 offset = 0;
2176 } else if (w->reg == TAPAN_A_CDC_CLK_TX_CLK_EN_B2_CTL) {
2177 dec_reset_reg = TAPAN_A_CDC_CLK_TX_RESET_B2_CTL;
2178 offset = 8;
2179 } else {
2180 pr_err("%s: Error, incorrect dec\n", __func__);
2181 ret = -EINVAL;
2182 goto out;
2183 }
2184
2185 tx_vol_ctl_reg = TAPAN_A_CDC_TX1_VOL_CTL_CFG + 8 * (decimator - 1);
2186 tx_mux_ctl_reg = TAPAN_A_CDC_TX1_MUX_CTL + 8 * (decimator - 1);
2187
2188 switch (event) {
2189 case SND_SOC_DAPM_PRE_PMU:
2190
2191 /* Enableable TX digital mute */
2192 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2193
2194 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
2195 1 << w->shift);
2196 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
2197
2198 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
2199
2200 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
2201
2202 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
2203 dec_hpf_cut_of_freq;
2204
2205 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
2206
2207 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
2208 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2209 CF_MIN_3DB_150HZ << 4);
2210 }
2211
2212 /* enable HPF */
2213 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
2214
2215 break;
2216
2217 case SND_SOC_DAPM_POST_PMU:
2218
2219 /* Disable TX digital mute */
2220 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
2221
2222 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
2223 CF_MIN_3DB_150HZ) {
2224
2225 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
2226 msecs_to_jiffies(300));
2227 }
2228 /* apply the digital gain after the decimator is enabled*/
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002229 if ((w->shift + offset) < ARRAY_SIZE(tx_digital_gain_reg))
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002230 snd_soc_write(codec,
2231 tx_digital_gain_reg[w->shift + offset],
2232 snd_soc_read(codec,
2233 tx_digital_gain_reg[w->shift + offset])
2234 );
2235
2236 break;
2237
2238 case SND_SOC_DAPM_PRE_PMD:
2239
2240 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
2241 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
2242 break;
2243
2244 case SND_SOC_DAPM_POST_PMD:
2245
2246 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
2247 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
2248 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
2249
2250 break;
2251 }
2252out:
2253 kfree(widget_name);
2254 return ret;
2255}
2256
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002257static int tapan_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w,
2258 struct snd_kcontrol *kcontrol, int event)
2259{
2260 struct snd_soc_codec *codec = w->codec;
2261 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
2262
2263 dev_dbg(codec->dev, "%s: %s %d\n", __func__, w->name, event);
2264
2265 switch (event) {
2266 case SND_SOC_DAPM_PRE_PMU:
2267
2268 if (spkr_drv_wrnd > 0) {
2269 WARN_ON(!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
2270 0x80));
2271 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
2272 0x00);
2273 }
2274 if (TAPAN_IS_1_0(core->version))
2275 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
2276 0x24, 0x00);
2277 break;
2278 case SND_SOC_DAPM_POST_PMD:
2279 if (TAPAN_IS_1_0(core->version))
2280 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_DBG_PWRSTG,
2281 0x24, 0x24);
2282 if (spkr_drv_wrnd > 0) {
2283 WARN_ON(!!(snd_soc_read(codec, TAPAN_A_SPKR_DRV_EN) &
2284 0x80));
2285 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80,
2286 0x80);
2287 }
2288 break;
2289 }
2290 return 0;
2291}
2292
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002293static int tapan_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
2294 struct snd_kcontrol *kcontrol, int event)
2295{
2296 struct snd_soc_codec *codec = w->codec;
2297
2298 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
2299
2300 switch (event) {
2301 case SND_SOC_DAPM_PRE_PMU:
2302 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_RESET_CTL,
2303 1 << w->shift, 1 << w->shift);
2304 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RX_RESET_CTL,
2305 1 << w->shift, 0x0);
2306 break;
2307 case SND_SOC_DAPM_POST_PMU:
2308 /* apply the digital gain after the interpolator is enabled*/
2309 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
2310 snd_soc_write(codec,
2311 rx_digital_gain_reg[w->shift],
2312 snd_soc_read(codec,
2313 rx_digital_gain_reg[w->shift])
2314 );
2315 break;
2316 }
2317 return 0;
2318}
2319
2320static int tapan_codec_enable_ldo_h(struct snd_soc_dapm_widget *w,
2321 struct snd_kcontrol *kcontrol, int event)
2322{
2323 switch (event) {
2324 case SND_SOC_DAPM_POST_PMU:
2325 case SND_SOC_DAPM_POST_PMD:
2326 usleep_range(1000, 1000);
2327 break;
2328 }
2329 return 0;
2330}
2331
2332static int tapan_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
2333 struct snd_kcontrol *kcontrol, int event)
2334{
2335 struct snd_soc_codec *codec = w->codec;
2336 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2337
2338 dev_dbg(codec->dev, "%s %d\n", __func__, event);
2339
2340 switch (event) {
2341 case SND_SOC_DAPM_PRE_PMU:
2342 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 1);
2343 break;
2344 case SND_SOC_DAPM_POST_PMD:
2345 wcd9xxx_resmgr_enable_rx_bias(&tapan->resmgr, 0);
2346 break;
2347 }
2348 return 0;
2349}
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002350
2351
2352static int tapan_hphl_dac_event(struct snd_soc_dapm_widget *w,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002353 struct snd_kcontrol *kcontrol, int event)
2354{
2355 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002356 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002357
2358 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2359
2360 switch (event) {
2361 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002362 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2363 0x02, 0x02);
2364 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
2365 WCD9XXX_CLSH_STATE_HPHL,
2366 WCD9XXX_CLSH_REQ_ENABLE,
2367 WCD9XXX_CLSH_EVENT_PRE_DAC);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002368 break;
2369 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002370 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2371 0x02, 0x00);
2372 }
2373 return 0;
2374}
2375
2376static int tapan_hphr_dac_event(struct snd_soc_dapm_widget *w,
2377 struct snd_kcontrol *kcontrol, int event)
2378{
2379 struct snd_soc_codec *codec = w->codec;
2380 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
2381
2382 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2383
2384 switch (event) {
2385 case SND_SOC_DAPM_PRE_PMU:
2386 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2387 0x04, 0x04);
2388 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2389 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
2390 WCD9XXX_CLSH_STATE_HPHR,
2391 WCD9XXX_CLSH_REQ_ENABLE,
2392 WCD9XXX_CLSH_EVENT_PRE_DAC);
2393 break;
2394 case SND_SOC_DAPM_POST_PMD:
2395 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_RDAC_CLK_EN_CTL,
2396 0x04, 0x00);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002397 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2398 break;
2399 }
2400 return 0;
2401}
2402
2403static int tapan_hph_pa_event(struct snd_soc_dapm_widget *w,
2404 struct snd_kcontrol *kcontrol, int event)
2405{
2406 struct snd_soc_codec *codec = w->codec;
2407 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
2408 enum wcd9xxx_notify_event e_pre_on, e_post_off;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002409 u8 req_clsh_state;
Banajit Goswamia7294452013-06-03 12:42:35 -07002410 u32 pa_settle_time = TAPAN_HPH_PA_SETTLE_COMP_OFF;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002411
2412 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
2413 if (w->shift == 5) {
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002414 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
2415 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002416 req_clsh_state = WCD9XXX_CLSH_STATE_HPHR;
Phani Kumar Uppalapatieca9a102013-06-18 11:02:38 -07002417 } else if (w->shift == 4) {
2418 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
2419 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
2420 req_clsh_state = WCD9XXX_CLSH_STATE_HPHL;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002421 } else {
2422 pr_err("%s: Invalid w->shift %d\n", __func__, w->shift);
2423 return -EINVAL;
2424 }
2425
Banajit Goswamia7294452013-06-03 12:42:35 -07002426 if (tapan->comp_enabled[COMPANDER_1])
2427 pa_settle_time = TAPAN_HPH_PA_SETTLE_COMP_ON;
2428
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002429 switch (event) {
2430 case SND_SOC_DAPM_PRE_PMU:
2431 /* Let MBHC module know PA is turning on */
2432 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_pre_on);
2433 break;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002434 case SND_SOC_DAPM_POST_PMU:
Banajit Goswamia7294452013-06-03 12:42:35 -07002435 dev_dbg(codec->dev, "%s: sleep %d ms after %s PA enable.\n",
2436 __func__, pa_settle_time / 1000, w->name);
2437 /* Time needed for PA to settle */
2438 usleep_range(pa_settle_time, pa_settle_time + 1000);
2439
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002440 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2441 req_clsh_state,
2442 WCD9XXX_CLSH_REQ_ENABLE,
2443 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002444
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002445 break;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002446 case SND_SOC_DAPM_POST_PMD:
Banajit Goswamia7294452013-06-03 12:42:35 -07002447 dev_dbg(codec->dev, "%s: sleep %d ms after %s PA disable.\n",
2448 __func__, pa_settle_time / 1000, w->name);
2449 /* Time needed for PA to settle */
2450 usleep_range(pa_settle_time, pa_settle_time + 1000);
2451
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002452 /* Let MBHC module know PA turned off */
2453 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, e_post_off);
2454
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002455 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2456 req_clsh_state,
2457 WCD9XXX_CLSH_REQ_DISABLE,
2458 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002459 break;
2460 }
2461 return 0;
2462}
2463
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002464static int tapan_codec_enable_anc_hph(struct snd_soc_dapm_widget *w,
2465 struct snd_kcontrol *kcontrol, int event)
2466{
2467 struct snd_soc_codec *codec = w->codec;
2468 int ret = 0;
2469
2470 switch (event) {
2471 case SND_SOC_DAPM_PRE_PMU:
2472 ret = tapan_hph_pa_event(w, kcontrol, event);
2473 if (w->shift == 4) {
2474 ret |= tapan_codec_enable_anc(w, kcontrol, event);
2475 msleep(50);
2476 }
2477 break;
2478 case SND_SOC_DAPM_POST_PMU:
2479 if (w->shift == 4) {
2480 snd_soc_update_bits(codec,
2481 TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x30);
2482 msleep(30);
2483 }
2484 ret = tapan_hph_pa_event(w, kcontrol, event);
2485 break;
2486 case SND_SOC_DAPM_PRE_PMD:
2487 if (w->shift == 5) {
2488 snd_soc_update_bits(codec,
2489 TAPAN_A_RX_HPH_CNP_EN, 0x30, 0x00);
2490 msleep(40);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002491 snd_soc_update_bits(codec,
2492 TAPAN_A_TX_7_MBHC_EN, 0x80, 00);
2493 ret |= tapan_codec_enable_anc(w, kcontrol, event);
2494 }
Damir Didjusto1ede84a2013-05-23 16:38:11 -07002495 break;
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002496 case SND_SOC_DAPM_POST_PMD:
2497 ret = tapan_hph_pa_event(w, kcontrol, event);
2498 break;
2499 }
2500 return ret;
2501}
2502
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002503static const struct snd_soc_dapm_widget tapan_dapm_i2s_widgets[] = {
2504 SND_SOC_DAPM_SUPPLY("I2S_CLK", TAPAN_A_CDC_CLK_I2S_CTL,
2505 4, 0, NULL, 0),
2506};
2507
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002508static int tapan_lineout_dac_event(struct snd_soc_dapm_widget *w,
2509 struct snd_kcontrol *kcontrol, int event)
2510{
2511 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002512 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002513
2514 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2515
2516 switch (event) {
2517 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002518 wcd9xxx_clsh_fsm(codec, &tapan->clsh_d,
2519 WCD9XXX_CLSH_STATE_LO,
2520 WCD9XXX_CLSH_REQ_ENABLE,
2521 WCD9XXX_CLSH_EVENT_PRE_DAC);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002522 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
2523 break;
2524
2525 case SND_SOC_DAPM_POST_PMD:
2526 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2527 break;
2528 }
2529 return 0;
2530}
2531
2532static int tapan_spk_dac_event(struct snd_soc_dapm_widget *w,
2533 struct snd_kcontrol *kcontrol, int event)
2534{
2535 struct snd_soc_codec *codec = w->codec;
2536
2537 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
2538 return 0;
2539}
2540
2541static const struct snd_soc_dapm_route audio_i2s_map[] = {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002542 {"I2S_CLK", NULL, "CDC_CONN"},
2543 {"SLIM RX1", NULL, "I2S_CLK"},
2544 {"SLIM RX2", NULL, "I2S_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002545
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002546 {"SLIM TX1 MUX", NULL, "I2S_CLK"},
2547 {"SLIM TX2 MUX", NULL, "I2S_CLK"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002548};
2549
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07002550static const struct snd_soc_dapm_route wcd9306_map[] = {
2551 {"SLIM TX1 MUX", "RMIX4", "RX4 MIX1"},
2552 {"SLIM TX2 MUX", "RMIX4", "RX4 MIX1"},
2553 {"SLIM TX3 MUX", "RMIX4", "RX4 MIX1"},
2554 {"SLIM TX4 MUX", "RMIX4", "RX4 MIX1"},
2555 {"SLIM TX5 MUX", "RMIX4", "RX4 MIX1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002556 {"SLIM TX1 MUX", "DEC3", "DEC3 MUX"},
2557 {"SLIM TX1 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002558 {"SLIM TX2 MUX", "DEC3", "DEC3 MUX"},
2559 {"SLIM TX2 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002560 {"SLIM TX3 MUX", "DEC3", "DEC3 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002561 {"SLIM TX4 MUX", "DEC4", "DEC4 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002562
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002563 {"ANC EAR", NULL, "ANC EAR PA"},
2564 {"ANC EAR PA", NULL, "EAR_PA_MIXER"},
2565 {"ANC1 FB MUX", "EAR_HPH_L", "RX1 MIX2"},
2566 {"ANC1 FB MUX", "EAR_LINE_1", "RX2 MIX2"},
2567
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002568 {"ANC HEADPHONE", NULL, "ANC HPHL"},
2569 {"ANC HEADPHONE", NULL, "ANC HPHR"},
2570
2571 {"ANC HPHL", NULL, "HPHL_PA_MIXER"},
2572 {"ANC HPHR", NULL, "HPHR_PA_MIXER"},
2573
2574 {"ANC1 MUX", "ADC1", "ADC1"},
2575 {"ANC1 MUX", "ADC2", "ADC2"},
2576 {"ANC1 MUX", "ADC3", "ADC3"},
2577 {"ANC1 MUX", "ADC4", "ADC4"},
2578 {"ANC1 MUX", "ADC5", "ADC5"},
2579 {"ANC1 MUX", "DMIC1", "DMIC1"},
2580 {"ANC1 MUX", "DMIC2", "DMIC2"},
2581 {"ANC1 MUX", "DMIC3", "DMIC3"},
2582 {"ANC1 MUX", "DMIC4", "DMIC4"},
2583 {"ANC2 MUX", "ADC1", "ADC1"},
2584 {"ANC2 MUX", "ADC2", "ADC2"},
2585 {"ANC2 MUX", "ADC3", "ADC3"},
2586 {"ANC2 MUX", "ADC4", "ADC4"},
2587 {"ANC2 MUX", "ADC5", "ADC5"},
2588 {"ANC2 MUX", "DMIC1", "DMIC1"},
2589 {"ANC2 MUX", "DMIC2", "DMIC2"},
2590 {"ANC2 MUX", "DMIC3", "DMIC3"},
2591 {"ANC2 MUX", "DMIC4", "DMIC4"},
2592
2593 {"ANC HPHR", NULL, "CDC_CONN"},
2594
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07002595 {"RDAC5 MUX", "DEM4", "RX4 MIX2"},
2596 {"SPK DAC", "Switch", "RX4 MIX2"},
2597
2598 {"RX1 MIX2", NULL, "ANC1 MUX"},
2599 {"RX2 MIX2", NULL, "ANC2 MUX"},
2600
2601 {"RX1 MIX1", NULL, "COMP1_CLK"},
2602 {"RX2 MIX1", NULL, "COMP1_CLK"},
2603 {"RX3 MIX1", NULL, "COMP2_CLK"},
2604 {"RX4 MIX1", NULL, "COMP0_CLK"},
2605
2606 {"RX4 MIX1", NULL, "RX4 MIX1 INP1"},
2607 {"RX4 MIX1", NULL, "RX4 MIX1 INP2"},
2608 {"RX4 MIX2", NULL, "RX4 MIX1"},
2609 {"RX4 MIX2", NULL, "RX4 MIX2 INP1"},
2610 {"RX4 MIX2", NULL, "RX4 MIX2 INP2"},
2611
2612 {"RX4 MIX1 INP1", "RX1", "SLIM RX1"},
2613 {"RX4 MIX1 INP1", "RX2", "SLIM RX2"},
2614 {"RX4 MIX1 INP1", "RX3", "SLIM RX3"},
2615 {"RX4 MIX1 INP1", "RX4", "SLIM RX4"},
2616 {"RX4 MIX1 INP1", "RX5", "SLIM RX5"},
2617 {"RX4 MIX1 INP1", "IIR1", "IIR1"},
2618 {"RX4 MIX1 INP2", "RX1", "SLIM RX1"},
2619 {"RX4 MIX1 INP2", "RX2", "SLIM RX2"},
2620 {"RX4 MIX1 INP2", "RX3", "SLIM RX3"},
2621 {"RX4 MIX1 INP2", "RX5", "SLIM RX5"},
2622 {"RX4 MIX1 INP2", "RX4", "SLIM RX4"},
2623 {"RX4 MIX1 INP2", "IIR1", "IIR1"},
2624 {"RX4 MIX2 INP1", "IIR1", "IIR1"},
2625 {"RX4 MIX2 INP2", "IIR1", "IIR1"},
2626
2627 {"DEC1 MUX", "DMIC3", "DMIC3"},
2628 {"DEC1 MUX", "DMIC4", "DMIC4"},
2629 {"DEC2 MUX", "DMIC3", "DMIC3"},
2630 {"DEC2 MUX", "DMIC4", "DMIC4"},
2631
2632 {"DEC3 MUX", "ADC1", "ADC1"},
2633 {"DEC3 MUX", "ADC2", "ADC2"},
2634 {"DEC3 MUX", "ADC3", "ADC3"},
2635 {"DEC3 MUX", "ADC4", "ADC4"},
2636 {"DEC3 MUX", "ADC5", "ADC5"},
2637 {"DEC3 MUX", "DMIC1", "DMIC1"},
2638 {"DEC3 MUX", "DMIC2", "DMIC2"},
2639 {"DEC3 MUX", "DMIC3", "DMIC3"},
2640 {"DEC3 MUX", "DMIC4", "DMIC4"},
2641 {"DEC3 MUX", NULL, "CDC_CONN"},
2642
2643 {"DEC4 MUX", "ADC1", "ADC1"},
2644 {"DEC4 MUX", "ADC2", "ADC2"},
2645 {"DEC4 MUX", "ADC3", "ADC3"},
2646 {"DEC4 MUX", "ADC4", "ADC4"},
2647 {"DEC4 MUX", "ADC5", "ADC5"},
2648 {"DEC4 MUX", "DMIC1", "DMIC1"},
2649 {"DEC4 MUX", "DMIC2", "DMIC2"},
2650 {"DEC4 MUX", "DMIC3", "DMIC3"},
2651 {"DEC4 MUX", "DMIC4", "DMIC4"},
2652 {"DEC4 MUX", NULL, "CDC_CONN"},
2653
2654 {"ADC5", NULL, "AMIC5"},
2655
2656 {"AUX_PGA_Left", NULL, "AMIC5"},
2657
2658 {"IIR1 INP1 MUX", "DEC3", "DEC3 MUX"},
2659 {"IIR1 INP1 MUX", "DEC4", "DEC4 MUX"},
2660
2661 {"MIC BIAS3 Internal1", NULL, "LDO_H"},
2662 {"MIC BIAS3 Internal2", NULL, "LDO_H"},
2663 {"MIC BIAS3 External", NULL, "LDO_H"},
2664};
2665
2666static const struct snd_soc_dapm_route audio_map[] = {
2667 /* SLIMBUS Connections */
2668 {"AIF1 CAP", NULL, "AIF1_CAP Mixer"},
2669 {"AIF2 CAP", NULL, "AIF2_CAP Mixer"},
2670 {"AIF3 CAP", NULL, "AIF3_CAP Mixer"},
2671
2672 /* SLIM_MIXER("AIF1_CAP Mixer"),*/
2673 {"AIF1_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2674 {"AIF1_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2675 {"AIF1_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2676 {"AIF1_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2677 {"AIF1_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
2678 /* SLIM_MIXER("AIF2_CAP Mixer"),*/
2679 {"AIF2_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2680 {"AIF2_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2681 {"AIF2_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2682 {"AIF2_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2683 {"AIF2_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
2684 /* SLIM_MIXER("AIF3_CAP Mixer"),*/
2685 {"AIF3_CAP Mixer", "SLIM TX1", "SLIM TX1 MUX"},
2686 {"AIF3_CAP Mixer", "SLIM TX2", "SLIM TX2 MUX"},
2687 {"AIF3_CAP Mixer", "SLIM TX3", "SLIM TX3 MUX"},
2688 {"AIF3_CAP Mixer", "SLIM TX4", "SLIM TX4 MUX"},
2689 {"AIF3_CAP Mixer", "SLIM TX5", "SLIM TX5 MUX"},
2690
2691 {"SLIM TX1 MUX", "DEC1", "DEC1 MUX"},
2692 {"SLIM TX1 MUX", "DEC2", "DEC2 MUX"},
2693 {"SLIM TX1 MUX", "RMIX1", "RX1 MIX1"},
2694 {"SLIM TX1 MUX", "RMIX2", "RX2 MIX1"},
2695 {"SLIM TX1 MUX", "RMIX3", "RX3 MIX1"},
2696
2697 {"SLIM TX2 MUX", "DEC1", "DEC1 MUX"},
2698 {"SLIM TX2 MUX", "DEC2", "DEC2 MUX"},
2699 {"SLIM TX2 MUX", "RMIX1", "RX1 MIX1"},
2700 {"SLIM TX2 MUX", "RMIX2", "RX2 MIX1"},
2701 {"SLIM TX2 MUX", "RMIX3", "RX3 MIX1"},
2702
2703 {"SLIM TX3 MUX", "RMIX1", "RX1 MIX1"},
2704 {"SLIM TX3 MUX", "RMIX2", "RX2 MIX1"},
2705 {"SLIM TX3 MUX", "RMIX3", "RX3 MIX1"},
2706
2707 {"SLIM TX4 MUX", "RMIX1", "RX1 MIX1"},
2708 {"SLIM TX4 MUX", "RMIX2", "RX2 MIX1"},
2709 {"SLIM TX4 MUX", "RMIX3", "RX3 MIX1"},
2710
2711 {"SLIM TX5 MUX", "DEC1", "DEC1 MUX"},
2712 {"SLIM TX5 MUX", "RMIX1", "RX1 MIX1"},
2713 {"SLIM TX5 MUX", "RMIX2", "RX2 MIX1"},
2714 {"SLIM TX5 MUX", "RMIX3", "RX3 MIX1"},
2715
2716 /* Earpiece (RX MIX1) */
2717 {"EAR", NULL, "EAR PA"},
2718 {"EAR PA", NULL, "EAR_PA_MIXER"},
2719 {"EAR_PA_MIXER", NULL, "DAC1"},
2720 {"DAC1", NULL, "RX_BIAS"},
2721 {"DAC1", NULL, "CDC_CP_VDD"},
2722
2723
2724 /* Headset (RX MIX1 and RX MIX2) */
2725 {"HEADPHONE", NULL, "HPHL"},
2726 {"HEADPHONE", NULL, "HPHR"},
2727
2728 {"HPHL", NULL, "HPHL_PA_MIXER"},
2729 {"HPHL_PA_MIXER", NULL, "HPHL DAC"},
2730 {"HPHL DAC", NULL, "RX_BIAS"},
2731 {"HPHL DAC", NULL, "CDC_CP_VDD"},
2732
2733 {"HPHR", NULL, "HPHR_PA_MIXER"},
2734 {"HPHR_PA_MIXER", NULL, "HPHR DAC"},
2735 {"HPHR DAC", NULL, "RX_BIAS"},
2736 {"HPHR DAC", NULL, "CDC_CP_VDD"},
2737
2738
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002739 {"DAC1", "Switch", "CLASS_H_DSM MUX"},
2740 {"HPHL DAC", "Switch", "CLASS_H_DSM MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002741 {"HPHR DAC", NULL, "RX2 CHAIN"},
2742
2743 {"LINEOUT1", NULL, "LINEOUT1 PA"},
2744 {"LINEOUT2", NULL, "LINEOUT2 PA"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002745 {"SPK_OUT", NULL, "SPK PA"},
2746
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002747 {"LINEOUT1 PA", NULL, "LINEOUT1_PA_MIXER"},
2748 {"LINEOUT1_PA_MIXER", NULL, "LINEOUT1 DAC"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002749 {"LINEOUT2 PA", NULL, "LINEOUT2_PA_MIXER"},
2750 {"LINEOUT2_PA_MIXER", NULL, "LINEOUT2 DAC"},
2751
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002752 {"LINEOUT1 DAC", NULL, "RX3 MIX1"},
2753
2754 {"RDAC5 MUX", "DEM3_INV", "RX3 MIX1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002755 {"LINEOUT2 DAC", NULL, "RDAC5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002756
2757 {"SPK PA", NULL, "SPK DAC"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002758 {"SPK DAC", NULL, "VDD_SPKDRV"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002759
2760 {"RX1 CHAIN", NULL, "RX1 MIX2"},
2761 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002762 {"CLASS_H_DSM MUX", "RX_HPHL", "RX1 CHAIN"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002763
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002764 {"LINEOUT1 DAC", NULL, "RX_BIAS"},
2765 {"LINEOUT2 DAC", NULL, "RX_BIAS"},
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07002766 {"LINEOUT1 DAC", NULL, "CDC_CP_VDD"},
2767 {"LINEOUT2 DAC", NULL, "CDC_CP_VDD"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002768
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07002769 {"RDAC3 MUX", "DEM2", "RX2 MIX1"},
2770 {"RDAC3 MUX", "DEM1", "RX1 CHAIN"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002771
2772 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2773 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2774 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
2775 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2776 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2777 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2778 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002779 {"RX1 MIX2", NULL, "RX1 MIX1"},
2780 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
2781 {"RX1 MIX2", NULL, "RX1 MIX2 INP2"},
2782 {"RX2 MIX2", NULL, "RX2 MIX1"},
2783 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
2784 {"RX2 MIX2", NULL, "RX2 MIX2 INP2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002785
2786 /* SLIM_MUX("AIF1_PB", "AIF1 PB"),*/
2787 {"SLIM RX1 MUX", "AIF1_PB", "AIF1 PB"},
2788 {"SLIM RX2 MUX", "AIF1_PB", "AIF1 PB"},
2789 {"SLIM RX3 MUX", "AIF1_PB", "AIF1 PB"},
2790 {"SLIM RX4 MUX", "AIF1_PB", "AIF1 PB"},
2791 {"SLIM RX5 MUX", "AIF1_PB", "AIF1 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002792 /* SLIM_MUX("AIF2_PB", "AIF2 PB"),*/
2793 {"SLIM RX1 MUX", "AIF2_PB", "AIF2 PB"},
2794 {"SLIM RX2 MUX", "AIF2_PB", "AIF2 PB"},
2795 {"SLIM RX3 MUX", "AIF2_PB", "AIF2 PB"},
2796 {"SLIM RX4 MUX", "AIF2_PB", "AIF2 PB"},
2797 {"SLIM RX5 MUX", "AIF2_PB", "AIF2 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002798 /* SLIM_MUX("AIF3_PB", "AIF3 PB"),*/
2799 {"SLIM RX1 MUX", "AIF3_PB", "AIF3 PB"},
2800 {"SLIM RX2 MUX", "AIF3_PB", "AIF3 PB"},
2801 {"SLIM RX3 MUX", "AIF3_PB", "AIF3 PB"},
2802 {"SLIM RX4 MUX", "AIF3_PB", "AIF3 PB"},
2803 {"SLIM RX5 MUX", "AIF3_PB", "AIF3 PB"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002804
2805 {"SLIM RX1", NULL, "SLIM RX1 MUX"},
2806 {"SLIM RX2", NULL, "SLIM RX2 MUX"},
2807 {"SLIM RX3", NULL, "SLIM RX3 MUX"},
2808 {"SLIM RX4", NULL, "SLIM RX4 MUX"},
2809 {"SLIM RX5", NULL, "SLIM RX5 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002810
2811 {"RX1 MIX1 INP1", "RX1", "SLIM RX1"},
2812 {"RX1 MIX1 INP1", "RX2", "SLIM RX2"},
2813 {"RX1 MIX1 INP1", "RX3", "SLIM RX3"},
2814 {"RX1 MIX1 INP1", "RX4", "SLIM RX4"},
2815 {"RX1 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002816 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2817 {"RX1 MIX1 INP2", "RX1", "SLIM RX1"},
2818 {"RX1 MIX1 INP2", "RX2", "SLIM RX2"},
2819 {"RX1 MIX1 INP2", "RX3", "SLIM RX3"},
2820 {"RX1 MIX1 INP2", "RX4", "SLIM RX4"},
2821 {"RX1 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002822 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2823 {"RX1 MIX1 INP3", "RX1", "SLIM RX1"},
2824 {"RX1 MIX1 INP3", "RX2", "SLIM RX2"},
2825 {"RX1 MIX1 INP3", "RX3", "SLIM RX3"},
2826 {"RX1 MIX1 INP3", "RX4", "SLIM RX4"},
2827 {"RX1 MIX1 INP3", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002828 {"RX2 MIX1 INP1", "RX1", "SLIM RX1"},
2829 {"RX2 MIX1 INP1", "RX2", "SLIM RX2"},
2830 {"RX2 MIX1 INP1", "RX3", "SLIM RX3"},
2831 {"RX2 MIX1 INP1", "RX4", "SLIM RX4"},
2832 {"RX2 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002833 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
2834 {"RX2 MIX1 INP2", "RX1", "SLIM RX1"},
2835 {"RX2 MIX1 INP2", "RX2", "SLIM RX2"},
2836 {"RX2 MIX1 INP2", "RX3", "SLIM RX3"},
2837 {"RX2 MIX1 INP2", "RX4", "SLIM RX4"},
2838 {"RX2 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002839 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
2840 {"RX3 MIX1 INP1", "RX1", "SLIM RX1"},
2841 {"RX3 MIX1 INP1", "RX2", "SLIM RX2"},
2842 {"RX3 MIX1 INP1", "RX3", "SLIM RX3"},
2843 {"RX3 MIX1 INP1", "RX4", "SLIM RX4"},
2844 {"RX3 MIX1 INP1", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002845 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
2846 {"RX3 MIX1 INP2", "RX1", "SLIM RX1"},
2847 {"RX3 MIX1 INP2", "RX2", "SLIM RX2"},
2848 {"RX3 MIX1 INP2", "RX3", "SLIM RX3"},
2849 {"RX3 MIX1 INP2", "RX4", "SLIM RX4"},
2850 {"RX3 MIX1 INP2", "RX5", "SLIM RX5"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002851 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002852
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002853 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
2854 {"RX1 MIX2 INP2", "IIR1", "IIR1"},
2855 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
2856 {"RX2 MIX2 INP2", "IIR1", "IIR1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002857
2858 /* Decimator Inputs */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002859 {"DEC1 MUX", "ADC1", "ADC1"},
2860 {"DEC1 MUX", "ADC2", "ADC2"},
2861 {"DEC1 MUX", "ADC3", "ADC3"},
2862 {"DEC1 MUX", "ADC4", "ADC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002863 {"DEC1 MUX", "DMIC1", "DMIC1"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002864 {"DEC1 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002865 {"DEC1 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002866
2867 {"DEC2 MUX", "ADC1", "ADC1"},
2868 {"DEC2 MUX", "ADC2", "ADC2"},
2869 {"DEC2 MUX", "ADC3", "ADC3"},
2870 {"DEC2 MUX", "ADC4", "ADC4"},
2871 {"DEC2 MUX", "DMIC1", "DMIC1"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002872 {"DEC2 MUX", "DMIC2", "DMIC2"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002873 {"DEC2 MUX", NULL, "CDC_CONN"},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002874
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002875 /* ADC Connections */
2876 {"ADC1", NULL, "AMIC1"},
2877 {"ADC2", NULL, "AMIC2"},
2878 {"ADC3", NULL, "AMIC3"},
2879 {"ADC4", NULL, "AMIC4"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002880
2881 /* AUX PGA Connections */
2882 {"EAR_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2883 {"HPHL_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2884 {"HPHR_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
2885 {"LINEOUT1_PA_MIXER", "AUX_PGA_L Switch", "AUX_PGA_Left"},
2886 {"LINEOUT2_PA_MIXER", "AUX_PGA_R Switch", "AUX_PGA_Right"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002887
2888 {"IIR1", NULL, "IIR1 INP1 MUX"},
2889 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2890 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002891
2892 {"MIC BIAS1 Internal1", NULL, "LDO_H"},
2893 {"MIC BIAS1 Internal2", NULL, "LDO_H"},
2894 {"MIC BIAS1 External", NULL, "LDO_H"},
2895 {"MIC BIAS2 Internal1", NULL, "LDO_H"},
2896 {"MIC BIAS2 Internal2", NULL, "LDO_H"},
2897 {"MIC BIAS2 Internal3", NULL, "LDO_H"},
2898 {"MIC BIAS2 External", NULL, "LDO_H"},
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07002899};
2900
2901static const struct snd_soc_dapm_route wcd9302_map[] = {
2902 {"SPK DAC", "Switch", "RX3 MIX1"},
2903
2904 {"RDAC4 MUX", "DEM3", "RX3 MIX1"},
2905 {"RDAC4 MUX", "DEM2", "RX2 CHAIN"},
2906 {"LINEOUT1 DAC", NULL, "RDAC4 MUX"},
2907
2908 {"RDAC5 MUX", "DEM4", "RX3 MIX1"},
2909 {"RDAC5 MUX", "DEM3_INV", "RDAC4 MUX"},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002910};
2911
2912static int tapan_readable(struct snd_soc_codec *ssc, unsigned int reg)
2913{
2914 return tapan_reg_readable[reg];
2915}
2916
2917static bool tapan_is_digital_gain_register(unsigned int reg)
2918{
2919 bool rtn = false;
2920 switch (reg) {
2921 case TAPAN_A_CDC_RX1_VOL_CTL_B2_CTL:
2922 case TAPAN_A_CDC_RX2_VOL_CTL_B2_CTL:
2923 case TAPAN_A_CDC_RX3_VOL_CTL_B2_CTL:
2924 case TAPAN_A_CDC_RX4_VOL_CTL_B2_CTL:
2925 case TAPAN_A_CDC_TX1_VOL_CTL_GAIN:
2926 case TAPAN_A_CDC_TX2_VOL_CTL_GAIN:
2927 case TAPAN_A_CDC_TX3_VOL_CTL_GAIN:
2928 case TAPAN_A_CDC_TX4_VOL_CTL_GAIN:
2929 rtn = true;
2930 break;
2931 default:
2932 break;
2933 }
2934 return rtn;
2935}
2936
2937static int tapan_volatile(struct snd_soc_codec *ssc, unsigned int reg)
2938{
2939 /* Registers lower than 0x100 are top level registers which can be
Bhalchandra Gajareea898742013-03-05 18:15:53 -08002940 * written by the Tapan core driver.
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002941 */
2942
2943 if ((reg >= TAPAN_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
2944 return 1;
2945
2946 /* IIR Coeff registers are not cacheable */
2947 if ((reg >= TAPAN_A_CDC_IIR1_COEF_B1_CTL) &&
2948 (reg <= TAPAN_A_CDC_IIR2_COEF_B2_CTL))
2949 return 1;
2950
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07002951 /* ANC filter registers are not cacheable */
2952 if ((reg >= TAPAN_A_CDC_ANC1_IIR_B1_CTL) &&
2953 (reg <= TAPAN_A_CDC_ANC1_LPF_B2_CTL))
2954 return 1;
2955 if ((reg >= TAPAN_A_CDC_ANC2_IIR_B1_CTL) &&
2956 (reg <= TAPAN_A_CDC_ANC2_LPF_B2_CTL))
2957 return 1;
2958
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08002959 /* Digital gain register is not cacheable so we have to write
2960 * the setting even it is the same
2961 */
2962 if (tapan_is_digital_gain_register(reg))
2963 return 1;
2964
2965 /* HPH status registers */
2966 if (reg == TAPAN_A_RX_HPH_L_STATUS || reg == TAPAN_A_RX_HPH_R_STATUS)
2967 return 1;
2968
2969 if (reg == TAPAN_A_MBHC_INSERT_DET_STATUS)
2970 return 1;
2971
2972 return 0;
2973}
2974
2975#define TAPAN_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
2976static int tapan_write(struct snd_soc_codec *codec, unsigned int reg,
2977 unsigned int value)
2978{
2979 int ret;
2980
2981 if (reg == SND_SOC_NOPM)
2982 return 0;
2983
2984 BUG_ON(reg > TAPAN_MAX_REGISTER);
2985
2986 if (!tapan_volatile(codec, reg)) {
2987 ret = snd_soc_cache_write(codec, reg, value);
2988 if (ret != 0)
2989 dev_err(codec->dev, "Cache write to %x failed: %d\n",
2990 reg, ret);
2991 }
2992
2993 return wcd9xxx_reg_write(codec->control_data, reg, value);
2994}
2995static unsigned int tapan_read(struct snd_soc_codec *codec,
2996 unsigned int reg)
2997{
2998 unsigned int val;
2999 int ret;
3000
3001 if (reg == SND_SOC_NOPM)
3002 return 0;
3003
3004 BUG_ON(reg > TAPAN_MAX_REGISTER);
3005
3006 if (!tapan_volatile(codec, reg) && tapan_readable(codec, reg) &&
3007 reg < codec->driver->reg_cache_size) {
3008 ret = snd_soc_cache_read(codec, reg, &val);
3009 if (ret >= 0) {
3010 return val;
3011 } else
3012 dev_err(codec->dev, "Cache read from %x failed: %d\n",
3013 reg, ret);
3014 }
3015
3016 val = wcd9xxx_reg_read(codec->control_data, reg);
3017 return val;
3018}
3019
3020static int tapan_startup(struct snd_pcm_substream *substream,
3021 struct snd_soc_dai *dai)
3022{
3023 struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
3024 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
3025 __func__, substream->name, substream->stream);
3026 if ((tapan_core != NULL) &&
3027 (tapan_core->dev != NULL) &&
3028 (tapan_core->dev->parent != NULL))
3029 pm_runtime_get_sync(tapan_core->dev->parent);
3030
3031 return 0;
3032}
3033
3034static void tapan_shutdown(struct snd_pcm_substream *substream,
3035 struct snd_soc_dai *dai)
3036{
3037 struct wcd9xxx *tapan_core = dev_get_drvdata(dai->codec->dev->parent);
3038 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
3039 __func__, substream->name, substream->stream);
3040 if ((tapan_core != NULL) &&
3041 (tapan_core->dev != NULL) &&
3042 (tapan_core->dev->parent != NULL)) {
3043 pm_runtime_mark_last_busy(tapan_core->dev->parent);
3044 pm_runtime_put(tapan_core->dev->parent);
3045 }
3046}
3047
Bhalchandra Gajare4e3dd852013-08-19 17:21:23 -07003048static void tapan_set_vdd_cx_current(struct snd_soc_codec *codec,
3049 int current_uA)
3050{
3051 struct regulator *cx_regulator;
3052 int ret;
3053
3054 cx_regulator = tapan_codec_find_regulator(codec,
3055 "cdc-vdd-cx");
3056
3057 if (!cx_regulator) {
3058 dev_err(codec->dev, "%s: Regulator %s not defined\n",
3059 __func__, "cdc-vdd-cx-supply");
3060 return;
3061 }
3062
3063 ret = regulator_set_optimum_mode(cx_regulator, current_uA);
3064 if (ret < 0)
3065 dev_err(codec->dev,
3066 "%s: Failed to set vdd_cx current to %d\n",
3067 __func__, current_uA);
3068}
3069
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003070int tapan_mclk_enable(struct snd_soc_codec *codec, int mclk_enable, bool dapm)
3071{
3072 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3073
3074 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n", __func__,
3075 mclk_enable, dapm);
3076
Joonwoo Park533b3682013-06-13 11:41:21 -07003077 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003078 if (mclk_enable) {
Bhalchandra Gajare4e3dd852013-08-19 17:21:23 -07003079 tapan_set_vdd_cx_current(codec, TAPAN_VDD_CX_OPTIMAL_UA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003080 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
3081 WCD9XXX_BANDGAP_AUDIO_MODE);
3082 wcd9xxx_resmgr_get_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
3083 } else {
3084 /* Put clock and BG */
3085 wcd9xxx_resmgr_put_clk_block(&tapan->resmgr, WCD9XXX_CLK_MCLK);
3086 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
3087 WCD9XXX_BANDGAP_AUDIO_MODE);
Bhalchandra Gajare4e3dd852013-08-19 17:21:23 -07003088 /* Set the vdd cx power rail sleep mode current */
3089 tapan_set_vdd_cx_current(codec, TAPAN_VDD_CX_SLEEP_UA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003090 }
Joonwoo Park533b3682013-06-13 11:41:21 -07003091 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003092
3093 return 0;
3094}
3095
3096static int tapan_set_dai_sysclk(struct snd_soc_dai *dai,
3097 int clk_id, unsigned int freq, int dir)
3098{
3099 dev_dbg(dai->codec->dev, "%s\n", __func__);
3100 return 0;
3101}
3102
3103static int tapan_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
3104{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003105 u8 val = 0;
3106 struct snd_soc_codec *codec = dai->codec;
3107 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3108
3109 dev_dbg(codec->dev, "%s\n", __func__);
3110 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
3111 case SND_SOC_DAIFMT_CBS_CFS:
3112 /* CPU is master */
3113 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3114 if (dai->id == AIF1_CAP)
3115 snd_soc_update_bits(codec,
3116 TAPAN_A_CDC_CLK_I2S_CTL,
3117 TAPAN_I2S_MASTER_MODE_MASK, 0);
3118 else if (dai->id == AIF1_PB)
3119 snd_soc_update_bits(codec,
3120 TAPAN_A_CDC_CLK_I2S_CTL,
3121 TAPAN_I2S_MASTER_MODE_MASK, 0);
3122 }
3123 break;
3124 case SND_SOC_DAIFMT_CBM_CFM:
3125 /* CPU is slave */
3126 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3127 val = TAPAN_I2S_MASTER_MODE_MASK;
3128 if (dai->id == AIF1_CAP)
3129 snd_soc_update_bits(codec,
3130 TAPAN_A_CDC_CLK_I2S_CTL, val, val);
3131 else if (dai->id == AIF1_PB)
3132 snd_soc_update_bits(codec,
3133 TAPAN_A_CDC_CLK_I2S_CTL, val, val);
3134 }
3135 break;
3136 default:
3137 return -EINVAL;
3138 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003139 return 0;
3140}
3141
3142static int tapan_set_channel_map(struct snd_soc_dai *dai,
3143 unsigned int tx_num, unsigned int *tx_slot,
3144 unsigned int rx_num, unsigned int *rx_slot)
3145
3146{
3147 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
3148 struct wcd9xxx *core = dev_get_drvdata(dai->codec->dev->parent);
3149 if (!tx_slot && !rx_slot) {
3150 pr_err("%s: Invalid\n", __func__);
3151 return -EINVAL;
3152 }
3153 dev_dbg(dai->codec->dev, "%s(): dai_name = %s DAI-ID %x\n",
3154 __func__, dai->name, dai->id);
3155 dev_dbg(dai->codec->dev, "%s(): tx_ch %d rx_ch %d\n intf_type %d\n",
3156 __func__, tx_num, rx_num, tapan->intf_type);
3157
3158 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3159 wcd9xxx_init_slimslave(core, core->slim->laddr,
3160 tx_num, tx_slot, rx_num, rx_slot);
3161 return 0;
3162}
3163
3164static int tapan_get_channel_map(struct snd_soc_dai *dai,
3165 unsigned int *tx_num, unsigned int *tx_slot,
3166 unsigned int *rx_num, unsigned int *rx_slot)
3167
3168{
3169 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(dai->codec);
3170 u32 i = 0;
3171 struct wcd9xxx_ch *ch;
3172
3173 switch (dai->id) {
3174 case AIF1_PB:
3175 case AIF2_PB:
3176 case AIF3_PB:
3177 if (!rx_slot || !rx_num) {
3178 pr_err("%s: Invalid rx_slot %d or rx_num %d\n",
3179 __func__, (u32) rx_slot, (u32) rx_num);
3180 return -EINVAL;
3181 }
3182 list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
3183 list) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003184 dev_dbg(dai->codec->dev, "%s: rx_slot[%d] %d, ch->ch_num %d\n",
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003185 __func__, i, rx_slot[i], ch->ch_num);
3186 rx_slot[i++] = ch->ch_num;
3187 }
3188 dev_dbg(dai->codec->dev, "%s: rx_num %d\n", __func__, i);
3189 *rx_num = i;
3190 break;
3191 case AIF1_CAP:
3192 case AIF2_CAP:
3193 case AIF3_CAP:
3194 if (!tx_slot || !tx_num) {
3195 pr_err("%s: Invalid tx_slot %d or tx_num %d\n",
3196 __func__, (u32) tx_slot, (u32) tx_num);
3197 return -EINVAL;
3198 }
3199 list_for_each_entry(ch, &tapan_p->dai[dai->id].wcd9xxx_ch_list,
3200 list) {
3201 dev_dbg(dai->codec->dev, "%s: tx_slot[%d] %d, ch->ch_num %d\n",
3202 __func__, i, tx_slot[i], ch->ch_num);
3203 tx_slot[i++] = ch->ch_num;
3204 }
3205 dev_dbg(dai->codec->dev, "%s: tx_num %d\n", __func__, i);
3206 *tx_num = i;
3207 break;
3208
3209 default:
3210 pr_err("%s: Invalid DAI ID %x\n", __func__, dai->id);
3211 break;
3212 }
3213
3214 return 0;
3215}
3216
3217static int tapan_set_interpolator_rate(struct snd_soc_dai *dai,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003218 u8 rx_fs_rate_reg_val, u32 compander_fs, u32 sample_rate)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003219{
3220 u32 j;
3221 u8 rx_mix1_inp;
3222 u16 rx_mix_1_reg_1, rx_mix_1_reg_2;
3223 u16 rx_fs_reg;
3224 u8 rx_mix_1_reg_1_val, rx_mix_1_reg_2_val;
Banajit Goswamia7294452013-06-03 12:42:35 -07003225 u8 rdac5_mux;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003226 struct snd_soc_codec *codec = dai->codec;
3227 struct wcd9xxx_ch *ch;
3228 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3229
3230 list_for_each_entry(ch, &tapan->dai[dai->id].wcd9xxx_ch_list, list) {
3231 /* for RX port starting from 16 instead of 10 like tabla */
3232 rx_mix1_inp = ch->port + RX_MIX1_INP_SEL_RX1 -
3233 TAPAN_TX_PORT_NUMBER;
3234 if ((rx_mix1_inp < RX_MIX1_INP_SEL_RX1) ||
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003235 (rx_mix1_inp > RX_MIX1_INP_SEL_RX5)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003236 pr_err("%s: Invalid TAPAN_RX%u port. Dai ID is %d\n",
3237 __func__, rx_mix1_inp - 5 , dai->id);
3238 return -EINVAL;
3239 }
3240
3241 rx_mix_1_reg_1 = TAPAN_A_CDC_CONN_RX1_B1_CTL;
3242
Banajit Goswamia7294452013-06-03 12:42:35 -07003243 rdac5_mux = snd_soc_read(codec, TAPAN_A_CDC_CONN_MISC);
3244 rdac5_mux = (rdac5_mux & 0x04) >> 2;
3245
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003246 for (j = 0; j < NUM_INTERPOLATORS; j++) {
3247 rx_mix_1_reg_2 = rx_mix_1_reg_1 + 1;
3248
3249 rx_mix_1_reg_1_val = snd_soc_read(codec,
3250 rx_mix_1_reg_1);
3251 rx_mix_1_reg_2_val = snd_soc_read(codec,
3252 rx_mix_1_reg_2);
3253
3254 if (((rx_mix_1_reg_1_val & 0x0F) == rx_mix1_inp) ||
3255 (((rx_mix_1_reg_1_val >> 4) & 0x0F)
3256 == rx_mix1_inp) ||
3257 ((rx_mix_1_reg_2_val & 0x0F) == rx_mix1_inp)) {
3258
3259 rx_fs_reg = TAPAN_A_CDC_RX1_B5_CTL + 8 * j;
3260
3261 dev_dbg(codec->dev, "%s: AIF_PB DAI(%d) connected to RX%u\n",
3262 __func__, dai->id, j + 1);
3263
3264 dev_dbg(codec->dev, "%s: set RX%u sample rate to %u\n",
3265 __func__, j + 1, sample_rate);
3266
3267 snd_soc_update_bits(codec, rx_fs_reg,
3268 0xE0, rx_fs_rate_reg_val);
3269
Banajit Goswamia7294452013-06-03 12:42:35 -07003270 if (comp_rx_path[j] < COMPANDER_MAX) {
3271 if ((j == 3) && (rdac5_mux == 1))
3272 tapan->comp_fs[COMPANDER_0] =
3273 compander_fs;
3274 else
3275 tapan->comp_fs[comp_rx_path[j]]
3276 = compander_fs;
3277 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003278 }
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07003279 if (j <= 1)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003280 rx_mix_1_reg_1 += 3;
3281 else
3282 rx_mix_1_reg_1 += 2;
3283 }
3284 }
3285 return 0;
3286}
3287
3288static int tapan_set_decimator_rate(struct snd_soc_dai *dai,
3289 u8 tx_fs_rate_reg_val, u32 sample_rate)
3290{
3291 struct snd_soc_codec *codec = dai->codec;
3292 struct wcd9xxx_ch *ch;
3293 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
3294 u32 tx_port;
3295 u16 tx_port_reg, tx_fs_reg;
3296 u8 tx_port_reg_val;
3297 s8 decimator;
3298
3299 list_for_each_entry(ch, &tapan->dai[dai->id].wcd9xxx_ch_list, list) {
3300
3301 tx_port = ch->port + 1;
3302 dev_dbg(codec->dev, "%s: dai->id = %d, tx_port = %d",
3303 __func__, dai->id, tx_port);
3304
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003305 if ((tx_port < 1) || (tx_port > TAPAN_SLIM_CODEC_TX_PORTS)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003306 pr_err("%s: Invalid SLIM TX%u port. DAI ID is %d\n",
3307 __func__, tx_port, dai->id);
3308 return -EINVAL;
3309 }
3310
3311 tx_port_reg = TAPAN_A_CDC_CONN_TX_SB_B1_CTL + (tx_port - 1);
3312 tx_port_reg_val = snd_soc_read(codec, tx_port_reg);
3313
3314 decimator = 0;
3315
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003316 tx_port_reg_val = tx_port_reg_val & 0x0F;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003317
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003318 if ((tx_port_reg_val >= 0x8) &&
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003319 (tx_port_reg_val <= 0x11)) {
3320
3321 decimator = (tx_port_reg_val - 0x8) + 1;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003322 }
3323
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003324
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003325 if (decimator) { /* SLIM_TX port has a DEC as input */
3326
3327 tx_fs_reg = TAPAN_A_CDC_TX1_CLK_FS_CTL +
3328 8 * (decimator - 1);
3329
3330 dev_dbg(codec->dev, "%s: set DEC%u (-> SLIM_TX%u) rate to %u\n",
3331 __func__, decimator, tx_port, sample_rate);
3332
3333 snd_soc_update_bits(codec, tx_fs_reg, 0x07,
3334 tx_fs_rate_reg_val);
3335
3336 } else {
3337 if ((tx_port_reg_val >= 0x1) &&
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003338 (tx_port_reg_val <= 0x4)) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003339
3340 dev_dbg(codec->dev, "%s: RMIX%u going to SLIM TX%u\n",
3341 __func__, tx_port_reg_val, tx_port);
3342
3343 } else if ((tx_port_reg_val >= 0x8) &&
3344 (tx_port_reg_val <= 0x11)) {
3345
3346 pr_err("%s: ERROR: Should not be here\n",
3347 __func__);
3348 pr_err("%s: ERROR: DEC connected to SLIM TX%u\n",
3349 __func__, tx_port);
3350 return -EINVAL;
3351
3352 } else if (tx_port_reg_val == 0) {
3353 dev_dbg(codec->dev, "%s: no signal to SLIM TX%u\n",
3354 __func__, tx_port);
3355 } else {
3356 pr_err("%s: ERROR: wrong signal to SLIM TX%u\n",
3357 __func__, tx_port);
3358 pr_err("%s: ERROR: wrong signal = %u\n",
3359 __func__, tx_port_reg_val);
3360 return -EINVAL;
3361 }
3362 }
3363 }
3364 return 0;
3365}
3366
3367static int tapan_hw_params(struct snd_pcm_substream *substream,
3368 struct snd_pcm_hw_params *params,
3369 struct snd_soc_dai *dai)
3370{
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003371 struct snd_soc_codec *codec = dai->codec;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003372 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(dai->codec);
3373 u8 tx_fs_rate, rx_fs_rate;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003374 u32 compander_fs;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003375 int ret;
3376
3377 dev_dbg(dai->codec->dev, "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n",
3378 __func__, dai->name, dai->id,
3379 params_rate(params), params_channels(params));
3380
3381 switch (params_rate(params)) {
3382 case 8000:
3383 tx_fs_rate = 0x00;
3384 rx_fs_rate = 0x00;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003385 compander_fs = COMPANDER_FS_8KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003386 break;
3387 case 16000:
3388 tx_fs_rate = 0x01;
3389 rx_fs_rate = 0x20;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003390 compander_fs = COMPANDER_FS_16KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003391 break;
3392 case 32000:
3393 tx_fs_rate = 0x02;
3394 rx_fs_rate = 0x40;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003395 compander_fs = COMPANDER_FS_32KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003396 break;
3397 case 48000:
3398 tx_fs_rate = 0x03;
3399 rx_fs_rate = 0x60;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003400 compander_fs = COMPANDER_FS_48KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003401 break;
3402 case 96000:
3403 tx_fs_rate = 0x04;
3404 rx_fs_rate = 0x80;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003405 compander_fs = COMPANDER_FS_96KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003406 break;
3407 case 192000:
3408 tx_fs_rate = 0x05;
3409 rx_fs_rate = 0xA0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003410 compander_fs = COMPANDER_FS_192KHZ;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003411 break;
3412 default:
3413 pr_err("%s: Invalid sampling rate %d\n", __func__,
3414 params_rate(params));
3415 return -EINVAL;
3416 }
3417
3418 switch (substream->stream) {
3419 case SNDRV_PCM_STREAM_CAPTURE:
3420 ret = tapan_set_decimator_rate(dai, tx_fs_rate,
3421 params_rate(params));
3422 if (ret < 0) {
3423 pr_err("%s: set decimator rate failed %d\n", __func__,
3424 ret);
3425 return ret;
3426 }
3427
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003428 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3429 switch (params_format(params)) {
3430 case SNDRV_PCM_FORMAT_S16_LE:
3431 snd_soc_update_bits(codec,
3432 TAPAN_A_CDC_CLK_I2S_CTL,
3433 0x20, 0x20);
3434 break;
3435 case SNDRV_PCM_FORMAT_S32_LE:
3436 snd_soc_update_bits(codec,
3437 TAPAN_A_CDC_CLK_I2S_CTL,
3438 0x20, 0x00);
3439 break;
3440 default:
3441 pr_err("invalid format\n");
3442 break;
3443 }
3444 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
3445 0x07, tx_fs_rate);
3446 } else {
3447 tapan->dai[dai->id].rate = params_rate(params);
3448 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003449 break;
3450
3451 case SNDRV_PCM_STREAM_PLAYBACK:
3452 ret = tapan_set_interpolator_rate(dai, rx_fs_rate,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003453 compander_fs,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003454 params_rate(params));
3455 if (ret < 0) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003456 dev_err(codec->dev, "%s: set decimator rate failed %d\n",
3457 __func__, ret);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003458 return ret;
3459 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003460 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
3461 switch (params_format(params)) {
3462 case SNDRV_PCM_FORMAT_S16_LE:
3463 snd_soc_update_bits(codec,
3464 TAPAN_A_CDC_CLK_I2S_CTL,
3465 0x20, 0x20);
3466 break;
3467 case SNDRV_PCM_FORMAT_S32_LE:
3468 snd_soc_update_bits(codec,
3469 TAPAN_A_CDC_CLK_I2S_CTL,
3470 0x20, 0x00);
3471 break;
3472 default:
3473 dev_err(codec->dev, "invalid format\n");
3474 break;
3475 }
3476 snd_soc_update_bits(codec, TAPAN_A_CDC_CLK_I2S_CTL,
3477 0x03, (rx_fs_rate >> 0x05));
3478 } else {
3479 switch (params_format(params)) {
3480 case SNDRV_PCM_FORMAT_S16_LE:
3481 snd_soc_update_bits(codec,
3482 TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
3483 0xFF, 0xAA);
3484 snd_soc_update_bits(codec,
3485 TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
3486 0xFF, 0x2A);
3487 tapan->dai[dai->id].bit_width = 16;
3488 break;
3489 case SNDRV_PCM_FORMAT_S24_LE:
3490 snd_soc_update_bits(codec,
3491 TAPAN_A_CDC_CONN_RX_SB_B1_CTL,
3492 0xFF, 0x00);
3493 snd_soc_update_bits(codec,
3494 TAPAN_A_CDC_CONN_RX_SB_B2_CTL,
3495 0xFF, 0x00);
3496 tapan->dai[dai->id].bit_width = 24;
3497 break;
3498 default:
3499 dev_err(codec->dev, "Invalid format\n");
3500 break;
3501 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003502 tapan->dai[dai->id].rate = params_rate(params);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003503 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003504 break;
3505 default:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003506 dev_err(codec->dev, "%s: Invalid stream type %d\n", __func__,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003507 substream->stream);
3508 return -EINVAL;
3509 }
3510
3511 return 0;
3512}
3513
3514static struct snd_soc_dai_ops tapan_dai_ops = {
3515 .startup = tapan_startup,
3516 .shutdown = tapan_shutdown,
3517 .hw_params = tapan_hw_params,
3518 .set_sysclk = tapan_set_dai_sysclk,
3519 .set_fmt = tapan_set_dai_fmt,
3520 .set_channel_map = tapan_set_channel_map,
3521 .get_channel_map = tapan_get_channel_map,
3522};
3523
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07003524static struct snd_soc_dai_driver tapan9302_dai[] = {
3525 {
3526 .name = "tapan9302_rx1",
3527 .id = AIF1_PB,
3528 .playback = {
3529 .stream_name = "AIF1 Playback",
3530 .rates = WCD9302_RATES,
3531 .formats = TAPAN_FORMATS,
3532 .rate_max = 48000,
3533 .rate_min = 8000,
3534 .channels_min = 1,
3535 .channels_max = 2,
3536 },
3537 .ops = &tapan_dai_ops,
3538 },
3539 {
3540 .name = "tapan9302_tx1",
3541 .id = AIF1_CAP,
3542 .capture = {
3543 .stream_name = "AIF1 Capture",
3544 .rates = WCD9302_RATES,
3545 .formats = TAPAN_FORMATS,
3546 .rate_max = 48000,
3547 .rate_min = 8000,
3548 .channels_min = 1,
3549 .channels_max = 4,
3550 },
3551 .ops = &tapan_dai_ops,
3552 },
3553 {
3554 .name = "tapan9302_rx2",
3555 .id = AIF2_PB,
3556 .playback = {
3557 .stream_name = "AIF2 Playback",
3558 .rates = WCD9302_RATES,
3559 .formats = TAPAN_FORMATS,
3560 .rate_min = 8000,
3561 .rate_max = 48000,
3562 .channels_min = 1,
3563 .channels_max = 2,
3564 },
3565 .ops = &tapan_dai_ops,
3566 },
3567 {
3568 .name = "tapan9302_tx2",
3569 .id = AIF2_CAP,
3570 .capture = {
3571 .stream_name = "AIF2 Capture",
3572 .rates = WCD9302_RATES,
3573 .formats = TAPAN_FORMATS,
3574 .rate_max = 48000,
3575 .rate_min = 8000,
3576 .channels_min = 1,
3577 .channels_max = 4,
3578 },
3579 .ops = &tapan_dai_ops,
3580 },
3581 {
3582 .name = "tapan9302_tx3",
3583 .id = AIF3_CAP,
3584 .capture = {
3585 .stream_name = "AIF3 Capture",
3586 .rates = WCD9302_RATES,
3587 .formats = TAPAN_FORMATS,
3588 .rate_max = 48000,
3589 .rate_min = 8000,
3590 .channels_min = 1,
3591 .channels_max = 2,
3592 },
3593 .ops = &tapan_dai_ops,
3594 },
3595 {
3596 .name = "tapan9302_rx3",
3597 .id = AIF3_PB,
3598 .playback = {
3599 .stream_name = "AIF3 Playback",
3600 .rates = WCD9302_RATES,
3601 .formats = TAPAN_FORMATS,
3602 .rate_min = 8000,
3603 .rate_max = 48000,
3604 .channels_min = 1,
3605 .channels_max = 2,
3606 },
3607 .ops = &tapan_dai_ops,
3608 },
3609};
3610
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003611static struct snd_soc_dai_driver tapan_dai[] = {
3612 {
3613 .name = "tapan_rx1",
3614 .id = AIF1_PB,
3615 .playback = {
3616 .stream_name = "AIF1 Playback",
3617 .rates = WCD9306_RATES,
3618 .formats = TAPAN_FORMATS,
3619 .rate_max = 192000,
3620 .rate_min = 8000,
3621 .channels_min = 1,
3622 .channels_max = 2,
3623 },
3624 .ops = &tapan_dai_ops,
3625 },
3626 {
3627 .name = "tapan_tx1",
3628 .id = AIF1_CAP,
3629 .capture = {
3630 .stream_name = "AIF1 Capture",
3631 .rates = WCD9306_RATES,
3632 .formats = TAPAN_FORMATS,
3633 .rate_max = 192000,
3634 .rate_min = 8000,
3635 .channels_min = 1,
3636 .channels_max = 4,
3637 },
3638 .ops = &tapan_dai_ops,
3639 },
3640 {
3641 .name = "tapan_rx2",
3642 .id = AIF2_PB,
3643 .playback = {
3644 .stream_name = "AIF2 Playback",
3645 .rates = WCD9306_RATES,
3646 .formats = TAPAN_FORMATS,
3647 .rate_min = 8000,
3648 .rate_max = 192000,
3649 .channels_min = 1,
3650 .channels_max = 2,
3651 },
3652 .ops = &tapan_dai_ops,
3653 },
3654 {
3655 .name = "tapan_tx2",
3656 .id = AIF2_CAP,
3657 .capture = {
3658 .stream_name = "AIF2 Capture",
3659 .rates = WCD9306_RATES,
3660 .formats = TAPAN_FORMATS,
3661 .rate_max = 192000,
3662 .rate_min = 8000,
3663 .channels_min = 1,
3664 .channels_max = 4,
3665 },
3666 .ops = &tapan_dai_ops,
3667 },
3668 {
3669 .name = "tapan_tx3",
3670 .id = AIF3_CAP,
3671 .capture = {
3672 .stream_name = "AIF3 Capture",
3673 .rates = WCD9306_RATES,
3674 .formats = TAPAN_FORMATS,
3675 .rate_max = 48000,
3676 .rate_min = 8000,
3677 .channels_min = 1,
3678 .channels_max = 2,
3679 },
3680 .ops = &tapan_dai_ops,
3681 },
3682 {
3683 .name = "tapan_rx3",
3684 .id = AIF3_PB,
3685 .playback = {
3686 .stream_name = "AIF3 Playback",
3687 .rates = WCD9306_RATES,
3688 .formats = TAPAN_FORMATS,
3689 .rate_min = 8000,
3690 .rate_max = 192000,
3691 .channels_min = 1,
3692 .channels_max = 2,
3693 },
3694 .ops = &tapan_dai_ops,
3695 },
3696};
3697
3698static struct snd_soc_dai_driver tapan_i2s_dai[] = {
3699 {
3700 .name = "tapan_i2s_rx1",
3701 .id = AIF1_PB,
3702 .playback = {
3703 .stream_name = "AIF1 Playback",
3704 .rates = WCD9306_RATES,
3705 .formats = TAPAN_FORMATS,
3706 .rate_max = 192000,
3707 .rate_min = 8000,
3708 .channels_min = 1,
3709 .channels_max = 4,
3710 },
3711 .ops = &tapan_dai_ops,
3712 },
3713 {
3714 .name = "tapan_i2s_tx1",
3715 .id = AIF1_CAP,
3716 .capture = {
3717 .stream_name = "AIF1 Capture",
3718 .rates = WCD9306_RATES,
3719 .formats = TAPAN_FORMATS,
3720 .rate_max = 192000,
3721 .rate_min = 8000,
3722 .channels_min = 1,
3723 .channels_max = 4,
3724 },
3725 .ops = &tapan_dai_ops,
3726 },
3727};
3728
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003729static int tapan_codec_enable_slim_chmask(struct wcd9xxx_codec_dai_data *dai,
3730 bool up)
3731{
3732 int ret = 0;
3733 struct wcd9xxx_ch *ch;
3734
3735 if (up) {
3736 list_for_each_entry(ch, &dai->wcd9xxx_ch_list, list) {
3737 ret = wcd9xxx_get_slave_port(ch->ch_num);
3738 if (ret < 0) {
3739 pr_debug("%s: Invalid slave port ID: %d\n",
3740 __func__, ret);
3741 ret = -EINVAL;
3742 } else {
3743 set_bit(ret, &dai->ch_mask);
3744 }
3745 }
3746 } else {
3747 ret = wait_event_timeout(dai->dai_wait, (dai->ch_mask == 0),
3748 msecs_to_jiffies(
3749 TAPAN_SLIM_CLOSE_TIMEOUT));
3750 if (!ret) {
3751 pr_debug("%s: Slim close tx/rx wait timeout\n",
3752 __func__);
3753 ret = -ETIMEDOUT;
3754 } else {
3755 ret = 0;
3756 }
3757 }
3758 return ret;
3759}
3760
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003761static int tapan_codec_enable_slimrx(struct snd_soc_dapm_widget *w,
3762 struct snd_kcontrol *kcontrol,
3763 int event)
3764{
3765 struct wcd9xxx *core;
3766 struct snd_soc_codec *codec = w->codec;
3767 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003768 int ret = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003769 struct wcd9xxx_codec_dai_data *dai;
3770
3771 core = dev_get_drvdata(codec->dev->parent);
3772
3773 dev_dbg(codec->dev, "%s: event called! codec name %s\n",
3774 __func__, w->codec->name);
3775 dev_dbg(codec->dev, "%s: num_dai %d stream name %s event %d\n",
3776 __func__, w->codec->num_dai, w->sname, event);
3777
3778 /* Execute the callback only if interface type is slimbus */
3779 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3780 return 0;
3781
3782 dai = &tapan_p->dai[w->shift];
3783 dev_dbg(codec->dev, "%s: w->name %s w->shift %d event %d\n",
3784 __func__, w->name, w->shift, event);
3785
3786 switch (event) {
3787 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003788 (void) tapan_codec_enable_slim_chmask(dai, true);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003789 ret = wcd9xxx_cfg_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3790 dai->rate, dai->bit_width,
3791 &dai->grph);
3792 break;
3793 case SND_SOC_DAPM_POST_PMD:
3794 ret = wcd9xxx_close_slim_sch_rx(core, &dai->wcd9xxx_ch_list,
3795 dai->grph);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003796 ret = tapan_codec_enable_slim_chmask(dai, false);
3797 if (ret < 0) {
3798 ret = wcd9xxx_disconnect_port(core,
3799 &dai->wcd9xxx_ch_list,
3800 dai->grph);
3801 dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
3802 __func__, ret);
3803 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003804 break;
3805 }
3806 return ret;
3807}
3808
3809static int tapan_codec_enable_slimtx(struct snd_soc_dapm_widget *w,
3810 struct snd_kcontrol *kcontrol,
3811 int event)
3812{
3813 struct wcd9xxx *core;
3814 struct snd_soc_codec *codec = w->codec;
3815 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
3816 u32 ret = 0;
3817 struct wcd9xxx_codec_dai_data *dai;
3818
3819 core = dev_get_drvdata(codec->dev->parent);
3820
3821 dev_dbg(codec->dev, "%s: event called! codec name %s\n",
3822 __func__, w->codec->name);
3823 dev_dbg(codec->dev, "%s: num_dai %d stream name %s\n",
3824 __func__, w->codec->num_dai, w->sname);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003825 /* Execute the callback only if interface type is slimbus */
3826 if (tapan_p->intf_type != WCD9XXX_INTERFACE_TYPE_SLIMBUS)
3827 return 0;
3828
3829 dev_dbg(codec->dev, "%s(): w->name %s event %d w->shift %d\n",
3830 __func__, w->name, event, w->shift);
3831
3832 dai = &tapan_p->dai[w->shift];
3833 switch (event) {
3834 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003835 (void) tapan_codec_enable_slim_chmask(dai, true);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003836 ret = wcd9xxx_cfg_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3837 dai->rate, dai->bit_width,
3838 &dai->grph);
3839 break;
3840 case SND_SOC_DAPM_POST_PMD:
3841 ret = wcd9xxx_close_slim_sch_tx(core, &dai->wcd9xxx_ch_list,
3842 dai->grph);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003843 ret = tapan_codec_enable_slim_chmask(dai, false);
3844 if (ret < 0) {
3845 ret = wcd9xxx_disconnect_port(core,
3846 &dai->wcd9xxx_ch_list,
3847 dai->grph);
3848 dev_dbg(codec->dev, "%s: Disconnect RX port, ret = %d\n",
3849 __func__, ret);
3850 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003851 break;
3852 }
3853 return ret;
3854}
3855
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003856
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003857static int tapan_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
3858 struct snd_kcontrol *kcontrol, int event)
3859{
3860 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003861 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003862
3863 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
3864
3865 switch (event) {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003866 case SND_SOC_DAPM_POST_PMU:
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003867 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3868 WCD9XXX_CLSH_STATE_EAR,
3869 WCD9XXX_CLSH_REQ_ENABLE,
3870 WCD9XXX_CLSH_EVENT_POST_PA);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003871
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003872 usleep_range(5000, 5010);
3873 break;
3874 case SND_SOC_DAPM_POST_PMD:
3875 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3876 WCD9XXX_CLSH_STATE_EAR,
3877 WCD9XXX_CLSH_REQ_DISABLE,
3878 WCD9XXX_CLSH_EVENT_POST_PA);
3879 usleep_range(5000, 5010);
3880 }
3881 return 0;
3882}
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003883
Bhalchandra Gajareea898742013-03-05 18:15:53 -08003884static int tapan_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
3885 struct snd_kcontrol *kcontrol, int event)
3886{
3887 struct snd_soc_codec *codec = w->codec;
3888 struct tapan_priv *tapan_p = snd_soc_codec_get_drvdata(codec);
3889
3890 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
3891
3892 switch (event) {
3893 case SND_SOC_DAPM_PRE_PMU:
3894 wcd9xxx_clsh_fsm(codec, &tapan_p->clsh_d,
3895 WCD9XXX_CLSH_STATE_EAR,
3896 WCD9XXX_CLSH_REQ_ENABLE,
3897 WCD9XXX_CLSH_EVENT_PRE_DAC);
3898 break;
3899 }
3900
3901 return 0;
3902}
3903
3904static int tapan_codec_dsm_mux_event(struct snd_soc_dapm_widget *w,
3905 struct snd_kcontrol *kcontrol, int event)
3906{
3907 struct snd_soc_codec *codec = w->codec;
3908 u8 reg_val, zoh_mux_val = 0x00;
3909
3910 dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
3911
3912 switch (event) {
3913 case SND_SOC_DAPM_POST_PMU:
3914 reg_val = snd_soc_read(codec, TAPAN_A_CDC_CONN_CLSH_CTL);
3915
3916 if ((reg_val & 0x30) == 0x10)
3917 zoh_mux_val = 0x04;
3918 else if ((reg_val & 0x30) == 0x20)
3919 zoh_mux_val = 0x08;
3920
3921 if (zoh_mux_val != 0x00)
3922 snd_soc_update_bits(codec,
3923 TAPAN_A_CDC_CONN_CLSH_CTL,
3924 0x0C, zoh_mux_val);
3925 break;
3926
3927 case SND_SOC_DAPM_POST_PMD:
3928 snd_soc_update_bits(codec, TAPAN_A_CDC_CONN_CLSH_CTL,
3929 0x0C, 0x00);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08003930 break;
3931 }
3932 return 0;
3933}
3934
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07003935static int tapan_codec_enable_anc_ear(struct snd_soc_dapm_widget *w,
3936 struct snd_kcontrol *kcontrol, int event)
3937{
3938 struct snd_soc_codec *codec = w->codec;
3939 int ret = 0;
3940
3941 switch (event) {
3942 case SND_SOC_DAPM_PRE_PMU:
3943 ret = tapan_codec_enable_anc(w, kcontrol, event);
3944 msleep(50);
3945 snd_soc_update_bits(codec, TAPAN_A_RX_EAR_EN, 0x10, 0x10);
3946 break;
3947 case SND_SOC_DAPM_POST_PMU:
3948 ret = tapan_codec_enable_ear_pa(w, kcontrol, event);
3949 break;
3950 case SND_SOC_DAPM_PRE_PMD:
3951 snd_soc_update_bits(codec, TAPAN_A_RX_EAR_EN, 0x10, 0x00);
3952 msleep(40);
3953 ret |= tapan_codec_enable_anc(w, kcontrol, event);
3954 break;
3955 case SND_SOC_DAPM_POST_PMD:
3956 ret = tapan_codec_enable_ear_pa(w, kcontrol, event);
3957 break;
3958 }
3959 return ret;
3960}
3961
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07003962static int tapan_codec_chargepump_vdd_event(struct snd_soc_dapm_widget *w,
3963 struct snd_kcontrol *kcontrol, int event)
3964{
3965 struct snd_soc_codec *codec = w->codec;
3966 struct tapan_priv *priv = snd_soc_codec_get_drvdata(codec);
3967 int ret = 0, i;
3968
3969 pr_info("%s: event = %d\n", __func__, event);
3970
3971
3972 if (!priv->cp_regulators[CP_REG_BUCK]
3973 && !priv->cp_regulators[CP_REG_BHELPER]) {
3974 pr_err("%s: No power supply defined for ChargePump\n",
3975 __func__);
3976 return -EINVAL;
3977 }
3978
3979 switch (event) {
3980 case SND_SOC_DAPM_PRE_PMU:
3981 for (i = 0; i < CP_REG_MAX ; i++) {
3982 if (!priv->cp_regulators[i])
3983 continue;
3984
3985 ret = regulator_enable(priv->cp_regulators[i]);
3986 if (ret) {
3987 pr_err("%s: CP Regulator enable failed, index = %d\n",
3988 __func__, i);
3989 continue;
3990 } else {
3991 pr_debug("%s: Enabled CP regulator, index %d\n",
3992 __func__, i);
3993 }
3994 }
3995 break;
3996 case SND_SOC_DAPM_POST_PMD:
3997 for (i = 0; i < CP_REG_MAX; i++) {
3998 if (!priv->cp_regulators[i])
3999 continue;
4000
4001 ret = regulator_disable(priv->cp_regulators[i]);
4002 if (ret) {
4003 pr_err("%s: CP Regulator disable failed, index = %d\n",
4004 __func__, i);
4005 return ret;
4006 } else {
4007 pr_debug("%s: Disabled CP regulator %d\n",
4008 __func__, i);
4009 }
4010 }
4011 break;
4012 }
4013 return 0;
4014}
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004015
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07004016static const struct snd_soc_dapm_widget tapan_9306_dapm_widgets[] = {
4017 /* RX4 MIX1 mux inputs */
4018 SND_SOC_DAPM_MUX("RX4 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4019 &rx4_mix1_inp1_mux),
4020 SND_SOC_DAPM_MUX("RX4 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4021 &rx4_mix1_inp2_mux),
4022 SND_SOC_DAPM_MUX("RX4 MIX1 INP3", SND_SOC_NOPM, 0, 0,
4023 &rx4_mix1_inp2_mux),
4024
4025 /* RX4 MIX2 mux inputs */
4026 SND_SOC_DAPM_MUX("RX4 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4027 &rx4_mix2_inp1_mux),
4028 SND_SOC_DAPM_MUX("RX4 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4029 &rx4_mix2_inp2_mux),
4030
4031 SND_SOC_DAPM_MIXER("RX4 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4032
4033 SND_SOC_DAPM_MIXER_E("RX4 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 3, 0, NULL,
4034 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
4035 SND_SOC_DAPM_POST_PMU),
4036
4037 SND_SOC_DAPM_MUX_E("DEC3 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 2, 0,
4038 &dec3_mux, tapan_codec_enable_dec,
4039 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4040 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
4041
4042 SND_SOC_DAPM_MUX_E("DEC4 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 3, 0,
4043 &dec4_mux, tapan_codec_enable_dec,
4044 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4045 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
4046
4047 SND_SOC_DAPM_SUPPLY("COMP0_CLK", SND_SOC_NOPM, 0, 0,
4048 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
4049 SND_SOC_DAPM_PRE_PMD),
4050 SND_SOC_DAPM_SUPPLY("COMP1_CLK", SND_SOC_NOPM, 1, 0,
4051 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
4052 SND_SOC_DAPM_PRE_PMD),
4053 SND_SOC_DAPM_SUPPLY("COMP2_CLK", SND_SOC_NOPM, 2, 0,
4054 tapan_config_compander, SND_SOC_DAPM_PRE_PMU |
4055 SND_SOC_DAPM_PRE_PMD),
4056
4057 SND_SOC_DAPM_INPUT("AMIC5"),
4058 SND_SOC_DAPM_ADC_E("ADC5", NULL, TAPAN_A_TX_5_EN, 7, 0,
4059 tapan_codec_enable_adc, SND_SOC_DAPM_POST_PMU),
4060
4061 SND_SOC_DAPM_MUX("ANC1 MUX", SND_SOC_NOPM, 0, 0, &anc1_mux),
4062 SND_SOC_DAPM_MUX("ANC2 MUX", SND_SOC_NOPM, 0, 0, &anc2_mux),
4063
4064 SND_SOC_DAPM_OUTPUT("ANC HEADPHONE"),
4065 SND_SOC_DAPM_PGA_E("ANC HPHL", SND_SOC_NOPM, 5, 0, NULL, 0,
4066 tapan_codec_enable_anc_hph,
4067 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
4068 SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU),
4069 SND_SOC_DAPM_PGA_E("ANC HPHR", SND_SOC_NOPM, 4, 0, NULL, 0,
4070 tapan_codec_enable_anc_hph, SND_SOC_DAPM_PRE_PMU |
4071 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD |
4072 SND_SOC_DAPM_POST_PMU),
4073 SND_SOC_DAPM_OUTPUT("ANC EAR"),
4074 SND_SOC_DAPM_PGA_E("ANC EAR PA", SND_SOC_NOPM, 0, 0, NULL, 0,
4075 tapan_codec_enable_anc_ear,
4076 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD |
4077 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4078 SND_SOC_DAPM_MUX("ANC1 FB MUX", SND_SOC_NOPM, 0, 0, &anc1_fb_mux),
4079
4080 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 External", TAPAN_A_MICB_3_CTL, 7, 0,
4081 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4082 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4083 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal1", TAPAN_A_MICB_3_CTL, 7, 0,
4084 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4085 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4086 SND_SOC_DAPM_MICBIAS_E("MIC BIAS3 Internal2", TAPAN_A_MICB_3_CTL, 7, 0,
4087 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4088 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4089
4090 SND_SOC_DAPM_ADC_E("DMIC3", NULL, SND_SOC_NOPM, 0, 0,
4091 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4092 SND_SOC_DAPM_POST_PMD),
4093
4094 SND_SOC_DAPM_ADC_E("DMIC4", NULL, SND_SOC_NOPM, 0, 0,
4095 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4096 SND_SOC_DAPM_POST_PMD),
4097};
4098
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004099/* Todo: Have seperate dapm widgets for I2S and Slimbus.
4100 * Might Need to have callbacks registered only for slimbus
4101 */
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07004102static const struct snd_soc_dapm_widget tapan_common_dapm_widgets[] = {
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004103
4104 SND_SOC_DAPM_AIF_IN_E("AIF1 PB", "AIF1 Playback", 0, SND_SOC_NOPM,
4105 AIF1_PB, 0, tapan_codec_enable_slimrx,
4106 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4107 SND_SOC_DAPM_AIF_IN_E("AIF2 PB", "AIF2 Playback", 0, SND_SOC_NOPM,
4108 AIF2_PB, 0, tapan_codec_enable_slimrx,
4109 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4110 SND_SOC_DAPM_AIF_IN_E("AIF3 PB", "AIF3 Playback", 0, SND_SOC_NOPM,
4111 AIF3_PB, 0, tapan_codec_enable_slimrx,
4112 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4113
4114 SND_SOC_DAPM_MUX("SLIM RX1 MUX", SND_SOC_NOPM, TAPAN_RX1, 0,
4115 &slim_rx_mux[TAPAN_RX1]),
4116 SND_SOC_DAPM_MUX("SLIM RX2 MUX", SND_SOC_NOPM, TAPAN_RX2, 0,
4117 &slim_rx_mux[TAPAN_RX2]),
4118 SND_SOC_DAPM_MUX("SLIM RX3 MUX", SND_SOC_NOPM, TAPAN_RX3, 0,
4119 &slim_rx_mux[TAPAN_RX3]),
4120 SND_SOC_DAPM_MUX("SLIM RX4 MUX", SND_SOC_NOPM, TAPAN_RX4, 0,
4121 &slim_rx_mux[TAPAN_RX4]),
4122 SND_SOC_DAPM_MUX("SLIM RX5 MUX", SND_SOC_NOPM, TAPAN_RX5, 0,
4123 &slim_rx_mux[TAPAN_RX5]),
4124
4125 SND_SOC_DAPM_MIXER("SLIM RX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4126 SND_SOC_DAPM_MIXER("SLIM RX2", SND_SOC_NOPM, 0, 0, NULL, 0),
4127 SND_SOC_DAPM_MIXER("SLIM RX3", SND_SOC_NOPM, 0, 0, NULL, 0),
4128 SND_SOC_DAPM_MIXER("SLIM RX4", SND_SOC_NOPM, 0, 0, NULL, 0),
4129 SND_SOC_DAPM_MIXER("SLIM RX5", SND_SOC_NOPM, 0, 0, NULL, 0),
4130
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004131
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004132 /* RX1 MIX1 mux inputs */
4133 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4134 &rx_mix1_inp1_mux),
4135 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4136 &rx_mix1_inp2_mux),
4137 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
4138 &rx_mix1_inp3_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004139
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004140 /* RX2 MIX1 mux inputs */
4141 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4142 &rx2_mix1_inp1_mux),
4143 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4144 &rx2_mix1_inp2_mux),
4145 SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0,
4146 &rx2_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004147
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004148 /* RX3 MIX1 mux inputs */
4149 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
4150 &rx3_mix1_inp1_mux),
4151 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
4152 &rx3_mix1_inp2_mux),
4153 SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0,
4154 &rx3_mix1_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004155
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004156 /* RX1 MIX2 mux inputs */
4157 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4158 &rx1_mix2_inp1_mux),
4159 SND_SOC_DAPM_MUX("RX1 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4160 &rx1_mix2_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004161
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004162 /* RX2 MIX2 mux inputs */
4163 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
4164 &rx2_mix2_inp1_mux),
4165 SND_SOC_DAPM_MUX("RX2 MIX2 INP2", SND_SOC_NOPM, 0, 0,
4166 &rx2_mix2_inp2_mux),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004167
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004168 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4169 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
4170
4171 SND_SOC_DAPM_MIXER_E("RX1 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
4172 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
4173 SND_SOC_DAPM_POST_PMU),
4174 SND_SOC_DAPM_MIXER_E("RX2 MIX2", TAPAN_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
4175 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
4176 SND_SOC_DAPM_POST_PMU),
4177 SND_SOC_DAPM_MIXER_E("RX3 MIX1", TAPAN_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
4178 0, tapan_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
4179 SND_SOC_DAPM_POST_PMU),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004180
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004181 SND_SOC_DAPM_MIXER("RX1 CHAIN", TAPAN_A_CDC_RX1_B6_CTL, 5, 0,
4182 NULL, 0),
4183 SND_SOC_DAPM_MIXER("RX2 CHAIN", TAPAN_A_CDC_RX2_B6_CTL, 5, 0,
4184 NULL, 0),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004185
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004186 SND_SOC_DAPM_MUX_E("CLASS_H_DSM MUX", SND_SOC_NOPM, 0, 0,
4187 &class_h_dsm_mux, tapan_codec_dsm_mux_event,
4188 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004189
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004190 /* RX Bias */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004191 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
4192 tapan_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
4193 SND_SOC_DAPM_POST_PMD),
4194
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07004195 /* CDC_CP_VDD */
4196 SND_SOC_DAPM_SUPPLY("CDC_CP_VDD", SND_SOC_NOPM, 0, 0,
4197 tapan_codec_chargepump_vdd_event, SND_SOC_DAPM_PRE_PMU |
4198 SND_SOC_DAPM_POST_PMD),
4199
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004200 /*EAR */
4201 SND_SOC_DAPM_PGA_E("EAR PA", TAPAN_A_RX_EAR_EN, 4, 0, NULL, 0,
4202 tapan_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU |
4203 SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004204
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004205 SND_SOC_DAPM_MIXER_E("DAC1", TAPAN_A_RX_EAR_EN, 6, 0, dac1_switch,
4206 ARRAY_SIZE(dac1_switch), tapan_codec_ear_dac_event,
4207 SND_SOC_DAPM_PRE_PMU),
4208
4209 /* Headphone Left */
4210 SND_SOC_DAPM_PGA_E("HPHL", TAPAN_A_RX_HPH_CNP_EN, 5, 0, NULL, 0,
4211 tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4212 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4213
4214 SND_SOC_DAPM_MIXER_E("HPHL DAC", TAPAN_A_RX_HPH_L_DAC_CTL, 7, 0,
4215 hphl_switch, ARRAY_SIZE(hphl_switch), tapan_hphl_dac_event,
4216 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4217
4218 /* Headphone Right */
4219 SND_SOC_DAPM_PGA_E("HPHR", TAPAN_A_RX_HPH_CNP_EN, 4, 0, NULL, 0,
4220 tapan_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
4221 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4222
4223 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, TAPAN_A_RX_HPH_R_DAC_CTL, 7, 0,
4224 tapan_hphr_dac_event,
4225 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4226
4227 /* LINEOUT1*/
4228 SND_SOC_DAPM_DAC_E("LINEOUT1 DAC", NULL, TAPAN_A_RX_LINE_1_DAC_CTL, 7, 0
4229 , tapan_lineout_dac_event,
4230 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4231
4232 SND_SOC_DAPM_PGA_E("LINEOUT1 PA", TAPAN_A_RX_LINE_CNP_EN, 0, 0, NULL,
4233 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4234 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4235
4236 /* LINEOUT2*/
4237 SND_SOC_DAPM_MUX("RDAC5 MUX", SND_SOC_NOPM, 0, 0,
4238 &rx_dac5_mux),
4239
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07004240 /* LINEOUT1*/
4241 SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
4242 &rx_dac4_mux),
4243
4244 SND_SOC_DAPM_MUX("RDAC3 MUX", SND_SOC_NOPM, 0, 0,
4245 &rx_dac3_mux),
4246
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004247 SND_SOC_DAPM_DAC_E("LINEOUT2 DAC", NULL, TAPAN_A_RX_LINE_2_DAC_CTL, 7, 0
4248 , tapan_lineout_dac_event,
4249 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4250
4251 SND_SOC_DAPM_PGA_E("LINEOUT2 PA", TAPAN_A_RX_LINE_CNP_EN, 1, 0, NULL,
4252 0, tapan_codec_enable_lineout, SND_SOC_DAPM_PRE_PMU |
4253 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4254
4255 /* CLASS-D SPK */
4256 SND_SOC_DAPM_MIXER_E("SPK DAC", SND_SOC_NOPM, 0, 0,
4257 spk_dac_switch, ARRAY_SIZE(spk_dac_switch), tapan_spk_dac_event,
4258 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4259
4260 SND_SOC_DAPM_PGA_E("SPK PA", SND_SOC_NOPM, 0, 0 , NULL,
4261 0, tapan_codec_enable_spk_pa,
4262 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4263
4264 SND_SOC_DAPM_SUPPLY("VDD_SPKDRV", SND_SOC_NOPM, 0, 0,
4265 tapan_codec_enable_vdd_spkr,
4266 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
4267
4268 SND_SOC_DAPM_OUTPUT("EAR"),
4269 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
4270 SND_SOC_DAPM_OUTPUT("LINEOUT1"),
4271 SND_SOC_DAPM_OUTPUT("LINEOUT2"),
4272 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
4273
4274 /* TX Path*/
4275 SND_SOC_DAPM_MIXER("AIF1_CAP Mixer", SND_SOC_NOPM, AIF1_CAP, 0,
4276 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
4277
4278 SND_SOC_DAPM_MIXER("AIF2_CAP Mixer", SND_SOC_NOPM, AIF2_CAP, 0,
4279 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
4280
4281 SND_SOC_DAPM_MIXER("AIF3_CAP Mixer", SND_SOC_NOPM, AIF3_CAP, 0,
4282 aif_cap_mixer, ARRAY_SIZE(aif_cap_mixer)),
4283
4284 SND_SOC_DAPM_MUX("SLIM TX1 MUX", SND_SOC_NOPM, TAPAN_TX1, 0,
4285 &sb_tx1_mux),
4286 SND_SOC_DAPM_MUX("SLIM TX2 MUX", SND_SOC_NOPM, TAPAN_TX2, 0,
4287 &sb_tx2_mux),
4288 SND_SOC_DAPM_MUX("SLIM TX3 MUX", SND_SOC_NOPM, TAPAN_TX3, 0,
4289 &sb_tx3_mux),
4290 SND_SOC_DAPM_MUX("SLIM TX4 MUX", SND_SOC_NOPM, TAPAN_TX4, 0,
4291 &sb_tx4_mux),
4292 SND_SOC_DAPM_MUX("SLIM TX5 MUX", SND_SOC_NOPM, TAPAN_TX5, 0,
4293 &sb_tx5_mux),
4294
4295 SND_SOC_DAPM_SUPPLY("CDC_CONN", WCD9XXX_A_CDC_CLK_OTHR_CTL, 2, 0, NULL,
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004296 0),
4297
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004298 /* Decimator MUX */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004299 SND_SOC_DAPM_MUX_E("DEC1 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
4300 &dec1_mux, tapan_codec_enable_dec,
4301 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4302 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
4303
4304 SND_SOC_DAPM_MUX_E("DEC2 MUX", TAPAN_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
4305 &dec2_mux, tapan_codec_enable_dec,
4306 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
4307 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
4308
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004309 SND_SOC_DAPM_SUPPLY("LDO_H", TAPAN_A_LDO_H_MODE_1, 7, 0,
4310 tapan_codec_enable_ldo_h, SND_SOC_DAPM_POST_PMU),
4311
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004312 SND_SOC_DAPM_INPUT("AMIC1"),
4313 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 External", TAPAN_A_MICB_1_CTL, 7, 0,
4314 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4315 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4316 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal1", TAPAN_A_MICB_1_CTL, 7, 0,
4317 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4318 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4319 SND_SOC_DAPM_MICBIAS_E("MIC BIAS1 Internal2", TAPAN_A_MICB_1_CTL, 7, 0,
4320 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4321 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4322
4323 SND_SOC_DAPM_ADC_E("ADC1", NULL, TAPAN_A_TX_1_EN, 7, 0,
4324 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4325 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4326 SND_SOC_DAPM_ADC_E("ADC2", NULL, TAPAN_A_TX_2_EN, 7, 0,
4327 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4328 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4329
4330 SND_SOC_DAPM_INPUT("AMIC3"),
4331 SND_SOC_DAPM_ADC_E("ADC3", NULL, TAPAN_A_TX_3_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
4335 SND_SOC_DAPM_INPUT("AMIC4"),
4336 SND_SOC_DAPM_ADC_E("ADC4", NULL, TAPAN_A_TX_4_EN, 7, 0,
4337 tapan_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
4338 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4339
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004340 SND_SOC_DAPM_INPUT("AMIC2"),
4341 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 External", TAPAN_A_MICB_2_CTL, 7, 0,
4342 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4343 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4344 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal1", TAPAN_A_MICB_2_CTL, 7, 0,
4345 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4346 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4347 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal2", TAPAN_A_MICB_2_CTL, 7, 0,
4348 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4349 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4350 SND_SOC_DAPM_MICBIAS_E("MIC BIAS2 Internal3", TAPAN_A_MICB_2_CTL, 7, 0,
4351 tapan_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
4352 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004353
4354 SND_SOC_DAPM_AIF_OUT_E("AIF1 CAP", "AIF1 Capture", 0, SND_SOC_NOPM,
4355 AIF1_CAP, 0, tapan_codec_enable_slimtx,
4356 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4357
4358 SND_SOC_DAPM_AIF_OUT_E("AIF2 CAP", "AIF2 Capture", 0, SND_SOC_NOPM,
4359 AIF2_CAP, 0, tapan_codec_enable_slimtx,
4360 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4361
4362 SND_SOC_DAPM_AIF_OUT_E("AIF3 CAP", "AIF3 Capture", 0, SND_SOC_NOPM,
4363 AIF3_CAP, 0, tapan_codec_enable_slimtx,
4364 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
4365
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004366 /* Digital Mic Inputs */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004367 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
4368 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4369 SND_SOC_DAPM_POST_PMD),
4370
4371 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
4372 tapan_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
4373 SND_SOC_DAPM_POST_PMD),
4374
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004375 /* Sidetone */
4376 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
4377 SND_SOC_DAPM_PGA("IIR1", TAPAN_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
4378
4379 /* AUX PGA */
4380 SND_SOC_DAPM_ADC_E("AUX_PGA_Left", NULL, TAPAN_A_RX_AUX_SW_CTL, 7, 0,
4381 tapan_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4382 SND_SOC_DAPM_POST_PMD),
4383
4384 SND_SOC_DAPM_ADC_E("AUX_PGA_Right", NULL, TAPAN_A_RX_AUX_SW_CTL, 6, 0,
4385 tapan_codec_enable_aux_pga, SND_SOC_DAPM_PRE_PMU |
4386 SND_SOC_DAPM_POST_PMD),
4387
4388 /* Lineout, ear and HPH PA Mixers */
4389
4390 SND_SOC_DAPM_MIXER("EAR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4391 ear_pa_mix, ARRAY_SIZE(ear_pa_mix)),
4392
4393 SND_SOC_DAPM_MIXER("HPHL_PA_MIXER", SND_SOC_NOPM, 0, 0,
4394 hphl_pa_mix, ARRAY_SIZE(hphl_pa_mix)),
4395
4396 SND_SOC_DAPM_MIXER("HPHR_PA_MIXER", SND_SOC_NOPM, 0, 0,
4397 hphr_pa_mix, ARRAY_SIZE(hphr_pa_mix)),
4398
4399 SND_SOC_DAPM_MIXER("LINEOUT1_PA_MIXER", SND_SOC_NOPM, 0, 0,
4400 lineout1_pa_mix, ARRAY_SIZE(lineout1_pa_mix)),
4401
4402 SND_SOC_DAPM_MIXER("LINEOUT2_PA_MIXER", SND_SOC_NOPM, 0, 0,
4403 lineout2_pa_mix, ARRAY_SIZE(lineout2_pa_mix)),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004404};
4405
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004406static irqreturn_t tapan_slimbus_irq(int irq, void *data)
4407{
4408 struct tapan_priv *priv = data;
4409 struct snd_soc_codec *codec = priv->codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004410 unsigned long status = 0;
4411 int i, j, port_id, k;
4412 u32 bit;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004413 u8 val;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004414 bool tx, cleared;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004415
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004416 for (i = TAPAN_SLIM_PGD_PORT_INT_STATUS_RX_0, j = 0;
4417 i <= TAPAN_SLIM_PGD_PORT_INT_STATUS_TX_1; i++, j++) {
4418 val = wcd9xxx_interface_reg_read(codec->control_data, i);
4419 status |= ((u32)val << (8 * j));
4420 }
4421
4422 for_each_set_bit(j, &status, 32) {
4423 tx = (j >= 16 ? true : false);
4424 port_id = (tx ? j - 16 : j);
4425 val = wcd9xxx_interface_reg_read(codec->control_data,
4426 TAPAN_SLIM_PGD_PORT_INT_RX_SOURCE0 + j);
4427 if (val & TAPAN_SLIM_IRQ_OVERFLOW)
4428 pr_err_ratelimited(
4429 "%s: overflow error on %s port %d, value %x\n",
4430 __func__, (tx ? "TX" : "RX"), port_id, val);
4431 if (val & TAPAN_SLIM_IRQ_UNDERFLOW)
4432 pr_err_ratelimited(
4433 "%s: underflow error on %s port %d, value %x\n",
4434 __func__, (tx ? "TX" : "RX"), port_id, val);
4435 if (val & TAPAN_SLIM_IRQ_PORT_CLOSED) {
4436 /*
4437 * INT SOURCE register starts from RX to TX
4438 * but port number in the ch_mask is in opposite way
4439 */
4440 bit = (tx ? j - 16 : j + 16);
4441 dev_dbg(codec->dev, "%s: %s port %d closed value %x, bit %u\n",
4442 __func__, (tx ? "TX" : "RX"), port_id, val,
4443 bit);
4444 for (k = 0, cleared = false; k < NUM_CODEC_DAIS; k++) {
4445 dev_dbg(codec->dev, "%s: priv->dai[%d].ch_mask = 0x%lx\n",
4446 __func__, k, priv->dai[k].ch_mask);
4447 if (test_and_clear_bit(bit,
4448 &priv->dai[k].ch_mask)) {
4449 cleared = true;
4450 if (!priv->dai[k].ch_mask)
4451 wake_up(&priv->dai[k].dai_wait);
4452 /*
4453 * There are cases when multiple DAIs
4454 * might be using the same slimbus
4455 * channel. Hence don't break here.
4456 */
4457 }
4458 }
4459 WARN(!cleared,
4460 "Couldn't find slimbus %s port %d for closing\n",
4461 (tx ? "TX" : "RX"), port_id);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004462 }
4463 wcd9xxx_interface_reg_write(codec->control_data,
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004464 TAPAN_SLIM_PGD_PORT_INT_CLR_RX_0 +
4465 (j / 8),
4466 1 << (j % 8));
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004467 }
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004468
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004469 return IRQ_HANDLED;
4470}
4471
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004472static int tapan_handle_pdata(struct tapan_priv *tapan)
4473{
4474 struct snd_soc_codec *codec = tapan->codec;
4475 struct wcd9xxx_pdata *pdata = tapan->resmgr.pdata;
4476 int k1, k2, k3, rc = 0;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004477 u8 txfe_bypass = pdata->amic_settings.txfe_enable;
4478 u8 txfe_buff = pdata->amic_settings.txfe_buff;
4479 u8 flag = pdata->amic_settings.use_pdata;
4480 u8 i = 0, j = 0;
4481 u8 val_txfe = 0, value = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004482
4483 if (!pdata) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004484 dev_err(codec->dev, "%s: NULL pdata\n", __func__);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004485 rc = -ENODEV;
4486 goto done;
4487 }
4488
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004489 /* Make sure settings are correct */
4490 if ((pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V) ||
4491 (pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
4492 (pdata->micbias.bias2_cfilt_sel > WCD9XXX_CFILT3_SEL) ||
4493 (pdata->micbias.bias3_cfilt_sel > WCD9XXX_CFILT3_SEL)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004494 dev_err(codec->dev, "%s: Invalid ldoh voltage or bias cfilt\n",
4495 __func__);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004496 rc = -EINVAL;
4497 goto done;
4498 }
4499 /* figure out k value */
4500 k1 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt1_mv);
4501 k2 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt2_mv);
4502 k3 = wcd9xxx_resmgr_get_k_val(&tapan->resmgr, pdata->micbias.cfilt3_mv);
4503
4504 if (IS_ERR_VALUE(k1) || IS_ERR_VALUE(k2) || IS_ERR_VALUE(k3)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004505 dev_err(codec->dev,
4506 "%s: could not get K value. k1 = %d k2 = %d k3 = %d\n",
4507 __func__, k1, k2, k3);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004508 rc = -EINVAL;
4509 goto done;
4510 }
4511 /* Set voltage level and always use LDO */
4512 snd_soc_update_bits(codec, TAPAN_A_LDO_H_MODE_1, 0x0C,
4513 (pdata->micbias.ldoh_v << 2));
4514
4515 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_1_VAL, 0xFC, (k1 << 2));
4516 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_2_VAL, 0xFC, (k2 << 2));
4517 snd_soc_update_bits(codec, TAPAN_A_MICB_CFILT_3_VAL, 0xFC, (k3 << 2));
4518
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004519 i = 0;
4520 while (i < 5) {
4521 if (flag & (0x01 << i)) {
4522 val_txfe = (txfe_bypass & (0x01 << i)) ? 0x20 : 0x00;
4523 val_txfe = val_txfe |
4524 ((txfe_buff & (0x01 << i)) ? 0x10 : 0x00);
4525 snd_soc_update_bits(codec,
4526 TAPAN_A_TX_1_2_TEST_EN + j * 10,
4527 0x30, val_txfe);
4528 }
4529 if (flag & (0x01 << (i + 1))) {
4530 val_txfe = (txfe_bypass &
4531 (0x01 << (i + 1))) ? 0x02 : 0x00;
4532 val_txfe |= (txfe_buff &
4533 (0x01 << (i + 1))) ? 0x01 : 0x00;
4534 snd_soc_update_bits(codec,
4535 TAPAN_A_TX_1_2_TEST_EN + j * 10,
4536 0x03, val_txfe);
4537 }
4538 /* Tapan only has TAPAN_A_TX_1_2_TEST_EN and
4539 TAPAN_A_TX_4_5_TEST_EN reg */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004540
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004541 if (i == 0) {
4542 i = 3;
4543 continue;
4544 } else if (i == 3) {
4545 break;
4546 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004547 }
4548
4549 if (pdata->ocp.use_pdata) {
4550 /* not defined in CODEC specification */
4551 if (pdata->ocp.hph_ocp_limit == 1 ||
4552 pdata->ocp.hph_ocp_limit == 5) {
4553 rc = -EINVAL;
4554 goto done;
4555 }
4556 snd_soc_update_bits(codec, TAPAN_A_RX_COM_OCP_CTL,
4557 0x0F, pdata->ocp.num_attempts);
4558 snd_soc_write(codec, TAPAN_A_RX_COM_OCP_COUNT,
4559 ((pdata->ocp.run_time << 4) | pdata->ocp.wait_time));
4560 snd_soc_update_bits(codec, TAPAN_A_RX_HPH_OCP_CTL,
4561 0xE0, (pdata->ocp.hph_ocp_limit << 5));
4562 }
4563
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004564 /* Set micbias capless mode with tail current */
4565 value = (pdata->micbias.bias1_cap_mode == MICBIAS_EXT_BYP_CAP ?
4566 0x00 : 0x10);
4567 snd_soc_update_bits(codec, TAPAN_A_MICB_1_CTL, 0x10, value);
4568 value = (pdata->micbias.bias2_cap_mode == MICBIAS_EXT_BYP_CAP ?
4569 0x00 : 0x10);
4570 snd_soc_update_bits(codec, TAPAN_A_MICB_2_CTL, 0x10, value);
4571 value = (pdata->micbias.bias3_cap_mode == MICBIAS_EXT_BYP_CAP ?
4572 0x00 : 0x10);
4573 snd_soc_update_bits(codec, TAPAN_A_MICB_3_CTL, 0x10, value);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004574
4575done:
4576 return rc;
4577}
4578
4579static const struct tapan_reg_mask_val tapan_reg_defaults[] = {
4580
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004581 /* enable QFUSE for wcd9306 */
4582 TAPAN_REG_VAL(TAPAN_A_QFUSE_CTL, 0x03),
4583
4584 /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
4585 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
4586
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004587 TAPAN_REG_VAL(TAPAN_A_CDC_CLK_POWER_CTL, 0x03),
4588
4589 /* EAR PA deafults */
4590 TAPAN_REG_VAL(TAPAN_A_RX_EAR_CMBUFF, 0x05),
4591
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004592 /* RX1 and RX2 defaults */
4593 TAPAN_REG_VAL(TAPAN_A_CDC_RX1_B6_CTL, 0xA0),
4594 TAPAN_REG_VAL(TAPAN_A_CDC_RX2_B6_CTL, 0xA0),
4595
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004596 /* Heaset set Right from RX2 */
4597 TAPAN_REG_VAL(TAPAN_A_CDC_CONN_RX2_B2_CTL, 0x10),
4598
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004599
4600 /*
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004601 * The following only need to be written for Tapan 1.0 parts.
4602 * Tapan 2.0 will have appropriate defaults for these registers.
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004603 */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004604
4605 /* Required defaults for class H operation */
4606 /* borrowed from Taiko class-h */
4607 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0xF4),
4608 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x08),
4609 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_1, 0x5B),
Banajit Goswamia7294452013-06-03 12:42:35 -07004610 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_CCL_3, 0x6F),
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004611
4612 /* TODO: Check below reg writes conflict with above */
4613 /* PROGRAM_THE_0P85V_VBG_REFERENCE = V_0P858V */
4614 TAPAN_REG_VAL(TAPAN_A_BIAS_CURR_CTL_2, 0x04),
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004615 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CHOP_CTL, 0x74),
4616 TAPAN_REG_VAL(TAPAN_A_RX_BUCK_BIAS1, 0x62),
4617
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004618 /* Choose max non-overlap time for NCP */
4619 TAPAN_REG_VAL(TAPAN_A_NCP_CLK, 0xFC),
4620 /* Use 25mV/50mV for deltap/m to reduce ripple */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004621 TAPAN_REG_VAL(WCD9XXX_A_BUCK_CTRL_VCL_1, 0x08),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004622 /*
4623 * Set DISABLE_MODE_SEL<1:0> to 0b10 (disable PWM in auto mode).
4624 * Note that the other bits of this register will be changed during
4625 * Rx PA bring up.
4626 */
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004627 TAPAN_REG_VAL(WCD9XXX_A_BUCK_MODE_3, 0xCE),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004628 /* Reduce HPH DAC bias to 70% */
4629 TAPAN_REG_VAL(TAPAN_A_RX_HPH_BIAS_PA, 0x7A),
4630 /*Reduce EAR DAC bias to 70% */
4631 TAPAN_REG_VAL(TAPAN_A_RX_EAR_BIAS_PA, 0x76),
4632 /* Reduce LINE DAC bias to 70% */
4633 TAPAN_REG_VAL(TAPAN_A_RX_LINE_BIAS_PA, 0x78),
4634
4635 /*
4636 * There is a diode to pull down the micbias while doing
4637 * insertion detection. This diode can cause leakage.
4638 * Set bit 0 to 1 to prevent leakage.
4639 * Setting this bit of micbias 2 prevents leakage for all other micbias.
4640 */
4641 TAPAN_REG_VAL(TAPAN_A_MICB_2_MBHC, 0x41),
4642
Bhalchandra Gajare7c739522013-06-20 15:31:02 -07004643 /*
4644 * Default register settings to support dynamic change of
4645 * vdd_buck between 1.8 volts and 2.15 volts.
4646 */
4647 TAPAN_REG_VAL(TAPAN_A_BUCK_MODE_2, 0xAA),
4648
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004649};
4650
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004651static const struct tapan_reg_mask_val tapan_2_x_reg_reset_values[] = {
4652
4653 TAPAN_REG_VAL(TAPAN_A_TX_7_MBHC_EN, 0x6C),
4654 TAPAN_REG_VAL(TAPAN_A_BUCK_CTRL_CCL_4, 0x51),
4655 TAPAN_REG_VAL(TAPAN_A_RX_HPH_CNP_WG_CTL, 0xDA),
4656 TAPAN_REG_VAL(TAPAN_A_RX_EAR_CNP, 0xC0),
4657 TAPAN_REG_VAL(TAPAN_A_RX_LINE_1_TEST, 0x02),
4658 TAPAN_REG_VAL(TAPAN_A_RX_LINE_2_TEST, 0x02),
4659 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_OCP_CTL, 0x97),
4660 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_CLIP_DET, 0x01),
4661 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_IEC, 0x00),
4662 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B1_CTL, 0xE4),
4663 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B2_CTL, 0x00),
4664 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_B3_CTL, 0x00),
4665 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_BUCK_NCP_VARS, 0x00),
4666 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_EAR, 0x00),
4667 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_HD_HPH, 0x00),
4668 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_EAR, 0x00),
4669 TAPAN_REG_VAL(TAPAN_A_CDC_CLSH_V_PA_MIN_HPH, 0x00),
4670};
4671
4672static const struct tapan_reg_mask_val tapan_1_0_reg_defaults[] = {
4673 /* Close leakage on the spkdrv */
4674 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_PWRSTG, 0x24),
4675 TAPAN_REG_VAL(TAPAN_A_SPKR_DRV_DBG_DAC, 0xE5),
4676
4677};
4678
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004679static void tapan_update_reg_defaults(struct snd_soc_codec *codec)
4680{
4681 u32 i;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004682 struct wcd9xxx *tapan_core = dev_get_drvdata(codec->dev->parent);
4683
4684 if (!TAPAN_IS_1_0(tapan_core->version)) {
4685 for (i = 0; i < ARRAY_SIZE(tapan_2_x_reg_reset_values); i++)
4686 snd_soc_write(codec, tapan_2_x_reg_reset_values[i].reg,
4687 tapan_2_x_reg_reset_values[i].val);
4688 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004689
4690 for (i = 0; i < ARRAY_SIZE(tapan_reg_defaults); i++)
4691 snd_soc_write(codec, tapan_reg_defaults[i].reg,
4692 tapan_reg_defaults[i].val);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004693
4694 if (TAPAN_IS_1_0(tapan_core->version)) {
4695 for (i = 0; i < ARRAY_SIZE(tapan_1_0_reg_defaults); i++)
4696 snd_soc_write(codec, tapan_1_0_reg_defaults[i].reg,
4697 tapan_1_0_reg_defaults[i].val);
4698 }
4699
4700 if (!TAPAN_IS_1_0(tapan_core->version))
4701 spkr_drv_wrnd = -1;
4702 else if (spkr_drv_wrnd == 1)
4703 snd_soc_write(codec, TAPAN_A_SPKR_DRV_EN, 0xEF);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004704}
4705
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004706static void tapan_update_reg_mclk_rate(struct wcd9xxx *wcd9xxx)
4707{
4708 struct snd_soc_codec *codec;
4709
4710 codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
4711 dev_dbg(codec->dev, "%s: MCLK Rate = %x\n",
4712 __func__, wcd9xxx->mclk_rate);
4713
4714 if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_12P288MHZ) {
4715 snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x0);
4716 snd_soc_update_bits(codec, TAPAN_A_RX_COM_TIMER_DIV, 0x01,
4717 0x01);
4718 } else if (wcd9xxx->mclk_rate == TAPAN_MCLK_CLK_9P6MHZ) {
4719 snd_soc_update_bits(codec, TAPAN_A_CHIP_CTL, 0x06, 0x2);
4720 }
4721}
4722
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004723static const struct tapan_reg_mask_val tapan_codec_reg_init_val[] = {
Phani Kumar Uppalapatieca9a102013-06-18 11:02:38 -07004724 /* Initialize current threshold to 365MA
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004725 * number of wait and run cycles to 4096
4726 */
Phani Kumar Uppalapatieca9a102013-06-18 11:02:38 -07004727 {TAPAN_A_RX_HPH_OCP_CTL, 0xE9, 0x69},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004728 {TAPAN_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Phani Kumar Uppalapatieca9a102013-06-18 11:02:38 -07004729 {TAPAN_A_RX_HPH_L_TEST, 0x01, 0x01},
4730 {TAPAN_A_RX_HPH_R_TEST, 0x01, 0x01},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004731
4732 /* Initialize gain registers to use register gain */
4733 {TAPAN_A_RX_HPH_L_GAIN, 0x20, 0x20},
4734 {TAPAN_A_RX_HPH_R_GAIN, 0x20, 0x20},
4735 {TAPAN_A_RX_LINE_1_GAIN, 0x20, 0x20},
4736 {TAPAN_A_RX_LINE_2_GAIN, 0x20, 0x20},
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004737 {TAPAN_A_SPKR_DRV_GAIN, 0x04, 0x04},
4738
4739 /* Set RDAC5 MUX to take input from DEM3_INV.
4740 * This sets LO2 DAC to get input from DEM3_INV
4741 * for LO1 and LO2 to work as differential outputs.
4742 */
4743 {TAPAN_A_CDC_CONN_MISC, 0x04, 0x04},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004744
4745 /* CLASS H config */
4746 {TAPAN_A_CDC_CONN_CLSH_CTL, 0x3C, 0x14},
4747
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004748 /* Use 16 bit sample size for TX1 to TX5 */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004749 {TAPAN_A_CDC_CONN_TX_SB_B1_CTL, 0x30, 0x20},
4750 {TAPAN_A_CDC_CONN_TX_SB_B2_CTL, 0x30, 0x20},
4751 {TAPAN_A_CDC_CONN_TX_SB_B3_CTL, 0x30, 0x20},
4752 {TAPAN_A_CDC_CONN_TX_SB_B4_CTL, 0x30, 0x20},
4753 {TAPAN_A_CDC_CONN_TX_SB_B5_CTL, 0x30, 0x20},
4754
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004755 /* Disable SPK SWITCH */
4756 {TAPAN_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
4757
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004758 /* Use 16 bit sample size for RX */
4759 {TAPAN_A_CDC_CONN_RX_SB_B1_CTL, 0xFF, 0xAA},
4760 {TAPAN_A_CDC_CONN_RX_SB_B2_CTL, 0xFF, 0x2A},
4761
4762 /*enable HPF filter for TX paths */
4763 {TAPAN_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
4764 {TAPAN_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
4765 {TAPAN_A_CDC_TX3_MUX_CTL, 0x8, 0x0},
4766 {TAPAN_A_CDC_TX4_MUX_CTL, 0x8, 0x0},
4767
4768 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
4769 {TAPAN_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
4770 {TAPAN_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
4771 {TAPAN_A_CDC_TX3_DMIC_CTL, 0x7, 0x1},
4772 {TAPAN_A_CDC_TX4_DMIC_CTL, 0x7, 0x1},
4773
4774 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
4775 {TAPAN_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004776
Bhalchandra Gajareea898742013-03-05 18:15:53 -08004777 /* Compander zone selection */
4778 {TAPAN_A_CDC_COMP0_B4_CTL, 0x3F, 0x37},
4779 {TAPAN_A_CDC_COMP1_B4_CTL, 0x3F, 0x37},
4780 {TAPAN_A_CDC_COMP2_B4_CTL, 0x3F, 0x37},
4781 {TAPAN_A_CDC_COMP0_B5_CTL, 0x7F, 0x7F},
4782 {TAPAN_A_CDC_COMP1_B5_CTL, 0x7F, 0x7F},
4783 {TAPAN_A_CDC_COMP2_B5_CTL, 0x7F, 0x7F},
Banajit Goswamia7294452013-06-03 12:42:35 -07004784
4785 /*
4786 * Setup wavegen timer to 20msec and disable chopper
4787 * as default. This corresponds to Compander OFF
4788 */
4789 {TAPAN_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDB},
4790 {TAPAN_A_RX_HPH_CNP_WG_TIME, 0xFF, 0x58},
4791 {TAPAN_A_RX_HPH_BIAS_WG_OCP, 0xFF, 0x1A},
4792 {TAPAN_A_RX_HPH_CHOP_CTL, 0xFF, 0x24},
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004793};
4794
4795static void tapan_codec_init_reg(struct snd_soc_codec *codec)
4796{
4797 u32 i;
4798
4799 for (i = 0; i < ARRAY_SIZE(tapan_codec_reg_init_val); i++)
4800 snd_soc_update_bits(codec, tapan_codec_reg_init_val[i].reg,
4801 tapan_codec_reg_init_val[i].mask,
4802 tapan_codec_reg_init_val[i].val);
4803}
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004804static void tapan_slim_interface_init_reg(struct snd_soc_codec *codec)
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004805{
4806 int i;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004807
4808 for (i = 0; i < WCD9XXX_SLIM_NUM_PORT_REG; i++)
4809 wcd9xxx_interface_reg_write(codec->control_data,
4810 TAPAN_SLIM_PGD_PORT_INT_EN0 + i,
4811 0xFF);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004812}
4813
4814static int tapan_setup_irqs(struct tapan_priv *tapan)
4815{
4816 int ret = 0;
4817 struct snd_soc_codec *codec = tapan->codec;
4818
4819 ret = wcd9xxx_request_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS,
4820 tapan_slimbus_irq, "SLIMBUS Slave", tapan);
4821 if (ret)
4822 pr_err("%s: Failed to request irq %d\n", __func__,
4823 WCD9XXX_IRQ_SLIMBUS);
4824 else
4825 tapan_slim_interface_init_reg(codec);
4826
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004827 return ret;
4828}
4829
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07004830static void tapan_cleanup_irqs(struct tapan_priv *tapan)
4831{
4832 struct snd_soc_codec *codec = tapan->codec;
4833 wcd9xxx_free_irq(codec->control_data, WCD9XXX_IRQ_SLIMBUS, tapan);
4834}
4835
Simmi Pateriya95466b12013-05-09 20:08:46 +05304836
4837static void tapan_enable_mux_bias_block(struct snd_soc_codec *codec)
4838{
4839 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
4840 0x80, 0x00);
4841}
4842
4843static void tapan_put_cfilt_fast_mode(struct snd_soc_codec *codec,
4844 struct wcd9xxx_mbhc *mbhc)
4845{
4846 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
4847 0x30, 0x30);
4848}
4849
4850static void tapan_codec_specific_cal_setup(struct snd_soc_codec *codec,
4851 struct wcd9xxx_mbhc *mbhc)
4852{
4853 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
Phani Kumar Uppalapati10754402013-07-12 22:48:45 -07004854 0x04, 0x04);
Simmi Pateriya95466b12013-05-09 20:08:46 +05304855 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN, 0xE0, 0xE0);
4856}
4857
4858static int tapan_get_jack_detect_irq(struct snd_soc_codec *codec)
4859{
4860 return TAPAN_IRQ_MBHC_JACK_SWITCH;
4861}
4862
4863static struct wcd9xxx_cfilt_mode tapan_codec_switch_cfilt_mode(
4864 struct wcd9xxx_mbhc *mbhc,
4865 bool fast)
4866{
4867 struct snd_soc_codec *codec = mbhc->codec;
4868 struct wcd9xxx_cfilt_mode cfilt_mode;
4869
4870 if (fast)
4871 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
4872 else
4873 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
4874
4875 cfilt_mode.cur_mode_val =
4876 snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
4877 return cfilt_mode;
4878}
4879
4880static void tapan_select_cfilt(struct snd_soc_codec *codec,
4881 struct wcd9xxx_mbhc *mbhc)
4882{
4883 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
4884}
4885
4886static void tapan_free_irq(struct wcd9xxx_mbhc *mbhc)
4887{
4888 void *cdata = mbhc->codec->control_data;
4889 wcd9xxx_free_irq(cdata, WCD9306_IRQ_MBHC_JACK_SWITCH, mbhc);
4890}
4891
4892static const struct wcd9xxx_mbhc_cb mbhc_cb = {
4893 .enable_mux_bias_block = tapan_enable_mux_bias_block,
4894 .cfilt_fast_mode = tapan_put_cfilt_fast_mode,
4895 .codec_specific_cal = tapan_codec_specific_cal_setup,
4896 .jack_detect_irq = tapan_get_jack_detect_irq,
4897 .switch_cfilt_mode = tapan_codec_switch_cfilt_mode,
4898 .select_cfilt = tapan_select_cfilt,
4899 .free_irq = tapan_free_irq,
4900};
4901
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004902int tapan_hs_detect(struct snd_soc_codec *codec,
4903 struct wcd9xxx_mbhc_config *mbhc_cfg)
4904{
4905 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
4906 return wcd9xxx_mbhc_start(&tapan->mbhc, mbhc_cfg);
4907}
4908EXPORT_SYMBOL_GPL(tapan_hs_detect);
4909
Joonwoo Park8ffa2812013-08-07 19:01:30 -07004910static int tapan_device_down(struct wcd9xxx *wcd9xxx)
4911{
4912 struct snd_soc_codec *codec;
4913
4914 codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
4915 snd_soc_card_change_online_state(codec->card, 0);
4916
4917 return 0;
4918}
4919
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004920static int tapan_post_reset_cb(struct wcd9xxx *wcd9xxx)
4921{
4922 int ret = 0;
4923 int rco_clk_rate;
4924 struct snd_soc_codec *codec;
4925 struct tapan_priv *tapan;
4926
4927 codec = (struct snd_soc_codec *)(wcd9xxx->ssr_priv);
4928 tapan = snd_soc_codec_get_drvdata(codec);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004929
Joonwoo Park8ffa2812013-08-07 19:01:30 -07004930 snd_soc_card_change_online_state(codec->card, 1);
4931
4932 mutex_lock(&codec->mutex);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004933 if (codec->reg_def_copy) {
4934 pr_debug("%s: Update ASOC cache", __func__);
4935 kfree(codec->reg_cache);
4936 codec->reg_cache = kmemdup(codec->reg_def_copy,
4937 codec->reg_size, GFP_KERNEL);
4938 if (!codec->reg_cache) {
4939 pr_err("%s: Cache update failed!\n", __func__);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004940 mutex_unlock(&codec->mutex);
4941 return -ENOMEM;
4942 }
4943 }
4944
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004945 if (spkr_drv_wrnd == 1)
4946 snd_soc_update_bits(codec, TAPAN_A_SPKR_DRV_EN, 0x80, 0x80);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004947
4948 tapan_update_reg_defaults(codec);
4949 tapan_update_reg_mclk_rate(wcd9xxx);
4950 tapan_codec_init_reg(codec);
4951 ret = tapan_handle_pdata(tapan);
4952 if (IS_ERR_VALUE(ret))
4953 pr_err("%s: bad pdata\n", __func__);
4954
4955 tapan_slim_interface_init_reg(codec);
4956
Joonwoo Park865bcf02013-07-15 14:05:32 -07004957 wcd9xxx_resmgr_post_ssr(&tapan->resmgr);
4958
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004959 wcd9xxx_mbhc_deinit(&tapan->mbhc);
4960
4961 if (TAPAN_IS_1_0(wcd9xxx->version))
4962 rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
4963 else
4964 rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
4965
4966 ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
Phani Kumar Uppalapatid7549e12013-07-12 22:22:03 -07004967 &mbhc_cb, rco_clk_rate, false);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004968 if (ret)
4969 pr_err("%s: mbhc init failed %d\n", __func__, ret);
4970 else
4971 wcd9xxx_mbhc_start(&tapan->mbhc, tapan->mbhc.mbhc_cfg);
4972 mutex_unlock(&codec->mutex);
4973 return ret;
4974}
4975
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08004976static struct wcd9xxx_reg_address tapan_reg_address = {
4977};
4978
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004979static int wcd9xxx_ssr_register(struct wcd9xxx *control,
Joonwoo Park8ffa2812013-08-07 19:01:30 -07004980 int (*device_down_cb)(struct wcd9xxx *wcd9xxx),
4981 int (*device_up_cb)(struct wcd9xxx *wcd9xxx),
4982 void *priv)
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004983{
Joonwoo Park8ffa2812013-08-07 19:01:30 -07004984 control->dev_down = device_down_cb;
4985 control->post_reset = device_up_cb;
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07004986 control->ssr_priv = priv;
4987 return 0;
4988}
4989
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07004990static struct regulator *tapan_codec_find_regulator(
4991 struct snd_soc_codec *codec,
4992 const char *name)
4993{
4994 int i;
4995 struct wcd9xxx *core = dev_get_drvdata(codec->dev->parent);
4996
4997 for (i = 0; i < core->num_of_supplies; i++) {
4998 if (core->supplies[i].supply &&
4999 !strcmp(core->supplies[i].supply, name))
5000 return core->supplies[i].consumer;
5001 }
5002 return NULL;
5003}
5004
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005005static void tapan_enable_config_rco(struct wcd9xxx *core, bool enable)
5006{
5007 if (enable) {
5008 /* Enable RC Oscillator */
5009 wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x10, 0x00);
5010 wcd9xxx_reg_write(core, WCD9XXX_A_BIAS_OSC_BG_CTL, 0x17);
5011 usleep_range(5, 5);
5012 wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_FREQ, 0x80, 0x80);
5013 wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x80);
5014 usleep_range(10, 10);
5015 wcd9xxx_reg_update(core, WCD9XXX_A_RC_OSC_TEST, 0x80, 0x00);
5016 usleep_range(20, 20);
5017 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x08, 0x08);
5018 /* Enable MCLK and wait 1ms till it gets enabled */
5019 wcd9xxx_reg_write(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02);
5020 usleep_range(1000, 1000);
5021 /* Enable CLK BUFF and wait for 1.2ms */
5022 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x01, 0x01);
5023 usleep_range(1000, 1200);
5024
5025 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x00);
5026 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x04);
5027 wcd9xxx_reg_update(core, WCD9XXX_A_CDC_CLK_MCLK_CTL,
5028 0x01, 0x01);
5029 usleep_range(50, 50);
5030 } else {
5031 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x04, 0x00);
5032 usleep_range(50, 50);
5033 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN2, 0x02, 0x02);
5034 wcd9xxx_reg_update(core, WCD9XXX_A_CLK_BUFF_EN1, 0x05, 0x00);
5035 usleep_range(50, 50);
5036 }
5037
5038}
5039
5040static bool tapan_check_wcd9306(struct device *cdc_dev, bool sensed)
5041{
5042 struct wcd9xxx *core = dev_get_drvdata(cdc_dev->parent);
5043 u8 reg_val;
5044 bool ret = true;
5045 unsigned long timeout;
5046 bool timedout;
5047
5048 if (!core) {
5049 dev_err(cdc_dev, "%s: core not initialized\n", __func__);
5050 return -EINVAL;
5051 }
5052
5053 tapan_enable_config_rco(core, 1);
5054
5055 if (sensed == false) {
5056 reg_val = wcd9xxx_reg_read(core, TAPAN_A_QFUSE_CTL);
5057 wcd9xxx_reg_write(core, TAPAN_A_QFUSE_CTL, (reg_val | 0x03));
5058 }
5059
5060 timeout = jiffies + HZ;
5061 do {
5062 if ((wcd9xxx_reg_read(core, TAPAN_A_QFUSE_STATUS)))
5063 break;
5064 } while (!(timedout = time_after(jiffies, timeout)));
5065
5066 if (wcd9xxx_reg_read(core, TAPAN_A_QFUSE_DATA_OUT1) ||
5067 wcd9xxx_reg_read(core, TAPAN_A_QFUSE_DATA_OUT2)) {
5068 dev_info(cdc_dev, "%s: wcd9302 detected\n", __func__);
5069 ret = false;
5070 } else
5071 dev_info(cdc_dev, "%s: wcd9306 detected\n", __func__);
5072
5073 tapan_enable_config_rco(core, 0);
5074 return ret;
5075};
5076
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005077static int tapan_codec_probe(struct snd_soc_codec *codec)
5078{
5079 struct wcd9xxx *control;
5080 struct tapan_priv *tapan;
5081 struct wcd9xxx_pdata *pdata;
5082 struct wcd9xxx *wcd9xxx;
5083 struct snd_soc_dapm_context *dapm = &codec->dapm;
5084 int ret = 0;
Phani Kumar Uppalapati43bc4152013-05-24 00:44:20 -07005085 int i, rco_clk_rate;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005086 void *ptr = NULL;
5087
5088 codec->control_data = dev_get_drvdata(codec->dev->parent);
5089 control = codec->control_data;
5090
Joonwoo Park8ffa2812013-08-07 19:01:30 -07005091 wcd9xxx_ssr_register(control, tapan_device_down,
5092 tapan_post_reset_cb, (void *)codec);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07005093
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005094 dev_info(codec->dev, "%s()\n", __func__);
5095
5096 tapan = kzalloc(sizeof(struct tapan_priv), GFP_KERNEL);
5097 if (!tapan) {
5098 dev_err(codec->dev, "Failed to allocate private data\n");
5099 return -ENOMEM;
5100 }
5101 for (i = 0 ; i < NUM_DECIMATORS; i++) {
5102 tx_hpf_work[i].tapan = tapan;
5103 tx_hpf_work[i].decimator = i + 1;
5104 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
5105 tx_hpf_corner_freq_callback);
5106 }
5107
5108 snd_soc_codec_set_drvdata(codec, tapan);
5109
5110 /* codec resmgr module init */
5111 wcd9xxx = codec->control_data;
5112 pdata = dev_get_platdata(codec->dev->parent);
5113 ret = wcd9xxx_resmgr_init(&tapan->resmgr, codec, wcd9xxx, pdata,
5114 &tapan_reg_address);
5115 if (ret) {
5116 pr_err("%s: wcd9xxx init failed %d\n", __func__, ret);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005117 return ret;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005118 }
5119
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07005120 tapan->cp_regulators[CP_REG_BUCK] = tapan_codec_find_regulator(codec,
5121 WCD9XXX_SUPPLY_BUCK_NAME);
5122 tapan->cp_regulators[CP_REG_BHELPER] = tapan_codec_find_regulator(codec,
5123 "cdc-vdd-buckhelper");
5124
Bhalchandra Gajare7c739522013-06-20 15:31:02 -07005125 tapan->clsh_d.buck_mv = tapan_codec_get_buck_mv(codec);
5126 /*
5127 * If 1.8 volts is requested on the vdd_cp line, then
5128 * assume that S4 is in a dynamically switchable state
5129 * and can switch between 1.8 volts and 2.15 volts
5130 */
5131 if (tapan->clsh_d.buck_mv == WCD9XXX_CDC_BUCK_MV_1P8)
5132 tapan->clsh_d.is_dynamic_vdd_cp = true;
5133 wcd9xxx_clsh_init(&tapan->clsh_d, &tapan->resmgr);
5134
Phani Kumar Uppalapati43bc4152013-05-24 00:44:20 -07005135 if (TAPAN_IS_1_0(control->version))
5136 rco_clk_rate = TAPAN_MCLK_CLK_12P288MHZ;
5137 else
5138 rco_clk_rate = TAPAN_MCLK_CLK_9P6MHZ;
5139
Joonwoo Parkccccba72013-04-26 11:19:46 -07005140 ret = wcd9xxx_mbhc_init(&tapan->mbhc, &tapan->resmgr, codec, NULL,
Phani Kumar Uppalapatid7549e12013-07-12 22:22:03 -07005141 &mbhc_cb, rco_clk_rate, false);
Simmi Pateriya95466b12013-05-09 20:08:46 +05305142
Simmi Pateriya0a44d842013-04-03 01:12:42 +05305143 if (ret) {
5144 pr_err("%s: mbhc init failed %d\n", __func__, ret);
5145 return ret;
5146 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005147
5148 tapan->codec = codec;
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005149 for (i = 0; i < COMPANDER_MAX; i++) {
5150 tapan->comp_enabled[i] = 0;
5151 tapan->comp_fs[i] = COMPANDER_FS_48KHZ;
5152 }
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005153 tapan->intf_type = wcd9xxx_get_intf_type();
5154 tapan->aux_pga_cnt = 0;
5155 tapan->aux_l_gain = 0x1F;
5156 tapan->aux_r_gain = 0x1F;
5157 tapan_update_reg_defaults(codec);
Ravishankar Sarawadid6273212013-05-07 15:08:27 -07005158 tapan_update_reg_mclk_rate(wcd9xxx);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005159 tapan_codec_init_reg(codec);
5160 ret = tapan_handle_pdata(tapan);
5161 if (IS_ERR_VALUE(ret)) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005162 dev_err(codec->dev, "%s: bad pdata\n", __func__);
5163 goto err_pdata;
5164 }
5165
5166 if (spkr_drv_wrnd > 0) {
Joonwoo Park533b3682013-06-13 11:41:21 -07005167 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005168 wcd9xxx_resmgr_get_bandgap(&tapan->resmgr,
5169 WCD9XXX_BANDGAP_AUDIO_MODE);
Joonwoo Park533b3682013-06-13 11:41:21 -07005170 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005171 }
5172
5173 ptr = kmalloc((sizeof(tapan_rx_chs) +
5174 sizeof(tapan_tx_chs)), GFP_KERNEL);
5175 if (!ptr) {
5176 pr_err("%s: no mem for slim chan ctl data\n", __func__);
5177 ret = -ENOMEM;
5178 goto err_nomem_slimch;
5179 }
5180
5181 if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_I2C) {
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005182 snd_soc_dapm_new_controls(dapm, tapan_dapm_i2s_widgets,
5183 ARRAY_SIZE(tapan_dapm_i2s_widgets));
5184 snd_soc_dapm_add_routes(dapm, audio_i2s_map,
5185 ARRAY_SIZE(audio_i2s_map));
5186 for (i = 0; i < ARRAY_SIZE(tapan_i2s_dai); i++)
5187 INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005188 } else if (tapan->intf_type == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
5189 for (i = 0; i < NUM_CODEC_DAIS; i++) {
5190 INIT_LIST_HEAD(&tapan->dai[i].wcd9xxx_ch_list);
5191 init_waitqueue_head(&tapan->dai[i].dai_wait);
5192 }
5193 }
5194
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005195 if (tapan_check_wcd9306(codec->dev, false) == true) {
5196 snd_soc_add_codec_controls(codec, tapan_9306_snd_controls,
5197 ARRAY_SIZE(tapan_9306_snd_controls));
5198 snd_soc_dapm_new_controls(dapm, tapan_9306_dapm_widgets,
5199 ARRAY_SIZE(tapan_9306_dapm_widgets));
5200 snd_soc_dapm_add_routes(dapm, wcd9306_map,
5201 ARRAY_SIZE(wcd9306_map));
5202 } else {
5203 snd_soc_dapm_add_routes(dapm, wcd9302_map,
5204 ARRAY_SIZE(wcd9302_map));
5205 }
5206
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005207 control->num_rx_port = TAPAN_RX_MAX;
5208 control->rx_chs = ptr;
5209 memcpy(control->rx_chs, tapan_rx_chs, sizeof(tapan_rx_chs));
5210 control->num_tx_port = TAPAN_TX_MAX;
5211 control->tx_chs = ptr + sizeof(tapan_rx_chs);
5212 memcpy(control->tx_chs, tapan_tx_chs, sizeof(tapan_tx_chs));
5213
5214 snd_soc_dapm_sync(dapm);
5215
5216 (void) tapan_setup_irqs(tapan);
5217
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005218 atomic_set(&kp_tapan_priv, (unsigned long)tapan);
Phani Kumar Uppalapati3a5f8cc2013-04-08 21:30:02 -07005219 mutex_lock(&dapm->codec->mutex);
5220 snd_soc_dapm_disable_pin(dapm, "ANC HPHL");
5221 snd_soc_dapm_disable_pin(dapm, "ANC HPHR");
5222 snd_soc_dapm_disable_pin(dapm, "ANC HEADPHONE");
5223 snd_soc_dapm_disable_pin(dapm, "ANC EAR PA");
5224 snd_soc_dapm_disable_pin(dapm, "ANC EAR");
5225 snd_soc_dapm_sync(dapm);
5226 mutex_unlock(&dapm->codec->mutex);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005227
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005228 codec->ignore_pmdown_time = 1;
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07005229
5230 if (ret)
5231 tapan_cleanup_irqs(tapan);
5232
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005233 return ret;
5234
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005235err_pdata:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005236 kfree(ptr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005237err_nomem_slimch:
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005238 kfree(tapan);
5239 return ret;
5240}
5241
5242static int tapan_codec_remove(struct snd_soc_codec *codec)
5243{
5244 struct tapan_priv *tapan = snd_soc_codec_get_drvdata(codec);
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07005245 int index = 0;
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005246
Joonwoo Park533b3682013-06-13 11:41:21 -07005247 WCD9XXX_BG_CLK_LOCK(&tapan->resmgr);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005248 atomic_set(&kp_tapan_priv, 0);
5249
5250 if (spkr_drv_wrnd > 0)
5251 wcd9xxx_resmgr_put_bandgap(&tapan->resmgr,
5252 WCD9XXX_BANDGAP_AUDIO_MODE);
Joonwoo Park533b3682013-06-13 11:41:21 -07005253 WCD9XXX_BG_CLK_UNLOCK(&tapan->resmgr);
Ravishankar Sarawadi7b700362013-04-18 15:56:02 -07005254
5255 tapan_cleanup_irqs(tapan);
5256
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005257 /* cleanup MBHC */
5258 wcd9xxx_mbhc_deinit(&tapan->mbhc);
5259 /* cleanup resmgr */
5260 wcd9xxx_resmgr_deinit(&tapan->resmgr);
5261
Bhalchandra Gajare5b4199c2013-07-03 14:35:43 -07005262 for (index = 0; index < CP_REG_MAX; index++)
5263 tapan->cp_regulators[index] = NULL;
5264
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005265 kfree(tapan);
5266 return 0;
5267}
5268
5269static struct snd_soc_codec_driver soc_codec_dev_tapan = {
5270 .probe = tapan_codec_probe,
5271 .remove = tapan_codec_remove,
5272
5273 .read = tapan_read,
5274 .write = tapan_write,
5275
5276 .readable_register = tapan_readable,
5277 .volatile_register = tapan_volatile,
5278
5279 .reg_cache_size = TAPAN_CACHE_SIZE,
5280 .reg_cache_default = tapan_reset_reg_defaults,
5281 .reg_word_size = 1,
5282
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005283 .controls = tapan_common_snd_controls,
5284 .num_controls = ARRAY_SIZE(tapan_common_snd_controls),
5285 .dapm_widgets = tapan_common_dapm_widgets,
5286 .num_dapm_widgets = ARRAY_SIZE(tapan_common_dapm_widgets),
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005287 .dapm_routes = audio_map,
5288 .num_dapm_routes = ARRAY_SIZE(audio_map),
5289};
5290
5291#ifdef CONFIG_PM
5292static int tapan_suspend(struct device *dev)
5293{
5294 dev_dbg(dev, "%s: system suspend\n", __func__);
5295 return 0;
5296}
5297
5298static int tapan_resume(struct device *dev)
5299{
5300 struct platform_device *pdev = to_platform_device(dev);
5301 struct tapan_priv *tapan = platform_get_drvdata(pdev);
5302 dev_dbg(dev, "%s: system resume\n", __func__);
Bhalchandra Gajareea898742013-03-05 18:15:53 -08005303 /* Notify */
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005304 wcd9xxx_resmgr_notifier_call(&tapan->resmgr, WCD9XXX_EVENT_POST_RESUME);
5305 return 0;
5306}
5307
5308static const struct dev_pm_ops tapan_pm_ops = {
5309 .suspend = tapan_suspend,
5310 .resume = tapan_resume,
5311};
5312#endif
5313
5314static int __devinit tapan_probe(struct platform_device *pdev)
5315{
5316 int ret = 0;
Phani Kumar Uppalapati71ba8882013-04-12 19:57:52 -07005317 bool is_wcd9306;
5318
5319 is_wcd9306 = tapan_check_wcd9306(&pdev->dev, false);
5320 if (is_wcd9306 < 0) {
5321 dev_info(&pdev->dev, "%s: cannot find codec type, default to 9306\n",
5322 __func__);
5323 is_wcd9306 = true;
5324 }
5325
5326 if (!is_wcd9306) {
5327 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
5328 ret = snd_soc_register_codec(&pdev->dev,
5329 &soc_codec_dev_tapan,
5330 tapan9302_dai, ARRAY_SIZE(tapan9302_dai));
5331 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
5332 ret = snd_soc_register_codec(&pdev->dev,
5333 &soc_codec_dev_tapan,
5334 tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
5335 } else {
5336 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS)
5337 ret = snd_soc_register_codec(&pdev->dev,
5338 &soc_codec_dev_tapan,
5339 tapan_dai, ARRAY_SIZE(tapan_dai));
5340 else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
5341 ret = snd_soc_register_codec(&pdev->dev,
5342 &soc_codec_dev_tapan,
5343 tapan_i2s_dai, ARRAY_SIZE(tapan_i2s_dai));
5344 }
5345
Bhalchandra Gajaredcf09f82012-11-09 11:58:26 -08005346 return ret;
5347}
5348static int __devexit tapan_remove(struct platform_device *pdev)
5349{
5350 snd_soc_unregister_codec(&pdev->dev);
5351 return 0;
5352}
5353static struct platform_driver tapan_codec_driver = {
5354 .probe = tapan_probe,
5355 .remove = tapan_remove,
5356 .driver = {
5357 .name = "tapan_codec",
5358 .owner = THIS_MODULE,
5359#ifdef CONFIG_PM
5360 .pm = &tapan_pm_ops,
5361#endif
5362 },
5363};
5364
5365static int __init tapan_codec_init(void)
5366{
5367 return platform_driver_register(&tapan_codec_driver);
5368}
5369
5370static void __exit tapan_codec_exit(void)
5371{
5372 platform_driver_unregister(&tapan_codec_driver);
5373}
5374
5375module_init(tapan_codec_init);
5376module_exit(tapan_codec_exit);
5377
5378MODULE_DESCRIPTION("Tapan codec driver");
5379MODULE_LICENSE("GPL v2");