blob: 0c39f7eac2c9fb111ed43473e84d420a4ee56a19 [file] [log] [blame]
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05301/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
Kuirong Wang265f3592012-12-05 16:17:41 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/firmware.h>
15#include <linux/slab.h>
16#include <linux/platform_device.h>
17#include <linux/device.h>
18#include <linux/printk.h>
19#include <linux/ratelimit.h>
20#include <linux/debugfs.h>
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"
Bhalchandra Gajarebbc32742013-10-18 12:32:29 -070042#include "wcd9xxx-common.h"
Kuirong Wang265f3592012-12-05 16:17:41 -080043
44#define MSM8X10_WCD_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
45 SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000)
46#define MSM8X10_WCD_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
47
48#define NUM_DECIMATORS 2
49#define NUM_INTERPOLATORS 3
50#define BITS_PER_REG 8
51#define MSM8X10_WCD_TX_PORT_NUMBER 4
52
Simmi Pateriyad54e6db2013-11-28 09:33:31 +053053#define DAPM_MICBIAS_EXTERNAL_STANDALONE "MIC BIAS External Standalone"
54
Kuirong Wang265f3592012-12-05 16:17:41 -080055#define MSM8X10_WCD_I2S_MASTER_MODE_MASK 0x08
56#define MSM8X10_DINO_CODEC_BASE_ADDR 0xFE043000
Fred Oh4d716bb2013-07-30 10:14:46 -070057#define MSM8X10_DINO_CODEC_REG_SIZE 0x200
Kuirong Wang2e81d322013-05-30 17:52:36 -070058#define MSM8x10_TLMM_CDC_PULL_CTL 0xFD512050
59#define HELICON_CORE_0_I2C_ADDR 0x0d
60#define HELICON_CORE_1_I2C_ADDR 0x77
61#define HELICON_CORE_2_I2C_ADDR 0x66
62#define HELICON_CORE_3_I2C_ADDR 0x55
Kuirong Wang265f3592012-12-05 16:17:41 -080063
Kuirong Wang3a6408d2013-02-20 17:46:46 -080064#define MAX_MSM8X10_WCD_DEVICE 4
Kuirong Wang265f3592012-12-05 16:17:41 -080065#define CODEC_DT_MAX_PROP_SIZE 40
Kuirong Wang49f506a2013-05-22 17:38:26 -070066#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
Bhalchandra Gajare9c19dc22013-07-11 17:16:53 -070067#define HELICON_MCLK_CLK_9P6MHZ 9600000
Kuirong Wang265f3592012-12-05 16:17:41 -080068
Bhalchandra Gajarebbc32742013-10-18 12:32:29 -070069/*
70 * Multiplication factor to compute impedance on codec
71 * This is computed from (Vx / (m*Ical)) = (10mV/(180*30uA))
72 */
73#define MSM8X10_WCD_ZDET_MUL_FACTOR 1852
74
75/* RX_HPH_CNP_WG_TIME increases by 0.24ms */
76#define MSM8X10_WCD_WG_TIME_FACTOR_US 240
77
Kuirong Wang265f3592012-12-05 16:17:41 -080078enum {
79 MSM8X10_WCD_I2C_TOP_LEVEL = 0,
80 MSM8X10_WCD_I2C_ANALOG,
81 MSM8X10_WCD_I2C_DIGITAL_1,
82 MSM8X10_WCD_I2C_DIGITAL_2,
83};
84
85enum {
86 AIF1_PB = 0,
87 AIF1_CAP,
88 NUM_CODEC_DAIS,
89};
90
91enum {
92 RX_MIX1_INP_SEL_ZERO = 0,
93 RX_MIX1_INP_SEL_IIR1,
94 RX_MIX1_INP_SEL_IIR2,
95 RX_MIX1_INP_SEL_RX1,
96 RX_MIX1_INP_SEL_RX2,
97 RX_MIX1_INP_SEL_RX3,
98};
99
100static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
101static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
102static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
103static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[];
104static const DECLARE_TLV_DB_SCALE(aux_pga_gain, 0, 2, 0);
105
Kuirong Wang91e52532013-03-31 14:24:22 -0700106#define MSM8X10_WCD_ACQUIRE_LOCK(x) do { \
107 mutex_lock_nested(&x, SINGLE_DEPTH_NESTING); \
108} while (0)
109#define MSM8X10_WCD_RELEASE_LOCK(x) do { mutex_unlock(&x); } while (0)
110
111
Kuirong Wang265f3592012-12-05 16:17:41 -0800112/* Codec supports 2 IIR filters */
113enum {
114 IIR1 = 0,
115 IIR2,
116 IIR_MAX,
117};
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800118
Kuirong Wang265f3592012-12-05 16:17:41 -0800119/* Codec supports 5 bands */
120enum {
121 BAND1 = 0,
122 BAND2,
123 BAND3,
124 BAND4,
125 BAND5,
126 BAND_MAX,
127};
128
Kuirong Wang91e52532013-03-31 14:24:22 -0700129enum msm8x10_wcd_bandgap_type {
130 MSM8X10_WCD_BANDGAP_OFF = 0,
131 MSM8X10_WCD_BANDGAP_AUDIO_MODE,
132 MSM8X10_WCD_BANDGAP_MBHC_MODE,
133};
134
Kuirong Wang49f506a2013-05-22 17:38:26 -0700135enum {
136 ON_DEMAND_MICBIAS = 0,
137 ON_DEMAND_CP,
138 ON_DEMAND_SUPPLIES_MAX,
139};
140
Kuirong Wanga0185b12013-07-26 17:49:13 -0700141/*
142 * The delay list is per codec HW specification.
143 * Please add delay in the list in the future instead
144 * of magic number
145 */
146enum {
147 CODEC_DELAY_1_MS = 1000,
148 CODEC_DELAY_1_1_MS = 1100,
149};
150
Kuirong Wang265f3592012-12-05 16:17:41 -0800151struct hpf_work {
152 struct msm8x10_wcd_priv *msm8x10_wcd;
153 u32 decimator;
154 u8 tx_hpf_cut_of_freq;
155 struct delayed_work dwork;
156};
157
158static struct hpf_work tx_hpf_work[NUM_DECIMATORS];
159
Kuirong Wang49f506a2013-05-22 17:38:26 -0700160struct on_demand_supply {
161 struct regulator *supply;
162 atomic_t ref;
163};
164
165static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
166 "cdc-vdd-mic-bias",
167 "cdc-vdda-cp",
168};
169
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -0800170static int on_demand_regulator_control(struct on_demand_supply *supply,
171 bool enable,
172 u8 shift);
173
Kuirong Wang265f3592012-12-05 16:17:41 -0800174struct msm8x10_wcd_priv {
175 struct snd_soc_codec *codec;
176 u32 adc_count;
177 u32 rx_bias_count;
178 s32 dmic_1_2_clk_cnt;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700179 struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
Kuirong Wang265f3592012-12-05 16:17:41 -0800180 /* resmgr module */
181 struct wcd9xxx_resmgr resmgr;
Bhalchandra Gajare9c19dc22013-07-11 17:16:53 -0700182 /* mbhc module */
183 struct wcd9xxx_mbhc mbhc;
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700184
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700185 struct wcd9xxx_mbhc_config *mbhc_cfg;
Bhalchandra Gajarebbc32742013-10-18 12:32:29 -0700186
187 /*
188 * list used to save/restore registers at start and
189 * end of impedance measurement
190 */
191 struct list_head reg_save_restore;
Kuirong Wang265f3592012-12-05 16:17:41 -0800192};
193
Kuirong Wang265f3592012-12-05 16:17:41 -0800194static unsigned short rx_digital_gain_reg[] = {
195 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
196 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
197 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
198};
199
200static unsigned short tx_digital_gain_reg[] = {
201 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
202 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
203};
204
205struct msm8x10_wcd_i2c {
206 struct i2c_client *client;
207 struct i2c_msg xfer_msg[2];
208 struct mutex xfer_lock;
209 int mod_id;
210};
211
Kuirong Wang265f3592012-12-05 16:17:41 -0800212static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
Kuirong Wang49f506a2013-05-22 17:38:26 -0700213 struct msm8x10_wcd_regulator *vreg,
214 const char *vreg_name, bool ondemand);
Kuirong Wang265f3592012-12-05 16:17:41 -0800215static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -0700216 struct wcd9xxx_micbias_setting *micbias);
Kuirong Wang265f3592012-12-05 16:17:41 -0800217static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
218 struct device *dev);
219
220struct msm8x10_wcd_i2c msm8x10_wcd_modules[MAX_MSM8X10_WCD_DEVICE];
221
Fred Ohcf2f8582013-06-13 18:32:07 -0700222static void *adsp_state_notifier;
223
224static struct snd_soc_codec *registered_codec;
225#define ADSP_STATE_READY_TIMEOUT_MS 2000
226
Kuirong Wang265f3592012-12-05 16:17:41 -0800227
228static int get_i2c_msm8x10_wcd_device_info(u16 reg,
229 struct msm8x10_wcd_i2c **msm8x10_wcd)
230{
231 int rtn = 0;
232 int value = ((reg & 0x0f00) >> 8) & 0x000f;
Kuirong Wang265f3592012-12-05 16:17:41 -0800233 switch (value) {
234 case 0:
235 case 1:
236 *msm8x10_wcd = &msm8x10_wcd_modules[value];
237 break;
238 default:
239 rtn = -EINVAL;
240 break;
241 }
242 return rtn;
243}
244
Fred Oh4d716bb2013-07-30 10:14:46 -0700245static int msm8x10_wcd_abh_write_device(struct msm8x10_wcd *msm8x10_wcd,
246 u16 reg, u8 *value, u32 bytes)
Kuirong Wang265f3592012-12-05 16:17:41 -0800247{
248 u32 temp = ((u32)(*value)) & 0x000000FF;
249 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
Fred Oh4d716bb2013-07-30 10:14:46 -0700250
251 iowrite32(temp, (msm8x10_wcd->pdino_base+offset));
Kuirong Wang265f3592012-12-05 16:17:41 -0800252 return 0;
253}
254
Fred Oh4d716bb2013-07-30 10:14:46 -0700255static int msm8x10_wcd_abh_read_device(struct msm8x10_wcd *msm8x10_wcd,
256 u16 reg, u32 bytes, u8 *value)
Kuirong Wang265f3592012-12-05 16:17:41 -0800257{
Kuirong Wang91e52532013-03-31 14:24:22 -0700258 u32 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800259 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
Fred Oh4d716bb2013-07-30 10:14:46 -0700260
261 temp = ioread32((msm8x10_wcd->pdino_base+offset));
Kuirong Wang91e52532013-03-31 14:24:22 -0700262 *value = (u8)temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800263 return 0;
264}
265
266static int msm8x10_wcd_i2c_write_device(u16 reg, u8 *value, u32 bytes)
267{
268
269 struct i2c_msg *msg;
270 int ret;
271 u8 reg_addr = 0;
272 u8 data[bytes + 1];
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800273 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800274
275 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800276 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800277 pr_err("%s: Invalid register address\n", __func__);
278 return ret;
279 }
280
281 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
282 pr_err("%s: Failed to get device info\n", __func__);
283 return -ENODEV;
284 }
285 reg_addr = (u8)reg;
286 msg = &msm8x10_wcd->xfer_msg[0];
287 msg->addr = msm8x10_wcd->client->addr;
288 msg->len = bytes + 1;
289 msg->flags = 0;
290 data[0] = reg;
291 data[1] = *value;
292 msg->buf = data;
293 ret = i2c_transfer(msm8x10_wcd->client->adapter,
294 msm8x10_wcd->xfer_msg, 1);
295 /* Try again if the write fails */
296 if (ret != 1) {
297 ret = i2c_transfer(msm8x10_wcd->client->adapter,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800298 msm8x10_wcd->xfer_msg, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -0800299 if (ret != 1) {
300 pr_err("failed to write the device\n");
301 return ret;
302 }
303 }
Kuirong Wang265f3592012-12-05 16:17:41 -0800304 return 0;
305}
306
307
308int msm8x10_wcd_i2c_read_device(u32 reg, u32 bytes, u8 *dest)
309{
310 struct i2c_msg *msg;
311 int ret = 0;
312 u8 reg_addr = 0;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800313 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800314 u8 i = 0;
315
316 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800317 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800318 pr_err("%s: Invalid register address\n", __func__);
319 return ret;
320 }
321
322 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
323 pr_err("%s: Failed to get device info\n", __func__);
324 return -ENODEV;
325 }
326
327 for (i = 0; i < bytes; i++) {
328 reg_addr = (u8)reg++;
329 msg = &msm8x10_wcd->xfer_msg[0];
330 msg->addr = msm8x10_wcd->client->addr;
331 msg->len = 1;
332 msg->flags = 0;
333 msg->buf = &reg_addr;
Kuirong Wang265f3592012-12-05 16:17:41 -0800334 msg = &msm8x10_wcd->xfer_msg[1];
335 msg->addr = msm8x10_wcd->client->addr;
336 msg->len = 1;
337 msg->flags = I2C_M_RD;
338 msg->buf = dest++;
339 ret = i2c_transfer(msm8x10_wcd->client->adapter,
340 msm8x10_wcd->xfer_msg, 2);
341
342 /* Try again if read fails first time */
343 if (ret != 2) {
344 ret = i2c_transfer(msm8x10_wcd->client->adapter,
345 msm8x10_wcd->xfer_msg, 2);
346 if (ret != 2) {
347 pr_err("failed to read msm8x10_wcd register\n");
348 return ret;
349 }
350 }
351 }
352 return 0;
353}
354
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800355int msm8x10_wcd_i2c_read(unsigned short reg, int bytes, void *dest)
Kuirong Wang265f3592012-12-05 16:17:41 -0800356{
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800357 return msm8x10_wcd_i2c_read_device(reg, bytes, dest);
358}
359
360int msm8x10_wcd_i2c_write(unsigned short reg, int bytes, void *src)
361{
362 return msm8x10_wcd_i2c_write_device(reg, src, bytes);
363}
364
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700365static unsigned short msm8x10_wcd_mask_reg(unsigned short reg)
366{
367 if (reg >= 0x3C0 && reg <= 0x3DF)
368 reg = reg & 0x00FF;
369 return reg;
370}
371
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700372static int __msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
373 unsigned short reg)
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800374{
Kuirong Wang265f3592012-12-05 16:17:41 -0800375 int ret = -EINVAL;
Kuirong Wang91e52532013-03-31 14:24:22 -0700376 u8 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800377
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700378 reg = msm8x10_wcd_mask_reg(reg);
379
Kuirong Wang265f3592012-12-05 16:17:41 -0800380 /* check if use I2C interface for Helicon or AHB for Dino */
381 mutex_lock(&msm8x10_wcd->io_lock);
382 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang91e52532013-03-31 14:24:22 -0700383 ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800384 else if (MSM8X10_WCD_IS_DINO_REG(reg))
Fred Oh4d716bb2013-07-30 10:14:46 -0700385 ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800386 mutex_unlock(&msm8x10_wcd->io_lock);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700387
388 if (ret < 0) {
389 dev_err(msm8x10_wcd->dev,
390 "%s: codec read failed for reg 0x%x\n",
391 __func__, reg);
392 return ret;
393 } else {
394 dev_dbg(msm8x10_wcd->dev, "Read 0x%02x from 0x%x\n",
395 temp, reg);
396 }
397
398 return temp;
399}
400
Yeleswarapu, Nagaradheshbbba6e32013-12-20 18:09:17 +0530401static int __msm8x10_wcd_bulk_write(struct msm8x10_wcd *msm8x10_wcd,
402 unsigned short reg, int count, u8 *buf)
403{
404 int ret = -EINVAL;
405 mutex_lock(&msm8x10_wcd->io_lock);
406 if (MSM8X10_WCD_IS_HELICON_REG(reg))
407 ret = msm8x10_wcd_i2c_write(reg, count, buf);
408 else if (MSM8X10_WCD_IS_DINO_REG(reg))
409 ret = msm8x10_wcd_abh_write_device(msm8x10_wcd, reg,
410 buf, count);
411 if (ret < 0)
412 dev_err(msm8x10_wcd->dev,
413 "%s: codec bulk write failed\n", __func__);
414 mutex_unlock(&msm8x10_wcd->io_lock);
415 return ret;
416}
417
418int msm8x10_wcd_bulk_write(struct wcd9xxx_core_resource *core_res,
419 unsigned short reg, int count, u8 *buf)
420{
421 struct msm8x10_wcd *msm8x10_wcd =
422 (struct msm8x10_wcd *) core_res->parent;
423 return __msm8x10_wcd_bulk_write(msm8x10_wcd, reg, count, buf);
424}
425EXPORT_SYMBOL(msm8x10_wcd_bulk_write);
426
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700427int msm8x10_wcd_reg_read(struct wcd9xxx_core_resource *core_res,
428 unsigned short reg)
429{
430 struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
431 return __msm8x10_wcd_reg_read(msm8x10_wcd, reg);
432}
433EXPORT_SYMBOL(msm8x10_wcd_reg_read);
434
435static int __msm8x10_wcd_bulk_read(struct msm8x10_wcd *msm8x10_wcd,
436 unsigned short reg, int count, u8 *buf)
437{
438 int ret = -EINVAL;
439 mutex_lock(&msm8x10_wcd->io_lock);
440 if (MSM8X10_WCD_IS_HELICON_REG(reg))
441 ret = msm8x10_wcd_i2c_read(reg, count, buf);
442 else if (MSM8X10_WCD_IS_DINO_REG(reg))
443 ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg,
444 count, buf);
445 mutex_unlock(&msm8x10_wcd->io_lock);
446
447 if (ret < 0)
448 dev_err(msm8x10_wcd->dev,
449 "%s: codec bulk read failed\n", __func__);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800450 return ret;
Kuirong Wang265f3592012-12-05 16:17:41 -0800451}
452
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700453int msm8x10_wcd_bulk_read(struct wcd9xxx_core_resource *core_res,
454 unsigned short reg, int count, u8 *buf)
455{
456 struct msm8x10_wcd *msm8x10_wcd =
457 (struct msm8x10_wcd *) core_res->parent;
458 return __msm8x10_wcd_bulk_read(msm8x10_wcd, reg, count, buf);
459}
460EXPORT_SYMBOL(msm8x10_wcd_bulk_read);
Kuirong Wang265f3592012-12-05 16:17:41 -0800461
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700462static int __msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd,
463 unsigned short reg, u8 val)
Kuirong Wang265f3592012-12-05 16:17:41 -0800464{
465 int ret = -EINVAL;
466
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700467 reg = msm8x10_wcd_mask_reg(reg);
468
Kuirong Wang265f3592012-12-05 16:17:41 -0800469 /* check if use I2C interface for Helicon or AHB for Dino */
470 mutex_lock(&msm8x10_wcd->io_lock);
471 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800472 ret = msm8x10_wcd_i2c_write(reg, 1, &val);
Kuirong Wang265f3592012-12-05 16:17:41 -0800473 else if (MSM8X10_WCD_IS_DINO_REG(reg))
Fred Oh4d716bb2013-07-30 10:14:46 -0700474 ret = msm8x10_wcd_abh_write_device(msm8x10_wcd, reg, &val, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -0800475 mutex_unlock(&msm8x10_wcd->io_lock);
476
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700477 if (ret < 0)
478 dev_err(msm8x10_wcd->dev,
479 "%s: codec write to reg 0x%x failed\n",
480 __func__, reg);
481 else
482 dev_dbg(msm8x10_wcd->dev,
Phani Kumar Uppalapatibfc63942014-01-28 15:18:43 -0800483 "%s: Write 0x%x to 0x%x\n",
484 __func__, val, reg);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700485
Kuirong Wang265f3592012-12-05 16:17:41 -0800486 return ret;
487}
488
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700489int msm8x10_wcd_reg_write(struct wcd9xxx_core_resource *core_res,
490 unsigned short reg, u8 val)
491{
492 struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
493 return __msm8x10_wcd_reg_write(msm8x10_wcd, reg, val);
494}
495EXPORT_SYMBOL(msm8x10_wcd_reg_write);
496
Kuirong Wang265f3592012-12-05 16:17:41 -0800497static bool msm8x10_wcd_is_digital_gain_register(unsigned int reg)
498{
499 bool rtn = false;
500 switch (reg) {
501 case MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL:
502 case MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL:
503 case MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL:
504 case MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN:
505 case MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN:
506 rtn = true;
507 break;
508 default:
509 break;
510 }
511 return rtn;
512}
513
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800514static int msm8x10_wcd_volatile(struct snd_soc_codec *codec, unsigned int reg)
Kuirong Wang265f3592012-12-05 16:17:41 -0800515{
516 /*
517 * Registers lower than 0x100 are top level registers which can be
518 * written by the Taiko core driver.
519 */
Kuirong Wang265f3592012-12-05 16:17:41 -0800520 if ((reg >= MSM8X10_WCD_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
521 return 1;
522
523 /* IIR Coeff registers are not cacheable */
524 if ((reg >= MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL) &&
525 (reg <= MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL))
526 return 1;
527
528 /*
529 * Digital gain register is not cacheable so we have to write
530 * the setting even it is the same
531 */
532 if (msm8x10_wcd_is_digital_gain_register(reg))
533 return 1;
534
535 /* HPH status registers */
536 if (reg == MSM8X10_WCD_A_RX_HPH_L_STATUS ||
537 reg == MSM8X10_WCD_A_RX_HPH_R_STATUS)
538 return 1;
539
540 if (reg == MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS)
541 return 1;
542
543 return 0;
544}
545
546static int msm8x10_wcd_readable(struct snd_soc_codec *ssc, unsigned int reg)
547{
548 return msm8x10_wcd_reg_readable[reg];
549}
550
551static int msm8x10_wcd_write(struct snd_soc_codec *codec, unsigned int reg,
552 unsigned int value)
553{
554 int ret;
Phani Kumar Uppalapatibfc63942014-01-28 15:18:43 -0800555 dev_dbg(codec->dev, "%s: Write to reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800556 if (reg == SND_SOC_NOPM)
557 return 0;
558
559 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
560
561 if (!msm8x10_wcd_volatile(codec, reg)) {
562 ret = snd_soc_cache_write(codec, reg, value);
563 if (ret != 0)
564 dev_err(codec->dev, "Cache write to %x failed: %d\n",
565 reg, ret);
566 }
567
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700568 return __msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
Kuirong Wang265f3592012-12-05 16:17:41 -0800569}
570
571static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
572 unsigned int reg)
573{
574 unsigned int val;
575 int ret;
576
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800577 dev_dbg(codec->dev, "%s: Read from reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800578 if (reg == SND_SOC_NOPM)
579 return 0;
580
581 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
582
583 if (!msm8x10_wcd_volatile(codec, reg) &&
584 msm8x10_wcd_readable(codec, reg) &&
585 reg < codec->driver->reg_cache_size) {
586 ret = snd_soc_cache_read(codec, reg, &val);
587 if (ret >= 0) {
588 return val;
589 } else
590 dev_err(codec->dev, "Cache read from %x failed: %d\n",
591 reg, ret);
592 }
593
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700594 val = __msm8x10_wcd_reg_read(codec->control_data, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800595 return val;
596}
597
598
599static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
Kuirong Wang49f506a2013-05-22 17:38:26 -0700600 struct msm8x10_wcd_regulator *vreg, const char *vreg_name,
601 bool ondemand)
Kuirong Wang265f3592012-12-05 16:17:41 -0800602{
603 int len, ret = 0;
604 const __be32 *prop;
605 char prop_name[CODEC_DT_MAX_PROP_SIZE];
606 struct device_node *regnode = NULL;
607 u32 prop_val;
608
609 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
610 vreg_name);
611 regnode = of_parse_phandle(dev->of_node, prop_name, 0);
612
613 if (!regnode) {
Kuirong Wang91e52532013-03-31 14:24:22 -0700614 dev_err(dev, "Looking up %s property in node %s failed\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800615 prop_name, dev->of_node->full_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800616 return -ENODEV;
617 }
Kuirong Wang91e52532013-03-31 14:24:22 -0700618
619 dev_dbg(dev, "Looking up %s property in node %s\n",
620 prop_name, dev->of_node->full_name);
621
Kuirong Wang265f3592012-12-05 16:17:41 -0800622 vreg->name = vreg_name;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700623 vreg->ondemand = ondemand;
Kuirong Wang265f3592012-12-05 16:17:41 -0800624
625 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
626 "qcom,%s-voltage", vreg_name);
627 prop = of_get_property(dev->of_node, prop_name, &len);
628
629 if (!prop || (len != (2 * sizeof(__be32)))) {
630 dev_err(dev, "%s %s property\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800631 prop ? "invalid format" : "no", prop_name);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700632 return -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800633 } else {
634 vreg->min_uV = be32_to_cpup(&prop[0]);
635 vreg->max_uV = be32_to_cpup(&prop[1]);
636 }
637
638 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800639 "qcom,%s-current", vreg_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800640
641 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
642 if (ret) {
643 dev_err(dev, "Looking up %s property in node %s failed",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800644 prop_name, dev->of_node->full_name);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700645 return -EFAULT;
Kuirong Wang265f3592012-12-05 16:17:41 -0800646 }
647 vreg->optimum_uA = prop_val;
648
Kuirong Wang49f506a2013-05-22 17:38:26 -0700649 dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
650 vreg->min_uV, vreg->max_uV, vreg->optimum_uA, vreg->ondemand);
Kuirong Wang265f3592012-12-05 16:17:41 -0800651 return 0;
652}
653
654static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -0700655 struct wcd9xxx_micbias_setting *micbias)
Kuirong Wang265f3592012-12-05 16:17:41 -0800656{
657 int ret = 0;
658 char prop_name[CODEC_DT_MAX_PROP_SIZE];
659 u32 prop_val;
660
661 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -0700662 "qcom,cdc-micbias-ldoh-v");
663 ret = of_property_read_u32(dev->of_node, prop_name,
664 &prop_val);
665 if (ret) {
666 dev_err(dev, "Looking up %s property in node %s failed",
667 prop_name, dev->of_node->full_name);
668 return -ENODEV;
669 }
670 micbias->ldoh_v = (u8) prop_val;
671
672 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700673 "qcom,cdc-micbias-cfilt-mv");
Kuirong Wang265f3592012-12-05 16:17:41 -0800674 ret = of_property_read_u32(dev->of_node, prop_name,
675 &micbias->cfilt1_mv);
676 if (ret) {
677 dev_err(dev, "Looking up %s property in node %s failed",
678 prop_name, dev->of_node->full_name);
679 return -ENODEV;
680 }
681
682 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700683 "qcom,cdc-micbias-cfilt-sel");
Kuirong Wang265f3592012-12-05 16:17:41 -0800684 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
685 if (ret) {
686 dev_err(dev, "Looking up %s property in node %s failed",
687 prop_name, dev->of_node->full_name);
688 return -ENODEV;
689 }
690 micbias->bias1_cfilt_sel = (u8)prop_val;
691
692 /* micbias external cap */
693 micbias->bias1_cap_mode =
694 (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
695 MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
696
697 dev_dbg(dev, "ldoh_v %u cfilt1_mv %u\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800698 (u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
Kuirong Wang265f3592012-12-05 16:17:41 -0800699 dev_dbg(dev, "bias1_cfilt_sel %u\n", (u32)micbias->bias1_cfilt_sel);
700 dev_dbg(dev, "bias1_ext_cap %d\n", micbias->bias1_cap_mode);
701
702 return 0;
703}
704
705static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
706 struct device *dev)
707{
708 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700709 int ret, static_cnt, ond_cnt, idx, i;
710 const char *name = NULL;
711 const char *static_prop_name = "qcom,cdc-static-supplies";
712 const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
Kuirong Wang265f3592012-12-05 16:17:41 -0800713
714 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
715 if (!pdata) {
716 dev_err(dev, "could not allocate memory for platform data\n");
717 return NULL;
718 }
Kuirong Wang49f506a2013-05-22 17:38:26 -0700719
720 static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
721 if (IS_ERR_VALUE(static_cnt)) {
722 dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
723 static_cnt);
724 ret = -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800725 goto err;
726 }
727
Kuirong Wang49f506a2013-05-22 17:38:26 -0700728 /* On-demand supply list is an optional property */
729 ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
730 if (IS_ERR_VALUE(ond_cnt))
731 ond_cnt = 0;
732
733 BUG_ON(static_cnt <= 0 || ond_cnt < 0);
734 if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800735 dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
Kuirong Wang49f506a2013-05-22 17:38:26 -0700736 __func__, static_cnt, ARRAY_SIZE(pdata->regulator));
737 ret = -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800738 goto err;
739 }
740
Kuirong Wang49f506a2013-05-22 17:38:26 -0700741 for (idx = 0; idx < static_cnt; idx++) {
742 ret = of_property_read_string_index(dev->of_node,
743 static_prop_name, idx,
744 &name);
745 if (ret) {
746 dev_err(dev, "%s: of read string %s idx %d error %d\n",
747 __func__, static_prop_name, idx, ret);
748 goto err;
749 }
750
751 dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
752 name);
753 ret = msm8x10_wcd_dt_parse_vreg_info(dev,
754 &pdata->regulator[idx],
755 name, false);
Kuirong Wang265f3592012-12-05 16:17:41 -0800756 if (ret)
757 goto err;
758 }
Kuirong Wang49f506a2013-05-22 17:38:26 -0700759
760 for (i = 0; i < ond_cnt; i++, idx++) {
761 ret = of_property_read_string_index(dev->of_node, ond_prop_name,
762 i, &name);
763 if (ret)
764 goto err;
765
766 dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
767 name);
768 ret = msm8x10_wcd_dt_parse_vreg_info(dev,
769 &pdata->regulator[idx],
770 name, true);
771 if (ret)
772 goto err;
773 }
774
Kuirong Wang265f3592012-12-05 16:17:41 -0800775 ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
776 if (ret)
777 goto err;
Kuirong Wang265f3592012-12-05 16:17:41 -0800778 return pdata;
779err:
780 devm_kfree(dev, pdata);
Kuirong Wang91e52532013-03-31 14:24:22 -0700781 dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
782 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -0800783 return NULL;
784}
785
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -0800786static int on_demand_regulator_control(struct on_demand_supply *supply,
787 bool enable,
788 u8 shift)
789{
790 int ret = 0;
791
792 if (!supply || !supply->supply)
793 return 0;
794
795 if (enable) {
796 if (atomic_inc_return(&supply->ref) == 1)
797 ret = regulator_enable(supply->supply);
798 if (ret)
799 pr_err("%s: Failed to enable %s\n",
800 __func__,
801 on_demand_supply_name[shift]);
802 } else {
803 if (atomic_read(&supply->ref) == 0) {
804 pr_debug("%s: %s supply has been disabled.\n",
805 __func__, on_demand_supply_name[shift]);
806 return 0;
807 }
808 if (atomic_dec_return(&supply->ref) == 0)
809 ret = regulator_disable(supply->supply);
810 if (ret)
811 pr_err("%s: Failed to disable %s\n",
812 __func__,
813 on_demand_supply_name[shift]);
814 }
815
816 return ret;
817}
818
Kuirong Wang49f506a2013-05-22 17:38:26 -0700819static int msm8x10_wcd_codec_enable_on_demand_supply(
820 struct snd_soc_dapm_widget *w,
821 struct snd_kcontrol *kcontrol, int event)
822{
823 int ret = 0;
824 struct snd_soc_codec *codec = w->codec;
825 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
826 struct on_demand_supply *supply;
827
828 if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
829 ret = -EINVAL;
830 goto out;
831 }
832 dev_dbg(codec->dev, "%s: supply: %s event: %d ref: %d\n",
833 __func__, on_demand_supply_name[w->shift], event,
834 atomic_read(&msm8x10_wcd->on_demand_list[w->shift].ref));
835
836 supply = &msm8x10_wcd->on_demand_list[w->shift];
837 WARN_ONCE(!supply->supply, "%s isn't defined\n",
838 on_demand_supply_name[w->shift]);
839 if (!supply->supply)
840 goto out;
841
842 switch (event) {
843 case SND_SOC_DAPM_PRE_PMU:
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -0800844 ret = on_demand_regulator_control(supply,
845 true,
846 w->shift);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700847 break;
848 case SND_SOC_DAPM_POST_PMD:
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -0800849 ret = on_demand_regulator_control(supply,
850 false,
851 w->shift);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700852 break;
853 default:
854 break;
855 }
856out:
857 return ret;
858}
859
Kuirong Wang265f3592012-12-05 16:17:41 -0800860static int msm8x10_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
861 struct snd_kcontrol *kcontrol, int event)
862{
863 struct snd_soc_codec *codec = w->codec;
864
Kuirong Wang49f506a2013-05-22 17:38:26 -0700865 dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -0800866 switch (event) {
867 case SND_SOC_DAPM_POST_PMU:
868 /* Enable charge pump clock*/
869 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
870 0x01, 0x01);
871 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLSG_CTL,
872 0x08, 0x08);
873 usleep_range(200, 300);
874 snd_soc_update_bits(codec, MSM8X10_WCD_A_CP_STATIC,
875 0x10, 0x00);
876 break;
877 case SND_SOC_DAPM_PRE_PMD:
878 snd_soc_update_bits(codec,
879 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
880 0x01, 0x01);
881 usleep_range(20, 100);
882 snd_soc_update_bits(codec,
883 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x08);
884 snd_soc_update_bits(codec,
885 MSM8X10_WCD_A_CP_STATIC, 0x10, 0x10);
886 snd_soc_update_bits(codec,
887 MSM8X10_WCD_A_CDC_CLSG_CTL, 0x08, 0x00);
888 snd_soc_update_bits(codec,
889 MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
890 0x00);
891 snd_soc_update_bits(codec,
Kuirong Wang91e52532013-03-31 14:24:22 -0700892 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
Kuirong Wang854de642013-05-24 13:40:41 -0700893 0x01, 0x00);
Kuirong Wang91e52532013-03-31 14:24:22 -0700894 snd_soc_update_bits(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800895 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
896 break;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700897 default:
898 break;
Kuirong Wang265f3592012-12-05 16:17:41 -0800899 }
900 return 0;
901}
902
903static int msm8x10_wcd_pa_gain_get(struct snd_kcontrol *kcontrol,
904 struct snd_ctl_elem_value *ucontrol)
905{
906 u8 ear_pa_gain;
907 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
908
909 ear_pa_gain = snd_soc_read(codec, MSM8X10_WCD_A_RX_EAR_GAIN);
910
911 ear_pa_gain = ear_pa_gain >> 5;
912
913 if (ear_pa_gain == 0x00) {
914 ucontrol->value.integer.value[0] = 0;
915 } else if (ear_pa_gain == 0x04) {
916 ucontrol->value.integer.value[0] = 1;
917 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800918 dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
919 __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800920 return -EINVAL;
921 }
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800922 dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800923 return 0;
924}
925
926static int msm8x10_wcd_pa_gain_put(struct snd_kcontrol *kcontrol,
927 struct snd_ctl_elem_value *ucontrol)
928{
929 u8 ear_pa_gain;
930 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
931
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800932 dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
933 __func__, ucontrol->value.integer.value[0]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800934
935 switch (ucontrol->value.integer.value[0]) {
936 case 0:
937 ear_pa_gain = 0x00;
938 break;
939 case 1:
940 ear_pa_gain = 0x80;
941 break;
942 default:
943 return -EINVAL;
944 }
945
946 snd_soc_update_bits(codec, MSM8X10_WCD_A_RX_EAR_GAIN,
947 0xE0, ear_pa_gain);
948 return 0;
949}
950
951static int msm8x10_wcd_get_iir_enable_audio_mixer(
952 struct snd_kcontrol *kcontrol,
953 struct snd_ctl_elem_value *ucontrol)
954{
955 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
956 int iir_idx = ((struct soc_multi_mixer_control *)
957 kcontrol->private_value)->reg;
958 int band_idx = ((struct soc_multi_mixer_control *)
959 kcontrol->private_value)->shift;
960
961 ucontrol->value.integer.value[0] =
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700962 (snd_soc_read(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800963 (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700964 (1 << band_idx)) != 0;
Kuirong Wang265f3592012-12-05 16:17:41 -0800965
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800966 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -0800967 iir_idx, band_idx,
968 (uint32_t)ucontrol->value.integer.value[0]);
969 return 0;
970}
971
972static int msm8x10_wcd_put_iir_enable_audio_mixer(
973 struct snd_kcontrol *kcontrol,
974 struct snd_ctl_elem_value *ucontrol)
975{
976 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
977 int iir_idx = ((struct soc_multi_mixer_control *)
978 kcontrol->private_value)->reg;
979 int band_idx = ((struct soc_multi_mixer_control *)
980 kcontrol->private_value)->shift;
981 int value = ucontrol->value.integer.value[0];
982
983 /* Mask first 5 bits, 6-8 are reserved */
984 snd_soc_update_bits(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx),
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800985 (1 << band_idx), (value << band_idx));
Kuirong Wang265f3592012-12-05 16:17:41 -0800986
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800987 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700988 iir_idx, band_idx,
989 ((snd_soc_read(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
990 (1 << band_idx)) != 0));
991
Kuirong Wang265f3592012-12-05 16:17:41 -0800992 return 0;
993}
994static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800995 int iir_idx, int band_idx,
996 int coeff_idx)
Kuirong Wang265f3592012-12-05 16:17:41 -0800997{
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700998 uint32_t value = 0;
999
Kuirong Wang265f3592012-12-05 16:17:41 -08001000 /* Address does not automatically update if reading */
1001 snd_soc_write(codec,
1002 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001003 ((band_idx * BAND_MAX + coeff_idx)
1004 * sizeof(uint32_t)) & 0x7F);
1005
1006 value |= snd_soc_read(codec,
1007 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx));
1008
1009 snd_soc_write(codec,
1010 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
1011 ((band_idx * BAND_MAX + coeff_idx)
1012 * sizeof(uint32_t) + 1) & 0x7F);
1013
1014 value |= (snd_soc_read(codec,
1015 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
1016
1017 snd_soc_write(codec,
1018 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
1019 ((band_idx * BAND_MAX + coeff_idx)
1020 * sizeof(uint32_t) + 2) & 0x7F);
1021
1022 value |= (snd_soc_read(codec,
1023 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
1024
1025 snd_soc_write(codec,
1026 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
1027 ((band_idx * BAND_MAX + coeff_idx)
1028 * sizeof(uint32_t) + 3) & 0x7F);
Kuirong Wang265f3592012-12-05 16:17:41 -08001029
1030 /* Mask bits top 2 bits since they are reserved */
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001031 value |= ((snd_soc_read(codec,
1032 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) & 0x3f) << 24);
1033
1034 return value;
1035
Kuirong Wang265f3592012-12-05 16:17:41 -08001036}
1037
1038static int msm8x10_wcd_get_iir_band_audio_mixer(
1039 struct snd_kcontrol *kcontrol,
1040 struct snd_ctl_elem_value *ucontrol)
1041{
1042 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1043 int iir_idx = ((struct soc_multi_mixer_control *)
1044 kcontrol->private_value)->reg;
1045 int band_idx = ((struct soc_multi_mixer_control *)
1046 kcontrol->private_value)->shift;
1047
1048 ucontrol->value.integer.value[0] =
1049 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
1050 ucontrol->value.integer.value[1] =
1051 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
1052 ucontrol->value.integer.value[2] =
1053 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
1054 ucontrol->value.integer.value[3] =
1055 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
1056 ucontrol->value.integer.value[4] =
1057 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
1058
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001059 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -08001060 "%s: IIR #%d band #%d b1 = 0x%x\n"
1061 "%s: IIR #%d band #%d b2 = 0x%x\n"
1062 "%s: IIR #%d band #%d a1 = 0x%x\n"
1063 "%s: IIR #%d band #%d a2 = 0x%x\n",
1064 __func__, iir_idx, band_idx,
1065 (uint32_t)ucontrol->value.integer.value[0],
1066 __func__, iir_idx, band_idx,
1067 (uint32_t)ucontrol->value.integer.value[1],
1068 __func__, iir_idx, band_idx,
1069 (uint32_t)ucontrol->value.integer.value[2],
1070 __func__, iir_idx, band_idx,
1071 (uint32_t)ucontrol->value.integer.value[3],
1072 __func__, iir_idx, band_idx,
1073 (uint32_t)ucontrol->value.integer.value[4]);
1074 return 0;
1075}
1076
1077static void set_iir_band_coeff(struct snd_soc_codec *codec,
1078 int iir_idx, int band_idx,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001079 uint32_t value)
Kuirong Wang265f3592012-12-05 16:17:41 -08001080{
Kuirong Wang265f3592012-12-05 16:17:41 -08001081 snd_soc_write(codec,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001082 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1083 (value & 0xFF));
1084
1085 snd_soc_write(codec,
1086 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1087 (value >> 8) & 0xFF);
1088
1089 snd_soc_write(codec,
1090 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1091 (value >> 16) & 0xFF);
Kuirong Wang265f3592012-12-05 16:17:41 -08001092
1093 /* Mask top 2 bits, 7-8 are reserved */
1094 snd_soc_write(codec,
1095 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1096 (value >> 24) & 0x3F);
1097
1098}
1099
1100static int msm8x10_wcd_put_iir_band_audio_mixer(
1101 struct snd_kcontrol *kcontrol,
1102 struct snd_ctl_elem_value *ucontrol)
1103{
1104 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1105 int iir_idx = ((struct soc_multi_mixer_control *)
1106 kcontrol->private_value)->reg;
1107 int band_idx = ((struct soc_multi_mixer_control *)
1108 kcontrol->private_value)->shift;
1109
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001110 /* Mask top bit it is reserved */
1111 /* Updates addr automatically for each B2 write */
1112 snd_soc_write(codec,
1113 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
1114 (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
1115
1116
1117 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001118 ucontrol->value.integer.value[0]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001119 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001120 ucontrol->value.integer.value[1]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001121 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001122 ucontrol->value.integer.value[2]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001123 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001124 ucontrol->value.integer.value[3]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001125 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001126 ucontrol->value.integer.value[4]);
Kuirong Wang265f3592012-12-05 16:17:41 -08001127
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001128 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -08001129 "%s: IIR #%d band #%d b1 = 0x%x\n"
1130 "%s: IIR #%d band #%d b2 = 0x%x\n"
1131 "%s: IIR #%d band #%d a1 = 0x%x\n"
1132 "%s: IIR #%d band #%d a2 = 0x%x\n",
1133 __func__, iir_idx, band_idx,
1134 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
1135 __func__, iir_idx, band_idx,
1136 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
1137 __func__, iir_idx, band_idx,
1138 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
1139 __func__, iir_idx, band_idx,
1140 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
1141 __func__, iir_idx, band_idx,
1142 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
1143 return 0;
1144}
1145
1146static const char * const msm8x10_wcd_ear_pa_gain_text[] = {
1147 "POS_6_DB", "POS_2_DB"};
1148static const struct soc_enum msm8x10_wcd_ear_pa_gain_enum[] = {
1149 SOC_ENUM_SINGLE_EXT(2, msm8x10_wcd_ear_pa_gain_text),
1150};
1151
1152/*cut of frequency for high pass filter*/
1153static const char * const cf_text[] = {
1154 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
1155};
1156
1157static const struct soc_enum cf_dec1_enum =
1158 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
1159
1160static const struct soc_enum cf_dec2_enum =
1161 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
1162
1163static const struct soc_enum cf_rxmix1_enum =
1164 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
1165
1166static const struct soc_enum cf_rxmix2_enum =
1167 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
1168
1169static const struct soc_enum cf_rxmix3_enum =
1170 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
1171
1172static const struct snd_kcontrol_new msm8x10_wcd_snd_controls[] = {
1173
1174 SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
1175 msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
1176
Kuirong Wang91e52532013-03-31 14:24:22 -07001177 SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
Kuirong Wang265f3592012-12-05 16:17:41 -08001178 0, 12, 1, line_gain),
1179
1180 SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
1181 0, 12, 1, line_gain),
1182 SOC_SINGLE_TLV("HPHR Volume", MSM8X10_WCD_A_RX_HPH_R_GAIN,
1183 0, 12, 1, line_gain),
1184
1185 SOC_SINGLE_S8_TLV("RX1 Digital Volume",
1186 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
1187 -84, 40, digital_gain),
1188 SOC_SINGLE_S8_TLV("RX2 Digital Volume",
1189 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
1190 -84, 40, digital_gain),
1191 SOC_SINGLE_S8_TLV("RX3 Digital Volume",
1192 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
1193 -84, 40, digital_gain),
1194
1195 SOC_SINGLE_S8_TLV("DEC1 Volume",
1196 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
1197 -84, 40, digital_gain),
1198 SOC_SINGLE_S8_TLV("DEC2 Volume",
1199 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
1200 -84, 40, digital_gain),
1201
1202 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
1203 MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL,
1204 -84, 40, digital_gain),
1205 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
1206 MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL,
1207 -84, 40, digital_gain),
1208 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
1209 MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL,
1210 -84, 40, digital_gain),
1211 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume",
1212 MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
1213 -84, 40, digital_gain),
1214
Kuirong Wang265f3592012-12-05 16:17:41 -08001215 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
1216 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
1217
1218 SOC_SINGLE("TX1 HPF Switch", MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 3, 1, 0),
1219 SOC_SINGLE("TX2 HPF Switch", MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 3, 1, 0),
1220
1221 SOC_SINGLE("RX1 HPF Switch", MSM8X10_WCD_A_CDC_RX1_B5_CTL, 2, 1, 0),
1222 SOC_SINGLE("RX2 HPF Switch", MSM8X10_WCD_A_CDC_RX2_B5_CTL, 2, 1, 0),
1223 SOC_SINGLE("RX3 HPF Switch", MSM8X10_WCD_A_CDC_RX3_B5_CTL, 2, 1, 0),
1224
1225 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1226 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1227 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
1228
1229 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1230 msm8x10_wcd_get_iir_enable_audio_mixer,
1231 msm8x10_wcd_put_iir_enable_audio_mixer),
1232 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1233 msm8x10_wcd_get_iir_enable_audio_mixer,
1234 msm8x10_wcd_put_iir_enable_audio_mixer),
1235 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1236 msm8x10_wcd_get_iir_enable_audio_mixer,
1237 msm8x10_wcd_put_iir_enable_audio_mixer),
1238 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1239 msm8x10_wcd_get_iir_enable_audio_mixer,
1240 msm8x10_wcd_put_iir_enable_audio_mixer),
1241 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1242 msm8x10_wcd_get_iir_enable_audio_mixer,
1243 msm8x10_wcd_put_iir_enable_audio_mixer),
1244 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1245 msm8x10_wcd_get_iir_enable_audio_mixer,
1246 msm8x10_wcd_put_iir_enable_audio_mixer),
1247 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1248 msm8x10_wcd_get_iir_enable_audio_mixer,
1249 msm8x10_wcd_put_iir_enable_audio_mixer),
1250 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1251 msm8x10_wcd_get_iir_enable_audio_mixer,
1252 msm8x10_wcd_put_iir_enable_audio_mixer),
1253 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1254 msm8x10_wcd_get_iir_enable_audio_mixer,
1255 msm8x10_wcd_put_iir_enable_audio_mixer),
1256 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1257 msm8x10_wcd_get_iir_enable_audio_mixer,
1258 msm8x10_wcd_put_iir_enable_audio_mixer),
1259
1260 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1261 msm8x10_wcd_get_iir_band_audio_mixer,
1262 msm8x10_wcd_put_iir_band_audio_mixer),
1263 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1264 msm8x10_wcd_get_iir_band_audio_mixer,
1265 msm8x10_wcd_put_iir_band_audio_mixer),
1266 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1267 msm8x10_wcd_get_iir_band_audio_mixer,
1268 msm8x10_wcd_put_iir_band_audio_mixer),
1269 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1270 msm8x10_wcd_get_iir_band_audio_mixer,
1271 msm8x10_wcd_put_iir_band_audio_mixer),
1272 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1273 msm8x10_wcd_get_iir_band_audio_mixer,
1274 msm8x10_wcd_put_iir_band_audio_mixer),
1275 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1276 msm8x10_wcd_get_iir_band_audio_mixer,
1277 msm8x10_wcd_put_iir_band_audio_mixer),
1278 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1279 msm8x10_wcd_get_iir_band_audio_mixer,
1280 msm8x10_wcd_put_iir_band_audio_mixer),
1281 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1282 msm8x10_wcd_get_iir_band_audio_mixer,
1283 msm8x10_wcd_put_iir_band_audio_mixer),
1284 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1285 msm8x10_wcd_get_iir_band_audio_mixer,
1286 msm8x10_wcd_put_iir_band_audio_mixer),
1287 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1288 msm8x10_wcd_get_iir_band_audio_mixer,
1289 msm8x10_wcd_put_iir_band_audio_mixer),
1290
1291};
1292
1293static const char * const rx_mix1_text[] = {
1294 "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
1295};
1296
1297static const char * const rx_mix2_text[] = {
1298 "ZERO", "IIR1", "IIR2"
1299};
1300
1301static const char * const dec_mux_text[] = {
1302 "ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
1303};
1304
Kuirong Wanga0185b12013-07-26 17:49:13 -07001305static const char * const adc2_mux_text[] = {
1306 "ZERO", "INP2", "INP3"
Kuirong Wang265f3592012-12-05 16:17:41 -08001307};
1308
1309static const char * const iir1_inp1_text[] = {
1310 "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
1311};
1312
Kuirong Wang78468f12013-06-19 01:55:53 -07001313/*
1314 * There is only one bit to select RX2 (0) or RX3 (1) so add 'ZERO' won't
1315 * cause any issue to select the right input, but it eliminates that lineout
1316 * is powered-up when HPH is enabled if the 'ZERO" is used in the disable
1317 * sequence for lineout.
1318 */
1319static const char * const rx_rdac4_text[] = {
1320 "ZERO", "RX3", "RX2"
1321};
1322
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05301323static const char * const rx_rdac3_text[] = {
1324 "RX1", "RX2"
1325};
1326
Kuirong Wang265f3592012-12-05 16:17:41 -08001327static const struct soc_enum rx_mix1_inp1_chain_enum =
1328 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
1329
1330static const struct soc_enum rx_mix1_inp2_chain_enum =
1331 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text);
1332
1333static const struct soc_enum rx_mix1_inp3_chain_enum =
1334 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text);
1335
1336static const struct soc_enum rx2_mix1_inp1_chain_enum =
1337 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text);
1338
1339static const struct soc_enum rx2_mix1_inp2_chain_enum =
1340 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text);
1341
1342static const struct soc_enum rx3_mix1_inp1_chain_enum =
1343 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text);
1344
1345static const struct soc_enum rx3_mix1_inp2_chain_enum =
1346 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text);
1347
1348static const struct soc_enum rx1_mix2_inp1_chain_enum =
1349 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
1350
1351static const struct soc_enum rx2_mix2_inp1_chain_enum =
1352 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
1353
1354static const struct soc_enum dec1_mux_enum =
1355 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 0, 5, dec_mux_text);
1356
1357static const struct soc_enum dec2_mux_enum =
1358 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 3, 5, dec_mux_text);
1359
1360static const struct soc_enum iir1_inp1_mux_enum =
1361 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
1362 iir1_inp1_text);
1363
Kuirong Wang78468f12013-06-19 01:55:53 -07001364static const struct soc_enum rx_rdac4_enum =
1365 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
1366 rx_rdac4_text);
1367
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05301368static const struct soc_enum rx_rdac3_enum =
1369 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_HPHR_DAC_CTL, 0, 2,
1370 rx_rdac3_text);
1371
Kuirong Wanga0185b12013-07-26 17:49:13 -07001372static const struct soc_enum adc2_enum =
1373 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
1374
Kuirong Wang265f3592012-12-05 16:17:41 -08001375static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1376 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1377
1378static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1379 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1380
1381static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1382 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1383
1384static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1385 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1386
1387static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1388 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1389
1390static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1391 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1392
1393static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1394 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1395
1396static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1397 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1398
1399static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1400 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1401
Kuirong Wang78468f12013-06-19 01:55:53 -07001402static const struct snd_kcontrol_new rx_dac4_mux =
1403 SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
1404
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05301405static const struct snd_kcontrol_new rx_dac3_mux =
1406 SOC_DAPM_ENUM("RDAC3 MUX Mux", rx_rdac3_enum);
1407
Kuirong Wanga0185b12013-07-26 17:49:13 -07001408static const struct snd_kcontrol_new tx_adc2_mux =
1409 SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
1410
Kuirong Wang265f3592012-12-05 16:17:41 -08001411static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
1412 struct snd_ctl_elem_value *ucontrol)
1413{
1414 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1415 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1416 struct snd_soc_codec *codec = w->codec;
1417 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1418 unsigned int dec_mux, decimator;
1419 char *dec_name = NULL;
1420 char *widget_name = NULL;
1421 char *temp;
1422 u16 tx_mux_ctl_reg;
1423 u8 adc_dmic_sel = 0x0;
1424 int ret = 0;
1425
1426 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1427 return -EINVAL;
1428
1429 dec_mux = ucontrol->value.enumerated.item[0];
1430
1431 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1432 if (!widget_name)
1433 return -ENOMEM;
1434 temp = widget_name;
1435
1436 dec_name = strsep(&widget_name, " ");
1437 widget_name = temp;
1438 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001439 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1440 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001441 ret = -EINVAL;
1442 goto out;
1443 }
1444
1445 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1446 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001447 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1448 __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001449 ret = -EINVAL;
1450 goto out;
1451 }
1452
1453 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1454 , __func__, w->name, decimator, dec_mux);
1455
1456 switch (decimator) {
1457 case 1:
1458 case 2:
Kuirong Wangd75ed012013-08-02 13:43:29 -07001459 if ((dec_mux == 3) || (dec_mux == 4))
1460 adc_dmic_sel = 0x1;
1461 else
1462 adc_dmic_sel = 0x0;
Kuirong Wang265f3592012-12-05 16:17:41 -08001463 break;
1464 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001465 dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
1466 __func__, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001467 ret = -EINVAL;
1468 goto out;
1469 }
1470
1471 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
1472
1473 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1474
1475 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1476
1477out:
1478 kfree(widget_name);
1479 return ret;
1480}
1481
1482#define MSM8X10_WCD_DEC_ENUM(xname, xenum) \
1483{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1484 .info = snd_soc_info_enum_double, \
1485 .get = snd_soc_dapm_get_enum_double, \
1486 .put = msm8x10_wcd_put_dec_enum, \
1487 .private_value = (unsigned long)&xenum }
1488
1489static const struct snd_kcontrol_new dec1_mux =
1490 MSM8X10_WCD_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1491
1492static const struct snd_kcontrol_new dec2_mux =
1493 MSM8X10_WCD_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1494
1495static const struct snd_kcontrol_new iir1_inp1_mux =
1496 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1497
1498static const struct snd_kcontrol_new dac1_switch[] = {
1499 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_EAR_EN, 5, 1, 0)
1500};
1501static const struct snd_kcontrol_new hphl_switch[] = {
1502 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1503};
1504
Kuirong Wang78468f12013-06-19 01:55:53 -07001505static const struct snd_kcontrol_new spkr_switch[] = {
1506 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
1507};
1508
Kuirong Wang265f3592012-12-05 16:17:41 -08001509static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
1510 int enable)
1511{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001512 struct msm8x10_wcd_priv *wcd8x10 = snd_soc_codec_get_drvdata(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08001513
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001514 dev_dbg(codec->dev, "%s %d\n", __func__, enable);
Kuirong Wang265f3592012-12-05 16:17:41 -08001515
1516 if (enable) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001517 wcd8x10->adc_count++;
Kuirong Wang265f3592012-12-05 16:17:41 -08001518 snd_soc_update_bits(codec,
1519 MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1520 0x20, 0x20);
Simmi Pateriyaeba2d5e2013-09-23 13:14:44 +05301521 } else
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001522 wcd8x10->adc_count--;
Kuirong Wang265f3592012-12-05 16:17:41 -08001523}
1524
1525static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
1526 struct snd_kcontrol *kcontrol, int event)
1527{
1528 struct snd_soc_codec *codec = w->codec;
1529 u16 adc_reg;
1530 u8 init_bit_shift;
1531
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001532 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001533 adc_reg = MSM8X10_WCD_A_TX_1_2_TEST_CTL;
1534
1535 if (w->reg == MSM8X10_WCD_A_TX_1_EN)
1536 init_bit_shift = 7;
Kuirong Wanga0185b12013-07-26 17:49:13 -07001537 else if ((w->reg == MSM8X10_WCD_A_TX_2_EN) ||
1538 (w->reg == MSM8X10_WCD_A_TX_3_EN))
Kuirong Wang265f3592012-12-05 16:17:41 -08001539 init_bit_shift = 6;
1540 else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001541 dev_err(codec->dev, "%s: Error, invalid adc register\n",
1542 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001543 return -EINVAL;
1544 }
1545
1546 switch (event) {
1547 case SND_SOC_DAPM_PRE_PMU:
1548 msm8x10_wcd_codec_enable_adc_block(codec, 1);
1549 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1550 1 << init_bit_shift);
Kuirong Wanga0185b12013-07-26 17:49:13 -07001551 usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
Kuirong Wang265f3592012-12-05 16:17:41 -08001552 break;
1553 case SND_SOC_DAPM_POST_PMU:
1554 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
Kuirong Wanga0185b12013-07-26 17:49:13 -07001555 usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
Kuirong Wang265f3592012-12-05 16:17:41 -08001556 break;
1557 case SND_SOC_DAPM_POST_PMD:
1558 msm8x10_wcd_codec_enable_adc_block(codec, 0);
1559 break;
1560 }
1561 return 0;
1562}
1563
1564static int msm8x10_wcd_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1565 struct snd_kcontrol *kcontrol, int event)
1566{
1567 struct snd_soc_codec *codec = w->codec;
1568 u16 lineout_gain_reg;
1569
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001570 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001571
1572 switch (w->shift) {
1573 case 0:
1574 lineout_gain_reg = MSM8X10_WCD_A_RX_LINE_1_GAIN;
1575 break;
1576 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001577 dev_err(codec->dev,
1578 "%s: Error, incorrect lineout register value\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001579 __func__);
1580 return -EINVAL;
1581 }
1582
1583 switch (event) {
1584 case SND_SOC_DAPM_PRE_PMU:
1585 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1586 break;
1587 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001588 dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
1589 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001590 usleep_range(16000, 16100);
1591 break;
1592 case SND_SOC_DAPM_POST_PMD:
1593 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1594 break;
1595 }
1596 return 0;
1597}
1598
1599static int msm8x10_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1600 struct snd_kcontrol *kcontrol, int event)
1601{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001602 dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001603 return 0;
1604}
1605
1606static int msm8x10_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1607 struct snd_kcontrol *kcontrol, int event)
1608{
1609 struct snd_soc_codec *codec = w->codec;
1610 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1611 u8 dmic_clk_en;
1612 u16 dmic_clk_reg;
1613 s32 *dmic_clk_cnt;
1614 unsigned int dmic;
1615 int ret;
1616
1617 ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
1618 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001619 dev_err(codec->dev,
1620 "%s: Invalid DMIC line on the codec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001621 return -EINVAL;
1622 }
1623
1624 switch (dmic) {
1625 case 1:
1626 case 2:
1627 dmic_clk_en = 0x01;
1628 dmic_clk_cnt = &(msm8x10_wcd->dmic_1_2_clk_cnt);
1629 dmic_clk_reg = MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001630 dev_dbg(codec->dev,
1631 "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001632 __func__, event, dmic, *dmic_clk_cnt);
1633 break;
1634 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001635 dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001636 return -EINVAL;
1637 }
1638
1639 switch (event) {
1640 case SND_SOC_DAPM_PRE_PMU:
1641
1642 (*dmic_clk_cnt)++;
1643 if (*dmic_clk_cnt == 1)
1644 snd_soc_update_bits(codec, dmic_clk_reg,
1645 dmic_clk_en, dmic_clk_en);
1646 break;
1647 case SND_SOC_DAPM_POST_PMD:
1648
1649 (*dmic_clk_cnt)--;
1650 if (*dmic_clk_cnt == 0)
1651 snd_soc_update_bits(codec, dmic_clk_reg,
1652 dmic_clk_en, 0);
1653 break;
1654 }
1655 return 0;
1656}
1657
1658static int msm8x10_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1659 struct snd_kcontrol *kcontrol, int event)
1660{
1661 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001662 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08001663 u16 micb_int_reg;
Kuirong Wang265f3592012-12-05 16:17:41 -08001664 char *internal1_text = "Internal1";
1665 char *internal2_text = "Internal2";
1666 char *internal3_text = "Internal3";
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001667 enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
Kuirong Wang265f3592012-12-05 16:17:41 -08001668
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001669 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001670 switch (w->reg) {
1671 case MSM8X10_WCD_A_MICB_1_CTL:
1672 micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001673 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
1674 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
1675 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
Kuirong Wang265f3592012-12-05 16:17:41 -08001676 break;
1677 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001678 dev_err(codec->dev,
Kuirong Wang91e52532013-03-31 14:24:22 -07001679 "%s: Error, invalid micbias register 0x%x\n",
1680 __func__, w->reg);
Kuirong Wang265f3592012-12-05 16:17:41 -08001681 return -EINVAL;
1682 }
1683
1684 switch (event) {
1685 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001686 /* Let MBHC module know micbias is about to turn ON */
1687 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
1688
Kuirong Wang265f3592012-12-05 16:17:41 -08001689 if (strnstr(w->name, internal1_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001690 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
Kuirong Wang265f3592012-12-05 16:17:41 -08001691 else if (strnstr(w->name, internal2_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001692 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08001693 else if (strnstr(w->name, internal3_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001694 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
Bhalchandra Gajare76fcfc62013-09-23 17:30:48 -07001695
1696 /* Always pull up TxFe for TX2 to Micbias */
1697 snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05301698 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
1699 0x80, 0x80);
Kuirong Wang265f3592012-12-05 16:17:41 -08001700 break;
1701 case SND_SOC_DAPM_POST_PMU:
1702 usleep_range(20000, 20100);
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001703 /* Let MBHC module know so micbias is on */
1704 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
Kuirong Wang265f3592012-12-05 16:17:41 -08001705 break;
1706 case SND_SOC_DAPM_POST_PMD:
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05301707 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
1708 0x80, 0x00);
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001709 /* Let MBHC module know so micbias switch to be off */
1710 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
1711
Kuirong Wang265f3592012-12-05 16:17:41 -08001712 if (strnstr(w->name, internal1_text, 30))
1713 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1714 else if (strnstr(w->name, internal2_text, 30))
1715 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1716 else if (strnstr(w->name, internal3_text, 30))
1717 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1718
Bhalchandra Gajare76fcfc62013-09-23 17:30:48 -07001719 /* Disable pull up TxFe for TX2 to Micbias */
1720 snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x00);
Kuirong Wang265f3592012-12-05 16:17:41 -08001721 break;
1722 }
Kuirong Wang265f3592012-12-05 16:17:41 -08001723 return 0;
1724}
1725
Kuirong Wang91e52532013-03-31 14:24:22 -07001726static void tx_hpf_corner_freq_callback(struct work_struct *work)
1727{
1728 struct delayed_work *hpf_delayed_work;
1729 struct hpf_work *hpf_work;
1730 struct msm8x10_wcd_priv *msm8x10_wcd;
1731 struct snd_soc_codec *codec;
1732 u16 tx_mux_ctl_reg;
1733 u8 hpf_cut_of_freq;
1734
1735 hpf_delayed_work = to_delayed_work(work);
1736 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
1737 msm8x10_wcd = hpf_work->msm8x10_wcd;
1738 codec = hpf_work->msm8x10_wcd->codec;
1739 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
1740
1741 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1742 (hpf_work->decimator - 1) * 32;
1743
1744 dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
1745 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
1746
1747 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
1748}
1749
1750
Kuirong Wang265f3592012-12-05 16:17:41 -08001751#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
1752#define CF_MIN_3DB_4HZ 0x0
1753#define CF_MIN_3DB_75HZ 0x1
1754#define CF_MIN_3DB_150HZ 0x2
1755
1756static int msm8x10_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
1757 struct snd_kcontrol *kcontrol, int event)
1758{
1759 struct snd_soc_codec *codec = w->codec;
1760 unsigned int decimator;
1761 char *dec_name = NULL;
1762 char *widget_name = NULL;
1763 char *temp;
1764 int ret = 0;
1765 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
1766 u8 dec_hpf_cut_of_freq;
1767 int offset;
1768
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001769 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001770
1771 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1772 if (!widget_name)
1773 return -ENOMEM;
1774 temp = widget_name;
1775
1776 dec_name = strsep(&widget_name, " ");
1777 widget_name = temp;
1778 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001779 dev_err(codec->dev,
1780 "%s: Invalid decimator = %s\n", __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001781 ret = -EINVAL;
1782 goto out;
1783 }
1784
1785 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1786 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001787 dev_err(codec->dev,
1788 "%s: Invalid decimator = %s\n", __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001789 ret = -EINVAL;
1790 goto out;
1791 }
1792
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001793 dev_dbg(codec->dev,
1794 "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
1795 w->name, dec_name, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001796
1797 if (w->reg == MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
1798 dec_reset_reg = MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
1799 offset = 0;
1800 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001801 dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001802 ret = -EINVAL;
1803 goto out;
1804 }
1805
1806 tx_vol_ctl_reg = MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG +
1807 32 * (decimator - 1);
1808 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1809 32 * (decimator - 1);
1810
1811 switch (event) {
1812 case SND_SOC_DAPM_PRE_PMU:
1813 /* Enableable TX digital mute */
1814 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1815
1816 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1817 1 << w->shift);
1818 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1819
1820 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
1821
1822 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
1823
1824 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
1825 dec_hpf_cut_of_freq;
1826
1827 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
1828
1829 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
1830 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1831 CF_MIN_3DB_150HZ << 4);
1832 }
1833
1834 /* enable HPF */
1835 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
1836 break;
1837 case SND_SOC_DAPM_POST_PMU:
1838 /* Disable TX digital mute */
1839 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
1840
1841 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
1842 CF_MIN_3DB_150HZ) {
1843
1844 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
1845 msecs_to_jiffies(300));
1846 }
1847 /* apply the digital gain after the decimator is enabled*/
1848 if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
1849 snd_soc_write(codec,
1850 tx_digital_gain_reg[w->shift + offset],
1851 snd_soc_read(codec,
1852 tx_digital_gain_reg[w->shift + offset])
1853 );
1854 break;
1855 case SND_SOC_DAPM_PRE_PMD:
1856 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1857 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
1858 break;
1859 case SND_SOC_DAPM_POST_PMD:
1860 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
1861 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1862 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
1863 break;
1864 }
1865out:
1866 kfree(widget_name);
1867 return ret;
1868}
1869
1870static int msm8x10_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001871 struct snd_kcontrol *kcontrol,
1872 int event)
Kuirong Wang265f3592012-12-05 16:17:41 -08001873{
1874 struct snd_soc_codec *codec = w->codec;
1875
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001876 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001877
1878 switch (event) {
1879 case SND_SOC_DAPM_PRE_PMU:
1880 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1881 1 << w->shift, 1 << w->shift);
1882 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1883 1 << w->shift, 0x0);
1884 break;
1885 case SND_SOC_DAPM_POST_PMU:
1886 /* apply the digital gain after the interpolator is enabled*/
1887 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
1888 snd_soc_write(codec,
1889 rx_digital_gain_reg[w->shift],
1890 snd_soc_read(codec,
1891 rx_digital_gain_reg[w->shift])
1892 );
1893 break;
1894 }
1895 return 0;
1896}
1897
1898
1899/* The register address is the same as other codec so it can use resmgr */
1900static int msm8x10_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1901 struct snd_kcontrol *kcontrol, int event)
1902{
1903 struct snd_soc_codec *codec = w->codec;
1904 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Kuirong Wang91e52532013-03-31 14:24:22 -07001905 msm8x10_wcd->resmgr.codec = codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08001906
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001907 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001908
1909 switch (event) {
1910 case SND_SOC_DAPM_PRE_PMU:
1911 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 1);
1912 break;
1913 case SND_SOC_DAPM_POST_PMD:
1914 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 0);
1915 break;
1916 }
1917 return 0;
1918}
1919
1920static int msm8x10_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
1921 struct snd_kcontrol *kcontrol, int event)
1922{
1923 struct snd_soc_codec *codec = w->codec;
1924
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001925 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001926
1927 switch (event) {
1928 case SND_SOC_DAPM_PRE_PMU:
1929 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1930 break;
1931 case SND_SOC_DAPM_POST_PMD:
1932 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1933 break;
1934 }
1935 return 0;
1936}
1937
1938static int msm8x10_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
1939 struct snd_kcontrol *kcontrol, int event)
1940{
1941 struct snd_soc_codec *codec = w->codec;
1942 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1943 enum wcd9xxx_notify_event e_pre_on, e_post_off;
1944
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001945 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001946 if (w->shift == 5) {
1947 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
1948 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
1949 } else if (w->shift == 4) {
1950 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
1951 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
1952 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001953 dev_err(codec->dev,
1954 "%s: Invalid w->shift %d\n", __func__, w->shift);
Kuirong Wang265f3592012-12-05 16:17:41 -08001955 return -EINVAL;
1956 }
1957
1958 switch (event) {
1959 case SND_SOC_DAPM_PRE_PMU:
1960 /* Let MBHC module know PA is turning on */
1961 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
1962 break;
1963
1964 case SND_SOC_DAPM_POST_PMU:
1965 usleep_range(10000, 10100);
1966 break;
1967
1968 case SND_SOC_DAPM_POST_PMD:
1969 /* Let MBHC module know PA turned off */
1970 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
1971
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001972 dev_dbg(codec->dev,
1973 "%s: sleep 10 ms after %s PA disable.\n", __func__,
1974 w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001975 usleep_range(10000, 10100);
1976 break;
1977 }
1978 return 0;
1979}
1980
1981static int msm8x10_wcd_lineout_dac_event(struct snd_soc_dapm_widget *w,
1982 struct snd_kcontrol *kcontrol, int event)
1983{
1984 struct snd_soc_codec *codec = w->codec;
1985
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001986 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001987
1988 switch (event) {
1989 case SND_SOC_DAPM_PRE_PMU:
1990 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1991 break;
1992
1993 case SND_SOC_DAPM_POST_PMD:
1994 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1995 break;
1996 }
1997 return 0;
1998}
1999
Kuirong Wang265f3592012-12-05 16:17:41 -08002000static const struct snd_soc_dapm_route audio_map[] = {
2001 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2002 {"I2S RX1", NULL, "RX_I2S_CLK"},
2003 {"I2S RX2", NULL, "RX_I2S_CLK"},
2004 {"I2S RX3", NULL, "RX_I2S_CLK"},
2005
2006 {"I2S TX1", NULL, "TX_I2S_CLK"},
2007 {"I2S TX2", NULL, "TX_I2S_CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002008
Kuirong Wang91e52532013-03-31 14:24:22 -07002009 {"I2S TX1", NULL, "DEC1 MUX"},
2010 {"I2S TX2", NULL, "DEC2 MUX"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002011
2012 /* Earpiece (RX MIX1) */
2013 {"EAR", NULL, "EAR PA"},
2014 {"EAR PA", NULL, "DAC1"},
2015 {"DAC1", NULL, "CP"},
2016
Kuirong Wang1261b1d2013-08-06 18:18:21 -07002017 /* Clocks for playback path */
2018 {"DAC1", NULL, "EAR CLK"},
2019 {"HPHL DAC", NULL, "HPHL CLK"},
2020 {"HPHR DAC", NULL, "HPHR CLK"},
2021 {"SPK DAC", NULL, "SPK CLK"},
2022 {"LINEOUT DAC", NULL, "LINEOUT CLK"},
2023
Kuirong Wang265f3592012-12-05 16:17:41 -08002024 /* Headset (RX MIX1 and RX MIX2) */
2025 {"HEADPHONE", NULL, "HPHL"},
2026 {"HEADPHONE", NULL, "HPHR"},
2027
2028 {"HPHL", NULL, "HPHL DAC"},
2029
2030 {"HPHR", NULL, "HPHR DAC"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002031
2032 {"HPHL DAC", NULL, "CP"},
2033
2034 {"HPHR DAC", NULL, "CP"},
Kuirong Wang91e52532013-03-31 14:24:22 -07002035 {"SPK DAC", NULL, "CP"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002036
2037 {"DAC1", "Switch", "RX1 CHAIN"},
2038 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05302039 {"HPHR DAC", NULL, "RDAC3 MUX"},
2040
2041 {"RDAC3 MUX", "RX1", "RX1 CHAIN"},
2042 {"RDAC3 MUX", "RX2", "RX2 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002043
Kuirong Wang91e52532013-03-31 14:24:22 -07002044 {"LINEOUT", NULL, "LINEOUT PA"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002045 {"SPK_OUT", NULL, "SPK PA"},
2046
Kuirong Wang91e52532013-03-31 14:24:22 -07002047 {"LINEOUT PA", NULL, "CP"},
2048 {"LINEOUT PA", NULL, "LINEOUT DAC"},
Kuirong Wang78468f12013-06-19 01:55:53 -07002049 {"LINEOUT DAC", NULL, "RDAC4 MUX"},
2050
2051 {"RDAC4 MUX", "RX2", "RX2 CHAIN"},
2052 {"RDAC4 MUX", "RX3", "RX3 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002053
Kuirong Wang49f506a2013-05-22 17:38:26 -07002054 {"CP", NULL, "CP_REGULATOR"},
Kuirong Wang91e52532013-03-31 14:24:22 -07002055 {"CP", NULL, "RX_BIAS"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002056 {"SPK PA", NULL, "SPK DAC"},
Kuirong Wang78468f12013-06-19 01:55:53 -07002057 {"SPK DAC", "Switch", "RX3 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002058
Kuirong Wang91e52532013-03-31 14:24:22 -07002059 {"RX1 CHAIN", NULL, "RX1 CLK"},
2060 {"RX2 CHAIN", NULL, "RX2 CLK"},
2061 {"RX3 CHAIN", NULL, "RX3 CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002062 {"RX1 CHAIN", NULL, "RX1 MIX2"},
2063 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Kuirong Wang91e52532013-03-31 14:24:22 -07002064 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002065
2066 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2067 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2068 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
2069 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2070 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2071 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2072 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2073 {"RX1 MIX2", NULL, "RX1 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07002074 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002075 {"RX2 MIX2", NULL, "RX2 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07002076 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002077
2078 {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
2079 {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
2080 {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
2081 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2082 {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
2083 {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
2084 {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
2085 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2086 {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
2087 {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
2088 {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
2089
2090 {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
2091 {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
2092 {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
2093 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
2094 {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
2095 {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
2096 {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
2097 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
2098
2099 {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
2100 {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
2101 {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
2102 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
2103 {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
2104 {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
2105 {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
2106 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
2107
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07002108 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
2109 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
2110
Kuirong Wang265f3592012-12-05 16:17:41 -08002111 /* Decimator Inputs */
2112 {"DEC1 MUX", "DMIC1", "DMIC1"},
2113 {"DEC1 MUX", "DMIC2", "DMIC2"},
2114 {"DEC1 MUX", "ADC1", "ADC1"},
2115 {"DEC1 MUX", "ADC2", "ADC2"},
2116 {"DEC1 MUX", NULL, "CDC_CONN"},
2117
2118 {"DEC2 MUX", "DMIC1", "DMIC1"},
2119 {"DEC2 MUX", "DMIC2", "DMIC2"},
2120 {"DEC2 MUX", "ADC1", "ADC1"},
2121 {"DEC2 MUX", "ADC2", "ADC2"},
2122 {"DEC2 MUX", NULL, "CDC_CONN"},
2123
Kuirong Wanga0185b12013-07-26 17:49:13 -07002124 {"ADC2", NULL, "ADC2 MUX"},
2125 {"ADC2 MUX", "INP2", "ADC2_INP2"},
2126 {"ADC2 MUX", "INP3", "ADC2_INP3"},
2127
Kuirong Wang265f3592012-12-05 16:17:41 -08002128 /* ADC Connections */
2129 {"ADC1", NULL, "AMIC1"},
Kuirong Wanga0185b12013-07-26 17:49:13 -07002130 {"ADC2_INP2", NULL, "AMIC2"},
2131 {"ADC2_INP3", NULL, "AMIC3"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002132
2133 {"IIR1", NULL, "IIR1 INP1 MUX"},
2134 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2135 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
quic_yandongy7424f1a2013-05-16 22:41:33 +08002136 {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
Kuirong Wang91e52532013-03-31 14:24:22 -07002137 {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
2138 {"MIC BIAS External", NULL, "INT_LDO_H"},
Kuirong Wang49f506a2013-05-22 17:38:26 -07002139 {"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
2140 {"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
2141 {"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002142};
2143
Kuirong Wang265f3592012-12-05 16:17:41 -08002144static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
2145 struct snd_soc_dai *dai)
2146{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002147 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
2148 __func__,
2149 substream->name, substream->stream);
Kuirong Wang265f3592012-12-05 16:17:41 -08002150 return 0;
2151}
2152
2153static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
2154 struct snd_soc_dai *dai)
2155{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002156 dev_dbg(dai->codec->dev,
2157 "%s(): substream = %s stream = %d\n" , __func__,
2158 substream->name, substream->stream);
Kuirong Wang91e52532013-03-31 14:24:22 -07002159}
2160
Kuirong Wang265f3592012-12-05 16:17:41 -08002161int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
2162 int mclk_enable, bool dapm)
2163{
2164 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
2165
Kuirong Wang91e52532013-03-31 14:24:22 -07002166 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
2167 __func__, mclk_enable, dapm);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002168
2169 WCD9XXX_BG_CLK_LOCK(&msm8x10_wcd->resmgr);
2170
Kuirong Wang265f3592012-12-05 16:17:41 -08002171 if (mclk_enable) {
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002172 wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
2173 WCD9XXX_BANDGAP_AUDIO_MODE);
2174 wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
2175 WCD9XXX_CLK_MCLK);
Kuirong Wang265f3592012-12-05 16:17:41 -08002176 } else {
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002177 wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
2178 WCD9XXX_CLK_MCLK);
2179 wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
2180 WCD9XXX_BANDGAP_AUDIO_MODE);
Kuirong Wang265f3592012-12-05 16:17:41 -08002181 }
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002182 WCD9XXX_BG_CLK_UNLOCK(&msm8x10_wcd->resmgr);
Kuirong Wang265f3592012-12-05 16:17:41 -08002183 return 0;
2184}
2185
2186static int msm8x10_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
2187 int clk_id, unsigned int freq, int dir)
2188{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002189 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002190 return 0;
2191}
2192
2193static int msm8x10_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2194{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002195 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002196 return 0;
2197}
2198
2199static int msm8x10_wcd_set_channel_map(struct snd_soc_dai *dai,
2200 unsigned int tx_num, unsigned int *tx_slot,
2201 unsigned int rx_num, unsigned int *rx_slot)
2202
2203{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002204 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002205 return 0;
2206}
2207
2208static int msm8x10_wcd_get_channel_map(struct snd_soc_dai *dai,
2209 unsigned int *tx_num, unsigned int *tx_slot,
2210 unsigned int *rx_num, unsigned int *rx_slot)
2211
2212{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002213 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002214 return 0;
2215}
2216
2217static int msm8x10_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
2218 u8 rx_fs_rate_reg_val, u32 sample_rate)
2219{
2220 return 0;
2221}
2222
2223static int msm8x10_wcd_set_decimator_rate(struct snd_soc_dai *dai,
2224 u8 tx_fs_rate_reg_val, u32 sample_rate)
2225{
2226 return 0;
2227}
2228
2229static int msm8x10_wcd_hw_params(struct snd_pcm_substream *substream,
2230 struct snd_pcm_hw_params *params,
2231 struct snd_soc_dai *dai)
2232{
2233 u8 tx_fs_rate, rx_fs_rate;
2234 int ret;
2235
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002236 dev_dbg(dai->codec->dev,
2237 "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002238 dai->name, dai->id, params_rate(params),
2239 params_channels(params));
2240
2241 switch (params_rate(params)) {
2242 case 8000:
2243 tx_fs_rate = 0x00;
2244 rx_fs_rate = 0x00;
2245 break;
2246 case 16000:
2247 tx_fs_rate = 0x01;
2248 rx_fs_rate = 0x20;
2249 break;
2250 case 32000:
2251 tx_fs_rate = 0x02;
2252 rx_fs_rate = 0x40;
2253 break;
2254 case 48000:
2255 tx_fs_rate = 0x03;
2256 rx_fs_rate = 0x60;
2257 break;
2258 case 96000:
2259 tx_fs_rate = 0x04;
2260 rx_fs_rate = 0x80;
2261 break;
2262 case 192000:
2263 tx_fs_rate = 0x05;
2264 rx_fs_rate = 0xA0;
2265 break;
2266 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002267 dev_err(dai->codec->dev,
2268 "%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002269 params_rate(params));
2270 return -EINVAL;
2271 }
2272
2273 switch (substream->stream) {
2274 case SNDRV_PCM_STREAM_CAPTURE:
2275 ret = msm8x10_wcd_set_decimator_rate(dai, tx_fs_rate,
2276 params_rate(params));
2277 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002278 dev_err(dai->codec->dev,
2279 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002280 ret);
2281 return ret;
2282 }
2283 break;
2284 case SNDRV_PCM_STREAM_PLAYBACK:
2285 ret = msm8x10_wcd_set_interpolator_rate(dai, rx_fs_rate,
2286 params_rate(params));
2287 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002288 dev_err(dai->codec->dev,
2289 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002290 ret);
2291 return ret;
2292 }
2293 break;
2294 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002295 dev_err(dai->codec->dev,
2296 "%s: Invalid stream type %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002297 substream->stream);
2298 return -EINVAL;
2299 }
2300
2301 return 0;
2302}
2303
2304static struct snd_soc_dai_ops msm8x10_wcd_dai_ops = {
2305 .startup = msm8x10_wcd_startup,
2306 .shutdown = msm8x10_wcd_shutdown,
2307 .hw_params = msm8x10_wcd_hw_params,
2308 .set_sysclk = msm8x10_wcd_set_dai_sysclk,
2309 .set_fmt = msm8x10_wcd_set_dai_fmt,
2310 .set_channel_map = msm8x10_wcd_set_channel_map,
2311 .get_channel_map = msm8x10_wcd_get_channel_map,
2312};
2313
2314static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[] = {
2315 {
2316 .name = "msm8x10_wcd_i2s_rx1",
2317 .id = AIF1_PB,
2318 .playback = {
2319 .stream_name = "AIF1 Playback",
2320 .rates = MSM8X10_WCD_RATES,
2321 .formats = MSM8X10_WCD_FORMATS,
2322 .rate_max = 192000,
2323 .rate_min = 8000,
2324 .channels_min = 1,
Kuirong Wang91e52532013-03-31 14:24:22 -07002325 .channels_max = 3,
Kuirong Wang265f3592012-12-05 16:17:41 -08002326 },
2327 .ops = &msm8x10_wcd_dai_ops,
2328 },
2329 {
2330 .name = "msm8x10_wcd_i2s_tx1",
2331 .id = AIF1_CAP,
2332 .capture = {
2333 .stream_name = "AIF1 Capture",
2334 .rates = MSM8X10_WCD_RATES,
2335 .formats = MSM8X10_WCD_FORMATS,
2336 .rate_max = 192000,
2337 .rate_min = 8000,
2338 .channels_min = 1,
2339 .channels_max = 4,
2340 },
2341 .ops = &msm8x10_wcd_dai_ops,
2342 },
2343};
2344
2345static int msm8x10_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
2346 struct snd_kcontrol *kcontrol, int event)
2347{
2348 switch (event) {
2349 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002350 dev_dbg(w->codec->dev,
2351 "%s: Sleeping 20ms after enabling EAR PA\n",
2352 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002353 msleep(20);
2354 break;
2355 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002356 dev_dbg(w->codec->dev,
2357 "%s: Sleeping 20ms after disabling EAR PA\n",
2358 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002359 msleep(20);
2360 break;
2361 }
2362 return 0;
2363}
2364
2365static const struct snd_soc_dapm_widget msm8x10_wcd_dapm_widgets[] = {
2366 /*RX stuff */
2367 SND_SOC_DAPM_OUTPUT("EAR"),
2368
2369 SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
Walter Yang4e09ad52013-12-23 10:53:20 +08002370 msm8x10_wcd_codec_enable_ear_pa,
2371 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang265f3592012-12-05 16:17:41 -08002372
2373 SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
2374 ARRAY_SIZE(dac1_switch)),
2375
Kuirong Wang91e52532013-03-31 14:24:22 -07002376 SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002377
Kuirong Wang91e52532013-03-31 14:24:22 -07002378 SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002379
Kuirong Wang91e52532013-03-31 14:24:22 -07002380 SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002381
Kuirong Wang91e52532013-03-31 14:24:22 -07002382 SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
2383
Kuirong Wang265f3592012-12-05 16:17:41 -08002384 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2385 SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2386 5, 0, NULL, 0,
2387 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2388 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2389 SND_SOC_DAPM_MIXER("HPHL DAC", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL,
2390 7, 0,
2391 hphl_switch, ARRAY_SIZE(hphl_switch)),
2392
2393 SND_SOC_DAPM_PGA_E("HPHR", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2394 4, 0, NULL, 0,
2395 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2396 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2397
2398 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, MSM8X10_WCD_A_RX_HPH_R_DAC_CTL,
2399 7, 0,
2400 msm8x10_wcd_hphr_dac_event,
2401 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2402
Kuirong Wang78468f12013-06-19 01:55:53 -07002403 SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
2404 spkr_switch, ARRAY_SIZE(spkr_switch)),
2405
Kuirong Wang265f3592012-12-05 16:17:41 -08002406 /* Speaker */
Kuirong Wang91e52532013-03-31 14:24:22 -07002407 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002408 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
2409
Kuirong Wang91e52532013-03-31 14:24:22 -07002410 SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
Kuirong Wang265f3592012-12-05 16:17:41 -08002411 0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
2412 SND_SOC_DAPM_PRE_PMU |
2413 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2414
2415 SND_SOC_DAPM_PGA_E("SPK PA", MSM8X10_WCD_A_SPKR_DRV_EN,
2416 7, 0 , NULL, 0, msm8x10_wcd_codec_enable_spk_pa,
2417 SND_SOC_DAPM_PRE_PMU |
2418 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2419
Kuirong Wang91e52532013-03-31 14:24:22 -07002420 SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
Kuirong Wang265f3592012-12-05 16:17:41 -08002421 MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
2422 msm8x10_wcd_lineout_dac_event,
2423 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2424
Kuirong Wang265f3592012-12-05 16:17:41 -08002425 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2426 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2427
2428 SND_SOC_DAPM_MIXER_E("RX1 MIX2",
2429 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
2430 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2431 SND_SOC_DAPM_POST_PMU),
2432 SND_SOC_DAPM_MIXER_E("RX2 MIX2",
2433 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
2434 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2435 SND_SOC_DAPM_POST_PMU),
2436 SND_SOC_DAPM_MIXER_E("RX3 MIX1",
2437 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
2438 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2439 SND_SOC_DAPM_POST_PMU),
2440
Kuirong Wang91e52532013-03-31 14:24:22 -07002441 SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2442 0, 0, NULL, 0),
2443 SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2444 1, 0, NULL, 0),
2445 SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2446 2, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002447 SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
2448 5, 0, NULL, 0),
2449 SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
2450 5, 0, NULL, 0),
Kuirong Wang91e52532013-03-31 14:24:22 -07002451 SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
2452 5, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002453
Kuirong Wang1261b1d2013-08-06 18:18:21 -07002454 SND_SOC_DAPM_SUPPLY("HPHR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2455 0, 0, NULL, 0),
2456 SND_SOC_DAPM_SUPPLY("HPHL CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2457 1, 0, NULL, 0),
2458 SND_SOC_DAPM_SUPPLY("EAR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2459 2, 0, NULL, 0),
2460 SND_SOC_DAPM_SUPPLY("LINEOUT CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2461 3, 0, NULL, 0),
2462 SND_SOC_DAPM_SUPPLY("SPK CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2463 4, 0, NULL, 0),
2464
Kuirong Wang265f3592012-12-05 16:17:41 -08002465 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2466 &rx_mix1_inp1_mux),
2467 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2468 &rx_mix1_inp2_mux),
2469 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
2470 &rx_mix1_inp3_mux),
2471 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2472 &rx2_mix1_inp1_mux),
2473 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2474 &rx2_mix1_inp2_mux),
2475 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2476 &rx3_mix1_inp1_mux),
2477 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2478 &rx3_mix1_inp2_mux),
2479 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2480 &rx1_mix2_inp1_mux),
2481 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2482 &rx2_mix2_inp1_mux),
Kuirong Wang78468f12013-06-19 01:55:53 -07002483 SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
2484 &rx_dac4_mux),
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05302485 SND_SOC_DAPM_MUX("RDAC3 MUX", SND_SOC_NOPM, 0, 0,
2486 &rx_dac3_mux),
Kuirong Wang265f3592012-12-05 16:17:41 -08002487
Kuirong Wang49f506a2013-05-22 17:38:26 -07002488 SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
2489 ON_DEMAND_MICBIAS, 0,
2490 msm8x10_wcd_codec_enable_on_demand_supply,
2491 SND_SOC_DAPM_PRE_PMU |
2492 SND_SOC_DAPM_POST_PMD),
2493
2494 SND_SOC_DAPM_SUPPLY("CP_REGULATOR", SND_SOC_NOPM,
2495 ON_DEMAND_CP, 0,
2496 msm8x10_wcd_codec_enable_on_demand_supply,
2497 SND_SOC_DAPM_PRE_PMU |
2498 SND_SOC_DAPM_POST_PMD),
2499
Kuirong Wang265f3592012-12-05 16:17:41 -08002500 SND_SOC_DAPM_SUPPLY("CP", MSM8X10_WCD_A_CP_EN, 0, 0,
Kuirong Wang49f506a2013-05-22 17:38:26 -07002501 msm8x10_wcd_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2502 SND_SOC_DAPM_PRE_PMD),
Kuirong Wang265f3592012-12-05 16:17:41 -08002503
2504 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2505 msm8x10_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2506 SND_SOC_DAPM_POST_PMD),
2507
2508 /* TX */
2509
2510 SND_SOC_DAPM_SUPPLY("CDC_CONN", MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
2511 2, 0, NULL, 0),
2512
2513
2514 SND_SOC_DAPM_INPUT("AMIC1"),
Kuirong Wang91e52532013-03-31 14:24:22 -07002515 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
Kuirong Wang265f3592012-12-05 16:17:41 -08002516 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2517 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2518 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002519 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
Kuirong Wang265f3592012-12-05 16:17:41 -08002520 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2521 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2522 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang91e52532013-03-31 14:24:22 -07002523 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
Kuirong Wang265f3592012-12-05 16:17:41 -08002524 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2525 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2526 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriyafaf04292013-10-01 17:05:44 +05302527 SND_SOC_DAPM_MICBIAS_E("MIC BIAS External",
2528 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2529 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2530 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302531 SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS_EXTERNAL_STANDALONE,
2532 MSM8X10_WCD_A_MICB_1_CTL,
2533 7, 0, msm8x10_wcd_codec_enable_micbias,
2534 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2535 SND_SOC_DAPM_POST_PMD),
Simmi Pateriyafaf04292013-10-01 17:05:44 +05302536
Kuirong Wang265f3592012-12-05 16:17:41 -08002537 SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
2538 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2539 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wanga0185b12013-07-26 17:49:13 -07002540 SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
Kuirong Wang265f3592012-12-05 16:17:41 -08002541 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2542 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wanga0185b12013-07-26 17:49:13 -07002543 SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, MSM8X10_WCD_A_TX_3_EN, 7, 0,
2544 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2545 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2546
2547 SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
2548
2549 SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
2550 &tx_adc2_mux),
Kuirong Wang265f3592012-12-05 16:17:41 -08002551
2552 SND_SOC_DAPM_INPUT("AMIC3"),
2553
2554 SND_SOC_DAPM_MUX_E("DEC1 MUX",
2555 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
2556 &dec1_mux, msm8x10_wcd_codec_enable_dec,
2557 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2558 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2559
2560 SND_SOC_DAPM_MUX_E("DEC2 MUX",
2561 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
2562 &dec2_mux, msm8x10_wcd_codec_enable_dec,
2563 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2564 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2565
2566 SND_SOC_DAPM_INPUT("AMIC2"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002567
Kuirong Wang91e52532013-03-31 14:24:22 -07002568 SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
2569 0, 0),
2570 SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
2571 0, 0),
2572 SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
2573 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002574
2575 /* Digital Mic Inputs */
2576 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2577 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2578 SND_SOC_DAPM_POST_PMD),
2579
2580 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2581 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2582 SND_SOC_DAPM_POST_PMD),
2583
2584 /* Sidetone */
2585 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2586 SND_SOC_DAPM_PGA("IIR1", MSM8X10_WCD_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2587
2588 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL,
2589 4, 0, NULL, 0),
2590 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL, 4,
2591 0, NULL, 0),
2592};
2593
2594static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
2595
2596 /* set MCLk to 9.6 */
Kuirong Wang91e52532013-03-31 14:24:22 -07002597 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
Kuirong Wang265f3592012-12-05 16:17:41 -08002598
2599 /* EAR PA deafults */
2600 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
2601
2602 /* RX deafults */
2603 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B5_CTL, 0x78),
2604 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B5_CTL, 0x78),
2605 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B5_CTL, 0x78),
2606
2607 /* RX1 and RX2 defaults */
2608 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xA0),
2609 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xA0),
2610
2611 /* RX3 to RX7 defaults */
2612 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B6_CTL, 0x80),
2613
2614 /* Reduce HPH DAC bias to 70% */
2615 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_HPH_BIAS_PA, 0x7A),
2616 /*Reduce EAR DAC bias to 70% */
2617 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_BIAS_PA, 0x76),
2618 /* Reduce LINE DAC bias to 70% */
2619 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
2620
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002621 /* Disable internal biasing path which can cause leakage */
Kuirong Wang91e52532013-03-31 14:24:22 -07002622 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07002623
Kuirong Wang91e52532013-03-31 14:24:22 -07002624 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
Kuirong Wangf046d7c2013-08-28 11:52:49 -07002625 /* Keep the same default gain settings for TX paths */
Kuirong Wang91e52532013-03-31 14:24:22 -07002626 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
2627 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
Kuirong Wangf046d7c2013-08-28 11:52:49 -07002628 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_3_EN, 0x30),
Kuirong Wang269ae352013-05-23 11:31:58 -07002629
2630 /* ClassG fine tuning setting for 16 ohm HPH */
2631 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL, 0x05),
2632 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL, 0x0C),
2633 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1A),
2634 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x47),
2635 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL, 0x23),
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002636
2637 /* Always set TXD_CLK_EN bit to reduce the leakage */
2638 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002639
2640 /* Always disable clock gating for MCLK to mbhc clock gate */
2641 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0x20),
2642 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
Kuirong Wang265f3592012-12-05 16:17:41 -08002643};
2644
2645static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
2646{
2647 u32 i;
2648
2649 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_reg_defaults); i++)
2650 snd_soc_write(codec, msm8x10_wcd_reg_defaults[i].reg,
2651 msm8x10_wcd_reg_defaults[i].val);
2652}
2653
2654static const struct msm8x10_wcd_reg_mask_val
2655 msm8x10_wcd_codec_reg_init_val[] = {
2656 /* Initialize current threshold to 350MA
2657 * number of wait and run cycles to 4096
2658 */
2659 {MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
2660 {MSM8X10_WCD_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Yeleswarapu, Nagaradheshf6572f82013-11-06 17:14:09 +05302661 {MSM8X10_WCD_A_RX_HPH_L_TEST, 0x01, 0x01},
2662 {MSM8X10_WCD_A_RX_HPH_R_TEST, 0x01, 0x01},
Kuirong Wang265f3592012-12-05 16:17:41 -08002663
2664 /* Initialize gain registers to use register gain */
2665 {MSM8X10_WCD_A_RX_HPH_L_GAIN, 0x20, 0x20},
2666 {MSM8X10_WCD_A_RX_HPH_R_GAIN, 0x20, 0x20},
2667 {MSM8X10_WCD_A_RX_LINE_1_GAIN, 0x20, 0x20},
2668
2669 /*enable HPF filter for TX paths */
2670 {MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
2671 {MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
2672
2673 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
2674 {MSM8X10_WCD_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
2675 {MSM8X10_WCD_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
2676
2677 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
2678 {MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
2679
Kuirong Wang78468f12013-06-19 01:55:53 -07002680 /* Disable REF_EN for MSM8X10_WCD_A_SPKR_DRV_DAC_CTL */
2681 {MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
Kuirong Wang265f3592012-12-05 16:17:41 -08002682};
2683
2684static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
2685{
2686 u32 i;
2687
2688 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_codec_reg_init_val); i++)
2689 snd_soc_update_bits(codec,
2690 msm8x10_wcd_codec_reg_init_val[i].reg,
2691 msm8x10_wcd_codec_reg_init_val[i].mask,
2692 msm8x10_wcd_codec_reg_init_val[i].val);
2693}
2694
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002695static void msm8x10_wcd_enable_mux_bias_block(
2696 struct snd_soc_codec *codec)
2697{
2698 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
2699 0x80, 0x00);
2700}
2701
2702static void msm8x10_wcd_put_cfilt_fast_mode(
2703 struct snd_soc_codec *codec,
2704 struct wcd9xxx_mbhc *mbhc)
2705{
2706 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
2707 0x30, 0x30);
2708}
2709
2710static void msm8x10_wcd_codec_specific_cal_setup(
2711 struct snd_soc_codec *codec,
2712 struct wcd9xxx_mbhc *mbhc)
2713{
2714 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
2715 0x04, 0x04);
2716 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN,
2717 0xE0, 0xE0);
2718}
2719
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002720static struct wcd9xxx_cfilt_mode msm8x10_wcd_switch_cfilt_mode(
2721 struct wcd9xxx_mbhc *mbhc, bool fast)
2722{
2723 struct snd_soc_codec *codec = mbhc->codec;
2724 struct wcd9xxx_cfilt_mode cfilt_mode;
2725
2726 if (fast)
2727 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
2728 else
2729 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
2730
2731 cfilt_mode.cur_mode_val =
2732 snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
2733 cfilt_mode.reg_mask = 0x30;
2734 return cfilt_mode;
2735}
2736
2737static void msm8x10_wcd_select_cfilt(struct snd_soc_codec *codec,
2738 struct wcd9xxx_mbhc *mbhc)
2739{
2740 snd_soc_update_bits(codec,
2741 mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
2742}
2743
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002744enum wcd9xxx_cdc_type msm8x10_wcd_get_cdc_type(void)
2745{
2746 return WCD9XXX_CDC_TYPE_HELICON;
2747}
2748
2749static void msm8x10_wcd_mbhc_clk_gate(struct snd_soc_codec *codec,
2750 bool on)
2751{
2752 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL, 0x10, 0x10);
2753}
2754
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07002755static void msm8x10_wcd_mbhc_txfe(struct snd_soc_codec *codec, bool on)
2756{
2757 snd_soc_update_bits(codec, MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL,
2758 0x80, on ? 0x80 : 0x00);
2759}
2760
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002761static int msm8x10_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -08002762 bool turn_on,
2763 bool use_dapm)
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002764{
2765 int ret = 0;
2766
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -08002767 if (use_dapm) {
2768 if (turn_on)
2769 ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
2770 "MICBIAS_REGULATOR");
2771 else
2772 ret = snd_soc_dapm_disable_pin(&codec->dapm,
2773 "MICBIAS_REGULATOR");
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002774
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -08002775 snd_soc_dapm_sync(&codec->dapm);
2776 } else {
2777 struct on_demand_supply *supply;
2778 struct msm8x10_wcd_priv *msm8x10_wcd =
2779 snd_soc_codec_get_drvdata(codec);
2780
2781 supply = &msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS];
2782 if (!supply || !supply->supply || !msm8x10_wcd)
2783 return 0;
2784
2785 ret = on_demand_regulator_control(supply,
2786 turn_on,
2787 ON_DEMAND_MICBIAS);
2788 }
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002789
2790 if (ret)
2791 dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
2792 __func__, turn_on ? "enable" : "disabled");
2793 else
2794 dev_dbg(codec->dev, "%s: %s external micbias source\n",
2795 __func__, turn_on ? "Enabled" : "Disabled");
2796
2797 return ret;
2798}
2799
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302800static int msm8x10_wcd_enable_mbhc_micbias(struct snd_soc_codec *codec,
2801 bool enable)
2802{
2803 int rc;
2804
2805 if (enable)
2806 rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
2807 DAPM_MICBIAS_EXTERNAL_STANDALONE);
2808 else
2809 rc = snd_soc_dapm_disable_pin(&codec->dapm,
2810 DAPM_MICBIAS_EXTERNAL_STANDALONE);
2811 snd_soc_dapm_sync(&codec->dapm);
2812
2813 snd_soc_update_bits(codec, WCD9XXX_A_MICB_1_CTL,
2814 0x80, enable ? 0x80 : 0x00);
2815 if (rc)
2816 pr_debug("%s: Failed to force %s micbias", __func__,
2817 enable ? "enable" : "disable");
2818 else
2819 pr_debug("%s: Trying force %s micbias", __func__,
2820 enable ? "enable" : "disable");
2821 return rc;
2822}
2823
Bhalchandra Gajare6a2296b2013-09-19 13:15:08 -07002824static void msm8x10_wcd_micb_internal(struct snd_soc_codec *codec, bool on)
2825{
2826 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_INT_RBIAS,
2827 0x1C, on ? 0x14 : 0x00);
2828}
2829
Bhalchandra Gajaref19a9262013-09-19 15:40:08 -07002830static void msm8x10_wcd_enable_mb_vddio(struct snd_soc_codec *codec, bool on)
2831{
2832 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_CTL,
2833 0x40, on ? 0x40 : 0x00);
2834}
2835
Bhalchandra Gajarebbc32742013-10-18 12:32:29 -07002836static void msm8x10_wcd_prepare_hph_pa(struct snd_soc_codec *codec,
2837 struct list_head *lh)
2838{
2839 int i;
2840 u32 delay;
2841
2842 const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
2843 {MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xFF, 0x01},
2844 {MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xFF, 0x01},
2845 {MSM8X10_WCD_A_RX_HPH_L_GAIN, 0xFF, 0x2C},
2846 {MSM8X10_WCD_A_RX_HPH_R_GAIN, 0xFF, 0x2C},
2847 {MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0xFF, 0x01},
2848 {MSM8X10_WCD_A_RX_COM_BIAS, 0xFF, 0x80},
2849 {MSM8X10_WCD_A_CP_EN, 0xFF, 0xE7},
2850 {MSM8X10_WCD_A_CP_STATIC, 0xFF, 0x13},
2851 {MSM8X10_WCD_A_CP_STATIC, 0xFF, 0x1B},
2852 {MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xFF, 0x01},
2853 {MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0xFF, 0x03},
2854 {MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0xFF, 0x22},
2855 {MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0xFF, 0x23},
2856 {MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDA},
2857 {MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0xFF, 0x01},
2858 {MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0xFF, 0x03},
2859 {MSM8X10_WCD_A_RX_HPH_CHOP_CTL, 0xFF, 0xA4},
2860 {MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xFF, 0x67},
2861 {MSM8X10_WCD_A_RX_HPH_L_TEST, 0x01, 0x00},
2862 {MSM8X10_WCD_A_RX_HPH_R_TEST, 0x01, 0x00},
2863 {MSM8X10_WCD_A_RX_HPH_BIAS_WG_OCP, 0xFF, 0x1A},
2864 {MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDB},
2865 {MSM8X10_WCD_A_RX_HPH_CNP_WG_TIME, 0xFF, 0xDB},
2866 {MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 0xFF, 0x40},
2867 {MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 0xFF, 0xC0},
2868 {MSM8X10_WCD_A_RX_HPH_R_DAC_CTL, 0xFF, 0x40},
2869 {MSM8X10_WCD_A_RX_HPH_R_DAC_CTL, 0xFF, 0xC0},
2870 {MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 0x03, 0x01},
2871 {MSM8X10_WCD_A_RX_HPH_R_DAC_CTL, 0x03, 0x01},
2872 };
2873
2874 for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++) {
2875 delay = 0;
2876 wcd9xxx_soc_update_bits_push(codec, lh,
2877 reg_set_paon[i].reg,
2878 reg_set_paon[i].mask,
2879 reg_set_paon[i].val, delay);
2880 }
2881 dev_dbg(codec->dev, "%s: PAs are prepared\n", __func__);
2882 return;
2883}
2884
2885static int msm8x10_wcd_enable_static_pa(struct snd_soc_codec *codec,
2886 bool enable)
2887{
2888 int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
2889 MSM8X10_WCD_WG_TIME_FACTOR_US;
2890
2891 wg_time += (int) (wg_time * 35) / 100;
2892
2893 snd_soc_update_bits(codec, MSM8X10_WCD_A_RX_HPH_CNP_EN, 0x30,
2894 enable ? 0x30 : 0x0);
2895 /* Wait for wave gen time to avoid pop noise */
2896 usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
2897 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xFF, 0x00);
2898 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xFF, 0x00);
2899
2900 dev_dbg(codec->dev, "%s: PAs are %s as static mode (wg_time %d)\n",
2901 __func__, enable ? "enabled" : "disabled", wg_time);
2902 return 0;
2903}
2904
2905static int msm8x10_wcd_setup_zdet(struct wcd9xxx_mbhc *mbhc,
2906 enum mbhc_impedance_detect_stages stage)
2907{
2908 int ret = 0;
2909 struct snd_soc_codec *codec = mbhc->codec;
2910 struct msm8x10_wcd_priv *wcd_priv = snd_soc_codec_get_drvdata(codec);
2911 const int mux_wait_us = 25;
2912
2913#define __wr(reg, mask, value) \
2914 do { \
2915 ret = wcd9xxx_soc_update_bits_push(codec, \
2916 &wcd_priv->reg_save_restore, \
2917 reg, mask, value, 0); \
2918 if (ret < 0) \
2919 return ret; \
2920 } while (0)
2921
2922 switch (stage) {
2923 case PRE_MEAS:
2924 dev_dbg(codec->dev, "%s: PRE_MEAS\n", __func__);
2925 INIT_LIST_HEAD(&wcd_priv->reg_save_restore);
2926 /* Configure PA */
2927 msm8x10_wcd_prepare_hph_pa(mbhc->codec,
2928 &wcd_priv->reg_save_restore);
2929
2930 /* Setup MBHC */
2931 __wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0x7F, 0x40);
2932 __wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
2933 __wr(0x171, 0xFF, 0x90);
2934 __wr(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0xF0);
2935 __wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0xFF, 0x45);
2936 __wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x80);
2937
2938 __wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
2939 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
2940 __wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
2941
2942 /* Enable Impedance Detection */
2943 __wr(WCD9XXX_A_MBHC_HPH, 0xFF, 0xC8);
2944
2945 /*
2946 * CnP setup for 0mV
2947 * Route static data as input to noise shaper
2948 */
2949 __wr(MSM8X10_WCD_A_CDC_RX1_B3_CTL, 0xFF, 0x02);
2950 __wr(MSM8X10_WCD_A_CDC_RX2_B3_CTL, 0xFF, 0x02);
2951
2952 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
2953 0x02, 0x00);
2954 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
2955 0x02, 0x00);
2956
2957 /* Reset the HPHL static data pointer */
2958 __wr(MSM8X10_WCD_A_CDC_RX1_B2_CTL, 0xFF, 0x00);
2959 /* Four consecutive writes to set 0V as static data input */
2960 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
2961 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
2962 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
2963 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
2964
2965 /* Reset the HPHR static data pointer */
2966 __wr(MSM8X10_WCD_A_CDC_RX2_B2_CTL, 0xFF, 0x00);
2967 /* Four consecutive writes to set 0V as static data input */
2968 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
2969 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
2970 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
2971 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
2972
2973 /* Enable the HPHL and HPHR PA */
2974 msm8x10_wcd_enable_static_pa(mbhc->codec, true);
2975 break;
2976
2977 case POST_MEAS:
2978 dev_dbg(codec->dev, "%s: POST_MEAS\n", __func__);
2979 /* Turn off ICAL */
2980 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0);
2981
2982 msm8x10_wcd_enable_static_pa(mbhc->codec, false);
2983
2984 /*
2985 * Setup CnP wavegen to ramp to the desired
2986 * output using a 40ms ramp
2987 */
2988
2989 /* CnP wavegen current to 0.5uA */
2990 snd_soc_write(codec, WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0x1A);
2991 /* Set the current division ratio to 2000 */
2992 snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xDF);
2993 /* Set the wavegen timer to max (60msec) */
2994 snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xA0);
2995 /* Set the CnP reference current to sc_bias */
2996 snd_soc_write(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x6D);
2997
2998 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B2_CTL, 0x00);
2999 /* Four consecutive writes to set -10mV as static data input */
3000 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
3001 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x1F);
3002 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0xE3);
3003 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x08);
3004
3005 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B2_CTL, 0x00);
3006 /* Four consecutive writes to set -10mV as static data input */
3007 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
3008 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x1F);
3009 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0xE3);
3010 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x08);
3011
3012 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
3013 0x02, 0x02);
3014 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
3015 0x02, 0x02);
3016 /* Enable the HPHL and HPHR PA and wait for 60mS */
3017 msm8x10_wcd_enable_static_pa(mbhc->codec, true);
3018
3019 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
3020 0x7F, 0x40);
3021 usleep_range(mux_wait_us,
3022 mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
3023 break;
3024 case PA_DISABLE:
3025 dev_dbg(codec->dev, "%s: PA_DISABLE\n", __func__);
3026 msm8x10_wcd_enable_static_pa(mbhc->codec, false);
3027 wcd9xxx_restore_registers(codec, &wcd_priv->reg_save_restore);
3028 break;
3029 }
3030#undef __wr
3031
3032 return ret;
3033}
3034
3035static void msm8x10_wcd_compute_impedance(s16 *l, s16 *r, uint32_t *zl,
3036 uint32_t *zr)
3037{
3038 int zln, zld;
3039 int zrn, zrd;
3040 int rl = 0, rr = 0;
3041
3042 zln = (l[1] - l[0]) * MSM8X10_WCD_ZDET_MUL_FACTOR;
3043 zld = (l[2] - l[0]);
3044 if (zld)
3045 rl = zln / zld;
3046
3047 zrn = (r[1] - r[0]) * MSM8X10_WCD_ZDET_MUL_FACTOR;
3048 zrd = (r[2] - r[0]);
3049 if (zrd)
3050 rr = zrn / zrd;
3051
3052 *zl = rl;
3053 *zr = rr;
3054}
3055
3056
3057
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003058static const struct wcd9xxx_mbhc_cb mbhc_cb = {
3059 .enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
3060 .cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
3061 .codec_specific_cal = msm8x10_wcd_codec_specific_cal_setup,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003062 .switch_cfilt_mode = msm8x10_wcd_switch_cfilt_mode,
3063 .select_cfilt = msm8x10_wcd_select_cfilt,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003064 .get_cdc_type = msm8x10_wcd_get_cdc_type,
3065 .enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07003066 .enable_mbhc_txfe = msm8x10_wcd_mbhc_txfe,
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07003067 .enable_mb_source = msm8x10_wcd_enable_ext_mb_source,
Bhalchandra Gajare6a2296b2013-09-19 13:15:08 -07003068 .setup_int_rbias = msm8x10_wcd_micb_internal,
Bhalchandra Gajaref19a9262013-09-19 15:40:08 -07003069 .pull_mb_to_vddio = msm8x10_wcd_enable_mb_vddio,
Bhalchandra Gajarebbc32742013-10-18 12:32:29 -07003070 .setup_zdet = msm8x10_wcd_setup_zdet,
3071 .compute_impedance = msm8x10_wcd_compute_impedance,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003072};
3073
Kuirong Wang265f3592012-12-05 16:17:41 -08003074int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
Bhalchandra Gajare9c19dc22013-07-11 17:16:53 -07003075 struct wcd9xxx_mbhc_config *mbhc_cfg)
Kuirong Wang265f3592012-12-05 16:17:41 -08003076{
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003077 struct msm8x10_wcd_priv *wcd = snd_soc_codec_get_drvdata(codec);
3078
Phani Kumar Uppalapatibfc63942014-01-28 15:18:43 -08003079 if (!wcd) {
3080 dev_err(codec->dev, "%s: Invalid private data for codec\n",
3081 __func__);
3082 return -EINVAL;
3083 }
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003084 wcd->mbhc_cfg = mbhc_cfg;
Phani Kumar Uppalapatibfc63942014-01-28 15:18:43 -08003085 return wcd9xxx_mbhc_start(&wcd->mbhc, wcd->mbhc_cfg);
Kuirong Wang265f3592012-12-05 16:17:41 -08003086}
3087EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
3088
Kuirong Wang2e81d322013-05-30 17:52:36 -07003089static int msm8x10_wcd_bringup(struct snd_soc_codec *codec)
3090{
3091 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
3092 snd_soc_write(codec, MSM8X10_WCD_A_CHIP_CTL, 0x00);
3093 usleep_range(5000, 5000);
3094 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
3095 return 0;
3096}
3097
Kuirong Wang49f506a2013-05-22 17:38:26 -07003098static struct regulator *wcd8x10_wcd_codec_find_regulator(
3099 const struct msm8x10_wcd *msm8x10,
3100 const char *name)
3101{
3102 int i;
3103
3104 for (i = 0; i < msm8x10->num_of_supplies; i++) {
3105 if (msm8x10->supplies[i].supply &&
3106 !strncmp(msm8x10->supplies[i].supply, name, strlen(name)))
3107 return msm8x10->supplies[i].consumer;
3108 }
3109
3110 return NULL;
3111}
Fred Oh5aa9d2c2013-10-29 17:01:15 -07003112static int msm8x10_wcd_device_down(struct snd_soc_codec *codec)
3113{
3114 dev_dbg(codec->dev, "%s: device down!\n", __func__);
3115
3116 snd_soc_card_change_online_state(codec->card, 0);
3117 return 0;
3118}
Kuirong Wang49f506a2013-05-22 17:38:26 -07003119
Fred Ohcf2f8582013-06-13 18:32:07 -07003120static int msm8x10_wcd_device_up(struct snd_soc_codec *codec)
3121{
Fred Oh5aa9d2c2013-10-29 17:01:15 -07003122 dev_dbg(codec->dev, "%s: device up!\n", __func__);
3123
3124 snd_soc_card_change_online_state(codec->card, 1);
3125 /* delay is required to make sure sound card state updated */
3126 usleep_range(5000, 5100);
Fred Ohcf2f8582013-06-13 18:32:07 -07003127
3128 mutex_lock(&codec->mutex);
3129
3130 msm8x10_wcd_bringup(codec);
3131 msm8x10_wcd_codec_init_reg(codec);
3132 msm8x10_wcd_update_reg_defaults(codec);
3133
3134 mutex_unlock(&codec->mutex);
3135
3136 return 0;
3137}
3138
3139static int adsp_state_callback(struct notifier_block *nb, unsigned long value,
3140 void *priv)
3141{
3142 bool timedout;
3143 unsigned long timeout;
3144
Fred Oh5aa9d2c2013-10-29 17:01:15 -07003145 if (value == SUBSYS_BEFORE_SHUTDOWN)
3146 msm8x10_wcd_device_down(registered_codec);
3147 else if (value == SUBSYS_AFTER_POWERUP) {
Fred Ohcf2f8582013-06-13 18:32:07 -07003148 pr_debug("%s: ADSP is about to power up. bring up codec\n",
3149 __func__);
3150
3151 timeout = jiffies +
3152 msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
3153 while (!(timedout = time_after(jiffies, timeout))) {
3154 if (!q6core_is_adsp_ready()) {
3155 pr_debug("%s: ADSP isn't ready\n", __func__);
3156 } else {
3157 pr_debug("%s: ADSP is ready\n", __func__);
3158 msm8x10_wcd_device_up(registered_codec);
3159 break;
3160 }
3161 }
3162 }
3163
3164 return NOTIFY_OK;
3165}
3166
3167static struct notifier_block adsp_state_notifier_block = {
3168 .notifier_call = adsp_state_callback,
3169 .priority = -INT_MAX,
3170};
3171
Bhalchandra Gajare16748932013-10-01 18:16:05 -07003172static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
3173 .poll_plug_rem = MSM8X10_WCD_IRQ_MBHC_REMOVAL,
3174 .shortavg_complete = MSM8X10_WCD_IRQ_MBHC_SHORT_TERM,
3175 .potential_button_press = MSM8X10_WCD_IRQ_MBHC_PRESS,
3176 .button_release = MSM8X10_WCD_IRQ_MBHC_RELEASE,
3177 .dce_est_complete = MSM8X10_WCD_IRQ_MBHC_POTENTIAL,
3178 .insertion = MSM8X10_WCD_IRQ_MBHC_INSERTION,
3179 .hph_left_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT,
3180 .hph_right_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT,
3181 .hs_jack_switch = MSM8X10_WCD_IRQ_MBHC_HS_DET,
3182};
Fred Ohcf2f8582013-06-13 18:32:07 -07003183
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003184static int msm8x10_wcd_handle_pdata(struct snd_soc_codec *codec,
3185 struct msm8x10_wcd_pdata *pdata)
3186{
3187 int k1, rc = 0;
3188 struct msm8x10_wcd_priv *msm8x10_wcd_priv;
3189
3190 msm8x10_wcd_priv = snd_soc_codec_get_drvdata(codec);
3191
3192 /* Make sure settings are correct */
3193 if (pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V ||
3194 pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT1_SEL) {
3195 rc = -EINVAL;
3196 goto done;
3197 }
3198
3199 /* figure out k value */
3200 k1 = wcd9xxx_resmgr_get_k_val(&msm8x10_wcd_priv->resmgr,
3201 pdata->micbias.cfilt1_mv);
3202 if (IS_ERR_VALUE(k1)) {
3203 rc = -EINVAL;
3204 goto done;
3205 }
3206
3207 /* Set voltage level */
3208 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_VAL,
3209 0xFC, (k1 << 2));
3210
3211 /* update micbias capless mode */
3212 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
3213 pdata->micbias.bias1_cap_mode << 4);
3214
3215done:
3216 return rc;
3217}
3218
Kuirong Wang265f3592012-12-05 16:17:41 -08003219static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
3220{
Fred Oh4d716bb2013-07-30 10:14:46 -07003221 struct msm8x10_wcd_priv *msm8x10_wcd_priv;
3222 struct msm8x10_wcd *msm8x10_wcd;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003223 struct wcd9xxx_core_resource *core_res;
3224 int i, ret = 0;
Bhalchandra Gajare5cc8f322013-09-19 17:46:13 -07003225 struct msm8x10_wcd_pdata *pdata;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003226
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003227 dev_dbg(codec->dev, "%s()\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08003228
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003229 msm8x10_wcd_priv = devm_kzalloc(codec->dev,
3230 sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
3231
Fred Oh4d716bb2013-07-30 10:14:46 -07003232 if (!msm8x10_wcd_priv) {
Kuirong Wang91e52532013-03-31 14:24:22 -07003233 dev_err(codec->dev, "Failed to allocate private data\n");
3234 return -ENOMEM;
3235 }
3236
3237 for (i = 0 ; i < NUM_DECIMATORS; i++) {
Fred Oh4d716bb2013-07-30 10:14:46 -07003238 tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd_priv;
Kuirong Wang91e52532013-03-31 14:24:22 -07003239 tx_hpf_work[i].decimator = i + 1;
3240 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
3241 tx_hpf_corner_freq_callback);
3242 }
3243
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003244 codec->control_data = dev_get_drvdata(codec->dev);
Fred Oh4d716bb2013-07-30 10:14:46 -07003245 snd_soc_codec_set_drvdata(codec, msm8x10_wcd_priv);
3246 msm8x10_wcd_priv->codec = codec;
3247
3248 /* map digital codec registers once */
3249 msm8x10_wcd = codec->control_data;
3250 msm8x10_wcd->pdino_base = ioremap(MSM8X10_DINO_CODEC_BASE_ADDR,
3251 MSM8X10_DINO_CODEC_REG_SIZE);
3252
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003253 pdata = dev_get_platdata(msm8x10_wcd->dev);
3254 if (!pdata) {
3255 dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
3256 __func__);
3257 }
3258
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003259 /* codec resmgr module init */
3260 msm8x10_wcd = codec->control_data;
3261 core_res = &msm8x10_wcd->wcd9xxx_res;
3262 ret = wcd9xxx_resmgr_init(&msm8x10_wcd_priv->resmgr,
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003263 codec, core_res, NULL, &pdata->micbias,
3264 NULL, WCD9XXX_CDC_TYPE_HELICON);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003265 if (ret) {
3266 dev_err(codec->dev,
3267 "%s: wcd9xxx init failed %d\n",
3268 __func__, ret);
3269 goto exit_probe;
3270 }
3271
Kuirong Wang2e81d322013-05-30 17:52:36 -07003272 msm8x10_wcd_bringup(codec);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003273 msm8x10_wcd_codec_init_reg(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08003274 msm8x10_wcd_update_reg_defaults(codec);
Bhalchandra Gajare5cc8f322013-09-19 17:46:13 -07003275
Fred Oh4d716bb2013-07-30 10:14:46 -07003276 msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].supply =
Kuirong Wang49f506a2013-05-22 17:38:26 -07003277 wcd8x10_wcd_codec_find_regulator(
3278 codec->control_data,
3279 on_demand_supply_name[ON_DEMAND_CP]);
Fred Oh4d716bb2013-07-30 10:14:46 -07003280 atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
3281 msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
Kuirong Wang49f506a2013-05-22 17:38:26 -07003282 wcd8x10_wcd_codec_find_regulator(
3283 codec->control_data,
3284 on_demand_supply_name[ON_DEMAND_MICBIAS]);
Fred Oh4d716bb2013-07-30 10:14:46 -07003285 atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003286
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003287 ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
3288 &msm8x10_wcd_priv->resmgr,
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05303289 codec, msm8x10_wcd_enable_mbhc_micbias,
3290 &mbhc_cb, &cdc_intr_ids,
Bhalchandra Gajarebbc32742013-10-18 12:32:29 -07003291 HELICON_MCLK_CLK_9P6MHZ, true);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003292 if (ret) {
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003293 dev_err(msm8x10_wcd->dev, "%s: Failed to initialize mbhc\n",
3294 __func__);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003295 goto exit_probe;
3296 }
Kuirong Wang265f3592012-12-05 16:17:41 -08003297
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003298 /* Handle the Pdata */
3299 ret = msm8x10_wcd_handle_pdata(codec, pdata);
3300 if (IS_ERR_VALUE(ret))
3301 dev_err(msm8x10_wcd->dev, "%s: Bad Pdata\n", __func__);
3302
Fred Ohcf2f8582013-06-13 18:32:07 -07003303 registered_codec = codec;
3304 adsp_state_notifier =
3305 subsys_notif_register_notifier("adsp",
3306 &adsp_state_notifier_block);
3307 if (!adsp_state_notifier) {
3308 pr_err("%s: Failed to register adsp state notifier\n",
3309 __func__);
3310 registered_codec = NULL;
3311 return -ENOMEM;
3312 }
Kuirong Wang265f3592012-12-05 16:17:41 -08003313 return 0;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003314
3315exit_probe:
3316 return ret;
3317
Kuirong Wang265f3592012-12-05 16:17:41 -08003318}
3319
3320static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
3321{
Fred Oh4d716bb2013-07-30 10:14:46 -07003322 struct msm8x10_wcd_priv *pwcd_priv = snd_soc_codec_get_drvdata(codec);
3323 struct msm8x10_wcd *msm8x10_wcd = pwcd_priv->codec->control_data;
Fred Oh4d716bb2013-07-30 10:14:46 -07003324 pwcd_priv->on_demand_list[ON_DEMAND_CP].supply = NULL;
3325 atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
3326 pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
3327 atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
3328
3329 /* cleanup resmgr */
3330 wcd9xxx_resmgr_deinit(&pwcd_priv->resmgr);
3331
3332 iounmap(msm8x10_wcd->pdino_base);
Kuirong Wang265f3592012-12-05 16:17:41 -08003333 return 0;
3334}
3335
3336static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
3337 .probe = msm8x10_wcd_codec_probe,
3338 .remove = msm8x10_wcd_codec_remove,
3339
3340 .read = msm8x10_wcd_read,
3341 .write = msm8x10_wcd_write,
3342
3343 .readable_register = msm8x10_wcd_readable,
3344 .volatile_register = msm8x10_wcd_volatile,
3345
3346 .reg_cache_size = MSM8X10_WCD_CACHE_SIZE,
3347 .reg_cache_default = msm8x10_wcd_reset_reg_defaults,
3348 .reg_word_size = 1,
3349
3350 .controls = msm8x10_wcd_snd_controls,
3351 .num_controls = ARRAY_SIZE(msm8x10_wcd_snd_controls),
3352 .dapm_widgets = msm8x10_wcd_dapm_widgets,
3353 .num_dapm_widgets = ARRAY_SIZE(msm8x10_wcd_dapm_widgets),
3354 .dapm_routes = audio_map,
3355 .num_dapm_routes = ARRAY_SIZE(audio_map),
3356};
3357
Kuirong Wang49f506a2013-05-22 17:38:26 -07003358static int msm8x10_wcd_init_supplies(struct msm8x10_wcd *msm8x10,
Kuirong Wang91e52532013-03-31 14:24:22 -07003359 struct msm8x10_wcd_pdata *pdata)
3360{
3361 int ret;
3362 int i;
3363 msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
3364 ARRAY_SIZE(pdata->regulator),
3365 GFP_KERNEL);
3366 if (!msm8x10->supplies) {
3367 ret = -ENOMEM;
3368 goto err;
3369 }
3370
3371 msm8x10->num_of_supplies = 0;
3372
3373 if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
3374 dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
3375 __func__);
3376 ret = -EINVAL;
3377 goto err;
3378 }
3379
3380 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
3381 if (pdata->regulator[i].name) {
3382 msm8x10->supplies[i].supply = pdata->regulator[i].name;
3383 msm8x10->num_of_supplies++;
3384 }
3385 }
3386
3387 ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
3388 msm8x10->supplies);
3389 if (ret != 0) {
3390 dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
3391 ret);
3392 goto err_supplies;
3393 }
3394
3395 for (i = 0; i < msm8x10->num_of_supplies; i++) {
Kuirong Wang49f506a2013-05-22 17:38:26 -07003396 if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
3397 0)
3398 continue;
3399
Kuirong Wang91e52532013-03-31 14:24:22 -07003400 ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
Kuirong Wang49f506a2013-05-22 17:38:26 -07003401 pdata->regulator[i].min_uV,
3402 pdata->regulator[i].max_uV);
Kuirong Wang91e52532013-03-31 14:24:22 -07003403 if (ret) {
3404 dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
3405 __func__, msm8x10->supplies[i].supply, ret);
3406 goto err_get;
3407 }
3408
3409 ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
3410 pdata->regulator[i].optimum_uA);
3411 if (ret < 0) {
3412 dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
3413 __func__, msm8x10->supplies[i].supply, ret);
3414 goto err_get;
Kuirong Wang49f506a2013-05-22 17:38:26 -07003415 } else {
3416 ret = 0;
Kuirong Wang91e52532013-03-31 14:24:22 -07003417 }
3418 }
3419
Kuirong Wang91e52532013-03-31 14:24:22 -07003420 return ret;
3421
Kuirong Wang91e52532013-03-31 14:24:22 -07003422err_get:
3423 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
3424err_supplies:
3425 kfree(msm8x10->supplies);
3426err:
3427 return ret;
3428}
3429
Kuirong Wang49f506a2013-05-22 17:38:26 -07003430static int msm8x10_wcd_enable_static_supplies(struct msm8x10_wcd *msm8x10,
3431 struct msm8x10_wcd_pdata *pdata)
3432{
3433 int i;
3434 int ret = 0;
3435
3436 for (i = 0; i < msm8x10->num_of_supplies; i++) {
3437 if (pdata->regulator[i].ondemand)
3438 continue;
3439 ret = regulator_enable(msm8x10->supplies[i].consumer);
3440 if (ret) {
3441 pr_err("%s: Failed to enable %s\n", __func__,
3442 msm8x10->supplies[i].supply);
3443 break;
3444 } else {
3445 pr_debug("%s: Enabled regulator %s\n", __func__,
3446 msm8x10->supplies[i].supply);
3447 }
3448 }
3449
3450 while (ret && --i)
3451 if (!pdata->regulator[i].ondemand)
3452 regulator_disable(msm8x10->supplies[i].consumer);
3453
3454 return ret;
3455}
3456
3457
3458
Kuirong Wang91e52532013-03-31 14:24:22 -07003459static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
3460 struct msm8x10_wcd_pdata *pdata)
3461{
3462 int i;
3463
3464 regulator_bulk_disable(msm8x10->num_of_supplies,
3465 msm8x10->supplies);
3466 for (i = 0; i < msm8x10->num_of_supplies; i++) {
Kuirong Wang49f506a2013-05-22 17:38:26 -07003467 if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
3468 0)
3469 continue;
Kuirong Wang91e52532013-03-31 14:24:22 -07003470 regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
3471 pdata->regulator[i].max_uV);
3472 regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
3473 }
3474 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
3475 kfree(msm8x10->supplies);
3476}
3477
Kuirong Wang2e81d322013-05-30 17:52:36 -07003478static int msm8x10_wcd_pads_config(void)
Kuirong Wang91e52532013-03-31 14:24:22 -07003479{
Fred Oh4d716bb2013-07-30 10:14:46 -07003480 void __iomem *ppull = ioremap(MSM8x10_TLMM_CDC_PULL_CTL, 4);
Kuirong Wang2e81d322013-05-30 17:52:36 -07003481 /* Set I2C pads as pull up and rest of pads as no pull */
Fred Oh4d716bb2013-07-30 10:14:46 -07003482 iowrite32(0x03C00000, ppull);
Kuirong Wang2e81d322013-05-30 17:52:36 -07003483 usleep_range(100, 200);
Fred Oh4d716bb2013-07-30 10:14:46 -07003484
3485 iounmap(ppull);
Kuirong Wang91e52532013-03-31 14:24:22 -07003486 return 0;
3487}
Kuirong Wangae340de2013-05-30 18:11:07 -07003488
3489
3490static int msm8x10_wcd_clk_init(void)
3491{
Fred Oh4d716bb2013-07-30 10:14:46 -07003492 void __iomem *pdig1 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4);
3493 void __iomem *pdig2 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4);
3494 void __iomem *pdig3 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4);
3495 void __iomem *pdig4 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4);
3496 void __iomem *pdig5 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4);
3497 void __iomem *pdig6 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4);
Kuirong Wangae340de2013-05-30 18:11:07 -07003498 /* Div-2 */
Fred Oh4d716bb2013-07-30 10:14:46 -07003499 iowrite32(0x3, pdig1);
3500 iowrite32(0x0, pdig2);
3501 iowrite32(0x0, pdig3);
3502 iowrite32(0x0, pdig4);
Kuirong Wangae340de2013-05-30 18:11:07 -07003503 /* Digital codec clock enable */
Fred Oh4d716bb2013-07-30 10:14:46 -07003504 iowrite32(0x1, pdig5);
Kuirong Wangae340de2013-05-30 18:11:07 -07003505 /* Set the update bit to make the settings go through */
Fred Oh4d716bb2013-07-30 10:14:46 -07003506 iowrite32(0x1, pdig6);
Kuirong Wangae340de2013-05-30 18:11:07 -07003507 usleep_range(100, 200);
Fred Oh4d716bb2013-07-30 10:14:46 -07003508
3509 iounmap(pdig1);
3510 iounmap(pdig2);
3511 iounmap(pdig3);
3512 iounmap(pdig4);
3513 iounmap(pdig5);
3514 iounmap(pdig6);
Kuirong Wangae340de2013-05-30 18:11:07 -07003515 return 0;
3516}
3517
Kuirong Wang91e52532013-03-31 14:24:22 -07003518static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
3519{
3520 mutex_init(&msm8x10->io_lock);
3521 mutex_init(&msm8x10->xfer_lock);
Kuirong Wang2e81d322013-05-30 17:52:36 -07003522 msm8x10_wcd_pads_config();
Kuirong Wangae340de2013-05-30 18:11:07 -07003523 msm8x10_wcd_clk_init();
Kuirong Wang91e52532013-03-31 14:24:22 -07003524 return 0;
3525}
3526
Bhalchandra Gajarece1fe592013-07-12 12:58:02 -07003527static struct intr_data interrupt_table[] = {
3528 {MSM8X10_WCD_IRQ_MBHC_INSERTION, true},
3529 {MSM8X10_WCD_IRQ_MBHC_POTENTIAL, true},
3530 {MSM8X10_WCD_IRQ_MBHC_RELEASE, true},
3531 {MSM8X10_WCD_IRQ_MBHC_PRESS, true},
3532 {MSM8X10_WCD_IRQ_MBHC_SHORT_TERM, true},
3533 {MSM8X10_WCD_IRQ_MBHC_REMOVAL, true},
3534 {MSM8X10_WCD_IRQ_MBHC_HS_DET, true},
3535 {MSM8X10_WCD_IRQ_RESERVED_0, false},
3536 {MSM8X10_WCD_IRQ_PA_STARTUP, false},
3537 {MSM8X10_WCD_IRQ_BG_PRECHARGE, false},
3538 {MSM8X10_WCD_IRQ_RESERVED_1, false},
3539 {MSM8X10_WCD_IRQ_EAR_PA_OCPL_FAULT, false},
3540 {MSM8X10_WCD_IRQ_EAR_PA_STARTUP, false},
3541 {MSM8X10_WCD_IRQ_SPKR_PA_OCPL_FAULT, false},
3542 {MSM8X10_WCD_IRQ_SPKR_CLIP_FAULT, false},
3543 {MSM8X10_WCD_IRQ_RESERVED_2, false},
3544 {MSM8X10_WCD_IRQ_HPH_L_PA_STARTUP, false},
3545 {MSM8X10_WCD_IRQ_HPH_R_PA_STARTUP, false},
3546 {MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT, false},
3547 {MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT, false},
3548 {MSM8X10_WCD_IRQ_RESERVED_3, false},
3549 {MSM8X10_WCD_IRQ_RESERVED_4, false},
3550 {MSM8X10_WCD_IRQ_RESERVED_5, false},
3551 {MSM8X10_WCD_IRQ_RESERVED_6, false},
3552};
3553
Kuirong Wang265f3592012-12-05 16:17:41 -08003554static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
3555 const struct i2c_device_id *id)
3556{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003557 int ret = 0;
3558 struct msm8x10_wcd *msm8x10 = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -08003559 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003560 static int device_id;
3561 struct device *dev;
Kuirong Wang2e81d322013-05-30 17:52:36 -07003562 enum apr_subsys_state q6_state;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003563 struct wcd9xxx_core_resource *core_res;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003564
Kuirong Wang2e81d322013-05-30 17:52:36 -07003565 dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
3566 __func__, __LINE__, client->addr, device_id);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003567
Kuirong Wang2e81d322013-05-30 17:52:36 -07003568 switch (client->addr) {
3569 case HELICON_CORE_0_I2C_ADDR:
3570 msm8x10_wcd_modules[0].client = client;
3571 break;
3572 case HELICON_CORE_1_I2C_ADDR:
3573 msm8x10_wcd_modules[1].client = client;
3574 goto rtn;
3575 case HELICON_CORE_2_I2C_ADDR:
3576 msm8x10_wcd_modules[2].client = client;
3577 goto rtn;
3578 case HELICON_CORE_3_I2C_ADDR:
3579 msm8x10_wcd_modules[3].client = client;
3580 goto rtn;
3581 default:
3582 ret = -EINVAL;
Kuirong Wang91e52532013-03-31 14:24:22 -07003583 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003584 }
3585
Kuirong Wang2e81d322013-05-30 17:52:36 -07003586 q6_state = apr_get_q6_state();
3587 if ((q6_state == APR_SUBSYS_DOWN) &&
3588 (client->addr == HELICON_CORE_0_I2C_ADDR)) {
3589 dev_info(&client->dev, "defering %s, adsp_state %d\n", __func__,
3590 q6_state);
3591 return -EPROBE_DEFER;
3592 } else
3593 dev_info(&client->dev, "adsp is ready\n");
3594
3595 dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
3596 __func__, __LINE__, client->addr, device_id);
3597
3598 if (client->addr != HELICON_CORE_0_I2C_ADDR)
3599 goto rtn;
3600
Kuirong Wang14b3fb92013-06-27 17:28:17 -07003601 dev_set_name(&client->dev, "%s", MSM8X10_CODEC_NAME);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003602 dev = &client->dev;
Kuirong Wang265f3592012-12-05 16:17:41 -08003603 if (client->dev.of_node) {
3604 dev_dbg(&client->dev, "%s:Platform data from device tree\n",
3605 __func__);
3606 pdata = msm8x10_wcd_populate_dt_pdata(&client->dev);
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003607 if (!pdata) {
3608 dev_err(&client->dev, "%s: Failed to parse pdata from device tree\n",
3609 __func__);
3610 goto rtn;
3611 }
Kuirong Wang265f3592012-12-05 16:17:41 -08003612 client->dev.platform_data = pdata;
3613 } else {
3614 dev_dbg(&client->dev, "%s:Platform data from board file\n",
3615 __func__);
3616 pdata = client->dev.platform_data;
3617 }
3618
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003619 msm8x10 = kzalloc(sizeof(struct msm8x10_wcd), GFP_KERNEL);
3620 if (msm8x10 == NULL) {
3621 dev_err(&client->dev,
3622 "%s: error, allocation failed\n", __func__);
3623 ret = -ENOMEM;
Kuirong Wang91e52532013-03-31 14:24:22 -07003624 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003625 }
Kuirong Wang265f3592012-12-05 16:17:41 -08003626
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003627 msm8x10->dev = &client->dev;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003628 msm8x10->read_dev = __msm8x10_wcd_reg_read;
3629 msm8x10->write_dev = __msm8x10_wcd_reg_write;
Kuirong Wang49f506a2013-05-22 17:38:26 -07003630 ret = msm8x10_wcd_init_supplies(msm8x10, pdata);
Kuirong Wang91e52532013-03-31 14:24:22 -07003631 if (ret) {
3632 dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
3633 __func__);
3634 goto err_codec;
3635 }
Kuirong Wang49f506a2013-05-22 17:38:26 -07003636
3637 ret = msm8x10_wcd_enable_static_supplies(msm8x10, pdata);
3638 if (ret) {
3639 pr_err("%s: Fail to enable Codec pre-reset supplies\n",
3640 __func__);
3641 goto err_codec;
3642 }
3643 usleep_range(5, 5);
3644
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003645 ret = msm8x10_wcd_device_init(msm8x10);
3646 if (ret) {
3647 dev_err(&client->dev,
3648 "%s:msm8x10_wcd_device_init failed with error %d\n",
3649 __func__, ret);
Kuirong Wang91e52532013-03-31 14:24:22 -07003650 goto err_supplies;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003651 }
3652 dev_set_drvdata(&client->dev, msm8x10);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003653 core_res = &msm8x10->wcd9xxx_res;
Bhalchandra Gajarece1fe592013-07-12 12:58:02 -07003654 core_res->parent = msm8x10;
3655 core_res->dev = msm8x10->dev;
3656 core_res->intr_table = interrupt_table;
3657 core_res->intr_table_size = ARRAY_SIZE(interrupt_table);
3658
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003659 wcd9xxx_core_res_init(core_res,
3660 MSM8X10_WCD_NUM_IRQS,
3661 MSM8X10_WCD_NUM_IRQ_REGS,
3662 msm8x10_wcd_reg_read,
3663 msm8x10_wcd_reg_write,
Yeleswarapu, Nagaradheshbbba6e32013-12-20 18:09:17 +05303664 msm8x10_wcd_bulk_read,
3665 msm8x10_wcd_bulk_write);
Bhalchandra Gajarece1fe592013-07-12 12:58:02 -07003666 if (wcd9xxx_core_irq_init(core_res)) {
3667 dev_err(msm8x10->dev,
3668 "%s: irq initialization failed\n", __func__);
3669 } else {
3670 dev_info(msm8x10->dev,
3671 "%s: irq initialization passed\n", __func__);
3672 }
3673
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003674 ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
3675 msm8x10_wcd_i2s_dai,
3676 ARRAY_SIZE(msm8x10_wcd_i2s_dai));
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003677 if (ret) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003678 dev_err(&client->dev,
3679 "%s:snd_soc_register_codec failed with error %d\n",
3680 __func__, ret);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003681 } else {
3682 wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
Kuirong Wang91e52532013-03-31 14:24:22 -07003683 goto rtn;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003684 }
Kuirong Wang91e52532013-03-31 14:24:22 -07003685
3686err_supplies:
3687 msm8x10_wcd_disable_supplies(msm8x10, pdata);
3688err_codec:
3689 kfree(msm8x10);
3690rtn:
Kuirong Wang265f3592012-12-05 16:17:41 -08003691 return ret;
3692}
3693
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003694static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
3695{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003696 mutex_destroy(&msm8x10->io_lock);
3697 mutex_destroy(&msm8x10->xfer_lock);
3698 kfree(msm8x10);
3699}
3700
Kuirong Wang265f3592012-12-05 16:17:41 -08003701static int __devexit msm8x10_wcd_i2c_remove(struct i2c_client *client)
3702{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003703 struct msm8x10_wcd *msm8x10 = dev_get_drvdata(&client->dev);
3704
3705 msm8x10_wcd_device_exit(msm8x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08003706 return 0;
3707}
3708
3709static struct i2c_device_id msm8x10_wcd_id_table[] = {
3710 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_TOP_LEVEL},
3711 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_ANALOG},
3712 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_1},
3713 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_2},
3714 {}
3715};
3716
3717static struct of_device_id msm8x10_wcd_of_match[] = {
3718 { .compatible = "qcom,msm8x10-wcd-i2c",},
3719 { },
3720};
3721
Bhalchandra Gajare812e31e2013-10-17 15:22:35 -07003722#ifdef CONFIG_PM
3723static int msm8x10_wcd_i2c_resume(struct device *dev)
3724{
3725 struct i2c_client *client = to_i2c_client(dev);
3726 struct msm8x10_wcd_priv *priv = i2c_get_clientdata(client);
3727 struct msm8x10_wcd *msm8x10;
3728 int ret = 0;
3729
3730 if (client->addr == HELICON_CORE_0_I2C_ADDR) {
3731 if (!priv || !priv->codec || !priv->codec->control_data) {
3732 ret = -EINVAL;
3733 dev_err(dev, "%s: Invalid client data\n", __func__);
3734 goto rtn;
3735 }
3736 msm8x10 = priv->codec->control_data;
3737 return wcd9xxx_core_res_resume(&msm8x10->wcd9xxx_res);
3738 }
3739rtn:
3740 return 0;
3741}
3742
3743static int msm8x10_wcd_i2c_suspend(struct device *dev)
3744{
3745 struct i2c_client *client = to_i2c_client(dev);
3746 struct msm8x10_wcd_priv *priv = i2c_get_clientdata(client);
3747 struct msm8x10_wcd *msm8x10;
3748 int ret = 0;
3749
3750 if (client->addr == HELICON_CORE_0_I2C_ADDR) {
3751 if (!priv || !priv->codec || !priv->codec->control_data) {
3752 ret = -EINVAL;
3753 dev_err(dev, "%s: Invalid client data\n", __func__);
3754 goto rtn;
3755 }
3756 msm8x10 = priv->codec->control_data;
3757 return wcd9xxx_core_res_suspend(&msm8x10->wcd9xxx_res,
3758 PMSG_SUSPEND);
3759 }
3760
3761rtn:
3762 return ret;
3763}
3764
3765static SIMPLE_DEV_PM_OPS(msm8x1_wcd_pm_ops, msm8x10_wcd_i2c_suspend,
3766 msm8x10_wcd_i2c_resume);
3767#endif
Kuirong Wang265f3592012-12-05 16:17:41 -08003768
3769static struct i2c_driver msm8x10_wcd_i2c_driver = {
3770 .driver = {
3771 .owner = THIS_MODULE,
3772 .name = "msm8x10-wcd-i2c-core",
Bhalchandra Gajare812e31e2013-10-17 15:22:35 -07003773 .of_match_table = msm8x10_wcd_of_match,
3774#ifdef CONFIG_PM
3775 .pm = &msm8x1_wcd_pm_ops,
3776#endif
Kuirong Wang265f3592012-12-05 16:17:41 -08003777 },
3778 .id_table = msm8x10_wcd_id_table,
3779 .probe = msm8x10_wcd_i2c_probe,
3780 .remove = __devexit_p(msm8x10_wcd_i2c_remove),
3781};
3782
3783static int __init msm8x10_wcd_codec_init(void)
3784{
3785 int ret;
3786
3787 pr_debug("%s:\n", __func__);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003788 wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
Kuirong Wang265f3592012-12-05 16:17:41 -08003789 ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
3790 if (ret != 0)
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003791 pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
3792 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -08003793 return ret;
3794}
3795
3796static void __exit msm8x10_wcd_codec_exit(void)
3797{
3798 i2c_del_driver(&msm8x10_wcd_i2c_driver);
3799}
3800
3801
3802module_init(msm8x10_wcd_codec_init);
3803module_exit(msm8x10_wcd_codec_exit);
3804
3805MODULE_DESCRIPTION("MSM8x10 Audio codec driver");
3806MODULE_LICENSE("GPL v2");
3807MODULE_DEVICE_TABLE(i2c, msm8x10_wcd_id_table);
3808