blob: 452bbab84a25852a062f19987cb8cff097aaf6b1 [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;
Simmi Pateriya1cc09012014-01-21 17:58:11 +0530192 u32 micb_en_count;
Kuirong Wang265f3592012-12-05 16:17:41 -0800193};
194
Kuirong Wang265f3592012-12-05 16:17:41 -0800195static unsigned short rx_digital_gain_reg[] = {
196 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
197 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
198 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
199};
200
201static unsigned short tx_digital_gain_reg[] = {
202 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
203 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
204};
205
206struct msm8x10_wcd_i2c {
207 struct i2c_client *client;
208 struct i2c_msg xfer_msg[2];
209 struct mutex xfer_lock;
210 int mod_id;
211};
212
Kuirong Wang265f3592012-12-05 16:17:41 -0800213static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
Kuirong Wang49f506a2013-05-22 17:38:26 -0700214 struct msm8x10_wcd_regulator *vreg,
215 const char *vreg_name, bool ondemand);
Kuirong Wang265f3592012-12-05 16:17:41 -0800216static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -0700217 struct wcd9xxx_micbias_setting *micbias);
Kuirong Wang265f3592012-12-05 16:17:41 -0800218static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
219 struct device *dev);
220
221struct msm8x10_wcd_i2c msm8x10_wcd_modules[MAX_MSM8X10_WCD_DEVICE];
222
Fred Ohcf2f8582013-06-13 18:32:07 -0700223static void *adsp_state_notifier;
224
225static struct snd_soc_codec *registered_codec;
226#define ADSP_STATE_READY_TIMEOUT_MS 2000
227
Kuirong Wang265f3592012-12-05 16:17:41 -0800228
229static int get_i2c_msm8x10_wcd_device_info(u16 reg,
230 struct msm8x10_wcd_i2c **msm8x10_wcd)
231{
232 int rtn = 0;
233 int value = ((reg & 0x0f00) >> 8) & 0x000f;
Kuirong Wang265f3592012-12-05 16:17:41 -0800234 switch (value) {
235 case 0:
236 case 1:
237 *msm8x10_wcd = &msm8x10_wcd_modules[value];
238 break;
239 default:
240 rtn = -EINVAL;
241 break;
242 }
243 return rtn;
244}
245
Fred Oh4d716bb2013-07-30 10:14:46 -0700246static int msm8x10_wcd_abh_write_device(struct msm8x10_wcd *msm8x10_wcd,
247 u16 reg, u8 *value, u32 bytes)
Kuirong Wang265f3592012-12-05 16:17:41 -0800248{
249 u32 temp = ((u32)(*value)) & 0x000000FF;
250 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
Fred Oh4d716bb2013-07-30 10:14:46 -0700251
252 iowrite32(temp, (msm8x10_wcd->pdino_base+offset));
Kuirong Wang265f3592012-12-05 16:17:41 -0800253 return 0;
254}
255
Fred Oh4d716bb2013-07-30 10:14:46 -0700256static int msm8x10_wcd_abh_read_device(struct msm8x10_wcd *msm8x10_wcd,
257 u16 reg, u32 bytes, u8 *value)
Kuirong Wang265f3592012-12-05 16:17:41 -0800258{
Kuirong Wang91e52532013-03-31 14:24:22 -0700259 u32 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800260 u32 offset = (((u32)(reg)) ^ 0x00000400) & 0x00000FFF;
Fred Oh4d716bb2013-07-30 10:14:46 -0700261
262 temp = ioread32((msm8x10_wcd->pdino_base+offset));
Kuirong Wang91e52532013-03-31 14:24:22 -0700263 *value = (u8)temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800264 return 0;
265}
266
267static int msm8x10_wcd_i2c_write_device(u16 reg, u8 *value, u32 bytes)
268{
269
270 struct i2c_msg *msg;
271 int ret;
272 u8 reg_addr = 0;
273 u8 data[bytes + 1];
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800274 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800275
276 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800277 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800278 pr_err("%s: Invalid register address\n", __func__);
279 return ret;
280 }
281
282 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
283 pr_err("%s: Failed to get device info\n", __func__);
284 return -ENODEV;
285 }
286 reg_addr = (u8)reg;
287 msg = &msm8x10_wcd->xfer_msg[0];
288 msg->addr = msm8x10_wcd->client->addr;
289 msg->len = bytes + 1;
290 msg->flags = 0;
291 data[0] = reg;
292 data[1] = *value;
293 msg->buf = data;
294 ret = i2c_transfer(msm8x10_wcd->client->adapter,
295 msm8x10_wcd->xfer_msg, 1);
296 /* Try again if the write fails */
297 if (ret != 1) {
298 ret = i2c_transfer(msm8x10_wcd->client->adapter,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800299 msm8x10_wcd->xfer_msg, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -0800300 if (ret != 1) {
301 pr_err("failed to write the device\n");
302 return ret;
303 }
304 }
Kuirong Wang265f3592012-12-05 16:17:41 -0800305 return 0;
306}
307
308
309int msm8x10_wcd_i2c_read_device(u32 reg, u32 bytes, u8 *dest)
310{
311 struct i2c_msg *msg;
312 int ret = 0;
313 u8 reg_addr = 0;
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800314 struct msm8x10_wcd_i2c *msm8x10_wcd = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800315 u8 i = 0;
316
317 ret = get_i2c_msm8x10_wcd_device_info(reg, &msm8x10_wcd);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800318 if (ret) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800319 pr_err("%s: Invalid register address\n", __func__);
320 return ret;
321 }
322
323 if (msm8x10_wcd == NULL || msm8x10_wcd->client == NULL) {
324 pr_err("%s: Failed to get device info\n", __func__);
325 return -ENODEV;
326 }
327
328 for (i = 0; i < bytes; i++) {
329 reg_addr = (u8)reg++;
330 msg = &msm8x10_wcd->xfer_msg[0];
331 msg->addr = msm8x10_wcd->client->addr;
332 msg->len = 1;
333 msg->flags = 0;
334 msg->buf = &reg_addr;
Kuirong Wang265f3592012-12-05 16:17:41 -0800335 msg = &msm8x10_wcd->xfer_msg[1];
336 msg->addr = msm8x10_wcd->client->addr;
337 msg->len = 1;
338 msg->flags = I2C_M_RD;
339 msg->buf = dest++;
340 ret = i2c_transfer(msm8x10_wcd->client->adapter,
341 msm8x10_wcd->xfer_msg, 2);
342
343 /* Try again if read fails first time */
344 if (ret != 2) {
345 ret = i2c_transfer(msm8x10_wcd->client->adapter,
346 msm8x10_wcd->xfer_msg, 2);
347 if (ret != 2) {
348 pr_err("failed to read msm8x10_wcd register\n");
349 return ret;
350 }
351 }
352 }
353 return 0;
354}
355
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800356int msm8x10_wcd_i2c_read(unsigned short reg, int bytes, void *dest)
Kuirong Wang265f3592012-12-05 16:17:41 -0800357{
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800358 return msm8x10_wcd_i2c_read_device(reg, bytes, dest);
359}
360
361int msm8x10_wcd_i2c_write(unsigned short reg, int bytes, void *src)
362{
363 return msm8x10_wcd_i2c_write_device(reg, src, bytes);
364}
365
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700366static unsigned short msm8x10_wcd_mask_reg(unsigned short reg)
367{
368 if (reg >= 0x3C0 && reg <= 0x3DF)
369 reg = reg & 0x00FF;
370 return reg;
371}
372
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700373static int __msm8x10_wcd_reg_read(struct msm8x10_wcd *msm8x10_wcd,
374 unsigned short reg)
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800375{
Kuirong Wang265f3592012-12-05 16:17:41 -0800376 int ret = -EINVAL;
Kuirong Wang91e52532013-03-31 14:24:22 -0700377 u8 temp;
Kuirong Wang265f3592012-12-05 16:17:41 -0800378
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700379 reg = msm8x10_wcd_mask_reg(reg);
380
Kuirong Wang265f3592012-12-05 16:17:41 -0800381 /* check if use I2C interface for Helicon or AHB for Dino */
382 mutex_lock(&msm8x10_wcd->io_lock);
383 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang91e52532013-03-31 14:24:22 -0700384 ret = msm8x10_wcd_i2c_read(reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800385 else if (MSM8X10_WCD_IS_DINO_REG(reg))
Fred Oh4d716bb2013-07-30 10:14:46 -0700386 ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg, 1, &temp);
Kuirong Wang265f3592012-12-05 16:17:41 -0800387 mutex_unlock(&msm8x10_wcd->io_lock);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700388
389 if (ret < 0) {
390 dev_err(msm8x10_wcd->dev,
391 "%s: codec read failed for reg 0x%x\n",
392 __func__, reg);
393 return ret;
394 } else {
395 dev_dbg(msm8x10_wcd->dev, "Read 0x%02x from 0x%x\n",
396 temp, reg);
397 }
398
399 return temp;
400}
401
Yeleswarapu, Nagaradheshbbba6e32013-12-20 18:09:17 +0530402static int __msm8x10_wcd_bulk_write(struct msm8x10_wcd *msm8x10_wcd,
403 unsigned short reg, int count, u8 *buf)
404{
405 int ret = -EINVAL;
406 mutex_lock(&msm8x10_wcd->io_lock);
407 if (MSM8X10_WCD_IS_HELICON_REG(reg))
408 ret = msm8x10_wcd_i2c_write(reg, count, buf);
409 else if (MSM8X10_WCD_IS_DINO_REG(reg))
410 ret = msm8x10_wcd_abh_write_device(msm8x10_wcd, reg,
411 buf, count);
412 if (ret < 0)
413 dev_err(msm8x10_wcd->dev,
414 "%s: codec bulk write failed\n", __func__);
415 mutex_unlock(&msm8x10_wcd->io_lock);
416 return ret;
417}
418
419int msm8x10_wcd_bulk_write(struct wcd9xxx_core_resource *core_res,
420 unsigned short reg, int count, u8 *buf)
421{
422 struct msm8x10_wcd *msm8x10_wcd =
423 (struct msm8x10_wcd *) core_res->parent;
424 return __msm8x10_wcd_bulk_write(msm8x10_wcd, reg, count, buf);
425}
426EXPORT_SYMBOL(msm8x10_wcd_bulk_write);
427
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700428int msm8x10_wcd_reg_read(struct wcd9xxx_core_resource *core_res,
429 unsigned short reg)
430{
431 struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
432 return __msm8x10_wcd_reg_read(msm8x10_wcd, reg);
433}
434EXPORT_SYMBOL(msm8x10_wcd_reg_read);
435
436static int __msm8x10_wcd_bulk_read(struct msm8x10_wcd *msm8x10_wcd,
437 unsigned short reg, int count, u8 *buf)
438{
439 int ret = -EINVAL;
440 mutex_lock(&msm8x10_wcd->io_lock);
441 if (MSM8X10_WCD_IS_HELICON_REG(reg))
442 ret = msm8x10_wcd_i2c_read(reg, count, buf);
443 else if (MSM8X10_WCD_IS_DINO_REG(reg))
444 ret = msm8x10_wcd_abh_read_device(msm8x10_wcd, reg,
445 count, buf);
446 mutex_unlock(&msm8x10_wcd->io_lock);
447
448 if (ret < 0)
449 dev_err(msm8x10_wcd->dev,
450 "%s: codec bulk read failed\n", __func__);
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800451 return ret;
Kuirong Wang265f3592012-12-05 16:17:41 -0800452}
453
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700454int msm8x10_wcd_bulk_read(struct wcd9xxx_core_resource *core_res,
455 unsigned short reg, int count, u8 *buf)
456{
457 struct msm8x10_wcd *msm8x10_wcd =
458 (struct msm8x10_wcd *) core_res->parent;
459 return __msm8x10_wcd_bulk_read(msm8x10_wcd, reg, count, buf);
460}
461EXPORT_SYMBOL(msm8x10_wcd_bulk_read);
Kuirong Wang265f3592012-12-05 16:17:41 -0800462
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700463static int __msm8x10_wcd_reg_write(struct msm8x10_wcd *msm8x10_wcd,
464 unsigned short reg, u8 val)
Kuirong Wang265f3592012-12-05 16:17:41 -0800465{
466 int ret = -EINVAL;
467
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -0700468 reg = msm8x10_wcd_mask_reg(reg);
469
Kuirong Wang265f3592012-12-05 16:17:41 -0800470 /* check if use I2C interface for Helicon or AHB for Dino */
471 mutex_lock(&msm8x10_wcd->io_lock);
472 if (MSM8X10_WCD_IS_HELICON_REG(reg))
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800473 ret = msm8x10_wcd_i2c_write(reg, 1, &val);
Kuirong Wang265f3592012-12-05 16:17:41 -0800474 else if (MSM8X10_WCD_IS_DINO_REG(reg))
Fred Oh4d716bb2013-07-30 10:14:46 -0700475 ret = msm8x10_wcd_abh_write_device(msm8x10_wcd, reg, &val, 1);
Kuirong Wang265f3592012-12-05 16:17:41 -0800476 mutex_unlock(&msm8x10_wcd->io_lock);
477
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700478 if (ret < 0)
479 dev_err(msm8x10_wcd->dev,
480 "%s: codec write to reg 0x%x failed\n",
481 __func__, reg);
482 else
483 dev_dbg(msm8x10_wcd->dev,
Phani Kumar Uppalapatibfc63942014-01-28 15:18:43 -0800484 "%s: Write 0x%x to 0x%x\n",
485 __func__, val, reg);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700486
Kuirong Wang265f3592012-12-05 16:17:41 -0800487 return ret;
488}
489
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700490int msm8x10_wcd_reg_write(struct wcd9xxx_core_resource *core_res,
491 unsigned short reg, u8 val)
492{
493 struct msm8x10_wcd *msm8x10_wcd = core_res->parent;
494 return __msm8x10_wcd_reg_write(msm8x10_wcd, reg, val);
495}
496EXPORT_SYMBOL(msm8x10_wcd_reg_write);
497
Kuirong Wang265f3592012-12-05 16:17:41 -0800498static bool msm8x10_wcd_is_digital_gain_register(unsigned int reg)
499{
500 bool rtn = false;
501 switch (reg) {
502 case MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL:
503 case MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL:
504 case MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL:
505 case MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN:
506 case MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN:
507 rtn = true;
508 break;
509 default:
510 break;
511 }
512 return rtn;
513}
514
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800515static int msm8x10_wcd_volatile(struct snd_soc_codec *codec, unsigned int reg)
Kuirong Wang265f3592012-12-05 16:17:41 -0800516{
517 /*
518 * Registers lower than 0x100 are top level registers which can be
519 * written by the Taiko core driver.
520 */
Kuirong Wang265f3592012-12-05 16:17:41 -0800521 if ((reg >= MSM8X10_WCD_A_CDC_MBHC_EN_CTL) || (reg < 0x100))
522 return 1;
523
524 /* IIR Coeff registers are not cacheable */
525 if ((reg >= MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL) &&
526 (reg <= MSM8X10_WCD_A_CDC_IIR2_COEF_B2_CTL))
527 return 1;
528
529 /*
530 * Digital gain register is not cacheable so we have to write
531 * the setting even it is the same
532 */
533 if (msm8x10_wcd_is_digital_gain_register(reg))
534 return 1;
535
536 /* HPH status registers */
537 if (reg == MSM8X10_WCD_A_RX_HPH_L_STATUS ||
538 reg == MSM8X10_WCD_A_RX_HPH_R_STATUS)
539 return 1;
540
541 if (reg == MSM8X10_WCD_A_MBHC_INSERT_DET_STATUS)
542 return 1;
543
544 return 0;
545}
546
547static int msm8x10_wcd_readable(struct snd_soc_codec *ssc, unsigned int reg)
548{
549 return msm8x10_wcd_reg_readable[reg];
550}
551
552static int msm8x10_wcd_write(struct snd_soc_codec *codec, unsigned int reg,
553 unsigned int value)
554{
555 int ret;
Phani Kumar Uppalapatibfc63942014-01-28 15:18:43 -0800556 dev_dbg(codec->dev, "%s: Write to reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800557 if (reg == SND_SOC_NOPM)
558 return 0;
559
560 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
561
562 if (!msm8x10_wcd_volatile(codec, reg)) {
563 ret = snd_soc_cache_write(codec, reg, value);
564 if (ret != 0)
565 dev_err(codec->dev, "Cache write to %x failed: %d\n",
566 reg, ret);
567 }
568
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700569 return __msm8x10_wcd_reg_write(codec->control_data, reg, (u8)value);
Kuirong Wang265f3592012-12-05 16:17:41 -0800570}
571
572static unsigned int msm8x10_wcd_read(struct snd_soc_codec *codec,
573 unsigned int reg)
574{
575 unsigned int val;
576 int ret;
577
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800578 dev_dbg(codec->dev, "%s: Read from reg 0x%x\n", __func__, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800579 if (reg == SND_SOC_NOPM)
580 return 0;
581
582 BUG_ON(reg > MSM8X10_WCD_MAX_REGISTER);
583
584 if (!msm8x10_wcd_volatile(codec, reg) &&
585 msm8x10_wcd_readable(codec, reg) &&
586 reg < codec->driver->reg_cache_size) {
587 ret = snd_soc_cache_read(codec, reg, &val);
588 if (ret >= 0) {
589 return val;
590 } else
591 dev_err(codec->dev, "Cache read from %x failed: %d\n",
592 reg, ret);
593 }
594
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -0700595 val = __msm8x10_wcd_reg_read(codec->control_data, reg);
Kuirong Wang265f3592012-12-05 16:17:41 -0800596 return val;
597}
598
599
600static int msm8x10_wcd_dt_parse_vreg_info(struct device *dev,
Kuirong Wang49f506a2013-05-22 17:38:26 -0700601 struct msm8x10_wcd_regulator *vreg, const char *vreg_name,
602 bool ondemand)
Kuirong Wang265f3592012-12-05 16:17:41 -0800603{
604 int len, ret = 0;
605 const __be32 *prop;
606 char prop_name[CODEC_DT_MAX_PROP_SIZE];
607 struct device_node *regnode = NULL;
608 u32 prop_val;
609
610 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "%s-supply",
611 vreg_name);
612 regnode = of_parse_phandle(dev->of_node, prop_name, 0);
613
614 if (!regnode) {
Kuirong Wang91e52532013-03-31 14:24:22 -0700615 dev_err(dev, "Looking up %s property in node %s failed\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800616 prop_name, dev->of_node->full_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800617 return -ENODEV;
618 }
Kuirong Wang91e52532013-03-31 14:24:22 -0700619
620 dev_dbg(dev, "Looking up %s property in node %s\n",
621 prop_name, dev->of_node->full_name);
622
Kuirong Wang265f3592012-12-05 16:17:41 -0800623 vreg->name = vreg_name;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700624 vreg->ondemand = ondemand;
Kuirong Wang265f3592012-12-05 16:17:41 -0800625
626 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
627 "qcom,%s-voltage", vreg_name);
628 prop = of_get_property(dev->of_node, prop_name, &len);
629
630 if (!prop || (len != (2 * sizeof(__be32)))) {
631 dev_err(dev, "%s %s property\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800632 prop ? "invalid format" : "no", prop_name);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700633 return -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800634 } else {
635 vreg->min_uV = be32_to_cpup(&prop[0]);
636 vreg->max_uV = be32_to_cpup(&prop[1]);
637 }
638
639 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800640 "qcom,%s-current", vreg_name);
Kuirong Wang265f3592012-12-05 16:17:41 -0800641
642 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
643 if (ret) {
644 dev_err(dev, "Looking up %s property in node %s failed",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800645 prop_name, dev->of_node->full_name);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700646 return -EFAULT;
Kuirong Wang265f3592012-12-05 16:17:41 -0800647 }
648 vreg->optimum_uA = prop_val;
649
Kuirong Wang49f506a2013-05-22 17:38:26 -0700650 dev_info(dev, "%s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n\n", vreg->name,
651 vreg->min_uV, vreg->max_uV, vreg->optimum_uA, vreg->ondemand);
Kuirong Wang265f3592012-12-05 16:17:41 -0800652 return 0;
653}
654
655static int msm8x10_wcd_dt_parse_micbias_info(struct device *dev,
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -0700656 struct wcd9xxx_micbias_setting *micbias)
Kuirong Wang265f3592012-12-05 16:17:41 -0800657{
658 int ret = 0;
659 char prop_name[CODEC_DT_MAX_PROP_SIZE];
660 u32 prop_val;
661
662 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -0700663 "qcom,cdc-micbias-ldoh-v");
664 ret = of_property_read_u32(dev->of_node, prop_name,
665 &prop_val);
666 if (ret) {
667 dev_err(dev, "Looking up %s property in node %s failed",
668 prop_name, dev->of_node->full_name);
669 return -ENODEV;
670 }
671 micbias->ldoh_v = (u8) prop_val;
672
673 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700674 "qcom,cdc-micbias-cfilt-mv");
Kuirong Wang265f3592012-12-05 16:17:41 -0800675 ret = of_property_read_u32(dev->of_node, prop_name,
676 &micbias->cfilt1_mv);
677 if (ret) {
678 dev_err(dev, "Looking up %s property in node %s failed",
679 prop_name, dev->of_node->full_name);
680 return -ENODEV;
681 }
682
683 snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE,
Kuirong Wang91e52532013-03-31 14:24:22 -0700684 "qcom,cdc-micbias-cfilt-sel");
Kuirong Wang265f3592012-12-05 16:17:41 -0800685 ret = of_property_read_u32(dev->of_node, prop_name, &prop_val);
686 if (ret) {
687 dev_err(dev, "Looking up %s property in node %s failed",
688 prop_name, dev->of_node->full_name);
689 return -ENODEV;
690 }
691 micbias->bias1_cfilt_sel = (u8)prop_val;
692
693 /* micbias external cap */
694 micbias->bias1_cap_mode =
695 (of_property_read_bool(dev->of_node, "qcom,cdc-micbias1-ext-cap") ?
696 MICBIAS_EXT_BYP_CAP : MICBIAS_NO_EXT_BYP_CAP);
697
698 dev_dbg(dev, "ldoh_v %u cfilt1_mv %u\n",
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800699 (u32)micbias->ldoh_v, (u32)micbias->cfilt1_mv);
Kuirong Wang265f3592012-12-05 16:17:41 -0800700 dev_dbg(dev, "bias1_cfilt_sel %u\n", (u32)micbias->bias1_cfilt_sel);
701 dev_dbg(dev, "bias1_ext_cap %d\n", micbias->bias1_cap_mode);
702
703 return 0;
704}
705
706static struct msm8x10_wcd_pdata *msm8x10_wcd_populate_dt_pdata(
707 struct device *dev)
708{
709 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700710 int ret, static_cnt, ond_cnt, idx, i;
711 const char *name = NULL;
712 const char *static_prop_name = "qcom,cdc-static-supplies";
713 const char *ond_prop_name = "qcom,cdc-on-demand-supplies";
Kuirong Wang265f3592012-12-05 16:17:41 -0800714
715 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
716 if (!pdata) {
717 dev_err(dev, "could not allocate memory for platform data\n");
718 return NULL;
719 }
Kuirong Wang49f506a2013-05-22 17:38:26 -0700720
721 static_cnt = of_property_count_strings(dev->of_node, static_prop_name);
722 if (IS_ERR_VALUE(static_cnt)) {
723 dev_err(dev, "%s: Failed to get static supplies %d\n", __func__,
724 static_cnt);
725 ret = -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800726 goto err;
727 }
728
Kuirong Wang49f506a2013-05-22 17:38:26 -0700729 /* On-demand supply list is an optional property */
730 ond_cnt = of_property_count_strings(dev->of_node, ond_prop_name);
731 if (IS_ERR_VALUE(ond_cnt))
732 ond_cnt = 0;
733
734 BUG_ON(static_cnt <= 0 || ond_cnt < 0);
735 if ((static_cnt + ond_cnt) > ARRAY_SIZE(pdata->regulator)) {
Kuirong Wang265f3592012-12-05 16:17:41 -0800736 dev_err(dev, "%s: Num of supplies %u > max supported %u\n",
Kuirong Wang49f506a2013-05-22 17:38:26 -0700737 __func__, static_cnt, ARRAY_SIZE(pdata->regulator));
738 ret = -EINVAL;
Kuirong Wang265f3592012-12-05 16:17:41 -0800739 goto err;
740 }
741
Kuirong Wang49f506a2013-05-22 17:38:26 -0700742 for (idx = 0; idx < static_cnt; idx++) {
743 ret = of_property_read_string_index(dev->of_node,
744 static_prop_name, idx,
745 &name);
746 if (ret) {
747 dev_err(dev, "%s: of read string %s idx %d error %d\n",
748 __func__, static_prop_name, idx, ret);
749 goto err;
750 }
751
752 dev_dbg(dev, "%s: Found static cdc supply %s\n", __func__,
753 name);
754 ret = msm8x10_wcd_dt_parse_vreg_info(dev,
755 &pdata->regulator[idx],
756 name, false);
Kuirong Wang265f3592012-12-05 16:17:41 -0800757 if (ret)
758 goto err;
759 }
Kuirong Wang49f506a2013-05-22 17:38:26 -0700760
761 for (i = 0; i < ond_cnt; i++, idx++) {
762 ret = of_property_read_string_index(dev->of_node, ond_prop_name,
763 i, &name);
764 if (ret)
765 goto err;
766
767 dev_dbg(dev, "%s: Found on-demand cdc supply %s\n", __func__,
768 name);
769 ret = msm8x10_wcd_dt_parse_vreg_info(dev,
770 &pdata->regulator[idx],
771 name, true);
772 if (ret)
773 goto err;
774 }
775
Kuirong Wang265f3592012-12-05 16:17:41 -0800776 ret = msm8x10_wcd_dt_parse_micbias_info(dev, &pdata->micbias);
777 if (ret)
778 goto err;
Kuirong Wang265f3592012-12-05 16:17:41 -0800779 return pdata;
780err:
781 devm_kfree(dev, pdata);
Kuirong Wang91e52532013-03-31 14:24:22 -0700782 dev_err(dev, "%s: Failed to populate DT data ret = %d\n",
783 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -0800784 return NULL;
785}
786
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -0800787static int on_demand_regulator_control(struct on_demand_supply *supply,
788 bool enable,
789 u8 shift)
790{
791 int ret = 0;
792
793 if (!supply || !supply->supply)
794 return 0;
795
796 if (enable) {
797 if (atomic_inc_return(&supply->ref) == 1)
798 ret = regulator_enable(supply->supply);
799 if (ret)
800 pr_err("%s: Failed to enable %s\n",
801 __func__,
802 on_demand_supply_name[shift]);
803 } else {
804 if (atomic_read(&supply->ref) == 0) {
805 pr_debug("%s: %s supply has been disabled.\n",
806 __func__, on_demand_supply_name[shift]);
807 return 0;
808 }
809 if (atomic_dec_return(&supply->ref) == 0)
810 ret = regulator_disable(supply->supply);
811 if (ret)
812 pr_err("%s: Failed to disable %s\n",
813 __func__,
814 on_demand_supply_name[shift]);
815 }
816
817 return ret;
818}
819
Kuirong Wang49f506a2013-05-22 17:38:26 -0700820static int msm8x10_wcd_codec_enable_on_demand_supply(
821 struct snd_soc_dapm_widget *w,
822 struct snd_kcontrol *kcontrol, int event)
823{
824 int ret = 0;
825 struct snd_soc_codec *codec = w->codec;
826 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
827 struct on_demand_supply *supply;
828
829 if (w->shift >= ON_DEMAND_SUPPLIES_MAX) {
830 ret = -EINVAL;
831 goto out;
832 }
833 dev_dbg(codec->dev, "%s: supply: %s event: %d ref: %d\n",
834 __func__, on_demand_supply_name[w->shift], event,
835 atomic_read(&msm8x10_wcd->on_demand_list[w->shift].ref));
836
837 supply = &msm8x10_wcd->on_demand_list[w->shift];
838 WARN_ONCE(!supply->supply, "%s isn't defined\n",
839 on_demand_supply_name[w->shift]);
840 if (!supply->supply)
841 goto out;
842
843 switch (event) {
844 case SND_SOC_DAPM_PRE_PMU:
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -0800845 ret = on_demand_regulator_control(supply,
846 true,
847 w->shift);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700848 break;
849 case SND_SOC_DAPM_POST_PMD:
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -0800850 ret = on_demand_regulator_control(supply,
851 false,
852 w->shift);
Kuirong Wang49f506a2013-05-22 17:38:26 -0700853 break;
854 default:
855 break;
856 }
857out:
858 return ret;
859}
860
Kuirong Wang265f3592012-12-05 16:17:41 -0800861static int msm8x10_wcd_codec_enable_charge_pump(struct snd_soc_dapm_widget *w,
862 struct snd_kcontrol *kcontrol, int event)
863{
864 struct snd_soc_codec *codec = w->codec;
865
Kuirong Wang49f506a2013-05-22 17:38:26 -0700866 dev_dbg(codec->dev, "%s: event = %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -0800867 switch (event) {
868 case SND_SOC_DAPM_POST_PMU:
869 /* Enable charge pump clock*/
870 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
871 0x01, 0x01);
872 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLSG_CTL,
873 0x08, 0x08);
874 usleep_range(200, 300);
875 snd_soc_update_bits(codec, MSM8X10_WCD_A_CP_STATIC,
876 0x10, 0x00);
877 break;
878 case SND_SOC_DAPM_PRE_PMD:
879 snd_soc_update_bits(codec,
880 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
881 0x01, 0x01);
882 usleep_range(20, 100);
883 snd_soc_update_bits(codec,
884 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x08);
885 snd_soc_update_bits(codec,
886 MSM8X10_WCD_A_CP_STATIC, 0x10, 0x10);
887 snd_soc_update_bits(codec,
888 MSM8X10_WCD_A_CDC_CLSG_CTL, 0x08, 0x00);
889 snd_soc_update_bits(codec,
890 MSM8X10_WCD_A_CDC_CLK_OTHR_CTL, 0x01,
891 0x00);
892 snd_soc_update_bits(codec,
Kuirong Wang91e52532013-03-31 14:24:22 -0700893 MSM8X10_WCD_A_CDC_CLK_OTHR_RESET_B1_CTL,
Kuirong Wang854de642013-05-24 13:40:41 -0700894 0x01, 0x00);
Kuirong Wang91e52532013-03-31 14:24:22 -0700895 snd_soc_update_bits(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800896 MSM8X10_WCD_A_CP_STATIC, 0x08, 0x00);
897 break;
Kuirong Wang49f506a2013-05-22 17:38:26 -0700898 default:
899 break;
Kuirong Wang265f3592012-12-05 16:17:41 -0800900 }
901 return 0;
902}
903
904static int msm8x10_wcd_pa_gain_get(struct snd_kcontrol *kcontrol,
905 struct snd_ctl_elem_value *ucontrol)
906{
907 u8 ear_pa_gain;
908 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
909
910 ear_pa_gain = snd_soc_read(codec, MSM8X10_WCD_A_RX_EAR_GAIN);
911
912 ear_pa_gain = ear_pa_gain >> 5;
913
914 if (ear_pa_gain == 0x00) {
915 ucontrol->value.integer.value[0] = 0;
916 } else if (ear_pa_gain == 0x04) {
917 ucontrol->value.integer.value[0] = 1;
918 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800919 dev_err(codec->dev, "%s: ERROR: Unsupported Ear Gain = 0x%x\n",
920 __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800921 return -EINVAL;
922 }
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800923 dev_dbg(codec->dev, "%s: ear_pa_gain = 0x%x\n", __func__, ear_pa_gain);
Kuirong Wang265f3592012-12-05 16:17:41 -0800924 return 0;
925}
926
927static int msm8x10_wcd_pa_gain_put(struct snd_kcontrol *kcontrol,
928 struct snd_ctl_elem_value *ucontrol)
929{
930 u8 ear_pa_gain;
931 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
932
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800933 dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
934 __func__, ucontrol->value.integer.value[0]);
Kuirong Wang265f3592012-12-05 16:17:41 -0800935
936 switch (ucontrol->value.integer.value[0]) {
937 case 0:
938 ear_pa_gain = 0x00;
939 break;
940 case 1:
941 ear_pa_gain = 0x80;
942 break;
943 default:
944 return -EINVAL;
945 }
946
947 snd_soc_update_bits(codec, MSM8X10_WCD_A_RX_EAR_GAIN,
948 0xE0, ear_pa_gain);
949 return 0;
950}
951
952static int msm8x10_wcd_get_iir_enable_audio_mixer(
953 struct snd_kcontrol *kcontrol,
954 struct snd_ctl_elem_value *ucontrol)
955{
956 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
957 int iir_idx = ((struct soc_multi_mixer_control *)
958 kcontrol->private_value)->reg;
959 int band_idx = ((struct soc_multi_mixer_control *)
960 kcontrol->private_value)->shift;
961
962 ucontrol->value.integer.value[0] =
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700963 (snd_soc_read(codec,
Kuirong Wang265f3592012-12-05 16:17:41 -0800964 (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700965 (1 << band_idx)) != 0;
Kuirong Wang265f3592012-12-05 16:17:41 -0800966
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800967 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -0800968 iir_idx, band_idx,
969 (uint32_t)ucontrol->value.integer.value[0]);
970 return 0;
971}
972
973static int msm8x10_wcd_put_iir_enable_audio_mixer(
974 struct snd_kcontrol *kcontrol,
975 struct snd_ctl_elem_value *ucontrol)
976{
977 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
978 int iir_idx = ((struct soc_multi_mixer_control *)
979 kcontrol->private_value)->reg;
980 int band_idx = ((struct soc_multi_mixer_control *)
981 kcontrol->private_value)->shift;
982 int value = ucontrol->value.integer.value[0];
983
984 /* Mask first 5 bits, 6-8 are reserved */
985 snd_soc_update_bits(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx),
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800986 (1 << band_idx), (value << band_idx));
Kuirong Wang265f3592012-12-05 16:17:41 -0800987
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800988 dev_dbg(codec->dev, "%s: IIR #%d band #%d enable %d\n", __func__,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700989 iir_idx, band_idx,
990 ((snd_soc_read(codec, (MSM8X10_WCD_A_CDC_IIR1_CTL + 64 * iir_idx)) &
991 (1 << band_idx)) != 0));
992
Kuirong Wang265f3592012-12-05 16:17:41 -0800993 return 0;
994}
995static uint32_t get_iir_band_coeff(struct snd_soc_codec *codec,
Kuirong Wang3a6408d2013-02-20 17:46:46 -0800996 int iir_idx, int band_idx,
997 int coeff_idx)
Kuirong Wang265f3592012-12-05 16:17:41 -0800998{
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -0700999 uint32_t value = 0;
1000
Kuirong Wang265f3592012-12-05 16:17:41 -08001001 /* Address does not automatically update if reading */
1002 snd_soc_write(codec,
1003 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001004 ((band_idx * BAND_MAX + coeff_idx)
1005 * sizeof(uint32_t)) & 0x7F);
1006
1007 value |= snd_soc_read(codec,
1008 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx));
1009
1010 snd_soc_write(codec,
1011 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
1012 ((band_idx * BAND_MAX + coeff_idx)
1013 * sizeof(uint32_t) + 1) & 0x7F);
1014
1015 value |= (snd_soc_read(codec,
1016 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 8);
1017
1018 snd_soc_write(codec,
1019 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
1020 ((band_idx * BAND_MAX + coeff_idx)
1021 * sizeof(uint32_t) + 2) & 0x7F);
1022
1023 value |= (snd_soc_read(codec,
1024 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) << 16);
1025
1026 snd_soc_write(codec,
1027 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
1028 ((band_idx * BAND_MAX + coeff_idx)
1029 * sizeof(uint32_t) + 3) & 0x7F);
Kuirong Wang265f3592012-12-05 16:17:41 -08001030
1031 /* Mask bits top 2 bits since they are reserved */
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001032 value |= ((snd_soc_read(codec,
1033 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx)) & 0x3f) << 24);
1034
1035 return value;
1036
Kuirong Wang265f3592012-12-05 16:17:41 -08001037}
1038
1039static int msm8x10_wcd_get_iir_band_audio_mixer(
1040 struct snd_kcontrol *kcontrol,
1041 struct snd_ctl_elem_value *ucontrol)
1042{
1043 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1044 int iir_idx = ((struct soc_multi_mixer_control *)
1045 kcontrol->private_value)->reg;
1046 int band_idx = ((struct soc_multi_mixer_control *)
1047 kcontrol->private_value)->shift;
1048
1049 ucontrol->value.integer.value[0] =
1050 get_iir_band_coeff(codec, iir_idx, band_idx, 0);
1051 ucontrol->value.integer.value[1] =
1052 get_iir_band_coeff(codec, iir_idx, band_idx, 1);
1053 ucontrol->value.integer.value[2] =
1054 get_iir_band_coeff(codec, iir_idx, band_idx, 2);
1055 ucontrol->value.integer.value[3] =
1056 get_iir_band_coeff(codec, iir_idx, band_idx, 3);
1057 ucontrol->value.integer.value[4] =
1058 get_iir_band_coeff(codec, iir_idx, band_idx, 4);
1059
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001060 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -08001061 "%s: IIR #%d band #%d b1 = 0x%x\n"
1062 "%s: IIR #%d band #%d b2 = 0x%x\n"
1063 "%s: IIR #%d band #%d a1 = 0x%x\n"
1064 "%s: IIR #%d band #%d a2 = 0x%x\n",
1065 __func__, iir_idx, band_idx,
1066 (uint32_t)ucontrol->value.integer.value[0],
1067 __func__, iir_idx, band_idx,
1068 (uint32_t)ucontrol->value.integer.value[1],
1069 __func__, iir_idx, band_idx,
1070 (uint32_t)ucontrol->value.integer.value[2],
1071 __func__, iir_idx, band_idx,
1072 (uint32_t)ucontrol->value.integer.value[3],
1073 __func__, iir_idx, band_idx,
1074 (uint32_t)ucontrol->value.integer.value[4]);
1075 return 0;
1076}
1077
1078static void set_iir_band_coeff(struct snd_soc_codec *codec,
1079 int iir_idx, int band_idx,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001080 uint32_t value)
Kuirong Wang265f3592012-12-05 16:17:41 -08001081{
Kuirong Wang265f3592012-12-05 16:17:41 -08001082 snd_soc_write(codec,
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001083 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1084 (value & 0xFF));
1085
1086 snd_soc_write(codec,
1087 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1088 (value >> 8) & 0xFF);
1089
1090 snd_soc_write(codec,
1091 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1092 (value >> 16) & 0xFF);
Kuirong Wang265f3592012-12-05 16:17:41 -08001093
1094 /* Mask top 2 bits, 7-8 are reserved */
1095 snd_soc_write(codec,
1096 (MSM8X10_WCD_A_CDC_IIR1_COEF_B2_CTL + 64 * iir_idx),
1097 (value >> 24) & 0x3F);
1098
1099}
1100
1101static int msm8x10_wcd_put_iir_band_audio_mixer(
1102 struct snd_kcontrol *kcontrol,
1103 struct snd_ctl_elem_value *ucontrol)
1104{
1105 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
1106 int iir_idx = ((struct soc_multi_mixer_control *)
1107 kcontrol->private_value)->reg;
1108 int band_idx = ((struct soc_multi_mixer_control *)
1109 kcontrol->private_value)->shift;
1110
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001111 /* Mask top bit it is reserved */
1112 /* Updates addr automatically for each B2 write */
1113 snd_soc_write(codec,
1114 (MSM8X10_WCD_A_CDC_IIR1_COEF_B1_CTL + 64 * iir_idx),
1115 (band_idx * BAND_MAX * sizeof(uint32_t)) & 0x7F);
1116
1117
1118 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001119 ucontrol->value.integer.value[0]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001120 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001121 ucontrol->value.integer.value[1]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001122 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001123 ucontrol->value.integer.value[2]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001124 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001125 ucontrol->value.integer.value[3]);
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07001126 set_iir_band_coeff(codec, iir_idx, band_idx,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001127 ucontrol->value.integer.value[4]);
Kuirong Wang265f3592012-12-05 16:17:41 -08001128
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001129 dev_dbg(codec->dev, "%s: IIR #%d band #%d b0 = 0x%x\n"
Kuirong Wang265f3592012-12-05 16:17:41 -08001130 "%s: IIR #%d band #%d b1 = 0x%x\n"
1131 "%s: IIR #%d band #%d b2 = 0x%x\n"
1132 "%s: IIR #%d band #%d a1 = 0x%x\n"
1133 "%s: IIR #%d band #%d a2 = 0x%x\n",
1134 __func__, iir_idx, band_idx,
1135 get_iir_band_coeff(codec, iir_idx, band_idx, 0),
1136 __func__, iir_idx, band_idx,
1137 get_iir_band_coeff(codec, iir_idx, band_idx, 1),
1138 __func__, iir_idx, band_idx,
1139 get_iir_band_coeff(codec, iir_idx, band_idx, 2),
1140 __func__, iir_idx, band_idx,
1141 get_iir_band_coeff(codec, iir_idx, band_idx, 3),
1142 __func__, iir_idx, band_idx,
1143 get_iir_band_coeff(codec, iir_idx, band_idx, 4));
1144 return 0;
1145}
1146
1147static const char * const msm8x10_wcd_ear_pa_gain_text[] = {
1148 "POS_6_DB", "POS_2_DB"};
1149static const struct soc_enum msm8x10_wcd_ear_pa_gain_enum[] = {
1150 SOC_ENUM_SINGLE_EXT(2, msm8x10_wcd_ear_pa_gain_text),
1151};
1152
1153/*cut of frequency for high pass filter*/
1154static const char * const cf_text[] = {
1155 "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz"
1156};
1157
1158static const struct soc_enum cf_dec1_enum =
1159 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 4, 3, cf_text);
1160
1161static const struct soc_enum cf_dec2_enum =
1162 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 4, 3, cf_text);
1163
1164static const struct soc_enum cf_rxmix1_enum =
1165 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX1_B4_CTL, 0, 3, cf_text);
1166
1167static const struct soc_enum cf_rxmix2_enum =
1168 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX2_B4_CTL, 0, 3, cf_text);
1169
1170static const struct soc_enum cf_rxmix3_enum =
1171 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_RX3_B4_CTL, 0, 3, cf_text);
1172
1173static const struct snd_kcontrol_new msm8x10_wcd_snd_controls[] = {
1174
1175 SOC_ENUM_EXT("EAR PA Gain", msm8x10_wcd_ear_pa_gain_enum[0],
1176 msm8x10_wcd_pa_gain_get, msm8x10_wcd_pa_gain_put),
1177
Kuirong Wang91e52532013-03-31 14:24:22 -07001178 SOC_SINGLE_TLV("LINEOUT Volume", MSM8X10_WCD_A_RX_LINE_1_GAIN,
Kuirong Wang265f3592012-12-05 16:17:41 -08001179 0, 12, 1, line_gain),
1180
1181 SOC_SINGLE_TLV("HPHL Volume", MSM8X10_WCD_A_RX_HPH_L_GAIN,
1182 0, 12, 1, line_gain),
1183 SOC_SINGLE_TLV("HPHR Volume", MSM8X10_WCD_A_RX_HPH_R_GAIN,
1184 0, 12, 1, line_gain),
1185
1186 SOC_SINGLE_S8_TLV("RX1 Digital Volume",
1187 MSM8X10_WCD_A_CDC_RX1_VOL_CTL_B2_CTL,
1188 -84, 40, digital_gain),
1189 SOC_SINGLE_S8_TLV("RX2 Digital Volume",
1190 MSM8X10_WCD_A_CDC_RX2_VOL_CTL_B2_CTL,
1191 -84, 40, digital_gain),
1192 SOC_SINGLE_S8_TLV("RX3 Digital Volume",
1193 MSM8X10_WCD_A_CDC_RX3_VOL_CTL_B2_CTL,
1194 -84, 40, digital_gain),
1195
1196 SOC_SINGLE_S8_TLV("DEC1 Volume",
1197 MSM8X10_WCD_A_CDC_TX1_VOL_CTL_GAIN,
1198 -84, 40, digital_gain),
1199 SOC_SINGLE_S8_TLV("DEC2 Volume",
1200 MSM8X10_WCD_A_CDC_TX2_VOL_CTL_GAIN,
1201 -84, 40, digital_gain),
1202
1203 SOC_SINGLE_S8_TLV("IIR1 INP1 Volume",
1204 MSM8X10_WCD_A_CDC_IIR1_GAIN_B1_CTL,
1205 -84, 40, digital_gain),
1206 SOC_SINGLE_S8_TLV("IIR1 INP2 Volume",
1207 MSM8X10_WCD_A_CDC_IIR1_GAIN_B2_CTL,
1208 -84, 40, digital_gain),
1209 SOC_SINGLE_S8_TLV("IIR1 INP3 Volume",
1210 MSM8X10_WCD_A_CDC_IIR1_GAIN_B3_CTL,
1211 -84, 40, digital_gain),
1212 SOC_SINGLE_S8_TLV("IIR1 INP4 Volume",
1213 MSM8X10_WCD_A_CDC_IIR1_GAIN_B4_CTL,
1214 -84, 40, digital_gain),
1215
Kuirong Wang265f3592012-12-05 16:17:41 -08001216 SOC_ENUM("TX1 HPF cut off", cf_dec1_enum),
1217 SOC_ENUM("TX2 HPF cut off", cf_dec2_enum),
1218
1219 SOC_SINGLE("TX1 HPF Switch", MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 3, 1, 0),
1220 SOC_SINGLE("TX2 HPF Switch", MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 3, 1, 0),
1221
1222 SOC_SINGLE("RX1 HPF Switch", MSM8X10_WCD_A_CDC_RX1_B5_CTL, 2, 1, 0),
1223 SOC_SINGLE("RX2 HPF Switch", MSM8X10_WCD_A_CDC_RX2_B5_CTL, 2, 1, 0),
1224 SOC_SINGLE("RX3 HPF Switch", MSM8X10_WCD_A_CDC_RX3_B5_CTL, 2, 1, 0),
1225
1226 SOC_ENUM("RX1 HPF cut off", cf_rxmix1_enum),
1227 SOC_ENUM("RX2 HPF cut off", cf_rxmix2_enum),
1228 SOC_ENUM("RX3 HPF cut off", cf_rxmix3_enum),
1229
1230 SOC_SINGLE_EXT("IIR1 Enable Band1", IIR1, BAND1, 1, 0,
1231 msm8x10_wcd_get_iir_enable_audio_mixer,
1232 msm8x10_wcd_put_iir_enable_audio_mixer),
1233 SOC_SINGLE_EXT("IIR1 Enable Band2", IIR1, BAND2, 1, 0,
1234 msm8x10_wcd_get_iir_enable_audio_mixer,
1235 msm8x10_wcd_put_iir_enable_audio_mixer),
1236 SOC_SINGLE_EXT("IIR1 Enable Band3", IIR1, BAND3, 1, 0,
1237 msm8x10_wcd_get_iir_enable_audio_mixer,
1238 msm8x10_wcd_put_iir_enable_audio_mixer),
1239 SOC_SINGLE_EXT("IIR1 Enable Band4", IIR1, BAND4, 1, 0,
1240 msm8x10_wcd_get_iir_enable_audio_mixer,
1241 msm8x10_wcd_put_iir_enable_audio_mixer),
1242 SOC_SINGLE_EXT("IIR1 Enable Band5", IIR1, BAND5, 1, 0,
1243 msm8x10_wcd_get_iir_enable_audio_mixer,
1244 msm8x10_wcd_put_iir_enable_audio_mixer),
1245 SOC_SINGLE_EXT("IIR2 Enable Band1", IIR2, BAND1, 1, 0,
1246 msm8x10_wcd_get_iir_enable_audio_mixer,
1247 msm8x10_wcd_put_iir_enable_audio_mixer),
1248 SOC_SINGLE_EXT("IIR2 Enable Band2", IIR2, BAND2, 1, 0,
1249 msm8x10_wcd_get_iir_enable_audio_mixer,
1250 msm8x10_wcd_put_iir_enable_audio_mixer),
1251 SOC_SINGLE_EXT("IIR2 Enable Band3", IIR2, BAND3, 1, 0,
1252 msm8x10_wcd_get_iir_enable_audio_mixer,
1253 msm8x10_wcd_put_iir_enable_audio_mixer),
1254 SOC_SINGLE_EXT("IIR2 Enable Band4", IIR2, BAND4, 1, 0,
1255 msm8x10_wcd_get_iir_enable_audio_mixer,
1256 msm8x10_wcd_put_iir_enable_audio_mixer),
1257 SOC_SINGLE_EXT("IIR2 Enable Band5", IIR2, BAND5, 1, 0,
1258 msm8x10_wcd_get_iir_enable_audio_mixer,
1259 msm8x10_wcd_put_iir_enable_audio_mixer),
1260
1261 SOC_SINGLE_MULTI_EXT("IIR1 Band1", IIR1, BAND1, 255, 0, 5,
1262 msm8x10_wcd_get_iir_band_audio_mixer,
1263 msm8x10_wcd_put_iir_band_audio_mixer),
1264 SOC_SINGLE_MULTI_EXT("IIR1 Band2", IIR1, BAND2, 255, 0, 5,
1265 msm8x10_wcd_get_iir_band_audio_mixer,
1266 msm8x10_wcd_put_iir_band_audio_mixer),
1267 SOC_SINGLE_MULTI_EXT("IIR1 Band3", IIR1, BAND3, 255, 0, 5,
1268 msm8x10_wcd_get_iir_band_audio_mixer,
1269 msm8x10_wcd_put_iir_band_audio_mixer),
1270 SOC_SINGLE_MULTI_EXT("IIR1 Band4", IIR1, BAND4, 255, 0, 5,
1271 msm8x10_wcd_get_iir_band_audio_mixer,
1272 msm8x10_wcd_put_iir_band_audio_mixer),
1273 SOC_SINGLE_MULTI_EXT("IIR1 Band5", IIR1, BAND5, 255, 0, 5,
1274 msm8x10_wcd_get_iir_band_audio_mixer,
1275 msm8x10_wcd_put_iir_band_audio_mixer),
1276 SOC_SINGLE_MULTI_EXT("IIR2 Band1", IIR2, BAND1, 255, 0, 5,
1277 msm8x10_wcd_get_iir_band_audio_mixer,
1278 msm8x10_wcd_put_iir_band_audio_mixer),
1279 SOC_SINGLE_MULTI_EXT("IIR2 Band2", IIR2, BAND2, 255, 0, 5,
1280 msm8x10_wcd_get_iir_band_audio_mixer,
1281 msm8x10_wcd_put_iir_band_audio_mixer),
1282 SOC_SINGLE_MULTI_EXT("IIR2 Band3", IIR2, BAND3, 255, 0, 5,
1283 msm8x10_wcd_get_iir_band_audio_mixer,
1284 msm8x10_wcd_put_iir_band_audio_mixer),
1285 SOC_SINGLE_MULTI_EXT("IIR2 Band4", IIR2, BAND4, 255, 0, 5,
1286 msm8x10_wcd_get_iir_band_audio_mixer,
1287 msm8x10_wcd_put_iir_band_audio_mixer),
1288 SOC_SINGLE_MULTI_EXT("IIR2 Band5", IIR2, BAND5, 255, 0, 5,
1289 msm8x10_wcd_get_iir_band_audio_mixer,
1290 msm8x10_wcd_put_iir_band_audio_mixer),
1291
1292};
1293
1294static const char * const rx_mix1_text[] = {
1295 "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3"
1296};
1297
1298static const char * const rx_mix2_text[] = {
1299 "ZERO", "IIR1", "IIR2"
1300};
1301
1302static const char * const dec_mux_text[] = {
1303 "ZERO", "ADC1", "ADC2", "DMIC1", "DMIC2"
1304};
1305
Kuirong Wanga0185b12013-07-26 17:49:13 -07001306static const char * const adc2_mux_text[] = {
1307 "ZERO", "INP2", "INP3"
Kuirong Wang265f3592012-12-05 16:17:41 -08001308};
1309
1310static const char * const iir1_inp1_text[] = {
1311 "ZERO", "DEC1", "DEC2", "RX1", "RX2", "RX3"
1312};
1313
Kuirong Wang78468f12013-06-19 01:55:53 -07001314/*
1315 * There is only one bit to select RX2 (0) or RX3 (1) so add 'ZERO' won't
1316 * cause any issue to select the right input, but it eliminates that lineout
1317 * is powered-up when HPH is enabled if the 'ZERO" is used in the disable
1318 * sequence for lineout.
1319 */
1320static const char * const rx_rdac4_text[] = {
1321 "ZERO", "RX3", "RX2"
1322};
1323
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05301324static const char * const rx_rdac3_text[] = {
1325 "RX1", "RX2"
1326};
1327
Kuirong Wang265f3592012-12-05 16:17:41 -08001328static const struct soc_enum rx_mix1_inp1_chain_enum =
1329 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text);
1330
1331static const struct soc_enum rx_mix1_inp2_chain_enum =
1332 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text);
1333
1334static const struct soc_enum rx_mix1_inp3_chain_enum =
1335 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text);
1336
1337static const struct soc_enum rx2_mix1_inp1_chain_enum =
1338 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text);
1339
1340static const struct soc_enum rx2_mix1_inp2_chain_enum =
1341 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text);
1342
1343static const struct soc_enum rx3_mix1_inp1_chain_enum =
1344 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text);
1345
1346static const struct soc_enum rx3_mix1_inp2_chain_enum =
1347 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text);
1348
1349static const struct soc_enum rx1_mix2_inp1_chain_enum =
1350 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text);
1351
1352static const struct soc_enum rx2_mix2_inp1_chain_enum =
1353 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text);
1354
1355static const struct soc_enum dec1_mux_enum =
1356 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 0, 5, dec_mux_text);
1357
1358static const struct soc_enum dec2_mux_enum =
1359 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_TX_B1_CTL, 3, 5, dec_mux_text);
1360
1361static const struct soc_enum iir1_inp1_mux_enum =
1362 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_EQ1_B1_CTL, 0, 6,
1363 iir1_inp1_text);
1364
Kuirong Wang78468f12013-06-19 01:55:53 -07001365static const struct soc_enum rx_rdac4_enum =
1366 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_LO_DAC_CTL, 0, 3,
1367 rx_rdac4_text);
1368
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05301369static const struct soc_enum rx_rdac3_enum =
1370 SOC_ENUM_SINGLE(MSM8X10_WCD_A_CDC_CONN_HPHR_DAC_CTL, 0, 2,
1371 rx_rdac3_text);
1372
Kuirong Wanga0185b12013-07-26 17:49:13 -07001373static const struct soc_enum adc2_enum =
1374 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(adc2_mux_text), adc2_mux_text);
1375
Kuirong Wang265f3592012-12-05 16:17:41 -08001376static const struct snd_kcontrol_new rx_mix1_inp1_mux =
1377 SOC_DAPM_ENUM("RX1 MIX1 INP1 Mux", rx_mix1_inp1_chain_enum);
1378
1379static const struct snd_kcontrol_new rx_mix1_inp2_mux =
1380 SOC_DAPM_ENUM("RX1 MIX1 INP2 Mux", rx_mix1_inp2_chain_enum);
1381
1382static const struct snd_kcontrol_new rx_mix1_inp3_mux =
1383 SOC_DAPM_ENUM("RX1 MIX1 INP3 Mux", rx_mix1_inp3_chain_enum);
1384
1385static const struct snd_kcontrol_new rx2_mix1_inp1_mux =
1386 SOC_DAPM_ENUM("RX2 MIX1 INP1 Mux", rx2_mix1_inp1_chain_enum);
1387
1388static const struct snd_kcontrol_new rx2_mix1_inp2_mux =
1389 SOC_DAPM_ENUM("RX2 MIX1 INP2 Mux", rx2_mix1_inp2_chain_enum);
1390
1391static const struct snd_kcontrol_new rx3_mix1_inp1_mux =
1392 SOC_DAPM_ENUM("RX3 MIX1 INP1 Mux", rx3_mix1_inp1_chain_enum);
1393
1394static const struct snd_kcontrol_new rx3_mix1_inp2_mux =
1395 SOC_DAPM_ENUM("RX3 MIX1 INP2 Mux", rx3_mix1_inp2_chain_enum);
1396
1397static const struct snd_kcontrol_new rx1_mix2_inp1_mux =
1398 SOC_DAPM_ENUM("RX1 MIX2 INP1 Mux", rx1_mix2_inp1_chain_enum);
1399
1400static const struct snd_kcontrol_new rx2_mix2_inp1_mux =
1401 SOC_DAPM_ENUM("RX2 MIX2 INP1 Mux", rx2_mix2_inp1_chain_enum);
1402
Kuirong Wang78468f12013-06-19 01:55:53 -07001403static const struct snd_kcontrol_new rx_dac4_mux =
1404 SOC_DAPM_ENUM("RDAC4 MUX Mux", rx_rdac4_enum);
1405
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05301406static const struct snd_kcontrol_new rx_dac3_mux =
1407 SOC_DAPM_ENUM("RDAC3 MUX Mux", rx_rdac3_enum);
1408
Kuirong Wanga0185b12013-07-26 17:49:13 -07001409static const struct snd_kcontrol_new tx_adc2_mux =
1410 SOC_DAPM_ENUM("ADC2 MUX Mux", adc2_enum);
1411
Kuirong Wang265f3592012-12-05 16:17:41 -08001412static int msm8x10_wcd_put_dec_enum(struct snd_kcontrol *kcontrol,
1413 struct snd_ctl_elem_value *ucontrol)
1414{
1415 struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
1416 struct snd_soc_dapm_widget *w = wlist->widgets[0];
1417 struct snd_soc_codec *codec = w->codec;
1418 struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
1419 unsigned int dec_mux, decimator;
1420 char *dec_name = NULL;
1421 char *widget_name = NULL;
1422 char *temp;
1423 u16 tx_mux_ctl_reg;
1424 u8 adc_dmic_sel = 0x0;
1425 int ret = 0;
1426
1427 if (ucontrol->value.enumerated.item[0] > e->max - 1)
1428 return -EINVAL;
1429
1430 dec_mux = ucontrol->value.enumerated.item[0];
1431
1432 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1433 if (!widget_name)
1434 return -ENOMEM;
1435 temp = widget_name;
1436
1437 dec_name = strsep(&widget_name, " ");
1438 widget_name = temp;
1439 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001440 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1441 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001442 ret = -EINVAL;
1443 goto out;
1444 }
1445
1446 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1447 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001448 dev_err(codec->dev, "%s: Invalid decimator = %s\n",
1449 __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001450 ret = -EINVAL;
1451 goto out;
1452 }
1453
1454 dev_dbg(w->dapm->dev, "%s(): widget = %s decimator = %u dec_mux = %u\n"
1455 , __func__, w->name, decimator, dec_mux);
1456
1457 switch (decimator) {
1458 case 1:
1459 case 2:
Kuirong Wangd75ed012013-08-02 13:43:29 -07001460 if ((dec_mux == 3) || (dec_mux == 4))
1461 adc_dmic_sel = 0x1;
1462 else
1463 adc_dmic_sel = 0x0;
Kuirong Wang265f3592012-12-05 16:17:41 -08001464 break;
1465 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001466 dev_err(codec->dev, "%s: Invalid Decimator = %u\n",
1467 __func__, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001468 ret = -EINVAL;
1469 goto out;
1470 }
1471
1472 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL + 32 * (decimator - 1);
1473
1474 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x1, adc_dmic_sel);
1475
1476 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol);
1477
1478out:
1479 kfree(widget_name);
1480 return ret;
1481}
1482
1483#define MSM8X10_WCD_DEC_ENUM(xname, xenum) \
1484{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
1485 .info = snd_soc_info_enum_double, \
1486 .get = snd_soc_dapm_get_enum_double, \
1487 .put = msm8x10_wcd_put_dec_enum, \
1488 .private_value = (unsigned long)&xenum }
1489
1490static const struct snd_kcontrol_new dec1_mux =
1491 MSM8X10_WCD_DEC_ENUM("DEC1 MUX Mux", dec1_mux_enum);
1492
1493static const struct snd_kcontrol_new dec2_mux =
1494 MSM8X10_WCD_DEC_ENUM("DEC2 MUX Mux", dec2_mux_enum);
1495
1496static const struct snd_kcontrol_new iir1_inp1_mux =
1497 SOC_DAPM_ENUM("IIR1 INP1 Mux", iir1_inp1_mux_enum);
1498
1499static const struct snd_kcontrol_new dac1_switch[] = {
1500 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_EAR_EN, 5, 1, 0)
1501};
1502static const struct snd_kcontrol_new hphl_switch[] = {
1503 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 6, 1, 0)
1504};
1505
Kuirong Wang78468f12013-06-19 01:55:53 -07001506static const struct snd_kcontrol_new spkr_switch[] = {
1507 SOC_DAPM_SINGLE("Switch", MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 2, 1, 0)
1508};
1509
Kuirong Wang265f3592012-12-05 16:17:41 -08001510static void msm8x10_wcd_codec_enable_adc_block(struct snd_soc_codec *codec,
1511 int enable)
1512{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001513 struct msm8x10_wcd_priv *wcd8x10 = snd_soc_codec_get_drvdata(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08001514
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001515 dev_dbg(codec->dev, "%s %d\n", __func__, enable);
Kuirong Wang265f3592012-12-05 16:17:41 -08001516
1517 if (enable) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001518 wcd8x10->adc_count++;
Kuirong Wang265f3592012-12-05 16:17:41 -08001519 snd_soc_update_bits(codec,
1520 MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
1521 0x20, 0x20);
Simmi Pateriyaeba2d5e2013-09-23 13:14:44 +05301522 } else
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001523 wcd8x10->adc_count--;
Kuirong Wang265f3592012-12-05 16:17:41 -08001524}
1525
1526static int msm8x10_wcd_codec_enable_adc(struct snd_soc_dapm_widget *w,
1527 struct snd_kcontrol *kcontrol, int event)
1528{
1529 struct snd_soc_codec *codec = w->codec;
1530 u16 adc_reg;
1531 u8 init_bit_shift;
1532
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001533 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001534 adc_reg = MSM8X10_WCD_A_TX_1_2_TEST_CTL;
1535
1536 if (w->reg == MSM8X10_WCD_A_TX_1_EN)
1537 init_bit_shift = 7;
Kuirong Wanga0185b12013-07-26 17:49:13 -07001538 else if ((w->reg == MSM8X10_WCD_A_TX_2_EN) ||
1539 (w->reg == MSM8X10_WCD_A_TX_3_EN))
Kuirong Wang265f3592012-12-05 16:17:41 -08001540 init_bit_shift = 6;
1541 else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001542 dev_err(codec->dev, "%s: Error, invalid adc register\n",
1543 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001544 return -EINVAL;
1545 }
1546
1547 switch (event) {
1548 case SND_SOC_DAPM_PRE_PMU:
1549 msm8x10_wcd_codec_enable_adc_block(codec, 1);
1550 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift,
1551 1 << init_bit_shift);
Kuirong Wanga0185b12013-07-26 17:49:13 -07001552 usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
Kuirong Wang265f3592012-12-05 16:17:41 -08001553 break;
1554 case SND_SOC_DAPM_POST_PMU:
1555 snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00);
Kuirong Wanga0185b12013-07-26 17:49:13 -07001556 usleep_range(CODEC_DELAY_1_MS, CODEC_DELAY_1_1_MS);
Kuirong Wang265f3592012-12-05 16:17:41 -08001557 break;
1558 case SND_SOC_DAPM_POST_PMD:
1559 msm8x10_wcd_codec_enable_adc_block(codec, 0);
1560 break;
1561 }
1562 return 0;
1563}
1564
1565static int msm8x10_wcd_codec_enable_lineout(struct snd_soc_dapm_widget *w,
1566 struct snd_kcontrol *kcontrol, int event)
1567{
1568 struct snd_soc_codec *codec = w->codec;
1569 u16 lineout_gain_reg;
1570
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001571 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001572
1573 switch (w->shift) {
1574 case 0:
1575 lineout_gain_reg = MSM8X10_WCD_A_RX_LINE_1_GAIN;
1576 break;
1577 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001578 dev_err(codec->dev,
1579 "%s: Error, incorrect lineout register value\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001580 __func__);
1581 return -EINVAL;
1582 }
1583
1584 switch (event) {
1585 case SND_SOC_DAPM_PRE_PMU:
1586 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x40);
1587 break;
1588 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001589 dev_dbg(codec->dev, "%s: sleeping 16 ms after %s PA turn on\n",
1590 __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001591 usleep_range(16000, 16100);
1592 break;
1593 case SND_SOC_DAPM_POST_PMD:
1594 snd_soc_update_bits(codec, lineout_gain_reg, 0x40, 0x00);
1595 break;
1596 }
1597 return 0;
1598}
1599
1600static int msm8x10_wcd_codec_enable_spk_pa(struct snd_soc_dapm_widget *w,
1601 struct snd_kcontrol *kcontrol, int event)
1602{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001603 dev_dbg(w->codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001604 return 0;
1605}
1606
1607static int msm8x10_wcd_codec_enable_dmic(struct snd_soc_dapm_widget *w,
1608 struct snd_kcontrol *kcontrol, int event)
1609{
1610 struct snd_soc_codec *codec = w->codec;
1611 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1612 u8 dmic_clk_en;
1613 u16 dmic_clk_reg;
1614 s32 *dmic_clk_cnt;
1615 unsigned int dmic;
1616 int ret;
1617
1618 ret = kstrtouint(strpbrk(w->name, "12"), 10, &dmic);
1619 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001620 dev_err(codec->dev,
1621 "%s: Invalid DMIC line on the codec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001622 return -EINVAL;
1623 }
1624
1625 switch (dmic) {
1626 case 1:
1627 case 2:
1628 dmic_clk_en = 0x01;
1629 dmic_clk_cnt = &(msm8x10_wcd->dmic_1_2_clk_cnt);
1630 dmic_clk_reg = MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001631 dev_dbg(codec->dev,
1632 "%s() event %d DMIC%d dmic_1_2_clk_cnt %d\n",
Kuirong Wang265f3592012-12-05 16:17:41 -08001633 __func__, event, dmic, *dmic_clk_cnt);
1634 break;
1635 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001636 dev_err(codec->dev, "%s: Invalid DMIC Selection\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001637 return -EINVAL;
1638 }
1639
1640 switch (event) {
1641 case SND_SOC_DAPM_PRE_PMU:
1642
1643 (*dmic_clk_cnt)++;
1644 if (*dmic_clk_cnt == 1)
1645 snd_soc_update_bits(codec, dmic_clk_reg,
1646 dmic_clk_en, dmic_clk_en);
1647 break;
1648 case SND_SOC_DAPM_POST_PMD:
1649
1650 (*dmic_clk_cnt)--;
1651 if (*dmic_clk_cnt == 0)
1652 snd_soc_update_bits(codec, dmic_clk_reg,
1653 dmic_clk_en, 0);
1654 break;
1655 }
1656 return 0;
1657}
1658
1659static int msm8x10_wcd_codec_enable_micbias(struct snd_soc_dapm_widget *w,
1660 struct snd_kcontrol *kcontrol, int event)
1661{
1662 struct snd_soc_codec *codec = w->codec;
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001663 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08001664 u16 micb_int_reg;
Kuirong Wang265f3592012-12-05 16:17:41 -08001665 char *internal1_text = "Internal1";
1666 char *internal2_text = "Internal2";
1667 char *internal3_text = "Internal3";
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001668 enum wcd9xxx_notify_event e_post_off, e_pre_on, e_post_on;
Kuirong Wang265f3592012-12-05 16:17:41 -08001669
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001670 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001671 switch (w->reg) {
1672 case MSM8X10_WCD_A_MICB_1_CTL:
1673 micb_int_reg = MSM8X10_WCD_A_MICB_1_INT_RBIAS;
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001674 e_pre_on = WCD9XXX_EVENT_PRE_MICBIAS_1_ON;
1675 e_post_on = WCD9XXX_EVENT_POST_MICBIAS_1_ON;
1676 e_post_off = WCD9XXX_EVENT_POST_MICBIAS_1_OFF;
Kuirong Wang265f3592012-12-05 16:17:41 -08001677 break;
1678 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001679 dev_err(codec->dev,
Kuirong Wang91e52532013-03-31 14:24:22 -07001680 "%s: Error, invalid micbias register 0x%x\n",
1681 __func__, w->reg);
Kuirong Wang265f3592012-12-05 16:17:41 -08001682 return -EINVAL;
1683 }
1684
1685 switch (event) {
1686 case SND_SOC_DAPM_PRE_PMU:
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001687 /* Let MBHC module know micbias is about to turn ON */
1688 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
1689
Kuirong Wang265f3592012-12-05 16:17:41 -08001690 if (strnstr(w->name, internal1_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001691 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x80);
Kuirong Wang265f3592012-12-05 16:17:41 -08001692 else if (strnstr(w->name, internal2_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001693 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08001694 else if (strnstr(w->name, internal3_text, 30))
Kuirong Wang91e52532013-03-31 14:24:22 -07001695 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x2);
Bhalchandra Gajare76fcfc62013-09-23 17:30:48 -07001696
1697 /* Always pull up TxFe for TX2 to Micbias */
1698 snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x04);
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05301699 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
1700 0x80, 0x80);
Simmi Pateriya1cc09012014-01-21 17:58:11 +05301701 msm8x10_wcd->micb_en_count++;
1702 pr_debug("%s micb_en_count : %d", __func__,
1703 msm8x10_wcd->micb_en_count);
Kuirong Wang265f3592012-12-05 16:17:41 -08001704 break;
1705 case SND_SOC_DAPM_POST_PMU:
1706 usleep_range(20000, 20100);
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001707 /* Let MBHC module know so micbias is on */
1708 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_on);
Kuirong Wang265f3592012-12-05 16:17:41 -08001709 break;
1710 case SND_SOC_DAPM_POST_PMD:
Simmi Pateriya1cc09012014-01-21 17:58:11 +05301711 if (msm8x10_wcd->micb_en_count > 0)
1712 msm8x10_wcd->micb_en_count--;
1713 pr_debug("%s micb_en_count : %d", __func__,
1714 msm8x10_wcd->micb_en_count);
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05301715 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL,
1716 0x80, 0x00);
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07001717 /* Let MBHC module know so micbias switch to be off */
1718 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
1719
Kuirong Wang265f3592012-12-05 16:17:41 -08001720 if (strnstr(w->name, internal1_text, 30))
1721 snd_soc_update_bits(codec, micb_int_reg, 0x80, 0x00);
1722 else if (strnstr(w->name, internal2_text, 30))
1723 snd_soc_update_bits(codec, micb_int_reg, 0x10, 0x00);
1724 else if (strnstr(w->name, internal3_text, 30))
1725 snd_soc_update_bits(codec, micb_int_reg, 0x2, 0x0);
1726
Bhalchandra Gajare76fcfc62013-09-23 17:30:48 -07001727 /* Disable pull up TxFe for TX2 to Micbias */
1728 snd_soc_update_bits(codec, micb_int_reg, 0x04, 0x00);
Kuirong Wang265f3592012-12-05 16:17:41 -08001729 break;
1730 }
Kuirong Wang265f3592012-12-05 16:17:41 -08001731 return 0;
1732}
1733
Kuirong Wang91e52532013-03-31 14:24:22 -07001734static void tx_hpf_corner_freq_callback(struct work_struct *work)
1735{
1736 struct delayed_work *hpf_delayed_work;
1737 struct hpf_work *hpf_work;
1738 struct msm8x10_wcd_priv *msm8x10_wcd;
1739 struct snd_soc_codec *codec;
1740 u16 tx_mux_ctl_reg;
1741 u8 hpf_cut_of_freq;
1742
1743 hpf_delayed_work = to_delayed_work(work);
1744 hpf_work = container_of(hpf_delayed_work, struct hpf_work, dwork);
1745 msm8x10_wcd = hpf_work->msm8x10_wcd;
1746 codec = hpf_work->msm8x10_wcd->codec;
1747 hpf_cut_of_freq = hpf_work->tx_hpf_cut_of_freq;
1748
1749 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1750 (hpf_work->decimator - 1) * 32;
1751
1752 dev_info(codec->dev, "%s(): decimator %u hpf_cut_of_freq 0x%x\n",
1753 __func__, hpf_work->decimator, (unsigned int)hpf_cut_of_freq);
1754
1755 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30, hpf_cut_of_freq << 4);
1756}
1757
1758
Kuirong Wang265f3592012-12-05 16:17:41 -08001759#define TX_MUX_CTL_CUT_OFF_FREQ_MASK 0x30
1760#define CF_MIN_3DB_4HZ 0x0
1761#define CF_MIN_3DB_75HZ 0x1
1762#define CF_MIN_3DB_150HZ 0x2
1763
1764static int msm8x10_wcd_codec_enable_dec(struct snd_soc_dapm_widget *w,
1765 struct snd_kcontrol *kcontrol, int event)
1766{
1767 struct snd_soc_codec *codec = w->codec;
1768 unsigned int decimator;
1769 char *dec_name = NULL;
1770 char *widget_name = NULL;
1771 char *temp;
1772 int ret = 0;
1773 u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg;
1774 u8 dec_hpf_cut_of_freq;
1775 int offset;
1776
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001777 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001778
1779 widget_name = kstrndup(w->name, 15, GFP_KERNEL);
1780 if (!widget_name)
1781 return -ENOMEM;
1782 temp = widget_name;
1783
1784 dec_name = strsep(&widget_name, " ");
1785 widget_name = temp;
1786 if (!dec_name) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001787 dev_err(codec->dev,
1788 "%s: Invalid decimator = %s\n", __func__, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001789 ret = -EINVAL;
1790 goto out;
1791 }
1792
1793 ret = kstrtouint(strpbrk(dec_name, "12"), 10, &decimator);
1794 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001795 dev_err(codec->dev,
1796 "%s: Invalid decimator = %s\n", __func__, dec_name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001797 ret = -EINVAL;
1798 goto out;
1799 }
1800
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001801 dev_dbg(codec->dev,
1802 "%s(): widget = %s dec_name = %s decimator = %u\n", __func__,
1803 w->name, dec_name, decimator);
Kuirong Wang265f3592012-12-05 16:17:41 -08001804
1805 if (w->reg == MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL) {
1806 dec_reset_reg = MSM8X10_WCD_A_CDC_CLK_TX_RESET_B1_CTL;
1807 offset = 0;
1808 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001809 dev_err(codec->dev, "%s: Error, incorrect dec\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08001810 ret = -EINVAL;
1811 goto out;
1812 }
1813
1814 tx_vol_ctl_reg = MSM8X10_WCD_A_CDC_TX1_VOL_CTL_CFG +
1815 32 * (decimator - 1);
1816 tx_mux_ctl_reg = MSM8X10_WCD_A_CDC_TX1_MUX_CTL +
1817 32 * (decimator - 1);
1818
1819 switch (event) {
1820 case SND_SOC_DAPM_PRE_PMU:
1821 /* Enableable TX digital mute */
1822 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1823
1824 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift,
1825 1 << w->shift);
1826 snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0);
1827
1828 dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg);
1829
1830 dec_hpf_cut_of_freq = (dec_hpf_cut_of_freq & 0x30) >> 4;
1831
1832 tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq =
1833 dec_hpf_cut_of_freq;
1834
1835 if ((dec_hpf_cut_of_freq != CF_MIN_3DB_150HZ)) {
1836
1837 /* set cut of freq to CF_MIN_3DB_150HZ (0x1); */
1838 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1839 CF_MIN_3DB_150HZ << 4);
1840 }
1841
1842 /* enable HPF */
1843 snd_soc_update_bits(codec, tx_mux_ctl_reg , 0x08, 0x00);
1844 break;
1845 case SND_SOC_DAPM_POST_PMU:
1846 /* Disable TX digital mute */
1847 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x00);
1848
1849 if (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq !=
1850 CF_MIN_3DB_150HZ) {
1851
1852 schedule_delayed_work(&tx_hpf_work[decimator - 1].dwork,
1853 msecs_to_jiffies(300));
1854 }
1855 /* apply the digital gain after the decimator is enabled*/
1856 if ((w->shift) < ARRAY_SIZE(tx_digital_gain_reg))
1857 snd_soc_write(codec,
1858 tx_digital_gain_reg[w->shift + offset],
1859 snd_soc_read(codec,
1860 tx_digital_gain_reg[w->shift + offset])
1861 );
1862 break;
1863 case SND_SOC_DAPM_PRE_PMD:
1864 snd_soc_update_bits(codec, tx_vol_ctl_reg, 0x01, 0x01);
1865 cancel_delayed_work_sync(&tx_hpf_work[decimator - 1].dwork);
1866 break;
1867 case SND_SOC_DAPM_POST_PMD:
1868 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x08, 0x08);
1869 snd_soc_update_bits(codec, tx_mux_ctl_reg, 0x30,
1870 (tx_hpf_work[decimator - 1].tx_hpf_cut_of_freq) << 4);
1871 break;
1872 }
1873out:
1874 kfree(widget_name);
1875 return ret;
1876}
1877
1878static int msm8x10_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w,
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001879 struct snd_kcontrol *kcontrol,
1880 int event)
Kuirong Wang265f3592012-12-05 16:17:41 -08001881{
1882 struct snd_soc_codec *codec = w->codec;
1883
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001884 dev_dbg(codec->dev, "%s %d %s\n", __func__, event, w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001885
1886 switch (event) {
1887 case SND_SOC_DAPM_PRE_PMU:
1888 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1889 1 << w->shift, 1 << w->shift);
1890 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_CLK_RX_RESET_CTL,
1891 1 << w->shift, 0x0);
1892 break;
1893 case SND_SOC_DAPM_POST_PMU:
1894 /* apply the digital gain after the interpolator is enabled*/
1895 if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg))
1896 snd_soc_write(codec,
1897 rx_digital_gain_reg[w->shift],
1898 snd_soc_read(codec,
1899 rx_digital_gain_reg[w->shift])
1900 );
1901 break;
1902 }
1903 return 0;
1904}
1905
1906
1907/* The register address is the same as other codec so it can use resmgr */
1908static int msm8x10_wcd_codec_enable_rx_bias(struct snd_soc_dapm_widget *w,
1909 struct snd_kcontrol *kcontrol, int event)
1910{
1911 struct snd_soc_codec *codec = w->codec;
1912 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Kuirong Wang91e52532013-03-31 14:24:22 -07001913 msm8x10_wcd->resmgr.codec = codec;
Kuirong Wang265f3592012-12-05 16:17:41 -08001914
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001915 dev_dbg(codec->dev, "%s %d\n", __func__, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001916
1917 switch (event) {
1918 case SND_SOC_DAPM_PRE_PMU:
1919 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 1);
1920 break;
1921 case SND_SOC_DAPM_POST_PMD:
1922 wcd9xxx_resmgr_enable_rx_bias(&msm8x10_wcd->resmgr, 0);
1923 break;
1924 }
1925 return 0;
1926}
1927
1928static int msm8x10_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w,
1929 struct snd_kcontrol *kcontrol, int event)
1930{
1931 struct snd_soc_codec *codec = w->codec;
1932
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001933 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001934
1935 switch (event) {
1936 case SND_SOC_DAPM_PRE_PMU:
1937 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1938 break;
1939 case SND_SOC_DAPM_POST_PMD:
1940 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
1941 break;
1942 }
1943 return 0;
1944}
1945
1946static int msm8x10_wcd_hph_pa_event(struct snd_soc_dapm_widget *w,
1947 struct snd_kcontrol *kcontrol, int event)
1948{
1949 struct snd_soc_codec *codec = w->codec;
1950 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
1951 enum wcd9xxx_notify_event e_pre_on, e_post_off;
1952
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001953 dev_dbg(codec->dev, "%s: %s event = %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001954 if (w->shift == 5) {
1955 e_pre_on = WCD9XXX_EVENT_PRE_HPHR_PA_ON;
1956 e_post_off = WCD9XXX_EVENT_POST_HPHR_PA_OFF;
1957 } else if (w->shift == 4) {
1958 e_pre_on = WCD9XXX_EVENT_PRE_HPHL_PA_ON;
1959 e_post_off = WCD9XXX_EVENT_POST_HPHL_PA_OFF;
1960 } else {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001961 dev_err(codec->dev,
1962 "%s: Invalid w->shift %d\n", __func__, w->shift);
Kuirong Wang265f3592012-12-05 16:17:41 -08001963 return -EINVAL;
1964 }
1965
1966 switch (event) {
1967 case SND_SOC_DAPM_PRE_PMU:
1968 /* Let MBHC module know PA is turning on */
1969 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_pre_on);
1970 break;
1971
1972 case SND_SOC_DAPM_POST_PMU:
1973 usleep_range(10000, 10100);
1974 break;
1975
1976 case SND_SOC_DAPM_POST_PMD:
1977 /* Let MBHC module know PA turned off */
1978 wcd9xxx_resmgr_notifier_call(&msm8x10_wcd->resmgr, e_post_off);
1979
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001980 dev_dbg(codec->dev,
1981 "%s: sleep 10 ms after %s PA disable.\n", __func__,
1982 w->name);
Kuirong Wang265f3592012-12-05 16:17:41 -08001983 usleep_range(10000, 10100);
1984 break;
1985 }
1986 return 0;
1987}
1988
1989static int msm8x10_wcd_lineout_dac_event(struct snd_soc_dapm_widget *w,
1990 struct snd_kcontrol *kcontrol, int event)
1991{
1992 struct snd_soc_codec *codec = w->codec;
1993
Kuirong Wang3a6408d2013-02-20 17:46:46 -08001994 dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event);
Kuirong Wang265f3592012-12-05 16:17:41 -08001995
1996 switch (event) {
1997 case SND_SOC_DAPM_PRE_PMU:
1998 snd_soc_update_bits(codec, w->reg, 0x40, 0x40);
1999 break;
2000
2001 case SND_SOC_DAPM_POST_PMD:
2002 snd_soc_update_bits(codec, w->reg, 0x40, 0x00);
2003 break;
2004 }
2005 return 0;
2006}
2007
Kuirong Wang265f3592012-12-05 16:17:41 -08002008static const struct snd_soc_dapm_route audio_map[] = {
2009 {"RX_I2S_CLK", NULL, "CDC_CONN"},
2010 {"I2S RX1", NULL, "RX_I2S_CLK"},
2011 {"I2S RX2", NULL, "RX_I2S_CLK"},
2012 {"I2S RX3", NULL, "RX_I2S_CLK"},
2013
2014 {"I2S TX1", NULL, "TX_I2S_CLK"},
2015 {"I2S TX2", NULL, "TX_I2S_CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002016
Kuirong Wang91e52532013-03-31 14:24:22 -07002017 {"I2S TX1", NULL, "DEC1 MUX"},
2018 {"I2S TX2", NULL, "DEC2 MUX"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002019
2020 /* Earpiece (RX MIX1) */
2021 {"EAR", NULL, "EAR PA"},
2022 {"EAR PA", NULL, "DAC1"},
2023 {"DAC1", NULL, "CP"},
2024
Kuirong Wang1261b1d2013-08-06 18:18:21 -07002025 /* Clocks for playback path */
2026 {"DAC1", NULL, "EAR CLK"},
2027 {"HPHL DAC", NULL, "HPHL CLK"},
2028 {"HPHR DAC", NULL, "HPHR CLK"},
2029 {"SPK DAC", NULL, "SPK CLK"},
2030 {"LINEOUT DAC", NULL, "LINEOUT CLK"},
2031
Kuirong Wang265f3592012-12-05 16:17:41 -08002032 /* Headset (RX MIX1 and RX MIX2) */
2033 {"HEADPHONE", NULL, "HPHL"},
2034 {"HEADPHONE", NULL, "HPHR"},
2035
2036 {"HPHL", NULL, "HPHL DAC"},
2037
2038 {"HPHR", NULL, "HPHR DAC"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002039
2040 {"HPHL DAC", NULL, "CP"},
2041
2042 {"HPHR DAC", NULL, "CP"},
Kuirong Wang91e52532013-03-31 14:24:22 -07002043 {"SPK DAC", NULL, "CP"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002044
2045 {"DAC1", "Switch", "RX1 CHAIN"},
2046 {"HPHL DAC", "Switch", "RX1 CHAIN"},
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05302047 {"HPHR DAC", NULL, "RDAC3 MUX"},
2048
2049 {"RDAC3 MUX", "RX1", "RX1 CHAIN"},
2050 {"RDAC3 MUX", "RX2", "RX2 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002051
Kuirong Wang91e52532013-03-31 14:24:22 -07002052 {"LINEOUT", NULL, "LINEOUT PA"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002053 {"SPK_OUT", NULL, "SPK PA"},
2054
Kuirong Wang91e52532013-03-31 14:24:22 -07002055 {"LINEOUT PA", NULL, "CP"},
2056 {"LINEOUT PA", NULL, "LINEOUT DAC"},
Kuirong Wang78468f12013-06-19 01:55:53 -07002057 {"LINEOUT DAC", NULL, "RDAC4 MUX"},
2058
2059 {"RDAC4 MUX", "RX2", "RX2 CHAIN"},
2060 {"RDAC4 MUX", "RX3", "RX3 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002061
Kuirong Wang49f506a2013-05-22 17:38:26 -07002062 {"CP", NULL, "CP_REGULATOR"},
Kuirong Wang91e52532013-03-31 14:24:22 -07002063 {"CP", NULL, "RX_BIAS"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002064 {"SPK PA", NULL, "SPK DAC"},
Kuirong Wang78468f12013-06-19 01:55:53 -07002065 {"SPK DAC", "Switch", "RX3 CHAIN"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002066
Kuirong Wang91e52532013-03-31 14:24:22 -07002067 {"RX1 CHAIN", NULL, "RX1 CLK"},
2068 {"RX2 CHAIN", NULL, "RX2 CLK"},
2069 {"RX3 CHAIN", NULL, "RX3 CLK"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002070 {"RX1 CHAIN", NULL, "RX1 MIX2"},
2071 {"RX2 CHAIN", NULL, "RX2 MIX2"},
Kuirong Wang91e52532013-03-31 14:24:22 -07002072 {"RX3 CHAIN", NULL, "RX3 MIX1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002073
2074 {"RX1 MIX1", NULL, "RX1 MIX1 INP1"},
2075 {"RX1 MIX1", NULL, "RX1 MIX1 INP2"},
2076 {"RX1 MIX1", NULL, "RX1 MIX1 INP3"},
2077 {"RX2 MIX1", NULL, "RX2 MIX1 INP1"},
2078 {"RX2 MIX1", NULL, "RX2 MIX1 INP2"},
2079 {"RX3 MIX1", NULL, "RX3 MIX1 INP1"},
2080 {"RX3 MIX1", NULL, "RX3 MIX1 INP2"},
2081 {"RX1 MIX2", NULL, "RX1 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07002082 {"RX1 MIX2", NULL, "RX1 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002083 {"RX2 MIX2", NULL, "RX2 MIX1"},
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07002084 {"RX2 MIX2", NULL, "RX2 MIX2 INP1"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002085
2086 {"RX1 MIX1 INP1", "RX1", "I2S RX1"},
2087 {"RX1 MIX1 INP1", "RX2", "I2S RX2"},
2088 {"RX1 MIX1 INP1", "RX3", "I2S RX3"},
2089 {"RX1 MIX1 INP1", "IIR1", "IIR1"},
2090 {"RX1 MIX1 INP2", "RX1", "I2S RX1"},
2091 {"RX1 MIX1 INP2", "RX2", "I2S RX2"},
2092 {"RX1 MIX1 INP2", "RX3", "I2S RX3"},
2093 {"RX1 MIX1 INP2", "IIR1", "IIR1"},
2094 {"RX1 MIX1 INP3", "RX1", "I2S RX1"},
2095 {"RX1 MIX1 INP3", "RX2", "I2S RX2"},
2096 {"RX1 MIX1 INP3", "RX3", "I2S RX3"},
2097
2098 {"RX2 MIX1 INP1", "RX1", "I2S RX1"},
2099 {"RX2 MIX1 INP1", "RX2", "I2S RX2"},
2100 {"RX2 MIX1 INP1", "RX3", "I2S RX3"},
2101 {"RX2 MIX1 INP1", "IIR1", "IIR1"},
2102 {"RX2 MIX1 INP2", "RX1", "I2S RX1"},
2103 {"RX2 MIX1 INP2", "RX2", "I2S RX2"},
2104 {"RX2 MIX1 INP2", "RX3", "I2S RX3"},
2105 {"RX2 MIX1 INP2", "IIR1", "IIR1"},
2106
2107 {"RX3 MIX1 INP1", "RX1", "I2S RX1"},
2108 {"RX3 MIX1 INP1", "RX2", "I2S RX2"},
2109 {"RX3 MIX1 INP1", "RX3", "I2S RX3"},
2110 {"RX3 MIX1 INP1", "IIR1", "IIR1"},
2111 {"RX3 MIX1 INP2", "RX1", "I2S RX1"},
2112 {"RX3 MIX1 INP2", "RX2", "I2S RX2"},
2113 {"RX3 MIX1 INP2", "RX3", "I2S RX3"},
2114 {"RX3 MIX1 INP2", "IIR1", "IIR1"},
2115
Phani Kumar Uppalapati88b01c02013-05-29 20:58:48 -07002116 {"RX1 MIX2 INP1", "IIR1", "IIR1"},
2117 {"RX2 MIX2 INP1", "IIR1", "IIR1"},
2118
Kuirong Wang265f3592012-12-05 16:17:41 -08002119 /* Decimator Inputs */
2120 {"DEC1 MUX", "DMIC1", "DMIC1"},
2121 {"DEC1 MUX", "DMIC2", "DMIC2"},
2122 {"DEC1 MUX", "ADC1", "ADC1"},
2123 {"DEC1 MUX", "ADC2", "ADC2"},
2124 {"DEC1 MUX", NULL, "CDC_CONN"},
2125
2126 {"DEC2 MUX", "DMIC1", "DMIC1"},
2127 {"DEC2 MUX", "DMIC2", "DMIC2"},
2128 {"DEC2 MUX", "ADC1", "ADC1"},
2129 {"DEC2 MUX", "ADC2", "ADC2"},
2130 {"DEC2 MUX", NULL, "CDC_CONN"},
2131
Kuirong Wanga0185b12013-07-26 17:49:13 -07002132 {"ADC2", NULL, "ADC2 MUX"},
2133 {"ADC2 MUX", "INP2", "ADC2_INP2"},
2134 {"ADC2 MUX", "INP3", "ADC2_INP3"},
2135
Kuirong Wang265f3592012-12-05 16:17:41 -08002136 /* ADC Connections */
2137 {"ADC1", NULL, "AMIC1"},
Kuirong Wanga0185b12013-07-26 17:49:13 -07002138 {"ADC2_INP2", NULL, "AMIC2"},
2139 {"ADC2_INP3", NULL, "AMIC3"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002140
2141 {"IIR1", NULL, "IIR1 INP1 MUX"},
2142 {"IIR1 INP1 MUX", "DEC1", "DEC1 MUX"},
2143 {"IIR1 INP1 MUX", "DEC2", "DEC2 MUX"},
quic_yandongy7424f1a2013-05-16 22:41:33 +08002144 {"MIC BIAS Internal1", NULL, "INT_LDO_H"},
Kuirong Wang91e52532013-03-31 14:24:22 -07002145 {"MIC BIAS Internal2", NULL, "INT_LDO_H"},
2146 {"MIC BIAS External", NULL, "INT_LDO_H"},
Kuirong Wang49f506a2013-05-22 17:38:26 -07002147 {"MIC BIAS Internal1", NULL, "MICBIAS_REGULATOR"},
2148 {"MIC BIAS Internal2", NULL, "MICBIAS_REGULATOR"},
2149 {"MIC BIAS External", NULL, "MICBIAS_REGULATOR"},
Kuirong Wang265f3592012-12-05 16:17:41 -08002150};
2151
Kuirong Wang265f3592012-12-05 16:17:41 -08002152static int msm8x10_wcd_startup(struct snd_pcm_substream *substream,
2153 struct snd_soc_dai *dai)
2154{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002155 dev_dbg(dai->codec->dev, "%s(): substream = %s stream = %d\n",
2156 __func__,
2157 substream->name, substream->stream);
Kuirong Wang265f3592012-12-05 16:17:41 -08002158 return 0;
2159}
2160
2161static void msm8x10_wcd_shutdown(struct snd_pcm_substream *substream,
2162 struct snd_soc_dai *dai)
2163{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002164 dev_dbg(dai->codec->dev,
2165 "%s(): substream = %s stream = %d\n" , __func__,
2166 substream->name, substream->stream);
Kuirong Wang91e52532013-03-31 14:24:22 -07002167}
2168
Kuirong Wang265f3592012-12-05 16:17:41 -08002169int msm8x10_wcd_mclk_enable(struct snd_soc_codec *codec,
2170 int mclk_enable, bool dapm)
2171{
2172 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
2173
Kuirong Wang91e52532013-03-31 14:24:22 -07002174 dev_dbg(codec->dev, "%s: mclk_enable = %u, dapm = %d\n",
2175 __func__, mclk_enable, dapm);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002176
2177 WCD9XXX_BG_CLK_LOCK(&msm8x10_wcd->resmgr);
2178
Kuirong Wang265f3592012-12-05 16:17:41 -08002179 if (mclk_enable) {
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002180 wcd9xxx_resmgr_get_bandgap(&msm8x10_wcd->resmgr,
2181 WCD9XXX_BANDGAP_AUDIO_MODE);
2182 wcd9xxx_resmgr_get_clk_block(&msm8x10_wcd->resmgr,
2183 WCD9XXX_CLK_MCLK);
Kuirong Wang265f3592012-12-05 16:17:41 -08002184 } else {
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002185 wcd9xxx_resmgr_put_clk_block(&msm8x10_wcd->resmgr,
2186 WCD9XXX_CLK_MCLK);
2187 wcd9xxx_resmgr_put_bandgap(&msm8x10_wcd->resmgr,
2188 WCD9XXX_BANDGAP_AUDIO_MODE);
Kuirong Wang265f3592012-12-05 16:17:41 -08002189 }
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002190 WCD9XXX_BG_CLK_UNLOCK(&msm8x10_wcd->resmgr);
Kuirong Wang265f3592012-12-05 16:17:41 -08002191 return 0;
2192}
2193
2194static int msm8x10_wcd_set_dai_sysclk(struct snd_soc_dai *dai,
2195 int clk_id, unsigned int freq, int dir)
2196{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002197 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002198 return 0;
2199}
2200
2201static int msm8x10_wcd_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
2202{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002203 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002204 return 0;
2205}
2206
2207static int msm8x10_wcd_set_channel_map(struct snd_soc_dai *dai,
2208 unsigned int tx_num, unsigned int *tx_slot,
2209 unsigned int rx_num, unsigned int *rx_slot)
2210
2211{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002212 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002213 return 0;
2214}
2215
2216static int msm8x10_wcd_get_channel_map(struct snd_soc_dai *dai,
2217 unsigned int *tx_num, unsigned int *tx_slot,
2218 unsigned int *rx_num, unsigned int *rx_slot)
2219
2220{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002221 dev_dbg(dai->codec->dev, "%s\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002222 return 0;
2223}
2224
2225static int msm8x10_wcd_set_interpolator_rate(struct snd_soc_dai *dai,
2226 u8 rx_fs_rate_reg_val, u32 sample_rate)
2227{
2228 return 0;
2229}
2230
2231static int msm8x10_wcd_set_decimator_rate(struct snd_soc_dai *dai,
2232 u8 tx_fs_rate_reg_val, u32 sample_rate)
2233{
2234 return 0;
2235}
2236
2237static int msm8x10_wcd_hw_params(struct snd_pcm_substream *substream,
2238 struct snd_pcm_hw_params *params,
2239 struct snd_soc_dai *dai)
2240{
2241 u8 tx_fs_rate, rx_fs_rate;
2242 int ret;
2243
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002244 dev_dbg(dai->codec->dev,
2245 "%s: dai_name = %s DAI-ID %x rate %d num_ch %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002246 dai->name, dai->id, params_rate(params),
2247 params_channels(params));
2248
2249 switch (params_rate(params)) {
2250 case 8000:
2251 tx_fs_rate = 0x00;
2252 rx_fs_rate = 0x00;
2253 break;
2254 case 16000:
2255 tx_fs_rate = 0x01;
2256 rx_fs_rate = 0x20;
2257 break;
2258 case 32000:
2259 tx_fs_rate = 0x02;
2260 rx_fs_rate = 0x40;
2261 break;
2262 case 48000:
2263 tx_fs_rate = 0x03;
2264 rx_fs_rate = 0x60;
2265 break;
2266 case 96000:
2267 tx_fs_rate = 0x04;
2268 rx_fs_rate = 0x80;
2269 break;
2270 case 192000:
2271 tx_fs_rate = 0x05;
2272 rx_fs_rate = 0xA0;
2273 break;
2274 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002275 dev_err(dai->codec->dev,
2276 "%s: Invalid sampling rate %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002277 params_rate(params));
2278 return -EINVAL;
2279 }
2280
2281 switch (substream->stream) {
2282 case SNDRV_PCM_STREAM_CAPTURE:
2283 ret = msm8x10_wcd_set_decimator_rate(dai, tx_fs_rate,
2284 params_rate(params));
2285 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002286 dev_err(dai->codec->dev,
2287 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002288 ret);
2289 return ret;
2290 }
2291 break;
2292 case SNDRV_PCM_STREAM_PLAYBACK:
2293 ret = msm8x10_wcd_set_interpolator_rate(dai, rx_fs_rate,
2294 params_rate(params));
2295 if (ret < 0) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002296 dev_err(dai->codec->dev,
2297 "%s: set decimator rate failed %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002298 ret);
2299 return ret;
2300 }
2301 break;
2302 default:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002303 dev_err(dai->codec->dev,
2304 "%s: Invalid stream type %d\n", __func__,
Kuirong Wang265f3592012-12-05 16:17:41 -08002305 substream->stream);
2306 return -EINVAL;
2307 }
2308
2309 return 0;
2310}
2311
2312static struct snd_soc_dai_ops msm8x10_wcd_dai_ops = {
2313 .startup = msm8x10_wcd_startup,
2314 .shutdown = msm8x10_wcd_shutdown,
2315 .hw_params = msm8x10_wcd_hw_params,
2316 .set_sysclk = msm8x10_wcd_set_dai_sysclk,
2317 .set_fmt = msm8x10_wcd_set_dai_fmt,
2318 .set_channel_map = msm8x10_wcd_set_channel_map,
2319 .get_channel_map = msm8x10_wcd_get_channel_map,
2320};
2321
2322static struct snd_soc_dai_driver msm8x10_wcd_i2s_dai[] = {
2323 {
2324 .name = "msm8x10_wcd_i2s_rx1",
2325 .id = AIF1_PB,
2326 .playback = {
2327 .stream_name = "AIF1 Playback",
2328 .rates = MSM8X10_WCD_RATES,
2329 .formats = MSM8X10_WCD_FORMATS,
2330 .rate_max = 192000,
2331 .rate_min = 8000,
2332 .channels_min = 1,
Kuirong Wang91e52532013-03-31 14:24:22 -07002333 .channels_max = 3,
Kuirong Wang265f3592012-12-05 16:17:41 -08002334 },
2335 .ops = &msm8x10_wcd_dai_ops,
2336 },
2337 {
2338 .name = "msm8x10_wcd_i2s_tx1",
2339 .id = AIF1_CAP,
2340 .capture = {
2341 .stream_name = "AIF1 Capture",
2342 .rates = MSM8X10_WCD_RATES,
2343 .formats = MSM8X10_WCD_FORMATS,
2344 .rate_max = 192000,
2345 .rate_min = 8000,
2346 .channels_min = 1,
2347 .channels_max = 4,
2348 },
2349 .ops = &msm8x10_wcd_dai_ops,
2350 },
2351};
2352
2353static int msm8x10_wcd_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
2354 struct snd_kcontrol *kcontrol, int event)
2355{
2356 switch (event) {
2357 case SND_SOC_DAPM_POST_PMU:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002358 dev_dbg(w->codec->dev,
2359 "%s: Sleeping 20ms after enabling EAR PA\n",
2360 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002361 msleep(20);
2362 break;
2363 case SND_SOC_DAPM_POST_PMD:
Kuirong Wang3a6408d2013-02-20 17:46:46 -08002364 dev_dbg(w->codec->dev,
2365 "%s: Sleeping 20ms after disabling EAR PA\n",
2366 __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08002367 msleep(20);
2368 break;
2369 }
2370 return 0;
2371}
2372
2373static const struct snd_soc_dapm_widget msm8x10_wcd_dapm_widgets[] = {
2374 /*RX stuff */
2375 SND_SOC_DAPM_OUTPUT("EAR"),
2376
2377 SND_SOC_DAPM_PGA_E("EAR PA", MSM8X10_WCD_A_RX_EAR_EN, 4, 0, NULL, 0,
Walter Yang4e09ad52013-12-23 10:53:20 +08002378 msm8x10_wcd_codec_enable_ear_pa,
2379 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wang265f3592012-12-05 16:17:41 -08002380
2381 SND_SOC_DAPM_MIXER("DAC1", MSM8X10_WCD_A_RX_EAR_EN, 6, 0, dac1_switch,
2382 ARRAY_SIZE(dac1_switch)),
2383
Kuirong Wang91e52532013-03-31 14:24:22 -07002384 SND_SOC_DAPM_AIF_IN("I2S RX1", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002385
Kuirong Wang91e52532013-03-31 14:24:22 -07002386 SND_SOC_DAPM_AIF_IN("I2S RX2", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002387
Kuirong Wang91e52532013-03-31 14:24:22 -07002388 SND_SOC_DAPM_AIF_IN("I2S RX3", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002389
Kuirong Wang91e52532013-03-31 14:24:22 -07002390 SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0),
2391
Kuirong Wang265f3592012-12-05 16:17:41 -08002392 SND_SOC_DAPM_OUTPUT("HEADPHONE"),
2393 SND_SOC_DAPM_PGA_E("HPHL", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2394 5, 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 SND_SOC_DAPM_MIXER("HPHL DAC", MSM8X10_WCD_A_RX_HPH_L_DAC_CTL,
2398 7, 0,
2399 hphl_switch, ARRAY_SIZE(hphl_switch)),
2400
2401 SND_SOC_DAPM_PGA_E("HPHR", MSM8X10_WCD_A_RX_HPH_CNP_EN,
2402 4, 0, NULL, 0,
2403 msm8x10_wcd_hph_pa_event, SND_SOC_DAPM_PRE_PMU |
2404 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2405
2406 SND_SOC_DAPM_DAC_E("HPHR DAC", NULL, MSM8X10_WCD_A_RX_HPH_R_DAC_CTL,
2407 7, 0,
2408 msm8x10_wcd_hphr_dac_event,
2409 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2410
Kuirong Wang78468f12013-06-19 01:55:53 -07002411 SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0,
2412 spkr_switch, ARRAY_SIZE(spkr_switch)),
2413
Kuirong Wang265f3592012-12-05 16:17:41 -08002414 /* Speaker */
Kuirong Wang91e52532013-03-31 14:24:22 -07002415 SND_SOC_DAPM_OUTPUT("LINEOUT"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002416 SND_SOC_DAPM_OUTPUT("SPK_OUT"),
2417
Kuirong Wang91e52532013-03-31 14:24:22 -07002418 SND_SOC_DAPM_PGA_E("LINEOUT PA", MSM8X10_WCD_A_RX_LINE_CNP_EN,
Kuirong Wang265f3592012-12-05 16:17:41 -08002419 0, 0, NULL, 0, msm8x10_wcd_codec_enable_lineout,
2420 SND_SOC_DAPM_PRE_PMU |
2421 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2422
2423 SND_SOC_DAPM_PGA_E("SPK PA", MSM8X10_WCD_A_SPKR_DRV_EN,
2424 7, 0 , NULL, 0, msm8x10_wcd_codec_enable_spk_pa,
2425 SND_SOC_DAPM_PRE_PMU |
2426 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2427
Kuirong Wang91e52532013-03-31 14:24:22 -07002428 SND_SOC_DAPM_DAC_E("LINEOUT DAC", NULL,
Kuirong Wang265f3592012-12-05 16:17:41 -08002429 MSM8X10_WCD_A_RX_LINE_1_DAC_CTL, 7, 0,
2430 msm8x10_wcd_lineout_dac_event,
2431 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
2432
Kuirong Wang265f3592012-12-05 16:17:41 -08002433 SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2434 SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0),
2435
2436 SND_SOC_DAPM_MIXER_E("RX1 MIX2",
2437 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL,
2438 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2439 SND_SOC_DAPM_POST_PMU),
2440 SND_SOC_DAPM_MIXER_E("RX2 MIX2",
2441 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL,
2442 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2443 SND_SOC_DAPM_POST_PMU),
2444 SND_SOC_DAPM_MIXER_E("RX3 MIX1",
2445 MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL,
2446 0, msm8x10_wcd_codec_enable_interpolator, SND_SOC_DAPM_PRE_PMU |
2447 SND_SOC_DAPM_POST_PMU),
2448
Kuirong Wang91e52532013-03-31 14:24:22 -07002449 SND_SOC_DAPM_SUPPLY("RX1 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2450 0, 0, NULL, 0),
2451 SND_SOC_DAPM_SUPPLY("RX2 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2452 1, 0, NULL, 0),
2453 SND_SOC_DAPM_SUPPLY("RX3 CLK", MSM8X10_WCD_A_CDC_DIG_CLK_CTL,
2454 2, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002455 SND_SOC_DAPM_MIXER("RX1 CHAIN", MSM8X10_WCD_A_CDC_RX1_B6_CTL,
2456 5, 0, NULL, 0),
2457 SND_SOC_DAPM_MIXER("RX2 CHAIN", MSM8X10_WCD_A_CDC_RX2_B6_CTL,
2458 5, 0, NULL, 0),
Kuirong Wang91e52532013-03-31 14:24:22 -07002459 SND_SOC_DAPM_MIXER("RX3 CHAIN", MSM8X10_WCD_A_CDC_RX3_B6_CTL,
2460 5, 0, NULL, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002461
Kuirong Wang1261b1d2013-08-06 18:18:21 -07002462 SND_SOC_DAPM_SUPPLY("HPHR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2463 0, 0, NULL, 0),
2464 SND_SOC_DAPM_SUPPLY("HPHL CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2465 1, 0, NULL, 0),
2466 SND_SOC_DAPM_SUPPLY("EAR CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2467 2, 0, NULL, 0),
2468 SND_SOC_DAPM_SUPPLY("LINEOUT CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2469 3, 0, NULL, 0),
2470 SND_SOC_DAPM_SUPPLY("SPK CLK", MSM8X10_WCD_A_CDC_ANA_CLK_CTL,
2471 4, 0, NULL, 0),
2472
Kuirong Wang265f3592012-12-05 16:17:41 -08002473 SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2474 &rx_mix1_inp1_mux),
2475 SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2476 &rx_mix1_inp2_mux),
2477 SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0,
2478 &rx_mix1_inp3_mux),
2479 SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2480 &rx2_mix1_inp1_mux),
2481 SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2482 &rx2_mix1_inp2_mux),
2483 SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0,
2484 &rx3_mix1_inp1_mux),
2485 SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0,
2486 &rx3_mix1_inp2_mux),
2487 SND_SOC_DAPM_MUX("RX1 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2488 &rx1_mix2_inp1_mux),
2489 SND_SOC_DAPM_MUX("RX2 MIX2 INP1", SND_SOC_NOPM, 0, 0,
2490 &rx2_mix2_inp1_mux),
Kuirong Wang78468f12013-06-19 01:55:53 -07002491 SND_SOC_DAPM_MUX("RDAC4 MUX", SND_SOC_NOPM, 0, 0,
2492 &rx_dac4_mux),
Mohammad Johny Shaikf4459eb2013-12-17 13:27:23 +05302493 SND_SOC_DAPM_MUX("RDAC3 MUX", SND_SOC_NOPM, 0, 0,
2494 &rx_dac3_mux),
Kuirong Wang265f3592012-12-05 16:17:41 -08002495
Kuirong Wang49f506a2013-05-22 17:38:26 -07002496 SND_SOC_DAPM_SUPPLY("MICBIAS_REGULATOR", SND_SOC_NOPM,
2497 ON_DEMAND_MICBIAS, 0,
2498 msm8x10_wcd_codec_enable_on_demand_supply,
2499 SND_SOC_DAPM_PRE_PMU |
2500 SND_SOC_DAPM_POST_PMD),
2501
2502 SND_SOC_DAPM_SUPPLY("CP_REGULATOR", SND_SOC_NOPM,
2503 ON_DEMAND_CP, 0,
2504 msm8x10_wcd_codec_enable_on_demand_supply,
2505 SND_SOC_DAPM_PRE_PMU |
2506 SND_SOC_DAPM_POST_PMD),
2507
Kuirong Wang265f3592012-12-05 16:17:41 -08002508 SND_SOC_DAPM_SUPPLY("CP", MSM8X10_WCD_A_CP_EN, 0, 0,
Kuirong Wang49f506a2013-05-22 17:38:26 -07002509 msm8x10_wcd_codec_enable_charge_pump, SND_SOC_DAPM_POST_PMU |
2510 SND_SOC_DAPM_PRE_PMD),
Kuirong Wang265f3592012-12-05 16:17:41 -08002511
2512 SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0,
2513 msm8x10_wcd_codec_enable_rx_bias, SND_SOC_DAPM_PRE_PMU |
2514 SND_SOC_DAPM_POST_PMD),
2515
2516 /* TX */
2517
2518 SND_SOC_DAPM_SUPPLY("CDC_CONN", MSM8X10_WCD_A_CDC_CLK_OTHR_CTL,
2519 2, 0, NULL, 0),
2520
2521
2522 SND_SOC_DAPM_INPUT("AMIC1"),
Kuirong Wang91e52532013-03-31 14:24:22 -07002523 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal1",
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),
Kuirong Wang91e52532013-03-31 14:24:22 -07002527 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal2",
Kuirong Wang265f3592012-12-05 16:17:41 -08002528 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),
Kuirong Wang91e52532013-03-31 14:24:22 -07002531 SND_SOC_DAPM_MICBIAS_E("MIC BIAS Internal3",
Kuirong Wang265f3592012-12-05 16:17:41 -08002532 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2533 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2534 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriyafaf04292013-10-01 17:05:44 +05302535 SND_SOC_DAPM_MICBIAS_E("MIC BIAS External",
2536 MSM8X10_WCD_A_MICB_1_CTL, 7, 0,
2537 msm8x10_wcd_codec_enable_micbias, SND_SOC_DAPM_PRE_PMU |
2538 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302539 SND_SOC_DAPM_MICBIAS_E(DAPM_MICBIAS_EXTERNAL_STANDALONE,
2540 MSM8X10_WCD_A_MICB_1_CTL,
2541 7, 0, msm8x10_wcd_codec_enable_micbias,
2542 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2543 SND_SOC_DAPM_POST_PMD),
Simmi Pateriyafaf04292013-10-01 17:05:44 +05302544
Kuirong Wang265f3592012-12-05 16:17:41 -08002545 SND_SOC_DAPM_ADC_E("ADC1", NULL, MSM8X10_WCD_A_TX_1_EN, 7, 0,
2546 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2547 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wanga0185b12013-07-26 17:49:13 -07002548 SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, MSM8X10_WCD_A_TX_2_EN, 7, 0,
Kuirong Wang265f3592012-12-05 16:17:41 -08002549 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2550 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
Kuirong Wanga0185b12013-07-26 17:49:13 -07002551 SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, MSM8X10_WCD_A_TX_3_EN, 7, 0,
2552 msm8x10_wcd_codec_enable_adc, SND_SOC_DAPM_PRE_PMU |
2553 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
2554
2555 SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
2556
2557 SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0,
2558 &tx_adc2_mux),
Kuirong Wang265f3592012-12-05 16:17:41 -08002559
2560 SND_SOC_DAPM_INPUT("AMIC3"),
2561
2562 SND_SOC_DAPM_MUX_E("DEC1 MUX",
2563 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0,
2564 &dec1_mux, msm8x10_wcd_codec_enable_dec,
2565 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2566 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2567
2568 SND_SOC_DAPM_MUX_E("DEC2 MUX",
2569 MSM8X10_WCD_A_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0,
2570 &dec2_mux, msm8x10_wcd_codec_enable_dec,
2571 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
2572 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
2573
2574 SND_SOC_DAPM_INPUT("AMIC2"),
Kuirong Wang265f3592012-12-05 16:17:41 -08002575
Kuirong Wang91e52532013-03-31 14:24:22 -07002576 SND_SOC_DAPM_AIF_OUT("I2S TX1", "AIF1 Capture", 0, SND_SOC_NOPM,
2577 0, 0),
2578 SND_SOC_DAPM_AIF_OUT("I2S TX2", "AIF1 Capture", 0, SND_SOC_NOPM,
2579 0, 0),
2580 SND_SOC_DAPM_AIF_OUT("I2S TX3", "AIF1 Capture", 0, SND_SOC_NOPM,
2581 0, 0),
Kuirong Wang265f3592012-12-05 16:17:41 -08002582
2583 /* Digital Mic Inputs */
2584 SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0,
2585 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2586 SND_SOC_DAPM_POST_PMD),
2587
2588 SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0,
2589 msm8x10_wcd_codec_enable_dmic, SND_SOC_DAPM_PRE_PMU |
2590 SND_SOC_DAPM_POST_PMD),
2591
2592 /* Sidetone */
2593 SND_SOC_DAPM_MUX("IIR1 INP1 MUX", SND_SOC_NOPM, 0, 0, &iir1_inp1_mux),
2594 SND_SOC_DAPM_PGA("IIR1", MSM8X10_WCD_A_CDC_CLK_SD_CTL, 0, 0, NULL, 0),
2595
2596 SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_RX_I2S_CTL,
2597 4, 0, NULL, 0),
2598 SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", MSM8X10_WCD_A_CDC_CLK_TX_I2S_CTL, 4,
2599 0, NULL, 0),
2600};
2601
2602static const struct msm8x10_wcd_reg_mask_val msm8x10_wcd_reg_defaults[] = {
2603
2604 /* set MCLk to 9.6 */
Kuirong Wang91e52532013-03-31 14:24:22 -07002605 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CHIP_CTL, 0x00),
Kuirong Wang265f3592012-12-05 16:17:41 -08002606
2607 /* EAR PA deafults */
2608 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_CMBUFF, 0x05),
2609
2610 /* RX deafults */
2611 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B5_CTL, 0x78),
2612 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B5_CTL, 0x78),
2613 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B5_CTL, 0x78),
2614
2615 /* RX1 and RX2 defaults */
2616 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xA0),
2617 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xA0),
2618
2619 /* RX3 to RX7 defaults */
2620 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_RX3_B6_CTL, 0x80),
2621
2622 /* Reduce HPH DAC bias to 70% */
2623 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_HPH_BIAS_PA, 0x7A),
2624 /*Reduce EAR DAC bias to 70% */
2625 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_EAR_BIAS_PA, 0x76),
2626 /* Reduce LINE DAC bias to 70% */
2627 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_RX_LINE_BIAS_PA, 0x78),
2628
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002629 /* Disable internal biasing path which can cause leakage */
Kuirong Wang91e52532013-03-31 14:24:22 -07002630 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_BIAS_CURR_CTL_2, 0x04),
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07002631
Kuirong Wang91e52532013-03-31 14:24:22 -07002632 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_COM_BIAS, 0xE0),
Kuirong Wangf046d7c2013-08-28 11:52:49 -07002633 /* Keep the same default gain settings for TX paths */
Kuirong Wang91e52532013-03-31 14:24:22 -07002634 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_1_EN, 0x32),
2635 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_2_EN, 0x32),
Kuirong Wangf046d7c2013-08-28 11:52:49 -07002636 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_TX_3_EN, 0x30),
Kuirong Wang269ae352013-05-23 11:31:58 -07002637
2638 /* ClassG fine tuning setting for 16 ohm HPH */
2639 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B1_CTL, 0x05),
2640 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B2_CTL, 0x0C),
2641 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B3_CTL, 0x1A),
2642 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_FREQ_THRESH_B4_CTL, 0x47),
2643 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_CLSG_GAIN_THRESH_CTL, 0x23),
Kuirong Wang1756a7b2013-05-28 17:29:23 -07002644
2645 /* Always set TXD_CLK_EN bit to reduce the leakage */
2646 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002647
2648 /* Always disable clock gating for MCLK to mbhc clock gate */
2649 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0x20),
2650 MSM8X10_WCD_REG_VAL(MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0x10),
Kuirong Wang265f3592012-12-05 16:17:41 -08002651};
2652
2653static void msm8x10_wcd_update_reg_defaults(struct snd_soc_codec *codec)
2654{
2655 u32 i;
2656
2657 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_reg_defaults); i++)
2658 snd_soc_write(codec, msm8x10_wcd_reg_defaults[i].reg,
2659 msm8x10_wcd_reg_defaults[i].val);
2660}
2661
2662static const struct msm8x10_wcd_reg_mask_val
2663 msm8x10_wcd_codec_reg_init_val[] = {
2664 /* Initialize current threshold to 350MA
2665 * number of wait and run cycles to 4096
2666 */
2667 {MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xE1, 0x61},
2668 {MSM8X10_WCD_A_RX_COM_OCP_COUNT, 0xFF, 0xFF},
Yeleswarapu, Nagaradheshf6572f82013-11-06 17:14:09 +05302669 {MSM8X10_WCD_A_RX_HPH_L_TEST, 0x01, 0x01},
2670 {MSM8X10_WCD_A_RX_HPH_R_TEST, 0x01, 0x01},
Kuirong Wang265f3592012-12-05 16:17:41 -08002671
2672 /* Initialize gain registers to use register gain */
2673 {MSM8X10_WCD_A_RX_HPH_L_GAIN, 0x20, 0x20},
2674 {MSM8X10_WCD_A_RX_HPH_R_GAIN, 0x20, 0x20},
2675 {MSM8X10_WCD_A_RX_LINE_1_GAIN, 0x20, 0x20},
2676
2677 /*enable HPF filter for TX paths */
2678 {MSM8X10_WCD_A_CDC_TX1_MUX_CTL, 0x8, 0x0},
2679 {MSM8X10_WCD_A_CDC_TX2_MUX_CTL, 0x8, 0x0},
2680
2681 /* config Decimator for DMIC CLK_MODE_1(3.2Mhz@9.6Mhz mclk) */
2682 {MSM8X10_WCD_A_CDC_TX1_DMIC_CTL, 0x7, 0x1},
2683 {MSM8X10_WCD_A_CDC_TX2_DMIC_CTL, 0x7, 0x1},
2684
2685 /* config DMIC clk to CLK_MODE_1 (3.2Mhz@9.6Mhz mclk) */
2686 {MSM8X10_WCD_A_CDC_CLK_DMIC_B1_CTL, 0xEE, 0x22},
2687
Kuirong Wang78468f12013-06-19 01:55:53 -07002688 /* Disable REF_EN for MSM8X10_WCD_A_SPKR_DRV_DAC_CTL */
2689 {MSM8X10_WCD_A_SPKR_DRV_DAC_CTL, 0x04, 0x00},
Kuirong Wang265f3592012-12-05 16:17:41 -08002690};
2691
2692static void msm8x10_wcd_codec_init_reg(struct snd_soc_codec *codec)
2693{
2694 u32 i;
2695
2696 for (i = 0; i < ARRAY_SIZE(msm8x10_wcd_codec_reg_init_val); i++)
2697 snd_soc_update_bits(codec,
2698 msm8x10_wcd_codec_reg_init_val[i].reg,
2699 msm8x10_wcd_codec_reg_init_val[i].mask,
2700 msm8x10_wcd_codec_reg_init_val[i].val);
2701}
2702
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002703static void msm8x10_wcd_enable_mux_bias_block(
2704 struct snd_soc_codec *codec)
2705{
2706 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
2707 0x80, 0x00);
2708}
2709
2710static void msm8x10_wcd_put_cfilt_fast_mode(
2711 struct snd_soc_codec *codec,
2712 struct wcd9xxx_mbhc *mbhc)
2713{
2714 snd_soc_update_bits(codec, mbhc->mbhc_bias_regs.cfilt_ctl,
2715 0x30, 0x30);
2716}
2717
2718static void msm8x10_wcd_codec_specific_cal_setup(
2719 struct snd_soc_codec *codec,
2720 struct wcd9xxx_mbhc *mbhc)
2721{
2722 snd_soc_update_bits(codec, WCD9XXX_A_CDC_MBHC_B1_CTL,
2723 0x04, 0x04);
2724 snd_soc_update_bits(codec, WCD9XXX_A_TX_7_MBHC_EN,
2725 0xE0, 0xE0);
2726}
2727
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002728static struct wcd9xxx_cfilt_mode msm8x10_wcd_switch_cfilt_mode(
2729 struct wcd9xxx_mbhc *mbhc, bool fast)
2730{
2731 struct snd_soc_codec *codec = mbhc->codec;
2732 struct wcd9xxx_cfilt_mode cfilt_mode;
2733
2734 if (fast)
2735 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_EN;
2736 else
2737 cfilt_mode.reg_mode_val = WCD9XXX_CFILT_EXT_PRCHG_DSBL;
2738
2739 cfilt_mode.cur_mode_val =
2740 snd_soc_read(codec, mbhc->mbhc_bias_regs.cfilt_ctl) & 0x30;
2741 cfilt_mode.reg_mask = 0x30;
2742 return cfilt_mode;
2743}
2744
2745static void msm8x10_wcd_select_cfilt(struct snd_soc_codec *codec,
2746 struct wcd9xxx_mbhc *mbhc)
2747{
2748 snd_soc_update_bits(codec,
2749 mbhc->mbhc_bias_regs.ctl_reg, 0x60, 0x00);
2750}
2751
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07002752enum wcd9xxx_cdc_type msm8x10_wcd_get_cdc_type(void)
2753{
2754 return WCD9XXX_CDC_TYPE_HELICON;
2755}
2756
2757static void msm8x10_wcd_mbhc_clk_gate(struct snd_soc_codec *codec,
2758 bool on)
2759{
2760 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_TOP_CLK_CTL, 0x10, 0x10);
2761}
2762
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07002763static void msm8x10_wcd_mbhc_txfe(struct snd_soc_codec *codec, bool on)
2764{
2765 snd_soc_update_bits(codec, MSM8X10_WCD_A_TX_7_MBHC_EN_ATEST_CTRL,
2766 0x80, on ? 0x80 : 0x00);
2767}
2768
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002769static int msm8x10_wcd_enable_ext_mb_source(struct snd_soc_codec *codec,
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -08002770 bool turn_on,
2771 bool use_dapm)
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002772{
2773 int ret = 0;
2774
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -08002775 if (use_dapm) {
2776 if (turn_on)
2777 ret = snd_soc_dapm_force_enable_pin(&codec->dapm,
2778 "MICBIAS_REGULATOR");
2779 else
2780 ret = snd_soc_dapm_disable_pin(&codec->dapm,
2781 "MICBIAS_REGULATOR");
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002782
Phani Kumar Uppalapatiaa98c282014-01-28 15:32:22 -08002783 snd_soc_dapm_sync(&codec->dapm);
2784 } else {
2785 struct on_demand_supply *supply;
2786 struct msm8x10_wcd_priv *msm8x10_wcd =
2787 snd_soc_codec_get_drvdata(codec);
2788
2789 supply = &msm8x10_wcd->on_demand_list[ON_DEMAND_MICBIAS];
2790 if (!supply || !supply->supply || !msm8x10_wcd)
2791 return 0;
2792
2793 ret = on_demand_regulator_control(supply,
2794 turn_on,
2795 ON_DEMAND_MICBIAS);
2796 }
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07002797
2798 if (ret)
2799 dev_err(codec->dev, "%s: Failed to %s external micbias source\n",
2800 __func__, turn_on ? "enable" : "disabled");
2801 else
2802 dev_dbg(codec->dev, "%s: %s external micbias source\n",
2803 __func__, turn_on ? "Enabled" : "Disabled");
2804
2805 return ret;
2806}
2807
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302808static int msm8x10_wcd_enable_mbhc_micbias(struct snd_soc_codec *codec,
Phani Kumar Uppalapatib7266bd2013-10-21 14:26:10 -07002809 bool enable,
2810 enum wcd9xxx_micbias_num micb_num)
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302811{
2812 int rc;
Simmi Pateriya1cc09012014-01-21 17:58:11 +05302813 struct msm8x10_wcd_priv *msm8x10_wcd = snd_soc_codec_get_drvdata(codec);
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302814
Phani Kumar Uppalapatib7266bd2013-10-21 14:26:10 -07002815 if (micb_num != MBHC_MICBIAS1) {
2816 rc = -EINVAL;
2817 goto err;
2818 }
2819
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302820 if (enable)
2821 rc = snd_soc_dapm_force_enable_pin(&codec->dapm,
2822 DAPM_MICBIAS_EXTERNAL_STANDALONE);
Simmi Pateriya1cc09012014-01-21 17:58:11 +05302823 else {
2824 if (msm8x10_wcd->micb_en_count > 0) {
2825 msm8x10_wcd->micb_en_count--;
2826 pr_debug("%s micb_en_count : %d", __func__,
2827 msm8x10_wcd->micb_en_count);
2828 return 0;
2829 }
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302830 rc = snd_soc_dapm_disable_pin(&codec->dapm,
2831 DAPM_MICBIAS_EXTERNAL_STANDALONE);
Simmi Pateriya1cc09012014-01-21 17:58:11 +05302832 }
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302833 snd_soc_dapm_sync(&codec->dapm);
2834
Phani Kumar Uppalapatib7266bd2013-10-21 14:26:10 -07002835err:
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05302836 if (rc)
2837 pr_debug("%s: Failed to force %s micbias", __func__,
2838 enable ? "enable" : "disable");
2839 else
2840 pr_debug("%s: Trying force %s micbias", __func__,
2841 enable ? "enable" : "disable");
2842 return rc;
2843}
2844
Bhalchandra Gajare6a2296b2013-09-19 13:15:08 -07002845static void msm8x10_wcd_micb_internal(struct snd_soc_codec *codec, bool on)
2846{
2847 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_INT_RBIAS,
2848 0x1C, on ? 0x14 : 0x00);
2849}
2850
Bhalchandra Gajaref19a9262013-09-19 15:40:08 -07002851static void msm8x10_wcd_enable_mb_vddio(struct snd_soc_codec *codec, bool on)
2852{
2853 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_CTL,
2854 0x40, on ? 0x40 : 0x00);
2855}
2856
Bhalchandra Gajarebbc32742013-10-18 12:32:29 -07002857static void msm8x10_wcd_prepare_hph_pa(struct snd_soc_codec *codec,
2858 struct list_head *lh)
2859{
2860 int i;
2861 u32 delay;
2862
2863 const struct wcd9xxx_reg_mask_val reg_set_paon[] = {
2864 {MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xFF, 0x01},
2865 {MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xFF, 0x01},
2866 {MSM8X10_WCD_A_RX_HPH_L_GAIN, 0xFF, 0x2C},
2867 {MSM8X10_WCD_A_RX_HPH_R_GAIN, 0xFF, 0x2C},
2868 {MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0xFF, 0x01},
2869 {MSM8X10_WCD_A_RX_COM_BIAS, 0xFF, 0x80},
2870 {MSM8X10_WCD_A_CP_EN, 0xFF, 0xE7},
2871 {MSM8X10_WCD_A_CP_STATIC, 0xFF, 0x13},
2872 {MSM8X10_WCD_A_CP_STATIC, 0xFF, 0x1B},
2873 {MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xFF, 0x01},
2874 {MSM8X10_WCD_A_CDC_CLK_RX_B1_CTL, 0xFF, 0x03},
2875 {MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0xFF, 0x22},
2876 {MSM8X10_WCD_A_CDC_ANA_CLK_CTL, 0xFF, 0x23},
2877 {MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDA},
2878 {MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0xFF, 0x01},
2879 {MSM8X10_WCD_A_CDC_DIG_CLK_CTL, 0xFF, 0x03},
2880 {MSM8X10_WCD_A_RX_HPH_CHOP_CTL, 0xFF, 0xA4},
2881 {MSM8X10_WCD_A_RX_HPH_OCP_CTL, 0xFF, 0x67},
2882 {MSM8X10_WCD_A_RX_HPH_L_TEST, 0x01, 0x00},
2883 {MSM8X10_WCD_A_RX_HPH_R_TEST, 0x01, 0x00},
2884 {MSM8X10_WCD_A_RX_HPH_BIAS_WG_OCP, 0xFF, 0x1A},
2885 {MSM8X10_WCD_A_RX_HPH_CNP_WG_CTL, 0xFF, 0xDB},
2886 {MSM8X10_WCD_A_RX_HPH_CNP_WG_TIME, 0xFF, 0xDB},
2887 {MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 0xFF, 0x40},
2888 {MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 0xFF, 0xC0},
2889 {MSM8X10_WCD_A_RX_HPH_R_DAC_CTL, 0xFF, 0x40},
2890 {MSM8X10_WCD_A_RX_HPH_R_DAC_CTL, 0xFF, 0xC0},
2891 {MSM8X10_WCD_A_RX_HPH_L_DAC_CTL, 0x03, 0x01},
2892 {MSM8X10_WCD_A_RX_HPH_R_DAC_CTL, 0x03, 0x01},
2893 };
2894
2895 for (i = 0; i < ARRAY_SIZE(reg_set_paon); i++) {
2896 delay = 0;
2897 wcd9xxx_soc_update_bits_push(codec, lh,
2898 reg_set_paon[i].reg,
2899 reg_set_paon[i].mask,
2900 reg_set_paon[i].val, delay);
2901 }
2902 dev_dbg(codec->dev, "%s: PAs are prepared\n", __func__);
2903 return;
2904}
2905
2906static int msm8x10_wcd_enable_static_pa(struct snd_soc_codec *codec,
2907 bool enable)
2908{
2909 int wg_time = snd_soc_read(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME) *
2910 MSM8X10_WCD_WG_TIME_FACTOR_US;
2911
2912 wg_time += (int) (wg_time * 35) / 100;
2913
2914 snd_soc_update_bits(codec, MSM8X10_WCD_A_RX_HPH_CNP_EN, 0x30,
2915 enable ? 0x30 : 0x0);
2916 /* Wait for wave gen time to avoid pop noise */
2917 usleep_range(wg_time, wg_time + WCD9XXX_USLEEP_RANGE_MARGIN_US);
2918 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_RX1_B6_CTL, 0xFF, 0x00);
2919 snd_soc_update_bits(codec, MSM8X10_WCD_A_CDC_RX2_B6_CTL, 0xFF, 0x00);
2920
2921 dev_dbg(codec->dev, "%s: PAs are %s as static mode (wg_time %d)\n",
2922 __func__, enable ? "enabled" : "disabled", wg_time);
2923 return 0;
2924}
2925
2926static int msm8x10_wcd_setup_zdet(struct wcd9xxx_mbhc *mbhc,
2927 enum mbhc_impedance_detect_stages stage)
2928{
2929 int ret = 0;
2930 struct snd_soc_codec *codec = mbhc->codec;
2931 struct msm8x10_wcd_priv *wcd_priv = snd_soc_codec_get_drvdata(codec);
2932 const int mux_wait_us = 25;
2933
2934#define __wr(reg, mask, value) \
2935 do { \
2936 ret = wcd9xxx_soc_update_bits_push(codec, \
2937 &wcd_priv->reg_save_restore, \
2938 reg, mask, value, 0); \
2939 if (ret < 0) \
2940 return ret; \
2941 } while (0)
2942
2943 switch (stage) {
2944 case PRE_MEAS:
2945 dev_dbg(codec->dev, "%s: PRE_MEAS\n", __func__);
2946 INIT_LIST_HEAD(&wcd_priv->reg_save_restore);
2947 /* Configure PA */
2948 msm8x10_wcd_prepare_hph_pa(mbhc->codec,
2949 &wcd_priv->reg_save_restore);
2950
2951 /* Setup MBHC */
2952 __wr(WCD9XXX_A_MBHC_SCALING_MUX_1, 0x7F, 0x40);
2953 __wr(WCD9XXX_A_MBHC_SCALING_MUX_2, 0xFF, 0xF0);
2954 __wr(0x171, 0xFF, 0x90);
2955 __wr(WCD9XXX_A_TX_7_MBHC_EN, 0xFF, 0xF0);
2956 __wr(WCD9XXX_A_CDC_MBHC_TIMER_B4_CTL, 0xFF, 0x45);
2957 __wr(WCD9XXX_A_CDC_MBHC_TIMER_B5_CTL, 0xFF, 0x80);
2958
2959 __wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x0A);
2960 snd_soc_write(codec, WCD9XXX_A_CDC_MBHC_EN_CTL, 0x2);
2961 __wr(WCD9XXX_A_CDC_MBHC_CLK_CTL, 0xFF, 0x02);
2962
2963 /* Enable Impedance Detection */
2964 __wr(WCD9XXX_A_MBHC_HPH, 0xFF, 0xC8);
2965
2966 /*
2967 * CnP setup for 0mV
2968 * Route static data as input to noise shaper
2969 */
2970 __wr(MSM8X10_WCD_A_CDC_RX1_B3_CTL, 0xFF, 0x02);
2971 __wr(MSM8X10_WCD_A_CDC_RX2_B3_CTL, 0xFF, 0x02);
2972
2973 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
2974 0x02, 0x00);
2975 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
2976 0x02, 0x00);
2977
2978 /* Reset the HPHL static data pointer */
2979 __wr(MSM8X10_WCD_A_CDC_RX1_B2_CTL, 0xFF, 0x00);
2980 /* Four consecutive writes to set 0V as static data input */
2981 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
2982 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
2983 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
2984 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
2985
2986 /* Reset the HPHR static data pointer */
2987 __wr(MSM8X10_WCD_A_CDC_RX2_B2_CTL, 0xFF, 0x00);
2988 /* Four consecutive writes to set 0V as static data input */
2989 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
2990 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
2991 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
2992 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
2993
2994 /* Enable the HPHL and HPHR PA */
2995 msm8x10_wcd_enable_static_pa(mbhc->codec, true);
2996 break;
2997
2998 case POST_MEAS:
2999 dev_dbg(codec->dev, "%s: POST_MEAS\n", __func__);
3000 /* Turn off ICAL */
3001 snd_soc_write(codec, WCD9XXX_A_MBHC_SCALING_MUX_2, 0xF0);
3002
3003 msm8x10_wcd_enable_static_pa(mbhc->codec, false);
3004
3005 /*
3006 * Setup CnP wavegen to ramp to the desired
3007 * output using a 40ms ramp
3008 */
3009
3010 /* CnP wavegen current to 0.5uA */
3011 snd_soc_write(codec, WCD9XXX_A_RX_HPH_BIAS_WG_OCP, 0x1A);
3012 /* Set the current division ratio to 2000 */
3013 snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_CTL, 0xDF);
3014 /* Set the wavegen timer to max (60msec) */
3015 snd_soc_write(codec, WCD9XXX_A_RX_HPH_CNP_WG_TIME, 0xA0);
3016 /* Set the CnP reference current to sc_bias */
3017 snd_soc_write(codec, WCD9XXX_A_RX_HPH_OCP_CTL, 0x6D);
3018
3019 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B2_CTL, 0x00);
3020 /* Four consecutive writes to set -10mV as static data input */
3021 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x00);
3022 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x1F);
3023 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0xE3);
3024 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX1_B1_CTL, 0x08);
3025
3026 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B2_CTL, 0x00);
3027 /* Four consecutive writes to set -10mV as static data input */
3028 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x00);
3029 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x1F);
3030 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0xE3);
3031 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RX2_B1_CTL, 0x08);
3032
3033 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_L_TEST,
3034 0x02, 0x02);
3035 snd_soc_update_bits(codec, WCD9XXX_A_RX_HPH_R_TEST,
3036 0x02, 0x02);
3037 /* Enable the HPHL and HPHR PA and wait for 60mS */
3038 msm8x10_wcd_enable_static_pa(mbhc->codec, true);
3039
3040 snd_soc_update_bits(codec, WCD9XXX_A_MBHC_SCALING_MUX_1,
3041 0x7F, 0x40);
3042 usleep_range(mux_wait_us,
3043 mux_wait_us + WCD9XXX_USLEEP_RANGE_MARGIN_US);
3044 break;
3045 case PA_DISABLE:
3046 dev_dbg(codec->dev, "%s: PA_DISABLE\n", __func__);
3047 msm8x10_wcd_enable_static_pa(mbhc->codec, false);
3048 wcd9xxx_restore_registers(codec, &wcd_priv->reg_save_restore);
3049 break;
3050 }
3051#undef __wr
3052
3053 return ret;
3054}
3055
3056static void msm8x10_wcd_compute_impedance(s16 *l, s16 *r, uint32_t *zl,
3057 uint32_t *zr)
3058{
3059 int zln, zld;
3060 int zrn, zrd;
3061 int rl = 0, rr = 0;
3062
3063 zln = (l[1] - l[0]) * MSM8X10_WCD_ZDET_MUL_FACTOR;
3064 zld = (l[2] - l[0]);
3065 if (zld)
3066 rl = zln / zld;
3067
3068 zrn = (r[1] - r[0]) * MSM8X10_WCD_ZDET_MUL_FACTOR;
3069 zrd = (r[2] - r[0]);
3070 if (zrd)
3071 rr = zrn / zrd;
3072
3073 *zl = rl;
3074 *zr = rr;
3075}
3076
3077
3078
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003079static const struct wcd9xxx_mbhc_cb mbhc_cb = {
3080 .enable_mux_bias_block = msm8x10_wcd_enable_mux_bias_block,
3081 .cfilt_fast_mode = msm8x10_wcd_put_cfilt_fast_mode,
3082 .codec_specific_cal = msm8x10_wcd_codec_specific_cal_setup,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003083 .switch_cfilt_mode = msm8x10_wcd_switch_cfilt_mode,
3084 .select_cfilt = msm8x10_wcd_select_cfilt,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003085 .get_cdc_type = msm8x10_wcd_get_cdc_type,
3086 .enable_clock_gate = msm8x10_wcd_mbhc_clk_gate,
Bhalchandra Gajare2763c722013-09-11 17:10:22 -07003087 .enable_mbhc_txfe = msm8x10_wcd_mbhc_txfe,
Bhalchandra Gajaredd01bf32013-09-05 14:00:29 -07003088 .enable_mb_source = msm8x10_wcd_enable_ext_mb_source,
Bhalchandra Gajare6a2296b2013-09-19 13:15:08 -07003089 .setup_int_rbias = msm8x10_wcd_micb_internal,
Bhalchandra Gajaref19a9262013-09-19 15:40:08 -07003090 .pull_mb_to_vddio = msm8x10_wcd_enable_mb_vddio,
Bhalchandra Gajarebbc32742013-10-18 12:32:29 -07003091 .setup_zdet = msm8x10_wcd_setup_zdet,
3092 .compute_impedance = msm8x10_wcd_compute_impedance,
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003093};
3094
Kuirong Wang265f3592012-12-05 16:17:41 -08003095int msm8x10_wcd_hs_detect(struct snd_soc_codec *codec,
Bhalchandra Gajare9c19dc22013-07-11 17:16:53 -07003096 struct wcd9xxx_mbhc_config *mbhc_cfg)
Kuirong Wang265f3592012-12-05 16:17:41 -08003097{
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003098 struct msm8x10_wcd_priv *wcd = snd_soc_codec_get_drvdata(codec);
3099
Phani Kumar Uppalapatibfc63942014-01-28 15:18:43 -08003100 if (!wcd) {
3101 dev_err(codec->dev, "%s: Invalid private data for codec\n",
3102 __func__);
3103 return -EINVAL;
3104 }
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003105 wcd->mbhc_cfg = mbhc_cfg;
Phani Kumar Uppalapatibfc63942014-01-28 15:18:43 -08003106 return wcd9xxx_mbhc_start(&wcd->mbhc, wcd->mbhc_cfg);
Kuirong Wang265f3592012-12-05 16:17:41 -08003107}
3108EXPORT_SYMBOL_GPL(msm8x10_wcd_hs_detect);
3109
Kuirong Wang2e81d322013-05-30 17:52:36 -07003110static int msm8x10_wcd_bringup(struct snd_soc_codec *codec)
3111{
3112 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RST_CTL, 0x02);
3113 snd_soc_write(codec, MSM8X10_WCD_A_CHIP_CTL, 0x00);
3114 usleep_range(5000, 5000);
3115 snd_soc_write(codec, MSM8X10_WCD_A_CDC_RST_CTL, 0x03);
3116 return 0;
3117}
3118
Kuirong Wang49f506a2013-05-22 17:38:26 -07003119static struct regulator *wcd8x10_wcd_codec_find_regulator(
3120 const struct msm8x10_wcd *msm8x10,
3121 const char *name)
3122{
3123 int i;
3124
3125 for (i = 0; i < msm8x10->num_of_supplies; i++) {
3126 if (msm8x10->supplies[i].supply &&
3127 !strncmp(msm8x10->supplies[i].supply, name, strlen(name)))
3128 return msm8x10->supplies[i].consumer;
3129 }
3130
3131 return NULL;
3132}
Fred Oh5aa9d2c2013-10-29 17:01:15 -07003133static int msm8x10_wcd_device_down(struct snd_soc_codec *codec)
3134{
3135 dev_dbg(codec->dev, "%s: device down!\n", __func__);
3136
3137 snd_soc_card_change_online_state(codec->card, 0);
3138 return 0;
3139}
Kuirong Wang49f506a2013-05-22 17:38:26 -07003140
Fred Ohcf2f8582013-06-13 18:32:07 -07003141static int msm8x10_wcd_device_up(struct snd_soc_codec *codec)
3142{
Fred Oh5aa9d2c2013-10-29 17:01:15 -07003143 dev_dbg(codec->dev, "%s: device up!\n", __func__);
3144
3145 snd_soc_card_change_online_state(codec->card, 1);
3146 /* delay is required to make sure sound card state updated */
3147 usleep_range(5000, 5100);
Fred Ohcf2f8582013-06-13 18:32:07 -07003148
3149 mutex_lock(&codec->mutex);
3150
3151 msm8x10_wcd_bringup(codec);
3152 msm8x10_wcd_codec_init_reg(codec);
3153 msm8x10_wcd_update_reg_defaults(codec);
3154
3155 mutex_unlock(&codec->mutex);
3156
3157 return 0;
3158}
3159
3160static int adsp_state_callback(struct notifier_block *nb, unsigned long value,
3161 void *priv)
3162{
3163 bool timedout;
3164 unsigned long timeout;
3165
Fred Oh5aa9d2c2013-10-29 17:01:15 -07003166 if (value == SUBSYS_BEFORE_SHUTDOWN)
3167 msm8x10_wcd_device_down(registered_codec);
3168 else if (value == SUBSYS_AFTER_POWERUP) {
Fred Ohcf2f8582013-06-13 18:32:07 -07003169 pr_debug("%s: ADSP is about to power up. bring up codec\n",
3170 __func__);
3171
3172 timeout = jiffies +
3173 msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS);
3174 while (!(timedout = time_after(jiffies, timeout))) {
3175 if (!q6core_is_adsp_ready()) {
3176 pr_debug("%s: ADSP isn't ready\n", __func__);
3177 } else {
3178 pr_debug("%s: ADSP is ready\n", __func__);
3179 msm8x10_wcd_device_up(registered_codec);
3180 break;
3181 }
3182 }
3183 }
3184
3185 return NOTIFY_OK;
3186}
3187
3188static struct notifier_block adsp_state_notifier_block = {
3189 .notifier_call = adsp_state_callback,
3190 .priority = -INT_MAX,
3191};
3192
Bhalchandra Gajare16748932013-10-01 18:16:05 -07003193static const struct wcd9xxx_mbhc_intr cdc_intr_ids = {
3194 .poll_plug_rem = MSM8X10_WCD_IRQ_MBHC_REMOVAL,
3195 .shortavg_complete = MSM8X10_WCD_IRQ_MBHC_SHORT_TERM,
3196 .potential_button_press = MSM8X10_WCD_IRQ_MBHC_PRESS,
3197 .button_release = MSM8X10_WCD_IRQ_MBHC_RELEASE,
3198 .dce_est_complete = MSM8X10_WCD_IRQ_MBHC_POTENTIAL,
3199 .insertion = MSM8X10_WCD_IRQ_MBHC_INSERTION,
3200 .hph_left_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT,
3201 .hph_right_ocp = MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT,
3202 .hs_jack_switch = MSM8X10_WCD_IRQ_MBHC_HS_DET,
3203};
Fred Ohcf2f8582013-06-13 18:32:07 -07003204
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003205static int msm8x10_wcd_handle_pdata(struct snd_soc_codec *codec,
3206 struct msm8x10_wcd_pdata *pdata)
3207{
3208 int k1, rc = 0;
3209 struct msm8x10_wcd_priv *msm8x10_wcd_priv;
3210
3211 msm8x10_wcd_priv = snd_soc_codec_get_drvdata(codec);
3212
3213 /* Make sure settings are correct */
3214 if (pdata->micbias.ldoh_v > WCD9XXX_LDOH_3P0_V ||
3215 pdata->micbias.bias1_cfilt_sel > WCD9XXX_CFILT1_SEL) {
3216 rc = -EINVAL;
3217 goto done;
3218 }
3219
3220 /* figure out k value */
3221 k1 = wcd9xxx_resmgr_get_k_val(&msm8x10_wcd_priv->resmgr,
3222 pdata->micbias.cfilt1_mv);
3223 if (IS_ERR_VALUE(k1)) {
3224 rc = -EINVAL;
3225 goto done;
3226 }
3227
3228 /* Set voltage level */
3229 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_CFILT_1_VAL,
3230 0xFC, (k1 << 2));
3231
3232 /* update micbias capless mode */
3233 snd_soc_update_bits(codec, MSM8X10_WCD_A_MICB_1_CTL, 0x10,
3234 pdata->micbias.bias1_cap_mode << 4);
3235
3236done:
3237 return rc;
3238}
3239
Kuirong Wang265f3592012-12-05 16:17:41 -08003240static int msm8x10_wcd_codec_probe(struct snd_soc_codec *codec)
3241{
Fred Oh4d716bb2013-07-30 10:14:46 -07003242 struct msm8x10_wcd_priv *msm8x10_wcd_priv;
3243 struct msm8x10_wcd *msm8x10_wcd;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003244 struct wcd9xxx_core_resource *core_res;
3245 int i, ret = 0;
Bhalchandra Gajare5cc8f322013-09-19 17:46:13 -07003246 struct msm8x10_wcd_pdata *pdata;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003247
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003248 dev_dbg(codec->dev, "%s()\n", __func__);
Kuirong Wang265f3592012-12-05 16:17:41 -08003249
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003250 msm8x10_wcd_priv = devm_kzalloc(codec->dev,
3251 sizeof(struct msm8x10_wcd_priv), GFP_KERNEL);
3252
Fred Oh4d716bb2013-07-30 10:14:46 -07003253 if (!msm8x10_wcd_priv) {
Kuirong Wang91e52532013-03-31 14:24:22 -07003254 dev_err(codec->dev, "Failed to allocate private data\n");
3255 return -ENOMEM;
3256 }
3257
3258 for (i = 0 ; i < NUM_DECIMATORS; i++) {
Fred Oh4d716bb2013-07-30 10:14:46 -07003259 tx_hpf_work[i].msm8x10_wcd = msm8x10_wcd_priv;
Kuirong Wang91e52532013-03-31 14:24:22 -07003260 tx_hpf_work[i].decimator = i + 1;
3261 INIT_DELAYED_WORK(&tx_hpf_work[i].dwork,
3262 tx_hpf_corner_freq_callback);
3263 }
3264
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003265 codec->control_data = dev_get_drvdata(codec->dev);
Fred Oh4d716bb2013-07-30 10:14:46 -07003266 snd_soc_codec_set_drvdata(codec, msm8x10_wcd_priv);
3267 msm8x10_wcd_priv->codec = codec;
3268
3269 /* map digital codec registers once */
3270 msm8x10_wcd = codec->control_data;
3271 msm8x10_wcd->pdino_base = ioremap(MSM8X10_DINO_CODEC_BASE_ADDR,
3272 MSM8X10_DINO_CODEC_REG_SIZE);
3273
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003274 pdata = dev_get_platdata(msm8x10_wcd->dev);
3275 if (!pdata) {
3276 dev_err(msm8x10_wcd->dev, "%s: platform data not found\n",
3277 __func__);
3278 }
3279
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003280 /* codec resmgr module init */
3281 msm8x10_wcd = codec->control_data;
3282 core_res = &msm8x10_wcd->wcd9xxx_res;
3283 ret = wcd9xxx_resmgr_init(&msm8x10_wcd_priv->resmgr,
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003284 codec, core_res, NULL, &pdata->micbias,
3285 NULL, WCD9XXX_CDC_TYPE_HELICON);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003286 if (ret) {
3287 dev_err(codec->dev,
3288 "%s: wcd9xxx init failed %d\n",
3289 __func__, ret);
3290 goto exit_probe;
3291 }
3292
Kuirong Wang2e81d322013-05-30 17:52:36 -07003293 msm8x10_wcd_bringup(codec);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003294 msm8x10_wcd_codec_init_reg(codec);
Kuirong Wang265f3592012-12-05 16:17:41 -08003295 msm8x10_wcd_update_reg_defaults(codec);
Bhalchandra Gajare5cc8f322013-09-19 17:46:13 -07003296
Fred Oh4d716bb2013-07-30 10:14:46 -07003297 msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].supply =
Kuirong Wang49f506a2013-05-22 17:38:26 -07003298 wcd8x10_wcd_codec_find_regulator(
3299 codec->control_data,
3300 on_demand_supply_name[ON_DEMAND_CP]);
Fred Oh4d716bb2013-07-30 10:14:46 -07003301 atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
3302 msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply =
Kuirong Wang49f506a2013-05-22 17:38:26 -07003303 wcd8x10_wcd_codec_find_regulator(
3304 codec->control_data,
3305 on_demand_supply_name[ON_DEMAND_MICBIAS]);
Fred Oh4d716bb2013-07-30 10:14:46 -07003306 atomic_set(&msm8x10_wcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003307
Simmi Pateriya1cc09012014-01-21 17:58:11 +05303308 msm8x10_wcd_priv->micb_en_count = 0;
3309
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003310 ret = wcd9xxx_mbhc_init(&msm8x10_wcd_priv->mbhc,
3311 &msm8x10_wcd_priv->resmgr,
Simmi Pateriyad54e6db2013-11-28 09:33:31 +05303312 codec, msm8x10_wcd_enable_mbhc_micbias,
3313 &mbhc_cb, &cdc_intr_ids,
Bhalchandra Gajarebbc32742013-10-18 12:32:29 -07003314 HELICON_MCLK_CLK_9P6MHZ, true);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003315 if (ret) {
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003316 dev_err(msm8x10_wcd->dev, "%s: Failed to initialize mbhc\n",
3317 __func__);
Bhalchandra Gajare8e5fe252013-07-15 19:42:21 -07003318 goto exit_probe;
3319 }
Kuirong Wang265f3592012-12-05 16:17:41 -08003320
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003321 /* Handle the Pdata */
3322 ret = msm8x10_wcd_handle_pdata(codec, pdata);
3323 if (IS_ERR_VALUE(ret))
3324 dev_err(msm8x10_wcd->dev, "%s: Bad Pdata\n", __func__);
3325
Fred Ohcf2f8582013-06-13 18:32:07 -07003326 registered_codec = codec;
3327 adsp_state_notifier =
3328 subsys_notif_register_notifier("adsp",
3329 &adsp_state_notifier_block);
3330 if (!adsp_state_notifier) {
3331 pr_err("%s: Failed to register adsp state notifier\n",
3332 __func__);
3333 registered_codec = NULL;
3334 return -ENOMEM;
3335 }
Kuirong Wang265f3592012-12-05 16:17:41 -08003336 return 0;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003337
3338exit_probe:
3339 return ret;
3340
Kuirong Wang265f3592012-12-05 16:17:41 -08003341}
3342
3343static int msm8x10_wcd_codec_remove(struct snd_soc_codec *codec)
3344{
Fred Oh4d716bb2013-07-30 10:14:46 -07003345 struct msm8x10_wcd_priv *pwcd_priv = snd_soc_codec_get_drvdata(codec);
3346 struct msm8x10_wcd *msm8x10_wcd = pwcd_priv->codec->control_data;
Fred Oh4d716bb2013-07-30 10:14:46 -07003347 pwcd_priv->on_demand_list[ON_DEMAND_CP].supply = NULL;
3348 atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_CP].ref, 0);
3349 pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].supply = NULL;
3350 atomic_set(&pwcd_priv->on_demand_list[ON_DEMAND_MICBIAS].ref, 0);
3351
3352 /* cleanup resmgr */
3353 wcd9xxx_resmgr_deinit(&pwcd_priv->resmgr);
3354
3355 iounmap(msm8x10_wcd->pdino_base);
Kuirong Wang265f3592012-12-05 16:17:41 -08003356 return 0;
3357}
3358
3359static struct snd_soc_codec_driver soc_codec_dev_msm8x10_wcd = {
3360 .probe = msm8x10_wcd_codec_probe,
3361 .remove = msm8x10_wcd_codec_remove,
3362
3363 .read = msm8x10_wcd_read,
3364 .write = msm8x10_wcd_write,
3365
3366 .readable_register = msm8x10_wcd_readable,
3367 .volatile_register = msm8x10_wcd_volatile,
3368
3369 .reg_cache_size = MSM8X10_WCD_CACHE_SIZE,
3370 .reg_cache_default = msm8x10_wcd_reset_reg_defaults,
3371 .reg_word_size = 1,
3372
3373 .controls = msm8x10_wcd_snd_controls,
3374 .num_controls = ARRAY_SIZE(msm8x10_wcd_snd_controls),
3375 .dapm_widgets = msm8x10_wcd_dapm_widgets,
3376 .num_dapm_widgets = ARRAY_SIZE(msm8x10_wcd_dapm_widgets),
3377 .dapm_routes = audio_map,
3378 .num_dapm_routes = ARRAY_SIZE(audio_map),
3379};
3380
Kuirong Wang49f506a2013-05-22 17:38:26 -07003381static int msm8x10_wcd_init_supplies(struct msm8x10_wcd *msm8x10,
Kuirong Wang91e52532013-03-31 14:24:22 -07003382 struct msm8x10_wcd_pdata *pdata)
3383{
3384 int ret;
3385 int i;
3386 msm8x10->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
3387 ARRAY_SIZE(pdata->regulator),
3388 GFP_KERNEL);
3389 if (!msm8x10->supplies) {
3390 ret = -ENOMEM;
3391 goto err;
3392 }
3393
3394 msm8x10->num_of_supplies = 0;
3395
3396 if (ARRAY_SIZE(pdata->regulator) > MAX_REGULATOR) {
3397 dev_err(msm8x10->dev, "%s: Array Size out of bound\n",
3398 __func__);
3399 ret = -EINVAL;
3400 goto err;
3401 }
3402
3403 for (i = 0; i < ARRAY_SIZE(pdata->regulator); i++) {
3404 if (pdata->regulator[i].name) {
3405 msm8x10->supplies[i].supply = pdata->regulator[i].name;
3406 msm8x10->num_of_supplies++;
3407 }
3408 }
3409
3410 ret = regulator_bulk_get(msm8x10->dev, msm8x10->num_of_supplies,
3411 msm8x10->supplies);
3412 if (ret != 0) {
3413 dev_err(msm8x10->dev, "Failed to get supplies: err = %d\n",
3414 ret);
3415 goto err_supplies;
3416 }
3417
3418 for (i = 0; i < msm8x10->num_of_supplies; i++) {
Kuirong Wang49f506a2013-05-22 17:38:26 -07003419 if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
3420 0)
3421 continue;
3422
Kuirong Wang91e52532013-03-31 14:24:22 -07003423 ret = regulator_set_voltage(msm8x10->supplies[i].consumer,
Kuirong Wang49f506a2013-05-22 17:38:26 -07003424 pdata->regulator[i].min_uV,
3425 pdata->regulator[i].max_uV);
Kuirong Wang91e52532013-03-31 14:24:22 -07003426 if (ret) {
3427 dev_err(msm8x10->dev, "%s: Setting regulator voltage failed for regulator %s err = %d\n",
3428 __func__, msm8x10->supplies[i].supply, ret);
3429 goto err_get;
3430 }
3431
3432 ret = regulator_set_optimum_mode(msm8x10->supplies[i].consumer,
3433 pdata->regulator[i].optimum_uA);
3434 if (ret < 0) {
3435 dev_err(msm8x10->dev, "%s: Setting regulator optimum mode failed for regulator %s err = %d\n",
3436 __func__, msm8x10->supplies[i].supply, ret);
3437 goto err_get;
Kuirong Wang49f506a2013-05-22 17:38:26 -07003438 } else {
3439 ret = 0;
Kuirong Wang91e52532013-03-31 14:24:22 -07003440 }
3441 }
3442
Kuirong Wang91e52532013-03-31 14:24:22 -07003443 return ret;
3444
Kuirong Wang91e52532013-03-31 14:24:22 -07003445err_get:
3446 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
3447err_supplies:
3448 kfree(msm8x10->supplies);
3449err:
3450 return ret;
3451}
3452
Kuirong Wang49f506a2013-05-22 17:38:26 -07003453static int msm8x10_wcd_enable_static_supplies(struct msm8x10_wcd *msm8x10,
3454 struct msm8x10_wcd_pdata *pdata)
3455{
3456 int i;
3457 int ret = 0;
3458
3459 for (i = 0; i < msm8x10->num_of_supplies; i++) {
3460 if (pdata->regulator[i].ondemand)
3461 continue;
3462 ret = regulator_enable(msm8x10->supplies[i].consumer);
3463 if (ret) {
3464 pr_err("%s: Failed to enable %s\n", __func__,
3465 msm8x10->supplies[i].supply);
3466 break;
3467 } else {
3468 pr_debug("%s: Enabled regulator %s\n", __func__,
3469 msm8x10->supplies[i].supply);
3470 }
3471 }
3472
3473 while (ret && --i)
3474 if (!pdata->regulator[i].ondemand)
3475 regulator_disable(msm8x10->supplies[i].consumer);
3476
3477 return ret;
3478}
3479
3480
3481
Kuirong Wang91e52532013-03-31 14:24:22 -07003482static void msm8x10_wcd_disable_supplies(struct msm8x10_wcd *msm8x10,
3483 struct msm8x10_wcd_pdata *pdata)
3484{
3485 int i;
3486
3487 regulator_bulk_disable(msm8x10->num_of_supplies,
3488 msm8x10->supplies);
3489 for (i = 0; i < msm8x10->num_of_supplies; i++) {
Kuirong Wang49f506a2013-05-22 17:38:26 -07003490 if (regulator_count_voltages(msm8x10->supplies[i].consumer) <=
3491 0)
3492 continue;
Kuirong Wang91e52532013-03-31 14:24:22 -07003493 regulator_set_voltage(msm8x10->supplies[i].consumer, 0,
3494 pdata->regulator[i].max_uV);
3495 regulator_set_optimum_mode(msm8x10->supplies[i].consumer, 0);
3496 }
3497 regulator_bulk_free(msm8x10->num_of_supplies, msm8x10->supplies);
3498 kfree(msm8x10->supplies);
3499}
3500
Kuirong Wang2e81d322013-05-30 17:52:36 -07003501static int msm8x10_wcd_pads_config(void)
Kuirong Wang91e52532013-03-31 14:24:22 -07003502{
Fred Oh4d716bb2013-07-30 10:14:46 -07003503 void __iomem *ppull = ioremap(MSM8x10_TLMM_CDC_PULL_CTL, 4);
Kuirong Wang2e81d322013-05-30 17:52:36 -07003504 /* Set I2C pads as pull up and rest of pads as no pull */
Fred Oh4d716bb2013-07-30 10:14:46 -07003505 iowrite32(0x03C00000, ppull);
Kuirong Wang2e81d322013-05-30 17:52:36 -07003506 usleep_range(100, 200);
Fred Oh4d716bb2013-07-30 10:14:46 -07003507
3508 iounmap(ppull);
Kuirong Wang91e52532013-03-31 14:24:22 -07003509 return 0;
3510}
Kuirong Wangae340de2013-05-30 18:11:07 -07003511
3512
3513static int msm8x10_wcd_clk_init(void)
3514{
Fred Oh4d716bb2013-07-30 10:14:46 -07003515 void __iomem *pdig1 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CFG_RCGR, 4);
3516 void __iomem *pdig2 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_M, 4);
3517 void __iomem *pdig3 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_N, 4);
3518 void __iomem *pdig4 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_D, 4);
3519 void __iomem *pdig5 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CBCR, 4);
3520 void __iomem *pdig6 = ioremap(MSM8X10_DINO_LPASS_DIGCODEC_CMD_RCGR, 4);
Kuirong Wangae340de2013-05-30 18:11:07 -07003521 /* Div-2 */
Fred Oh4d716bb2013-07-30 10:14:46 -07003522 iowrite32(0x3, pdig1);
3523 iowrite32(0x0, pdig2);
3524 iowrite32(0x0, pdig3);
3525 iowrite32(0x0, pdig4);
Kuirong Wangae340de2013-05-30 18:11:07 -07003526 /* Digital codec clock enable */
Fred Oh4d716bb2013-07-30 10:14:46 -07003527 iowrite32(0x1, pdig5);
Kuirong Wangae340de2013-05-30 18:11:07 -07003528 /* Set the update bit to make the settings go through */
Fred Oh4d716bb2013-07-30 10:14:46 -07003529 iowrite32(0x1, pdig6);
Kuirong Wangae340de2013-05-30 18:11:07 -07003530 usleep_range(100, 200);
Fred Oh4d716bb2013-07-30 10:14:46 -07003531
3532 iounmap(pdig1);
3533 iounmap(pdig2);
3534 iounmap(pdig3);
3535 iounmap(pdig4);
3536 iounmap(pdig5);
3537 iounmap(pdig6);
Kuirong Wangae340de2013-05-30 18:11:07 -07003538 return 0;
3539}
3540
Kuirong Wang91e52532013-03-31 14:24:22 -07003541static int msm8x10_wcd_device_init(struct msm8x10_wcd *msm8x10)
3542{
3543 mutex_init(&msm8x10->io_lock);
3544 mutex_init(&msm8x10->xfer_lock);
Kuirong Wang2e81d322013-05-30 17:52:36 -07003545 msm8x10_wcd_pads_config();
Kuirong Wangae340de2013-05-30 18:11:07 -07003546 msm8x10_wcd_clk_init();
Kuirong Wang91e52532013-03-31 14:24:22 -07003547 return 0;
3548}
3549
Bhalchandra Gajarece1fe592013-07-12 12:58:02 -07003550static struct intr_data interrupt_table[] = {
3551 {MSM8X10_WCD_IRQ_MBHC_INSERTION, true},
3552 {MSM8X10_WCD_IRQ_MBHC_POTENTIAL, true},
3553 {MSM8X10_WCD_IRQ_MBHC_RELEASE, true},
3554 {MSM8X10_WCD_IRQ_MBHC_PRESS, true},
3555 {MSM8X10_WCD_IRQ_MBHC_SHORT_TERM, true},
3556 {MSM8X10_WCD_IRQ_MBHC_REMOVAL, true},
3557 {MSM8X10_WCD_IRQ_MBHC_HS_DET, true},
3558 {MSM8X10_WCD_IRQ_RESERVED_0, false},
3559 {MSM8X10_WCD_IRQ_PA_STARTUP, false},
3560 {MSM8X10_WCD_IRQ_BG_PRECHARGE, false},
3561 {MSM8X10_WCD_IRQ_RESERVED_1, false},
3562 {MSM8X10_WCD_IRQ_EAR_PA_OCPL_FAULT, false},
3563 {MSM8X10_WCD_IRQ_EAR_PA_STARTUP, false},
3564 {MSM8X10_WCD_IRQ_SPKR_PA_OCPL_FAULT, false},
3565 {MSM8X10_WCD_IRQ_SPKR_CLIP_FAULT, false},
3566 {MSM8X10_WCD_IRQ_RESERVED_2, false},
3567 {MSM8X10_WCD_IRQ_HPH_L_PA_STARTUP, false},
3568 {MSM8X10_WCD_IRQ_HPH_R_PA_STARTUP, false},
3569 {MSM8X10_WCD_IRQ_HPH_PA_OCPL_FAULT, false},
3570 {MSM8X10_WCD_IRQ_HPH_PA_OCPR_FAULT, false},
3571 {MSM8X10_WCD_IRQ_RESERVED_3, false},
3572 {MSM8X10_WCD_IRQ_RESERVED_4, false},
3573 {MSM8X10_WCD_IRQ_RESERVED_5, false},
3574 {MSM8X10_WCD_IRQ_RESERVED_6, false},
3575};
3576
Kuirong Wang265f3592012-12-05 16:17:41 -08003577static int __devinit msm8x10_wcd_i2c_probe(struct i2c_client *client,
3578 const struct i2c_device_id *id)
3579{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003580 int ret = 0;
3581 struct msm8x10_wcd *msm8x10 = NULL;
Kuirong Wang265f3592012-12-05 16:17:41 -08003582 struct msm8x10_wcd_pdata *pdata;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003583 static int device_id;
3584 struct device *dev;
Kuirong Wang2e81d322013-05-30 17:52:36 -07003585 enum apr_subsys_state q6_state;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003586 struct wcd9xxx_core_resource *core_res;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003587
Kuirong Wang2e81d322013-05-30 17:52:36 -07003588 dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
3589 __func__, __LINE__, client->addr, device_id);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003590
Kuirong Wang2e81d322013-05-30 17:52:36 -07003591 switch (client->addr) {
3592 case HELICON_CORE_0_I2C_ADDR:
3593 msm8x10_wcd_modules[0].client = client;
3594 break;
3595 case HELICON_CORE_1_I2C_ADDR:
3596 msm8x10_wcd_modules[1].client = client;
3597 goto rtn;
3598 case HELICON_CORE_2_I2C_ADDR:
3599 msm8x10_wcd_modules[2].client = client;
3600 goto rtn;
3601 case HELICON_CORE_3_I2C_ADDR:
3602 msm8x10_wcd_modules[3].client = client;
3603 goto rtn;
3604 default:
3605 ret = -EINVAL;
Kuirong Wang91e52532013-03-31 14:24:22 -07003606 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003607 }
3608
Kuirong Wang2e81d322013-05-30 17:52:36 -07003609 q6_state = apr_get_q6_state();
3610 if ((q6_state == APR_SUBSYS_DOWN) &&
3611 (client->addr == HELICON_CORE_0_I2C_ADDR)) {
3612 dev_info(&client->dev, "defering %s, adsp_state %d\n", __func__,
3613 q6_state);
3614 return -EPROBE_DEFER;
3615 } else
3616 dev_info(&client->dev, "adsp is ready\n");
3617
3618 dev_dbg(&client->dev, "%s(%d):slave addr = 0x%x device_id = %d\n",
3619 __func__, __LINE__, client->addr, device_id);
3620
3621 if (client->addr != HELICON_CORE_0_I2C_ADDR)
3622 goto rtn;
3623
Kuirong Wang14b3fb92013-06-27 17:28:17 -07003624 dev_set_name(&client->dev, "%s", MSM8X10_CODEC_NAME);
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003625 dev = &client->dev;
Kuirong Wang265f3592012-12-05 16:17:41 -08003626 if (client->dev.of_node) {
3627 dev_dbg(&client->dev, "%s:Platform data from device tree\n",
3628 __func__);
3629 pdata = msm8x10_wcd_populate_dt_pdata(&client->dev);
Bhalchandra Gajare9943aa62013-10-09 18:40:11 -07003630 if (!pdata) {
3631 dev_err(&client->dev, "%s: Failed to parse pdata from device tree\n",
3632 __func__);
3633 goto rtn;
3634 }
Kuirong Wang265f3592012-12-05 16:17:41 -08003635 client->dev.platform_data = pdata;
3636 } else {
3637 dev_dbg(&client->dev, "%s:Platform data from board file\n",
3638 __func__);
3639 pdata = client->dev.platform_data;
3640 }
3641
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003642 msm8x10 = kzalloc(sizeof(struct msm8x10_wcd), GFP_KERNEL);
3643 if (msm8x10 == NULL) {
3644 dev_err(&client->dev,
3645 "%s: error, allocation failed\n", __func__);
3646 ret = -ENOMEM;
Kuirong Wang91e52532013-03-31 14:24:22 -07003647 goto rtn;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003648 }
Kuirong Wang265f3592012-12-05 16:17:41 -08003649
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003650 msm8x10->dev = &client->dev;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003651 msm8x10->read_dev = __msm8x10_wcd_reg_read;
3652 msm8x10->write_dev = __msm8x10_wcd_reg_write;
Kuirong Wang49f506a2013-05-22 17:38:26 -07003653 ret = msm8x10_wcd_init_supplies(msm8x10, pdata);
Kuirong Wang91e52532013-03-31 14:24:22 -07003654 if (ret) {
3655 dev_err(&client->dev, "%s: Fail to enable Codec supplies\n",
3656 __func__);
3657 goto err_codec;
3658 }
Kuirong Wang49f506a2013-05-22 17:38:26 -07003659
3660 ret = msm8x10_wcd_enable_static_supplies(msm8x10, pdata);
3661 if (ret) {
3662 pr_err("%s: Fail to enable Codec pre-reset supplies\n",
3663 __func__);
3664 goto err_codec;
3665 }
3666 usleep_range(5, 5);
3667
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003668 ret = msm8x10_wcd_device_init(msm8x10);
3669 if (ret) {
3670 dev_err(&client->dev,
3671 "%s:msm8x10_wcd_device_init failed with error %d\n",
3672 __func__, ret);
Kuirong Wang91e52532013-03-31 14:24:22 -07003673 goto err_supplies;
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003674 }
3675 dev_set_drvdata(&client->dev, msm8x10);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003676 core_res = &msm8x10->wcd9xxx_res;
Bhalchandra Gajarece1fe592013-07-12 12:58:02 -07003677 core_res->parent = msm8x10;
3678 core_res->dev = msm8x10->dev;
3679 core_res->intr_table = interrupt_table;
3680 core_res->intr_table_size = ARRAY_SIZE(interrupt_table);
3681
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003682 wcd9xxx_core_res_init(core_res,
3683 MSM8X10_WCD_NUM_IRQS,
3684 MSM8X10_WCD_NUM_IRQ_REGS,
3685 msm8x10_wcd_reg_read,
3686 msm8x10_wcd_reg_write,
Yeleswarapu, Nagaradheshbbba6e32013-12-20 18:09:17 +05303687 msm8x10_wcd_bulk_read,
3688 msm8x10_wcd_bulk_write);
Bhalchandra Gajarece1fe592013-07-12 12:58:02 -07003689 if (wcd9xxx_core_irq_init(core_res)) {
3690 dev_err(msm8x10->dev,
3691 "%s: irq initialization failed\n", __func__);
3692 } else {
3693 dev_info(msm8x10->dev,
3694 "%s: irq initialization passed\n", __func__);
3695 }
3696
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003697 ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_msm8x10_wcd,
3698 msm8x10_wcd_i2s_dai,
3699 ARRAY_SIZE(msm8x10_wcd_i2s_dai));
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003700 if (ret) {
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003701 dev_err(&client->dev,
3702 "%s:snd_soc_register_codec failed with error %d\n",
3703 __func__, ret);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003704 } else {
3705 wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_I2C);
Kuirong Wang91e52532013-03-31 14:24:22 -07003706 goto rtn;
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003707 }
Kuirong Wang91e52532013-03-31 14:24:22 -07003708
3709err_supplies:
3710 msm8x10_wcd_disable_supplies(msm8x10, pdata);
3711err_codec:
3712 kfree(msm8x10);
3713rtn:
Kuirong Wang265f3592012-12-05 16:17:41 -08003714 return ret;
3715}
3716
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003717static void msm8x10_wcd_device_exit(struct msm8x10_wcd *msm8x10)
3718{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003719 mutex_destroy(&msm8x10->io_lock);
3720 mutex_destroy(&msm8x10->xfer_lock);
3721 kfree(msm8x10);
3722}
3723
Kuirong Wang265f3592012-12-05 16:17:41 -08003724static int __devexit msm8x10_wcd_i2c_remove(struct i2c_client *client)
3725{
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003726 struct msm8x10_wcd *msm8x10 = dev_get_drvdata(&client->dev);
3727
3728 msm8x10_wcd_device_exit(msm8x10);
Kuirong Wang265f3592012-12-05 16:17:41 -08003729 return 0;
3730}
3731
3732static struct i2c_device_id msm8x10_wcd_id_table[] = {
3733 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_TOP_LEVEL},
3734 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_ANALOG},
3735 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_1},
3736 {"msm8x10-wcd-i2c", MSM8X10_WCD_I2C_DIGITAL_2},
3737 {}
3738};
3739
3740static struct of_device_id msm8x10_wcd_of_match[] = {
3741 { .compatible = "qcom,msm8x10-wcd-i2c",},
3742 { },
3743};
3744
Bhalchandra Gajare812e31e2013-10-17 15:22:35 -07003745#ifdef CONFIG_PM
3746static int msm8x10_wcd_i2c_resume(struct device *dev)
3747{
3748 struct i2c_client *client = to_i2c_client(dev);
3749 struct msm8x10_wcd_priv *priv = i2c_get_clientdata(client);
3750 struct msm8x10_wcd *msm8x10;
3751 int ret = 0;
3752
3753 if (client->addr == HELICON_CORE_0_I2C_ADDR) {
3754 if (!priv || !priv->codec || !priv->codec->control_data) {
3755 ret = -EINVAL;
3756 dev_err(dev, "%s: Invalid client data\n", __func__);
3757 goto rtn;
3758 }
3759 msm8x10 = priv->codec->control_data;
3760 return wcd9xxx_core_res_resume(&msm8x10->wcd9xxx_res);
3761 }
3762rtn:
3763 return 0;
3764}
3765
3766static int msm8x10_wcd_i2c_suspend(struct device *dev)
3767{
3768 struct i2c_client *client = to_i2c_client(dev);
3769 struct msm8x10_wcd_priv *priv = i2c_get_clientdata(client);
3770 struct msm8x10_wcd *msm8x10;
3771 int ret = 0;
3772
3773 if (client->addr == HELICON_CORE_0_I2C_ADDR) {
3774 if (!priv || !priv->codec || !priv->codec->control_data) {
3775 ret = -EINVAL;
3776 dev_err(dev, "%s: Invalid client data\n", __func__);
3777 goto rtn;
3778 }
3779 msm8x10 = priv->codec->control_data;
3780 return wcd9xxx_core_res_suspend(&msm8x10->wcd9xxx_res,
3781 PMSG_SUSPEND);
3782 }
3783
3784rtn:
3785 return ret;
3786}
3787
3788static SIMPLE_DEV_PM_OPS(msm8x1_wcd_pm_ops, msm8x10_wcd_i2c_suspend,
3789 msm8x10_wcd_i2c_resume);
3790#endif
Kuirong Wang265f3592012-12-05 16:17:41 -08003791
3792static struct i2c_driver msm8x10_wcd_i2c_driver = {
3793 .driver = {
3794 .owner = THIS_MODULE,
3795 .name = "msm8x10-wcd-i2c-core",
Bhalchandra Gajare812e31e2013-10-17 15:22:35 -07003796 .of_match_table = msm8x10_wcd_of_match,
3797#ifdef CONFIG_PM
3798 .pm = &msm8x1_wcd_pm_ops,
3799#endif
Kuirong Wang265f3592012-12-05 16:17:41 -08003800 },
3801 .id_table = msm8x10_wcd_id_table,
3802 .probe = msm8x10_wcd_i2c_probe,
3803 .remove = __devexit_p(msm8x10_wcd_i2c_remove),
3804};
3805
3806static int __init msm8x10_wcd_codec_init(void)
3807{
3808 int ret;
3809
3810 pr_debug("%s:\n", __func__);
Bhalchandra Gajared610c6b2013-07-11 16:28:56 -07003811 wcd9xxx_set_intf_type(WCD9XXX_INTERFACE_TYPE_PROBING);
Kuirong Wang265f3592012-12-05 16:17:41 -08003812 ret = i2c_add_driver(&msm8x10_wcd_i2c_driver);
3813 if (ret != 0)
Kuirong Wang3a6408d2013-02-20 17:46:46 -08003814 pr_err("%s: Failed to add msm8x10 wcd I2C driver - error %d\n",
3815 __func__, ret);
Kuirong Wang265f3592012-12-05 16:17:41 -08003816 return ret;
3817}
3818
3819static void __exit msm8x10_wcd_codec_exit(void)
3820{
3821 i2c_del_driver(&msm8x10_wcd_i2c_driver);
3822}
3823
3824
3825module_init(msm8x10_wcd_codec_init);
3826module_exit(msm8x10_wcd_codec_exit);
3827
3828MODULE_DESCRIPTION("MSM8x10 Audio codec driver");
3829MODULE_LICENSE("GPL v2");
3830MODULE_DEVICE_TABLE(i2c, msm8x10_wcd_id_table);
3831