blob: 4c20bb9bf8bb741361c07b25e5a73f404497785a [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>
Kuirong Wang265f3592012-12-05 16:17:41 -080030#include <linux/mfd/wcd9xxx/pdata.h>
31#include <sound/pcm.h>
32#include <sound/pcm_params.h>
33#include <sound/soc.h>
34#include <sound/soc-dapm.h>
35#include <sound/tlv.h>
Kuirong Wang91e52532013-03-31 14:24:22 -070036#include <mach/qdsp6v2/apr.h>
Fred Ohcf2f8582013-06-13 18:32:07 -070037#include <mach/subsystem_notif.h>
Kuirong Wang265f3592012-12-05 16:17:41 -080038#include "msm8x10-wcd.h"
39#include "wcd9xxx-resmgr.h"
40#include "msm8x10_wcd_registers.h"
Fred Ohcf2f8582013-06-13 18:32:07 -070041#include "../msm/qdsp6v2/q6core.h"
Kuirong Wang265f3592012-12-05 16:17:41 -080042
43#define MSM8X10_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
44 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
45#define MSM8X10_WCD_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
46
47#define NUM_DECIMATORS 2
48#define NUM_INTERPOLATORS 3
49#define BITS_PER_REG 8
50#define MSM8X10_WCD_TX_PORT_NUMBER 4
51
52#define MSM8X10_WCD_I2S_MASTER_MODE_MASK 0x08
53#define MSM8X10_DINO_CODEC_BASE_ADDR 0xFE043000
Fred Oh4d716bb2013-07-30 10:14:46 -070054#define MSM8X10_DINO_CODEC_REG_SIZE 0x200
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
Bhalchandra Gajare9c19dc22013-07-11 17:16:53 -070064#define HELICON_MCLK_CLK_9P6MHZ 9600000
Kuirong Wang265f3592012-12-05 16:17:41 -080065
66enum {
67 MSM8X10_WCD_I2C_TOP_LEVEL = 0,
68 MSM8X10_WCD_I2C_ANALOG,
69 MSM8X10_WCD_I2C_DIGITAL_1,
70 MSM8X10_WCD_I2C_DIGITAL_2,
71};
72
73enum {
74 AIF1_PB = 0,
75 AIF1_CAP,
76 NUM_CODEC_DAIS,
77};
78
79enum {
80 RX_MIX1_INP_SEL_ZERO = 0,
81 RX_MIX1_INP_SEL_IIR1,
82 RX_MIX1_INP_SEL_IIR2,
83 RX_MIX1_INP_SEL_RX1,
84 RX_MIX1_INP_SEL_RX2,
85 RX_MIX1_INP_SEL_RX3,
86};
87
88static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
89static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
90static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
91static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[];
92static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
93
Kuirong Wang91e52532013-03-31 14:24:22 -070094#define MSM8X10_WCD_ACQUIRE_LOCK(x) do { \
95 mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
96} while (0)
97#define MSM8X10_WCD_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
98
99
Kuirong Wang265f3592012-12-05 16:17:41 -0800100/* Codec supports 2 IIR filters */
101enum {
102 IIR1 = 0,
103 IIR2,
104 IIR_MAX,
105};
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800106
Kuirong Wang265f3592012-12-05 16:17:41 -0800107/* Codec supports 5 bands */
108enum {
109 BAND1 = 0,
110 BAND2,
111 BAND3,
112 BAND4,
113 BAND5,
114 BAND_MAX,
115};
116
Kuirong Wang91e52532013-03-31 14:24:22 -0700117enum msm8x10_wcd_bandgap_type {
118 MSM8X10_WCD_BANDGAP_OFF = 0,
119 MSM8X10_WCD_BANDGAP_AUDIO_MODE,
120 MSM8X10_WCD_BANDGAP_MBHC_MODE,
121};
122
Kuirong Wang49f506a2013-05-22 17:38:26 -0700123enum {
124 ON_DEMAND_MICBIAS = 0,
125 ON_DEMAND_CP,
126 ON_DEMAND_SUPPLIES_MAX,
127};
128
Kuirong Wanga0185b12013-07-26 17:49:13 -0700129/*
130 * The delay list is per codec HW specification.
131 * Please add delay in the list in the future instead
132 * of magic number
133 */
134enum {
135 CODEC_DELAY_1_MS = 1000,
136 CODEC_DELAY_1_1_MS = 1100,
137};
138
Kuirong Wang265f3592012-12-05 16:17:41 -0800139struct hpf_work {
140 struct msm8x10_wcd_priv *msm8x10_wcd;
141 u32 decimator;
142 u8 tx_hpf_cut_of_freq;
143 struct delayed_work dwork;
144};
145
146static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
147
Kuirong Wang49f506a2013-05-22 17:38:26 -0700148struct on_demand_supply {
149 struct regulator *supply;
150 atomic_t ref;
151};
152
153static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
154 "cdc-vdd-mic-bias",
155 "cdc-vdda-cp",
156};
157
Kuirong Wang265f3592012-12-05 16:17:41 -0800158struct msm8x10_wcd_priv {
159 struct snd_soc_codec *codec;
160 u32 adc_count;
161 u32 rx_bias_count;
162 s32 dmic_1_2_clk_cnt;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700163 struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
Kuirong Wang265f3592012-12-05 16:17:41 -0800164 /* resmgr module */
165 struct wcd9xxx_resmgr resmgr;
Bhalchandra Gajare9c19dc22013-07-11 17:16:53 -0700166 /* mbhc module */
167 struct wcd9xxx_mbhc mbhc;
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700168
169 struct delayed_work hs_detect_work;
170 struct wcd9xxx_mbhc_config *mbhc_cfg;
Kuirong Wang265f3592012-12-05 16:17:41 -0800171};
172
Kuirong Wang265f3592012-12-05 16:17:41 -0800173static unsigned short rx_digital_gain_reg[] = {
174 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
175 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
176 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
177};
178
179static unsigned short tx_digital_gain_reg[] = {
180 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
181 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
182};
183
184struct msm8x10_wcd_i2c {
185 struct i2c_client *client;
186 struct i2c_msg xfer_msg[2];
187 struct mutex xfer_lock;
188 int mod_id;
189};
190
Kuirong Wang265f3592012-12-05 16:17:41 -0800191static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
Kuirong Wang49f506a2013-05-22 17:38:26 -0700192 struct msm8x10_wcd_regulator *vreg,
193 const char *vreg_name, bool ondemand);
Kuirong Wang265f3592012-12-05 16:17:41 -0800194static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
195 struct msm8x10_wcd_micbias_setting *micbias);
196static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
197 struct device *dev);
198
199struct msm8x10_wcd_i2c msm8x10_wcd_modules[MAX_MSM8X10_WCD_DEVICE];
200
Fred Ohcf2f8582013-06-13 18:32:07 -0700201static void *adsp_state_notifier;
202
203static struct snd_soc_codec *registered_codec;
204#define ADSP_STATE_READY_TIMEOUT_MS 2000
205
Kuirong Wang265f3592012-12-05 16:17:41 -0800206
207static int get_i2c_msm8x10_wcd_device_info(u16 reg,
208 struct msm8x10_wcd_i2c **msm8x10_wcd)
209{
210 int rtn = 0;
211 int value = ((reg & 0x0f00) >> 8) & 0x000f;
Kuirong Wang265f3592012-12-05 16:17:41 -0800212 switch (value) {
213 case 0:
214 case 1:
215 *msm8x10_wcd = &msm8x10_wcd_modules[value];
216 break;
217 default:
218 rtn = -EINVAL;
219 break;
220 }
221 return rtn;
222}
223
Fred Oh4d716bb2013-07-30 10:14:46 -0700224static int msm8x10_wcd_abh_write_device(struct msm8x10_wcd *msm8x10_wcd,
225 u16 reg, u8 *value, u32 bytes)
Kuirong Wang265f3592012-12-05 16:17:41 -0800226{
227 u32 temp = ((u32)(*value)) & 0x000000FF;
228 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
Fred Oh4d716bb2013-07-30 10:14:46 -0700229
230 iowrite32(temp, (msm8x10_wcd->pdino_base+offset));
Kuirong Wang265f3592012-12-05 16:17:41 -0800231 return 0;
232}
233
Fred Oh4d716bb2013-07-30 10:14:46 -0700234static int msm8x10_wcd_abh_read_device(struct msm8x10_wcd *msm8x10_wcd,
235 u16 reg, u32 bytes, u8 *value)
Kuirong Wang265f3592012-12-05 16:17:41 -0800236{
Kuirong Wang91e52532013-03-31 14:24:22 -0700237 u32 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800238 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
Fred Oh4d716bb2013-07-30 10:14:46 -0700239
240 temp = ioread32((msm8x10_wcd->pdino_base+offset));
Kuirong Wang91e52532013-03-31 14:24:22 -0700241 *value = (u8)temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800242 return 0;
243}
244
245static int msm8x10_wcd_i2c_write_device(u16 reg, u8 *value, u32 bytes)
246{
247
248 struct i2c_msg *msg;
249 int ret;
250 u8 reg_addr = 0;
251 u8 data[bytes + 1];
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800252 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800253
254 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800255 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800256 pr_err("%s: Invalid register address\n", __func__);
257 return ret;
258 }
259
260 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
261 pr_err("%s: Failed to get device info\n", __func__);
262 return -ENODEV;
263 }
264 reg_addr = (u8)reg;
265 msg = &msm8x10_wcd->xfer_msg[0];
266 msg->addr = msm8x10_wcd->client->addr;
267 msg->len = bytes + 1;
268 msg->flags = 0;
269 data[0] = reg;
270 data[1] = *value;
271 msg->buf = data;
272 ret = i2c_transfer(msm8x10_wcd->client->adapter,
273 msm8x10_wcd->xfer_msg, 1);
274 /* Try again if the write fails */
275 if (ret != 1) {
276 ret = i2c_transfer(msm8x10_wcd->client->adapter,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800277 msm8x10_wcd->xfer_msg, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -0800278 if (ret != 1) {
279 pr_err("failed to write the device\n");
280 return ret;
281 }
282 }
283 pr_debug("write sucess register = %x val = %x\n", reg, data[1]);
284 return 0;
285}
286
287
288int msm8x10_wcd_i2c_read_device(u32 reg, u32 bytes, u8 *dest)
289{
290 struct i2c_msg *msg;
291 int ret = 0;
292 u8 reg_addr = 0;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800293 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800294 u8 i = 0;
295
296 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800297 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800298 pr_err("%s: Invalid register address\n", __func__);
299 return ret;
300 }
301
302 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
303 pr_err("%s: Failed to get device info\n", __func__);
304 return -ENODEV;
305 }
306
307 for (i = 0; i < bytes; i++) {
308 reg_addr = (u8)reg++;
309 msg = &msm8x10_wcd->xfer_msg[0];
310 msg->addr = msm8x10_wcd->client->addr;
311 msg->len = 1;
312 msg->flags = 0;
313 msg->buf = &reg_addr;
Kuirong Wang265f3592012-12-05 16:17:41 -0800314 msg = &msm8x10_wcd->xfer_msg[1];
315 msg->addr = msm8x10_wcd->client->addr;
316 msg->len = 1;
317 msg->flags = I2C_M_RD;
318 msg->buf = dest++;
319 ret = i2c_transfer(msm8x10_wcd->client->adapter,
320 msm8x10_wcd->xfer_msg, 2);
321
322 /* Try again if read fails first time */
323 if (ret != 2) {
324 ret = i2c_transfer(msm8x10_wcd->client->adapter,
325 msm8x10_wcd->xfer_msg, 2);
326 if (ret != 2) {
327 pr_err("failed to read msm8x10_wcd register\n");
328 return ret;
329 }
330 }
331 }
Kuirong Wang91e52532013-03-31 14:24:22 -0700332 pr_debug("%s: reg 0x%x = 0x%x\n", __func__, reg, *dest);
Kuirong Wang265f3592012-12-05 16:17:41 -0800333 return 0;
334}
335
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800336int msm8x10_wcd_i2c_read(unsigned short reg, int bytes, void *dest)
Kuirong Wang265f3592012-12-05 16:17:41 -0800337{
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800338 return msm8x10_wcd_i2c_read_device(reg, bytes, dest);
339}
340
341int msm8x10_wcd_i2c_write(unsigned short reg, int bytes, void *src)
342{
343 return msm8x10_wcd_i2c_write_device(reg, src, bytes);
344}
345
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700346static unsigned short msm8x10_wcd_mask_reg(unsigned short reg)
347{
348 if (reg >= 0x3C0 && reg <= 0x3DF)
349 reg = reg & 0x00FF;
350 return reg;
351}
352
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700353static int __msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
354 unsigned short reg)
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800355{
Kuirong Wang265f3592012-12-05 16:17:41 -0800356 int ret = -EINVAL;
Kuirong Wang91e52532013-03-31 14:24:22 -0700357 u8 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800358
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700359 reg = msm8x10_wcd_mask_reg(reg);
360
Kuirong Wang265f3592012-12-05 16:17:41 -0800361 /* check if use I2C interface for Helicon or AHB for Dino */
362 mutex_lock(&msm8x10_wcd->io_lock);
363 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang91e52532013-03-31 14:24:22 -0700364 ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800365 else if (MSM8X10_WCD_IS_DINO_REG(reg))
Fred Oh4d716bb2013-07-30 10:14:46 -0700366 ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800367 mutex_unlock(&msm8x10_wcd->io_lock);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700368
369 if (ret < 0) {
370 dev_err(msm8x10_wcd->dev,
371 "%s: codec read failed for reg 0x%x\n",
372 __func__, reg);
373 return ret;
374 } else {
375 dev_dbg(msm8x10_wcd->dev, "Read 0x%02x from 0x%x\n",
376 temp, reg);
377 }
378
379 return temp;
380}
381
382int msm8x10_wcd_reg_read(struct wcd9xxx_core_resource *core_res,
383 unsigned short reg)
384{
385 struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
386 return __msm8x10_wcd_reg_read(msm8x10_wcd, reg);
387}
388EXPORT_SYMBOL(msm8x10_wcd_reg_read);
389
390static int __msm8x10_wcd_bulk_read(struct msm8x10_wcd *msm8x10_wcd,
391 unsigned short reg, int count, u8 *buf)
392{
393 int ret = -EINVAL;
394 mutex_lock(&msm8x10_wcd->io_lock);
395 if (MSM8X10_WCD_IS_HELICON_REG(reg))
396 ret = msm8x10_wcd_i2c_read(reg, count, buf);
397 else if (MSM8X10_WCD_IS_DINO_REG(reg))
398 ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg,
399 count, buf);
400 mutex_unlock(&msm8x10_wcd->io_lock);
401
402 if (ret < 0)
403 dev_err(msm8x10_wcd->dev,
404 "%s: codec bulk read failed\n", __func__);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800405 return ret;
Kuirong Wang265f3592012-12-05 16:17:41 -0800406}
407
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700408int msm8x10_wcd_bulk_read(struct wcd9xxx_core_resource *core_res,
409 unsigned short reg, int count, u8 *buf)
410{
411 struct msm8x10_wcd *msm8x10_wcd =
412 (struct msm8x10_wcd *) core_res->parent;
413 return __msm8x10_wcd_bulk_read(msm8x10_wcd, reg, count, buf);
414}
415EXPORT_SYMBOL(msm8x10_wcd_bulk_read);
Kuirong Wang265f3592012-12-05 16:17:41 -0800416
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700417static int __msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd,
418 unsigned short reg, u8 val)
Kuirong Wang265f3592012-12-05 16:17:41 -0800419{
420 int ret = -EINVAL;
421
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700422 reg = msm8x10_wcd_mask_reg(reg);
423
Kuirong Wang265f3592012-12-05 16:17:41 -0800424 /* check if use I2C interface for Helicon or AHB for Dino */
425 mutex_lock(&msm8x10_wcd->io_lock);
426 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800427 ret = msm8x10_wcd_i2c_write(reg, 1, &val);
Kuirong Wang265f3592012-12-05 16:17:41 -0800428 else if (MSM8X10_WCD_IS_DINO_REG(reg))
Fred Oh4d716bb2013-07-30 10:14:46 -0700429 ret = msm8x10_wcd_abh_write_device(msm8x10_wcd, reg, &val, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -0800430 mutex_unlock(&msm8x10_wcd->io_lock);
431
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700432 if (ret < 0)
433 dev_err(msm8x10_wcd->dev,
434 "%s: codec write to reg 0x%x failed\n",
435 __func__, reg);
436 else
437 dev_dbg(msm8x10_wcd->dev,
438 "%s: Codec reg 0x%x written with value 0x%x\n",
439 __func__, reg, val);
440
Kuirong Wang265f3592012-12-05 16:17:41 -0800441 return ret;
442}
443
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700444int msm8x10_wcd_reg_write(struct wcd9xxx_core_resource *core_res,
445 unsigned short reg, u8 val)
446{
447 struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
448 return __msm8x10_wcd_reg_write(msm8x10_wcd, reg, val);
449}
450EXPORT_SYMBOL(msm8x10_wcd_reg_write);
451
Kuirong Wang265f3592012-12-05 16:17:41 -0800452static bool msm8x10_wcd_is_digital_gain_register(unsigned int reg)
453{
454 bool rtn = false;
455 switch (reg) {
456 case MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL:
457 case MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL:
458 case MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL:
459 case MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN:
460 case MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN:
461 rtn = true;
462 break;
463 default:
464 break;
465 }
466 return rtn;
467}
468
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800469static int msm8x10_wcd_volatile(struct snd_soc_codec *codec, unsigned int reg)
Kuirong Wang265f3592012-12-05 16:17:41 -0800470{
471 /*
472 * Registers lower than 0x100 are top level registers which can be
473 * written by the Taiko core driver.
474 */
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800475 dev_dbg(codec->dev, "%s: reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800476
477 if ((reg >= MSM8X10_WCD_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
478 return 1;
479
480 /* IIR Coeff registers are not cacheable */
481 if ((reg >= MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL) &&
482 (reg <= MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL))
483 return 1;
484
485 /*
486 * Digital gain register is not cacheable so we have to write
487 * the setting even it is the same
488 */
489 if (msm8x10_wcd_is_digital_gain_register(reg))
490 return 1;
491
492 /* HPH status registers */
493 if (reg == MSM8X10_WCD_A_RX_HPH_L_STATUS ||
494 reg == MSM8X10_WCD_A_RX_HPH_R_STATUS)
495 return 1;
496
497 if (reg == MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS)
498 return 1;
499
500 return 0;
501}
502
503static int msm8x10_wcd_readable(struct snd_soc_codec *ssc, unsigned int reg)
504{
505 return msm8x10_wcd_reg_readable[reg];
506}
507
508static int msm8x10_wcd_write(struct snd_soc_codec *codec, unsigned int reg,
509 unsigned int value)
510{
511 int ret;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800512 dev_dbg(codec->dev, "%s: Write from reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800513 if (reg == SND_SOC_NOPM)
514 return 0;
515
516 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
517
518 if (!msm8x10_wcd_volatile(codec, reg)) {
519 ret = snd_soc_cache_write(codec, reg, value);
520 if (ret != 0)
521 dev_err(codec->dev, "Cache write to %x failed: %d\n",
522 reg, ret);
523 }
524
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700525 return __msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
Kuirong Wang265f3592012-12-05 16:17:41 -0800526}
527
528static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
529 unsigned int reg)
530{
531 unsigned int val;
532 int ret;
533
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800534 dev_dbg(codec->dev, "%s: Read from reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800535 if (reg == SND_SOC_NOPM)
536 return 0;
537
538 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
539
540 if (!msm8x10_wcd_volatile(codec, reg) &&
541 msm8x10_wcd_readable(codec, reg) &&
542 reg < codec->driver->reg_cache_size) {
543 ret = snd_soc_cache_read(codec, reg, &val);
544 if (ret >= 0) {
545 return val;
546 } else
547 dev_err(codec->dev, "Cache read from %x failed: %d\n",
548 reg, ret);
549 }
550
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700551 val = __msm8x10_wcd_reg_read(codec->control_data, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800552 return val;
553}
554
555
556static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
Kuirong Wang49f506a2013-05-22 17:38:26 -0700557 struct msm8x10_wcd_regulator *vreg, const char *vreg_name,
558 bool ondemand)
Kuirong Wang265f3592012-12-05 16:17:41 -0800559{
560 int len, ret = 0;
561 const __be32 *prop;
562 char prop_name[CODEC_DT_MAX_PROP_SIZE];
563 struct device_node *regnode = NULL;
564 u32 prop_val;
565
566 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
567 vreg_name);
568 regnode = of_parse_phandle(dev->of_node, prop_name, 0);
569
570 if (!regnode) {
Kuirong Wang91e52532013-03-31 14:24:22 -0700571 dev_err(dev, "Looking up %s property in node %s failed\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800572 prop_name, dev->of_node->full_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800573 return -ENODEV;
574 }
Kuirong Wang91e52532013-03-31 14:24:22 -0700575
576 dev_dbg(dev, "Looking up %s property in node %s\n",
577 prop_name, dev->of_node->full_name);
578
Kuirong Wang265f3592012-12-05 16:17:41 -0800579 vreg->name = vreg_name;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700580 vreg->ondemand = ondemand;
Kuirong Wang265f3592012-12-05 16:17:41 -0800581
582 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
583 "qcom,%s-voltage", vreg_name);
584 prop = of_get_property(dev->of_node, prop_name, &len);
585
586 if (!prop || (len != (2 * sizeof(__be32)))) {
587 dev_err(dev, "%s %s property\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800588 prop ? "invalid format" : "no", prop_name);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700589 return -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800590 } else {
591 vreg->min_uV = be32_to_cpup(&prop[0]);
592 vreg->max_uV = be32_to_cpup(&prop[1]);
593 }
594
595 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800596 "qcom,%s-current", vreg_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800597
598 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
599 if (ret) {
600 dev_err(dev, "Looking up %s property in node %s failed",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800601 prop_name, dev->of_node->full_name);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700602 return -EFAULT;
Kuirong Wang265f3592012-12-05 16:17:41 -0800603 }
604 vreg->optimum_uA = prop_val;
605
Kuirong Wang49f506a2013-05-22 17:38:26 -0700606 dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
607 vreg->min_uV, vreg->max_uV, vreg->optimum_uA, vreg->ondemand);
Kuirong Wang265f3592012-12-05 16:17:41 -0800608 return 0;
609}
610
611static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
612 struct msm8x10_wcd_micbias_setting *micbias)
613{
614 int ret = 0;
615 char prop_name[CODEC_DT_MAX_PROP_SIZE];
616 u32 prop_val;
617
618 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700619 "qcom,cdc-micbias-cfilt-mv");
Kuirong Wang265f3592012-12-05 16:17:41 -0800620 ret = of_property_read_u32(dev->of_node, prop_name,
621 &micbias->cfilt1_mv);
622 if (ret) {
623 dev_err(dev, "Looking up %s property in node %s failed",
624 prop_name, dev->of_node->full_name);
625 return -ENODEV;
626 }
627
628 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700629 "qcom,cdc-micbias-cfilt-sel");
Kuirong Wang265f3592012-12-05 16:17:41 -0800630 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
631 if (ret) {
632 dev_err(dev, "Looking up %s property in node %s failed",
633 prop_name, dev->of_node->full_name);
634 return -ENODEV;
635 }
636 micbias->bias1_cfilt_sel = (u8)prop_val;
637
638 /* micbias external cap */
639 micbias->bias1_cap_mode =
640 (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
641 MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
642
643 dev_dbg(dev, "ldoh_v %u cfilt1_mv %u\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800644 (u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
Kuirong Wang265f3592012-12-05 16:17:41 -0800645 dev_dbg(dev, "bias1_cfilt_sel %u\n", (u32)micbias->bias1_cfilt_sel);
646 dev_dbg(dev, "bias1_ext_cap %d\n", micbias->bias1_cap_mode);
647
648 return 0;
649}
650
651static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
652 struct device *dev)
653{
654 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700655 int ret, static_cnt, ond_cnt, idx, i;
656 const char *name = NULL;
657 const char *static_prop_name = "qcom,cdc-static-supplies";
658 const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
Kuirong Wang265f3592012-12-05 16:17:41 -0800659
660 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
661 if (!pdata) {
662 dev_err(dev, "could not allocate memory for platform data\n");
663 return NULL;
664 }
Kuirong Wang49f506a2013-05-22 17:38:26 -0700665
666 static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
667 if (IS_ERR_VALUE(static_cnt)) {
668 dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
669 static_cnt);
670 ret = -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800671 goto err;
672 }
673
Kuirong Wang49f506a2013-05-22 17:38:26 -0700674 /* On-demand supply list is an optional property */
675 ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
676 if (IS_ERR_VALUE(ond_cnt))
677 ond_cnt = 0;
678
679 BUG_ON(static_cnt <= 0 || ond_cnt < 0);
680 if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800681 dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
Kuirong Wang49f506a2013-05-22 17:38:26 -0700682 __func__, static_cnt, ARRAY_SIZE(pdata->regulator));
683 ret = -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800684 goto err;
685 }
686
Kuirong Wang49f506a2013-05-22 17:38:26 -0700687 for (idx = 0; idx < static_cnt; idx++) {
688 ret = of_property_read_string_index(dev->of_node,
689 static_prop_name, idx,
690 &name);
691 if (ret) {
692 dev_err(dev, "%s: of read string %s idx %d error %d\n",
693 __func__, static_prop_name, idx, ret);
694 goto err;
695 }
696
697 dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
698 name);
699 ret = msm8x10_wcd_dt_parse_vreg_info(dev,
700 &pdata->regulator[idx],
701 name, false);
Kuirong Wang265f3592012-12-05 16:17:41 -0800702 if (ret)
703 goto err;
704 }
Kuirong Wang49f506a2013-05-22 17:38:26 -0700705
706 for (i = 0; i < ond_cnt; i++, idx++) {
707 ret = of_property_read_string_index(dev->of_node, ond_prop_name,
708 i, &name);
709 if (ret)
710 goto err;
711
712 dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
713 name);
714 ret = msm8x10_wcd_dt_parse_vreg_info(dev,
715 &pdata->regulator[idx],
716 name, true);
717 if (ret)
718 goto err;
719 }
720
Kuirong Wang265f3592012-12-05 16:17:41 -0800721 ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
722 if (ret)
723 goto err;
Kuirong Wang265f3592012-12-05 16:17:41 -0800724 return pdata;
725err:
726 devm_kfree(dev, pdata);
Kuirong Wang91e52532013-03-31 14:24:22 -0700727 dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
728 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -0800729 return NULL;
730}
731
Kuirong Wang49f506a2013-05-22 17:38:26 -0700732static int msm8x10_wcd_codec_enable_on_demand_supply(
733 struct snd_soc_dapm_widget *w,
734 struct snd_kcontrol *kcontrol, int event)
735{
736 int ret = 0;
737 struct snd_soc_codec *codec = w->codec;
738 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
739 struct on_demand_supply *supply;
740
741 if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
742 ret = -EINVAL;
743 goto out;
744 }
745 dev_dbg(codec->dev, "%s: supply: %s event: %d ref: %d\n",
746 __func__, on_demand_supply_name[w->shift], event,
747 atomic_read(&msm8x10_wcd->on_demand_list[w->shift].ref));
748
749 supply = &msm8x10_wcd->on_demand_list[w->shift];
750 WARN_ONCE(!supply->supply, "%s isn't defined\n",
751 on_demand_supply_name[w->shift]);
752 if (!supply->supply)
753 goto out;
754
755 switch (event) {
756 case SND_SOC_DAPM_PRE_PMU:
757 if (atomic_inc_return(&supply->ref) == 1)
758 ret = regulator_enable(supply->supply);
759 if (ret)
760 dev_err(codec->dev, "%s: Failed to enable %s\n",
761 __func__,
762 on_demand_supply_name[w->shift]);
763 break;
764 case SND_SOC_DAPM_POST_PMD:
765 if (atomic_read(&supply->ref) == 0) {
766 dev_dbg(codec->dev, "%s: %s supply has been disabled.\n",
767 __func__, on_demand_supply_name[w->shift]);
768 goto out;
769 }
770 if (atomic_dec_return(&supply->ref) == 0)
771 ret = regulator_disable(supply->supply);
772 if (ret)
773 dev_err(codec->dev, "%s: Failed to disable %s\n",
774 __func__,
775 on_demand_supply_name[w->shift]);
776 break;
777 default:
778 break;
779 }
780out:
781 return ret;
782}
783
Kuirong Wang265f3592012-12-05 16:17:41 -0800784static int msm8x10_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
785 struct snd_kcontrol *kcontrol, int event)
786{
787 struct snd_soc_codec *codec = w->codec;
788
Kuirong Wang49f506a2013-05-22 17:38:26 -0700789 dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -0800790 switch (event) {
791 case SND_SOC_DAPM_POST_PMU:
792 /* Enable charge pump clock*/
793 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
794 0x01, 0x01);
795 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLSG_CTL,
796 0x08, 0x08);
797 usleep_range(200, 300);
798 snd_soc_update_bits(codec, MSM8X10_WCD_A_CP_STATIC,
799 0x10, 0x00);
800 break;
801 case SND_SOC_DAPM_PRE_PMD:
802 snd_soc_update_bits(codec,
803 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
804 0x01, 0x01);
805 usleep_range(20, 100);
806 snd_soc_update_bits(codec,
807 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x08);
808 snd_soc_update_bits(codec,
809 MSM8X10_WCD_A_CP_STATIC, 0x10, 0x10);
810 snd_soc_update_bits(codec,
811 MSM8X10_WCD_A_CDC_CLSG_CTL, 0x08, 0x00);
812 snd_soc_update_bits(codec,
813 MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
814 0x00);
815 snd_soc_update_bits(codec,
Kuirong Wang91e52532013-03-31 14:24:22 -0700816 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
Kuirong Wang854de642013-05-24 13:40:41 -0700817 0x01, 0x00);
Kuirong Wang91e52532013-03-31 14:24:22 -0700818 snd_soc_update_bits(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800819 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
820 break;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700821 default:
822 break;
Kuirong Wang265f3592012-12-05 16:17:41 -0800823 }
824 return 0;
825}
826
827static int msm8x10_wcd_pa_gain_get(struct snd_kcontrol *kcontrol,
828 struct snd_ctl_elem_value *ucontrol)
829{
830 u8 ear_pa_gain;
831 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
832
833 ear_pa_gain = snd_soc_read(codec, MSM8X10_WCD_A_RX_EAR_GAIN);
834
835 ear_pa_gain = ear_pa_gain >> 5;
836
837 if (ear_pa_gain == 0x00) {
838 ucontrol->value.integer.value[0] = 0;
839 } else if (ear_pa_gain == 0x04) {
840 ucontrol->value.integer.value[0] = 1;
841 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800842 dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
843 __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800844 return -EINVAL;
845 }
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800846 dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800847 return 0;
848}
849
850static int msm8x10_wcd_pa_gain_put(struct snd_kcontrol *kcontrol,
851 struct snd_ctl_elem_value *ucontrol)
852{
853 u8 ear_pa_gain;
854 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
855
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800856 dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
857 __func__, ucontrol->value.integer.value[0]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800858
859 switch (ucontrol->value.integer.value[0]) {
860 case 0:
861 ear_pa_gain = 0x00;
862 break;
863 case 1:
864 ear_pa_gain = 0x80;
865 break;
866 default:
867 return -EINVAL;
868 }
869
870 snd_soc_update_bits(codec, MSM8X10_WCD_A_RX_EAR_GAIN,
871 0xE0, ear_pa_gain);
872 return 0;
873}
874
875static int msm8x10_wcd_get_iir_enable_audio_mixer(
876 struct snd_kcontrol *kcontrol,
877 struct snd_ctl_elem_value *ucontrol)
878{
879 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
880 int iir_idx = ((struct soc_multi_mixer_control *)
881 kcontrol->private_value)->reg;
882 int band_idx = ((struct soc_multi_mixer_control *)
883 kcontrol->private_value)->shift;
884
885 ucontrol->value.integer.value[0] =
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700886 (snd_soc_read(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800887 (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700888 (1 << band_idx)) != 0;
Kuirong Wang265f3592012-12-05 16:17:41 -0800889
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800890 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -0800891 iir_idx, band_idx,
892 (uint32_t)ucontrol->value.integer.value[0]);
893 return 0;
894}
895
896static int msm8x10_wcd_put_iir_enable_audio_mixer(
897 struct snd_kcontrol *kcontrol,
898 struct snd_ctl_elem_value *ucontrol)
899{
900 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
901 int iir_idx = ((struct soc_multi_mixer_control *)
902 kcontrol->private_value)->reg;
903 int band_idx = ((struct soc_multi_mixer_control *)
904 kcontrol->private_value)->shift;
905 int value = ucontrol->value.integer.value[0];
906
907 /* Mask first 5 bits, 6-8 are reserved */
908 snd_soc_update_bits(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx),
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800909 (1 << band_idx), (value << band_idx));
Kuirong Wang265f3592012-12-05 16:17:41 -0800910
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800911 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700912 iir_idx, band_idx,
913 ((snd_soc_read(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
914 (1 << band_idx)) != 0));
915
Kuirong Wang265f3592012-12-05 16:17:41 -0800916 return 0;
917}
918static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800919 int iir_idx, int band_idx,
920 int coeff_idx)
Kuirong Wang265f3592012-12-05 16:17:41 -0800921{
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700922 uint32_t value = 0;
923
Kuirong Wang265f3592012-12-05 16:17:41 -0800924 /* Address does not automatically update if reading */
925 snd_soc_write(codec,
926 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700927 ((band_idx * BAND_MAX + coeff_idx)
928 * sizeof(uint32_t)) & 0x7F);
929
930 value |= snd_soc_read(codec,
931 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx));
932
933 snd_soc_write(codec,
934 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
935 ((band_idx * BAND_MAX + coeff_idx)
936 * sizeof(uint32_t) + 1) & 0x7F);
937
938 value |= (snd_soc_read(codec,
939 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
940
941 snd_soc_write(codec,
942 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
943 ((band_idx * BAND_MAX + coeff_idx)
944 * sizeof(uint32_t) + 2) & 0x7F);
945
946 value |= (snd_soc_read(codec,
947 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
948
949 snd_soc_write(codec,
950 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
951 ((band_idx * BAND_MAX + coeff_idx)
952 * sizeof(uint32_t) + 3) & 0x7F);
Kuirong Wang265f3592012-12-05 16:17:41 -0800953
954 /* Mask bits top 2 bits since they are reserved */
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700955 value |= ((snd_soc_read(codec,
956 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) & 0x3f) << 24);
957
958 return value;
959
Kuirong Wang265f3592012-12-05 16:17:41 -0800960}
961
962static int msm8x10_wcd_get_iir_band_audio_mixer(
963 struct snd_kcontrol *kcontrol,
964 struct snd_ctl_elem_value *ucontrol)
965{
966 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
967 int iir_idx = ((struct soc_multi_mixer_control *)
968 kcontrol->private_value)->reg;
969 int band_idx = ((struct soc_multi_mixer_control *)
970 kcontrol->private_value)->shift;
971
972 ucontrol->value.integer.value[0] =
973 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
974 ucontrol->value.integer.value[1] =
975 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
976 ucontrol->value.integer.value[2] =
977 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
978 ucontrol->value.integer.value[3] =
979 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
980 ucontrol->value.integer.value[4] =
981 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
982
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800983 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -0800984 "%s: IIR #%d band #%d b1 = 0x%x\n"
985 "%s: IIR #%d band #%d b2 = 0x%x\n"
986 "%s: IIR #%d band #%d a1 = 0x%x\n"
987 "%s: IIR #%d band #%d a2 = 0x%x\n",
988 __func__, iir_idx, band_idx,
989 (uint32_t)ucontrol->value.integer.value[0],
990 __func__, iir_idx, band_idx,
991 (uint32_t)ucontrol->value.integer.value[1],
992 __func__, iir_idx, band_idx,
993 (uint32_t)ucontrol->value.integer.value[2],
994 __func__, iir_idx, band_idx,
995 (uint32_t)ucontrol->value.integer.value[3],
996 __func__, iir_idx, band_idx,
997 (uint32_t)ucontrol->value.integer.value[4]);
998 return 0;
999}
1000
1001static void set_iir_band_coeff(struct snd_soc_codec *codec,
1002 int iir_idx, int band_idx,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001003 uint32_t value)
Kuirong Wang265f3592012-12-05 16:17:41 -08001004{
Kuirong Wang265f3592012-12-05 16:17:41 -08001005 snd_soc_write(codec,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001006 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1007 (value & 0xFF));
1008
1009 snd_soc_write(codec,
1010 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1011 (value >> 8) & 0xFF);
1012
1013 snd_soc_write(codec,
1014 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1015 (value >> 16) & 0xFF);
Kuirong Wang265f3592012-12-05 16:17:41 -08001016
1017 /* Mask top 2 bits, 7-8 are reserved */
1018 snd_soc_write(codec,
1019 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1020 (value >> 24) & 0x3F);
1021
1022}
1023
1024static int msm8x10_wcd_put_iir_band_audio_mixer(
1025 struct snd_kcontrol *kcontrol,
1026 struct snd_ctl_elem_value *ucontrol)
1027{
1028 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1029 int iir_idx = ((struct soc_multi_mixer_control *)
1030 kcontrol->private_value)->reg;
1031 int band_idx = ((struct soc_multi_mixer_control *)
1032 kcontrol->private_value)->shift;
1033
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001034 /* Mask top bit it is reserved */
1035 /* Updates addr automatically for each B2 write */
1036 snd_soc_write(codec,
1037 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
1038 (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
1039
1040
1041 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001042 ucontrol->value.integer.value[0]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001043 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001044 ucontrol->value.integer.value[1]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001045 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001046 ucontrol->value.integer.value[2]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001047 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001048 ucontrol->value.integer.value[3]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001049 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001050 ucontrol->value.integer.value[4]);
Kuirong Wang265f3592012-12-05 16:17:41 -08001051
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001052 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -08001053 "%s: IIR #%d band #%d b1 = 0x%x\n"
1054 "%s: IIR #%d band #%d b2 = 0x%x\n"
1055 "%s: IIR #%d band #%d a1 = 0x%x\n"
1056 "%s: IIR #%d band #%d a2 = 0x%x\n",
1057 __func__, iir_idx, band_idx,
1058 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
1059 __func__, iir_idx, band_idx,
1060 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
1061 __func__, iir_idx, band_idx,
1062 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
1063 __func__, iir_idx, band_idx,
1064 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
1065 __func__, iir_idx, band_idx,
1066 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
1067 return 0;
1068}
1069
1070static const char * const msm8x10_wcd_ear_pa_gain_text[] = {
1071 "POS_6_DB", "POS_2_DB"};
1072static const struct soc_enum msm8x10_wcd_ear_pa_gain_enum[] = {
1073 SOC_ENUM_SINGLE_EXT(2, msm8x10_wcd_ear_pa_gain_text),
1074};
1075
1076/*cut of frequency for high pass filter*/
1077static const char * const cf_text[] = {
1078 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
1079};
1080
1081static const struct soc_enum cf_dec1_enum =
1082 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
1083
1084static const struct soc_enum cf_dec2_enum =
1085 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
1086
1087static const struct soc_enum cf_rxmix1_enum =
1088 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
1089
1090static const struct soc_enum cf_rxmix2_enum =
1091 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
1092
1093static const struct soc_enum cf_rxmix3_enum =
1094 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
1095
1096static const struct snd_kcontrol_new msm8x10_wcd_snd_controls[] = {
1097
1098 SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
1099 msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
1100
Kuirong Wang91e52532013-03-31 14:24:22 -07001101 SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
Kuirong Wang265f3592012-12-05 16:17:41 -08001102 0, 12, 1, line_gain),
1103
1104 SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
1105 0, 12, 1, line_gain),
1106 SOC_SINGLE_TLV("HPHR Volume", MSM8X10_WCD_A_RX_HPH_R_GAIN,
1107 0, 12, 1, line_gain),
1108
1109 SOC_SINGLE_S8_TLV("RX1 Digital Volume",
1110 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
1111 -84, 40, digital_gain),
1112 SOC_SINGLE_S8_TLV("RX2 Digital Volume",
1113 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
1114 -84, 40, digital_gain),
1115 SOC_SINGLE_S8_TLV("RX3 Digital Volume",
1116 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
1117 -84, 40, digital_gain),
1118
1119 SOC_SINGLE_S8_TLV("DEC1 Volume",
1120 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
1121 -84, 40, digital_gain),
1122 SOC_SINGLE_S8_TLV("DEC2 Volume",
1123 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
1124 -84, 40, digital_gain),
1125
1126 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
1127 MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL,
1128 -84, 40, digital_gain),
1129 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
1130 MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL,
1131 -84, 40, digital_gain),
1132 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
1133 MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL,
1134 -84, 40, digital_gain),
1135 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume",
1136 MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
1137 -84, 40, digital_gain),
1138
Kuirong Wang265f3592012-12-05 16:17:41 -08001139 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
1140 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
1141
1142 SOC_SINGLE("TX1 HPF Switch", MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 3, 1, 0),
1143 SOC_SINGLE("TX2 HPF Switch", MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 3, 1, 0),
1144
1145 SOC_SINGLE("RX1 HPF Switch", MSM8X10_WCD_A_CDC_RX1_B5_CTL, 2, 1, 0),
1146 SOC_SINGLE("RX2 HPF Switch", MSM8X10_WCD_A_CDC_RX2_B5_CTL, 2, 1, 0),
1147 SOC_SINGLE("RX3 HPF Switch", MSM8X10_WCD_A_CDC_RX3_B5_CTL, 2, 1, 0),
1148
1149 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1150 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1151 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
1152
1153 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1154 msm8x10_wcd_get_iir_enable_audio_mixer,
1155 msm8x10_wcd_put_iir_enable_audio_mixer),
1156 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1157 msm8x10_wcd_get_iir_enable_audio_mixer,
1158 msm8x10_wcd_put_iir_enable_audio_mixer),
1159 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1160 msm8x10_wcd_get_iir_enable_audio_mixer,
1161 msm8x10_wcd_put_iir_enable_audio_mixer),
1162 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1163 msm8x10_wcd_get_iir_enable_audio_mixer,
1164 msm8x10_wcd_put_iir_enable_audio_mixer),
1165 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1166 msm8x10_wcd_get_iir_enable_audio_mixer,
1167 msm8x10_wcd_put_iir_enable_audio_mixer),
1168 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1169 msm8x10_wcd_get_iir_enable_audio_mixer,
1170 msm8x10_wcd_put_iir_enable_audio_mixer),
1171 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1172 msm8x10_wcd_get_iir_enable_audio_mixer,
1173 msm8x10_wcd_put_iir_enable_audio_mixer),
1174 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1175 msm8x10_wcd_get_iir_enable_audio_mixer,
1176 msm8x10_wcd_put_iir_enable_audio_mixer),
1177 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1178 msm8x10_wcd_get_iir_enable_audio_mixer,
1179 msm8x10_wcd_put_iir_enable_audio_mixer),
1180 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1181 msm8x10_wcd_get_iir_enable_audio_mixer,
1182 msm8x10_wcd_put_iir_enable_audio_mixer),
1183
1184 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1185 msm8x10_wcd_get_iir_band_audio_mixer,
1186 msm8x10_wcd_put_iir_band_audio_mixer),
1187 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1188 msm8x10_wcd_get_iir_band_audio_mixer,
1189 msm8x10_wcd_put_iir_band_audio_mixer),
1190 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1191 msm8x10_wcd_get_iir_band_audio_mixer,
1192 msm8x10_wcd_put_iir_band_audio_mixer),
1193 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1194 msm8x10_wcd_get_iir_band_audio_mixer,
1195 msm8x10_wcd_put_iir_band_audio_mixer),
1196 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1197 msm8x10_wcd_get_iir_band_audio_mixer,
1198 msm8x10_wcd_put_iir_band_audio_mixer),
1199 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1200 msm8x10_wcd_get_iir_band_audio_mixer,
1201 msm8x10_wcd_put_iir_band_audio_mixer),
1202 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1203 msm8x10_wcd_get_iir_band_audio_mixer,
1204 msm8x10_wcd_put_iir_band_audio_mixer),
1205 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1206 msm8x10_wcd_get_iir_band_audio_mixer,
1207 msm8x10_wcd_put_iir_band_audio_mixer),
1208 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1209 msm8x10_wcd_get_iir_band_audio_mixer,
1210 msm8x10_wcd_put_iir_band_audio_mixer),
1211 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1212 msm8x10_wcd_get_iir_band_audio_mixer,
1213 msm8x10_wcd_put_iir_band_audio_mixer),
1214
1215};
1216
1217static const char * const rx_mix1_text[] = {
1218 "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
1219};
1220
1221static const char * const rx_mix2_text[] = {
1222 "ZERO", "IIR1", "IIR2"
1223};
1224
1225static const char * const dec_mux_text[] = {
1226 "ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
1227};
1228
Kuirong Wanga0185b12013-07-26 17:49:13 -07001229static const char * const adc2_mux_text[] = {
1230 "ZERO", "INP2", "INP3"
Kuirong Wang265f3592012-12-05 16:17:41 -08001231};
1232
1233static const char * const iir1_inp1_text[] = {
1234 "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
1235};
1236
Kuirong Wang78468f12013-06-19 01:55:53 -07001237/*
1238 * There is only one bit to select RX2 (0) or RX3 (1) so add 'ZERO' won't
1239 * cause any issue to select the right input, but it eliminates that lineout
1240 * is powered-up when HPH is enabled if the 'ZERO" is used in the disable
1241 * sequence for lineout.
1242 */
1243static const char * const rx_rdac4_text[] = {
1244 "ZERO", "RX3", "RX2"
1245};
1246
Kuirong Wang265f3592012-12-05 16:17:41 -08001247static const struct soc_enum rx_mix1_inp1_chain_enum =
1248 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
1249
1250static const struct soc_enum rx_mix1_inp2_chain_enum =
1251 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text);
1252
1253static const struct soc_enum rx_mix1_inp3_chain_enum =
1254 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text);
1255
1256static const struct soc_enum rx2_mix1_inp1_chain_enum =
1257 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text);
1258
1259static const struct soc_enum rx2_mix1_inp2_chain_enum =
1260 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text);
1261
1262static const struct soc_enum rx3_mix1_inp1_chain_enum =
1263 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text);
1264
1265static const struct soc_enum rx3_mix1_inp2_chain_enum =
1266 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text);
1267
1268static const struct soc_enum rx1_mix2_inp1_chain_enum =
1269 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
1270
1271static const struct soc_enum rx2_mix2_inp1_chain_enum =
1272 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
1273
1274static const struct soc_enum dec1_mux_enum =
1275 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 0, 5, dec_mux_text);
1276
1277static const struct soc_enum dec2_mux_enum =
1278 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 3, 5, dec_mux_text);
1279
1280static const struct soc_enum iir1_inp1_mux_enum =
1281 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
1282 iir1_inp1_text);
1283
Kuirong Wang78468f12013-06-19 01:55:53 -07001284static const struct soc_enum rx_rdac4_enum =
1285 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
1286 rx_rdac4_text);
1287
Kuirong Wanga0185b12013-07-26 17:49:13 -07001288static const struct soc_enum adc2_enum =
1289 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
1290
Kuirong Wang265f3592012-12-05 16:17:41 -08001291static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1292 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1293
1294static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1295 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1296
1297static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1298 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1299
1300static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1301 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1302
1303static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1304 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1305
1306static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1307 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1308
1309static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1310 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1311
1312static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1313 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1314
1315static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1316 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1317
Kuirong Wang78468f12013-06-19 01:55:53 -07001318static const struct snd_kcontrol_new rx_dac4_mux =
1319 SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
1320
Kuirong Wanga0185b12013-07-26 17:49:13 -07001321static const struct snd_kcontrol_new tx_adc2_mux =
1322 SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
1323
Kuirong Wang265f3592012-12-05 16:17:41 -08001324static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
1325 struct snd_ctl_elem_value *ucontrol)
1326{
1327 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1328 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1329 struct snd_soc_codec *codec = w->codec;
1330 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1331 unsigned int dec_mux, decimator;
1332 char *dec_name = NULL;
1333 char *widget_name = NULL;
1334 char *temp;
1335 u16 tx_mux_ctl_reg;
1336 u8 adc_dmic_sel = 0x0;
1337 int ret = 0;
1338
1339 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1340 return -EINVAL;
1341
1342 dec_mux = ucontrol->value.enumerated.item[0];
1343
1344 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1345 if (!widget_name)
1346 return -ENOMEM;
1347 temp = widget_name;
1348
1349 dec_name = strsep(&widget_name, " ");
1350 widget_name = temp;
1351 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001352 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1353 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001354 ret = -EINVAL;
1355 goto out;
1356 }
1357
1358 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1359 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001360 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1361 __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001362 ret = -EINVAL;
1363 goto out;
1364 }
1365
1366 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1367 , __func__, w->name, decimator, dec_mux);
1368
1369 switch (decimator) {
1370 case 1:
1371 case 2:
Kuirong Wang265f3592012-12-05 16:17:41 -08001372 adc_dmic_sel = 0x0;
1373 break;
1374 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001375 dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
1376 __func__, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001377 ret = -EINVAL;
1378 goto out;
1379 }
1380
1381 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
1382
1383 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1384
1385 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1386
1387out:
1388 kfree(widget_name);
1389 return ret;
1390}
1391
1392#define MSM8X10_WCD_DEC_ENUM(xname, xenum) \
1393{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1394 .info = snd_soc_info_enum_double, \
1395 .get = snd_soc_dapm_get_enum_double, \
1396 .put = msm8x10_wcd_put_dec_enum, \
1397 .private_value = (unsigned long)&xenum }
1398
1399static const struct snd_kcontrol_new dec1_mux =
1400 MSM8X10_WCD_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1401
1402static const struct snd_kcontrol_new dec2_mux =
1403 MSM8X10_WCD_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1404
1405static const struct snd_kcontrol_new iir1_inp1_mux =
1406 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1407
1408static const struct snd_kcontrol_new dac1_switch[] = {
1409 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_EAR_EN, 5, 1, 0)
1410};
1411static const struct snd_kcontrol_new hphl_switch[] = {
1412 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1413};
1414
Kuirong Wang78468f12013-06-19 01:55:53 -07001415static const struct snd_kcontrol_new spkr_switch[] = {
1416 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
1417};
1418
Kuirong Wang265f3592012-12-05 16:17:41 -08001419static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
1420 int enable)
1421{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001422 struct msm8x10_wcd_priv *wcd8x10 = snd_soc_codec_get_drvdata(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08001423
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001424 dev_dbg(codec->dev, "%s %d\n", __func__, enable);
Kuirong Wang265f3592012-12-05 16:17:41 -08001425
1426 if (enable) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001427 wcd8x10->adc_count++;
Kuirong Wang265f3592012-12-05 16:17:41 -08001428 snd_soc_update_bits(codec,
1429 MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1430 0x20, 0x20);
Simmi Pateriyaeba2d5e2013-09-23 13:14:44 +05301431 } else
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001432 wcd8x10->adc_count--;
Kuirong Wang265f3592012-12-05 16:17:41 -08001433}
1434
1435static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
1436 struct snd_kcontrol *kcontrol, int event)
1437{
1438 struct snd_soc_codec *codec = w->codec;
1439 u16 adc_reg;
1440 u8 init_bit_shift;
1441
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001442 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001443 adc_reg = MSM8X10_WCD_A_TX_1_2_TEST_CTL;
1444
1445 if (w->reg == MSM8X10_WCD_A_TX_1_EN)
1446 init_bit_shift = 7;
Kuirong Wanga0185b12013-07-26 17:49:13 -07001447 else if ((w->reg == MSM8X10_WCD_A_TX_2_EN) ||
1448 (w->reg == MSM8X10_WCD_A_TX_3_EN))
Kuirong Wang265f3592012-12-05 16:17:41 -08001449 init_bit_shift = 6;
1450 else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001451 dev_err(codec->dev, "%s: Error, invalid adc register\n",
1452 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001453 return -EINVAL;
1454 }
1455
1456 switch (event) {
1457 case SND_SOC_DAPM_PRE_PMU:
1458 msm8x10_wcd_codec_enable_adc_block(codec, 1);
1459 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1460 1 << init_bit_shift);
Kuirong Wanga0185b12013-07-26 17:49:13 -07001461 usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
Kuirong Wang265f3592012-12-05 16:17:41 -08001462 break;
1463 case SND_SOC_DAPM_POST_PMU:
1464 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
Kuirong Wanga0185b12013-07-26 17:49:13 -07001465 usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
Kuirong Wang265f3592012-12-05 16:17:41 -08001466 break;
1467 case SND_SOC_DAPM_POST_PMD:
1468 msm8x10_wcd_codec_enable_adc_block(codec, 0);
1469 break;
1470 }
1471 return 0;
1472}
1473
1474static int msm8x10_wcd_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1475 struct snd_kcontrol *kcontrol, int event)
1476{
1477 struct snd_soc_codec *codec = w->codec;
1478 u16 lineout_gain_reg;
1479
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001480 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001481
1482 switch (w->shift) {
1483 case 0:
1484 lineout_gain_reg = MSM8X10_WCD_A_RX_LINE_1_GAIN;
1485 break;
1486 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001487 dev_err(codec->dev,
1488 "%s: Error, incorrect lineout register value\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001489 __func__);
1490 return -EINVAL;
1491 }
1492
1493 switch (event) {
1494 case SND_SOC_DAPM_PRE_PMU:
1495 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1496 break;
1497 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001498 dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
1499 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001500 usleep_range(16000, 16100);
1501 break;
1502 case SND_SOC_DAPM_POST_PMD:
1503 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1504 break;
1505 }
1506 return 0;
1507}
1508
1509static int msm8x10_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1510 struct snd_kcontrol *kcontrol, int event)
1511{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001512 dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001513 return 0;
1514}
1515
1516static int msm8x10_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1517 struct snd_kcontrol *kcontrol, int event)
1518{
1519 struct snd_soc_codec *codec = w->codec;
1520 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1521 u8 dmic_clk_en;
1522 u16 dmic_clk_reg;
1523 s32 *dmic_clk_cnt;
1524 unsigned int dmic;
1525 int ret;
1526
1527 ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
1528 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001529 dev_err(codec->dev,
1530 "%s: Invalid DMIC line on the codec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001531 return -EINVAL;
1532 }
1533
1534 switch (dmic) {
1535 case 1:
1536 case 2:
1537 dmic_clk_en = 0x01;
1538 dmic_clk_cnt = &(msm8x10_wcd->dmic_1_2_clk_cnt);
1539 dmic_clk_reg = MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001540 dev_dbg(codec->dev,
1541 "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001542 __func__, event, dmic, *dmic_clk_cnt);
1543 break;
1544 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001545 dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001546 return -EINVAL;
1547 }
1548
1549 switch (event) {
1550 case SND_SOC_DAPM_PRE_PMU:
1551
1552 (*dmic_clk_cnt)++;
1553 if (*dmic_clk_cnt == 1)
1554 snd_soc_update_bits(codec, dmic_clk_reg,
1555 dmic_clk_en, dmic_clk_en);
1556 break;
1557 case SND_SOC_DAPM_POST_PMD:
1558
1559 (*dmic_clk_cnt)--;
1560 if (*dmic_clk_cnt == 0)
1561 snd_soc_update_bits(codec, dmic_clk_reg,
1562 dmic_clk_en, 0);
1563 break;
1564 }
1565 return 0;
1566}
1567
1568static int msm8x10_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1569 struct snd_kcontrol *kcontrol, int event)
1570{
1571 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001572 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08001573 u16 micb_int_reg;
Kuirong Wang265f3592012-12-05 16:17:41 -08001574 char *internal1_text = "Internal1";
1575 char *internal2_text = "Internal2";
1576 char *internal3_text = "Internal3";
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001577 enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
Kuirong Wang265f3592012-12-05 16:17:41 -08001578
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001579 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001580 switch (w->reg) {
1581 case MSM8X10_WCD_A_MICB_1_CTL:
1582 micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001583 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
1584 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
1585 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
Kuirong Wang265f3592012-12-05 16:17:41 -08001586 break;
1587 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001588 dev_err(codec->dev,
Kuirong Wang91e52532013-03-31 14:24:22 -07001589 "%s: Error, invalid micbias register 0x%x\n",
1590 __func__, w->reg);
Kuirong Wang265f3592012-12-05 16:17:41 -08001591 return -EINVAL;
1592 }
1593
1594 switch (event) {
1595 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001596 /* Let MBHC module know micbias is about to turn ON */
1597 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
1598
Kuirong Wang265f3592012-12-05 16:17:41 -08001599 if (strnstr(w->name, internal1_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001600 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
Kuirong Wang265f3592012-12-05 16:17:41 -08001601 else if (strnstr(w->name, internal2_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001602 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08001603 else if (strnstr(w->name, internal3_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001604 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
Bhalchandra Gajare76fcfc62013-09-23 17:30:48 -07001605
1606 /* Always pull up TxFe for TX2 to Micbias */
1607 snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
Kuirong Wang265f3592012-12-05 16:17:41 -08001608 break;
1609 case SND_SOC_DAPM_POST_PMU:
1610 usleep_range(20000, 20100);
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001611 /* Let MBHC module know so micbias is on */
1612 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
Kuirong Wang265f3592012-12-05 16:17:41 -08001613 break;
1614 case SND_SOC_DAPM_POST_PMD:
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001615 /* Let MBHC module know so micbias switch to be off */
1616 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
1617
Kuirong Wang265f3592012-12-05 16:17:41 -08001618 if (strnstr(w->name, internal1_text, 30))
1619 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1620 else if (strnstr(w->name, internal2_text, 30))
1621 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1622 else if (strnstr(w->name, internal3_text, 30))
1623 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1624
Bhalchandra Gajare76fcfc62013-09-23 17:30:48 -07001625 /* Disable pull up TxFe for TX2 to Micbias */
1626 snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x00);
Kuirong Wang265f3592012-12-05 16:17:41 -08001627 break;
1628 }
Kuirong Wang265f3592012-12-05 16:17:41 -08001629 return 0;
1630}
1631
Kuirong Wang91e52532013-03-31 14:24:22 -07001632static void tx_hpf_corner_freq_callback(struct work_struct *work)
1633{
1634 struct delayed_work *hpf_delayed_work;
1635 struct hpf_work *hpf_work;
1636 struct msm8x10_wcd_priv *msm8x10_wcd;
1637 struct snd_soc_codec *codec;
1638 u16 tx_mux_ctl_reg;
1639 u8 hpf_cut_of_freq;
1640
1641 hpf_delayed_work = to_delayed_work(work);
1642 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
1643 msm8x10_wcd = hpf_work->msm8x10_wcd;
1644 codec = hpf_work->msm8x10_wcd->codec;
1645 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
1646
1647 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1648 (hpf_work->decimator - 1) * 32;
1649
1650 dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
1651 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
1652
1653 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
1654}
1655
1656
Kuirong Wang265f3592012-12-05 16:17:41 -08001657#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
1658#define CF_MIN_3DB_4HZ 0x0
1659#define CF_MIN_3DB_75HZ 0x1
1660#define CF_MIN_3DB_150HZ 0x2
1661
1662static int msm8x10_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
1663 struct snd_kcontrol *kcontrol, int event)
1664{
1665 struct snd_soc_codec *codec = w->codec;
1666 unsigned int decimator;
1667 char *dec_name = NULL;
1668 char *widget_name = NULL;
1669 char *temp;
1670 int ret = 0;
1671 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
1672 u8 dec_hpf_cut_of_freq;
1673 int offset;
1674
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001675 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001676
1677 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1678 if (!widget_name)
1679 return -ENOMEM;
1680 temp = widget_name;
1681
1682 dec_name = strsep(&widget_name, " ");
1683 widget_name = temp;
1684 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001685 dev_err(codec->dev,
1686 "%s: Invalid decimator = %s\n", __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001687 ret = -EINVAL;
1688 goto out;
1689 }
1690
1691 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1692 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001693 dev_err(codec->dev,
1694 "%s: Invalid decimator = %s\n", __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001695 ret = -EINVAL;
1696 goto out;
1697 }
1698
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001699 dev_dbg(codec->dev,
1700 "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
1701 w->name, dec_name, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001702
1703 if (w->reg == MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
1704 dec_reset_reg = MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
1705 offset = 0;
1706 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001707 dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001708 ret = -EINVAL;
1709 goto out;
1710 }
1711
1712 tx_vol_ctl_reg = MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG +
1713 32 * (decimator - 1);
1714 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1715 32 * (decimator - 1);
1716
1717 switch (event) {
1718 case SND_SOC_DAPM_PRE_PMU:
1719 /* Enableable TX digital mute */
1720 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1721
1722 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1723 1 << w->shift);
1724 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1725
1726 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
1727
1728 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
1729
1730 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
1731 dec_hpf_cut_of_freq;
1732
1733 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
1734
1735 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
1736 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1737 CF_MIN_3DB_150HZ << 4);
1738 }
1739
1740 /* enable HPF */
1741 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
1742 break;
1743 case SND_SOC_DAPM_POST_PMU:
1744 /* Disable TX digital mute */
1745 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
1746
1747 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
1748 CF_MIN_3DB_150HZ) {
1749
1750 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
1751 msecs_to_jiffies(300));
1752 }
1753 /* apply the digital gain after the decimator is enabled*/
1754 if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
1755 snd_soc_write(codec,
1756 tx_digital_gain_reg[w->shift + offset],
1757 snd_soc_read(codec,
1758 tx_digital_gain_reg[w->shift + offset])
1759 );
1760 break;
1761 case SND_SOC_DAPM_PRE_PMD:
1762 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1763 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
1764 break;
1765 case SND_SOC_DAPM_POST_PMD:
1766 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
1767 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1768 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
1769 break;
1770 }
1771out:
1772 kfree(widget_name);
1773 return ret;
1774}
1775
1776static int msm8x10_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001777 struct snd_kcontrol *kcontrol,
1778 int event)
Kuirong Wang265f3592012-12-05 16:17:41 -08001779{
1780 struct snd_soc_codec *codec = w->codec;
1781
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001782 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001783
1784 switch (event) {
1785 case SND_SOC_DAPM_PRE_PMU:
1786 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1787 1 << w->shift, 1 << w->shift);
1788 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1789 1 << w->shift, 0x0);
1790 break;
1791 case SND_SOC_DAPM_POST_PMU:
1792 /* apply the digital gain after the interpolator is enabled*/
1793 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
1794 snd_soc_write(codec,
1795 rx_digital_gain_reg[w->shift],
1796 snd_soc_read(codec,
1797 rx_digital_gain_reg[w->shift])
1798 );
1799 break;
1800 }
1801 return 0;
1802}
1803
1804
1805/* The register address is the same as other codec so it can use resmgr */
1806static int msm8x10_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1807 struct snd_kcontrol *kcontrol, int event)
1808{
1809 struct snd_soc_codec *codec = w->codec;
1810 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Kuirong Wang91e52532013-03-31 14:24:22 -07001811 msm8x10_wcd->resmgr.codec = codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08001812
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001813 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001814
1815 switch (event) {
1816 case SND_SOC_DAPM_PRE_PMU:
1817 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 1);
1818 break;
1819 case SND_SOC_DAPM_POST_PMD:
1820 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 0);
1821 break;
1822 }
1823 return 0;
1824}
1825
1826static int msm8x10_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
1827 struct snd_kcontrol *kcontrol, int event)
1828{
1829 struct snd_soc_codec *codec = w->codec;
1830
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001831 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001832
1833 switch (event) {
1834 case SND_SOC_DAPM_PRE_PMU:
1835 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1836 break;
1837 case SND_SOC_DAPM_POST_PMD:
1838 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1839 break;
1840 }
1841 return 0;
1842}
1843
1844static int msm8x10_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
1845 struct snd_kcontrol *kcontrol, int event)
1846{
1847 struct snd_soc_codec *codec = w->codec;
1848 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1849 enum wcd9xxx_notify_event e_pre_on, e_post_off;
1850
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001851 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001852 if (w->shift == 5) {
1853 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
1854 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
1855 } else if (w->shift == 4) {
1856 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
1857 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
1858 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001859 dev_err(codec->dev,
1860 "%s: Invalid w->shift %d\n", __func__, w->shift);
Kuirong Wang265f3592012-12-05 16:17:41 -08001861 return -EINVAL;
1862 }
1863
1864 switch (event) {
1865 case SND_SOC_DAPM_PRE_PMU:
1866 /* Let MBHC module know PA is turning on */
1867 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
1868 break;
1869
1870 case SND_SOC_DAPM_POST_PMU:
1871 usleep_range(10000, 10100);
1872 break;
1873
1874 case SND_SOC_DAPM_POST_PMD:
1875 /* Let MBHC module know PA turned off */
1876 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
1877
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001878 dev_dbg(codec->dev,
1879 "%s: sleep 10 ms after %s PA disable.\n", __func__,
1880 w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001881 usleep_range(10000, 10100);
1882 break;
1883 }
1884 return 0;
1885}
1886
1887static int msm8x10_wcd_lineout_dac_event(struct snd_soc_dapm_widget *w,
1888 struct snd_kcontrol *kcontrol, int event)
1889{
1890 struct snd_soc_codec *codec = w->codec;
1891
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001892 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001893
1894 switch (event) {
1895 case SND_SOC_DAPM_PRE_PMU:
1896 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1897 break;
1898
1899 case SND_SOC_DAPM_POST_PMD:
1900 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1901 break;
1902 }
1903 return 0;
1904}
1905
Kuirong Wang265f3592012-12-05 16:17:41 -08001906static const struct snd_soc_dapm_route audio_map[] = {
1907 {"RX_I2S_CLK", NULL, "CDC_CONN"},
1908 {"I2S RX1", NULL, "RX_I2S_CLK"},
1909 {"I2S RX2", NULL, "RX_I2S_CLK"},
1910 {"I2S RX3", NULL, "RX_I2S_CLK"},
1911
1912 {"I2S TX1", NULL, "TX_I2S_CLK"},
1913 {"I2S TX2", NULL, "TX_I2S_CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001914
Kuirong Wang91e52532013-03-31 14:24:22 -07001915 {"I2S TX1", NULL, "DEC1 MUX"},
1916 {"I2S TX2", NULL, "DEC2 MUX"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001917
1918 /* Earpiece (RX MIX1) */
1919 {"EAR", NULL, "EAR PA"},
1920 {"EAR PA", NULL, "DAC1"},
1921 {"DAC1", NULL, "CP"},
1922
Kuirong Wang1261b1d2013-08-06 18:18:21 -07001923 /* Clocks for playback path */
1924 {"DAC1", NULL, "EAR CLK"},
1925 {"HPHL DAC", NULL, "HPHL CLK"},
1926 {"HPHR DAC", NULL, "HPHR CLK"},
1927 {"SPK DAC", NULL, "SPK CLK"},
1928 {"LINEOUT DAC", NULL, "LINEOUT CLK"},
1929
Kuirong Wang265f3592012-12-05 16:17:41 -08001930 /* Headset (RX MIX1 and RX MIX2) */
1931 {"HEADPHONE", NULL, "HPHL"},
1932 {"HEADPHONE", NULL, "HPHR"},
1933
1934 {"HPHL", NULL, "HPHL DAC"},
1935
1936 {"HPHR", NULL, "HPHR DAC"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001937
1938 {"HPHL DAC", NULL, "CP"},
1939
1940 {"HPHR DAC", NULL, "CP"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001941 {"SPK DAC", NULL, "CP"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001942
1943 {"DAC1", "Switch", "RX1 CHAIN"},
1944 {"HPHL DAC", "Switch", "RX1 CHAIN"},
1945 {"HPHR DAC", NULL, "RX2 CHAIN"},
1946
Kuirong Wang91e52532013-03-31 14:24:22 -07001947 {"LINEOUT", NULL, "LINEOUT PA"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001948 {"SPK_OUT", NULL, "SPK PA"},
1949
Kuirong Wang91e52532013-03-31 14:24:22 -07001950 {"LINEOUT PA", NULL, "CP"},
1951 {"LINEOUT PA", NULL, "LINEOUT DAC"},
Kuirong Wang78468f12013-06-19 01:55:53 -07001952 {"LINEOUT DAC", NULL, "RDAC4 MUX"},
1953
1954 {"RDAC4 MUX", "RX2", "RX2 CHAIN"},
1955 {"RDAC4 MUX", "RX3", "RX3 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001956
Kuirong Wang49f506a2013-05-22 17:38:26 -07001957 {"CP", NULL, "CP_REGULATOR"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001958 {"CP", NULL, "RX_BIAS"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001959 {"SPK PA", NULL, "SPK DAC"},
Kuirong Wang78468f12013-06-19 01:55:53 -07001960 {"SPK DAC", "Switch", "RX3 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001961
Kuirong Wang91e52532013-03-31 14:24:22 -07001962 {"RX1 CHAIN", NULL, "RX1 CLK"},
1963 {"RX2 CHAIN", NULL, "RX2 CLK"},
1964 {"RX3 CHAIN", NULL, "RX3 CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001965 {"RX1 CHAIN", NULL, "RX1 MIX2"},
1966 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Kuirong Wang91e52532013-03-31 14:24:22 -07001967 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001968
1969 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
1970 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
1971 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
1972 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
1973 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
1974 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
1975 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
1976 {"RX1 MIX2", NULL, "RX1 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001977 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001978 {"RX2 MIX2", NULL, "RX2 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001979 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08001980
1981 {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
1982 {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
1983 {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
1984 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
1985 {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
1986 {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
1987 {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
1988 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
1989 {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
1990 {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
1991 {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
1992
1993 {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
1994 {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
1995 {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
1996 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
1997 {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
1998 {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
1999 {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
2000 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
2001
2002 {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
2003 {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
2004 {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
2005 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
2006 {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
2007 {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
2008 {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
2009 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
2010
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07002011 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
2012 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
2013
Kuirong Wang265f3592012-12-05 16:17:41 -08002014 /* Decimator Inputs */
2015 {"DEC1 MUX", "DMIC1", "DMIC1"},
2016 {"DEC1 MUX", "DMIC2", "DMIC2"},
2017 {"DEC1 MUX", "ADC1", "ADC1"},
2018 {"DEC1 MUX", "ADC2", "ADC2"},
2019 {"DEC1 MUX", NULL, "CDC_CONN"},
2020
2021 {"DEC2 MUX", "DMIC1", "DMIC1"},
2022 {"DEC2 MUX", "DMIC2", "DMIC2"},
2023 {"DEC2 MUX", "ADC1", "ADC1"},
2024 {"DEC2 MUX", "ADC2", "ADC2"},
2025 {"DEC2 MUX", NULL, "CDC_CONN"},
2026
Kuirong Wanga0185b12013-07-26 17:49:13 -07002027 {"ADC2", NULL, "ADC2 MUX"},
2028 {"ADC2 MUX", "INP2", "ADC2_INP2"},
2029 {"ADC2 MUX", "INP3", "ADC2_INP3"},
2030
Kuirong Wang265f3592012-12-05 16:17:41 -08002031 /* ADC Connections */
2032 {"ADC1", NULL, "AMIC1"},
Kuirong Wanga0185b12013-07-26 17:49:13 -07002033 {"ADC2_INP2", NULL, "AMIC2"},
2034 {"ADC2_INP3", NULL, "AMIC3"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002035
2036 {"IIR1", NULL, "IIR1 INP1 MUX"},
2037 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2038 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
quic_yandongy7424f1a2013-05-16 22:41:33 +08002039 {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
Kuirong Wang91e52532013-03-31 14:24:22 -07002040 {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
2041 {"MIC BIAS External", NULL, "INT_LDO_H"},
Kuirong Wang49f506a2013-05-22 17:38:26 -07002042 {"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
2043 {"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
2044 {"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002045};
2046
Kuirong Wang265f3592012-12-05 16:17:41 -08002047static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
2048 struct snd_soc_dai *dai)
2049{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002050 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
2051 __func__,
2052 substream->name, substream->stream);
Kuirong Wang265f3592012-12-05 16:17:41 -08002053 return 0;
2054}
2055
2056static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
2057 struct snd_soc_dai *dai)
2058{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002059 dev_dbg(dai->codec->dev,
2060 "%s(): substream = %s stream = %d\n" , __func__,
2061 substream->name, substream->stream);
Kuirong Wang91e52532013-03-31 14:24:22 -07002062}
2063
Kuirong Wang265f3592012-12-05 16:17:41 -08002064int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
2065 int mclk_enable, bool dapm)
2066{
2067 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
2068
Kuirong Wang91e52532013-03-31 14:24:22 -07002069 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
2070 __func__, mclk_enable, dapm);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002071
2072 WCD9XXX_BG_CLK_LOCK(&msm8x10_wcd->resmgr);
2073
Kuirong Wang265f3592012-12-05 16:17:41 -08002074 if (mclk_enable) {
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002075 wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
2076 WCD9XXX_BANDGAP_AUDIO_MODE);
2077 wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
2078 WCD9XXX_CLK_MCLK);
Kuirong Wang265f3592012-12-05 16:17:41 -08002079 } else {
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002080 wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
2081 WCD9XXX_CLK_MCLK);
2082 wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
2083 WCD9XXX_BANDGAP_AUDIO_MODE);
Kuirong Wang265f3592012-12-05 16:17:41 -08002084 }
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002085 WCD9XXX_BG_CLK_UNLOCK(&msm8x10_wcd->resmgr);
Kuirong Wang265f3592012-12-05 16:17:41 -08002086 return 0;
2087}
2088
2089static int msm8x10_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
2090 int clk_id, unsigned int freq, int dir)
2091{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002092 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002093 return 0;
2094}
2095
2096static int msm8x10_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2097{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002098 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002099 return 0;
2100}
2101
2102static int msm8x10_wcd_set_channel_map(struct snd_soc_dai *dai,
2103 unsigned int tx_num, unsigned int *tx_slot,
2104 unsigned int rx_num, unsigned int *rx_slot)
2105
2106{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002107 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002108 return 0;
2109}
2110
2111static int msm8x10_wcd_get_channel_map(struct snd_soc_dai *dai,
2112 unsigned int *tx_num, unsigned int *tx_slot,
2113 unsigned int *rx_num, unsigned int *rx_slot)
2114
2115{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002116 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002117 return 0;
2118}
2119
2120static int msm8x10_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
2121 u8 rx_fs_rate_reg_val, u32 sample_rate)
2122{
2123 return 0;
2124}
2125
2126static int msm8x10_wcd_set_decimator_rate(struct snd_soc_dai *dai,
2127 u8 tx_fs_rate_reg_val, u32 sample_rate)
2128{
2129 return 0;
2130}
2131
2132static int msm8x10_wcd_hw_params(struct snd_pcm_substream *substream,
2133 struct snd_pcm_hw_params *params,
2134 struct snd_soc_dai *dai)
2135{
2136 u8 tx_fs_rate, rx_fs_rate;
2137 int ret;
2138
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002139 dev_dbg(dai->codec->dev,
2140 "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002141 dai->name, dai->id, params_rate(params),
2142 params_channels(params));
2143
2144 switch (params_rate(params)) {
2145 case 8000:
2146 tx_fs_rate = 0x00;
2147 rx_fs_rate = 0x00;
2148 break;
2149 case 16000:
2150 tx_fs_rate = 0x01;
2151 rx_fs_rate = 0x20;
2152 break;
2153 case 32000:
2154 tx_fs_rate = 0x02;
2155 rx_fs_rate = 0x40;
2156 break;
2157 case 48000:
2158 tx_fs_rate = 0x03;
2159 rx_fs_rate = 0x60;
2160 break;
2161 case 96000:
2162 tx_fs_rate = 0x04;
2163 rx_fs_rate = 0x80;
2164 break;
2165 case 192000:
2166 tx_fs_rate = 0x05;
2167 rx_fs_rate = 0xA0;
2168 break;
2169 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002170 dev_err(dai->codec->dev,
2171 "%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002172 params_rate(params));
2173 return -EINVAL;
2174 }
2175
2176 switch (substream->stream) {
2177 case SNDRV_PCM_STREAM_CAPTURE:
2178 ret = msm8x10_wcd_set_decimator_rate(dai, tx_fs_rate,
2179 params_rate(params));
2180 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002181 dev_err(dai->codec->dev,
2182 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002183 ret);
2184 return ret;
2185 }
2186 break;
2187 case SNDRV_PCM_STREAM_PLAYBACK:
2188 ret = msm8x10_wcd_set_interpolator_rate(dai, rx_fs_rate,
2189 params_rate(params));
2190 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002191 dev_err(dai->codec->dev,
2192 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002193 ret);
2194 return ret;
2195 }
2196 break;
2197 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002198 dev_err(dai->codec->dev,
2199 "%s: Invalid stream type %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002200 substream->stream);
2201 return -EINVAL;
2202 }
2203
2204 return 0;
2205}
2206
2207static struct snd_soc_dai_ops msm8x10_wcd_dai_ops = {
2208 .startup = msm8x10_wcd_startup,
2209 .shutdown = msm8x10_wcd_shutdown,
2210 .hw_params = msm8x10_wcd_hw_params,
2211 .set_sysclk = msm8x10_wcd_set_dai_sysclk,
2212 .set_fmt = msm8x10_wcd_set_dai_fmt,
2213 .set_channel_map = msm8x10_wcd_set_channel_map,
2214 .get_channel_map = msm8x10_wcd_get_channel_map,
2215};
2216
2217static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[] = {
2218 {
2219 .name = "msm8x10_wcd_i2s_rx1",
2220 .id = AIF1_PB,
2221 .playback = {
2222 .stream_name = "AIF1 Playback",
2223 .rates = MSM8X10_WCD_RATES,
2224 .formats = MSM8X10_WCD_FORMATS,
2225 .rate_max = 192000,
2226 .rate_min = 8000,
2227 .channels_min = 1,
Kuirong Wang91e52532013-03-31 14:24:22 -07002228 .channels_max = 3,
Kuirong Wang265f3592012-12-05 16:17:41 -08002229 },
2230 .ops = &msm8x10_wcd_dai_ops,
2231 },
2232 {
2233 .name = "msm8x10_wcd_i2s_tx1",
2234 .id = AIF1_CAP,
2235 .capture = {
2236 .stream_name = "AIF1 Capture",
2237 .rates = MSM8X10_WCD_RATES,
2238 .formats = MSM8X10_WCD_FORMATS,
2239 .rate_max = 192000,
2240 .rate_min = 8000,
2241 .channels_min = 1,
2242 .channels_max = 4,
2243 },
2244 .ops = &msm8x10_wcd_dai_ops,
2245 },
2246};
2247
2248static int msm8x10_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
2249 struct snd_kcontrol *kcontrol, int event)
2250{
2251 switch (event) {
2252 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002253 dev_dbg(w->codec->dev,
2254 "%s: Sleeping 20ms after enabling EAR PA\n",
2255 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002256 msleep(20);
2257 break;
2258 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002259 dev_dbg(w->codec->dev,
2260 "%s: Sleeping 20ms after disabling EAR PA\n",
2261 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002262 msleep(20);
2263 break;
2264 }
2265 return 0;
2266}
2267
2268static const struct snd_soc_dapm_widget msm8x10_wcd_dapm_widgets[] = {
2269 /*RX stuff */
2270 SND_SOC_DAPM_OUTPUT("EAR"),
2271
2272 SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
2273 msm8x10_wcd_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU),
2274
2275 SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
2276 ARRAY_SIZE(dac1_switch)),
2277
Kuirong Wang91e52532013-03-31 14:24:22 -07002278 SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002279
Kuirong Wang91e52532013-03-31 14:24:22 -07002280 SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002281
Kuirong Wang91e52532013-03-31 14:24:22 -07002282 SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002283
Kuirong Wang91e52532013-03-31 14:24:22 -07002284 SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
2285
Kuirong Wang265f3592012-12-05 16:17:41 -08002286 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2287 SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2288 5, 0, NULL, 0,
2289 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2290 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2291 SND_SOC_DAPM_MIXER("HPHL DAC", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL,
2292 7, 0,
2293 hphl_switch, ARRAY_SIZE(hphl_switch)),
2294
2295 SND_SOC_DAPM_PGA_E("HPHR", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2296 4, 0, NULL, 0,
2297 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2298 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2299
2300 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, MSM8X10_WCD_A_RX_HPH_R_DAC_CTL,
2301 7, 0,
2302 msm8x10_wcd_hphr_dac_event,
2303 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2304
Kuirong Wang78468f12013-06-19 01:55:53 -07002305 SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
2306 spkr_switch, ARRAY_SIZE(spkr_switch)),
2307
Kuirong Wang265f3592012-12-05 16:17:41 -08002308 /* Speaker */
Kuirong Wang91e52532013-03-31 14:24:22 -07002309 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002310 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
2311
Kuirong Wang91e52532013-03-31 14:24:22 -07002312 SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
Kuirong Wang265f3592012-12-05 16:17:41 -08002313 0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
2314 SND_SOC_DAPM_PRE_PMU |
2315 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2316
2317 SND_SOC_DAPM_PGA_E("SPK PA", MSM8X10_WCD_A_SPKR_DRV_EN,
2318 7, 0 , NULL, 0, msm8x10_wcd_codec_enable_spk_pa,
2319 SND_SOC_DAPM_PRE_PMU |
2320 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2321
Kuirong Wang91e52532013-03-31 14:24:22 -07002322 SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
Kuirong Wang265f3592012-12-05 16:17:41 -08002323 MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
2324 msm8x10_wcd_lineout_dac_event,
2325 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2326
Kuirong Wang265f3592012-12-05 16:17:41 -08002327 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2328 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2329
2330 SND_SOC_DAPM_MIXER_E("RX1 MIX2",
2331 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
2332 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2333 SND_SOC_DAPM_POST_PMU),
2334 SND_SOC_DAPM_MIXER_E("RX2 MIX2",
2335 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
2336 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2337 SND_SOC_DAPM_POST_PMU),
2338 SND_SOC_DAPM_MIXER_E("RX3 MIX1",
2339 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
2340 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2341 SND_SOC_DAPM_POST_PMU),
2342
Kuirong Wang91e52532013-03-31 14:24:22 -07002343 SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2344 0, 0, NULL, 0),
2345 SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2346 1, 0, NULL, 0),
2347 SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2348 2, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002349 SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
2350 5, 0, NULL, 0),
2351 SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
2352 5, 0, NULL, 0),
Kuirong Wang91e52532013-03-31 14:24:22 -07002353 SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
2354 5, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002355
Kuirong Wang1261b1d2013-08-06 18:18:21 -07002356 SND_SOC_DAPM_SUPPLY("HPHR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2357 0, 0, NULL, 0),
2358 SND_SOC_DAPM_SUPPLY("HPHL CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2359 1, 0, NULL, 0),
2360 SND_SOC_DAPM_SUPPLY("EAR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2361 2, 0, NULL, 0),
2362 SND_SOC_DAPM_SUPPLY("LINEOUT CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2363 3, 0, NULL, 0),
2364 SND_SOC_DAPM_SUPPLY("SPK CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2365 4, 0, NULL, 0),
2366
Kuirong Wang265f3592012-12-05 16:17:41 -08002367 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2368 &rx_mix1_inp1_mux),
2369 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2370 &rx_mix1_inp2_mux),
2371 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
2372 &rx_mix1_inp3_mux),
2373 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2374 &rx2_mix1_inp1_mux),
2375 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2376 &rx2_mix1_inp2_mux),
2377 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2378 &rx3_mix1_inp1_mux),
2379 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2380 &rx3_mix1_inp2_mux),
2381 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2382 &rx1_mix2_inp1_mux),
2383 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2384 &rx2_mix2_inp1_mux),
Kuirong Wang78468f12013-06-19 01:55:53 -07002385 SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
2386 &rx_dac4_mux),
Kuirong Wang265f3592012-12-05 16:17:41 -08002387
Kuirong Wang49f506a2013-05-22 17:38:26 -07002388 SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
2389 ON_DEMAND_MICBIAS, 0,
2390 msm8x10_wcd_codec_enable_on_demand_supply,
2391 SND_SOC_DAPM_PRE_PMU |
2392 SND_SOC_DAPM_POST_PMD),
2393
2394 SND_SOC_DAPM_SUPPLY("CP_REGULATOR", SND_SOC_NOPM,
2395 ON_DEMAND_CP, 0,
2396 msm8x10_wcd_codec_enable_on_demand_supply,
2397 SND_SOC_DAPM_PRE_PMU |
2398 SND_SOC_DAPM_POST_PMD),
2399
Kuirong Wang265f3592012-12-05 16:17:41 -08002400 SND_SOC_DAPM_SUPPLY("CP", MSM8X10_WCD_A_CP_EN, 0, 0,
Kuirong Wang49f506a2013-05-22 17:38:26 -07002401 msm8x10_wcd_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2402 SND_SOC_DAPM_PRE_PMD),
Kuirong Wang265f3592012-12-05 16:17:41 -08002403
2404 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2405 msm8x10_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2406 SND_SOC_DAPM_POST_PMD),
2407
2408 /* TX */
2409
2410 SND_SOC_DAPM_SUPPLY("CDC_CONN", MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
2411 2, 0, NULL, 0),
2412
2413
2414 SND_SOC_DAPM_INPUT("AMIC1"),
Kuirong Wang91e52532013-03-31 14:24:22 -07002415 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
Kuirong Wang265f3592012-12-05 16:17:41 -08002416 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2417 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2418 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002419 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
Kuirong Wang265f3592012-12-05 16:17:41 -08002420 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2421 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2422 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002423 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
Kuirong Wang265f3592012-12-05 16:17:41 -08002424 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2425 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2426 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriyafaf04292013-10-01 17:05:44 +05302427 SND_SOC_DAPM_MICBIAS_E("MIC BIAS External",
2428 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2429 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2430 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2431
Kuirong Wang265f3592012-12-05 16:17:41 -08002432 SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
2433 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2434 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wanga0185b12013-07-26 17:49:13 -07002435 SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
Kuirong Wang265f3592012-12-05 16:17:41 -08002436 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2437 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wanga0185b12013-07-26 17:49:13 -07002438 SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, MSM8X10_WCD_A_TX_3_EN, 7, 0,
2439 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2440 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2441
2442 SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
2443
2444 SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
2445 &tx_adc2_mux),
Kuirong Wang265f3592012-12-05 16:17:41 -08002446
2447 SND_SOC_DAPM_INPUT("AMIC3"),
2448
2449 SND_SOC_DAPM_MUX_E("DEC1 MUX",
2450 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
2451 &dec1_mux, msm8x10_wcd_codec_enable_dec,
2452 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2453 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2454
2455 SND_SOC_DAPM_MUX_E("DEC2 MUX",
2456 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
2457 &dec2_mux, msm8x10_wcd_codec_enable_dec,
2458 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2459 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2460
2461 SND_SOC_DAPM_INPUT("AMIC2"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002462
Kuirong Wang91e52532013-03-31 14:24:22 -07002463 SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
2464 0, 0),
2465 SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
2466 0, 0),
2467 SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
2468 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002469
2470 /* Digital Mic Inputs */
2471 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2472 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2473 SND_SOC_DAPM_POST_PMD),
2474
2475 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2476 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2477 SND_SOC_DAPM_POST_PMD),
2478
2479 /* Sidetone */
2480 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2481 SND_SOC_DAPM_PGA("IIR1", MSM8X10_WCD_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2482
2483 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL,
2484 4, 0, NULL, 0),
2485 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL, 4,
2486 0, NULL, 0),
2487};
2488
2489static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
2490
2491 /* set MCLk to 9.6 */
Kuirong Wang91e52532013-03-31 14:24:22 -07002492 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
Kuirong Wang265f3592012-12-05 16:17:41 -08002493
2494 /* EAR PA deafults */
2495 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
2496
2497 /* RX deafults */
2498 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B5_CTL, 0x78),
2499 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B5_CTL, 0x78),
2500 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B5_CTL, 0x78),
2501
2502 /* RX1 and RX2 defaults */
2503 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xA0),
2504 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xA0),
2505
2506 /* RX3 to RX7 defaults */
2507 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B6_CTL, 0x80),
2508
2509 /* Reduce HPH DAC bias to 70% */
2510 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_HPH_BIAS_PA, 0x7A),
2511 /*Reduce EAR DAC bias to 70% */
2512 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_BIAS_PA, 0x76),
2513 /* Reduce LINE DAC bias to 70% */
2514 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
2515
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002516 /* Disable internal biasing path which can cause leakage */
Kuirong Wang91e52532013-03-31 14:24:22 -07002517 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
2518 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_CFILT_1_VAL, 0x60),
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002519 /* Enable pulldown to reduce leakage */
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002520 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_MICB_1_CTL, 0x82),
Kuirong Wang91e52532013-03-31 14:24:22 -07002521 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
Kuirong Wangf046d7c2013-08-28 11:52:49 -07002522 /* Keep the same default gain settings for TX paths */
Kuirong Wang91e52532013-03-31 14:24:22 -07002523 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
2524 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
Kuirong Wangf046d7c2013-08-28 11:52:49 -07002525 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_3_EN, 0x30),
Kuirong Wang269ae352013-05-23 11:31:58 -07002526
2527 /* ClassG fine tuning setting for 16 ohm HPH */
2528 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL, 0x05),
2529 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL, 0x0C),
2530 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1A),
2531 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x47),
2532 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL, 0x23),
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002533
2534 /* Always set TXD_CLK_EN bit to reduce the leakage */
2535 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002536
2537 /* Always disable clock gating for MCLK to mbhc clock gate */
2538 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0x20),
2539 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
Kuirong Wang265f3592012-12-05 16:17:41 -08002540};
2541
2542static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
2543{
2544 u32 i;
2545
2546 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_reg_defaults); i++)
2547 snd_soc_write(codec, msm8x10_wcd_reg_defaults[i].reg,
2548 msm8x10_wcd_reg_defaults[i].val);
2549}
2550
2551static const struct msm8x10_wcd_reg_mask_val
2552 msm8x10_wcd_codec_reg_init_val[] = {
2553 /* Initialize current threshold to 350MA
2554 * number of wait and run cycles to 4096
2555 */
2556 {MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
2557 {MSM8X10_WCD_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
2558
2559 /* Initialize gain registers to use register gain */
2560 {MSM8X10_WCD_A_RX_HPH_L_GAIN, 0x20, 0x20},
2561 {MSM8X10_WCD_A_RX_HPH_R_GAIN, 0x20, 0x20},
2562 {MSM8X10_WCD_A_RX_LINE_1_GAIN, 0x20, 0x20},
2563
2564 /*enable HPF filter for TX paths */
2565 {MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
2566 {MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
2567
2568 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
2569 {MSM8X10_WCD_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
2570 {MSM8X10_WCD_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
2571
2572 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
2573 {MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
2574
Kuirong Wang78468f12013-06-19 01:55:53 -07002575 /* Disable REF_EN for MSM8X10_WCD_A_SPKR_DRV_DAC_CTL */
2576 {MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
Kuirong Wang265f3592012-12-05 16:17:41 -08002577};
2578
2579static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
2580{
2581 u32 i;
2582
2583 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_codec_reg_init_val); i++)
2584 snd_soc_update_bits(codec,
2585 msm8x10_wcd_codec_reg_init_val[i].reg,
2586 msm8x10_wcd_codec_reg_init_val[i].mask,
2587 msm8x10_wcd_codec_reg_init_val[i].val);
2588}
2589
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002590static void msm8x10_wcd_enable_mux_bias_block(
2591 struct snd_soc_codec *codec)
2592{
2593 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
2594 0x80, 0x00);
2595}
2596
2597static void msm8x10_wcd_put_cfilt_fast_mode(
2598 struct snd_soc_codec *codec,
2599 struct wcd9xxx_mbhc *mbhc)
2600{
2601 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
2602 0x30, 0x30);
2603}
2604
2605static void msm8x10_wcd_codec_specific_cal_setup(
2606 struct snd_soc_codec *codec,
2607 struct wcd9xxx_mbhc *mbhc)
2608{
2609 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
2610 0x04, 0x04);
2611 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN,
2612 0xE0, 0xE0);
2613}
2614
2615static int msm8x10_wcd_get_jack_detect_irq(
2616 struct snd_soc_codec *codec)
2617{
2618 return MSM8X10_WCD_IRQ_MBHC_HS_DET;
2619}
2620
2621static struct wcd9xxx_cfilt_mode msm8x10_wcd_switch_cfilt_mode(
2622 struct wcd9xxx_mbhc *mbhc, bool fast)
2623{
2624 struct snd_soc_codec *codec = mbhc->codec;
2625 struct wcd9xxx_cfilt_mode cfilt_mode;
2626
2627 if (fast)
2628 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
2629 else
2630 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
2631
2632 cfilt_mode.cur_mode_val =
2633 snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
2634 cfilt_mode.reg_mask = 0x30;
2635 return cfilt_mode;
2636}
2637
2638static void msm8x10_wcd_select_cfilt(struct snd_soc_codec *codec,
2639 struct wcd9xxx_mbhc *mbhc)
2640{
2641 snd_soc_update_bits(codec,
2642 mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
2643}
2644
2645static void msm8x10_wcd_free_irq(struct wcd9xxx_mbhc *mbhc)
2646{
2647 struct msm8x10_wcd *msm8x10_wcd = mbhc->codec->control_data;
2648 struct wcd9xxx_core_resource *core_res =
2649 &msm8x10_wcd->wcd9xxx_res;
2650 wcd9xxx_free_irq(core_res, MSM8X10_WCD_IRQ_MBHC_HS_DET, mbhc);
2651}
2652
2653enum wcd9xxx_cdc_type msm8x10_wcd_get_cdc_type(void)
2654{
2655 return WCD9XXX_CDC_TYPE_HELICON;
2656}
2657
2658static void msm8x10_wcd_mbhc_clk_gate(struct snd_soc_codec *codec,
2659 bool on)
2660{
2661 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL, 0x10, 0x10);
2662}
2663
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07002664static void msm8x10_wcd_mbhc_txfe(struct snd_soc_codec *codec, bool on)
2665{
2666 snd_soc_update_bits(codec, MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL,
2667 0x80, on ? 0x80 : 0x00);
2668}
2669
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002670static int msm8x10_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
2671 bool turn_on)
2672{
2673 int ret = 0;
2674
2675 if (turn_on)
2676 ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
2677 "MICBIAS_REGULATOR");
2678 else
2679 ret = snd_soc_dapm_disable_pin(&codec->dapm,
2680 "MICBIAS_REGULATOR");
2681
2682 snd_soc_dapm_sync(&codec->dapm);
2683
2684 if (ret)
2685 dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
2686 __func__, turn_on ? "enable" : "disabled");
2687 else
2688 dev_dbg(codec->dev, "%s: %s external micbias source\n",
2689 __func__, turn_on ? "Enabled" : "Disabled");
2690
2691 return ret;
2692}
2693
Bhalchandra Gajare6a2296b2013-09-19 13:15:08 -07002694static void msm8x10_wcd_micb_internal(struct snd_soc_codec *codec, bool on)
2695{
2696 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_INT_RBIAS,
2697 0x1C, on ? 0x14 : 0x00);
2698}
2699
Bhalchandra Gajaref19a9262013-09-19 15:40:08 -07002700static void msm8x10_wcd_enable_mb_vddio(struct snd_soc_codec *codec, bool on)
2701{
2702 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_CTL,
2703 0x40, on ? 0x40 : 0x00);
2704}
2705
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002706static const struct wcd9xxx_mbhc_cb mbhc_cb = {
2707 .enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
2708 .cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
2709 .codec_specific_cal = msm8x10_wcd_codec_specific_cal_setup,
2710 .jack_detect_irq = msm8x10_wcd_get_jack_detect_irq,
2711 .switch_cfilt_mode = msm8x10_wcd_switch_cfilt_mode,
2712 .select_cfilt = msm8x10_wcd_select_cfilt,
2713 .free_irq = msm8x10_wcd_free_irq,
2714 .get_cdc_type = msm8x10_wcd_get_cdc_type,
2715 .enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07002716 .enable_mbhc_txfe = msm8x10_wcd_mbhc_txfe,
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002717 .enable_mb_source = msm8x10_wcd_enable_ext_mb_source,
Bhalchandra Gajare6a2296b2013-09-19 13:15:08 -07002718 .setup_int_rbias = msm8x10_wcd_micb_internal,
Bhalchandra Gajaref19a9262013-09-19 15:40:08 -07002719 .pull_mb_to_vddio = msm8x10_wcd_enable_mb_vddio,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002720};
2721
2722static void delayed_hs_detect_fn(struct work_struct *work)
2723{
2724 struct delayed_work *delayed_work;
2725 struct msm8x10_wcd_priv *wcd_priv;
2726
2727 delayed_work = to_delayed_work(work);
2728 wcd_priv = container_of(delayed_work, struct msm8x10_wcd_priv,
2729 hs_detect_work);
2730
2731 if (!wcd_priv) {
2732 pr_err("%s: Invalid private data for codec\n", __func__);
2733 return;
2734 }
2735
2736 wcd9xxx_mbhc_start(&wcd_priv->mbhc, wcd_priv->mbhc_cfg);
2737}
2738
2739
Kuirong Wang265f3592012-12-05 16:17:41 -08002740int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
Bhalchandra Gajare9c19dc22013-07-11 17:16:53 -07002741 struct wcd9xxx_mbhc_config *mbhc_cfg)
Kuirong Wang265f3592012-12-05 16:17:41 -08002742{
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002743 struct msm8x10_wcd_priv *wcd = snd_soc_codec_get_drvdata(codec);
2744
2745 wcd->mbhc_cfg = mbhc_cfg;
2746 schedule_delayed_work(&wcd->hs_detect_work,
2747 msecs_to_jiffies(5000));
Kuirong Wang265f3592012-12-05 16:17:41 -08002748 return 0;
2749}
2750EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
2751
Kuirong Wang2e81d322013-05-30 17:52:36 -07002752static int msm8x10_wcd_bringup(struct snd_soc_codec *codec)
2753{
2754 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
2755 snd_soc_write(codec, MSM8X10_WCD_A_CHIP_CTL, 0x00);
2756 usleep_range(5000, 5000);
2757 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
2758 return 0;
2759}
2760
Kuirong Wang49f506a2013-05-22 17:38:26 -07002761static struct regulator *wcd8x10_wcd_codec_find_regulator(
2762 const struct msm8x10_wcd *msm8x10,
2763 const char *name)
2764{
2765 int i;
2766
2767 for (i = 0; i < msm8x10->num_of_supplies; i++) {
2768 if (msm8x10->supplies[i].supply &&
2769 !strncmp(msm8x10->supplies[i].supply, name, strlen(name)))
2770 return msm8x10->supplies[i].consumer;
2771 }
2772
2773 return NULL;
2774}
2775
Fred Ohcf2f8582013-06-13 18:32:07 -07002776static int msm8x10_wcd_device_up(struct snd_soc_codec *codec)
2777{
2778 pr_debug("%s: device up!\n", __func__);
2779
2780 mutex_lock(&codec->mutex);
2781
2782 msm8x10_wcd_bringup(codec);
2783 msm8x10_wcd_codec_init_reg(codec);
2784 msm8x10_wcd_update_reg_defaults(codec);
2785
2786 mutex_unlock(&codec->mutex);
2787
2788 return 0;
2789}
2790
2791static int adsp_state_callback(struct notifier_block *nb, unsigned long value,
2792 void *priv)
2793{
2794 bool timedout;
2795 unsigned long timeout;
2796
2797 if (value == SUBSYS_AFTER_POWERUP) {
2798 pr_debug("%s: ADSP is about to power up. bring up codec\n",
2799 __func__);
2800
2801 timeout = jiffies +
2802 msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
2803 while (!(timedout = time_after(jiffies, timeout))) {
2804 if (!q6core_is_adsp_ready()) {
2805 pr_debug("%s: ADSP isn't ready\n", __func__);
2806 } else {
2807 pr_debug("%s: ADSP is ready\n", __func__);
2808 msm8x10_wcd_device_up(registered_codec);
2809 break;
2810 }
2811 }
2812 }
2813
2814 return NOTIFY_OK;
2815}
2816
2817static struct notifier_block adsp_state_notifier_block = {
2818 .notifier_call = adsp_state_callback,
2819 .priority = -INT_MAX,
2820};
2821
2822
Kuirong Wang265f3592012-12-05 16:17:41 -08002823static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
2824{
Fred Oh4d716bb2013-07-30 10:14:46 -07002825 struct msm8x10_wcd_priv *msm8x10_wcd_priv;
2826 struct msm8x10_wcd *msm8x10_wcd;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07002827 struct wcd9xxx_core_resource *core_res;
2828 int i, ret = 0;
Bhalchandra Gajare5cc8f322013-09-19 17:46:13 -07002829 struct msm8x10_wcd_pdata *pdata;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07002830
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002831 dev_dbg(codec->dev, "%s()\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002832
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07002833 msm8x10_wcd_priv = devm_kzalloc(codec->dev,
2834 sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
2835
Fred Oh4d716bb2013-07-30 10:14:46 -07002836 if (!msm8x10_wcd_priv) {
Kuirong Wang91e52532013-03-31 14:24:22 -07002837 dev_err(codec->dev, "Failed to allocate private data\n");
2838 return -ENOMEM;
2839 }
2840
2841 for (i = 0 ; i < NUM_DECIMATORS; i++) {
Fred Oh4d716bb2013-07-30 10:14:46 -07002842 tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd_priv;
Kuirong Wang91e52532013-03-31 14:24:22 -07002843 tx_hpf_work[i].decimator = i + 1;
2844 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
2845 tx_hpf_corner_freq_callback);
2846 }
2847
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002848 codec->control_data = dev_get_drvdata(codec->dev);
Fred Oh4d716bb2013-07-30 10:14:46 -07002849 snd_soc_codec_set_drvdata(codec, msm8x10_wcd_priv);
2850 msm8x10_wcd_priv->codec = codec;
2851
2852 /* map digital codec registers once */
2853 msm8x10_wcd = codec->control_data;
2854 msm8x10_wcd->pdino_base = ioremap(MSM8X10_DINO_CODEC_BASE_ADDR,
2855 MSM8X10_DINO_CODEC_REG_SIZE);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002856 INIT_DELAYED_WORK(&msm8x10_wcd_priv->hs_detect_work,
2857 delayed_hs_detect_fn);
Fred Oh4d716bb2013-07-30 10:14:46 -07002858
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07002859 /* codec resmgr module init */
2860 msm8x10_wcd = codec->control_data;
2861 core_res = &msm8x10_wcd->wcd9xxx_res;
2862 ret = wcd9xxx_resmgr_init(&msm8x10_wcd_priv->resmgr,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002863 codec, core_res, NULL, NULL,
2864 WCD9XXX_CDC_TYPE_HELICON);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07002865 if (ret) {
2866 dev_err(codec->dev,
2867 "%s: wcd9xxx init failed %d\n",
2868 __func__, ret);
2869 goto exit_probe;
2870 }
2871
Kuirong Wang2e81d322013-05-30 17:52:36 -07002872 msm8x10_wcd_bringup(codec);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002873 msm8x10_wcd_codec_init_reg(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08002874 msm8x10_wcd_update_reg_defaults(codec);
Bhalchandra Gajare5cc8f322013-09-19 17:46:13 -07002875
2876 pdata = dev_get_platdata(msm8x10_wcd->dev);
2877 if (!pdata) {
2878 dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
2879 __func__);
2880 }
2881
2882 /* update micbias capless mode */
2883 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
2884 pdata->micbias.bias1_cap_mode << 4);
2885
Fred Oh4d716bb2013-07-30 10:14:46 -07002886 msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].supply =
Kuirong Wang49f506a2013-05-22 17:38:26 -07002887 wcd8x10_wcd_codec_find_regulator(
2888 codec->control_data,
2889 on_demand_supply_name[ON_DEMAND_CP]);
Fred Oh4d716bb2013-07-30 10:14:46 -07002890 atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
2891 msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
Kuirong Wang49f506a2013-05-22 17:38:26 -07002892 wcd8x10_wcd_codec_find_regulator(
2893 codec->control_data,
2894 on_demand_supply_name[ON_DEMAND_MICBIAS]);
Fred Oh4d716bb2013-07-30 10:14:46 -07002895 atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07002896
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002897 ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
2898 &msm8x10_wcd_priv->resmgr,
2899 codec, NULL, &mbhc_cb,
2900 HELICON_MCLK_CLK_9P6MHZ, false);
2901 if (ret) {
2902 pr_err("%s: Failed to initialize mbhc\n", __func__);
2903 goto exit_probe;
2904 }
Kuirong Wang265f3592012-12-05 16:17:41 -08002905
Fred Ohcf2f8582013-06-13 18:32:07 -07002906 registered_codec = codec;
2907 adsp_state_notifier =
2908 subsys_notif_register_notifier("adsp",
2909 &adsp_state_notifier_block);
2910 if (!adsp_state_notifier) {
2911 pr_err("%s: Failed to register adsp state notifier\n",
2912 __func__);
2913 registered_codec = NULL;
2914 return -ENOMEM;
2915 }
Kuirong Wang265f3592012-12-05 16:17:41 -08002916 return 0;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07002917
2918exit_probe:
2919 return ret;
2920
Kuirong Wang265f3592012-12-05 16:17:41 -08002921}
2922
2923static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
2924{
Fred Oh4d716bb2013-07-30 10:14:46 -07002925 struct msm8x10_wcd_priv *pwcd_priv = snd_soc_codec_get_drvdata(codec);
2926 struct msm8x10_wcd *msm8x10_wcd = pwcd_priv->codec->control_data;
Fred Oh4d716bb2013-07-30 10:14:46 -07002927 pwcd_priv->on_demand_list[ON_DEMAND_CP].supply = NULL;
2928 atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
2929 pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
2930 atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
2931
2932 /* cleanup resmgr */
2933 wcd9xxx_resmgr_deinit(&pwcd_priv->resmgr);
2934
2935 iounmap(msm8x10_wcd->pdino_base);
Kuirong Wang265f3592012-12-05 16:17:41 -08002936 return 0;
2937}
2938
2939static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
2940 .probe = msm8x10_wcd_codec_probe,
2941 .remove = msm8x10_wcd_codec_remove,
2942
2943 .read = msm8x10_wcd_read,
2944 .write = msm8x10_wcd_write,
2945
2946 .readable_register = msm8x10_wcd_readable,
2947 .volatile_register = msm8x10_wcd_volatile,
2948
2949 .reg_cache_size = MSM8X10_WCD_CACHE_SIZE,
2950 .reg_cache_default = msm8x10_wcd_reset_reg_defaults,
2951 .reg_word_size = 1,
2952
2953 .controls = msm8x10_wcd_snd_controls,
2954 .num_controls = ARRAY_SIZE(msm8x10_wcd_snd_controls),
2955 .dapm_widgets = msm8x10_wcd_dapm_widgets,
2956 .num_dapm_widgets = ARRAY_SIZE(msm8x10_wcd_dapm_widgets),
2957 .dapm_routes = audio_map,
2958 .num_dapm_routes = ARRAY_SIZE(audio_map),
2959};
2960
Kuirong Wang49f506a2013-05-22 17:38:26 -07002961static int msm8x10_wcd_init_supplies(struct msm8x10_wcd *msm8x10,
Kuirong Wang91e52532013-03-31 14:24:22 -07002962 struct msm8x10_wcd_pdata *pdata)
2963{
2964 int ret;
2965 int i;
2966 msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
2967 ARRAY_SIZE(pdata->regulator),
2968 GFP_KERNEL);
2969 if (!msm8x10->supplies) {
2970 ret = -ENOMEM;
2971 goto err;
2972 }
2973
2974 msm8x10->num_of_supplies = 0;
2975
2976 if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
2977 dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
2978 __func__);
2979 ret = -EINVAL;
2980 goto err;
2981 }
2982
2983 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
2984 if (pdata->regulator[i].name) {
2985 msm8x10->supplies[i].supply = pdata->regulator[i].name;
2986 msm8x10->num_of_supplies++;
2987 }
2988 }
2989
2990 ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
2991 msm8x10->supplies);
2992 if (ret != 0) {
2993 dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
2994 ret);
2995 goto err_supplies;
2996 }
2997
2998 for (i = 0; i < msm8x10->num_of_supplies; i++) {
Kuirong Wang49f506a2013-05-22 17:38:26 -07002999 if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
3000 0)
3001 continue;
3002
Kuirong Wang91e52532013-03-31 14:24:22 -07003003 ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
Kuirong Wang49f506a2013-05-22 17:38:26 -07003004 pdata->regulator[i].min_uV,
3005 pdata->regulator[i].max_uV);
Kuirong Wang91e52532013-03-31 14:24:22 -07003006 if (ret) {
3007 dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
3008 __func__, msm8x10->supplies[i].supply, ret);
3009 goto err_get;
3010 }
3011
3012 ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
3013 pdata->regulator[i].optimum_uA);
3014 if (ret < 0) {
3015 dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
3016 __func__, msm8x10->supplies[i].supply, ret);
3017 goto err_get;
Kuirong Wang49f506a2013-05-22 17:38:26 -07003018 } else {
3019 ret = 0;
Kuirong Wang91e52532013-03-31 14:24:22 -07003020 }
3021 }
3022
Kuirong Wang91e52532013-03-31 14:24:22 -07003023 return ret;
3024
Kuirong Wang91e52532013-03-31 14:24:22 -07003025err_get:
3026 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
3027err_supplies:
3028 kfree(msm8x10->supplies);
3029err:
3030 return ret;
3031}
3032
Kuirong Wang49f506a2013-05-22 17:38:26 -07003033static int msm8x10_wcd_enable_static_supplies(struct msm8x10_wcd *msm8x10,
3034 struct msm8x10_wcd_pdata *pdata)
3035{
3036 int i;
3037 int ret = 0;
3038
3039 for (i = 0; i < msm8x10->num_of_supplies; i++) {
3040 if (pdata->regulator[i].ondemand)
3041 continue;
3042 ret = regulator_enable(msm8x10->supplies[i].consumer);
3043 if (ret) {
3044 pr_err("%s: Failed to enable %s\n", __func__,
3045 msm8x10->supplies[i].supply);
3046 break;
3047 } else {
3048 pr_debug("%s: Enabled regulator %s\n", __func__,
3049 msm8x10->supplies[i].supply);
3050 }
3051 }
3052
3053 while (ret && --i)
3054 if (!pdata->regulator[i].ondemand)
3055 regulator_disable(msm8x10->supplies[i].consumer);
3056
3057 return ret;
3058}
3059
3060
3061
Kuirong Wang91e52532013-03-31 14:24:22 -07003062static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
3063 struct msm8x10_wcd_pdata *pdata)
3064{
3065 int i;
3066
3067 regulator_bulk_disable(msm8x10->num_of_supplies,
3068 msm8x10->supplies);
3069 for (i = 0; i < msm8x10->num_of_supplies; i++) {
Kuirong Wang49f506a2013-05-22 17:38:26 -07003070 if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
3071 0)
3072 continue;
Kuirong Wang91e52532013-03-31 14:24:22 -07003073 regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
3074 pdata->regulator[i].max_uV);
3075 regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
3076 }
3077 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
3078 kfree(msm8x10->supplies);
3079}
3080
Kuirong Wang2e81d322013-05-30 17:52:36 -07003081static int msm8x10_wcd_pads_config(void)
Kuirong Wang91e52532013-03-31 14:24:22 -07003082{
Fred Oh4d716bb2013-07-30 10:14:46 -07003083 void __iomem *ppull = ioremap(MSM8x10_TLMM_CDC_PULL_CTL, 4);
Kuirong Wang2e81d322013-05-30 17:52:36 -07003084 /* Set I2C pads as pull up and rest of pads as no pull */
Fred Oh4d716bb2013-07-30 10:14:46 -07003085 iowrite32(0x03C00000, ppull);
Kuirong Wang2e81d322013-05-30 17:52:36 -07003086 usleep_range(100, 200);
Fred Oh4d716bb2013-07-30 10:14:46 -07003087
3088 iounmap(ppull);
Kuirong Wang91e52532013-03-31 14:24:22 -07003089 return 0;
3090}
Kuirong Wangae340de2013-05-30 18:11:07 -07003091
3092
3093static int msm8x10_wcd_clk_init(void)
3094{
Fred Oh4d716bb2013-07-30 10:14:46 -07003095 void __iomem *pdig1 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4);
3096 void __iomem *pdig2 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4);
3097 void __iomem *pdig3 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4);
3098 void __iomem *pdig4 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4);
3099 void __iomem *pdig5 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4);
3100 void __iomem *pdig6 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4);
Kuirong Wangae340de2013-05-30 18:11:07 -07003101 /* Div-2 */
Fred Oh4d716bb2013-07-30 10:14:46 -07003102 iowrite32(0x3, pdig1);
3103 iowrite32(0x0, pdig2);
3104 iowrite32(0x0, pdig3);
3105 iowrite32(0x0, pdig4);
Kuirong Wangae340de2013-05-30 18:11:07 -07003106 /* Digital codec clock enable */
Fred Oh4d716bb2013-07-30 10:14:46 -07003107 iowrite32(0x1, pdig5);
Kuirong Wangae340de2013-05-30 18:11:07 -07003108 /* Set the update bit to make the settings go through */
Fred Oh4d716bb2013-07-30 10:14:46 -07003109 iowrite32(0x1, pdig6);
Kuirong Wangae340de2013-05-30 18:11:07 -07003110 usleep_range(100, 200);
Fred Oh4d716bb2013-07-30 10:14:46 -07003111
3112 iounmap(pdig1);
3113 iounmap(pdig2);
3114 iounmap(pdig3);
3115 iounmap(pdig4);
3116 iounmap(pdig5);
3117 iounmap(pdig6);
Kuirong Wangae340de2013-05-30 18:11:07 -07003118 return 0;
3119}
3120
Kuirong Wang91e52532013-03-31 14:24:22 -07003121static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
3122{
3123 mutex_init(&msm8x10->io_lock);
3124 mutex_init(&msm8x10->xfer_lock);
Kuirong Wang2e81d322013-05-30 17:52:36 -07003125 msm8x10_wcd_pads_config();
Kuirong Wangae340de2013-05-30 18:11:07 -07003126 msm8x10_wcd_clk_init();
Kuirong Wang91e52532013-03-31 14:24:22 -07003127 return 0;
3128}
3129
Bhalchandra Gajarece1fe592013-07-12 12:58:02 -07003130static struct intr_data interrupt_table[] = {
3131 {MSM8X10_WCD_IRQ_MBHC_INSERTION, true},
3132 {MSM8X10_WCD_IRQ_MBHC_POTENTIAL, true},
3133 {MSM8X10_WCD_IRQ_MBHC_RELEASE, true},
3134 {MSM8X10_WCD_IRQ_MBHC_PRESS, true},
3135 {MSM8X10_WCD_IRQ_MBHC_SHORT_TERM, true},
3136 {MSM8X10_WCD_IRQ_MBHC_REMOVAL, true},
3137 {MSM8X10_WCD_IRQ_MBHC_HS_DET, true},
3138 {MSM8X10_WCD_IRQ_RESERVED_0, false},
3139 {MSM8X10_WCD_IRQ_PA_STARTUP, false},
3140 {MSM8X10_WCD_IRQ_BG_PRECHARGE, false},
3141 {MSM8X10_WCD_IRQ_RESERVED_1, false},
3142 {MSM8X10_WCD_IRQ_EAR_PA_OCPL_FAULT, false},
3143 {MSM8X10_WCD_IRQ_EAR_PA_STARTUP, false},
3144 {MSM8X10_WCD_IRQ_SPKR_PA_OCPL_FAULT, false},
3145 {MSM8X10_WCD_IRQ_SPKR_CLIP_FAULT, false},
3146 {MSM8X10_WCD_IRQ_RESERVED_2, false},
3147 {MSM8X10_WCD_IRQ_HPH_L_PA_STARTUP, false},
3148 {MSM8X10_WCD_IRQ_HPH_R_PA_STARTUP, false},
3149 {MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT, false},
3150 {MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT, false},
3151 {MSM8X10_WCD_IRQ_RESERVED_3, false},
3152 {MSM8X10_WCD_IRQ_RESERVED_4, false},
3153 {MSM8X10_WCD_IRQ_RESERVED_5, false},
3154 {MSM8X10_WCD_IRQ_RESERVED_6, false},
3155};
3156
Kuirong Wang265f3592012-12-05 16:17:41 -08003157static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
3158 const struct i2c_device_id *id)
3159{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003160 int ret = 0;
3161 struct msm8x10_wcd *msm8x10 = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -08003162 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003163 static int device_id;
3164 struct device *dev;
Kuirong Wang2e81d322013-05-30 17:52:36 -07003165 enum apr_subsys_state q6_state;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003166 struct wcd9xxx_core_resource *core_res;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003167
Kuirong Wang2e81d322013-05-30 17:52:36 -07003168 dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
3169 __func__, __LINE__, client->addr, device_id);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003170
Kuirong Wang2e81d322013-05-30 17:52:36 -07003171 switch (client->addr) {
3172 case HELICON_CORE_0_I2C_ADDR:
3173 msm8x10_wcd_modules[0].client = client;
3174 break;
3175 case HELICON_CORE_1_I2C_ADDR:
3176 msm8x10_wcd_modules[1].client = client;
3177 goto rtn;
3178 case HELICON_CORE_2_I2C_ADDR:
3179 msm8x10_wcd_modules[2].client = client;
3180 goto rtn;
3181 case HELICON_CORE_3_I2C_ADDR:
3182 msm8x10_wcd_modules[3].client = client;
3183 goto rtn;
3184 default:
3185 ret = -EINVAL;
Kuirong Wang91e52532013-03-31 14:24:22 -07003186 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003187 }
3188
Kuirong Wang2e81d322013-05-30 17:52:36 -07003189 q6_state = apr_get_q6_state();
3190 if ((q6_state == APR_SUBSYS_DOWN) &&
3191 (client->addr == HELICON_CORE_0_I2C_ADDR)) {
3192 dev_info(&client->dev, "defering %s, adsp_state %d\n", __func__,
3193 q6_state);
3194 return -EPROBE_DEFER;
3195 } else
3196 dev_info(&client->dev, "adsp is ready\n");
3197
3198 dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
3199 __func__, __LINE__, client->addr, device_id);
3200
3201 if (client->addr != HELICON_CORE_0_I2C_ADDR)
3202 goto rtn;
3203
Kuirong Wang14b3fb92013-06-27 17:28:17 -07003204 dev_set_name(&client->dev, "%s", MSM8X10_CODEC_NAME);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003205 dev = &client->dev;
Kuirong Wang265f3592012-12-05 16:17:41 -08003206 if (client->dev.of_node) {
3207 dev_dbg(&client->dev, "%s:Platform data from device tree\n",
3208 __func__);
3209 pdata = msm8x10_wcd_populate_dt_pdata(&client->dev);
3210 client->dev.platform_data = pdata;
3211 } else {
3212 dev_dbg(&client->dev, "%s:Platform data from board file\n",
3213 __func__);
3214 pdata = client->dev.platform_data;
3215 }
3216
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003217 msm8x10 = kzalloc(sizeof(struct msm8x10_wcd), GFP_KERNEL);
3218 if (msm8x10 == NULL) {
3219 dev_err(&client->dev,
3220 "%s: error, allocation failed\n", __func__);
3221 ret = -ENOMEM;
Kuirong Wang91e52532013-03-31 14:24:22 -07003222 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003223 }
Kuirong Wang265f3592012-12-05 16:17:41 -08003224
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003225 msm8x10->dev = &client->dev;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003226 msm8x10->read_dev = __msm8x10_wcd_reg_read;
3227 msm8x10->write_dev = __msm8x10_wcd_reg_write;
Kuirong Wang49f506a2013-05-22 17:38:26 -07003228 ret = msm8x10_wcd_init_supplies(msm8x10, pdata);
Kuirong Wang91e52532013-03-31 14:24:22 -07003229 if (ret) {
3230 dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
3231 __func__);
3232 goto err_codec;
3233 }
Kuirong Wang49f506a2013-05-22 17:38:26 -07003234
3235 ret = msm8x10_wcd_enable_static_supplies(msm8x10, pdata);
3236 if (ret) {
3237 pr_err("%s: Fail to enable Codec pre-reset supplies\n",
3238 __func__);
3239 goto err_codec;
3240 }
3241 usleep_range(5, 5);
3242
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003243 ret = msm8x10_wcd_device_init(msm8x10);
3244 if (ret) {
3245 dev_err(&client->dev,
3246 "%s:msm8x10_wcd_device_init failed with error %d\n",
3247 __func__, ret);
Kuirong Wang91e52532013-03-31 14:24:22 -07003248 goto err_supplies;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003249 }
3250 dev_set_drvdata(&client->dev, msm8x10);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003251 core_res = &msm8x10->wcd9xxx_res;
Bhalchandra Gajarece1fe592013-07-12 12:58:02 -07003252 core_res->parent = msm8x10;
3253 core_res->dev = msm8x10->dev;
3254 core_res->intr_table = interrupt_table;
3255 core_res->intr_table_size = ARRAY_SIZE(interrupt_table);
3256
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003257 wcd9xxx_core_res_init(core_res,
3258 MSM8X10_WCD_NUM_IRQS,
3259 MSM8X10_WCD_NUM_IRQ_REGS,
3260 msm8x10_wcd_reg_read,
3261 msm8x10_wcd_reg_write,
3262 msm8x10_wcd_bulk_read);
Bhalchandra Gajarece1fe592013-07-12 12:58:02 -07003263 if (wcd9xxx_core_irq_init(core_res)) {
3264 dev_err(msm8x10->dev,
3265 "%s: irq initialization failed\n", __func__);
3266 } else {
3267 dev_info(msm8x10->dev,
3268 "%s: irq initialization passed\n", __func__);
3269 }
3270
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003271 ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
3272 msm8x10_wcd_i2s_dai,
3273 ARRAY_SIZE(msm8x10_wcd_i2s_dai));
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003274 if (ret) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003275 dev_err(&client->dev,
3276 "%s:snd_soc_register_codec failed with error %d\n",
3277 __func__, ret);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003278 } else {
3279 wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
Kuirong Wang91e52532013-03-31 14:24:22 -07003280 goto rtn;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003281 }
Kuirong Wang91e52532013-03-31 14:24:22 -07003282
3283err_supplies:
3284 msm8x10_wcd_disable_supplies(msm8x10, pdata);
3285err_codec:
3286 kfree(msm8x10);
3287rtn:
Kuirong Wang265f3592012-12-05 16:17:41 -08003288 return ret;
3289}
3290
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003291static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
3292{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003293 mutex_destroy(&msm8x10->io_lock);
3294 mutex_destroy(&msm8x10->xfer_lock);
3295 kfree(msm8x10);
3296}
3297
Kuirong Wang265f3592012-12-05 16:17:41 -08003298static int __devexit msm8x10_wcd_i2c_remove(struct i2c_client *client)
3299{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003300 struct msm8x10_wcd *msm8x10 = dev_get_drvdata(&client->dev);
3301
3302 msm8x10_wcd_device_exit(msm8x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08003303 return 0;
3304}
3305
3306static struct i2c_device_id msm8x10_wcd_id_table[] = {
3307 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_TOP_LEVEL},
3308 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_ANALOG},
3309 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_1},
3310 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_2},
3311 {}
3312};
3313
3314static struct of_device_id msm8x10_wcd_of_match[] = {
3315 { .compatible = "qcom,msm8x10-wcd-i2c",},
3316 { },
3317};
3318
3319
3320static struct i2c_driver msm8x10_wcd_i2c_driver = {
3321 .driver = {
3322 .owner = THIS_MODULE,
3323 .name = "msm8x10-wcd-i2c-core",
3324 .of_match_table = msm8x10_wcd_of_match
3325 },
3326 .id_table = msm8x10_wcd_id_table,
3327 .probe = msm8x10_wcd_i2c_probe,
3328 .remove = __devexit_p(msm8x10_wcd_i2c_remove),
3329};
3330
3331static int __init msm8x10_wcd_codec_init(void)
3332{
3333 int ret;
3334
3335 pr_debug("%s:\n", __func__);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003336 wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
Kuirong Wang265f3592012-12-05 16:17:41 -08003337 ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
3338 if (ret != 0)
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003339 pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
3340 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -08003341 return ret;
3342}
3343
3344static void __exit msm8x10_wcd_codec_exit(void)
3345{
3346 i2c_del_driver(&msm8x10_wcd_i2c_driver);
3347}
3348
3349
3350module_init(msm8x10_wcd_codec_init);
3351module_exit(msm8x10_wcd_codec_exit);
3352
3353MODULE_DESCRIPTION("MSM8x10 Audio codec driver");
3354MODULE_LICENSE("GPL v2");
3355MODULE_DEVICE_TABLE(i2c, msm8x10_wcd_id_table);
3356