blob: 3c941fecbf2fe8a3d9fbcbbf67949fcf26fbd86f [file] [log] [blame]
Kuirong Wang265f3592012-12-05 16:17:41 -08001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
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>
21#include <linux/io.h>
22#include <linux/bitops.h>
23#include <linux/delay.h>
24#include <linux/pm_runtime.h>
25#include <linux/kernel.h>
26#include <linux/gpio.h>
27#include <linux/i2c.h>
28#include <linux/of_gpio.h>
29#include <linux/regulator/consumer.h>
30#include <linux/mfd/wcd9xxx/core.h>
31#include <linux/mfd/wcd9xxx/pdata.h>
32#include <sound/pcm.h>
33#include <sound/pcm_params.h>
34#include <sound/soc.h>
35#include <sound/soc-dapm.h>
36#include <sound/tlv.h>
Kuirong Wang91e52532013-03-31 14:24:22 -070037#include <mach/qdsp6v2/apr.h>
Kuirong Wang265f3592012-12-05 16:17:41 -080038#include "msm8x10-wcd.h"
39#include "wcd9xxx-resmgr.h"
40#include "msm8x10_wcd_registers.h"
41
42#define MSM8X10_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
43 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
44#define MSM8X10_WCD_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
45
46#define NUM_DECIMATORS 2
47#define NUM_INTERPOLATORS 3
48#define BITS_PER_REG 8
49#define MSM8X10_WCD_TX_PORT_NUMBER 4
50
51#define MSM8X10_WCD_I2S_MASTER_MODE_MASK 0x08
52#define MSM8X10_DINO_CODEC_BASE_ADDR 0xFE043000
53
Kuirong Wang3a6408d2013-02-20 17:46:46 -080054#define MAX_MSM8X10_WCD_DEVICE 4
Kuirong Wang265f3592012-12-05 16:17:41 -080055#define CODEC_DT_MAX_PROP_SIZE 40
Kuirong Wang91e52532013-03-31 14:24:22 -070056#define MSM8X10_WCD_I2C_GSBI_SLAVE_ID "5-000d"
Kuirong Wang265f3592012-12-05 16:17:41 -080057
58enum {
59 MSM8X10_WCD_I2C_TOP_LEVEL = 0,
60 MSM8X10_WCD_I2C_ANALOG,
61 MSM8X10_WCD_I2C_DIGITAL_1,
62 MSM8X10_WCD_I2C_DIGITAL_2,
63};
64
65enum {
66 AIF1_PB = 0,
67 AIF1_CAP,
68 NUM_CODEC_DAIS,
69};
70
71enum {
72 RX_MIX1_INP_SEL_ZERO = 0,
73 RX_MIX1_INP_SEL_IIR1,
74 RX_MIX1_INP_SEL_IIR2,
75 RX_MIX1_INP_SEL_RX1,
76 RX_MIX1_INP_SEL_RX2,
77 RX_MIX1_INP_SEL_RX3,
78};
79
80static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
81static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
82static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
83static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[];
84static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
85
Kuirong Wang91e52532013-03-31 14:24:22 -070086#define MSM8X10_WCD_ACQUIRE_LOCK(x) do { \
87 mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
88} while (0)
89#define MSM8X10_WCD_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
90
91
Kuirong Wang265f3592012-12-05 16:17:41 -080092/* Codec supports 2 IIR filters */
93enum {
94 IIR1 = 0,
95 IIR2,
96 IIR_MAX,
97};
Kuirong Wang3a6408d2013-02-20 17:46:46 -080098
Kuirong Wang265f3592012-12-05 16:17:41 -080099/* Codec supports 5 bands */
100enum {
101 BAND1 = 0,
102 BAND2,
103 BAND3,
104 BAND4,
105 BAND5,
106 BAND_MAX,
107};
108
Kuirong Wang91e52532013-03-31 14:24:22 -0700109enum msm8x10_wcd_bandgap_type {
110 MSM8X10_WCD_BANDGAP_OFF = 0,
111 MSM8X10_WCD_BANDGAP_AUDIO_MODE,
112 MSM8X10_WCD_BANDGAP_MBHC_MODE,
113};
114
Kuirong Wang265f3592012-12-05 16:17:41 -0800115struct hpf_work {
116 struct msm8x10_wcd_priv *msm8x10_wcd;
117 u32 decimator;
118 u8 tx_hpf_cut_of_freq;
119 struct delayed_work dwork;
120};
121
122static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
123
124struct msm8x10_wcd_priv {
125 struct snd_soc_codec *codec;
126 u32 adc_count;
127 u32 rx_bias_count;
128 s32 dmic_1_2_clk_cnt;
Kuirong Wang91e52532013-03-31 14:24:22 -0700129 enum msm8x10_wcd_bandgap_type bandgap_type;
130 bool mclk_enabled;
131 bool clock_active;
132 bool config_mode_active;
133 bool mbhc_polling_active;
134 struct mutex codec_resource_lock;
Kuirong Wang265f3592012-12-05 16:17:41 -0800135 /* resmgr module */
136 struct wcd9xxx_resmgr resmgr;
Kuirong Wang265f3592012-12-05 16:17:41 -0800137};
138
Kuirong Wang265f3592012-12-05 16:17:41 -0800139static unsigned short rx_digital_gain_reg[] = {
140 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
141 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
142 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
143};
144
145static unsigned short tx_digital_gain_reg[] = {
146 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
147 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
148};
149
150struct msm8x10_wcd_i2c {
151 struct i2c_client *client;
152 struct i2c_msg xfer_msg[2];
153 struct mutex xfer_lock;
154 int mod_id;
155};
156
157static char *msm8x10_wcd_supplies[] = {
Kuirong Wang91e52532013-03-31 14:24:22 -0700158 "cdc-vdda-cp", "cdc-vdda-h", "cdc-vdd-px", "cdc-vdd-1p2v",
159 "cdc-vdd-mic-bias",
Kuirong Wang265f3592012-12-05 16:17:41 -0800160};
161
162static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
163 struct msm8x10_wcd_regulator *vreg, const char *vreg_name);
164static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
165 struct msm8x10_wcd_micbias_setting *micbias);
166static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
167 struct device *dev);
168
169struct msm8x10_wcd_i2c msm8x10_wcd_modules[MAX_MSM8X10_WCD_DEVICE];
170
171
172static int get_i2c_msm8x10_wcd_device_info(u16 reg,
173 struct msm8x10_wcd_i2c **msm8x10_wcd)
174{
175 int rtn = 0;
176 int value = ((reg & 0x0f00) >> 8) & 0x000f;
Kuirong Wang265f3592012-12-05 16:17:41 -0800177 switch (value) {
178 case 0:
179 case 1:
180 *msm8x10_wcd = &msm8x10_wcd_modules[value];
181 break;
182 default:
183 rtn = -EINVAL;
184 break;
185 }
186 return rtn;
187}
188
Kuirong Wang91e52532013-03-31 14:24:22 -0700189static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
Kuirong Wang265f3592012-12-05 16:17:41 -0800190{
191 u32 temp = ((u32)(*value)) & 0x000000FF;
192 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
193 iowrite32(temp, ioremap(MSM8X10_DINO_CODEC_BASE_ADDR + offset, 4));
194 return 0;
195}
196
Kuirong Wang91e52532013-03-31 14:24:22 -0700197static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
Kuirong Wang265f3592012-12-05 16:17:41 -0800198{
Kuirong Wang91e52532013-03-31 14:24:22 -0700199 u32 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800200 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
Kuirong Wang91e52532013-03-31 14:24:22 -0700201 temp = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
Kuirong Wang265f3592012-12-05 16:17:41 -0800202 offset, 4));
Kuirong Wang91e52532013-03-31 14:24:22 -0700203 *value = (u8)temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800204 return 0;
205}
206
207static int msm8x10_wcd_i2c_write_device(u16 reg, u8 *value, u32 bytes)
208{
209
210 struct i2c_msg *msg;
211 int ret;
212 u8 reg_addr = 0;
213 u8 data[bytes + 1];
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800214 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800215
216 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800217 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800218 pr_err("%s: Invalid register address\n", __func__);
219 return ret;
220 }
221
222 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
223 pr_err("%s: Failed to get device info\n", __func__);
224 return -ENODEV;
225 }
226 reg_addr = (u8)reg;
227 msg = &msm8x10_wcd->xfer_msg[0];
228 msg->addr = msm8x10_wcd->client->addr;
229 msg->len = bytes + 1;
230 msg->flags = 0;
231 data[0] = reg;
232 data[1] = *value;
233 msg->buf = data;
234 ret = i2c_transfer(msm8x10_wcd->client->adapter,
235 msm8x10_wcd->xfer_msg, 1);
236 /* Try again if the write fails */
237 if (ret != 1) {
238 ret = i2c_transfer(msm8x10_wcd->client->adapter,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800239 msm8x10_wcd->xfer_msg, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -0800240 if (ret != 1) {
241 pr_err("failed to write the device\n");
242 return ret;
243 }
244 }
245 pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
246 return 0;
247}
248
249
250int msm8x10_wcd_i2c_read_device(u32 reg, u32 bytes, u8 *dest)
251{
252 struct i2c_msg *msg;
253 int ret = 0;
254 u8 reg_addr = 0;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800255 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800256 u8 i = 0;
257
258 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800259 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800260 pr_err("%s: Invalid register address\n", __func__);
261 return ret;
262 }
263
264 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
265 pr_err("%s: Failed to get device info\n", __func__);
266 return -ENODEV;
267 }
268
269 for (i = 0; i < bytes; i++) {
270 reg_addr = (u8)reg++;
271 msg = &msm8x10_wcd->xfer_msg[0];
272 msg->addr = msm8x10_wcd->client->addr;
273 msg->len = 1;
274 msg->flags = 0;
275 msg->buf = &reg_addr;
Kuirong Wang265f3592012-12-05 16:17:41 -0800276 msg = &msm8x10_wcd->xfer_msg[1];
277 msg->addr = msm8x10_wcd->client->addr;
278 msg->len = 1;
279 msg->flags = I2C_M_RD;
280 msg->buf = dest++;
281 ret = i2c_transfer(msm8x10_wcd->client->adapter,
282 msm8x10_wcd->xfer_msg, 2);
283
284 /* Try again if read fails first time */
285 if (ret != 2) {
286 ret = i2c_transfer(msm8x10_wcd->client->adapter,
287 msm8x10_wcd->xfer_msg, 2);
288 if (ret != 2) {
289 pr_err("failed to read msm8x10_wcd register\n");
290 return ret;
291 }
292 }
293 }
Kuirong Wang91e52532013-03-31 14:24:22 -0700294 pr_debug("%s: reg 0x%x = 0x%x\n", __func__, reg, *dest);
Kuirong Wang265f3592012-12-05 16:17:41 -0800295 return 0;
296}
297
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800298int msm8x10_wcd_i2c_read(unsigned short reg, int bytes, void *dest)
Kuirong Wang265f3592012-12-05 16:17:41 -0800299{
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800300 return msm8x10_wcd_i2c_read_device(reg, bytes, dest);
301}
302
303int msm8x10_wcd_i2c_write(unsigned short reg, int bytes, void *src)
304{
305 return msm8x10_wcd_i2c_write_device(reg, src, bytes);
306}
307
308static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
309 u16 reg, unsigned int *val)
310{
Kuirong Wang265f3592012-12-05 16:17:41 -0800311 int ret = -EINVAL;
Kuirong Wang91e52532013-03-31 14:24:22 -0700312 u8 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800313
314 /* check if use I2C interface for Helicon or AHB for Dino */
315 mutex_lock(&msm8x10_wcd->io_lock);
316 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang91e52532013-03-31 14:24:22 -0700317 ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800318 else if (MSM8X10_WCD_IS_DINO_REG(reg))
Kuirong Wang91e52532013-03-31 14:24:22 -0700319 ret = msm8x10_wcd_abh_read_device(reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800320 mutex_unlock(&msm8x10_wcd->io_lock);
Kuirong Wang91e52532013-03-31 14:24:22 -0700321 *val = temp;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800322 return ret;
Kuirong Wang265f3592012-12-05 16:17:41 -0800323}
324
325
326static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16 reg,
Kuirong Wang91e52532013-03-31 14:24:22 -0700327 u8 val)
Kuirong Wang265f3592012-12-05 16:17:41 -0800328{
329 int ret = -EINVAL;
330
331 /* check if use I2C interface for Helicon or AHB for Dino */
332 mutex_lock(&msm8x10_wcd->io_lock);
333 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800334 ret = msm8x10_wcd_i2c_write(reg, 1, &val);
Kuirong Wang265f3592012-12-05 16:17:41 -0800335 else if (MSM8X10_WCD_IS_DINO_REG(reg))
336 ret = msm8x10_wcd_abh_write_device(reg, &val, 1);
337 mutex_unlock(&msm8x10_wcd->io_lock);
338
339 return ret;
340}
341
342static bool msm8x10_wcd_is_digital_gain_register(unsigned int reg)
343{
344 bool rtn = false;
345 switch (reg) {
346 case MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL:
347 case MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL:
348 case MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL:
349 case MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN:
350 case MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN:
351 rtn = true;
352 break;
353 default:
354 break;
355 }
356 return rtn;
357}
358
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800359static int msm8x10_wcd_volatile(struct snd_soc_codec *codec, unsigned int reg)
Kuirong Wang265f3592012-12-05 16:17:41 -0800360{
361 /*
362 * Registers lower than 0x100 are top level registers which can be
363 * written by the Taiko core driver.
364 */
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800365 dev_dbg(codec->dev, "%s: reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800366
367 if ((reg >= MSM8X10_WCD_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
368 return 1;
369
370 /* IIR Coeff registers are not cacheable */
371 if ((reg >= MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL) &&
372 (reg <= MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL))
373 return 1;
374
375 /*
376 * Digital gain register is not cacheable so we have to write
377 * the setting even it is the same
378 */
379 if (msm8x10_wcd_is_digital_gain_register(reg))
380 return 1;
381
382 /* HPH status registers */
383 if (reg == MSM8X10_WCD_A_RX_HPH_L_STATUS ||
384 reg == MSM8X10_WCD_A_RX_HPH_R_STATUS)
385 return 1;
386
387 if (reg == MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS)
388 return 1;
389
390 return 0;
391}
392
393static int msm8x10_wcd_readable(struct snd_soc_codec *ssc, unsigned int reg)
394{
395 return msm8x10_wcd_reg_readable[reg];
396}
397
398static int msm8x10_wcd_write(struct snd_soc_codec *codec, unsigned int reg,
399 unsigned int value)
400{
401 int ret;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800402 dev_dbg(codec->dev, "%s: Write from reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800403 if (reg == SND_SOC_NOPM)
404 return 0;
405
406 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
407
408 if (!msm8x10_wcd_volatile(codec, reg)) {
409 ret = snd_soc_cache_write(codec, reg, value);
410 if (ret != 0)
411 dev_err(codec->dev, "Cache write to %x failed: %d\n",
412 reg, ret);
413 }
414
Kuirong Wang91e52532013-03-31 14:24:22 -0700415 return msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
Kuirong Wang265f3592012-12-05 16:17:41 -0800416}
417
418static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
419 unsigned int reg)
420{
421 unsigned int val;
422 int ret;
423
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800424 dev_dbg(codec->dev, "%s: Read from reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800425 if (reg == SND_SOC_NOPM)
426 return 0;
427
428 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
429
430 if (!msm8x10_wcd_volatile(codec, reg) &&
431 msm8x10_wcd_readable(codec, reg) &&
432 reg < codec->driver->reg_cache_size) {
433 ret = snd_soc_cache_read(codec, reg, &val);
434 if (ret >= 0) {
435 return val;
436 } else
437 dev_err(codec->dev, "Cache read from %x failed: %d\n",
438 reg, ret);
439 }
440
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800441 ret = msm8x10_wcd_reg_read(codec->control_data, reg, &val);
Kuirong Wang265f3592012-12-05 16:17:41 -0800442 return val;
443}
444
445
446static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
447 struct msm8x10_wcd_regulator *vreg, const char *vreg_name)
448{
449 int len, ret = 0;
450 const __be32 *prop;
451 char prop_name[CODEC_DT_MAX_PROP_SIZE];
452 struct device_node *regnode = NULL;
453 u32 prop_val;
454
455 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
456 vreg_name);
457 regnode = of_parse_phandle(dev->of_node, prop_name, 0);
458
459 if (!regnode) {
Kuirong Wang91e52532013-03-31 14:24:22 -0700460 dev_err(dev, "Looking up %s property in node %s failed\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800461 prop_name, dev->of_node->full_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800462 return -ENODEV;
463 }
Kuirong Wang91e52532013-03-31 14:24:22 -0700464
465 dev_dbg(dev, "Looking up %s property in node %s\n",
466 prop_name, dev->of_node->full_name);
467
Kuirong Wang265f3592012-12-05 16:17:41 -0800468 vreg->name = vreg_name;
469
470 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
471 "qcom,%s-voltage", vreg_name);
472 prop = of_get_property(dev->of_node, prop_name, &len);
473
474 if (!prop || (len != (2 * sizeof(__be32)))) {
475 dev_err(dev, "%s %s property\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800476 prop ? "invalid format" : "no", prop_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800477 return -ENODEV;
478 } else {
479 vreg->min_uV = be32_to_cpup(&prop[0]);
480 vreg->max_uV = be32_to_cpup(&prop[1]);
481 }
482
483 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800484 "qcom,%s-current", vreg_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800485
486 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
487 if (ret) {
488 dev_err(dev, "Looking up %s property in node %s failed",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800489 prop_name, dev->of_node->full_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800490 return -ENODEV;
491 }
492 vreg->optimum_uA = prop_val;
493
494 dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA\n", vreg->name,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800495 vreg->min_uV, vreg->max_uV, vreg->optimum_uA);
Kuirong Wang265f3592012-12-05 16:17:41 -0800496 return 0;
497}
498
499static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
500 struct msm8x10_wcd_micbias_setting *micbias)
501{
502 int ret = 0;
503 char prop_name[CODEC_DT_MAX_PROP_SIZE];
504 u32 prop_val;
505
506 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700507 "qcom,cdc-micbias-cfilt-mv");
Kuirong Wang265f3592012-12-05 16:17:41 -0800508 ret = of_property_read_u32(dev->of_node, prop_name,
509 &micbias->cfilt1_mv);
510 if (ret) {
511 dev_err(dev, "Looking up %s property in node %s failed",
512 prop_name, dev->of_node->full_name);
513 return -ENODEV;
514 }
515
516 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700517 "qcom,cdc-micbias-cfilt-sel");
Kuirong Wang265f3592012-12-05 16:17:41 -0800518 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
519 if (ret) {
520 dev_err(dev, "Looking up %s property in node %s failed",
521 prop_name, dev->of_node->full_name);
522 return -ENODEV;
523 }
524 micbias->bias1_cfilt_sel = (u8)prop_val;
525
526 /* micbias external cap */
527 micbias->bias1_cap_mode =
528 (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
529 MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
530
531 dev_dbg(dev, "ldoh_v %u cfilt1_mv %u\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800532 (u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
Kuirong Wang265f3592012-12-05 16:17:41 -0800533 dev_dbg(dev, "bias1_cfilt_sel %u\n", (u32)micbias->bias1_cfilt_sel);
534 dev_dbg(dev, "bias1_ext_cap %d\n", micbias->bias1_cap_mode);
535
536 return 0;
537}
538
539static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
540 struct device *dev)
541{
542 struct msm8x10_wcd_pdata *pdata;
543 int ret, i;
544 char **codec_supplies;
545 u32 num_of_supplies = 0;
546
547 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
548 if (!pdata) {
549 dev_err(dev, "could not allocate memory for platform data\n");
550 return NULL;
551 }
552 if ((!strcmp(dev_name(dev), MSM8X10_WCD_I2C_GSBI_SLAVE_ID))) {
553 codec_supplies = msm8x10_wcd_supplies;
554 num_of_supplies = ARRAY_SIZE(msm8x10_wcd_supplies);
555 } else {
556 dev_err(dev, "%s unsupported device %s\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800557 __func__, dev_name(dev));
Kuirong Wang265f3592012-12-05 16:17:41 -0800558 goto err;
559 }
560
561 if (num_of_supplies > ARRAY_SIZE(pdata->regulator)) {
562 dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800563 __func__, num_of_supplies,
564 ARRAY_SIZE(pdata->regulator));
Kuirong Wang265f3592012-12-05 16:17:41 -0800565
566 goto err;
567 }
568
569 for (i = 0; i < num_of_supplies; i++) {
570 ret = msm8x10_wcd_dt_parse_vreg_info(dev, &pdata->regulator[i],
571 codec_supplies[i]);
572 if (ret)
573 goto err;
574 }
Kuirong Wang265f3592012-12-05 16:17:41 -0800575 ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
576 if (ret)
577 goto err;
Kuirong Wang265f3592012-12-05 16:17:41 -0800578 return pdata;
579err:
580 devm_kfree(dev, pdata);
Kuirong Wang91e52532013-03-31 14:24:22 -0700581 dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
582 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -0800583 return NULL;
584}
585
586static int msm8x10_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
587 struct snd_kcontrol *kcontrol, int event)
588{
589 struct snd_soc_codec *codec = w->codec;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800590 dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -0800591
Kuirong Wang265f3592012-12-05 16:17:41 -0800592 switch (event) {
593 case SND_SOC_DAPM_POST_PMU:
594 /* Enable charge pump clock*/
595 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
596 0x01, 0x01);
597 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLSG_CTL,
598 0x08, 0x08);
599 usleep_range(200, 300);
600 snd_soc_update_bits(codec, MSM8X10_WCD_A_CP_STATIC,
601 0x10, 0x00);
602 break;
603 case SND_SOC_DAPM_PRE_PMD:
604 snd_soc_update_bits(codec,
605 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
606 0x01, 0x01);
607 usleep_range(20, 100);
608 snd_soc_update_bits(codec,
609 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x08);
610 snd_soc_update_bits(codec,
611 MSM8X10_WCD_A_CP_STATIC, 0x10, 0x10);
612 snd_soc_update_bits(codec,
613 MSM8X10_WCD_A_CDC_CLSG_CTL, 0x08, 0x00);
614 snd_soc_update_bits(codec,
615 MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
616 0x00);
617 snd_soc_update_bits(codec,
Kuirong Wang91e52532013-03-31 14:24:22 -0700618 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
619 0x01, 0x01);
620 snd_soc_update_bits(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800621 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
622 break;
623 }
624 return 0;
625}
626
627static int msm8x10_wcd_pa_gain_get(struct snd_kcontrol *kcontrol,
628 struct snd_ctl_elem_value *ucontrol)
629{
630 u8 ear_pa_gain;
631 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
632
633 ear_pa_gain = snd_soc_read(codec, MSM8X10_WCD_A_RX_EAR_GAIN);
634
635 ear_pa_gain = ear_pa_gain >> 5;
636
637 if (ear_pa_gain == 0x00) {
638 ucontrol->value.integer.value[0] = 0;
639 } else if (ear_pa_gain == 0x04) {
640 ucontrol->value.integer.value[0] = 1;
641 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800642 dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
643 __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800644 return -EINVAL;
645 }
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800646 dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800647 return 0;
648}
649
650static int msm8x10_wcd_pa_gain_put(struct snd_kcontrol *kcontrol,
651 struct snd_ctl_elem_value *ucontrol)
652{
653 u8 ear_pa_gain;
654 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
655
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800656 dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
657 __func__, ucontrol->value.integer.value[0]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800658
659 switch (ucontrol->value.integer.value[0]) {
660 case 0:
661 ear_pa_gain = 0x00;
662 break;
663 case 1:
664 ear_pa_gain = 0x80;
665 break;
666 default:
667 return -EINVAL;
668 }
669
670 snd_soc_update_bits(codec, MSM8X10_WCD_A_RX_EAR_GAIN,
671 0xE0, ear_pa_gain);
672 return 0;
673}
674
675static int msm8x10_wcd_get_iir_enable_audio_mixer(
676 struct snd_kcontrol *kcontrol,
677 struct snd_ctl_elem_value *ucontrol)
678{
679 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
680 int iir_idx = ((struct soc_multi_mixer_control *)
681 kcontrol->private_value)->reg;
682 int band_idx = ((struct soc_multi_mixer_control *)
683 kcontrol->private_value)->shift;
684
685 ucontrol->value.integer.value[0] =
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700686 (snd_soc_read(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800687 (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700688 (1 << band_idx)) != 0;
Kuirong Wang265f3592012-12-05 16:17:41 -0800689
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800690 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -0800691 iir_idx, band_idx,
692 (uint32_t)ucontrol->value.integer.value[0]);
693 return 0;
694}
695
696static int msm8x10_wcd_put_iir_enable_audio_mixer(
697 struct snd_kcontrol *kcontrol,
698 struct snd_ctl_elem_value *ucontrol)
699{
700 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
701 int iir_idx = ((struct soc_multi_mixer_control *)
702 kcontrol->private_value)->reg;
703 int band_idx = ((struct soc_multi_mixer_control *)
704 kcontrol->private_value)->shift;
705 int value = ucontrol->value.integer.value[0];
706
707 /* Mask first 5 bits, 6-8 are reserved */
708 snd_soc_update_bits(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx),
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800709 (1 << band_idx), (value << band_idx));
Kuirong Wang265f3592012-12-05 16:17:41 -0800710
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800711 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700712 iir_idx, band_idx,
713 ((snd_soc_read(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
714 (1 << band_idx)) != 0));
715
Kuirong Wang265f3592012-12-05 16:17:41 -0800716 return 0;
717}
718static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800719 int iir_idx, int band_idx,
720 int coeff_idx)
Kuirong Wang265f3592012-12-05 16:17:41 -0800721{
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700722 uint32_t value = 0;
723
Kuirong Wang265f3592012-12-05 16:17:41 -0800724 /* Address does not automatically update if reading */
725 snd_soc_write(codec,
726 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700727 ((band_idx * BAND_MAX + coeff_idx)
728 * sizeof(uint32_t)) & 0x7F);
729
730 value |= snd_soc_read(codec,
731 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx));
732
733 snd_soc_write(codec,
734 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
735 ((band_idx * BAND_MAX + coeff_idx)
736 * sizeof(uint32_t) + 1) & 0x7F);
737
738 value |= (snd_soc_read(codec,
739 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
740
741 snd_soc_write(codec,
742 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
743 ((band_idx * BAND_MAX + coeff_idx)
744 * sizeof(uint32_t) + 2) & 0x7F);
745
746 value |= (snd_soc_read(codec,
747 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
748
749 snd_soc_write(codec,
750 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
751 ((band_idx * BAND_MAX + coeff_idx)
752 * sizeof(uint32_t) + 3) & 0x7F);
Kuirong Wang265f3592012-12-05 16:17:41 -0800753
754 /* Mask bits top 2 bits since they are reserved */
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700755 value |= ((snd_soc_read(codec,
756 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) & 0x3f) << 24);
757
758 return value;
759
Kuirong Wang265f3592012-12-05 16:17:41 -0800760}
761
762static int msm8x10_wcd_get_iir_band_audio_mixer(
763 struct snd_kcontrol *kcontrol,
764 struct snd_ctl_elem_value *ucontrol)
765{
766 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
767 int iir_idx = ((struct soc_multi_mixer_control *)
768 kcontrol->private_value)->reg;
769 int band_idx = ((struct soc_multi_mixer_control *)
770 kcontrol->private_value)->shift;
771
772 ucontrol->value.integer.value[0] =
773 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
774 ucontrol->value.integer.value[1] =
775 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
776 ucontrol->value.integer.value[2] =
777 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
778 ucontrol->value.integer.value[3] =
779 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
780 ucontrol->value.integer.value[4] =
781 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
782
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800783 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -0800784 "%s: IIR #%d band #%d b1 = 0x%x\n"
785 "%s: IIR #%d band #%d b2 = 0x%x\n"
786 "%s: IIR #%d band #%d a1 = 0x%x\n"
787 "%s: IIR #%d band #%d a2 = 0x%x\n",
788 __func__, iir_idx, band_idx,
789 (uint32_t)ucontrol->value.integer.value[0],
790 __func__, iir_idx, band_idx,
791 (uint32_t)ucontrol->value.integer.value[1],
792 __func__, iir_idx, band_idx,
793 (uint32_t)ucontrol->value.integer.value[2],
794 __func__, iir_idx, band_idx,
795 (uint32_t)ucontrol->value.integer.value[3],
796 __func__, iir_idx, band_idx,
797 (uint32_t)ucontrol->value.integer.value[4]);
798 return 0;
799}
800
801static void set_iir_band_coeff(struct snd_soc_codec *codec,
802 int iir_idx, int band_idx,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700803 uint32_t value)
Kuirong Wang265f3592012-12-05 16:17:41 -0800804{
Kuirong Wang265f3592012-12-05 16:17:41 -0800805 snd_soc_write(codec,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700806 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
807 (value & 0xFF));
808
809 snd_soc_write(codec,
810 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
811 (value >> 8) & 0xFF);
812
813 snd_soc_write(codec,
814 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
815 (value >> 16) & 0xFF);
Kuirong Wang265f3592012-12-05 16:17:41 -0800816
817 /* Mask top 2 bits, 7-8 are reserved */
818 snd_soc_write(codec,
819 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
820 (value >> 24) & 0x3F);
821
822}
823
824static int msm8x10_wcd_put_iir_band_audio_mixer(
825 struct snd_kcontrol *kcontrol,
826 struct snd_ctl_elem_value *ucontrol)
827{
828 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
829 int iir_idx = ((struct soc_multi_mixer_control *)
830 kcontrol->private_value)->reg;
831 int band_idx = ((struct soc_multi_mixer_control *)
832 kcontrol->private_value)->shift;
833
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700834 /* Mask top bit it is reserved */
835 /* Updates addr automatically for each B2 write */
836 snd_soc_write(codec,
837 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
838 (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
839
840
841 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800842 ucontrol->value.integer.value[0]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700843 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800844 ucontrol->value.integer.value[1]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700845 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800846 ucontrol->value.integer.value[2]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700847 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800848 ucontrol->value.integer.value[3]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700849 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800850 ucontrol->value.integer.value[4]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800851
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800852 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -0800853 "%s: IIR #%d band #%d b1 = 0x%x\n"
854 "%s: IIR #%d band #%d b2 = 0x%x\n"
855 "%s: IIR #%d band #%d a1 = 0x%x\n"
856 "%s: IIR #%d band #%d a2 = 0x%x\n",
857 __func__, iir_idx, band_idx,
858 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
859 __func__, iir_idx, band_idx,
860 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
861 __func__, iir_idx, band_idx,
862 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
863 __func__, iir_idx, band_idx,
864 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
865 __func__, iir_idx, band_idx,
866 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
867 return 0;
868}
869
870static const char * const msm8x10_wcd_ear_pa_gain_text[] = {
871 "POS_6_DB", "POS_2_DB"};
872static const struct soc_enum msm8x10_wcd_ear_pa_gain_enum[] = {
873 SOC_ENUM_SINGLE_EXT(2, msm8x10_wcd_ear_pa_gain_text),
874};
875
876/*cut of frequency for high pass filter*/
877static const char * const cf_text[] = {
878 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
879};
880
881static const struct soc_enum cf_dec1_enum =
882 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
883
884static const struct soc_enum cf_dec2_enum =
885 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
886
887static const struct soc_enum cf_rxmix1_enum =
888 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
889
890static const struct soc_enum cf_rxmix2_enum =
891 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
892
893static const struct soc_enum cf_rxmix3_enum =
894 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
895
896static const struct snd_kcontrol_new msm8x10_wcd_snd_controls[] = {
897
898 SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
899 msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
900
Kuirong Wang91e52532013-03-31 14:24:22 -0700901 SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
Kuirong Wang265f3592012-12-05 16:17:41 -0800902 0, 12, 1, line_gain),
903
904 SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
905 0, 12, 1, line_gain),
906 SOC_SINGLE_TLV("HPHR Volume", MSM8X10_WCD_A_RX_HPH_R_GAIN,
907 0, 12, 1, line_gain),
908
909 SOC_SINGLE_S8_TLV("RX1 Digital Volume",
910 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
911 -84, 40, digital_gain),
912 SOC_SINGLE_S8_TLV("RX2 Digital Volume",
913 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
914 -84, 40, digital_gain),
915 SOC_SINGLE_S8_TLV("RX3 Digital Volume",
916 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
917 -84, 40, digital_gain),
918
919 SOC_SINGLE_S8_TLV("DEC1 Volume",
920 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
921 -84, 40, digital_gain),
922 SOC_SINGLE_S8_TLV("DEC2 Volume",
923 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
924 -84, 40, digital_gain),
925
926 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
927 MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL,
928 -84, 40, digital_gain),
929 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
930 MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL,
931 -84, 40, digital_gain),
932 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
933 MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL,
934 -84, 40, digital_gain),
935 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume",
936 MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
937 -84, 40, digital_gain),
938
939 SOC_SINGLE("MICBIAS1 CAPLESS Switch",
940 MSM8X10_WCD_A_MICB_1_CTL, 4, 1, 1),
941
942 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
943 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
944
945 SOC_SINGLE("TX1 HPF Switch", MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 3, 1, 0),
946 SOC_SINGLE("TX2 HPF Switch", MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 3, 1, 0),
947
948 SOC_SINGLE("RX1 HPF Switch", MSM8X10_WCD_A_CDC_RX1_B5_CTL, 2, 1, 0),
949 SOC_SINGLE("RX2 HPF Switch", MSM8X10_WCD_A_CDC_RX2_B5_CTL, 2, 1, 0),
950 SOC_SINGLE("RX3 HPF Switch", MSM8X10_WCD_A_CDC_RX3_B5_CTL, 2, 1, 0),
951
952 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
953 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
954 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
955
956 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
957 msm8x10_wcd_get_iir_enable_audio_mixer,
958 msm8x10_wcd_put_iir_enable_audio_mixer),
959 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
960 msm8x10_wcd_get_iir_enable_audio_mixer,
961 msm8x10_wcd_put_iir_enable_audio_mixer),
962 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
963 msm8x10_wcd_get_iir_enable_audio_mixer,
964 msm8x10_wcd_put_iir_enable_audio_mixer),
965 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
966 msm8x10_wcd_get_iir_enable_audio_mixer,
967 msm8x10_wcd_put_iir_enable_audio_mixer),
968 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
969 msm8x10_wcd_get_iir_enable_audio_mixer,
970 msm8x10_wcd_put_iir_enable_audio_mixer),
971 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
972 msm8x10_wcd_get_iir_enable_audio_mixer,
973 msm8x10_wcd_put_iir_enable_audio_mixer),
974 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
975 msm8x10_wcd_get_iir_enable_audio_mixer,
976 msm8x10_wcd_put_iir_enable_audio_mixer),
977 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
978 msm8x10_wcd_get_iir_enable_audio_mixer,
979 msm8x10_wcd_put_iir_enable_audio_mixer),
980 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
981 msm8x10_wcd_get_iir_enable_audio_mixer,
982 msm8x10_wcd_put_iir_enable_audio_mixer),
983 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
984 msm8x10_wcd_get_iir_enable_audio_mixer,
985 msm8x10_wcd_put_iir_enable_audio_mixer),
986
987 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
988 msm8x10_wcd_get_iir_band_audio_mixer,
989 msm8x10_wcd_put_iir_band_audio_mixer),
990 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
991 msm8x10_wcd_get_iir_band_audio_mixer,
992 msm8x10_wcd_put_iir_band_audio_mixer),
993 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
994 msm8x10_wcd_get_iir_band_audio_mixer,
995 msm8x10_wcd_put_iir_band_audio_mixer),
996 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
997 msm8x10_wcd_get_iir_band_audio_mixer,
998 msm8x10_wcd_put_iir_band_audio_mixer),
999 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1000 msm8x10_wcd_get_iir_band_audio_mixer,
1001 msm8x10_wcd_put_iir_band_audio_mixer),
1002 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1003 msm8x10_wcd_get_iir_band_audio_mixer,
1004 msm8x10_wcd_put_iir_band_audio_mixer),
1005 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1006 msm8x10_wcd_get_iir_band_audio_mixer,
1007 msm8x10_wcd_put_iir_band_audio_mixer),
1008 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1009 msm8x10_wcd_get_iir_band_audio_mixer,
1010 msm8x10_wcd_put_iir_band_audio_mixer),
1011 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1012 msm8x10_wcd_get_iir_band_audio_mixer,
1013 msm8x10_wcd_put_iir_band_audio_mixer),
1014 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1015 msm8x10_wcd_get_iir_band_audio_mixer,
1016 msm8x10_wcd_put_iir_band_audio_mixer),
1017
1018};
1019
1020static const char * const rx_mix1_text[] = {
1021 "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
1022};
1023
1024static const char * const rx_mix2_text[] = {
1025 "ZERO", "IIR1", "IIR2"
1026};
1027
1028static const char * const dec_mux_text[] = {
1029 "ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
1030};
1031
Kuirong Wang265f3592012-12-05 16:17:41 -08001032static const char * const anc_mux_text[] = {
1033 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1034 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1035};
1036
1037static const char * const anc1_fb_mux_text[] = {
1038 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1039};
1040
1041static const char * const iir1_inp1_text[] = {
1042 "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
1043};
1044
1045static const struct soc_enum rx_mix1_inp1_chain_enum =
1046 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
1047
1048static const struct soc_enum rx_mix1_inp2_chain_enum =
1049 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text);
1050
1051static const struct soc_enum rx_mix1_inp3_chain_enum =
1052 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text);
1053
1054static const struct soc_enum rx2_mix1_inp1_chain_enum =
1055 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text);
1056
1057static const struct soc_enum rx2_mix1_inp2_chain_enum =
1058 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text);
1059
1060static const struct soc_enum rx3_mix1_inp1_chain_enum =
1061 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text);
1062
1063static const struct soc_enum rx3_mix1_inp2_chain_enum =
1064 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text);
1065
1066static const struct soc_enum rx1_mix2_inp1_chain_enum =
1067 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
1068
1069static const struct soc_enum rx2_mix2_inp1_chain_enum =
1070 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
1071
1072static const struct soc_enum dec1_mux_enum =
1073 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 0, 5, dec_mux_text);
1074
1075static const struct soc_enum dec2_mux_enum =
1076 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 3, 5, dec_mux_text);
1077
1078static const struct soc_enum iir1_inp1_mux_enum =
1079 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
1080 iir1_inp1_text);
1081
1082static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1083 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1084
1085static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1086 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1087
1088static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1089 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1090
1091static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1092 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1093
1094static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1095 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1096
1097static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1098 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1099
1100static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1101 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1102
1103static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1104 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1105
1106static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1107 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1108
1109static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
1110 struct snd_ctl_elem_value *ucontrol)
1111{
1112 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1113 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1114 struct snd_soc_codec *codec = w->codec;
1115 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1116 unsigned int dec_mux, decimator;
1117 char *dec_name = NULL;
1118 char *widget_name = NULL;
1119 char *temp;
1120 u16 tx_mux_ctl_reg;
1121 u8 adc_dmic_sel = 0x0;
1122 int ret = 0;
1123
1124 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1125 return -EINVAL;
1126
1127 dec_mux = ucontrol->value.enumerated.item[0];
1128
1129 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1130 if (!widget_name)
1131 return -ENOMEM;
1132 temp = widget_name;
1133
1134 dec_name = strsep(&widget_name, " ");
1135 widget_name = temp;
1136 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001137 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1138 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001139 ret = -EINVAL;
1140 goto out;
1141 }
1142
1143 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1144 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001145 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1146 __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001147 ret = -EINVAL;
1148 goto out;
1149 }
1150
1151 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1152 , __func__, w->name, decimator, dec_mux);
1153
1154 switch (decimator) {
1155 case 1:
1156 case 2:
Kuirong Wang265f3592012-12-05 16:17:41 -08001157 adc_dmic_sel = 0x0;
1158 break;
1159 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001160 dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
1161 __func__, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001162 ret = -EINVAL;
1163 goto out;
1164 }
1165
1166 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
1167
1168 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1169
1170 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1171
1172out:
1173 kfree(widget_name);
1174 return ret;
1175}
1176
1177#define MSM8X10_WCD_DEC_ENUM(xname, xenum) \
1178{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1179 .info = snd_soc_info_enum_double, \
1180 .get = snd_soc_dapm_get_enum_double, \
1181 .put = msm8x10_wcd_put_dec_enum, \
1182 .private_value = (unsigned long)&xenum }
1183
1184static const struct snd_kcontrol_new dec1_mux =
1185 MSM8X10_WCD_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1186
1187static const struct snd_kcontrol_new dec2_mux =
1188 MSM8X10_WCD_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1189
1190static const struct snd_kcontrol_new iir1_inp1_mux =
1191 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1192
1193static const struct snd_kcontrol_new dac1_switch[] = {
1194 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_EAR_EN, 5, 1, 0)
1195};
1196static const struct snd_kcontrol_new hphl_switch[] = {
1197 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1198};
1199
Kuirong Wang265f3592012-12-05 16:17:41 -08001200static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
1201 int enable)
1202{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001203 struct msm8x10_wcd_priv *wcd8x10 = snd_soc_codec_get_drvdata(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08001204
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001205 dev_dbg(codec->dev, "%s %d\n", __func__, enable);
Kuirong Wang265f3592012-12-05 16:17:41 -08001206
1207 if (enable) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001208 wcd8x10->adc_count++;
Kuirong Wang265f3592012-12-05 16:17:41 -08001209 snd_soc_update_bits(codec,
1210 MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1211 0x20, 0x20);
1212 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001213 wcd8x10->adc_count--;
1214 if (!wcd8x10->adc_count)
Kuirong Wang265f3592012-12-05 16:17:41 -08001215 snd_soc_update_bits(codec,
1216 MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1217 0x20, 0x0);
1218 }
1219}
1220
1221static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
1222 struct snd_kcontrol *kcontrol, int event)
1223{
1224 struct snd_soc_codec *codec = w->codec;
1225 u16 adc_reg;
1226 u8 init_bit_shift;
1227
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001228 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001229 adc_reg = MSM8X10_WCD_A_TX_1_2_TEST_CTL;
1230
1231 if (w->reg == MSM8X10_WCD_A_TX_1_EN)
1232 init_bit_shift = 7;
Kuirong Wang91e52532013-03-31 14:24:22 -07001233 else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
Kuirong Wang265f3592012-12-05 16:17:41 -08001234 init_bit_shift = 6;
1235 else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001236 dev_err(codec->dev, "%s: Error, invalid adc register\n",
1237 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001238 return -EINVAL;
1239 }
1240
1241 switch (event) {
1242 case SND_SOC_DAPM_PRE_PMU:
1243 msm8x10_wcd_codec_enable_adc_block(codec, 1);
1244 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1245 1 << init_bit_shift);
1246 break;
1247 case SND_SOC_DAPM_POST_PMU:
1248 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1249 break;
1250 case SND_SOC_DAPM_POST_PMD:
1251 msm8x10_wcd_codec_enable_adc_block(codec, 0);
1252 break;
1253 }
1254 return 0;
1255}
1256
1257static int msm8x10_wcd_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1258 struct snd_kcontrol *kcontrol, int event)
1259{
1260 struct snd_soc_codec *codec = w->codec;
1261 u16 lineout_gain_reg;
1262
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001263 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001264
1265 switch (w->shift) {
1266 case 0:
1267 lineout_gain_reg = MSM8X10_WCD_A_RX_LINE_1_GAIN;
1268 break;
1269 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001270 dev_err(codec->dev,
1271 "%s: Error, incorrect lineout register value\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001272 __func__);
1273 return -EINVAL;
1274 }
1275
1276 switch (event) {
1277 case SND_SOC_DAPM_PRE_PMU:
1278 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1279 break;
1280 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001281 dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
1282 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001283 usleep_range(16000, 16100);
1284 break;
1285 case SND_SOC_DAPM_POST_PMD:
1286 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1287 break;
1288 }
1289 return 0;
1290}
1291
1292static int msm8x10_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1293 struct snd_kcontrol *kcontrol, int event)
1294{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001295 dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001296 return 0;
1297}
1298
1299static int msm8x10_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1300 struct snd_kcontrol *kcontrol, int event)
1301{
1302 struct snd_soc_codec *codec = w->codec;
1303 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1304 u8 dmic_clk_en;
1305 u16 dmic_clk_reg;
1306 s32 *dmic_clk_cnt;
1307 unsigned int dmic;
1308 int ret;
1309
1310 ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
1311 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001312 dev_err(codec->dev,
1313 "%s: Invalid DMIC line on the codec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001314 return -EINVAL;
1315 }
1316
1317 switch (dmic) {
1318 case 1:
1319 case 2:
1320 dmic_clk_en = 0x01;
1321 dmic_clk_cnt = &(msm8x10_wcd->dmic_1_2_clk_cnt);
1322 dmic_clk_reg = MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001323 dev_dbg(codec->dev,
1324 "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001325 __func__, event, dmic, *dmic_clk_cnt);
1326 break;
1327 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001328 dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001329 return -EINVAL;
1330 }
1331
1332 switch (event) {
1333 case SND_SOC_DAPM_PRE_PMU:
1334
1335 (*dmic_clk_cnt)++;
1336 if (*dmic_clk_cnt == 1)
1337 snd_soc_update_bits(codec, dmic_clk_reg,
1338 dmic_clk_en, dmic_clk_en);
1339 break;
1340 case SND_SOC_DAPM_POST_PMD:
1341
1342 (*dmic_clk_cnt)--;
1343 if (*dmic_clk_cnt == 0)
1344 snd_soc_update_bits(codec, dmic_clk_reg,
1345 dmic_clk_en, 0);
1346 break;
1347 }
1348 return 0;
1349}
1350
1351static int msm8x10_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1352 struct snd_kcontrol *kcontrol, int event)
1353{
1354 struct snd_soc_codec *codec = w->codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08001355 u16 micb_int_reg;
Kuirong Wang265f3592012-12-05 16:17:41 -08001356 char *internal1_text = "Internal1";
1357 char *internal2_text = "Internal2";
1358 char *internal3_text = "Internal3";
Kuirong Wang265f3592012-12-05 16:17:41 -08001359
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001360 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001361 switch (w->reg) {
1362 case MSM8X10_WCD_A_MICB_1_CTL:
1363 micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
Kuirong Wang265f3592012-12-05 16:17:41 -08001364 break;
1365 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001366 dev_err(codec->dev,
Kuirong Wang91e52532013-03-31 14:24:22 -07001367 "%s: Error, invalid micbias register 0x%x\n",
1368 __func__, w->reg);
Kuirong Wang265f3592012-12-05 16:17:41 -08001369 return -EINVAL;
1370 }
1371
1372 switch (event) {
1373 case SND_SOC_DAPM_PRE_PMU:
Kuirong Wang265f3592012-12-05 16:17:41 -08001374 if (strnstr(w->name, internal1_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001375 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
Kuirong Wang265f3592012-12-05 16:17:41 -08001376 else if (strnstr(w->name, internal2_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001377 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08001378 else if (strnstr(w->name, internal3_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001379 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
Kuirong Wang265f3592012-12-05 16:17:41 -08001380 break;
1381 case SND_SOC_DAPM_POST_PMU:
1382 usleep_range(20000, 20100);
Kuirong Wang265f3592012-12-05 16:17:41 -08001383 break;
1384 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang265f3592012-12-05 16:17:41 -08001385 if (strnstr(w->name, internal1_text, 30))
1386 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1387 else if (strnstr(w->name, internal2_text, 30))
1388 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1389 else if (strnstr(w->name, internal3_text, 30))
1390 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1391
Kuirong Wang265f3592012-12-05 16:17:41 -08001392 break;
1393 }
Kuirong Wang265f3592012-12-05 16:17:41 -08001394 return 0;
1395}
1396
Kuirong Wang91e52532013-03-31 14:24:22 -07001397static void tx_hpf_corner_freq_callback(struct work_struct *work)
1398{
1399 struct delayed_work *hpf_delayed_work;
1400 struct hpf_work *hpf_work;
1401 struct msm8x10_wcd_priv *msm8x10_wcd;
1402 struct snd_soc_codec *codec;
1403 u16 tx_mux_ctl_reg;
1404 u8 hpf_cut_of_freq;
1405
1406 hpf_delayed_work = to_delayed_work(work);
1407 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
1408 msm8x10_wcd = hpf_work->msm8x10_wcd;
1409 codec = hpf_work->msm8x10_wcd->codec;
1410 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
1411
1412 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1413 (hpf_work->decimator - 1) * 32;
1414
1415 dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
1416 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
1417
1418 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
1419}
1420
1421
Kuirong Wang265f3592012-12-05 16:17:41 -08001422#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
1423#define CF_MIN_3DB_4HZ 0x0
1424#define CF_MIN_3DB_75HZ 0x1
1425#define CF_MIN_3DB_150HZ 0x2
1426
1427static int msm8x10_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
1428 struct snd_kcontrol *kcontrol, int event)
1429{
1430 struct snd_soc_codec *codec = w->codec;
1431 unsigned int decimator;
1432 char *dec_name = NULL;
1433 char *widget_name = NULL;
1434 char *temp;
1435 int ret = 0;
1436 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
1437 u8 dec_hpf_cut_of_freq;
1438 int offset;
1439
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001440 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001441
1442 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1443 if (!widget_name)
1444 return -ENOMEM;
1445 temp = widget_name;
1446
1447 dec_name = strsep(&widget_name, " ");
1448 widget_name = temp;
1449 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001450 dev_err(codec->dev,
1451 "%s: Invalid decimator = %s\n", __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001452 ret = -EINVAL;
1453 goto out;
1454 }
1455
1456 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1457 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001458 dev_err(codec->dev,
1459 "%s: Invalid decimator = %s\n", __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001460 ret = -EINVAL;
1461 goto out;
1462 }
1463
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001464 dev_dbg(codec->dev,
1465 "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
1466 w->name, dec_name, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001467
1468 if (w->reg == MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
1469 dec_reset_reg = MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
1470 offset = 0;
1471 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001472 dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001473 ret = -EINVAL;
1474 goto out;
1475 }
1476
1477 tx_vol_ctl_reg = MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG +
1478 32 * (decimator - 1);
1479 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1480 32 * (decimator - 1);
1481
1482 switch (event) {
1483 case SND_SOC_DAPM_PRE_PMU:
1484 /* Enableable TX digital mute */
1485 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1486
1487 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1488 1 << w->shift);
1489 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1490
1491 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
1492
1493 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
1494
1495 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
1496 dec_hpf_cut_of_freq;
1497
1498 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
1499
1500 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
1501 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1502 CF_MIN_3DB_150HZ << 4);
1503 }
1504
1505 /* enable HPF */
1506 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
1507 break;
1508 case SND_SOC_DAPM_POST_PMU:
1509 /* Disable TX digital mute */
1510 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
1511
1512 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
1513 CF_MIN_3DB_150HZ) {
1514
1515 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
1516 msecs_to_jiffies(300));
1517 }
1518 /* apply the digital gain after the decimator is enabled*/
1519 if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
1520 snd_soc_write(codec,
1521 tx_digital_gain_reg[w->shift + offset],
1522 snd_soc_read(codec,
1523 tx_digital_gain_reg[w->shift + offset])
1524 );
1525 break;
1526 case SND_SOC_DAPM_PRE_PMD:
1527 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1528 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
1529 break;
1530 case SND_SOC_DAPM_POST_PMD:
1531 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
1532 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1533 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
1534 break;
1535 }
1536out:
1537 kfree(widget_name);
1538 return ret;
1539}
1540
1541static int msm8x10_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001542 struct snd_kcontrol *kcontrol,
1543 int event)
Kuirong Wang265f3592012-12-05 16:17:41 -08001544{
1545 struct snd_soc_codec *codec = w->codec;
1546
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001547 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001548
1549 switch (event) {
1550 case SND_SOC_DAPM_PRE_PMU:
1551 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1552 1 << w->shift, 1 << w->shift);
1553 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1554 1 << w->shift, 0x0);
1555 break;
1556 case SND_SOC_DAPM_POST_PMU:
1557 /* apply the digital gain after the interpolator is enabled*/
1558 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
1559 snd_soc_write(codec,
1560 rx_digital_gain_reg[w->shift],
1561 snd_soc_read(codec,
1562 rx_digital_gain_reg[w->shift])
1563 );
1564 break;
1565 }
1566 return 0;
1567}
1568
1569
1570/* The register address is the same as other codec so it can use resmgr */
1571static int msm8x10_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1572 struct snd_kcontrol *kcontrol, int event)
1573{
1574 struct snd_soc_codec *codec = w->codec;
1575 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Kuirong Wang91e52532013-03-31 14:24:22 -07001576 msm8x10_wcd->resmgr.codec = codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08001577
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001578 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001579
1580 switch (event) {
1581 case SND_SOC_DAPM_PRE_PMU:
1582 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 1);
1583 break;
1584 case SND_SOC_DAPM_POST_PMD:
1585 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 0);
1586 break;
1587 }
1588 return 0;
1589}
1590
1591static int msm8x10_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
1592 struct snd_kcontrol *kcontrol, int event)
1593{
1594 struct snd_soc_codec *codec = w->codec;
1595
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001596 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001597
1598 switch (event) {
1599 case SND_SOC_DAPM_PRE_PMU:
1600 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1601 break;
1602 case SND_SOC_DAPM_POST_PMD:
1603 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1604 break;
1605 }
1606 return 0;
1607}
1608
1609static int msm8x10_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
1610 struct snd_kcontrol *kcontrol, int event)
1611{
1612 struct snd_soc_codec *codec = w->codec;
1613 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1614 enum wcd9xxx_notify_event e_pre_on, e_post_off;
1615
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001616 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001617 if (w->shift == 5) {
1618 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
1619 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
1620 } else if (w->shift == 4) {
1621 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
1622 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
1623 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001624 dev_err(codec->dev,
1625 "%s: Invalid w->shift %d\n", __func__, w->shift);
Kuirong Wang265f3592012-12-05 16:17:41 -08001626 return -EINVAL;
1627 }
1628
1629 switch (event) {
1630 case SND_SOC_DAPM_PRE_PMU:
1631 /* Let MBHC module know PA is turning on */
1632 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
1633 break;
1634
1635 case SND_SOC_DAPM_POST_PMU:
1636 usleep_range(10000, 10100);
1637 break;
1638
1639 case SND_SOC_DAPM_POST_PMD:
1640 /* Let MBHC module know PA turned off */
1641 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
1642
1643 /*
1644 * schedule work is required because at the time HPH PA DAPM
1645 * event callback is called by DAPM framework, CODEC dapm mutex
1646 * would have been locked while snd_soc_jack_report also
1647 * attempts to acquire same lock.
1648 */
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001649 dev_dbg(codec->dev,
1650 "%s: sleep 10 ms after %s PA disable.\n", __func__,
1651 w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001652 usleep_range(10000, 10100);
1653 break;
1654 }
1655 return 0;
1656}
1657
1658static int msm8x10_wcd_lineout_dac_event(struct snd_soc_dapm_widget *w,
1659 struct snd_kcontrol *kcontrol, int event)
1660{
1661 struct snd_soc_codec *codec = w->codec;
1662
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001663 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001664
1665 switch (event) {
1666 case SND_SOC_DAPM_PRE_PMU:
1667 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1668 break;
1669
1670 case SND_SOC_DAPM_POST_PMD:
1671 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1672 break;
1673 }
1674 return 0;
1675}
1676
1677static int msm8x10_wcd_spk_dac_event(struct snd_soc_dapm_widget *w,
1678 struct snd_kcontrol *kcontrol, int event)
1679{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001680 dev_dbg(w->codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001681 return 0;
1682}
1683
1684static const struct snd_soc_dapm_route audio_map[] = {
1685 {"RX_I2S_CLK", NULL, "CDC_CONN"},
1686 {"I2S RX1", NULL, "RX_I2S_CLK"},
1687 {"I2S RX2", NULL, "RX_I2S_CLK"},
1688 {"I2S RX3", NULL, "RX_I2S_CLK"},
1689
1690 {"I2S TX1", NULL, "TX_I2S_CLK"},
1691 {"I2S TX2", NULL, "TX_I2S_CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001692
Kuirong Wang91e52532013-03-31 14:24:22 -07001693 {"DEC1 MUX", NULL, "TX CLK"},
1694 {"DEC2 MUX", NULL, "TX CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001695
Kuirong Wang91e52532013-03-31 14:24:22 -07001696 {"I2S TX1", NULL, "DEC1 MUX"},
1697 {"I2S TX2", NULL, "DEC2 MUX"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001698
1699 /* Earpiece (RX MIX1) */
1700 {"EAR", NULL, "EAR PA"},
1701 {"EAR PA", NULL, "DAC1"},
1702 {"DAC1", NULL, "CP"},
1703
1704 /* Headset (RX MIX1 and RX MIX2) */
1705 {"HEADPHONE", NULL, "HPHL"},
1706 {"HEADPHONE", NULL, "HPHR"},
1707
1708 {"HPHL", NULL, "HPHL DAC"},
1709
1710 {"HPHR", NULL, "HPHR DAC"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001711
1712 {"HPHL DAC", NULL, "CP"},
1713
1714 {"HPHR DAC", NULL, "CP"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001715 {"SPK DAC", NULL, "CP"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001716
1717 {"DAC1", "Switch", "RX1 CHAIN"},
1718 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1719 {"HPHR DAC", NULL, "RX2 CHAIN"},
1720
Kuirong Wang91e52532013-03-31 14:24:22 -07001721 {"LINEOUT", NULL, "LINEOUT PA"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001722 {"SPK_OUT", NULL, "SPK PA"},
1723
Kuirong Wang91e52532013-03-31 14:24:22 -07001724 {"LINEOUT PA", NULL, "CP"},
1725 {"LINEOUT PA", NULL, "LINEOUT DAC"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001726
Kuirong Wang91e52532013-03-31 14:24:22 -07001727 {"CP", NULL, "RX_BIAS"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001728 {"SPK PA", NULL, "SPK DAC"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001729 {"SPK DAC", NULL, "RX3 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001730
Kuirong Wang91e52532013-03-31 14:24:22 -07001731 {"RX1 CHAIN", NULL, "RX1 CLK"},
1732 {"RX2 CHAIN", NULL, "RX2 CLK"},
1733 {"RX3 CHAIN", NULL, "RX3 CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001734 {"RX1 CHAIN", NULL, "RX1 MIX2"},
1735 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001736 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001737
1738 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1739 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1740 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
1741 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1742 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
1743 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1744 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1745 {"RX1 MIX2", NULL, "RX1 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001746 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001747 {"RX2 MIX2", NULL, "RX2 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001748 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001749
1750 {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
1751 {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
1752 {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
1753 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1754 {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
1755 {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
1756 {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
1757 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1758 {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
1759 {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
1760 {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
1761
1762 {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
1763 {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
1764 {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
1765 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
1766 {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
1767 {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
1768 {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
1769 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
1770
1771 {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
1772 {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
1773 {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
1774 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
1775 {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
1776 {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
1777 {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
1778 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
1779
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001780 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
1781 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
1782
Kuirong Wang265f3592012-12-05 16:17:41 -08001783 /* Decimator Inputs */
1784 {"DEC1 MUX", "DMIC1", "DMIC1"},
1785 {"DEC1 MUX", "DMIC2", "DMIC2"},
1786 {"DEC1 MUX", "ADC1", "ADC1"},
1787 {"DEC1 MUX", "ADC2", "ADC2"},
1788 {"DEC1 MUX", NULL, "CDC_CONN"},
1789
1790 {"DEC2 MUX", "DMIC1", "DMIC1"},
1791 {"DEC2 MUX", "DMIC2", "DMIC2"},
1792 {"DEC2 MUX", "ADC1", "ADC1"},
1793 {"DEC2 MUX", "ADC2", "ADC2"},
1794 {"DEC2 MUX", NULL, "CDC_CONN"},
1795
1796 /* ADC Connections */
1797 {"ADC1", NULL, "AMIC1"},
1798 {"ADC2", NULL, "AMIC2"},
1799
1800 {"IIR1", NULL, "IIR1 INP1 MUX"},
1801 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
1802 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001803 {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
1804 {"MIC BIAS External", NULL, "INT_LDO_H"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001805};
1806
Kuirong Wang265f3592012-12-05 16:17:41 -08001807static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
1808 struct snd_soc_dai *dai)
1809{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001810 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
1811 __func__,
1812 substream->name, substream->stream);
Kuirong Wang265f3592012-12-05 16:17:41 -08001813 return 0;
1814}
1815
1816static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
1817 struct snd_soc_dai *dai)
1818{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001819 dev_dbg(dai->codec->dev,
1820 "%s(): substream = %s stream = %d\n" , __func__,
1821 substream->name, substream->stream);
Kuirong Wang91e52532013-03-31 14:24:22 -07001822}
1823
1824static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
1825 int enable)
1826{
1827 if (enable) {
1828 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
1829 0x01, 0x01);
1830 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
1831 0x03, 0x03);
1832 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
1833 0x0f, 0x0d);
1834 } else {
1835 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
1836 0x0f, 0x00);
Kuirong Wangf1ab8352013-05-20 12:22:37 -07001837 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
Kuirong Wang91e52532013-03-31 14:24:22 -07001838 0x03, 0x00);
Kuirong Wang265f3592012-12-05 16:17:41 -08001839 }
Kuirong Wang91e52532013-03-31 14:24:22 -07001840 return 0;
1841}
1842
1843static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
1844 *codec)
1845{
1846 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
1847 0x80);
1848 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
1849 0x04);
1850 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
1851 0x01);
1852 usleep_range(1000, 1000);
1853 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
1854 0x00);
1855}
1856
1857static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
1858 enum msm8x10_wcd_bandgap_type choice)
1859{
1860 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1861
1862 /* TODO lock resources accessed by audio streams and threaded
1863 * interrupt handlers
1864 */
1865
1866 dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
1867 __func__, choice,
1868 msm8x10_wcd->bandgap_type);
1869
1870 if (msm8x10_wcd->bandgap_type == choice)
1871 return;
1872
1873 if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
1874 (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
1875 msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
1876 } else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
1877 /* bandgap mode becomes fast,
1878 * mclk should be off or clk buff source souldn't be VBG
1879 * Let's turn off mclk always */
1880 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1881 0x2, 0x2);
1882 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1883 0x80, 0x80);
1884 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1885 0x4, 0x4);
1886 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1887 0x01, 0x01);
1888 usleep_range(1000, 1000);
1889 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1890 0x80, 0x00);
1891 } else if ((msm8x10_wcd->bandgap_type ==
1892 MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
1893 (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
1894 snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
1895 usleep_range(100, 100);
1896 msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
1897 } else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
1898 snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
1899 } else {
1900 dev_err(codec->dev,
1901 "%s: Error, Invalid bandgap settings\n", __func__);
1902 }
1903 msm8x10_wcd->bandgap_type = choice;
Kuirong Wang265f3592012-12-05 16:17:41 -08001904}
1905
1906int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
1907 int mclk_enable, bool dapm)
1908{
1909 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1910
Kuirong Wang91e52532013-03-31 14:24:22 -07001911 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
1912 __func__, mclk_enable, dapm);
1913 if (dapm)
1914 MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
Kuirong Wang265f3592012-12-05 16:17:41 -08001915 if (mclk_enable) {
Kuirong Wang91e52532013-03-31 14:24:22 -07001916 msm8x10_wcd->mclk_enabled = true;
1917 msm8x10_wcd_codec_enable_bandgap(codec,
1918 MSM8X10_WCD_BANDGAP_AUDIO_MODE);
1919 msm8x10_wcd_codec_enable_clock_block(codec, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -08001920 } else {
Kuirong Wang91e52532013-03-31 14:24:22 -07001921 if (!msm8x10_wcd->mclk_enabled) {
1922 if (dapm)
1923 MSM8X10_WCD_RELEASE_LOCK(
1924 msm8x10_wcd->codec_resource_lock);
1925 dev_err(codec->dev, "Error, MCLK already diabled\n");
1926 return -EINVAL;
1927 }
1928 msm8x10_wcd->mclk_enabled = false;
1929 msm8x10_wcd_codec_enable_clock_block(codec, 0);
1930 msm8x10_wcd_codec_enable_bandgap(codec,
1931 MSM8X10_WCD_BANDGAP_OFF);
Kuirong Wang265f3592012-12-05 16:17:41 -08001932 }
Kuirong Wang91e52532013-03-31 14:24:22 -07001933 if (dapm)
1934 MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
Kuirong Wang265f3592012-12-05 16:17:41 -08001935 return 0;
1936}
1937
1938static int msm8x10_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
1939 int clk_id, unsigned int freq, int dir)
1940{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001941 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001942 return 0;
1943}
1944
1945static int msm8x10_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1946{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001947 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001948 return 0;
1949}
1950
1951static int msm8x10_wcd_set_channel_map(struct snd_soc_dai *dai,
1952 unsigned int tx_num, unsigned int *tx_slot,
1953 unsigned int rx_num, unsigned int *rx_slot)
1954
1955{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001956 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001957 return 0;
1958}
1959
1960static int msm8x10_wcd_get_channel_map(struct snd_soc_dai *dai,
1961 unsigned int *tx_num, unsigned int *tx_slot,
1962 unsigned int *rx_num, unsigned int *rx_slot)
1963
1964{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001965 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001966 return 0;
1967}
1968
1969static int msm8x10_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
1970 u8 rx_fs_rate_reg_val, u32 sample_rate)
1971{
1972 return 0;
1973}
1974
1975static int msm8x10_wcd_set_decimator_rate(struct snd_soc_dai *dai,
1976 u8 tx_fs_rate_reg_val, u32 sample_rate)
1977{
1978 return 0;
1979}
1980
1981static int msm8x10_wcd_hw_params(struct snd_pcm_substream *substream,
1982 struct snd_pcm_hw_params *params,
1983 struct snd_soc_dai *dai)
1984{
1985 u8 tx_fs_rate, rx_fs_rate;
1986 int ret;
1987
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001988 dev_dbg(dai->codec->dev,
1989 "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08001990 dai->name, dai->id, params_rate(params),
1991 params_channels(params));
1992
1993 switch (params_rate(params)) {
1994 case 8000:
1995 tx_fs_rate = 0x00;
1996 rx_fs_rate = 0x00;
1997 break;
1998 case 16000:
1999 tx_fs_rate = 0x01;
2000 rx_fs_rate = 0x20;
2001 break;
2002 case 32000:
2003 tx_fs_rate = 0x02;
2004 rx_fs_rate = 0x40;
2005 break;
2006 case 48000:
2007 tx_fs_rate = 0x03;
2008 rx_fs_rate = 0x60;
2009 break;
2010 case 96000:
2011 tx_fs_rate = 0x04;
2012 rx_fs_rate = 0x80;
2013 break;
2014 case 192000:
2015 tx_fs_rate = 0x05;
2016 rx_fs_rate = 0xA0;
2017 break;
2018 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002019 dev_err(dai->codec->dev,
2020 "%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002021 params_rate(params));
2022 return -EINVAL;
2023 }
2024
2025 switch (substream->stream) {
2026 case SNDRV_PCM_STREAM_CAPTURE:
2027 ret = msm8x10_wcd_set_decimator_rate(dai, tx_fs_rate,
2028 params_rate(params));
2029 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002030 dev_err(dai->codec->dev,
2031 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002032 ret);
2033 return ret;
2034 }
2035 break;
2036 case SNDRV_PCM_STREAM_PLAYBACK:
2037 ret = msm8x10_wcd_set_interpolator_rate(dai, rx_fs_rate,
2038 params_rate(params));
2039 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002040 dev_err(dai->codec->dev,
2041 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002042 ret);
2043 return ret;
2044 }
2045 break;
2046 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002047 dev_err(dai->codec->dev,
2048 "%s: Invalid stream type %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002049 substream->stream);
2050 return -EINVAL;
2051 }
2052
2053 return 0;
2054}
2055
2056static struct snd_soc_dai_ops msm8x10_wcd_dai_ops = {
2057 .startup = msm8x10_wcd_startup,
2058 .shutdown = msm8x10_wcd_shutdown,
2059 .hw_params = msm8x10_wcd_hw_params,
2060 .set_sysclk = msm8x10_wcd_set_dai_sysclk,
2061 .set_fmt = msm8x10_wcd_set_dai_fmt,
2062 .set_channel_map = msm8x10_wcd_set_channel_map,
2063 .get_channel_map = msm8x10_wcd_get_channel_map,
2064};
2065
2066static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[] = {
2067 {
2068 .name = "msm8x10_wcd_i2s_rx1",
2069 .id = AIF1_PB,
2070 .playback = {
2071 .stream_name = "AIF1 Playback",
2072 .rates = MSM8X10_WCD_RATES,
2073 .formats = MSM8X10_WCD_FORMATS,
2074 .rate_max = 192000,
2075 .rate_min = 8000,
2076 .channels_min = 1,
Kuirong Wang91e52532013-03-31 14:24:22 -07002077 .channels_max = 3,
Kuirong Wang265f3592012-12-05 16:17:41 -08002078 },
2079 .ops = &msm8x10_wcd_dai_ops,
2080 },
2081 {
2082 .name = "msm8x10_wcd_i2s_tx1",
2083 .id = AIF1_CAP,
2084 .capture = {
2085 .stream_name = "AIF1 Capture",
2086 .rates = MSM8X10_WCD_RATES,
2087 .formats = MSM8X10_WCD_FORMATS,
2088 .rate_max = 192000,
2089 .rate_min = 8000,
2090 .channels_min = 1,
2091 .channels_max = 4,
2092 },
2093 .ops = &msm8x10_wcd_dai_ops,
2094 },
2095};
2096
2097static int msm8x10_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
2098 struct snd_kcontrol *kcontrol, int event)
2099{
2100 switch (event) {
2101 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002102 dev_dbg(w->codec->dev,
2103 "%s: Sleeping 20ms after enabling EAR PA\n",
2104 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002105 msleep(20);
2106 break;
2107 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002108 dev_dbg(w->codec->dev,
2109 "%s: Sleeping 20ms after disabling EAR PA\n",
2110 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002111 msleep(20);
2112 break;
2113 }
2114 return 0;
2115}
2116
2117static const struct snd_soc_dapm_widget msm8x10_wcd_dapm_widgets[] = {
2118 /*RX stuff */
2119 SND_SOC_DAPM_OUTPUT("EAR"),
2120
2121 SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
2122 msm8x10_wcd_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
2123
2124 SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
2125 ARRAY_SIZE(dac1_switch)),
2126
Kuirong Wang91e52532013-03-31 14:24:22 -07002127 SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002128
Kuirong Wang91e52532013-03-31 14:24:22 -07002129 SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002130
Kuirong Wang91e52532013-03-31 14:24:22 -07002131 SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002132
Kuirong Wang91e52532013-03-31 14:24:22 -07002133 SND_SOC_DAPM_SUPPLY("TX CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2134 4, 0, NULL, 0),
2135 SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
2136
Kuirong Wang265f3592012-12-05 16:17:41 -08002137 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2138 SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2139 5, 0, NULL, 0,
2140 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2141 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2142 SND_SOC_DAPM_MIXER("HPHL DAC", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL,
2143 7, 0,
2144 hphl_switch, ARRAY_SIZE(hphl_switch)),
2145
2146 SND_SOC_DAPM_PGA_E("HPHR", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2147 4, 0, NULL, 0,
2148 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2149 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2150
2151 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, MSM8X10_WCD_A_RX_HPH_R_DAC_CTL,
2152 7, 0,
2153 msm8x10_wcd_hphr_dac_event,
2154 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2155
2156 /* Speaker */
Kuirong Wang91e52532013-03-31 14:24:22 -07002157 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002158 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
2159
Kuirong Wang91e52532013-03-31 14:24:22 -07002160 SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
Kuirong Wang265f3592012-12-05 16:17:41 -08002161 0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
2162 SND_SOC_DAPM_PRE_PMU |
2163 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2164
2165 SND_SOC_DAPM_PGA_E("SPK PA", MSM8X10_WCD_A_SPKR_DRV_EN,
2166 7, 0 , NULL, 0, msm8x10_wcd_codec_enable_spk_pa,
2167 SND_SOC_DAPM_PRE_PMU |
2168 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2169
Kuirong Wang91e52532013-03-31 14:24:22 -07002170 SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
Kuirong Wang265f3592012-12-05 16:17:41 -08002171 MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
2172 msm8x10_wcd_lineout_dac_event,
2173 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2174
2175 SND_SOC_DAPM_DAC_E("SPK DAC", NULL, SND_SOC_NOPM, 0, 0,
2176 msm8x10_wcd_spk_dac_event,
2177 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2178
2179 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2180 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2181
2182 SND_SOC_DAPM_MIXER_E("RX1 MIX2",
2183 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
2184 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2185 SND_SOC_DAPM_POST_PMU),
2186 SND_SOC_DAPM_MIXER_E("RX2 MIX2",
2187 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
2188 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2189 SND_SOC_DAPM_POST_PMU),
2190 SND_SOC_DAPM_MIXER_E("RX3 MIX1",
2191 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
2192 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2193 SND_SOC_DAPM_POST_PMU),
2194
Kuirong Wang91e52532013-03-31 14:24:22 -07002195 SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2196 0, 0, NULL, 0),
2197 SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2198 1, 0, NULL, 0),
2199 SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2200 2, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002201 SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
2202 5, 0, NULL, 0),
2203 SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
2204 5, 0, NULL, 0),
Kuirong Wang91e52532013-03-31 14:24:22 -07002205 SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
2206 5, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002207
2208 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2209 &rx_mix1_inp1_mux),
2210 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2211 &rx_mix1_inp2_mux),
2212 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
2213 &rx_mix1_inp3_mux),
2214 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2215 &rx2_mix1_inp1_mux),
2216 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2217 &rx2_mix1_inp2_mux),
2218 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2219 &rx3_mix1_inp1_mux),
2220 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2221 &rx3_mix1_inp2_mux),
2222 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2223 &rx1_mix2_inp1_mux),
2224 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2225 &rx2_mix2_inp1_mux),
2226
2227 SND_SOC_DAPM_SUPPLY("CP", MSM8X10_WCD_A_CP_EN, 0, 0,
2228 msm8x10_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
2229 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
2230
2231 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2232 msm8x10_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2233 SND_SOC_DAPM_POST_PMD),
2234
2235 /* TX */
2236
2237 SND_SOC_DAPM_SUPPLY("CDC_CONN", MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
2238 2, 0, NULL, 0),
2239
2240
2241 SND_SOC_DAPM_INPUT("AMIC1"),
Kuirong Wang91e52532013-03-31 14:24:22 -07002242 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
Kuirong Wang265f3592012-12-05 16:17:41 -08002243 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2244 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2245 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002246 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
Kuirong Wang265f3592012-12-05 16:17:41 -08002247 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2248 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2249 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002250 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
Kuirong Wang265f3592012-12-05 16:17:41 -08002251 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2252 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2253 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2254 SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
2255 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2256 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002257 SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
Kuirong Wang265f3592012-12-05 16:17:41 -08002258 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2259 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2260
Kuirong Wang91e52532013-03-31 14:24:22 -07002261 SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
2262 7, 0),
2263
Kuirong Wang265f3592012-12-05 16:17:41 -08002264 SND_SOC_DAPM_INPUT("AMIC3"),
2265
2266 SND_SOC_DAPM_MUX_E("DEC1 MUX",
2267 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
2268 &dec1_mux, msm8x10_wcd_codec_enable_dec,
2269 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2270 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2271
2272 SND_SOC_DAPM_MUX_E("DEC2 MUX",
2273 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
2274 &dec2_mux, msm8x10_wcd_codec_enable_dec,
2275 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2276 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2277
2278 SND_SOC_DAPM_INPUT("AMIC2"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002279
Kuirong Wang91e52532013-03-31 14:24:22 -07002280 SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
2281 0, 0),
2282 SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
2283 0, 0),
2284 SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
2285 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002286
2287 /* Digital Mic Inputs */
2288 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2289 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2290 SND_SOC_DAPM_POST_PMD),
2291
2292 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2293 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2294 SND_SOC_DAPM_POST_PMD),
2295
2296 /* Sidetone */
2297 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2298 SND_SOC_DAPM_PGA("IIR1", MSM8X10_WCD_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2299
2300 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL,
2301 4, 0, NULL, 0),
2302 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL, 4,
2303 0, NULL, 0),
2304};
2305
2306static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
2307
2308 /* set MCLk to 9.6 */
Kuirong Wang91e52532013-03-31 14:24:22 -07002309 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
Kuirong Wang265f3592012-12-05 16:17:41 -08002310
2311 /* EAR PA deafults */
2312 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
2313
2314 /* RX deafults */
2315 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B5_CTL, 0x78),
2316 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B5_CTL, 0x78),
2317 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B5_CTL, 0x78),
2318
2319 /* RX1 and RX2 defaults */
2320 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xA0),
2321 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xA0),
2322
2323 /* RX3 to RX7 defaults */
2324 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B6_CTL, 0x80),
2325
2326 /* Reduce HPH DAC bias to 70% */
2327 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_HPH_BIAS_PA, 0x7A),
2328 /*Reduce EAR DAC bias to 70% */
2329 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_BIAS_PA, 0x76),
2330 /* Reduce LINE DAC bias to 70% */
2331 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
2332
2333
2334 /* Disable TX7 internal biasing path which can cause leakage */
Kuirong Wang91e52532013-03-31 14:24:22 -07002335 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
2336 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
2337 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
2338 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
2339 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
2340 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
Kuirong Wang265f3592012-12-05 16:17:41 -08002341};
2342
2343static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
2344{
2345 u32 i;
2346
2347 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_reg_defaults); i++)
2348 snd_soc_write(codec, msm8x10_wcd_reg_defaults[i].reg,
2349 msm8x10_wcd_reg_defaults[i].val);
2350}
2351
2352static const struct msm8x10_wcd_reg_mask_val
2353 msm8x10_wcd_codec_reg_init_val[] = {
2354 /* Initialize current threshold to 350MA
2355 * number of wait and run cycles to 4096
2356 */
2357 {MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
2358 {MSM8X10_WCD_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
2359
2360 /* Initialize gain registers to use register gain */
2361 {MSM8X10_WCD_A_RX_HPH_L_GAIN, 0x20, 0x20},
2362 {MSM8X10_WCD_A_RX_HPH_R_GAIN, 0x20, 0x20},
2363 {MSM8X10_WCD_A_RX_LINE_1_GAIN, 0x20, 0x20},
2364
2365 /*enable HPF filter for TX paths */
2366 {MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
2367 {MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
2368
2369 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
2370 {MSM8X10_WCD_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
2371 {MSM8X10_WCD_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
2372
2373 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
2374 {MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
2375
2376};
2377
2378static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
2379{
2380 u32 i;
2381
2382 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_codec_reg_init_val); i++)
2383 snd_soc_update_bits(codec,
2384 msm8x10_wcd_codec_reg_init_val[i].reg,
2385 msm8x10_wcd_codec_reg_init_val[i].mask,
2386 msm8x10_wcd_codec_reg_init_val[i].val);
2387}
2388
2389int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
2390 struct msm8x10_wcd_mbhc_config *mbhc_cfg)
2391{
2392 return 0;
2393}
2394EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
2395
2396static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
2397{
Kuirong Wang91e52532013-03-31 14:24:22 -07002398 struct msm8x10_wcd_priv *msm8x10_wcd;
2399 int i;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002400 dev_dbg(codec->dev, "%s()\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002401
Kuirong Wang91e52532013-03-31 14:24:22 -07002402 msm8x10_wcd = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
2403 if (!msm8x10_wcd) {
2404 dev_err(codec->dev, "Failed to allocate private data\n");
2405 return -ENOMEM;
2406 }
2407
2408 for (i = 0 ; i < NUM_DECIMATORS; i++) {
2409 tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd;
2410 tx_hpf_work[i].decimator = i + 1;
2411 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
2412 tx_hpf_corner_freq_callback);
2413 }
2414
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002415 codec->control_data = dev_get_drvdata(codec->dev);
Kuirong Wang91e52532013-03-31 14:24:22 -07002416 snd_soc_codec_set_drvdata(codec, msm8x10_wcd);
2417 msm8x10_wcd->codec = codec;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002418 msm8x10_wcd_codec_init_reg(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08002419 msm8x10_wcd_update_reg_defaults(codec);
2420
Kuirong Wang91e52532013-03-31 14:24:22 -07002421 msm8x10_wcd->mclk_enabled = false;
2422 msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
2423 msm8x10_wcd->clock_active = false;
2424 msm8x10_wcd->config_mode_active = false;
2425 msm8x10_wcd->mbhc_polling_active = false;
2426 mutex_init(&msm8x10_wcd->codec_resource_lock);
2427 msm8x10_wcd->codec = codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08002428
2429 return 0;
2430}
2431
2432static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
2433{
2434 return 0;
2435}
2436
2437static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
2438 .probe = msm8x10_wcd_codec_probe,
2439 .remove = msm8x10_wcd_codec_remove,
2440
2441 .read = msm8x10_wcd_read,
2442 .write = msm8x10_wcd_write,
2443
2444 .readable_register = msm8x10_wcd_readable,
2445 .volatile_register = msm8x10_wcd_volatile,
2446
2447 .reg_cache_size = MSM8X10_WCD_CACHE_SIZE,
2448 .reg_cache_default = msm8x10_wcd_reset_reg_defaults,
2449 .reg_word_size = 1,
2450
2451 .controls = msm8x10_wcd_snd_controls,
2452 .num_controls = ARRAY_SIZE(msm8x10_wcd_snd_controls),
2453 .dapm_widgets = msm8x10_wcd_dapm_widgets,
2454 .num_dapm_widgets = ARRAY_SIZE(msm8x10_wcd_dapm_widgets),
2455 .dapm_routes = audio_map,
2456 .num_dapm_routes = ARRAY_SIZE(audio_map),
2457};
2458
Kuirong Wang91e52532013-03-31 14:24:22 -07002459static int msm8x10_wcd_enable_supplies(struct msm8x10_wcd *msm8x10,
2460 struct msm8x10_wcd_pdata *pdata)
2461{
2462 int ret;
2463 int i;
2464 msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
2465 ARRAY_SIZE(pdata->regulator),
2466 GFP_KERNEL);
2467 if (!msm8x10->supplies) {
2468 ret = -ENOMEM;
2469 goto err;
2470 }
2471
2472 msm8x10->num_of_supplies = 0;
2473
2474 if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
2475 dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
2476 __func__);
2477 ret = -EINVAL;
2478 goto err;
2479 }
2480
2481 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
2482 if (pdata->regulator[i].name) {
2483 msm8x10->supplies[i].supply = pdata->regulator[i].name;
2484 msm8x10->num_of_supplies++;
2485 }
2486 }
2487
2488 ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
2489 msm8x10->supplies);
2490 if (ret != 0) {
2491 dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
2492 ret);
2493 goto err_supplies;
2494 }
2495
2496 for (i = 0; i < msm8x10->num_of_supplies; i++) {
2497 ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
2498 pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
2499 if (ret) {
2500 dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
2501 __func__, msm8x10->supplies[i].supply, ret);
2502 goto err_get;
2503 }
2504
2505 ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
2506 pdata->regulator[i].optimum_uA);
2507 if (ret < 0) {
2508 dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
2509 __func__, msm8x10->supplies[i].supply, ret);
2510 goto err_get;
2511 }
2512 }
2513
2514 ret = regulator_bulk_enable(msm8x10->num_of_supplies,
2515 msm8x10->supplies);
2516 if (ret != 0) {
2517 dev_err(msm8x10->dev, "Failed to enable supplies: err = %d\n",
2518 ret);
2519 goto err_configure;
2520 }
2521 return ret;
2522
2523err_configure:
2524 for (i = 0; i < msm8x10->num_of_supplies; i++) {
2525 regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
2526 pdata->regulator[i].max_uV);
2527 regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
2528 }
2529err_get:
2530 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
2531err_supplies:
2532 kfree(msm8x10->supplies);
2533err:
2534 return ret;
2535}
2536
2537static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
2538 struct msm8x10_wcd_pdata *pdata)
2539{
2540 int i;
2541
2542 regulator_bulk_disable(msm8x10->num_of_supplies,
2543 msm8x10->supplies);
2544 for (i = 0; i < msm8x10->num_of_supplies; i++) {
2545 regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
2546 pdata->regulator[i].max_uV);
2547 regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
2548 }
2549 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
2550 kfree(msm8x10->supplies);
2551}
2552
2553static int msm8x10_wcd_bringup(struct msm8x10_wcd *msm8x10)
2554{
2555 msm8x10->read_dev = msm8x10_wcd_reg_read;
2556 msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
2557 msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CHIP_CTL, 0x00);
2558 usleep_range(5000, 5000);
2559 msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
2560 return 0;
2561}
2562
2563static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
2564{
2565 mutex_init(&msm8x10->io_lock);
2566 mutex_init(&msm8x10->xfer_lock);
2567 mutex_init(&msm8x10->pm_lock);
2568 msm8x10->wlock_holders = 0;
2569
2570 iowrite32(0x03C00000, ioremap(0xFD512050, 4));
2571 usleep_range(5000, 5000);
2572
2573 msm8x10_wcd_bringup(msm8x10);
2574 return 0;
2575}
2576
Kuirong Wang265f3592012-12-05 16:17:41 -08002577static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
2578 const struct i2c_device_id *id)
2579{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002580 int ret = 0;
2581 struct msm8x10_wcd *msm8x10 = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -08002582 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002583 static int device_id;
2584 struct device *dev;
2585
2586 dev_dbg(&client->dev, "%s:slave addr = 0x%x device_id = %d\n",
2587 __func__, client->addr, device_id);
2588
2589 if (device_id > 0) {
2590 msm8x10_wcd_modules[device_id++].client = client;
Kuirong Wang91e52532013-03-31 14:24:22 -07002591 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002592 }
2593
2594 dev = &client->dev;
Kuirong Wang265f3592012-12-05 16:17:41 -08002595 if (client->dev.of_node) {
2596 dev_dbg(&client->dev, "%s:Platform data from device tree\n",
2597 __func__);
2598 pdata = msm8x10_wcd_populate_dt_pdata(&client->dev);
2599 client->dev.platform_data = pdata;
2600 } else {
2601 dev_dbg(&client->dev, "%s:Platform data from board file\n",
2602 __func__);
2603 pdata = client->dev.platform_data;
2604 }
2605
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002606 msm8x10 = kzalloc(sizeof(struct msm8x10_wcd), GFP_KERNEL);
2607 if (msm8x10 == NULL) {
2608 dev_err(&client->dev,
2609 "%s: error, allocation failed\n", __func__);
2610 ret = -ENOMEM;
Kuirong Wang91e52532013-03-31 14:24:22 -07002611 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002612 }
Kuirong Wang265f3592012-12-05 16:17:41 -08002613
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002614 msm8x10->dev = &client->dev;
2615 msm8x10_wcd_modules[device_id++].client = client;
2616 msm8x10->read_dev = msm8x10_wcd_reg_read;
2617 msm8x10->write_dev = msm8x10_wcd_reg_write;
Kuirong Wang91e52532013-03-31 14:24:22 -07002618 ret = msm8x10_wcd_enable_supplies(msm8x10, pdata);
2619 if (ret) {
2620 dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
2621 __func__);
2622 goto err_codec;
2623 }
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002624 ret = msm8x10_wcd_device_init(msm8x10);
2625 if (ret) {
2626 dev_err(&client->dev,
2627 "%s:msm8x10_wcd_device_init failed with error %d\n",
2628 __func__, ret);
Kuirong Wang91e52532013-03-31 14:24:22 -07002629 goto err_supplies;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002630 }
2631 dev_set_drvdata(&client->dev, msm8x10);
2632 ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
2633 msm8x10_wcd_i2s_dai,
2634 ARRAY_SIZE(msm8x10_wcd_i2s_dai));
2635 if (ret)
2636 dev_err(&client->dev,
2637 "%s:snd_soc_register_codec failed with error %d\n",
2638 __func__, ret);
Kuirong Wang91e52532013-03-31 14:24:22 -07002639 else
2640 goto rtn;
2641
2642err_supplies:
2643 msm8x10_wcd_disable_supplies(msm8x10, pdata);
2644err_codec:
2645 kfree(msm8x10);
2646rtn:
Kuirong Wang265f3592012-12-05 16:17:41 -08002647 return ret;
2648}
2649
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002650static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
2651{
2652 mutex_destroy(&msm8x10->pm_lock);
2653 mutex_destroy(&msm8x10->io_lock);
2654 mutex_destroy(&msm8x10->xfer_lock);
2655 kfree(msm8x10);
2656}
2657
Kuirong Wang265f3592012-12-05 16:17:41 -08002658static int __devexit msm8x10_wcd_i2c_remove(struct i2c_client *client)
2659{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002660 struct msm8x10_wcd *msm8x10 = dev_get_drvdata(&client->dev);
2661
2662 msm8x10_wcd_device_exit(msm8x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08002663 return 0;
2664}
2665
2666static struct i2c_device_id msm8x10_wcd_id_table[] = {
2667 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_TOP_LEVEL},
2668 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_ANALOG},
2669 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_1},
2670 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_2},
2671 {}
2672};
2673
2674static struct of_device_id msm8x10_wcd_of_match[] = {
2675 { .compatible = "qcom,msm8x10-wcd-i2c",},
2676 { },
2677};
2678
2679
2680static struct i2c_driver msm8x10_wcd_i2c_driver = {
2681 .driver = {
2682 .owner = THIS_MODULE,
2683 .name = "msm8x10-wcd-i2c-core",
2684 .of_match_table = msm8x10_wcd_of_match
2685 },
2686 .id_table = msm8x10_wcd_id_table,
2687 .probe = msm8x10_wcd_i2c_probe,
2688 .remove = __devexit_p(msm8x10_wcd_i2c_remove),
2689};
2690
2691static int __init msm8x10_wcd_codec_init(void)
2692{
2693 int ret;
2694
2695 pr_debug("%s:\n", __func__);
2696 ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
2697 if (ret != 0)
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002698 pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
2699 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -08002700 return ret;
2701}
2702
2703static void __exit msm8x10_wcd_codec_exit(void)
2704{
2705 i2c_del_driver(&msm8x10_wcd_i2c_driver);
2706}
2707
2708
2709module_init(msm8x10_wcd_codec_init);
2710module_exit(msm8x10_wcd_codec_exit);
2711
2712MODULE_DESCRIPTION("MSM8x10 Audio codec driver");
2713MODULE_LICENSE("GPL v2");
2714MODULE_DEVICE_TABLE(i2c, msm8x10_wcd_id_table);
2715