blob: e1a904ffd4c0aaedc003b01dad51c33c7827d759 [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] =
686 snd_soc_read(codec,
687 (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
688 (1 << band_idx);
689
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__,
Kuirong Wang265f3592012-12-05 16:17:41 -0800712 iir_idx, band_idx, value);
713 return 0;
714}
715static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800716 int iir_idx, int band_idx,
717 int coeff_idx)
Kuirong Wang265f3592012-12-05 16:17:41 -0800718{
719 /* Address does not automatically update if reading */
720 snd_soc_write(codec,
721 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
722 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
723
724 /* Mask bits top 2 bits since they are reserved */
725 return ((snd_soc_read(codec,
726 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 24)) &
727 0x3FFFFFFF;
728}
729
730static int msm8x10_wcd_get_iir_band_audio_mixer(
731 struct snd_kcontrol *kcontrol,
732 struct snd_ctl_elem_value *ucontrol)
733{
734 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
735 int iir_idx = ((struct soc_multi_mixer_control *)
736 kcontrol->private_value)->reg;
737 int band_idx = ((struct soc_multi_mixer_control *)
738 kcontrol->private_value)->shift;
739
740 ucontrol->value.integer.value[0] =
741 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
742 ucontrol->value.integer.value[1] =
743 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
744 ucontrol->value.integer.value[2] =
745 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
746 ucontrol->value.integer.value[3] =
747 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
748 ucontrol->value.integer.value[4] =
749 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
750
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800751 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -0800752 "%s: IIR #%d band #%d b1 = 0x%x\n"
753 "%s: IIR #%d band #%d b2 = 0x%x\n"
754 "%s: IIR #%d band #%d a1 = 0x%x\n"
755 "%s: IIR #%d band #%d a2 = 0x%x\n",
756 __func__, iir_idx, band_idx,
757 (uint32_t)ucontrol->value.integer.value[0],
758 __func__, iir_idx, band_idx,
759 (uint32_t)ucontrol->value.integer.value[1],
760 __func__, iir_idx, band_idx,
761 (uint32_t)ucontrol->value.integer.value[2],
762 __func__, iir_idx, band_idx,
763 (uint32_t)ucontrol->value.integer.value[3],
764 __func__, iir_idx, band_idx,
765 (uint32_t)ucontrol->value.integer.value[4]);
766 return 0;
767}
768
769static void set_iir_band_coeff(struct snd_soc_codec *codec,
770 int iir_idx, int band_idx,
771 int coeff_idx, uint32_t value)
772{
773 /* Mask top 3 bits, 6-8 are reserved */
774 /* Update address manually each time */
775 snd_soc_write(codec,
776 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
777 (band_idx * BAND_MAX + coeff_idx) & 0x1F);
778
779 /* Mask top 2 bits, 7-8 are reserved */
780 snd_soc_write(codec,
781 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
782 (value >> 24) & 0x3F);
783
784}
785
786static int msm8x10_wcd_put_iir_band_audio_mixer(
787 struct snd_kcontrol *kcontrol,
788 struct snd_ctl_elem_value *ucontrol)
789{
790 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
791 int iir_idx = ((struct soc_multi_mixer_control *)
792 kcontrol->private_value)->reg;
793 int band_idx = ((struct soc_multi_mixer_control *)
794 kcontrol->private_value)->shift;
795
796 set_iir_band_coeff(codec, iir_idx, band_idx, 0,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800797 ucontrol->value.integer.value[0]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800798 set_iir_band_coeff(codec, iir_idx, band_idx, 1,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800799 ucontrol->value.integer.value[1]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800800 set_iir_band_coeff(codec, iir_idx, band_idx, 2,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800801 ucontrol->value.integer.value[2]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800802 set_iir_band_coeff(codec, iir_idx, band_idx, 3,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800803 ucontrol->value.integer.value[3]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800804 set_iir_band_coeff(codec, iir_idx, band_idx, 4,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800805 ucontrol->value.integer.value[4]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800806
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800807 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -0800808 "%s: IIR #%d band #%d b1 = 0x%x\n"
809 "%s: IIR #%d band #%d b2 = 0x%x\n"
810 "%s: IIR #%d band #%d a1 = 0x%x\n"
811 "%s: IIR #%d band #%d a2 = 0x%x\n",
812 __func__, iir_idx, band_idx,
813 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
814 __func__, iir_idx, band_idx,
815 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
816 __func__, iir_idx, band_idx,
817 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
818 __func__, iir_idx, band_idx,
819 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
820 __func__, iir_idx, band_idx,
821 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
822 return 0;
823}
824
825static const char * const msm8x10_wcd_ear_pa_gain_text[] = {
826 "POS_6_DB", "POS_2_DB"};
827static const struct soc_enum msm8x10_wcd_ear_pa_gain_enum[] = {
828 SOC_ENUM_SINGLE_EXT(2, msm8x10_wcd_ear_pa_gain_text),
829};
830
831/*cut of frequency for high pass filter*/
832static const char * const cf_text[] = {
833 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
834};
835
836static const struct soc_enum cf_dec1_enum =
837 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
838
839static const struct soc_enum cf_dec2_enum =
840 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
841
842static const struct soc_enum cf_rxmix1_enum =
843 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
844
845static const struct soc_enum cf_rxmix2_enum =
846 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
847
848static const struct soc_enum cf_rxmix3_enum =
849 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
850
851static const struct snd_kcontrol_new msm8x10_wcd_snd_controls[] = {
852
853 SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
854 msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
855
Kuirong Wang91e52532013-03-31 14:24:22 -0700856 SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
Kuirong Wang265f3592012-12-05 16:17:41 -0800857 0, 12, 1, line_gain),
858
859 SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
860 0, 12, 1, line_gain),
861 SOC_SINGLE_TLV("HPHR Volume", MSM8X10_WCD_A_RX_HPH_R_GAIN,
862 0, 12, 1, line_gain),
863
864 SOC_SINGLE_S8_TLV("RX1 Digital Volume",
865 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
866 -84, 40, digital_gain),
867 SOC_SINGLE_S8_TLV("RX2 Digital Volume",
868 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
869 -84, 40, digital_gain),
870 SOC_SINGLE_S8_TLV("RX3 Digital Volume",
871 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
872 -84, 40, digital_gain),
873
874 SOC_SINGLE_S8_TLV("DEC1 Volume",
875 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
876 -84, 40, digital_gain),
877 SOC_SINGLE_S8_TLV("DEC2 Volume",
878 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
879 -84, 40, digital_gain),
880
881 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
882 MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL,
883 -84, 40, digital_gain),
884 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
885 MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL,
886 -84, 40, digital_gain),
887 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
888 MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL,
889 -84, 40, digital_gain),
890 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume",
891 MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
892 -84, 40, digital_gain),
893
894 SOC_SINGLE("MICBIAS1 CAPLESS Switch",
895 MSM8X10_WCD_A_MICB_1_CTL, 4, 1, 1),
896
897 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
898 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
899
900 SOC_SINGLE("TX1 HPF Switch", MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 3, 1, 0),
901 SOC_SINGLE("TX2 HPF Switch", MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 3, 1, 0),
902
903 SOC_SINGLE("RX1 HPF Switch", MSM8X10_WCD_A_CDC_RX1_B5_CTL, 2, 1, 0),
904 SOC_SINGLE("RX2 HPF Switch", MSM8X10_WCD_A_CDC_RX2_B5_CTL, 2, 1, 0),
905 SOC_SINGLE("RX3 HPF Switch", MSM8X10_WCD_A_CDC_RX3_B5_CTL, 2, 1, 0),
906
907 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
908 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
909 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
910
911 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
912 msm8x10_wcd_get_iir_enable_audio_mixer,
913 msm8x10_wcd_put_iir_enable_audio_mixer),
914 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
915 msm8x10_wcd_get_iir_enable_audio_mixer,
916 msm8x10_wcd_put_iir_enable_audio_mixer),
917 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
918 msm8x10_wcd_get_iir_enable_audio_mixer,
919 msm8x10_wcd_put_iir_enable_audio_mixer),
920 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
921 msm8x10_wcd_get_iir_enable_audio_mixer,
922 msm8x10_wcd_put_iir_enable_audio_mixer),
923 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
924 msm8x10_wcd_get_iir_enable_audio_mixer,
925 msm8x10_wcd_put_iir_enable_audio_mixer),
926 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
927 msm8x10_wcd_get_iir_enable_audio_mixer,
928 msm8x10_wcd_put_iir_enable_audio_mixer),
929 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
930 msm8x10_wcd_get_iir_enable_audio_mixer,
931 msm8x10_wcd_put_iir_enable_audio_mixer),
932 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
933 msm8x10_wcd_get_iir_enable_audio_mixer,
934 msm8x10_wcd_put_iir_enable_audio_mixer),
935 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
936 msm8x10_wcd_get_iir_enable_audio_mixer,
937 msm8x10_wcd_put_iir_enable_audio_mixer),
938 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
939 msm8x10_wcd_get_iir_enable_audio_mixer,
940 msm8x10_wcd_put_iir_enable_audio_mixer),
941
942 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
943 msm8x10_wcd_get_iir_band_audio_mixer,
944 msm8x10_wcd_put_iir_band_audio_mixer),
945 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
946 msm8x10_wcd_get_iir_band_audio_mixer,
947 msm8x10_wcd_put_iir_band_audio_mixer),
948 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
949 msm8x10_wcd_get_iir_band_audio_mixer,
950 msm8x10_wcd_put_iir_band_audio_mixer),
951 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
952 msm8x10_wcd_get_iir_band_audio_mixer,
953 msm8x10_wcd_put_iir_band_audio_mixer),
954 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
955 msm8x10_wcd_get_iir_band_audio_mixer,
956 msm8x10_wcd_put_iir_band_audio_mixer),
957 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
958 msm8x10_wcd_get_iir_band_audio_mixer,
959 msm8x10_wcd_put_iir_band_audio_mixer),
960 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
961 msm8x10_wcd_get_iir_band_audio_mixer,
962 msm8x10_wcd_put_iir_band_audio_mixer),
963 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
964 msm8x10_wcd_get_iir_band_audio_mixer,
965 msm8x10_wcd_put_iir_band_audio_mixer),
966 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
967 msm8x10_wcd_get_iir_band_audio_mixer,
968 msm8x10_wcd_put_iir_band_audio_mixer),
969 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
970 msm8x10_wcd_get_iir_band_audio_mixer,
971 msm8x10_wcd_put_iir_band_audio_mixer),
972
973};
974
975static const char * const rx_mix1_text[] = {
976 "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
977};
978
979static const char * const rx_mix2_text[] = {
980 "ZERO", "IIR1", "IIR2"
981};
982
983static const char * const dec_mux_text[] = {
984 "ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
985};
986
Kuirong Wang265f3592012-12-05 16:17:41 -0800987static const char * const anc_mux_text[] = {
988 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
989 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
990};
991
992static const char * const anc1_fb_mux_text[] = {
993 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
994};
995
996static const char * const iir1_inp1_text[] = {
997 "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
998};
999
1000static const struct soc_enum rx_mix1_inp1_chain_enum =
1001 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
1002
1003static const struct soc_enum rx_mix1_inp2_chain_enum =
1004 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text);
1005
1006static const struct soc_enum rx_mix1_inp3_chain_enum =
1007 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text);
1008
1009static const struct soc_enum rx2_mix1_inp1_chain_enum =
1010 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text);
1011
1012static const struct soc_enum rx2_mix1_inp2_chain_enum =
1013 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text);
1014
1015static const struct soc_enum rx3_mix1_inp1_chain_enum =
1016 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text);
1017
1018static const struct soc_enum rx3_mix1_inp2_chain_enum =
1019 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text);
1020
1021static const struct soc_enum rx1_mix2_inp1_chain_enum =
1022 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
1023
1024static const struct soc_enum rx2_mix2_inp1_chain_enum =
1025 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
1026
1027static const struct soc_enum dec1_mux_enum =
1028 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 0, 5, dec_mux_text);
1029
1030static const struct soc_enum dec2_mux_enum =
1031 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 3, 5, dec_mux_text);
1032
1033static const struct soc_enum iir1_inp1_mux_enum =
1034 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
1035 iir1_inp1_text);
1036
1037static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1038 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1039
1040static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1041 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1042
1043static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1044 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1045
1046static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1047 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1048
1049static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1050 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1051
1052static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1053 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1054
1055static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1056 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1057
1058static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1059 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1060
1061static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1062 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1063
1064static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
1065 struct snd_ctl_elem_value *ucontrol)
1066{
1067 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1068 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1069 struct snd_soc_codec *codec = w->codec;
1070 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1071 unsigned int dec_mux, decimator;
1072 char *dec_name = NULL;
1073 char *widget_name = NULL;
1074 char *temp;
1075 u16 tx_mux_ctl_reg;
1076 u8 adc_dmic_sel = 0x0;
1077 int ret = 0;
1078
1079 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1080 return -EINVAL;
1081
1082 dec_mux = ucontrol->value.enumerated.item[0];
1083
1084 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1085 if (!widget_name)
1086 return -ENOMEM;
1087 temp = widget_name;
1088
1089 dec_name = strsep(&widget_name, " ");
1090 widget_name = temp;
1091 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001092 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1093 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001094 ret = -EINVAL;
1095 goto out;
1096 }
1097
1098 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1099 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001100 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1101 __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001102 ret = -EINVAL;
1103 goto out;
1104 }
1105
1106 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1107 , __func__, w->name, decimator, dec_mux);
1108
1109 switch (decimator) {
1110 case 1:
1111 case 2:
Kuirong Wang265f3592012-12-05 16:17:41 -08001112 adc_dmic_sel = 0x0;
1113 break;
1114 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001115 dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
1116 __func__, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001117 ret = -EINVAL;
1118 goto out;
1119 }
1120
1121 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
1122
1123 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1124
1125 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1126
1127out:
1128 kfree(widget_name);
1129 return ret;
1130}
1131
1132#define MSM8X10_WCD_DEC_ENUM(xname, xenum) \
1133{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1134 .info = snd_soc_info_enum_double, \
1135 .get = snd_soc_dapm_get_enum_double, \
1136 .put = msm8x10_wcd_put_dec_enum, \
1137 .private_value = (unsigned long)&xenum }
1138
1139static const struct snd_kcontrol_new dec1_mux =
1140 MSM8X10_WCD_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1141
1142static const struct snd_kcontrol_new dec2_mux =
1143 MSM8X10_WCD_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1144
1145static const struct snd_kcontrol_new iir1_inp1_mux =
1146 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1147
1148static const struct snd_kcontrol_new dac1_switch[] = {
1149 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_EAR_EN, 5, 1, 0)
1150};
1151static const struct snd_kcontrol_new hphl_switch[] = {
1152 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1153};
1154
Kuirong Wang265f3592012-12-05 16:17:41 -08001155static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
1156 int enable)
1157{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001158 struct msm8x10_wcd_priv *wcd8x10 = snd_soc_codec_get_drvdata(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08001159
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001160 dev_dbg(codec->dev, "%s %d\n", __func__, enable);
Kuirong Wang265f3592012-12-05 16:17:41 -08001161
1162 if (enable) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001163 wcd8x10->adc_count++;
Kuirong Wang265f3592012-12-05 16:17:41 -08001164 snd_soc_update_bits(codec,
1165 MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1166 0x20, 0x20);
1167 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001168 wcd8x10->adc_count--;
1169 if (!wcd8x10->adc_count)
Kuirong Wang265f3592012-12-05 16:17:41 -08001170 snd_soc_update_bits(codec,
1171 MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1172 0x20, 0x0);
1173 }
1174}
1175
1176static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
1177 struct snd_kcontrol *kcontrol, int event)
1178{
1179 struct snd_soc_codec *codec = w->codec;
1180 u16 adc_reg;
1181 u8 init_bit_shift;
1182
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001183 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001184 adc_reg = MSM8X10_WCD_A_TX_1_2_TEST_CTL;
1185
1186 if (w->reg == MSM8X10_WCD_A_TX_1_EN)
1187 init_bit_shift = 7;
Kuirong Wang91e52532013-03-31 14:24:22 -07001188 else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
Kuirong Wang265f3592012-12-05 16:17:41 -08001189 init_bit_shift = 6;
1190 else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001191 dev_err(codec->dev, "%s: Error, invalid adc register\n",
1192 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001193 return -EINVAL;
1194 }
1195
1196 switch (event) {
1197 case SND_SOC_DAPM_PRE_PMU:
1198 msm8x10_wcd_codec_enable_adc_block(codec, 1);
1199 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1200 1 << init_bit_shift);
1201 break;
1202 case SND_SOC_DAPM_POST_PMU:
1203 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1204 break;
1205 case SND_SOC_DAPM_POST_PMD:
1206 msm8x10_wcd_codec_enable_adc_block(codec, 0);
1207 break;
1208 }
1209 return 0;
1210}
1211
1212static int msm8x10_wcd_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1213 struct snd_kcontrol *kcontrol, int event)
1214{
1215 struct snd_soc_codec *codec = w->codec;
1216 u16 lineout_gain_reg;
1217
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001218 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001219
1220 switch (w->shift) {
1221 case 0:
1222 lineout_gain_reg = MSM8X10_WCD_A_RX_LINE_1_GAIN;
1223 break;
1224 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001225 dev_err(codec->dev,
1226 "%s: Error, incorrect lineout register value\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001227 __func__);
1228 return -EINVAL;
1229 }
1230
1231 switch (event) {
1232 case SND_SOC_DAPM_PRE_PMU:
1233 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1234 break;
1235 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001236 dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
1237 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001238 usleep_range(16000, 16100);
1239 break;
1240 case SND_SOC_DAPM_POST_PMD:
1241 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1242 break;
1243 }
1244 return 0;
1245}
1246
1247static int msm8x10_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1248 struct snd_kcontrol *kcontrol, int event)
1249{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001250 dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001251 return 0;
1252}
1253
1254static int msm8x10_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1255 struct snd_kcontrol *kcontrol, int event)
1256{
1257 struct snd_soc_codec *codec = w->codec;
1258 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1259 u8 dmic_clk_en;
1260 u16 dmic_clk_reg;
1261 s32 *dmic_clk_cnt;
1262 unsigned int dmic;
1263 int ret;
1264
1265 ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
1266 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001267 dev_err(codec->dev,
1268 "%s: Invalid DMIC line on the codec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001269 return -EINVAL;
1270 }
1271
1272 switch (dmic) {
1273 case 1:
1274 case 2:
1275 dmic_clk_en = 0x01;
1276 dmic_clk_cnt = &(msm8x10_wcd->dmic_1_2_clk_cnt);
1277 dmic_clk_reg = MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001278 dev_dbg(codec->dev,
1279 "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001280 __func__, event, dmic, *dmic_clk_cnt);
1281 break;
1282 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001283 dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001284 return -EINVAL;
1285 }
1286
1287 switch (event) {
1288 case SND_SOC_DAPM_PRE_PMU:
1289
1290 (*dmic_clk_cnt)++;
1291 if (*dmic_clk_cnt == 1)
1292 snd_soc_update_bits(codec, dmic_clk_reg,
1293 dmic_clk_en, dmic_clk_en);
1294 break;
1295 case SND_SOC_DAPM_POST_PMD:
1296
1297 (*dmic_clk_cnt)--;
1298 if (*dmic_clk_cnt == 0)
1299 snd_soc_update_bits(codec, dmic_clk_reg,
1300 dmic_clk_en, 0);
1301 break;
1302 }
1303 return 0;
1304}
1305
1306static int msm8x10_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1307 struct snd_kcontrol *kcontrol, int event)
1308{
1309 struct snd_soc_codec *codec = w->codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08001310 u16 micb_int_reg;
Kuirong Wang265f3592012-12-05 16:17:41 -08001311 char *internal1_text = "Internal1";
1312 char *internal2_text = "Internal2";
1313 char *internal3_text = "Internal3";
Kuirong Wang265f3592012-12-05 16:17:41 -08001314
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001315 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001316 switch (w->reg) {
1317 case MSM8X10_WCD_A_MICB_1_CTL:
1318 micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
Kuirong Wang265f3592012-12-05 16:17:41 -08001319 break;
1320 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001321 dev_err(codec->dev,
Kuirong Wang91e52532013-03-31 14:24:22 -07001322 "%s: Error, invalid micbias register 0x%x\n",
1323 __func__, w->reg);
Kuirong Wang265f3592012-12-05 16:17:41 -08001324 return -EINVAL;
1325 }
1326
1327 switch (event) {
1328 case SND_SOC_DAPM_PRE_PMU:
Kuirong Wang265f3592012-12-05 16:17:41 -08001329 if (strnstr(w->name, internal1_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001330 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
Kuirong Wang265f3592012-12-05 16:17:41 -08001331 else if (strnstr(w->name, internal2_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001332 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08001333 else if (strnstr(w->name, internal3_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001334 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
Kuirong Wang265f3592012-12-05 16:17:41 -08001335 break;
1336 case SND_SOC_DAPM_POST_PMU:
1337 usleep_range(20000, 20100);
Kuirong Wang265f3592012-12-05 16:17:41 -08001338 break;
1339 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang265f3592012-12-05 16:17:41 -08001340 if (strnstr(w->name, internal1_text, 30))
1341 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1342 else if (strnstr(w->name, internal2_text, 30))
1343 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1344 else if (strnstr(w->name, internal3_text, 30))
1345 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1346
Kuirong Wang265f3592012-12-05 16:17:41 -08001347 break;
1348 }
Kuirong Wang265f3592012-12-05 16:17:41 -08001349 return 0;
1350}
1351
Kuirong Wang91e52532013-03-31 14:24:22 -07001352static void tx_hpf_corner_freq_callback(struct work_struct *work)
1353{
1354 struct delayed_work *hpf_delayed_work;
1355 struct hpf_work *hpf_work;
1356 struct msm8x10_wcd_priv *msm8x10_wcd;
1357 struct snd_soc_codec *codec;
1358 u16 tx_mux_ctl_reg;
1359 u8 hpf_cut_of_freq;
1360
1361 hpf_delayed_work = to_delayed_work(work);
1362 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
1363 msm8x10_wcd = hpf_work->msm8x10_wcd;
1364 codec = hpf_work->msm8x10_wcd->codec;
1365 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
1366
1367 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1368 (hpf_work->decimator - 1) * 32;
1369
1370 dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
1371 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
1372
1373 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
1374}
1375
1376
Kuirong Wang265f3592012-12-05 16:17:41 -08001377#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
1378#define CF_MIN_3DB_4HZ 0x0
1379#define CF_MIN_3DB_75HZ 0x1
1380#define CF_MIN_3DB_150HZ 0x2
1381
1382static int msm8x10_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
1383 struct snd_kcontrol *kcontrol, int event)
1384{
1385 struct snd_soc_codec *codec = w->codec;
1386 unsigned int decimator;
1387 char *dec_name = NULL;
1388 char *widget_name = NULL;
1389 char *temp;
1390 int ret = 0;
1391 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
1392 u8 dec_hpf_cut_of_freq;
1393 int offset;
1394
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001395 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001396
1397 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1398 if (!widget_name)
1399 return -ENOMEM;
1400 temp = widget_name;
1401
1402 dec_name = strsep(&widget_name, " ");
1403 widget_name = temp;
1404 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001405 dev_err(codec->dev,
1406 "%s: Invalid decimator = %s\n", __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001407 ret = -EINVAL;
1408 goto out;
1409 }
1410
1411 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1412 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001413 dev_err(codec->dev,
1414 "%s: Invalid decimator = %s\n", __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001415 ret = -EINVAL;
1416 goto out;
1417 }
1418
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001419 dev_dbg(codec->dev,
1420 "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
1421 w->name, dec_name, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001422
1423 if (w->reg == MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
1424 dec_reset_reg = MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
1425 offset = 0;
1426 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001427 dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001428 ret = -EINVAL;
1429 goto out;
1430 }
1431
1432 tx_vol_ctl_reg = MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG +
1433 32 * (decimator - 1);
1434 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1435 32 * (decimator - 1);
1436
1437 switch (event) {
1438 case SND_SOC_DAPM_PRE_PMU:
1439 /* Enableable TX digital mute */
1440 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1441
1442 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1443 1 << w->shift);
1444 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1445
1446 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
1447
1448 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
1449
1450 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
1451 dec_hpf_cut_of_freq;
1452
1453 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
1454
1455 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
1456 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1457 CF_MIN_3DB_150HZ << 4);
1458 }
1459
1460 /* enable HPF */
1461 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
1462 break;
1463 case SND_SOC_DAPM_POST_PMU:
1464 /* Disable TX digital mute */
1465 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
1466
1467 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
1468 CF_MIN_3DB_150HZ) {
1469
1470 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
1471 msecs_to_jiffies(300));
1472 }
1473 /* apply the digital gain after the decimator is enabled*/
1474 if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
1475 snd_soc_write(codec,
1476 tx_digital_gain_reg[w->shift + offset],
1477 snd_soc_read(codec,
1478 tx_digital_gain_reg[w->shift + offset])
1479 );
1480 break;
1481 case SND_SOC_DAPM_PRE_PMD:
1482 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1483 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
1484 break;
1485 case SND_SOC_DAPM_POST_PMD:
1486 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
1487 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1488 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
1489 break;
1490 }
1491out:
1492 kfree(widget_name);
1493 return ret;
1494}
1495
1496static int msm8x10_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001497 struct snd_kcontrol *kcontrol,
1498 int event)
Kuirong Wang265f3592012-12-05 16:17:41 -08001499{
1500 struct snd_soc_codec *codec = w->codec;
1501
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001502 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001503
1504 switch (event) {
1505 case SND_SOC_DAPM_PRE_PMU:
1506 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1507 1 << w->shift, 1 << w->shift);
1508 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1509 1 << w->shift, 0x0);
1510 break;
1511 case SND_SOC_DAPM_POST_PMU:
1512 /* apply the digital gain after the interpolator is enabled*/
1513 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
1514 snd_soc_write(codec,
1515 rx_digital_gain_reg[w->shift],
1516 snd_soc_read(codec,
1517 rx_digital_gain_reg[w->shift])
1518 );
1519 break;
1520 }
1521 return 0;
1522}
1523
1524
1525/* The register address is the same as other codec so it can use resmgr */
1526static int msm8x10_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1527 struct snd_kcontrol *kcontrol, int event)
1528{
1529 struct snd_soc_codec *codec = w->codec;
1530 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Kuirong Wang91e52532013-03-31 14:24:22 -07001531 msm8x10_wcd->resmgr.codec = codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08001532
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001533 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001534
1535 switch (event) {
1536 case SND_SOC_DAPM_PRE_PMU:
1537 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 1);
1538 break;
1539 case SND_SOC_DAPM_POST_PMD:
1540 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 0);
1541 break;
1542 }
1543 return 0;
1544}
1545
1546static int msm8x10_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
1547 struct snd_kcontrol *kcontrol, int event)
1548{
1549 struct snd_soc_codec *codec = w->codec;
1550
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001551 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001552
1553 switch (event) {
1554 case SND_SOC_DAPM_PRE_PMU:
1555 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1556 break;
1557 case SND_SOC_DAPM_POST_PMD:
1558 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1559 break;
1560 }
1561 return 0;
1562}
1563
1564static int msm8x10_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
1565 struct snd_kcontrol *kcontrol, int event)
1566{
1567 struct snd_soc_codec *codec = w->codec;
1568 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1569 enum wcd9xxx_notify_event e_pre_on, e_post_off;
1570
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001571 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001572 if (w->shift == 5) {
1573 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
1574 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
1575 } else if (w->shift == 4) {
1576 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
1577 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
1578 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001579 dev_err(codec->dev,
1580 "%s: Invalid w->shift %d\n", __func__, w->shift);
Kuirong Wang265f3592012-12-05 16:17:41 -08001581 return -EINVAL;
1582 }
1583
1584 switch (event) {
1585 case SND_SOC_DAPM_PRE_PMU:
1586 /* Let MBHC module know PA is turning on */
1587 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
1588 break;
1589
1590 case SND_SOC_DAPM_POST_PMU:
1591 usleep_range(10000, 10100);
1592 break;
1593
1594 case SND_SOC_DAPM_POST_PMD:
1595 /* Let MBHC module know PA turned off */
1596 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
1597
1598 /*
1599 * schedule work is required because at the time HPH PA DAPM
1600 * event callback is called by DAPM framework, CODEC dapm mutex
1601 * would have been locked while snd_soc_jack_report also
1602 * attempts to acquire same lock.
1603 */
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001604 dev_dbg(codec->dev,
1605 "%s: sleep 10 ms after %s PA disable.\n", __func__,
1606 w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001607 usleep_range(10000, 10100);
1608 break;
1609 }
1610 return 0;
1611}
1612
1613static int msm8x10_wcd_lineout_dac_event(struct snd_soc_dapm_widget *w,
1614 struct snd_kcontrol *kcontrol, int event)
1615{
1616 struct snd_soc_codec *codec = w->codec;
1617
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001618 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001619
1620 switch (event) {
1621 case SND_SOC_DAPM_PRE_PMU:
1622 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1623 break;
1624
1625 case SND_SOC_DAPM_POST_PMD:
1626 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1627 break;
1628 }
1629 return 0;
1630}
1631
1632static int msm8x10_wcd_spk_dac_event(struct snd_soc_dapm_widget *w,
1633 struct snd_kcontrol *kcontrol, int event)
1634{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001635 dev_dbg(w->codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001636 return 0;
1637}
1638
1639static const struct snd_soc_dapm_route audio_map[] = {
1640 {"RX_I2S_CLK", NULL, "CDC_CONN"},
1641 {"I2S RX1", NULL, "RX_I2S_CLK"},
1642 {"I2S RX2", NULL, "RX_I2S_CLK"},
1643 {"I2S RX3", NULL, "RX_I2S_CLK"},
1644
1645 {"I2S TX1", NULL, "TX_I2S_CLK"},
1646 {"I2S TX2", NULL, "TX_I2S_CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001647
Kuirong Wang91e52532013-03-31 14:24:22 -07001648 {"DEC1 MUX", NULL, "TX CLK"},
1649 {"DEC2 MUX", NULL, "TX CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001650
Kuirong Wang91e52532013-03-31 14:24:22 -07001651 {"I2S TX1", NULL, "DEC1 MUX"},
1652 {"I2S TX2", NULL, "DEC2 MUX"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001653
1654 /* Earpiece (RX MIX1) */
1655 {"EAR", NULL, "EAR PA"},
1656 {"EAR PA", NULL, "DAC1"},
1657 {"DAC1", NULL, "CP"},
1658
1659 /* Headset (RX MIX1 and RX MIX2) */
1660 {"HEADPHONE", NULL, "HPHL"},
1661 {"HEADPHONE", NULL, "HPHR"},
1662
1663 {"HPHL", NULL, "HPHL DAC"},
1664
1665 {"HPHR", NULL, "HPHR DAC"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001666
1667 {"HPHL DAC", NULL, "CP"},
1668
1669 {"HPHR DAC", NULL, "CP"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001670 {"SPK DAC", NULL, "CP"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001671
1672 {"DAC1", "Switch", "RX1 CHAIN"},
1673 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1674 {"HPHR DAC", NULL, "RX2 CHAIN"},
1675
Kuirong Wang91e52532013-03-31 14:24:22 -07001676 {"LINEOUT", NULL, "LINEOUT PA"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001677 {"SPK_OUT", NULL, "SPK PA"},
1678
Kuirong Wang91e52532013-03-31 14:24:22 -07001679 {"LINEOUT PA", NULL, "CP"},
1680 {"LINEOUT PA", NULL, "LINEOUT DAC"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001681
Kuirong Wang91e52532013-03-31 14:24:22 -07001682 {"CP", NULL, "RX_BIAS"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001683 {"SPK PA", NULL, "SPK DAC"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001684 {"SPK DAC", NULL, "RX3 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001685
Kuirong Wang91e52532013-03-31 14:24:22 -07001686 {"RX1 CHAIN", NULL, "RX1 CLK"},
1687 {"RX2 CHAIN", NULL, "RX2 CLK"},
1688 {"RX3 CHAIN", NULL, "RX3 CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001689 {"RX1 CHAIN", NULL, "RX1 MIX2"},
1690 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001691 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001692
1693 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1694 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1695 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
1696 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1697 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
1698 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1699 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1700 {"RX1 MIX2", NULL, "RX1 MIX1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001701 {"RX2 MIX2", NULL, "RX2 MIX1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001702
1703 {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
1704 {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
1705 {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
1706 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1707 {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
1708 {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
1709 {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
1710 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1711 {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
1712 {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
1713 {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
1714
1715 {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
1716 {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
1717 {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
1718 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
1719 {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
1720 {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
1721 {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
1722 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
1723
1724 {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
1725 {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
1726 {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
1727 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
1728 {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
1729 {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
1730 {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
1731 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
1732
1733 /* Decimator Inputs */
1734 {"DEC1 MUX", "DMIC1", "DMIC1"},
1735 {"DEC1 MUX", "DMIC2", "DMIC2"},
1736 {"DEC1 MUX", "ADC1", "ADC1"},
1737 {"DEC1 MUX", "ADC2", "ADC2"},
1738 {"DEC1 MUX", NULL, "CDC_CONN"},
1739
1740 {"DEC2 MUX", "DMIC1", "DMIC1"},
1741 {"DEC2 MUX", "DMIC2", "DMIC2"},
1742 {"DEC2 MUX", "ADC1", "ADC1"},
1743 {"DEC2 MUX", "ADC2", "ADC2"},
1744 {"DEC2 MUX", NULL, "CDC_CONN"},
1745
1746 /* ADC Connections */
1747 {"ADC1", NULL, "AMIC1"},
1748 {"ADC2", NULL, "AMIC2"},
1749
1750 {"IIR1", NULL, "IIR1 INP1 MUX"},
1751 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
1752 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001753 {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
1754 {"MIC BIAS External", NULL, "INT_LDO_H"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001755};
1756
Kuirong Wang265f3592012-12-05 16:17:41 -08001757static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
1758 struct snd_soc_dai *dai)
1759{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001760 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
1761 __func__,
1762 substream->name, substream->stream);
Kuirong Wang265f3592012-12-05 16:17:41 -08001763 return 0;
1764}
1765
1766static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
1767 struct snd_soc_dai *dai)
1768{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001769 dev_dbg(dai->codec->dev,
1770 "%s(): substream = %s stream = %d\n" , __func__,
1771 substream->name, substream->stream);
Kuirong Wang91e52532013-03-31 14:24:22 -07001772}
1773
1774static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
1775 int enable)
1776{
1777 if (enable) {
1778 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
1779 0x01, 0x01);
1780 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
1781 0x03, 0x03);
1782 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
1783 0x0f, 0x0d);
1784 } else {
1785 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
1786 0x0f, 0x00);
1787 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
1788 0x01, 0x01);
1789 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
1790 0x03, 0x00);
Kuirong Wang265f3592012-12-05 16:17:41 -08001791 }
Kuirong Wang91e52532013-03-31 14:24:22 -07001792 return 0;
1793}
1794
1795static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
1796 *codec)
1797{
1798 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
1799 0x80);
1800 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
1801 0x04);
1802 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
1803 0x01);
1804 usleep_range(1000, 1000);
1805 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
1806 0x00);
1807}
1808
1809static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
1810 enum msm8x10_wcd_bandgap_type choice)
1811{
1812 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1813
1814 /* TODO lock resources accessed by audio streams and threaded
1815 * interrupt handlers
1816 */
1817
1818 dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
1819 __func__, choice,
1820 msm8x10_wcd->bandgap_type);
1821
1822 if (msm8x10_wcd->bandgap_type == choice)
1823 return;
1824
1825 if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
1826 (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
1827 msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
1828 } else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
1829 /* bandgap mode becomes fast,
1830 * mclk should be off or clk buff source souldn't be VBG
1831 * Let's turn off mclk always */
1832 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1833 0x2, 0x2);
1834 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1835 0x80, 0x80);
1836 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1837 0x4, 0x4);
1838 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1839 0x01, 0x01);
1840 usleep_range(1000, 1000);
1841 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
1842 0x80, 0x00);
1843 } else if ((msm8x10_wcd->bandgap_type ==
1844 MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
1845 (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
1846 snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
1847 usleep_range(100, 100);
1848 msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
1849 } else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
1850 snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
1851 } else {
1852 dev_err(codec->dev,
1853 "%s: Error, Invalid bandgap settings\n", __func__);
1854 }
1855 msm8x10_wcd->bandgap_type = choice;
Kuirong Wang265f3592012-12-05 16:17:41 -08001856}
1857
1858int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
1859 int mclk_enable, bool dapm)
1860{
1861 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1862
Kuirong Wang91e52532013-03-31 14:24:22 -07001863 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
1864 __func__, mclk_enable, dapm);
1865 if (dapm)
1866 MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
Kuirong Wang265f3592012-12-05 16:17:41 -08001867 if (mclk_enable) {
Kuirong Wang91e52532013-03-31 14:24:22 -07001868 msm8x10_wcd->mclk_enabled = true;
1869 msm8x10_wcd_codec_enable_bandgap(codec,
1870 MSM8X10_WCD_BANDGAP_AUDIO_MODE);
1871 msm8x10_wcd_codec_enable_clock_block(codec, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -08001872 } else {
Kuirong Wang91e52532013-03-31 14:24:22 -07001873 if (!msm8x10_wcd->mclk_enabled) {
1874 if (dapm)
1875 MSM8X10_WCD_RELEASE_LOCK(
1876 msm8x10_wcd->codec_resource_lock);
1877 dev_err(codec->dev, "Error, MCLK already diabled\n");
1878 return -EINVAL;
1879 }
1880 msm8x10_wcd->mclk_enabled = false;
1881 msm8x10_wcd_codec_enable_clock_block(codec, 0);
1882 msm8x10_wcd_codec_enable_bandgap(codec,
1883 MSM8X10_WCD_BANDGAP_OFF);
Kuirong Wang265f3592012-12-05 16:17:41 -08001884 }
Kuirong Wang91e52532013-03-31 14:24:22 -07001885 if (dapm)
1886 MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
Kuirong Wang265f3592012-12-05 16:17:41 -08001887 return 0;
1888}
1889
1890static int msm8x10_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
1891 int clk_id, unsigned int freq, int dir)
1892{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001893 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001894 return 0;
1895}
1896
1897static int msm8x10_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
1898{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001899 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001900 return 0;
1901}
1902
1903static int msm8x10_wcd_set_channel_map(struct snd_soc_dai *dai,
1904 unsigned int tx_num, unsigned int *tx_slot,
1905 unsigned int rx_num, unsigned int *rx_slot)
1906
1907{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001908 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001909 return 0;
1910}
1911
1912static int msm8x10_wcd_get_channel_map(struct snd_soc_dai *dai,
1913 unsigned int *tx_num, unsigned int *tx_slot,
1914 unsigned int *rx_num, unsigned int *rx_slot)
1915
1916{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001917 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001918 return 0;
1919}
1920
1921static int msm8x10_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
1922 u8 rx_fs_rate_reg_val, u32 sample_rate)
1923{
1924 return 0;
1925}
1926
1927static int msm8x10_wcd_set_decimator_rate(struct snd_soc_dai *dai,
1928 u8 tx_fs_rate_reg_val, u32 sample_rate)
1929{
1930 return 0;
1931}
1932
1933static int msm8x10_wcd_hw_params(struct snd_pcm_substream *substream,
1934 struct snd_pcm_hw_params *params,
1935 struct snd_soc_dai *dai)
1936{
1937 u8 tx_fs_rate, rx_fs_rate;
1938 int ret;
1939
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001940 dev_dbg(dai->codec->dev,
1941 "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08001942 dai->name, dai->id, params_rate(params),
1943 params_channels(params));
1944
1945 switch (params_rate(params)) {
1946 case 8000:
1947 tx_fs_rate = 0x00;
1948 rx_fs_rate = 0x00;
1949 break;
1950 case 16000:
1951 tx_fs_rate = 0x01;
1952 rx_fs_rate = 0x20;
1953 break;
1954 case 32000:
1955 tx_fs_rate = 0x02;
1956 rx_fs_rate = 0x40;
1957 break;
1958 case 48000:
1959 tx_fs_rate = 0x03;
1960 rx_fs_rate = 0x60;
1961 break;
1962 case 96000:
1963 tx_fs_rate = 0x04;
1964 rx_fs_rate = 0x80;
1965 break;
1966 case 192000:
1967 tx_fs_rate = 0x05;
1968 rx_fs_rate = 0xA0;
1969 break;
1970 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001971 dev_err(dai->codec->dev,
1972 "%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08001973 params_rate(params));
1974 return -EINVAL;
1975 }
1976
1977 switch (substream->stream) {
1978 case SNDRV_PCM_STREAM_CAPTURE:
1979 ret = msm8x10_wcd_set_decimator_rate(dai, tx_fs_rate,
1980 params_rate(params));
1981 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001982 dev_err(dai->codec->dev,
1983 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08001984 ret);
1985 return ret;
1986 }
1987 break;
1988 case SNDRV_PCM_STREAM_PLAYBACK:
1989 ret = msm8x10_wcd_set_interpolator_rate(dai, rx_fs_rate,
1990 params_rate(params));
1991 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001992 dev_err(dai->codec->dev,
1993 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08001994 ret);
1995 return ret;
1996 }
1997 break;
1998 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001999 dev_err(dai->codec->dev,
2000 "%s: Invalid stream type %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002001 substream->stream);
2002 return -EINVAL;
2003 }
2004
2005 return 0;
2006}
2007
2008static struct snd_soc_dai_ops msm8x10_wcd_dai_ops = {
2009 .startup = msm8x10_wcd_startup,
2010 .shutdown = msm8x10_wcd_shutdown,
2011 .hw_params = msm8x10_wcd_hw_params,
2012 .set_sysclk = msm8x10_wcd_set_dai_sysclk,
2013 .set_fmt = msm8x10_wcd_set_dai_fmt,
2014 .set_channel_map = msm8x10_wcd_set_channel_map,
2015 .get_channel_map = msm8x10_wcd_get_channel_map,
2016};
2017
2018static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[] = {
2019 {
2020 .name = "msm8x10_wcd_i2s_rx1",
2021 .id = AIF1_PB,
2022 .playback = {
2023 .stream_name = "AIF1 Playback",
2024 .rates = MSM8X10_WCD_RATES,
2025 .formats = MSM8X10_WCD_FORMATS,
2026 .rate_max = 192000,
2027 .rate_min = 8000,
2028 .channels_min = 1,
Kuirong Wang91e52532013-03-31 14:24:22 -07002029 .channels_max = 3,
Kuirong Wang265f3592012-12-05 16:17:41 -08002030 },
2031 .ops = &msm8x10_wcd_dai_ops,
2032 },
2033 {
2034 .name = "msm8x10_wcd_i2s_tx1",
2035 .id = AIF1_CAP,
2036 .capture = {
2037 .stream_name = "AIF1 Capture",
2038 .rates = MSM8X10_WCD_RATES,
2039 .formats = MSM8X10_WCD_FORMATS,
2040 .rate_max = 192000,
2041 .rate_min = 8000,
2042 .channels_min = 1,
2043 .channels_max = 4,
2044 },
2045 .ops = &msm8x10_wcd_dai_ops,
2046 },
2047};
2048
2049static int msm8x10_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
2050 struct snd_kcontrol *kcontrol, int event)
2051{
2052 switch (event) {
2053 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002054 dev_dbg(w->codec->dev,
2055 "%s: Sleeping 20ms after enabling EAR PA\n",
2056 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002057 msleep(20);
2058 break;
2059 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002060 dev_dbg(w->codec->dev,
2061 "%s: Sleeping 20ms after disabling EAR PA\n",
2062 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002063 msleep(20);
2064 break;
2065 }
2066 return 0;
2067}
2068
2069static const struct snd_soc_dapm_widget msm8x10_wcd_dapm_widgets[] = {
2070 /*RX stuff */
2071 SND_SOC_DAPM_OUTPUT("EAR"),
2072
2073 SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
2074 msm8x10_wcd_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
2075
2076 SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
2077 ARRAY_SIZE(dac1_switch)),
2078
Kuirong Wang91e52532013-03-31 14:24:22 -07002079 SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002080
Kuirong Wang91e52532013-03-31 14:24:22 -07002081 SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002082
Kuirong Wang91e52532013-03-31 14:24:22 -07002083 SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002084
Kuirong Wang91e52532013-03-31 14:24:22 -07002085 SND_SOC_DAPM_SUPPLY("TX CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2086 4, 0, NULL, 0),
2087 SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
2088
Kuirong Wang265f3592012-12-05 16:17:41 -08002089 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2090 SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2091 5, 0, NULL, 0,
2092 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2093 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2094 SND_SOC_DAPM_MIXER("HPHL DAC", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL,
2095 7, 0,
2096 hphl_switch, ARRAY_SIZE(hphl_switch)),
2097
2098 SND_SOC_DAPM_PGA_E("HPHR", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2099 4, 0, NULL, 0,
2100 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2101 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2102
2103 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, MSM8X10_WCD_A_RX_HPH_R_DAC_CTL,
2104 7, 0,
2105 msm8x10_wcd_hphr_dac_event,
2106 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2107
2108 /* Speaker */
Kuirong Wang91e52532013-03-31 14:24:22 -07002109 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002110 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
2111
Kuirong Wang91e52532013-03-31 14:24:22 -07002112 SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
Kuirong Wang265f3592012-12-05 16:17:41 -08002113 0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
2114 SND_SOC_DAPM_PRE_PMU |
2115 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2116
2117 SND_SOC_DAPM_PGA_E("SPK PA", MSM8X10_WCD_A_SPKR_DRV_EN,
2118 7, 0 , NULL, 0, msm8x10_wcd_codec_enable_spk_pa,
2119 SND_SOC_DAPM_PRE_PMU |
2120 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2121
Kuirong Wang91e52532013-03-31 14:24:22 -07002122 SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
Kuirong Wang265f3592012-12-05 16:17:41 -08002123 MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
2124 msm8x10_wcd_lineout_dac_event,
2125 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2126
2127 SND_SOC_DAPM_DAC_E("SPK DAC", NULL, SND_SOC_NOPM, 0, 0,
2128 msm8x10_wcd_spk_dac_event,
2129 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2130
2131 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2132 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2133
2134 SND_SOC_DAPM_MIXER_E("RX1 MIX2",
2135 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
2136 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2137 SND_SOC_DAPM_POST_PMU),
2138 SND_SOC_DAPM_MIXER_E("RX2 MIX2",
2139 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
2140 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2141 SND_SOC_DAPM_POST_PMU),
2142 SND_SOC_DAPM_MIXER_E("RX3 MIX1",
2143 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
2144 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2145 SND_SOC_DAPM_POST_PMU),
2146
Kuirong Wang91e52532013-03-31 14:24:22 -07002147 SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2148 0, 0, NULL, 0),
2149 SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2150 1, 0, NULL, 0),
2151 SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2152 2, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002153 SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
2154 5, 0, NULL, 0),
2155 SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
2156 5, 0, NULL, 0),
Kuirong Wang91e52532013-03-31 14:24:22 -07002157 SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
2158 5, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002159
2160 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2161 &rx_mix1_inp1_mux),
2162 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2163 &rx_mix1_inp2_mux),
2164 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
2165 &rx_mix1_inp3_mux),
2166 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2167 &rx2_mix1_inp1_mux),
2168 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2169 &rx2_mix1_inp2_mux),
2170 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2171 &rx3_mix1_inp1_mux),
2172 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2173 &rx3_mix1_inp2_mux),
2174 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2175 &rx1_mix2_inp1_mux),
2176 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2177 &rx2_mix2_inp1_mux),
2178
2179 SND_SOC_DAPM_SUPPLY("CP", MSM8X10_WCD_A_CP_EN, 0, 0,
2180 msm8x10_wcd_codec_enable_charge_pump, SND_SOC_DAPM_PRE_PMU |
2181 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
2182
2183 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2184 msm8x10_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2185 SND_SOC_DAPM_POST_PMD),
2186
2187 /* TX */
2188
2189 SND_SOC_DAPM_SUPPLY("CDC_CONN", MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
2190 2, 0, NULL, 0),
2191
2192
2193 SND_SOC_DAPM_INPUT("AMIC1"),
Kuirong Wang91e52532013-03-31 14:24:22 -07002194 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
Kuirong Wang265f3592012-12-05 16:17:41 -08002195 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2196 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2197 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002198 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
Kuirong Wang265f3592012-12-05 16:17:41 -08002199 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2200 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2201 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002202 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
Kuirong Wang265f3592012-12-05 16:17:41 -08002203 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2204 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2205 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2206 SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
2207 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2208 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002209 SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
Kuirong Wang265f3592012-12-05 16:17:41 -08002210 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2211 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2212
Kuirong Wang91e52532013-03-31 14:24:22 -07002213 SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
2214 7, 0),
2215
Kuirong Wang265f3592012-12-05 16:17:41 -08002216 SND_SOC_DAPM_INPUT("AMIC3"),
2217
2218 SND_SOC_DAPM_MUX_E("DEC1 MUX",
2219 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
2220 &dec1_mux, msm8x10_wcd_codec_enable_dec,
2221 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2222 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2223
2224 SND_SOC_DAPM_MUX_E("DEC2 MUX",
2225 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
2226 &dec2_mux, msm8x10_wcd_codec_enable_dec,
2227 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2228 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2229
2230 SND_SOC_DAPM_INPUT("AMIC2"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002231
Kuirong Wang91e52532013-03-31 14:24:22 -07002232 SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
2233 0, 0),
2234 SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
2235 0, 0),
2236 SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
2237 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002238
2239 /* Digital Mic Inputs */
2240 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2241 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2242 SND_SOC_DAPM_POST_PMD),
2243
2244 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2245 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2246 SND_SOC_DAPM_POST_PMD),
2247
2248 /* Sidetone */
2249 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2250 SND_SOC_DAPM_PGA("IIR1", MSM8X10_WCD_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2251
2252 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL,
2253 4, 0, NULL, 0),
2254 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL, 4,
2255 0, NULL, 0),
2256};
2257
2258static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
2259
2260 /* set MCLk to 9.6 */
Kuirong Wang91e52532013-03-31 14:24:22 -07002261 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
Kuirong Wang265f3592012-12-05 16:17:41 -08002262
2263 /* EAR PA deafults */
2264 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
2265
2266 /* RX deafults */
2267 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B5_CTL, 0x78),
2268 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B5_CTL, 0x78),
2269 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B5_CTL, 0x78),
2270
2271 /* RX1 and RX2 defaults */
2272 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xA0),
2273 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xA0),
2274
2275 /* RX3 to RX7 defaults */
2276 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B6_CTL, 0x80),
2277
2278 /* Reduce HPH DAC bias to 70% */
2279 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_HPH_BIAS_PA, 0x7A),
2280 /*Reduce EAR DAC bias to 70% */
2281 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_BIAS_PA, 0x76),
2282 /* Reduce LINE DAC bias to 70% */
2283 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
2284
2285
2286 /* Disable TX7 internal biasing path which can cause leakage */
Kuirong Wang91e52532013-03-31 14:24:22 -07002287 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
2288 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
2289 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
2290 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
2291 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
2292 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
Kuirong Wang265f3592012-12-05 16:17:41 -08002293};
2294
2295static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
2296{
2297 u32 i;
2298
2299 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_reg_defaults); i++)
2300 snd_soc_write(codec, msm8x10_wcd_reg_defaults[i].reg,
2301 msm8x10_wcd_reg_defaults[i].val);
2302}
2303
2304static const struct msm8x10_wcd_reg_mask_val
2305 msm8x10_wcd_codec_reg_init_val[] = {
2306 /* Initialize current threshold to 350MA
2307 * number of wait and run cycles to 4096
2308 */
2309 {MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
2310 {MSM8X10_WCD_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
2311
2312 /* Initialize gain registers to use register gain */
2313 {MSM8X10_WCD_A_RX_HPH_L_GAIN, 0x20, 0x20},
2314 {MSM8X10_WCD_A_RX_HPH_R_GAIN, 0x20, 0x20},
2315 {MSM8X10_WCD_A_RX_LINE_1_GAIN, 0x20, 0x20},
2316
2317 /*enable HPF filter for TX paths */
2318 {MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
2319 {MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
2320
2321 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
2322 {MSM8X10_WCD_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
2323 {MSM8X10_WCD_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
2324
2325 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
2326 {MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
2327
2328};
2329
2330static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
2331{
2332 u32 i;
2333
2334 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_codec_reg_init_val); i++)
2335 snd_soc_update_bits(codec,
2336 msm8x10_wcd_codec_reg_init_val[i].reg,
2337 msm8x10_wcd_codec_reg_init_val[i].mask,
2338 msm8x10_wcd_codec_reg_init_val[i].val);
2339}
2340
2341int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
2342 struct msm8x10_wcd_mbhc_config *mbhc_cfg)
2343{
2344 return 0;
2345}
2346EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
2347
2348static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
2349{
Kuirong Wang91e52532013-03-31 14:24:22 -07002350 struct msm8x10_wcd_priv *msm8x10_wcd;
2351 int i;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002352 dev_dbg(codec->dev, "%s()\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002353
Kuirong Wang91e52532013-03-31 14:24:22 -07002354 msm8x10_wcd = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
2355 if (!msm8x10_wcd) {
2356 dev_err(codec->dev, "Failed to allocate private data\n");
2357 return -ENOMEM;
2358 }
2359
2360 for (i = 0 ; i < NUM_DECIMATORS; i++) {
2361 tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd;
2362 tx_hpf_work[i].decimator = i + 1;
2363 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
2364 tx_hpf_corner_freq_callback);
2365 }
2366
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002367 codec->control_data = dev_get_drvdata(codec->dev);
Kuirong Wang91e52532013-03-31 14:24:22 -07002368 snd_soc_codec_set_drvdata(codec, msm8x10_wcd);
2369 msm8x10_wcd->codec = codec;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002370 msm8x10_wcd_codec_init_reg(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08002371 msm8x10_wcd_update_reg_defaults(codec);
2372
Kuirong Wang91e52532013-03-31 14:24:22 -07002373 msm8x10_wcd->mclk_enabled = false;
2374 msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
2375 msm8x10_wcd->clock_active = false;
2376 msm8x10_wcd->config_mode_active = false;
2377 msm8x10_wcd->mbhc_polling_active = false;
2378 mutex_init(&msm8x10_wcd->codec_resource_lock);
2379 msm8x10_wcd->codec = codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08002380
2381 return 0;
2382}
2383
2384static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
2385{
2386 return 0;
2387}
2388
2389static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
2390 .probe = msm8x10_wcd_codec_probe,
2391 .remove = msm8x10_wcd_codec_remove,
2392
2393 .read = msm8x10_wcd_read,
2394 .write = msm8x10_wcd_write,
2395
2396 .readable_register = msm8x10_wcd_readable,
2397 .volatile_register = msm8x10_wcd_volatile,
2398
2399 .reg_cache_size = MSM8X10_WCD_CACHE_SIZE,
2400 .reg_cache_default = msm8x10_wcd_reset_reg_defaults,
2401 .reg_word_size = 1,
2402
2403 .controls = msm8x10_wcd_snd_controls,
2404 .num_controls = ARRAY_SIZE(msm8x10_wcd_snd_controls),
2405 .dapm_widgets = msm8x10_wcd_dapm_widgets,
2406 .num_dapm_widgets = ARRAY_SIZE(msm8x10_wcd_dapm_widgets),
2407 .dapm_routes = audio_map,
2408 .num_dapm_routes = ARRAY_SIZE(audio_map),
2409};
2410
Kuirong Wang91e52532013-03-31 14:24:22 -07002411static int msm8x10_wcd_enable_supplies(struct msm8x10_wcd *msm8x10,
2412 struct msm8x10_wcd_pdata *pdata)
2413{
2414 int ret;
2415 int i;
2416 msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
2417 ARRAY_SIZE(pdata->regulator),
2418 GFP_KERNEL);
2419 if (!msm8x10->supplies) {
2420 ret = -ENOMEM;
2421 goto err;
2422 }
2423
2424 msm8x10->num_of_supplies = 0;
2425
2426 if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
2427 dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
2428 __func__);
2429 ret = -EINVAL;
2430 goto err;
2431 }
2432
2433 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
2434 if (pdata->regulator[i].name) {
2435 msm8x10->supplies[i].supply = pdata->regulator[i].name;
2436 msm8x10->num_of_supplies++;
2437 }
2438 }
2439
2440 ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
2441 msm8x10->supplies);
2442 if (ret != 0) {
2443 dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
2444 ret);
2445 goto err_supplies;
2446 }
2447
2448 for (i = 0; i < msm8x10->num_of_supplies; i++) {
2449 ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
2450 pdata->regulator[i].min_uV, pdata->regulator[i].max_uV);
2451 if (ret) {
2452 dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
2453 __func__, msm8x10->supplies[i].supply, ret);
2454 goto err_get;
2455 }
2456
2457 ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
2458 pdata->regulator[i].optimum_uA);
2459 if (ret < 0) {
2460 dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
2461 __func__, msm8x10->supplies[i].supply, ret);
2462 goto err_get;
2463 }
2464 }
2465
2466 ret = regulator_bulk_enable(msm8x10->num_of_supplies,
2467 msm8x10->supplies);
2468 if (ret != 0) {
2469 dev_err(msm8x10->dev, "Failed to enable supplies: err = %d\n",
2470 ret);
2471 goto err_configure;
2472 }
2473 return ret;
2474
2475err_configure:
2476 for (i = 0; i < msm8x10->num_of_supplies; i++) {
2477 regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
2478 pdata->regulator[i].max_uV);
2479 regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
2480 }
2481err_get:
2482 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
2483err_supplies:
2484 kfree(msm8x10->supplies);
2485err:
2486 return ret;
2487}
2488
2489static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
2490 struct msm8x10_wcd_pdata *pdata)
2491{
2492 int i;
2493
2494 regulator_bulk_disable(msm8x10->num_of_supplies,
2495 msm8x10->supplies);
2496 for (i = 0; i < msm8x10->num_of_supplies; i++) {
2497 regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
2498 pdata->regulator[i].max_uV);
2499 regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
2500 }
2501 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
2502 kfree(msm8x10->supplies);
2503}
2504
2505static int msm8x10_wcd_bringup(struct msm8x10_wcd *msm8x10)
2506{
2507 msm8x10->read_dev = msm8x10_wcd_reg_read;
2508 msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
2509 msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CHIP_CTL, 0x00);
2510 usleep_range(5000, 5000);
2511 msm8x10->write_dev(msm8x10, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
2512 return 0;
2513}
2514
2515static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
2516{
2517 mutex_init(&msm8x10->io_lock);
2518 mutex_init(&msm8x10->xfer_lock);
2519 mutex_init(&msm8x10->pm_lock);
2520 msm8x10->wlock_holders = 0;
2521
2522 iowrite32(0x03C00000, ioremap(0xFD512050, 4));
2523 usleep_range(5000, 5000);
2524
2525 msm8x10_wcd_bringup(msm8x10);
2526 return 0;
2527}
2528
Kuirong Wang265f3592012-12-05 16:17:41 -08002529static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
2530 const struct i2c_device_id *id)
2531{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002532 int ret = 0;
2533 struct msm8x10_wcd *msm8x10 = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -08002534 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002535 static int device_id;
2536 struct device *dev;
2537
2538 dev_dbg(&client->dev, "%s:slave addr = 0x%x device_id = %d\n",
2539 __func__, client->addr, device_id);
2540
2541 if (device_id > 0) {
2542 msm8x10_wcd_modules[device_id++].client = client;
Kuirong Wang91e52532013-03-31 14:24:22 -07002543 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002544 }
2545
2546 dev = &client->dev;
Kuirong Wang265f3592012-12-05 16:17:41 -08002547 if (client->dev.of_node) {
2548 dev_dbg(&client->dev, "%s:Platform data from device tree\n",
2549 __func__);
2550 pdata = msm8x10_wcd_populate_dt_pdata(&client->dev);
2551 client->dev.platform_data = pdata;
2552 } else {
2553 dev_dbg(&client->dev, "%s:Platform data from board file\n",
2554 __func__);
2555 pdata = client->dev.platform_data;
2556 }
2557
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002558 msm8x10 = kzalloc(sizeof(struct msm8x10_wcd), GFP_KERNEL);
2559 if (msm8x10 == NULL) {
2560 dev_err(&client->dev,
2561 "%s: error, allocation failed\n", __func__);
2562 ret = -ENOMEM;
Kuirong Wang91e52532013-03-31 14:24:22 -07002563 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002564 }
Kuirong Wang265f3592012-12-05 16:17:41 -08002565
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002566 msm8x10->dev = &client->dev;
2567 msm8x10_wcd_modules[device_id++].client = client;
2568 msm8x10->read_dev = msm8x10_wcd_reg_read;
2569 msm8x10->write_dev = msm8x10_wcd_reg_write;
Kuirong Wang91e52532013-03-31 14:24:22 -07002570 ret = msm8x10_wcd_enable_supplies(msm8x10, pdata);
2571 if (ret) {
2572 dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
2573 __func__);
2574 goto err_codec;
2575 }
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002576 ret = msm8x10_wcd_device_init(msm8x10);
2577 if (ret) {
2578 dev_err(&client->dev,
2579 "%s:msm8x10_wcd_device_init failed with error %d\n",
2580 __func__, ret);
Kuirong Wang91e52532013-03-31 14:24:22 -07002581 goto err_supplies;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002582 }
2583 dev_set_drvdata(&client->dev, msm8x10);
2584 ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
2585 msm8x10_wcd_i2s_dai,
2586 ARRAY_SIZE(msm8x10_wcd_i2s_dai));
2587 if (ret)
2588 dev_err(&client->dev,
2589 "%s:snd_soc_register_codec failed with error %d\n",
2590 __func__, ret);
Kuirong Wang91e52532013-03-31 14:24:22 -07002591 else
2592 goto rtn;
2593
2594err_supplies:
2595 msm8x10_wcd_disable_supplies(msm8x10, pdata);
2596err_codec:
2597 kfree(msm8x10);
2598rtn:
Kuirong Wang265f3592012-12-05 16:17:41 -08002599 return ret;
2600}
2601
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002602static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
2603{
2604 mutex_destroy(&msm8x10->pm_lock);
2605 mutex_destroy(&msm8x10->io_lock);
2606 mutex_destroy(&msm8x10->xfer_lock);
2607 kfree(msm8x10);
2608}
2609
Kuirong Wang265f3592012-12-05 16:17:41 -08002610static int __devexit msm8x10_wcd_i2c_remove(struct i2c_client *client)
2611{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002612 struct msm8x10_wcd *msm8x10 = dev_get_drvdata(&client->dev);
2613
2614 msm8x10_wcd_device_exit(msm8x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08002615 return 0;
2616}
2617
2618static struct i2c_device_id msm8x10_wcd_id_table[] = {
2619 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_TOP_LEVEL},
2620 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_ANALOG},
2621 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_1},
2622 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_2},
2623 {}
2624};
2625
2626static struct of_device_id msm8x10_wcd_of_match[] = {
2627 { .compatible = "qcom,msm8x10-wcd-i2c",},
2628 { },
2629};
2630
2631
2632static struct i2c_driver msm8x10_wcd_i2c_driver = {
2633 .driver = {
2634 .owner = THIS_MODULE,
2635 .name = "msm8x10-wcd-i2c-core",
2636 .of_match_table = msm8x10_wcd_of_match
2637 },
2638 .id_table = msm8x10_wcd_id_table,
2639 .probe = msm8x10_wcd_i2c_probe,
2640 .remove = __devexit_p(msm8x10_wcd_i2c_remove),
2641};
2642
2643static int __init msm8x10_wcd_codec_init(void)
2644{
2645 int ret;
2646
2647 pr_debug("%s:\n", __func__);
2648 ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
2649 if (ret != 0)
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002650 pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
2651 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -08002652 return ret;
2653}
2654
2655static void __exit msm8x10_wcd_codec_exit(void)
2656{
2657 i2c_del_driver(&msm8x10_wcd_i2c_driver);
2658}
2659
2660
2661module_init(msm8x10_wcd_codec_init);
2662module_exit(msm8x10_wcd_codec_exit);
2663
2664MODULE_DESCRIPTION("MSM8x10 Audio codec driver");
2665MODULE_LICENSE("GPL v2");
2666MODULE_DEVICE_TABLE(i2c, msm8x10_wcd_id_table);
2667