blob: 46b0a9195d5d7e2feb35ac9e68645392f357499c [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>
Fred Ohcf2f8582013-06-13 18:32:07 -070038#include <mach/subsystem_notif.h>
Kuirong Wang265f3592012-12-05 16:17:41 -080039#include "msm8x10-wcd.h"
40#include "wcd9xxx-resmgr.h"
41#include "msm8x10_wcd_registers.h"
Fred Ohcf2f8582013-06-13 18:32:07 -070042#include "../msm/qdsp6v2/q6core.h"
Kuirong Wang265f3592012-12-05 16:17:41 -080043
44#define MSM8X10_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
45 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
46#define MSM8X10_WCD_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
47
48#define NUM_DECIMATORS 2
49#define NUM_INTERPOLATORS 3
50#define BITS_PER_REG 8
51#define MSM8X10_WCD_TX_PORT_NUMBER 4
52
53#define MSM8X10_WCD_I2S_MASTER_MODE_MASK 0x08
54#define MSM8X10_DINO_CODEC_BASE_ADDR 0xFE043000
Kuirong Wang2e81d322013-05-30 17:52:36 -070055#define MSM8x10_TLMM_CDC_PULL_CTL 0xFD512050
56#define HELICON_CORE_0_I2C_ADDR 0x0d
57#define HELICON_CORE_1_I2C_ADDR 0x77
58#define HELICON_CORE_2_I2C_ADDR 0x66
59#define HELICON_CORE_3_I2C_ADDR 0x55
Kuirong Wang265f3592012-12-05 16:17:41 -080060
Kuirong Wang3a6408d2013-02-20 17:46:46 -080061#define MAX_MSM8X10_WCD_DEVICE 4
Kuirong Wang265f3592012-12-05 16:17:41 -080062#define CODEC_DT_MAX_PROP_SIZE 40
Kuirong Wang49f506a2013-05-22 17:38:26 -070063#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
Kuirong Wang265f3592012-12-05 16:17:41 -080064
65enum {
66 MSM8X10_WCD_I2C_TOP_LEVEL = 0,
67 MSM8X10_WCD_I2C_ANALOG,
68 MSM8X10_WCD_I2C_DIGITAL_1,
69 MSM8X10_WCD_I2C_DIGITAL_2,
70};
71
72enum {
73 AIF1_PB = 0,
74 AIF1_CAP,
75 NUM_CODEC_DAIS,
76};
77
78enum {
79 RX_MIX1_INP_SEL_ZERO = 0,
80 RX_MIX1_INP_SEL_IIR1,
81 RX_MIX1_INP_SEL_IIR2,
82 RX_MIX1_INP_SEL_RX1,
83 RX_MIX1_INP_SEL_RX2,
84 RX_MIX1_INP_SEL_RX3,
85};
86
87static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
88static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
89static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
90static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[];
91static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
92
Kuirong Wang91e52532013-03-31 14:24:22 -070093#define MSM8X10_WCD_ACQUIRE_LOCK(x) do { \
94 mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
95} while (0)
96#define MSM8X10_WCD_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
97
98
Kuirong Wang265f3592012-12-05 16:17:41 -080099/* Codec supports 2 IIR filters */
100enum {
101 IIR1 = 0,
102 IIR2,
103 IIR_MAX,
104};
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800105
Kuirong Wang265f3592012-12-05 16:17:41 -0800106/* Codec supports 5 bands */
107enum {
108 BAND1 = 0,
109 BAND2,
110 BAND3,
111 BAND4,
112 BAND5,
113 BAND_MAX,
114};
115
Kuirong Wang91e52532013-03-31 14:24:22 -0700116enum msm8x10_wcd_bandgap_type {
117 MSM8X10_WCD_BANDGAP_OFF = 0,
118 MSM8X10_WCD_BANDGAP_AUDIO_MODE,
119 MSM8X10_WCD_BANDGAP_MBHC_MODE,
120};
121
Kuirong Wang49f506a2013-05-22 17:38:26 -0700122enum {
123 ON_DEMAND_MICBIAS = 0,
124 ON_DEMAND_CP,
125 ON_DEMAND_SUPPLIES_MAX,
126};
127
Kuirong Wang265f3592012-12-05 16:17:41 -0800128struct hpf_work {
129 struct msm8x10_wcd_priv *msm8x10_wcd;
130 u32 decimator;
131 u8 tx_hpf_cut_of_freq;
132 struct delayed_work dwork;
133};
134
135static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
136
Kuirong Wang49f506a2013-05-22 17:38:26 -0700137struct on_demand_supply {
138 struct regulator *supply;
139 atomic_t ref;
140};
141
142static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
143 "cdc-vdd-mic-bias",
144 "cdc-vdda-cp",
145};
146
Kuirong Wang265f3592012-12-05 16:17:41 -0800147struct msm8x10_wcd_priv {
148 struct snd_soc_codec *codec;
149 u32 adc_count;
150 u32 rx_bias_count;
151 s32 dmic_1_2_clk_cnt;
Kuirong Wang91e52532013-03-31 14:24:22 -0700152 enum msm8x10_wcd_bandgap_type bandgap_type;
153 bool mclk_enabled;
154 bool clock_active;
155 bool config_mode_active;
156 bool mbhc_polling_active;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700157 struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
Kuirong Wang91e52532013-03-31 14:24:22 -0700158 struct mutex codec_resource_lock;
Kuirong Wang265f3592012-12-05 16:17:41 -0800159 /* resmgr module */
160 struct wcd9xxx_resmgr resmgr;
Kuirong Wang265f3592012-12-05 16:17:41 -0800161};
162
Kuirong Wang265f3592012-12-05 16:17:41 -0800163static unsigned short rx_digital_gain_reg[] = {
164 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
165 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
166 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
167};
168
169static unsigned short tx_digital_gain_reg[] = {
170 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
171 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
172};
173
174struct msm8x10_wcd_i2c {
175 struct i2c_client *client;
176 struct i2c_msg xfer_msg[2];
177 struct mutex xfer_lock;
178 int mod_id;
179};
180
Kuirong Wang265f3592012-12-05 16:17:41 -0800181static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
Kuirong Wang49f506a2013-05-22 17:38:26 -0700182 struct msm8x10_wcd_regulator *vreg,
183 const char *vreg_name, bool ondemand);
Kuirong Wang265f3592012-12-05 16:17:41 -0800184static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
185 struct msm8x10_wcd_micbias_setting *micbias);
186static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
187 struct device *dev);
188
189struct msm8x10_wcd_i2c msm8x10_wcd_modules[MAX_MSM8X10_WCD_DEVICE];
190
Fred Ohcf2f8582013-06-13 18:32:07 -0700191static void *adsp_state_notifier;
192
193static struct snd_soc_codec *registered_codec;
194#define ADSP_STATE_READY_TIMEOUT_MS 2000
195
Kuirong Wang265f3592012-12-05 16:17:41 -0800196
197static int get_i2c_msm8x10_wcd_device_info(u16 reg,
198 struct msm8x10_wcd_i2c **msm8x10_wcd)
199{
200 int rtn = 0;
201 int value = ((reg & 0x0f00) >> 8) & 0x000f;
Kuirong Wang265f3592012-12-05 16:17:41 -0800202 switch (value) {
203 case 0:
204 case 1:
205 *msm8x10_wcd = &msm8x10_wcd_modules[value];
206 break;
207 default:
208 rtn = -EINVAL;
209 break;
210 }
211 return rtn;
212}
213
Kuirong Wang91e52532013-03-31 14:24:22 -0700214static int msm8x10_wcd_abh_write_device(u16 reg, u8 *value, u32 bytes)
Kuirong Wang265f3592012-12-05 16:17:41 -0800215{
216 u32 temp = ((u32)(*value)) & 0x000000FF;
217 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
218 iowrite32(temp, ioremap(MSM8X10_DINO_CODEC_BASE_ADDR + offset, 4));
219 return 0;
220}
221
Kuirong Wang91e52532013-03-31 14:24:22 -0700222static int msm8x10_wcd_abh_read_device(u16 reg, u32 bytes, u8 *value)
Kuirong Wang265f3592012-12-05 16:17:41 -0800223{
Kuirong Wang91e52532013-03-31 14:24:22 -0700224 u32 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800225 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
Kuirong Wang91e52532013-03-31 14:24:22 -0700226 temp = ioread32(ioremap(MSM8X10_DINO_CODEC_BASE_ADDR +
Kuirong Wang265f3592012-12-05 16:17:41 -0800227 offset, 4));
Kuirong Wang91e52532013-03-31 14:24:22 -0700228 *value = (u8)temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800229 return 0;
230}
231
232static int msm8x10_wcd_i2c_write_device(u16 reg, u8 *value, u32 bytes)
233{
234
235 struct i2c_msg *msg;
236 int ret;
237 u8 reg_addr = 0;
238 u8 data[bytes + 1];
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800239 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800240
241 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800242 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800243 pr_err("%s: Invalid register address\n", __func__);
244 return ret;
245 }
246
247 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
248 pr_err("%s: Failed to get device info\n", __func__);
249 return -ENODEV;
250 }
251 reg_addr = (u8)reg;
252 msg = &msm8x10_wcd->xfer_msg[0];
253 msg->addr = msm8x10_wcd->client->addr;
254 msg->len = bytes + 1;
255 msg->flags = 0;
256 data[0] = reg;
257 data[1] = *value;
258 msg->buf = data;
259 ret = i2c_transfer(msm8x10_wcd->client->adapter,
260 msm8x10_wcd->xfer_msg, 1);
261 /* Try again if the write fails */
262 if (ret != 1) {
263 ret = i2c_transfer(msm8x10_wcd->client->adapter,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800264 msm8x10_wcd->xfer_msg, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -0800265 if (ret != 1) {
266 pr_err("failed to write the device\n");
267 return ret;
268 }
269 }
270 pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
271 return 0;
272}
273
274
275int msm8x10_wcd_i2c_read_device(u32 reg, u32 bytes, u8 *dest)
276{
277 struct i2c_msg *msg;
278 int ret = 0;
279 u8 reg_addr = 0;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800280 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800281 u8 i = 0;
282
283 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800284 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800285 pr_err("%s: Invalid register address\n", __func__);
286 return ret;
287 }
288
289 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
290 pr_err("%s: Failed to get device info\n", __func__);
291 return -ENODEV;
292 }
293
294 for (i = 0; i < bytes; i++) {
295 reg_addr = (u8)reg++;
296 msg = &msm8x10_wcd->xfer_msg[0];
297 msg->addr = msm8x10_wcd->client->addr;
298 msg->len = 1;
299 msg->flags = 0;
300 msg->buf = &reg_addr;
Kuirong Wang265f3592012-12-05 16:17:41 -0800301 msg = &msm8x10_wcd->xfer_msg[1];
302 msg->addr = msm8x10_wcd->client->addr;
303 msg->len = 1;
304 msg->flags = I2C_M_RD;
305 msg->buf = dest++;
306 ret = i2c_transfer(msm8x10_wcd->client->adapter,
307 msm8x10_wcd->xfer_msg, 2);
308
309 /* Try again if read fails first time */
310 if (ret != 2) {
311 ret = i2c_transfer(msm8x10_wcd->client->adapter,
312 msm8x10_wcd->xfer_msg, 2);
313 if (ret != 2) {
314 pr_err("failed to read msm8x10_wcd register\n");
315 return ret;
316 }
317 }
318 }
Kuirong Wang91e52532013-03-31 14:24:22 -0700319 pr_debug("%s: reg 0x%x = 0x%x\n", __func__, reg, *dest);
Kuirong Wang265f3592012-12-05 16:17:41 -0800320 return 0;
321}
322
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800323int msm8x10_wcd_i2c_read(unsigned short reg, int bytes, void *dest)
Kuirong Wang265f3592012-12-05 16:17:41 -0800324{
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800325 return msm8x10_wcd_i2c_read_device(reg, bytes, dest);
326}
327
328int msm8x10_wcd_i2c_write(unsigned short reg, int bytes, void *src)
329{
330 return msm8x10_wcd_i2c_write_device(reg, src, bytes);
331}
332
333static int msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
334 u16 reg, unsigned int *val)
335{
Kuirong Wang265f3592012-12-05 16:17:41 -0800336 int ret = -EINVAL;
Kuirong Wang91e52532013-03-31 14:24:22 -0700337 u8 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800338
339 /* check if use I2C interface for Helicon or AHB for Dino */
340 mutex_lock(&msm8x10_wcd->io_lock);
341 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang91e52532013-03-31 14:24:22 -0700342 ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800343 else if (MSM8X10_WCD_IS_DINO_REG(reg))
Kuirong Wang91e52532013-03-31 14:24:22 -0700344 ret = msm8x10_wcd_abh_read_device(reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800345 mutex_unlock(&msm8x10_wcd->io_lock);
Kuirong Wang91e52532013-03-31 14:24:22 -0700346 *val = temp;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800347 return ret;
Kuirong Wang265f3592012-12-05 16:17:41 -0800348}
349
350
351static int msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd, u16 reg,
Kuirong Wang91e52532013-03-31 14:24:22 -0700352 u8 val)
Kuirong Wang265f3592012-12-05 16:17:41 -0800353{
354 int ret = -EINVAL;
355
356 /* check if use I2C interface for Helicon or AHB for Dino */
357 mutex_lock(&msm8x10_wcd->io_lock);
358 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800359 ret = msm8x10_wcd_i2c_write(reg, 1, &val);
Kuirong Wang265f3592012-12-05 16:17:41 -0800360 else if (MSM8X10_WCD_IS_DINO_REG(reg))
361 ret = msm8x10_wcd_abh_write_device(reg, &val, 1);
362 mutex_unlock(&msm8x10_wcd->io_lock);
363
364 return ret;
365}
366
367static bool msm8x10_wcd_is_digital_gain_register(unsigned int reg)
368{
369 bool rtn = false;
370 switch (reg) {
371 case MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL:
372 case MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL:
373 case MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL:
374 case MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN:
375 case MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN:
376 rtn = true;
377 break;
378 default:
379 break;
380 }
381 return rtn;
382}
383
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800384static int msm8x10_wcd_volatile(struct snd_soc_codec *codec, unsigned int reg)
Kuirong Wang265f3592012-12-05 16:17:41 -0800385{
386 /*
387 * Registers lower than 0x100 are top level registers which can be
388 * written by the Taiko core driver.
389 */
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800390 dev_dbg(codec->dev, "%s: reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800391
392 if ((reg >= MSM8X10_WCD_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
393 return 1;
394
395 /* IIR Coeff registers are not cacheable */
396 if ((reg >= MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL) &&
397 (reg <= MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL))
398 return 1;
399
400 /*
401 * Digital gain register is not cacheable so we have to write
402 * the setting even it is the same
403 */
404 if (msm8x10_wcd_is_digital_gain_register(reg))
405 return 1;
406
407 /* HPH status registers */
408 if (reg == MSM8X10_WCD_A_RX_HPH_L_STATUS ||
409 reg == MSM8X10_WCD_A_RX_HPH_R_STATUS)
410 return 1;
411
412 if (reg == MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS)
413 return 1;
414
415 return 0;
416}
417
418static int msm8x10_wcd_readable(struct snd_soc_codec *ssc, unsigned int reg)
419{
420 return msm8x10_wcd_reg_readable[reg];
421}
422
423static int msm8x10_wcd_write(struct snd_soc_codec *codec, unsigned int reg,
424 unsigned int value)
425{
426 int ret;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800427 dev_dbg(codec->dev, "%s: Write from reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800428 if (reg == SND_SOC_NOPM)
429 return 0;
430
431 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
432
433 if (!msm8x10_wcd_volatile(codec, reg)) {
434 ret = snd_soc_cache_write(codec, reg, value);
435 if (ret != 0)
436 dev_err(codec->dev, "Cache write to %x failed: %d\n",
437 reg, ret);
438 }
439
Kuirong Wang91e52532013-03-31 14:24:22 -0700440 return msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
Kuirong Wang265f3592012-12-05 16:17:41 -0800441}
442
443static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
444 unsigned int reg)
445{
446 unsigned int val;
447 int ret;
448
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800449 dev_dbg(codec->dev, "%s: Read from reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800450 if (reg == SND_SOC_NOPM)
451 return 0;
452
453 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
454
455 if (!msm8x10_wcd_volatile(codec, reg) &&
456 msm8x10_wcd_readable(codec, reg) &&
457 reg < codec->driver->reg_cache_size) {
458 ret = snd_soc_cache_read(codec, reg, &val);
459 if (ret >= 0) {
460 return val;
461 } else
462 dev_err(codec->dev, "Cache read from %x failed: %d\n",
463 reg, ret);
464 }
465
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800466 ret = msm8x10_wcd_reg_read(codec->control_data, reg, &val);
Kuirong Wang265f3592012-12-05 16:17:41 -0800467 return val;
468}
469
470
471static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
Kuirong Wang49f506a2013-05-22 17:38:26 -0700472 struct msm8x10_wcd_regulator *vreg, const char *vreg_name,
473 bool ondemand)
Kuirong Wang265f3592012-12-05 16:17:41 -0800474{
475 int len, ret = 0;
476 const __be32 *prop;
477 char prop_name[CODEC_DT_MAX_PROP_SIZE];
478 struct device_node *regnode = NULL;
479 u32 prop_val;
480
481 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
482 vreg_name);
483 regnode = of_parse_phandle(dev->of_node, prop_name, 0);
484
485 if (!regnode) {
Kuirong Wang91e52532013-03-31 14:24:22 -0700486 dev_err(dev, "Looking up %s property in node %s failed\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800487 prop_name, dev->of_node->full_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800488 return -ENODEV;
489 }
Kuirong Wang91e52532013-03-31 14:24:22 -0700490
491 dev_dbg(dev, "Looking up %s property in node %s\n",
492 prop_name, dev->of_node->full_name);
493
Kuirong Wang265f3592012-12-05 16:17:41 -0800494 vreg->name = vreg_name;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700495 vreg->ondemand = ondemand;
Kuirong Wang265f3592012-12-05 16:17:41 -0800496
497 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
498 "qcom,%s-voltage", vreg_name);
499 prop = of_get_property(dev->of_node, prop_name, &len);
500
501 if (!prop || (len != (2 * sizeof(__be32)))) {
502 dev_err(dev, "%s %s property\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800503 prop ? "invalid format" : "no", prop_name);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700504 return -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800505 } else {
506 vreg->min_uV = be32_to_cpup(&prop[0]);
507 vreg->max_uV = be32_to_cpup(&prop[1]);
508 }
509
510 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800511 "qcom,%s-current", vreg_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800512
513 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
514 if (ret) {
515 dev_err(dev, "Looking up %s property in node %s failed",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800516 prop_name, dev->of_node->full_name);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700517 return -EFAULT;
Kuirong Wang265f3592012-12-05 16:17:41 -0800518 }
519 vreg->optimum_uA = prop_val;
520
Kuirong Wang49f506a2013-05-22 17:38:26 -0700521 dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
522 vreg->min_uV, vreg->max_uV, vreg->optimum_uA, vreg->ondemand);
Kuirong Wang265f3592012-12-05 16:17:41 -0800523 return 0;
524}
525
526static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
527 struct msm8x10_wcd_micbias_setting *micbias)
528{
529 int ret = 0;
530 char prop_name[CODEC_DT_MAX_PROP_SIZE];
531 u32 prop_val;
532
533 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700534 "qcom,cdc-micbias-cfilt-mv");
Kuirong Wang265f3592012-12-05 16:17:41 -0800535 ret = of_property_read_u32(dev->of_node, prop_name,
536 &micbias->cfilt1_mv);
537 if (ret) {
538 dev_err(dev, "Looking up %s property in node %s failed",
539 prop_name, dev->of_node->full_name);
540 return -ENODEV;
541 }
542
543 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700544 "qcom,cdc-micbias-cfilt-sel");
Kuirong Wang265f3592012-12-05 16:17:41 -0800545 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
546 if (ret) {
547 dev_err(dev, "Looking up %s property in node %s failed",
548 prop_name, dev->of_node->full_name);
549 return -ENODEV;
550 }
551 micbias->bias1_cfilt_sel = (u8)prop_val;
552
553 /* micbias external cap */
554 micbias->bias1_cap_mode =
555 (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
556 MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
557
558 dev_dbg(dev, "ldoh_v %u cfilt1_mv %u\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800559 (u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
Kuirong Wang265f3592012-12-05 16:17:41 -0800560 dev_dbg(dev, "bias1_cfilt_sel %u\n", (u32)micbias->bias1_cfilt_sel);
561 dev_dbg(dev, "bias1_ext_cap %d\n", micbias->bias1_cap_mode);
562
563 return 0;
564}
565
566static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
567 struct device *dev)
568{
569 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700570 int ret, static_cnt, ond_cnt, idx, i;
571 const char *name = NULL;
572 const char *static_prop_name = "qcom,cdc-static-supplies";
573 const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
Kuirong Wang265f3592012-12-05 16:17:41 -0800574
575 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
576 if (!pdata) {
577 dev_err(dev, "could not allocate memory for platform data\n");
578 return NULL;
579 }
Kuirong Wang49f506a2013-05-22 17:38:26 -0700580
581 static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
582 if (IS_ERR_VALUE(static_cnt)) {
583 dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
584 static_cnt);
585 ret = -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800586 goto err;
587 }
588
Kuirong Wang49f506a2013-05-22 17:38:26 -0700589 /* On-demand supply list is an optional property */
590 ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
591 if (IS_ERR_VALUE(ond_cnt))
592 ond_cnt = 0;
593
594 BUG_ON(static_cnt <= 0 || ond_cnt < 0);
595 if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800596 dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
Kuirong Wang49f506a2013-05-22 17:38:26 -0700597 __func__, static_cnt, ARRAY_SIZE(pdata->regulator));
598 ret = -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800599 goto err;
600 }
601
Kuirong Wang49f506a2013-05-22 17:38:26 -0700602 for (idx = 0; idx < static_cnt; idx++) {
603 ret = of_property_read_string_index(dev->of_node,
604 static_prop_name, idx,
605 &name);
606 if (ret) {
607 dev_err(dev, "%s: of read string %s idx %d error %d\n",
608 __func__, static_prop_name, idx, ret);
609 goto err;
610 }
611
612 dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
613 name);
614 ret = msm8x10_wcd_dt_parse_vreg_info(dev,
615 &pdata->regulator[idx],
616 name, false);
Kuirong Wang265f3592012-12-05 16:17:41 -0800617 if (ret)
618 goto err;
619 }
Kuirong Wang49f506a2013-05-22 17:38:26 -0700620
621 for (i = 0; i < ond_cnt; i++, idx++) {
622 ret = of_property_read_string_index(dev->of_node, ond_prop_name,
623 i, &name);
624 if (ret)
625 goto err;
626
627 dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
628 name);
629 ret = msm8x10_wcd_dt_parse_vreg_info(dev,
630 &pdata->regulator[idx],
631 name, true);
632 if (ret)
633 goto err;
634 }
635
Kuirong Wang265f3592012-12-05 16:17:41 -0800636 ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
637 if (ret)
638 goto err;
Kuirong Wang265f3592012-12-05 16:17:41 -0800639 return pdata;
640err:
641 devm_kfree(dev, pdata);
Kuirong Wang91e52532013-03-31 14:24:22 -0700642 dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
643 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -0800644 return NULL;
645}
646
Kuirong Wang49f506a2013-05-22 17:38:26 -0700647static int msm8x10_wcd_codec_enable_on_demand_supply(
648 struct snd_soc_dapm_widget *w,
649 struct snd_kcontrol *kcontrol, int event)
650{
651 int ret = 0;
652 struct snd_soc_codec *codec = w->codec;
653 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
654 struct on_demand_supply *supply;
655
656 if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
657 ret = -EINVAL;
658 goto out;
659 }
660 dev_dbg(codec->dev, "%s: supply: %s event: %d ref: %d\n",
661 __func__, on_demand_supply_name[w->shift], event,
662 atomic_read(&msm8x10_wcd->on_demand_list[w->shift].ref));
663
664 supply = &msm8x10_wcd->on_demand_list[w->shift];
665 WARN_ONCE(!supply->supply, "%s isn't defined\n",
666 on_demand_supply_name[w->shift]);
667 if (!supply->supply)
668 goto out;
669
670 switch (event) {
671 case SND_SOC_DAPM_PRE_PMU:
672 if (atomic_inc_return(&supply->ref) == 1)
673 ret = regulator_enable(supply->supply);
674 if (ret)
675 dev_err(codec->dev, "%s: Failed to enable %s\n",
676 __func__,
677 on_demand_supply_name[w->shift]);
678 break;
679 case SND_SOC_DAPM_POST_PMD:
680 if (atomic_read(&supply->ref) == 0) {
681 dev_dbg(codec->dev, "%s: %s supply has been disabled.\n",
682 __func__, on_demand_supply_name[w->shift]);
683 goto out;
684 }
685 if (atomic_dec_return(&supply->ref) == 0)
686 ret = regulator_disable(supply->supply);
687 if (ret)
688 dev_err(codec->dev, "%s: Failed to disable %s\n",
689 __func__,
690 on_demand_supply_name[w->shift]);
691 break;
692 default:
693 break;
694 }
695out:
696 return ret;
697}
698
Kuirong Wang265f3592012-12-05 16:17:41 -0800699static int msm8x10_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
700 struct snd_kcontrol *kcontrol, int event)
701{
702 struct snd_soc_codec *codec = w->codec;
703
Kuirong Wang49f506a2013-05-22 17:38:26 -0700704 dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -0800705 switch (event) {
706 case SND_SOC_DAPM_POST_PMU:
707 /* Enable charge pump clock*/
708 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
709 0x01, 0x01);
710 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLSG_CTL,
711 0x08, 0x08);
712 usleep_range(200, 300);
713 snd_soc_update_bits(codec, MSM8X10_WCD_A_CP_STATIC,
714 0x10, 0x00);
715 break;
716 case SND_SOC_DAPM_PRE_PMD:
717 snd_soc_update_bits(codec,
718 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
719 0x01, 0x01);
720 usleep_range(20, 100);
721 snd_soc_update_bits(codec,
722 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x08);
723 snd_soc_update_bits(codec,
724 MSM8X10_WCD_A_CP_STATIC, 0x10, 0x10);
725 snd_soc_update_bits(codec,
726 MSM8X10_WCD_A_CDC_CLSG_CTL, 0x08, 0x00);
727 snd_soc_update_bits(codec,
728 MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
729 0x00);
730 snd_soc_update_bits(codec,
Kuirong Wang91e52532013-03-31 14:24:22 -0700731 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
Kuirong Wang854de642013-05-24 13:40:41 -0700732 0x01, 0x00);
Kuirong Wang91e52532013-03-31 14:24:22 -0700733 snd_soc_update_bits(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800734 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
735 break;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700736 default:
737 break;
Kuirong Wang265f3592012-12-05 16:17:41 -0800738 }
739 return 0;
740}
741
742static int msm8x10_wcd_pa_gain_get(struct snd_kcontrol *kcontrol,
743 struct snd_ctl_elem_value *ucontrol)
744{
745 u8 ear_pa_gain;
746 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
747
748 ear_pa_gain = snd_soc_read(codec, MSM8X10_WCD_A_RX_EAR_GAIN);
749
750 ear_pa_gain = ear_pa_gain >> 5;
751
752 if (ear_pa_gain == 0x00) {
753 ucontrol->value.integer.value[0] = 0;
754 } else if (ear_pa_gain == 0x04) {
755 ucontrol->value.integer.value[0] = 1;
756 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800757 dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
758 __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800759 return -EINVAL;
760 }
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800761 dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800762 return 0;
763}
764
765static int msm8x10_wcd_pa_gain_put(struct snd_kcontrol *kcontrol,
766 struct snd_ctl_elem_value *ucontrol)
767{
768 u8 ear_pa_gain;
769 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
770
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800771 dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
772 __func__, ucontrol->value.integer.value[0]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800773
774 switch (ucontrol->value.integer.value[0]) {
775 case 0:
776 ear_pa_gain = 0x00;
777 break;
778 case 1:
779 ear_pa_gain = 0x80;
780 break;
781 default:
782 return -EINVAL;
783 }
784
785 snd_soc_update_bits(codec, MSM8X10_WCD_A_RX_EAR_GAIN,
786 0xE0, ear_pa_gain);
787 return 0;
788}
789
790static int msm8x10_wcd_get_iir_enable_audio_mixer(
791 struct snd_kcontrol *kcontrol,
792 struct snd_ctl_elem_value *ucontrol)
793{
794 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
795 int iir_idx = ((struct soc_multi_mixer_control *)
796 kcontrol->private_value)->reg;
797 int band_idx = ((struct soc_multi_mixer_control *)
798 kcontrol->private_value)->shift;
799
800 ucontrol->value.integer.value[0] =
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700801 (snd_soc_read(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800802 (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700803 (1 << band_idx)) != 0;
Kuirong Wang265f3592012-12-05 16:17:41 -0800804
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800805 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -0800806 iir_idx, band_idx,
807 (uint32_t)ucontrol->value.integer.value[0]);
808 return 0;
809}
810
811static int msm8x10_wcd_put_iir_enable_audio_mixer(
812 struct snd_kcontrol *kcontrol,
813 struct snd_ctl_elem_value *ucontrol)
814{
815 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
816 int iir_idx = ((struct soc_multi_mixer_control *)
817 kcontrol->private_value)->reg;
818 int band_idx = ((struct soc_multi_mixer_control *)
819 kcontrol->private_value)->shift;
820 int value = ucontrol->value.integer.value[0];
821
822 /* Mask first 5 bits, 6-8 are reserved */
823 snd_soc_update_bits(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx),
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800824 (1 << band_idx), (value << band_idx));
Kuirong Wang265f3592012-12-05 16:17:41 -0800825
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800826 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700827 iir_idx, band_idx,
828 ((snd_soc_read(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
829 (1 << band_idx)) != 0));
830
Kuirong Wang265f3592012-12-05 16:17:41 -0800831 return 0;
832}
833static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800834 int iir_idx, int band_idx,
835 int coeff_idx)
Kuirong Wang265f3592012-12-05 16:17:41 -0800836{
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700837 uint32_t value = 0;
838
Kuirong Wang265f3592012-12-05 16:17:41 -0800839 /* Address does not automatically update if reading */
840 snd_soc_write(codec,
841 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700842 ((band_idx * BAND_MAX + coeff_idx)
843 * sizeof(uint32_t)) & 0x7F);
844
845 value |= snd_soc_read(codec,
846 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx));
847
848 snd_soc_write(codec,
849 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
850 ((band_idx * BAND_MAX + coeff_idx)
851 * sizeof(uint32_t) + 1) & 0x7F);
852
853 value |= (snd_soc_read(codec,
854 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
855
856 snd_soc_write(codec,
857 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
858 ((band_idx * BAND_MAX + coeff_idx)
859 * sizeof(uint32_t) + 2) & 0x7F);
860
861 value |= (snd_soc_read(codec,
862 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
863
864 snd_soc_write(codec,
865 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
866 ((band_idx * BAND_MAX + coeff_idx)
867 * sizeof(uint32_t) + 3) & 0x7F);
Kuirong Wang265f3592012-12-05 16:17:41 -0800868
869 /* Mask bits top 2 bits since they are reserved */
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700870 value |= ((snd_soc_read(codec,
871 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) & 0x3f) << 24);
872
873 return value;
874
Kuirong Wang265f3592012-12-05 16:17:41 -0800875}
876
877static int msm8x10_wcd_get_iir_band_audio_mixer(
878 struct snd_kcontrol *kcontrol,
879 struct snd_ctl_elem_value *ucontrol)
880{
881 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
882 int iir_idx = ((struct soc_multi_mixer_control *)
883 kcontrol->private_value)->reg;
884 int band_idx = ((struct soc_multi_mixer_control *)
885 kcontrol->private_value)->shift;
886
887 ucontrol->value.integer.value[0] =
888 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
889 ucontrol->value.integer.value[1] =
890 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
891 ucontrol->value.integer.value[2] =
892 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
893 ucontrol->value.integer.value[3] =
894 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
895 ucontrol->value.integer.value[4] =
896 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
897
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800898 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -0800899 "%s: IIR #%d band #%d b1 = 0x%x\n"
900 "%s: IIR #%d band #%d b2 = 0x%x\n"
901 "%s: IIR #%d band #%d a1 = 0x%x\n"
902 "%s: IIR #%d band #%d a2 = 0x%x\n",
903 __func__, iir_idx, band_idx,
904 (uint32_t)ucontrol->value.integer.value[0],
905 __func__, iir_idx, band_idx,
906 (uint32_t)ucontrol->value.integer.value[1],
907 __func__, iir_idx, band_idx,
908 (uint32_t)ucontrol->value.integer.value[2],
909 __func__, iir_idx, band_idx,
910 (uint32_t)ucontrol->value.integer.value[3],
911 __func__, iir_idx, band_idx,
912 (uint32_t)ucontrol->value.integer.value[4]);
913 return 0;
914}
915
916static void set_iir_band_coeff(struct snd_soc_codec *codec,
917 int iir_idx, int band_idx,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700918 uint32_t value)
Kuirong Wang265f3592012-12-05 16:17:41 -0800919{
Kuirong Wang265f3592012-12-05 16:17:41 -0800920 snd_soc_write(codec,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700921 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
922 (value & 0xFF));
923
924 snd_soc_write(codec,
925 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
926 (value >> 8) & 0xFF);
927
928 snd_soc_write(codec,
929 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
930 (value >> 16) & 0xFF);
Kuirong Wang265f3592012-12-05 16:17:41 -0800931
932 /* Mask top 2 bits, 7-8 are reserved */
933 snd_soc_write(codec,
934 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
935 (value >> 24) & 0x3F);
936
937}
938
939static int msm8x10_wcd_put_iir_band_audio_mixer(
940 struct snd_kcontrol *kcontrol,
941 struct snd_ctl_elem_value *ucontrol)
942{
943 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
944 int iir_idx = ((struct soc_multi_mixer_control *)
945 kcontrol->private_value)->reg;
946 int band_idx = ((struct soc_multi_mixer_control *)
947 kcontrol->private_value)->shift;
948
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700949 /* Mask top bit it is reserved */
950 /* Updates addr automatically for each B2 write */
951 snd_soc_write(codec,
952 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
953 (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
954
955
956 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800957 ucontrol->value.integer.value[0]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700958 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800959 ucontrol->value.integer.value[1]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700960 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800961 ucontrol->value.integer.value[2]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700962 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800963 ucontrol->value.integer.value[3]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700964 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800965 ucontrol->value.integer.value[4]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800966
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800967 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -0800968 "%s: IIR #%d band #%d b1 = 0x%x\n"
969 "%s: IIR #%d band #%d b2 = 0x%x\n"
970 "%s: IIR #%d band #%d a1 = 0x%x\n"
971 "%s: IIR #%d band #%d a2 = 0x%x\n",
972 __func__, iir_idx, band_idx,
973 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
974 __func__, iir_idx, band_idx,
975 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
976 __func__, iir_idx, band_idx,
977 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
978 __func__, iir_idx, band_idx,
979 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
980 __func__, iir_idx, band_idx,
981 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
982 return 0;
983}
984
985static const char * const msm8x10_wcd_ear_pa_gain_text[] = {
986 "POS_6_DB", "POS_2_DB"};
987static const struct soc_enum msm8x10_wcd_ear_pa_gain_enum[] = {
988 SOC_ENUM_SINGLE_EXT(2, msm8x10_wcd_ear_pa_gain_text),
989};
990
991/*cut of frequency for high pass filter*/
992static const char * const cf_text[] = {
993 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
994};
995
996static const struct soc_enum cf_dec1_enum =
997 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
998
999static const struct soc_enum cf_dec2_enum =
1000 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
1001
1002static const struct soc_enum cf_rxmix1_enum =
1003 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
1004
1005static const struct soc_enum cf_rxmix2_enum =
1006 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
1007
1008static const struct soc_enum cf_rxmix3_enum =
1009 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
1010
1011static const struct snd_kcontrol_new msm8x10_wcd_snd_controls[] = {
1012
1013 SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
1014 msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
1015
Kuirong Wang91e52532013-03-31 14:24:22 -07001016 SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
Kuirong Wang265f3592012-12-05 16:17:41 -08001017 0, 12, 1, line_gain),
1018
1019 SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
1020 0, 12, 1, line_gain),
1021 SOC_SINGLE_TLV("HPHR Volume", MSM8X10_WCD_A_RX_HPH_R_GAIN,
1022 0, 12, 1, line_gain),
1023
1024 SOC_SINGLE_S8_TLV("RX1 Digital Volume",
1025 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
1026 -84, 40, digital_gain),
1027 SOC_SINGLE_S8_TLV("RX2 Digital Volume",
1028 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
1029 -84, 40, digital_gain),
1030 SOC_SINGLE_S8_TLV("RX3 Digital Volume",
1031 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
1032 -84, 40, digital_gain),
1033
1034 SOC_SINGLE_S8_TLV("DEC1 Volume",
1035 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
1036 -84, 40, digital_gain),
1037 SOC_SINGLE_S8_TLV("DEC2 Volume",
1038 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
1039 -84, 40, digital_gain),
1040
1041 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
1042 MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL,
1043 -84, 40, digital_gain),
1044 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
1045 MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL,
1046 -84, 40, digital_gain),
1047 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
1048 MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL,
1049 -84, 40, digital_gain),
1050 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume",
1051 MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
1052 -84, 40, digital_gain),
1053
1054 SOC_SINGLE("MICBIAS1 CAPLESS Switch",
1055 MSM8X10_WCD_A_MICB_1_CTL, 4, 1, 1),
1056
1057 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
1058 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
1059
1060 SOC_SINGLE("TX1 HPF Switch", MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 3, 1, 0),
1061 SOC_SINGLE("TX2 HPF Switch", MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 3, 1, 0),
1062
1063 SOC_SINGLE("RX1 HPF Switch", MSM8X10_WCD_A_CDC_RX1_B5_CTL, 2, 1, 0),
1064 SOC_SINGLE("RX2 HPF Switch", MSM8X10_WCD_A_CDC_RX2_B5_CTL, 2, 1, 0),
1065 SOC_SINGLE("RX3 HPF Switch", MSM8X10_WCD_A_CDC_RX3_B5_CTL, 2, 1, 0),
1066
1067 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1068 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1069 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
1070
1071 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1072 msm8x10_wcd_get_iir_enable_audio_mixer,
1073 msm8x10_wcd_put_iir_enable_audio_mixer),
1074 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1075 msm8x10_wcd_get_iir_enable_audio_mixer,
1076 msm8x10_wcd_put_iir_enable_audio_mixer),
1077 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1078 msm8x10_wcd_get_iir_enable_audio_mixer,
1079 msm8x10_wcd_put_iir_enable_audio_mixer),
1080 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1081 msm8x10_wcd_get_iir_enable_audio_mixer,
1082 msm8x10_wcd_put_iir_enable_audio_mixer),
1083 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1084 msm8x10_wcd_get_iir_enable_audio_mixer,
1085 msm8x10_wcd_put_iir_enable_audio_mixer),
1086 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1087 msm8x10_wcd_get_iir_enable_audio_mixer,
1088 msm8x10_wcd_put_iir_enable_audio_mixer),
1089 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1090 msm8x10_wcd_get_iir_enable_audio_mixer,
1091 msm8x10_wcd_put_iir_enable_audio_mixer),
1092 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1093 msm8x10_wcd_get_iir_enable_audio_mixer,
1094 msm8x10_wcd_put_iir_enable_audio_mixer),
1095 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1096 msm8x10_wcd_get_iir_enable_audio_mixer,
1097 msm8x10_wcd_put_iir_enable_audio_mixer),
1098 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1099 msm8x10_wcd_get_iir_enable_audio_mixer,
1100 msm8x10_wcd_put_iir_enable_audio_mixer),
1101
1102 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1103 msm8x10_wcd_get_iir_band_audio_mixer,
1104 msm8x10_wcd_put_iir_band_audio_mixer),
1105 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1106 msm8x10_wcd_get_iir_band_audio_mixer,
1107 msm8x10_wcd_put_iir_band_audio_mixer),
1108 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1109 msm8x10_wcd_get_iir_band_audio_mixer,
1110 msm8x10_wcd_put_iir_band_audio_mixer),
1111 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1112 msm8x10_wcd_get_iir_band_audio_mixer,
1113 msm8x10_wcd_put_iir_band_audio_mixer),
1114 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1115 msm8x10_wcd_get_iir_band_audio_mixer,
1116 msm8x10_wcd_put_iir_band_audio_mixer),
1117 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1118 msm8x10_wcd_get_iir_band_audio_mixer,
1119 msm8x10_wcd_put_iir_band_audio_mixer),
1120 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1121 msm8x10_wcd_get_iir_band_audio_mixer,
1122 msm8x10_wcd_put_iir_band_audio_mixer),
1123 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1124 msm8x10_wcd_get_iir_band_audio_mixer,
1125 msm8x10_wcd_put_iir_band_audio_mixer),
1126 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1127 msm8x10_wcd_get_iir_band_audio_mixer,
1128 msm8x10_wcd_put_iir_band_audio_mixer),
1129 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1130 msm8x10_wcd_get_iir_band_audio_mixer,
1131 msm8x10_wcd_put_iir_band_audio_mixer),
1132
1133};
1134
1135static const char * const rx_mix1_text[] = {
1136 "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
1137};
1138
1139static const char * const rx_mix2_text[] = {
1140 "ZERO", "IIR1", "IIR2"
1141};
1142
1143static const char * const dec_mux_text[] = {
1144 "ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
1145};
1146
Kuirong Wang265f3592012-12-05 16:17:41 -08001147static const char * const anc_mux_text[] = {
1148 "ZERO", "ADC1", "ADC2", "ADC3", "ADC4", "ADC5", "ADC6", "ADC_MB",
1149 "RSVD_1", "DMIC1", "DMIC2", "DMIC3", "DMIC4", "DMIC5", "DMIC6"
1150};
1151
1152static const char * const anc1_fb_mux_text[] = {
1153 "ZERO", "EAR_HPH_L", "EAR_LINE_1",
1154};
1155
1156static const char * const iir1_inp1_text[] = {
1157 "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
1158};
1159
1160static const struct soc_enum rx_mix1_inp1_chain_enum =
1161 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
1162
1163static const struct soc_enum rx_mix1_inp2_chain_enum =
1164 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text);
1165
1166static const struct soc_enum rx_mix1_inp3_chain_enum =
1167 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text);
1168
1169static const struct soc_enum rx2_mix1_inp1_chain_enum =
1170 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text);
1171
1172static const struct soc_enum rx2_mix1_inp2_chain_enum =
1173 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text);
1174
1175static const struct soc_enum rx3_mix1_inp1_chain_enum =
1176 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text);
1177
1178static const struct soc_enum rx3_mix1_inp2_chain_enum =
1179 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text);
1180
1181static const struct soc_enum rx1_mix2_inp1_chain_enum =
1182 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
1183
1184static const struct soc_enum rx2_mix2_inp1_chain_enum =
1185 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
1186
1187static const struct soc_enum dec1_mux_enum =
1188 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 0, 5, dec_mux_text);
1189
1190static const struct soc_enum dec2_mux_enum =
1191 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 3, 5, dec_mux_text);
1192
1193static const struct soc_enum iir1_inp1_mux_enum =
1194 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
1195 iir1_inp1_text);
1196
1197static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1198 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1199
1200static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1201 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1202
1203static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1204 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1205
1206static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1207 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1208
1209static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1210 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1211
1212static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1213 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1214
1215static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1216 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1217
1218static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1219 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1220
1221static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1222 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1223
1224static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
1225 struct snd_ctl_elem_value *ucontrol)
1226{
1227 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1228 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1229 struct snd_soc_codec *codec = w->codec;
1230 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1231 unsigned int dec_mux, decimator;
1232 char *dec_name = NULL;
1233 char *widget_name = NULL;
1234 char *temp;
1235 u16 tx_mux_ctl_reg;
1236 u8 adc_dmic_sel = 0x0;
1237 int ret = 0;
1238
1239 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1240 return -EINVAL;
1241
1242 dec_mux = ucontrol->value.enumerated.item[0];
1243
1244 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1245 if (!widget_name)
1246 return -ENOMEM;
1247 temp = widget_name;
1248
1249 dec_name = strsep(&widget_name, " ");
1250 widget_name = temp;
1251 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001252 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1253 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001254 ret = -EINVAL;
1255 goto out;
1256 }
1257
1258 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1259 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001260 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1261 __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001262 ret = -EINVAL;
1263 goto out;
1264 }
1265
1266 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1267 , __func__, w->name, decimator, dec_mux);
1268
1269 switch (decimator) {
1270 case 1:
1271 case 2:
Kuirong Wang265f3592012-12-05 16:17:41 -08001272 adc_dmic_sel = 0x0;
1273 break;
1274 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001275 dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
1276 __func__, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001277 ret = -EINVAL;
1278 goto out;
1279 }
1280
1281 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
1282
1283 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1284
1285 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1286
1287out:
1288 kfree(widget_name);
1289 return ret;
1290}
1291
1292#define MSM8X10_WCD_DEC_ENUM(xname, xenum) \
1293{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1294 .info = snd_soc_info_enum_double, \
1295 .get = snd_soc_dapm_get_enum_double, \
1296 .put = msm8x10_wcd_put_dec_enum, \
1297 .private_value = (unsigned long)&xenum }
1298
1299static const struct snd_kcontrol_new dec1_mux =
1300 MSM8X10_WCD_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1301
1302static const struct snd_kcontrol_new dec2_mux =
1303 MSM8X10_WCD_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1304
1305static const struct snd_kcontrol_new iir1_inp1_mux =
1306 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1307
1308static const struct snd_kcontrol_new dac1_switch[] = {
1309 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_EAR_EN, 5, 1, 0)
1310};
1311static const struct snd_kcontrol_new hphl_switch[] = {
1312 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1313};
1314
Kuirong Wang265f3592012-12-05 16:17:41 -08001315static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
1316 int enable)
1317{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001318 struct msm8x10_wcd_priv *wcd8x10 = snd_soc_codec_get_drvdata(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08001319
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001320 dev_dbg(codec->dev, "%s %d\n", __func__, enable);
Kuirong Wang265f3592012-12-05 16:17:41 -08001321
1322 if (enable) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001323 wcd8x10->adc_count++;
Kuirong Wang265f3592012-12-05 16:17:41 -08001324 snd_soc_update_bits(codec,
1325 MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1326 0x20, 0x20);
1327 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001328 wcd8x10->adc_count--;
1329 if (!wcd8x10->adc_count)
Kuirong Wang265f3592012-12-05 16:17:41 -08001330 snd_soc_update_bits(codec,
1331 MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1332 0x20, 0x0);
1333 }
1334}
1335
1336static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
1337 struct snd_kcontrol *kcontrol, int event)
1338{
1339 struct snd_soc_codec *codec = w->codec;
1340 u16 adc_reg;
1341 u8 init_bit_shift;
1342
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001343 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001344 adc_reg = MSM8X10_WCD_A_TX_1_2_TEST_CTL;
1345
1346 if (w->reg == MSM8X10_WCD_A_TX_1_EN)
1347 init_bit_shift = 7;
Kuirong Wang91e52532013-03-31 14:24:22 -07001348 else if (w->reg == MSM8X10_WCD_A_TX_2_EN)
Kuirong Wang265f3592012-12-05 16:17:41 -08001349 init_bit_shift = 6;
1350 else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001351 dev_err(codec->dev, "%s: Error, invalid adc register\n",
1352 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001353 return -EINVAL;
1354 }
1355
1356 switch (event) {
1357 case SND_SOC_DAPM_PRE_PMU:
1358 msm8x10_wcd_codec_enable_adc_block(codec, 1);
1359 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1360 1 << init_bit_shift);
1361 break;
1362 case SND_SOC_DAPM_POST_PMU:
1363 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
1364 break;
1365 case SND_SOC_DAPM_POST_PMD:
1366 msm8x10_wcd_codec_enable_adc_block(codec, 0);
1367 break;
1368 }
1369 return 0;
1370}
1371
1372static int msm8x10_wcd_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1373 struct snd_kcontrol *kcontrol, int event)
1374{
1375 struct snd_soc_codec *codec = w->codec;
1376 u16 lineout_gain_reg;
1377
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001378 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001379
1380 switch (w->shift) {
1381 case 0:
1382 lineout_gain_reg = MSM8X10_WCD_A_RX_LINE_1_GAIN;
1383 break;
1384 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001385 dev_err(codec->dev,
1386 "%s: Error, incorrect lineout register value\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001387 __func__);
1388 return -EINVAL;
1389 }
1390
1391 switch (event) {
1392 case SND_SOC_DAPM_PRE_PMU:
1393 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1394 break;
1395 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001396 dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
1397 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001398 usleep_range(16000, 16100);
1399 break;
1400 case SND_SOC_DAPM_POST_PMD:
1401 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1402 break;
1403 }
1404 return 0;
1405}
1406
1407static int msm8x10_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1408 struct snd_kcontrol *kcontrol, int event)
1409{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001410 dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001411 return 0;
1412}
1413
1414static int msm8x10_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1415 struct snd_kcontrol *kcontrol, int event)
1416{
1417 struct snd_soc_codec *codec = w->codec;
1418 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1419 u8 dmic_clk_en;
1420 u16 dmic_clk_reg;
1421 s32 *dmic_clk_cnt;
1422 unsigned int dmic;
1423 int ret;
1424
1425 ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
1426 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001427 dev_err(codec->dev,
1428 "%s: Invalid DMIC line on the codec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001429 return -EINVAL;
1430 }
1431
1432 switch (dmic) {
1433 case 1:
1434 case 2:
1435 dmic_clk_en = 0x01;
1436 dmic_clk_cnt = &(msm8x10_wcd->dmic_1_2_clk_cnt);
1437 dmic_clk_reg = MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001438 dev_dbg(codec->dev,
1439 "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001440 __func__, event, dmic, *dmic_clk_cnt);
1441 break;
1442 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001443 dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001444 return -EINVAL;
1445 }
1446
1447 switch (event) {
1448 case SND_SOC_DAPM_PRE_PMU:
1449
1450 (*dmic_clk_cnt)++;
1451 if (*dmic_clk_cnt == 1)
1452 snd_soc_update_bits(codec, dmic_clk_reg,
1453 dmic_clk_en, dmic_clk_en);
1454 break;
1455 case SND_SOC_DAPM_POST_PMD:
1456
1457 (*dmic_clk_cnt)--;
1458 if (*dmic_clk_cnt == 0)
1459 snd_soc_update_bits(codec, dmic_clk_reg,
1460 dmic_clk_en, 0);
1461 break;
1462 }
1463 return 0;
1464}
1465
1466static int msm8x10_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1467 struct snd_kcontrol *kcontrol, int event)
1468{
1469 struct snd_soc_codec *codec = w->codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08001470 u16 micb_int_reg;
Kuirong Wang265f3592012-12-05 16:17:41 -08001471 char *internal1_text = "Internal1";
1472 char *internal2_text = "Internal2";
1473 char *internal3_text = "Internal3";
Kuirong Wang265f3592012-12-05 16:17:41 -08001474
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001475 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001476 switch (w->reg) {
1477 case MSM8X10_WCD_A_MICB_1_CTL:
1478 micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
Kuirong Wang265f3592012-12-05 16:17:41 -08001479 break;
1480 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001481 dev_err(codec->dev,
Kuirong Wang91e52532013-03-31 14:24:22 -07001482 "%s: Error, invalid micbias register 0x%x\n",
1483 __func__, w->reg);
Kuirong Wang265f3592012-12-05 16:17:41 -08001484 return -EINVAL;
1485 }
1486
1487 switch (event) {
1488 case SND_SOC_DAPM_PRE_PMU:
Kuirong Wang265f3592012-12-05 16:17:41 -08001489 if (strnstr(w->name, internal1_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001490 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
Kuirong Wang265f3592012-12-05 16:17:41 -08001491 else if (strnstr(w->name, internal2_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001492 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08001493 else if (strnstr(w->name, internal3_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001494 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
Kuirong Wang1756a7b2013-05-28 17:29:23 -07001495 snd_soc_update_bits(codec, w->reg, 0x1, 0x0);
Kuirong Wang265f3592012-12-05 16:17:41 -08001496 break;
1497 case SND_SOC_DAPM_POST_PMU:
1498 usleep_range(20000, 20100);
Kuirong Wang265f3592012-12-05 16:17:41 -08001499 break;
1500 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang265f3592012-12-05 16:17:41 -08001501 if (strnstr(w->name, internal1_text, 30))
1502 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1503 else if (strnstr(w->name, internal2_text, 30))
1504 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1505 else if (strnstr(w->name, internal3_text, 30))
1506 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1507
Kuirong Wang1756a7b2013-05-28 17:29:23 -07001508 snd_soc_update_bits(codec, w->reg, 0x1, 0x1);
Kuirong Wang265f3592012-12-05 16:17:41 -08001509 break;
1510 }
Kuirong Wang265f3592012-12-05 16:17:41 -08001511 return 0;
1512}
1513
Kuirong Wang91e52532013-03-31 14:24:22 -07001514static void tx_hpf_corner_freq_callback(struct work_struct *work)
1515{
1516 struct delayed_work *hpf_delayed_work;
1517 struct hpf_work *hpf_work;
1518 struct msm8x10_wcd_priv *msm8x10_wcd;
1519 struct snd_soc_codec *codec;
1520 u16 tx_mux_ctl_reg;
1521 u8 hpf_cut_of_freq;
1522
1523 hpf_delayed_work = to_delayed_work(work);
1524 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
1525 msm8x10_wcd = hpf_work->msm8x10_wcd;
1526 codec = hpf_work->msm8x10_wcd->codec;
1527 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
1528
1529 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1530 (hpf_work->decimator - 1) * 32;
1531
1532 dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
1533 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
1534
1535 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
1536}
1537
1538
Kuirong Wang265f3592012-12-05 16:17:41 -08001539#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
1540#define CF_MIN_3DB_4HZ 0x0
1541#define CF_MIN_3DB_75HZ 0x1
1542#define CF_MIN_3DB_150HZ 0x2
1543
1544static int msm8x10_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
1545 struct snd_kcontrol *kcontrol, int event)
1546{
1547 struct snd_soc_codec *codec = w->codec;
1548 unsigned int decimator;
1549 char *dec_name = NULL;
1550 char *widget_name = NULL;
1551 char *temp;
1552 int ret = 0;
1553 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
1554 u8 dec_hpf_cut_of_freq;
1555 int offset;
1556
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001557 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001558
1559 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1560 if (!widget_name)
1561 return -ENOMEM;
1562 temp = widget_name;
1563
1564 dec_name = strsep(&widget_name, " ");
1565 widget_name = temp;
1566 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001567 dev_err(codec->dev,
1568 "%s: Invalid decimator = %s\n", __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001569 ret = -EINVAL;
1570 goto out;
1571 }
1572
1573 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1574 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001575 dev_err(codec->dev,
1576 "%s: Invalid decimator = %s\n", __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001577 ret = -EINVAL;
1578 goto out;
1579 }
1580
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001581 dev_dbg(codec->dev,
1582 "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
1583 w->name, dec_name, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001584
1585 if (w->reg == MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
1586 dec_reset_reg = MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
1587 offset = 0;
1588 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001589 dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001590 ret = -EINVAL;
1591 goto out;
1592 }
1593
1594 tx_vol_ctl_reg = MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG +
1595 32 * (decimator - 1);
1596 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1597 32 * (decimator - 1);
1598
1599 switch (event) {
1600 case SND_SOC_DAPM_PRE_PMU:
1601 /* Enableable TX digital mute */
1602 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1603
1604 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1605 1 << w->shift);
1606 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1607
1608 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
1609
1610 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
1611
1612 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
1613 dec_hpf_cut_of_freq;
1614
1615 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
1616
1617 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
1618 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1619 CF_MIN_3DB_150HZ << 4);
1620 }
1621
1622 /* enable HPF */
1623 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
1624 break;
1625 case SND_SOC_DAPM_POST_PMU:
1626 /* Disable TX digital mute */
1627 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
1628
1629 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
1630 CF_MIN_3DB_150HZ) {
1631
1632 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
1633 msecs_to_jiffies(300));
1634 }
1635 /* apply the digital gain after the decimator is enabled*/
1636 if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
1637 snd_soc_write(codec,
1638 tx_digital_gain_reg[w->shift + offset],
1639 snd_soc_read(codec,
1640 tx_digital_gain_reg[w->shift + offset])
1641 );
1642 break;
1643 case SND_SOC_DAPM_PRE_PMD:
1644 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1645 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
1646 break;
1647 case SND_SOC_DAPM_POST_PMD:
1648 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
1649 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1650 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
1651 break;
1652 }
1653out:
1654 kfree(widget_name);
1655 return ret;
1656}
1657
1658static int msm8x10_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001659 struct snd_kcontrol *kcontrol,
1660 int event)
Kuirong Wang265f3592012-12-05 16:17:41 -08001661{
1662 struct snd_soc_codec *codec = w->codec;
1663
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001664 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001665
1666 switch (event) {
1667 case SND_SOC_DAPM_PRE_PMU:
1668 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1669 1 << w->shift, 1 << w->shift);
1670 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1671 1 << w->shift, 0x0);
1672 break;
1673 case SND_SOC_DAPM_POST_PMU:
1674 /* apply the digital gain after the interpolator is enabled*/
1675 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
1676 snd_soc_write(codec,
1677 rx_digital_gain_reg[w->shift],
1678 snd_soc_read(codec,
1679 rx_digital_gain_reg[w->shift])
1680 );
1681 break;
1682 }
1683 return 0;
1684}
1685
1686
1687/* The register address is the same as other codec so it can use resmgr */
1688static int msm8x10_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1689 struct snd_kcontrol *kcontrol, int event)
1690{
1691 struct snd_soc_codec *codec = w->codec;
1692 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Kuirong Wang91e52532013-03-31 14:24:22 -07001693 msm8x10_wcd->resmgr.codec = codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08001694
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001695 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001696
1697 switch (event) {
1698 case SND_SOC_DAPM_PRE_PMU:
1699 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 1);
1700 break;
1701 case SND_SOC_DAPM_POST_PMD:
1702 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 0);
1703 break;
1704 }
1705 return 0;
1706}
1707
1708static int msm8x10_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
1709 struct snd_kcontrol *kcontrol, int event)
1710{
1711 struct snd_soc_codec *codec = w->codec;
1712
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001713 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001714
1715 switch (event) {
1716 case SND_SOC_DAPM_PRE_PMU:
1717 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1718 break;
1719 case SND_SOC_DAPM_POST_PMD:
1720 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1721 break;
1722 }
1723 return 0;
1724}
1725
1726static int msm8x10_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
1727 struct snd_kcontrol *kcontrol, int event)
1728{
1729 struct snd_soc_codec *codec = w->codec;
1730 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1731 enum wcd9xxx_notify_event e_pre_on, e_post_off;
1732
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001733 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001734 if (w->shift == 5) {
1735 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
1736 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
1737 } else if (w->shift == 4) {
1738 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
1739 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
1740 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001741 dev_err(codec->dev,
1742 "%s: Invalid w->shift %d\n", __func__, w->shift);
Kuirong Wang265f3592012-12-05 16:17:41 -08001743 return -EINVAL;
1744 }
1745
1746 switch (event) {
1747 case SND_SOC_DAPM_PRE_PMU:
1748 /* Let MBHC module know PA is turning on */
1749 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
1750 break;
1751
1752 case SND_SOC_DAPM_POST_PMU:
1753 usleep_range(10000, 10100);
1754 break;
1755
1756 case SND_SOC_DAPM_POST_PMD:
1757 /* Let MBHC module know PA turned off */
1758 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
1759
1760 /*
1761 * schedule work is required because at the time HPH PA DAPM
1762 * event callback is called by DAPM framework, CODEC dapm mutex
1763 * would have been locked while snd_soc_jack_report also
1764 * attempts to acquire same lock.
1765 */
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001766 dev_dbg(codec->dev,
1767 "%s: sleep 10 ms after %s PA disable.\n", __func__,
1768 w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001769 usleep_range(10000, 10100);
1770 break;
1771 }
1772 return 0;
1773}
1774
1775static int msm8x10_wcd_lineout_dac_event(struct snd_soc_dapm_widget *w,
1776 struct snd_kcontrol *kcontrol, int event)
1777{
1778 struct snd_soc_codec *codec = w->codec;
1779
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001780 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001781
1782 switch (event) {
1783 case SND_SOC_DAPM_PRE_PMU:
1784 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1785 break;
1786
1787 case SND_SOC_DAPM_POST_PMD:
1788 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1789 break;
1790 }
1791 return 0;
1792}
1793
1794static int msm8x10_wcd_spk_dac_event(struct snd_soc_dapm_widget *w,
1795 struct snd_kcontrol *kcontrol, int event)
1796{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001797 dev_dbg(w->codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001798 return 0;
1799}
1800
1801static const struct snd_soc_dapm_route audio_map[] = {
1802 {"RX_I2S_CLK", NULL, "CDC_CONN"},
1803 {"I2S RX1", NULL, "RX_I2S_CLK"},
1804 {"I2S RX2", NULL, "RX_I2S_CLK"},
1805 {"I2S RX3", NULL, "RX_I2S_CLK"},
1806
1807 {"I2S TX1", NULL, "TX_I2S_CLK"},
1808 {"I2S TX2", NULL, "TX_I2S_CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001809
Kuirong Wang91e52532013-03-31 14:24:22 -07001810 {"I2S TX1", NULL, "DEC1 MUX"},
1811 {"I2S TX2", NULL, "DEC2 MUX"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001812
1813 /* Earpiece (RX MIX1) */
1814 {"EAR", NULL, "EAR PA"},
1815 {"EAR PA", NULL, "DAC1"},
1816 {"DAC1", NULL, "CP"},
1817
1818 /* Headset (RX MIX1 and RX MIX2) */
1819 {"HEADPHONE", NULL, "HPHL"},
1820 {"HEADPHONE", NULL, "HPHR"},
1821
1822 {"HPHL", NULL, "HPHL DAC"},
1823
1824 {"HPHR", NULL, "HPHR DAC"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001825
1826 {"HPHL DAC", NULL, "CP"},
1827
1828 {"HPHR DAC", NULL, "CP"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001829 {"SPK DAC", NULL, "CP"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001830
1831 {"DAC1", "Switch", "RX1 CHAIN"},
1832 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1833 {"HPHR DAC", NULL, "RX2 CHAIN"},
1834
Kuirong Wang91e52532013-03-31 14:24:22 -07001835 {"LINEOUT", NULL, "LINEOUT PA"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001836 {"SPK_OUT", NULL, "SPK PA"},
1837
Kuirong Wang91e52532013-03-31 14:24:22 -07001838 {"LINEOUT PA", NULL, "CP"},
1839 {"LINEOUT PA", NULL, "LINEOUT DAC"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001840
Kuirong Wang49f506a2013-05-22 17:38:26 -07001841 {"CP", NULL, "CP_REGULATOR"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001842 {"CP", NULL, "RX_BIAS"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001843 {"SPK PA", NULL, "SPK DAC"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001844 {"SPK DAC", NULL, "RX3 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001845
Kuirong Wang91e52532013-03-31 14:24:22 -07001846 {"RX1 CHAIN", NULL, "RX1 CLK"},
1847 {"RX2 CHAIN", NULL, "RX2 CLK"},
1848 {"RX3 CHAIN", NULL, "RX3 CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001849 {"RX1 CHAIN", NULL, "RX1 MIX2"},
1850 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001851 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001852
1853 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1854 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1855 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
1856 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1857 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
1858 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1859 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1860 {"RX1 MIX2", NULL, "RX1 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001861 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001862 {"RX2 MIX2", NULL, "RX2 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001863 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001864
1865 {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
1866 {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
1867 {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
1868 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1869 {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
1870 {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
1871 {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
1872 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1873 {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
1874 {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
1875 {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
1876
1877 {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
1878 {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
1879 {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
1880 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
1881 {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
1882 {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
1883 {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
1884 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
1885
1886 {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
1887 {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
1888 {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
1889 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
1890 {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
1891 {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
1892 {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
1893 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
1894
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001895 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
1896 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
1897
Kuirong Wang265f3592012-12-05 16:17:41 -08001898 /* Decimator Inputs */
1899 {"DEC1 MUX", "DMIC1", "DMIC1"},
1900 {"DEC1 MUX", "DMIC2", "DMIC2"},
1901 {"DEC1 MUX", "ADC1", "ADC1"},
1902 {"DEC1 MUX", "ADC2", "ADC2"},
1903 {"DEC1 MUX", NULL, "CDC_CONN"},
1904
1905 {"DEC2 MUX", "DMIC1", "DMIC1"},
1906 {"DEC2 MUX", "DMIC2", "DMIC2"},
1907 {"DEC2 MUX", "ADC1", "ADC1"},
1908 {"DEC2 MUX", "ADC2", "ADC2"},
1909 {"DEC2 MUX", NULL, "CDC_CONN"},
1910
1911 /* ADC Connections */
1912 {"ADC1", NULL, "AMIC1"},
1913 {"ADC2", NULL, "AMIC2"},
1914
1915 {"IIR1", NULL, "IIR1 INP1 MUX"},
1916 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
1917 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
quic_yandongy7424f1a2013-05-16 22:41:33 +08001918 {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001919 {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
1920 {"MIC BIAS External", NULL, "INT_LDO_H"},
Kuirong Wang49f506a2013-05-22 17:38:26 -07001921 {"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
1922 {"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
1923 {"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001924};
1925
Kuirong Wang265f3592012-12-05 16:17:41 -08001926static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
1927 struct snd_soc_dai *dai)
1928{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001929 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
1930 __func__,
1931 substream->name, substream->stream);
Kuirong Wang265f3592012-12-05 16:17:41 -08001932 return 0;
1933}
1934
1935static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
1936 struct snd_soc_dai *dai)
1937{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001938 dev_dbg(dai->codec->dev,
1939 "%s(): substream = %s stream = %d\n" , __func__,
1940 substream->name, substream->stream);
Kuirong Wang91e52532013-03-31 14:24:22 -07001941}
1942
1943static int msm8x10_wcd_codec_enable_clock_block(struct snd_soc_codec *codec,
1944 int enable)
1945{
1946 if (enable) {
1947 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_MCLK_CTL,
1948 0x01, 0x01);
1949 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
1950 0x03, 0x03);
1951 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
1952 0x0f, 0x0d);
1953 } else {
1954 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL,
1955 0x0f, 0x00);
Kuirong Wangf1ab8352013-05-20 12:22:37 -07001956 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_PDM_CTL,
Kuirong Wang91e52532013-03-31 14:24:22 -07001957 0x03, 0x00);
Kuirong Wang265f3592012-12-05 16:17:41 -08001958 }
Kuirong Wang91e52532013-03-31 14:24:22 -07001959 return 0;
1960}
1961
1962static void msm8x10_wcd_codec_enable_audio_mode_bandgap(struct snd_soc_codec
1963 *codec)
1964{
1965 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
1966 0x80);
1967 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x04,
1968 0x04);
1969 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x01,
1970 0x01);
1971 usleep_range(1000, 1000);
1972 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x80,
1973 0x00);
1974}
1975
1976static void msm8x10_wcd_codec_enable_bandgap(struct snd_soc_codec *codec,
1977 enum msm8x10_wcd_bandgap_type choice)
1978{
1979 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1980
1981 /* TODO lock resources accessed by audio streams and threaded
1982 * interrupt handlers
1983 */
1984
1985 dev_dbg(codec->dev, "%s, choice is %d, current is %d\n",
1986 __func__, choice,
1987 msm8x10_wcd->bandgap_type);
1988
1989 if (msm8x10_wcd->bandgap_type == choice)
1990 return;
1991
1992 if ((msm8x10_wcd->bandgap_type == MSM8X10_WCD_BANDGAP_OFF) &&
1993 (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
1994 msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
1995 } else if (choice == MSM8X10_WCD_BANDGAP_MBHC_MODE) {
1996 /* bandgap mode becomes fast,
1997 * mclk should be off or clk buff source souldn't be VBG
1998 * Let's turn off mclk always */
1999 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
2000 0x2, 0x2);
2001 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
2002 0x80, 0x80);
2003 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
2004 0x4, 0x4);
2005 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
2006 0x01, 0x01);
2007 usleep_range(1000, 1000);
2008 snd_soc_update_bits(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL,
2009 0x80, 0x00);
2010 } else if ((msm8x10_wcd->bandgap_type ==
2011 MSM8X10_WCD_BANDGAP_MBHC_MODE) &&
2012 (choice == MSM8X10_WCD_BANDGAP_AUDIO_MODE)) {
2013 snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
2014 usleep_range(100, 100);
2015 msm8x10_wcd_codec_enable_audio_mode_bandgap(codec);
2016 } else if (choice == MSM8X10_WCD_BANDGAP_OFF) {
2017 snd_soc_write(codec, MSM8X10_WCD_A_BIAS_CENTRAL_BG_CTL, 0x50);
2018 } else {
2019 dev_err(codec->dev,
2020 "%s: Error, Invalid bandgap settings\n", __func__);
2021 }
2022 msm8x10_wcd->bandgap_type = choice;
Kuirong Wang265f3592012-12-05 16:17:41 -08002023}
2024
2025int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
2026 int mclk_enable, bool dapm)
2027{
2028 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
2029
Kuirong Wang91e52532013-03-31 14:24:22 -07002030 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
2031 __func__, mclk_enable, dapm);
2032 if (dapm)
2033 MSM8X10_WCD_ACQUIRE_LOCK(msm8x10_wcd->codec_resource_lock);
Kuirong Wang265f3592012-12-05 16:17:41 -08002034 if (mclk_enable) {
Kuirong Wang91e52532013-03-31 14:24:22 -07002035 msm8x10_wcd->mclk_enabled = true;
2036 msm8x10_wcd_codec_enable_bandgap(codec,
2037 MSM8X10_WCD_BANDGAP_AUDIO_MODE);
2038 msm8x10_wcd_codec_enable_clock_block(codec, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -08002039 } else {
Kuirong Wang91e52532013-03-31 14:24:22 -07002040 if (!msm8x10_wcd->mclk_enabled) {
2041 if (dapm)
2042 MSM8X10_WCD_RELEASE_LOCK(
2043 msm8x10_wcd->codec_resource_lock);
2044 dev_err(codec->dev, "Error, MCLK already diabled\n");
2045 return -EINVAL;
2046 }
2047 msm8x10_wcd->mclk_enabled = false;
2048 msm8x10_wcd_codec_enable_clock_block(codec, 0);
2049 msm8x10_wcd_codec_enable_bandgap(codec,
2050 MSM8X10_WCD_BANDGAP_OFF);
Kuirong Wang265f3592012-12-05 16:17:41 -08002051 }
Kuirong Wang91e52532013-03-31 14:24:22 -07002052 if (dapm)
2053 MSM8X10_WCD_RELEASE_LOCK(msm8x10_wcd->codec_resource_lock);
Kuirong Wang265f3592012-12-05 16:17:41 -08002054 return 0;
2055}
2056
2057static int msm8x10_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
2058 int clk_id, unsigned int freq, int dir)
2059{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002060 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002061 return 0;
2062}
2063
2064static int msm8x10_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2065{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002066 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002067 return 0;
2068}
2069
2070static int msm8x10_wcd_set_channel_map(struct snd_soc_dai *dai,
2071 unsigned int tx_num, unsigned int *tx_slot,
2072 unsigned int rx_num, unsigned int *rx_slot)
2073
2074{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002075 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002076 return 0;
2077}
2078
2079static int msm8x10_wcd_get_channel_map(struct snd_soc_dai *dai,
2080 unsigned int *tx_num, unsigned int *tx_slot,
2081 unsigned int *rx_num, unsigned int *rx_slot)
2082
2083{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002084 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002085 return 0;
2086}
2087
2088static int msm8x10_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
2089 u8 rx_fs_rate_reg_val, u32 sample_rate)
2090{
2091 return 0;
2092}
2093
2094static int msm8x10_wcd_set_decimator_rate(struct snd_soc_dai *dai,
2095 u8 tx_fs_rate_reg_val, u32 sample_rate)
2096{
2097 return 0;
2098}
2099
2100static int msm8x10_wcd_hw_params(struct snd_pcm_substream *substream,
2101 struct snd_pcm_hw_params *params,
2102 struct snd_soc_dai *dai)
2103{
2104 u8 tx_fs_rate, rx_fs_rate;
2105 int ret;
2106
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002107 dev_dbg(dai->codec->dev,
2108 "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002109 dai->name, dai->id, params_rate(params),
2110 params_channels(params));
2111
2112 switch (params_rate(params)) {
2113 case 8000:
2114 tx_fs_rate = 0x00;
2115 rx_fs_rate = 0x00;
2116 break;
2117 case 16000:
2118 tx_fs_rate = 0x01;
2119 rx_fs_rate = 0x20;
2120 break;
2121 case 32000:
2122 tx_fs_rate = 0x02;
2123 rx_fs_rate = 0x40;
2124 break;
2125 case 48000:
2126 tx_fs_rate = 0x03;
2127 rx_fs_rate = 0x60;
2128 break;
2129 case 96000:
2130 tx_fs_rate = 0x04;
2131 rx_fs_rate = 0x80;
2132 break;
2133 case 192000:
2134 tx_fs_rate = 0x05;
2135 rx_fs_rate = 0xA0;
2136 break;
2137 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002138 dev_err(dai->codec->dev,
2139 "%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002140 params_rate(params));
2141 return -EINVAL;
2142 }
2143
2144 switch (substream->stream) {
2145 case SNDRV_PCM_STREAM_CAPTURE:
2146 ret = msm8x10_wcd_set_decimator_rate(dai, tx_fs_rate,
2147 params_rate(params));
2148 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002149 dev_err(dai->codec->dev,
2150 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002151 ret);
2152 return ret;
2153 }
2154 break;
2155 case SNDRV_PCM_STREAM_PLAYBACK:
2156 ret = msm8x10_wcd_set_interpolator_rate(dai, rx_fs_rate,
2157 params_rate(params));
2158 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002159 dev_err(dai->codec->dev,
2160 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002161 ret);
2162 return ret;
2163 }
2164 break;
2165 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002166 dev_err(dai->codec->dev,
2167 "%s: Invalid stream type %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002168 substream->stream);
2169 return -EINVAL;
2170 }
2171
2172 return 0;
2173}
2174
2175static struct snd_soc_dai_ops msm8x10_wcd_dai_ops = {
2176 .startup = msm8x10_wcd_startup,
2177 .shutdown = msm8x10_wcd_shutdown,
2178 .hw_params = msm8x10_wcd_hw_params,
2179 .set_sysclk = msm8x10_wcd_set_dai_sysclk,
2180 .set_fmt = msm8x10_wcd_set_dai_fmt,
2181 .set_channel_map = msm8x10_wcd_set_channel_map,
2182 .get_channel_map = msm8x10_wcd_get_channel_map,
2183};
2184
2185static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[] = {
2186 {
2187 .name = "msm8x10_wcd_i2s_rx1",
2188 .id = AIF1_PB,
2189 .playback = {
2190 .stream_name = "AIF1 Playback",
2191 .rates = MSM8X10_WCD_RATES,
2192 .formats = MSM8X10_WCD_FORMATS,
2193 .rate_max = 192000,
2194 .rate_min = 8000,
2195 .channels_min = 1,
Kuirong Wang91e52532013-03-31 14:24:22 -07002196 .channels_max = 3,
Kuirong Wang265f3592012-12-05 16:17:41 -08002197 },
2198 .ops = &msm8x10_wcd_dai_ops,
2199 },
2200 {
2201 .name = "msm8x10_wcd_i2s_tx1",
2202 .id = AIF1_CAP,
2203 .capture = {
2204 .stream_name = "AIF1 Capture",
2205 .rates = MSM8X10_WCD_RATES,
2206 .formats = MSM8X10_WCD_FORMATS,
2207 .rate_max = 192000,
2208 .rate_min = 8000,
2209 .channels_min = 1,
2210 .channels_max = 4,
2211 },
2212 .ops = &msm8x10_wcd_dai_ops,
2213 },
2214};
2215
2216static int msm8x10_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
2217 struct snd_kcontrol *kcontrol, int event)
2218{
2219 switch (event) {
2220 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002221 dev_dbg(w->codec->dev,
2222 "%s: Sleeping 20ms after enabling EAR PA\n",
2223 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002224 msleep(20);
2225 break;
2226 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002227 dev_dbg(w->codec->dev,
2228 "%s: Sleeping 20ms after disabling EAR PA\n",
2229 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002230 msleep(20);
2231 break;
2232 }
2233 return 0;
2234}
2235
2236static const struct snd_soc_dapm_widget msm8x10_wcd_dapm_widgets[] = {
2237 /*RX stuff */
2238 SND_SOC_DAPM_OUTPUT("EAR"),
2239
2240 SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
2241 msm8x10_wcd_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
2242
2243 SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
2244 ARRAY_SIZE(dac1_switch)),
2245
Kuirong Wang91e52532013-03-31 14:24:22 -07002246 SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002247
Kuirong Wang91e52532013-03-31 14:24:22 -07002248 SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002249
Kuirong Wang91e52532013-03-31 14:24:22 -07002250 SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002251
Kuirong Wang91e52532013-03-31 14:24:22 -07002252 SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
2253
Kuirong Wang265f3592012-12-05 16:17:41 -08002254 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2255 SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2256 5, 0, NULL, 0,
2257 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2258 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2259 SND_SOC_DAPM_MIXER("HPHL DAC", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL,
2260 7, 0,
2261 hphl_switch, ARRAY_SIZE(hphl_switch)),
2262
2263 SND_SOC_DAPM_PGA_E("HPHR", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2264 4, 0, NULL, 0,
2265 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2266 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2267
2268 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, MSM8X10_WCD_A_RX_HPH_R_DAC_CTL,
2269 7, 0,
2270 msm8x10_wcd_hphr_dac_event,
2271 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2272
2273 /* Speaker */
Kuirong Wang91e52532013-03-31 14:24:22 -07002274 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002275 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
2276
Kuirong Wang91e52532013-03-31 14:24:22 -07002277 SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
Kuirong Wang265f3592012-12-05 16:17:41 -08002278 0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
2279 SND_SOC_DAPM_PRE_PMU |
2280 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2281
2282 SND_SOC_DAPM_PGA_E("SPK PA", MSM8X10_WCD_A_SPKR_DRV_EN,
2283 7, 0 , NULL, 0, msm8x10_wcd_codec_enable_spk_pa,
2284 SND_SOC_DAPM_PRE_PMU |
2285 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2286
Kuirong Wang91e52532013-03-31 14:24:22 -07002287 SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
Kuirong Wang265f3592012-12-05 16:17:41 -08002288 MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
2289 msm8x10_wcd_lineout_dac_event,
2290 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2291
2292 SND_SOC_DAPM_DAC_E("SPK DAC", NULL, SND_SOC_NOPM, 0, 0,
2293 msm8x10_wcd_spk_dac_event,
2294 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2295
2296 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2297 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2298
2299 SND_SOC_DAPM_MIXER_E("RX1 MIX2",
2300 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
2301 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2302 SND_SOC_DAPM_POST_PMU),
2303 SND_SOC_DAPM_MIXER_E("RX2 MIX2",
2304 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
2305 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2306 SND_SOC_DAPM_POST_PMU),
2307 SND_SOC_DAPM_MIXER_E("RX3 MIX1",
2308 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
2309 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2310 SND_SOC_DAPM_POST_PMU),
2311
Kuirong Wang91e52532013-03-31 14:24:22 -07002312 SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2313 0, 0, NULL, 0),
2314 SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2315 1, 0, NULL, 0),
2316 SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2317 2, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002318 SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
2319 5, 0, NULL, 0),
2320 SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
2321 5, 0, NULL, 0),
Kuirong Wang91e52532013-03-31 14:24:22 -07002322 SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
2323 5, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002324
2325 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2326 &rx_mix1_inp1_mux),
2327 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2328 &rx_mix1_inp2_mux),
2329 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
2330 &rx_mix1_inp3_mux),
2331 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2332 &rx2_mix1_inp1_mux),
2333 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2334 &rx2_mix1_inp2_mux),
2335 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2336 &rx3_mix1_inp1_mux),
2337 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2338 &rx3_mix1_inp2_mux),
2339 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2340 &rx1_mix2_inp1_mux),
2341 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2342 &rx2_mix2_inp1_mux),
2343
Kuirong Wang49f506a2013-05-22 17:38:26 -07002344 SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
2345 ON_DEMAND_MICBIAS, 0,
2346 msm8x10_wcd_codec_enable_on_demand_supply,
2347 SND_SOC_DAPM_PRE_PMU |
2348 SND_SOC_DAPM_POST_PMD),
2349
2350 SND_SOC_DAPM_SUPPLY("CP_REGULATOR", SND_SOC_NOPM,
2351 ON_DEMAND_CP, 0,
2352 msm8x10_wcd_codec_enable_on_demand_supply,
2353 SND_SOC_DAPM_PRE_PMU |
2354 SND_SOC_DAPM_POST_PMD),
2355
Kuirong Wang265f3592012-12-05 16:17:41 -08002356 SND_SOC_DAPM_SUPPLY("CP", MSM8X10_WCD_A_CP_EN, 0, 0,
Kuirong Wang49f506a2013-05-22 17:38:26 -07002357 msm8x10_wcd_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2358 SND_SOC_DAPM_PRE_PMD),
Kuirong Wang265f3592012-12-05 16:17:41 -08002359
2360 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2361 msm8x10_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2362 SND_SOC_DAPM_POST_PMD),
2363
2364 /* TX */
2365
2366 SND_SOC_DAPM_SUPPLY("CDC_CONN", MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
2367 2, 0, NULL, 0),
2368
2369
2370 SND_SOC_DAPM_INPUT("AMIC1"),
Kuirong Wang91e52532013-03-31 14:24:22 -07002371 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
Kuirong Wang265f3592012-12-05 16:17:41 -08002372 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2373 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2374 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002375 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
Kuirong Wang265f3592012-12-05 16:17:41 -08002376 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2377 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2378 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002379 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
Kuirong Wang265f3592012-12-05 16:17:41 -08002380 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2381 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2382 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2383 SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
2384 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2385 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002386 SND_SOC_DAPM_ADC_E("ADC2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
Kuirong Wang265f3592012-12-05 16:17:41 -08002387 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2388 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2389
Kuirong Wang91e52532013-03-31 14:24:22 -07002390 SND_SOC_DAPM_MICBIAS("MIC BIAS External", MSM8X10_WCD_A_MICB_1_CTL,
2391 7, 0),
2392
Kuirong Wang265f3592012-12-05 16:17:41 -08002393 SND_SOC_DAPM_INPUT("AMIC3"),
2394
2395 SND_SOC_DAPM_MUX_E("DEC1 MUX",
2396 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
2397 &dec1_mux, msm8x10_wcd_codec_enable_dec,
2398 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2399 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2400
2401 SND_SOC_DAPM_MUX_E("DEC2 MUX",
2402 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
2403 &dec2_mux, msm8x10_wcd_codec_enable_dec,
2404 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2405 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2406
2407 SND_SOC_DAPM_INPUT("AMIC2"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002408
Kuirong Wang91e52532013-03-31 14:24:22 -07002409 SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
2410 0, 0),
2411 SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
2412 0, 0),
2413 SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
2414 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002415
2416 /* Digital Mic Inputs */
2417 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2418 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2419 SND_SOC_DAPM_POST_PMD),
2420
2421 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2422 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2423 SND_SOC_DAPM_POST_PMD),
2424
2425 /* Sidetone */
2426 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2427 SND_SOC_DAPM_PGA("IIR1", MSM8X10_WCD_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2428
2429 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL,
2430 4, 0, NULL, 0),
2431 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL, 4,
2432 0, NULL, 0),
2433};
2434
2435static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
2436
2437 /* set MCLk to 9.6 */
Kuirong Wang91e52532013-03-31 14:24:22 -07002438 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
Kuirong Wang265f3592012-12-05 16:17:41 -08002439
2440 /* EAR PA deafults */
2441 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
2442
2443 /* RX deafults */
2444 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B5_CTL, 0x78),
2445 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B5_CTL, 0x78),
2446 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B5_CTL, 0x78),
2447
2448 /* RX1 and RX2 defaults */
2449 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xA0),
2450 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xA0),
2451
2452 /* RX3 to RX7 defaults */
2453 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B6_CTL, 0x80),
2454
2455 /* Reduce HPH DAC bias to 70% */
2456 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_HPH_BIAS_PA, 0x7A),
2457 /*Reduce EAR DAC bias to 70% */
2458 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_BIAS_PA, 0x76),
2459 /* Reduce LINE DAC bias to 70% */
2460 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
2461
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002462 /* Disable internal biasing path which can cause leakage */
Kuirong Wang91e52532013-03-31 14:24:22 -07002463 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
2464 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002465 /* Enable pulldown to reduce leakage */
2466 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x83),
Kuirong Wang91e52532013-03-31 14:24:22 -07002467 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
2468 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
2469 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
Kuirong Wang269ae352013-05-23 11:31:58 -07002470
2471 /* ClassG fine tuning setting for 16 ohm HPH */
2472 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL, 0x05),
2473 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL, 0x0C),
2474 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1A),
2475 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x47),
2476 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL, 0x23),
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002477
2478 /* Always set TXD_CLK_EN bit to reduce the leakage */
2479 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
Kuirong Wang265f3592012-12-05 16:17:41 -08002480};
2481
2482static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
2483{
2484 u32 i;
2485
2486 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_reg_defaults); i++)
2487 snd_soc_write(codec, msm8x10_wcd_reg_defaults[i].reg,
2488 msm8x10_wcd_reg_defaults[i].val);
2489}
2490
2491static const struct msm8x10_wcd_reg_mask_val
2492 msm8x10_wcd_codec_reg_init_val[] = {
2493 /* Initialize current threshold to 350MA
2494 * number of wait and run cycles to 4096
2495 */
2496 {MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
2497 {MSM8X10_WCD_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
2498
2499 /* Initialize gain registers to use register gain */
2500 {MSM8X10_WCD_A_RX_HPH_L_GAIN, 0x20, 0x20},
2501 {MSM8X10_WCD_A_RX_HPH_R_GAIN, 0x20, 0x20},
2502 {MSM8X10_WCD_A_RX_LINE_1_GAIN, 0x20, 0x20},
2503
2504 /*enable HPF filter for TX paths */
2505 {MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
2506 {MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
2507
2508 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
2509 {MSM8X10_WCD_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
2510 {MSM8X10_WCD_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
2511
2512 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
2513 {MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
2514
2515};
2516
2517static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
2518{
2519 u32 i;
2520
2521 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_codec_reg_init_val); i++)
2522 snd_soc_update_bits(codec,
2523 msm8x10_wcd_codec_reg_init_val[i].reg,
2524 msm8x10_wcd_codec_reg_init_val[i].mask,
2525 msm8x10_wcd_codec_reg_init_val[i].val);
2526}
2527
2528int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
2529 struct msm8x10_wcd_mbhc_config *mbhc_cfg)
2530{
2531 return 0;
2532}
2533EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
2534
Kuirong Wang2e81d322013-05-30 17:52:36 -07002535static int msm8x10_wcd_bringup(struct snd_soc_codec *codec)
2536{
2537 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
2538 snd_soc_write(codec, MSM8X10_WCD_A_CHIP_CTL, 0x00);
2539 usleep_range(5000, 5000);
2540 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
2541 return 0;
2542}
2543
Kuirong Wang49f506a2013-05-22 17:38:26 -07002544static struct regulator *wcd8x10_wcd_codec_find_regulator(
2545 const struct msm8x10_wcd *msm8x10,
2546 const char *name)
2547{
2548 int i;
2549
2550 for (i = 0; i < msm8x10->num_of_supplies; i++) {
2551 if (msm8x10->supplies[i].supply &&
2552 !strncmp(msm8x10->supplies[i].supply, name, strlen(name)))
2553 return msm8x10->supplies[i].consumer;
2554 }
2555
2556 return NULL;
2557}
2558
Fred Ohcf2f8582013-06-13 18:32:07 -07002559static int msm8x10_wcd_device_up(struct snd_soc_codec *codec)
2560{
2561 pr_debug("%s: device up!\n", __func__);
2562
2563 mutex_lock(&codec->mutex);
2564
2565 msm8x10_wcd_bringup(codec);
2566 msm8x10_wcd_codec_init_reg(codec);
2567 msm8x10_wcd_update_reg_defaults(codec);
2568
2569 mutex_unlock(&codec->mutex);
2570
2571 return 0;
2572}
2573
2574static int adsp_state_callback(struct notifier_block *nb, unsigned long value,
2575 void *priv)
2576{
2577 bool timedout;
2578 unsigned long timeout;
2579
2580 if (value == SUBSYS_AFTER_POWERUP) {
2581 pr_debug("%s: ADSP is about to power up. bring up codec\n",
2582 __func__);
2583
2584 timeout = jiffies +
2585 msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
2586 while (!(timedout = time_after(jiffies, timeout))) {
2587 if (!q6core_is_adsp_ready()) {
2588 pr_debug("%s: ADSP isn't ready\n", __func__);
2589 } else {
2590 pr_debug("%s: ADSP is ready\n", __func__);
2591 msm8x10_wcd_device_up(registered_codec);
2592 break;
2593 }
2594 }
2595 }
2596
2597 return NOTIFY_OK;
2598}
2599
2600static struct notifier_block adsp_state_notifier_block = {
2601 .notifier_call = adsp_state_callback,
2602 .priority = -INT_MAX,
2603};
2604
2605
Kuirong Wang265f3592012-12-05 16:17:41 -08002606static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
2607{
Kuirong Wang91e52532013-03-31 14:24:22 -07002608 struct msm8x10_wcd_priv *msm8x10_wcd;
2609 int i;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002610 dev_dbg(codec->dev, "%s()\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002611
Kuirong Wang91e52532013-03-31 14:24:22 -07002612 msm8x10_wcd = kzalloc(sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
2613 if (!msm8x10_wcd) {
2614 dev_err(codec->dev, "Failed to allocate private data\n");
2615 return -ENOMEM;
2616 }
2617
2618 for (i = 0 ; i < NUM_DECIMATORS; i++) {
2619 tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd;
2620 tx_hpf_work[i].decimator = i + 1;
2621 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
2622 tx_hpf_corner_freq_callback);
2623 }
2624
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002625 codec->control_data = dev_get_drvdata(codec->dev);
Kuirong Wang91e52532013-03-31 14:24:22 -07002626 snd_soc_codec_set_drvdata(codec, msm8x10_wcd);
2627 msm8x10_wcd->codec = codec;
Kuirong Wang2e81d322013-05-30 17:52:36 -07002628 msm8x10_wcd_bringup(codec);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002629 msm8x10_wcd_codec_init_reg(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08002630 msm8x10_wcd_update_reg_defaults(codec);
Kuirong Wang49f506a2013-05-22 17:38:26 -07002631 msm8x10_wcd->on_demand_list[ON_DEMAND_CP].supply =
2632 wcd8x10_wcd_codec_find_regulator(
2633 codec->control_data,
2634 on_demand_supply_name[ON_DEMAND_CP]);
2635 atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_CP].ref, 0);
2636 msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].supply =
2637 wcd8x10_wcd_codec_find_regulator(
2638 codec->control_data,
2639 on_demand_supply_name[ON_DEMAND_MICBIAS]);
2640 atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
Kuirong Wang91e52532013-03-31 14:24:22 -07002641 msm8x10_wcd->mclk_enabled = false;
2642 msm8x10_wcd->bandgap_type = MSM8X10_WCD_BANDGAP_OFF;
2643 msm8x10_wcd->clock_active = false;
2644 msm8x10_wcd->config_mode_active = false;
2645 msm8x10_wcd->mbhc_polling_active = false;
2646 mutex_init(&msm8x10_wcd->codec_resource_lock);
Kuirong Wang265f3592012-12-05 16:17:41 -08002647
Fred Ohcf2f8582013-06-13 18:32:07 -07002648 registered_codec = codec;
2649 adsp_state_notifier =
2650 subsys_notif_register_notifier("adsp",
2651 &adsp_state_notifier_block);
2652 if (!adsp_state_notifier) {
2653 pr_err("%s: Failed to register adsp state notifier\n",
2654 __func__);
2655 registered_codec = NULL;
2656 return -ENOMEM;
2657 }
Kuirong Wang265f3592012-12-05 16:17:41 -08002658 return 0;
2659}
2660
2661static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
2662{
Kuirong Wang49f506a2013-05-22 17:38:26 -07002663 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
2664 msm8x10_wcd->on_demand_list[ON_DEMAND_CP].supply = NULL;
2665 atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_CP].ref, 0);
2666 msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
2667 atomic_set(&msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
Kuirong Wang265f3592012-12-05 16:17:41 -08002668 return 0;
2669}
2670
2671static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
2672 .probe = msm8x10_wcd_codec_probe,
2673 .remove = msm8x10_wcd_codec_remove,
2674
2675 .read = msm8x10_wcd_read,
2676 .write = msm8x10_wcd_write,
2677
2678 .readable_register = msm8x10_wcd_readable,
2679 .volatile_register = msm8x10_wcd_volatile,
2680
2681 .reg_cache_size = MSM8X10_WCD_CACHE_SIZE,
2682 .reg_cache_default = msm8x10_wcd_reset_reg_defaults,
2683 .reg_word_size = 1,
2684
2685 .controls = msm8x10_wcd_snd_controls,
2686 .num_controls = ARRAY_SIZE(msm8x10_wcd_snd_controls),
2687 .dapm_widgets = msm8x10_wcd_dapm_widgets,
2688 .num_dapm_widgets = ARRAY_SIZE(msm8x10_wcd_dapm_widgets),
2689 .dapm_routes = audio_map,
2690 .num_dapm_routes = ARRAY_SIZE(audio_map),
2691};
2692
Kuirong Wang49f506a2013-05-22 17:38:26 -07002693static int msm8x10_wcd_init_supplies(struct msm8x10_wcd *msm8x10,
Kuirong Wang91e52532013-03-31 14:24:22 -07002694 struct msm8x10_wcd_pdata *pdata)
2695{
2696 int ret;
2697 int i;
2698 msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
2699 ARRAY_SIZE(pdata->regulator),
2700 GFP_KERNEL);
2701 if (!msm8x10->supplies) {
2702 ret = -ENOMEM;
2703 goto err;
2704 }
2705
2706 msm8x10->num_of_supplies = 0;
2707
2708 if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
2709 dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
2710 __func__);
2711 ret = -EINVAL;
2712 goto err;
2713 }
2714
2715 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
2716 if (pdata->regulator[i].name) {
2717 msm8x10->supplies[i].supply = pdata->regulator[i].name;
2718 msm8x10->num_of_supplies++;
2719 }
2720 }
2721
2722 ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
2723 msm8x10->supplies);
2724 if (ret != 0) {
2725 dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
2726 ret);
2727 goto err_supplies;
2728 }
2729
2730 for (i = 0; i < msm8x10->num_of_supplies; i++) {
Kuirong Wang49f506a2013-05-22 17:38:26 -07002731 if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
2732 0)
2733 continue;
2734
Kuirong Wang91e52532013-03-31 14:24:22 -07002735 ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
Kuirong Wang49f506a2013-05-22 17:38:26 -07002736 pdata->regulator[i].min_uV,
2737 pdata->regulator[i].max_uV);
Kuirong Wang91e52532013-03-31 14:24:22 -07002738 if (ret) {
2739 dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
2740 __func__, msm8x10->supplies[i].supply, ret);
2741 goto err_get;
2742 }
2743
2744 ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
2745 pdata->regulator[i].optimum_uA);
2746 if (ret < 0) {
2747 dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
2748 __func__, msm8x10->supplies[i].supply, ret);
2749 goto err_get;
Kuirong Wang49f506a2013-05-22 17:38:26 -07002750 } else {
2751 ret = 0;
Kuirong Wang91e52532013-03-31 14:24:22 -07002752 }
2753 }
2754
Kuirong Wang91e52532013-03-31 14:24:22 -07002755 return ret;
2756
Kuirong Wang91e52532013-03-31 14:24:22 -07002757err_get:
2758 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
2759err_supplies:
2760 kfree(msm8x10->supplies);
2761err:
2762 return ret;
2763}
2764
Kuirong Wang49f506a2013-05-22 17:38:26 -07002765static int msm8x10_wcd_enable_static_supplies(struct msm8x10_wcd *msm8x10,
2766 struct msm8x10_wcd_pdata *pdata)
2767{
2768 int i;
2769 int ret = 0;
2770
2771 for (i = 0; i < msm8x10->num_of_supplies; i++) {
2772 if (pdata->regulator[i].ondemand)
2773 continue;
2774 ret = regulator_enable(msm8x10->supplies[i].consumer);
2775 if (ret) {
2776 pr_err("%s: Failed to enable %s\n", __func__,
2777 msm8x10->supplies[i].supply);
2778 break;
2779 } else {
2780 pr_debug("%s: Enabled regulator %s\n", __func__,
2781 msm8x10->supplies[i].supply);
2782 }
2783 }
2784
2785 while (ret && --i)
2786 if (!pdata->regulator[i].ondemand)
2787 regulator_disable(msm8x10->supplies[i].consumer);
2788
2789 return ret;
2790}
2791
2792
2793
Kuirong Wang91e52532013-03-31 14:24:22 -07002794static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
2795 struct msm8x10_wcd_pdata *pdata)
2796{
2797 int i;
2798
2799 regulator_bulk_disable(msm8x10->num_of_supplies,
2800 msm8x10->supplies);
2801 for (i = 0; i < msm8x10->num_of_supplies; i++) {
Kuirong Wang49f506a2013-05-22 17:38:26 -07002802 if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
2803 0)
2804 continue;
Kuirong Wang91e52532013-03-31 14:24:22 -07002805 regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
2806 pdata->regulator[i].max_uV);
2807 regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
2808 }
2809 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
2810 kfree(msm8x10->supplies);
2811}
2812
Kuirong Wang2e81d322013-05-30 17:52:36 -07002813static int msm8x10_wcd_pads_config(void)
Kuirong Wang91e52532013-03-31 14:24:22 -07002814{
Kuirong Wang2e81d322013-05-30 17:52:36 -07002815 /* Set I2C pads as pull up and rest of pads as no pull */
2816 iowrite32(0x03C00000, ioremap(MSM8x10_TLMM_CDC_PULL_CTL, 4));
2817 usleep_range(100, 200);
Kuirong Wang91e52532013-03-31 14:24:22 -07002818 return 0;
2819}
Kuirong Wangae340de2013-05-30 18:11:07 -07002820
2821
2822static int msm8x10_wcd_clk_init(void)
2823{
2824 /* Div-2 */
2825 iowrite32(0x3, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4));
2826 iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4));
2827 iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4));
2828 iowrite32(0x0, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4));
2829 /* Digital codec clock enable */
2830 iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4));
2831 /* Set the update bit to make the settings go through */
2832 iowrite32(0x1, ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4));
2833 usleep_range(100, 200);
2834 return 0;
2835}
2836
Kuirong Wang91e52532013-03-31 14:24:22 -07002837static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
2838{
2839 mutex_init(&msm8x10->io_lock);
2840 mutex_init(&msm8x10->xfer_lock);
2841 mutex_init(&msm8x10->pm_lock);
2842 msm8x10->wlock_holders = 0;
Kuirong Wang2e81d322013-05-30 17:52:36 -07002843 msm8x10_wcd_pads_config();
Kuirong Wangae340de2013-05-30 18:11:07 -07002844 msm8x10_wcd_clk_init();
Kuirong Wang91e52532013-03-31 14:24:22 -07002845 return 0;
2846}
2847
Kuirong Wang265f3592012-12-05 16:17:41 -08002848static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
2849 const struct i2c_device_id *id)
2850{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002851 int ret = 0;
2852 struct msm8x10_wcd *msm8x10 = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -08002853 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002854 static int device_id;
2855 struct device *dev;
Kuirong Wang2e81d322013-05-30 17:52:36 -07002856 enum apr_subsys_state q6_state;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002857
Kuirong Wang2e81d322013-05-30 17:52:36 -07002858 dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
2859 __func__, __LINE__, client->addr, device_id);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002860
Kuirong Wang2e81d322013-05-30 17:52:36 -07002861 switch (client->addr) {
2862 case HELICON_CORE_0_I2C_ADDR:
2863 msm8x10_wcd_modules[0].client = client;
2864 break;
2865 case HELICON_CORE_1_I2C_ADDR:
2866 msm8x10_wcd_modules[1].client = client;
2867 goto rtn;
2868 case HELICON_CORE_2_I2C_ADDR:
2869 msm8x10_wcd_modules[2].client = client;
2870 goto rtn;
2871 case HELICON_CORE_3_I2C_ADDR:
2872 msm8x10_wcd_modules[3].client = client;
2873 goto rtn;
2874 default:
2875 ret = -EINVAL;
Kuirong Wang91e52532013-03-31 14:24:22 -07002876 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002877 }
2878
Kuirong Wang2e81d322013-05-30 17:52:36 -07002879 q6_state = apr_get_q6_state();
2880 if ((q6_state == APR_SUBSYS_DOWN) &&
2881 (client->addr == HELICON_CORE_0_I2C_ADDR)) {
2882 dev_info(&client->dev, "defering %s, adsp_state %d\n", __func__,
2883 q6_state);
2884 return -EPROBE_DEFER;
2885 } else
2886 dev_info(&client->dev, "adsp is ready\n");
2887
2888 dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
2889 __func__, __LINE__, client->addr, device_id);
2890
2891 if (client->addr != HELICON_CORE_0_I2C_ADDR)
2892 goto rtn;
2893
Kuirong Wang14b3fb92013-06-27 17:28:17 -07002894 dev_set_name(&client->dev, "%s", MSM8X10_CODEC_NAME);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002895 dev = &client->dev;
Kuirong Wang265f3592012-12-05 16:17:41 -08002896 if (client->dev.of_node) {
2897 dev_dbg(&client->dev, "%s:Platform data from device tree\n",
2898 __func__);
2899 pdata = msm8x10_wcd_populate_dt_pdata(&client->dev);
2900 client->dev.platform_data = pdata;
2901 } else {
2902 dev_dbg(&client->dev, "%s:Platform data from board file\n",
2903 __func__);
2904 pdata = client->dev.platform_data;
2905 }
2906
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002907 msm8x10 = kzalloc(sizeof(struct msm8x10_wcd), GFP_KERNEL);
2908 if (msm8x10 == NULL) {
2909 dev_err(&client->dev,
2910 "%s: error, allocation failed\n", __func__);
2911 ret = -ENOMEM;
Kuirong Wang91e52532013-03-31 14:24:22 -07002912 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002913 }
Kuirong Wang265f3592012-12-05 16:17:41 -08002914
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002915 msm8x10->dev = &client->dev;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002916 msm8x10->read_dev = msm8x10_wcd_reg_read;
2917 msm8x10->write_dev = msm8x10_wcd_reg_write;
Kuirong Wang49f506a2013-05-22 17:38:26 -07002918 ret = msm8x10_wcd_init_supplies(msm8x10, pdata);
Kuirong Wang91e52532013-03-31 14:24:22 -07002919 if (ret) {
2920 dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
2921 __func__);
2922 goto err_codec;
2923 }
Kuirong Wang49f506a2013-05-22 17:38:26 -07002924
2925 ret = msm8x10_wcd_enable_static_supplies(msm8x10, pdata);
2926 if (ret) {
2927 pr_err("%s: Fail to enable Codec pre-reset supplies\n",
2928 __func__);
2929 goto err_codec;
2930 }
2931 usleep_range(5, 5);
2932
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002933 ret = msm8x10_wcd_device_init(msm8x10);
2934 if (ret) {
2935 dev_err(&client->dev,
2936 "%s:msm8x10_wcd_device_init failed with error %d\n",
2937 __func__, ret);
Kuirong Wang91e52532013-03-31 14:24:22 -07002938 goto err_supplies;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002939 }
2940 dev_set_drvdata(&client->dev, msm8x10);
2941 ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
2942 msm8x10_wcd_i2s_dai,
2943 ARRAY_SIZE(msm8x10_wcd_i2s_dai));
2944 if (ret)
2945 dev_err(&client->dev,
2946 "%s:snd_soc_register_codec failed with error %d\n",
2947 __func__, ret);
Kuirong Wang91e52532013-03-31 14:24:22 -07002948 else
2949 goto rtn;
2950
2951err_supplies:
2952 msm8x10_wcd_disable_supplies(msm8x10, pdata);
2953err_codec:
2954 kfree(msm8x10);
2955rtn:
Kuirong Wang265f3592012-12-05 16:17:41 -08002956 return ret;
2957}
2958
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002959static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
2960{
2961 mutex_destroy(&msm8x10->pm_lock);
2962 mutex_destroy(&msm8x10->io_lock);
2963 mutex_destroy(&msm8x10->xfer_lock);
2964 kfree(msm8x10);
2965}
2966
Kuirong Wang265f3592012-12-05 16:17:41 -08002967static int __devexit msm8x10_wcd_i2c_remove(struct i2c_client *client)
2968{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002969 struct msm8x10_wcd *msm8x10 = dev_get_drvdata(&client->dev);
2970
2971 msm8x10_wcd_device_exit(msm8x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08002972 return 0;
2973}
2974
2975static struct i2c_device_id msm8x10_wcd_id_table[] = {
2976 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_TOP_LEVEL},
2977 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_ANALOG},
2978 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_1},
2979 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_2},
2980 {}
2981};
2982
2983static struct of_device_id msm8x10_wcd_of_match[] = {
2984 { .compatible = "qcom,msm8x10-wcd-i2c",},
2985 { },
2986};
2987
2988
2989static struct i2c_driver msm8x10_wcd_i2c_driver = {
2990 .driver = {
2991 .owner = THIS_MODULE,
2992 .name = "msm8x10-wcd-i2c-core",
2993 .of_match_table = msm8x10_wcd_of_match
2994 },
2995 .id_table = msm8x10_wcd_id_table,
2996 .probe = msm8x10_wcd_i2c_probe,
2997 .remove = __devexit_p(msm8x10_wcd_i2c_remove),
2998};
2999
3000static int __init msm8x10_wcd_codec_init(void)
3001{
3002 int ret;
3003
3004 pr_debug("%s:\n", __func__);
3005 ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
3006 if (ret != 0)
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003007 pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
3008 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -08003009 return ret;
3010}
3011
3012static void __exit msm8x10_wcd_codec_exit(void)
3013{
3014 i2c_del_driver(&msm8x10_wcd_i2c_driver);
3015}
3016
3017
3018module_init(msm8x10_wcd_codec_init);
3019module_exit(msm8x10_wcd_codec_exit);
3020
3021MODULE_DESCRIPTION("MSM8x10 Audio codec driver");
3022MODULE_LICENSE("GPL v2");
3023MODULE_DEVICE_TABLE(i2c, msm8x10_wcd_id_table);
3024