blob: 90d8723eba7fc3ce59e4f2b5d7f5db03b7ecd1ee [file] [log] [blame]
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/clk.h>
14#include <linux/delay.h>
15#include <linux/gpio.h>
16#include <linux/mfd/pm8xxx/pm8018.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -070019#include <linux/io.h>
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -080020#include <sound/core.h>
21#include <sound/soc.h>
22#include <sound/soc-dapm.h>
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -080023#include <sound/pcm.h>
24#include <sound/jack.h>
25#include <asm/mach-types.h>
26#include <mach/socinfo.h>
27#include "msm-pcm-routing.h"
28#include "../codecs/wcd9310.h"
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -070029#include <mach/gpiomux.h>
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -080030
31/* 9615 machine driver */
32
33#define PM8018_GPIO_BASE NR_GPIO_IRQS
34#define PM8018_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8018_GPIO_BASE)
35
36#define MDM9615_SPK_ON 1
37#define MDM9615_SPK_OFF 0
38
39#define MDM9615_SLIM_0_RX_MAX_CHANNELS 2
40#define MDM9615_SLIM_0_TX_MAX_CHANNELS 4
41
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -070042#define SAMPLE_RATE_8KHZ 8000
43#define SAMPLE_RATE_16KHZ 16000
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -080044
45#define BOTTOM_SPK_AMP_POS 0x1
46#define BOTTOM_SPK_AMP_NEG 0x2
47#define TOP_SPK_AMP_POS 0x4
48#define TOP_SPK_AMP_NEG 0x8
49
Shiv Maliyappanahallia23ea702012-06-01 15:19:46 -070050#define GPIO_AUX_PCM_DOUT 23
51#define GPIO_AUX_PCM_DIN 22
52#define GPIO_AUX_PCM_SYNC 21
53#define GPIO_AUX_PCM_CLK 20
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -080054
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -070055#define GPIO_SEC_AUX_PCM_DOUT 28
56#define GPIO_SEC_AUX_PCM_DIN 27
57#define GPIO_SEC_AUX_PCM_SYNC 26
58#define GPIO_SEC_AUX_PCM_CLK 25
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -080059
60#define TABLA_EXT_CLK_RATE 12288000
61
62#define TABLA_MBHC_DEF_BUTTONS 8
63#define TABLA_MBHC_DEF_RLOADS 5
64
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -070065/*
66 * Added for I2S
67 */
68#define GPIO_SPKR_I2S_MCLK 24
69#define GPIO_PRIM_I2S_SCK 20
70#define GPIO_PRIM_I2S_DOUT 23
71#define GPIO_PRIM_I2S_WS 21
72#define GPIO_PRIM_I2S_DIN 22
73#define GPIO_SEC_I2S_SCK 25
74#define GPIO_SEC_I2S_WS 26
75#define GPIO_SEC_I2S_DOUT 28
76#define GPIO_SEC_I2S_DIN 27
77
78static struct gpiomux_setting cdc_i2s_mclk = {
79 .func = GPIOMUX_FUNC_1,
80 .drv = GPIOMUX_DRV_8MA,
81 .pull = GPIOMUX_PULL_NONE,
82};
83
84static struct gpiomux_setting cdc_i2s_sclk = {
85 .func = GPIOMUX_FUNC_1,
86 .drv = GPIOMUX_DRV_8MA,
87 .pull = GPIOMUX_PULL_NONE,
88};
89
90static struct gpiomux_setting cdc_i2s_dout = {
91 .func = GPIOMUX_FUNC_1,
92 .drv = GPIOMUX_DRV_8MA,
93 .pull = GPIOMUX_PULL_NONE,
94};
95
96static struct gpiomux_setting cdc_i2s_ws = {
97 .func = GPIOMUX_FUNC_1,
98 .drv = GPIOMUX_DRV_8MA,
99 .pull = GPIOMUX_PULL_NONE,
100};
101
102static struct gpiomux_setting cdc_i2s_din = {
103 .func = GPIOMUX_FUNC_1,
104 .drv = GPIOMUX_DRV_8MA,
105 .pull = GPIOMUX_PULL_NONE,
106};
107
108
109static struct msm_gpiomux_config msm9615_audio_prim_i2s_codec_configs[] = {
110 {
111 .gpio = GPIO_SPKR_I2S_MCLK,
112 .settings = {
113 [GPIOMUX_SUSPENDED] = &cdc_i2s_mclk,
114 },
115 },
116 {
117 .gpio = GPIO_PRIM_I2S_SCK,
118 .settings = {
119 [GPIOMUX_SUSPENDED] = &cdc_i2s_sclk,
120 },
121 },
122 {
123 .gpio = GPIO_PRIM_I2S_DOUT,
124 .settings = {
125 [GPIOMUX_SUSPENDED] = &cdc_i2s_dout,
126 },
127 },
128 {
129 .gpio = GPIO_PRIM_I2S_WS,
130 .settings = {
131 [GPIOMUX_SUSPENDED] = &cdc_i2s_ws,
132 },
133 },
134 {
135 .gpio = GPIO_PRIM_I2S_DIN,
136 .settings = {
137 [GPIOMUX_SUSPENDED] = &cdc_i2s_din,
138 },
139 },
140};
141
142/* Physical address for LPA CSR
143 * LPA SIF mux registers. These are
144 * ioremap( ) for Virtual address.
145 */
146#define LPASS_CSR_BASE 0x28000000
147#define LPA_IF_BASE 0x28100000
148#define SIF_MUX_REG_BASE (LPASS_CSR_BASE + 0x00000000)
149#define LPA_IF_REG_BASE (LPA_IF_BASE + 0x00000000)
150#define LPASS_SIF_MUX_ADDR (SIF_MUX_REG_BASE + 0x00004000)
151#define LPAIF_SPARE_ADDR (LPA_IF_REG_BASE + 0x00000070)
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700152#define SEC_PCM_PORT_SLC_ADDR 0x00802074
153/* bits 2:0 should be updated with 100 to select SDC2 */
154#define SEC_PCM_PORT_SLC_VALUE 0x4
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -0700155/* SIF & SPARE MUX Values */
156#define MSM_SIF_FUNC_PCM 0
157#define MSM_SIF_FUNC_I2S_MIC 1
158#define MSM_SIF_FUNC_I2S_SPKR 2
159#define MSM_LPAIF_SPARE_DISABLE 0x0
160#define MSM_LPAIF_SPARE_BOTH_ENABLE 0x3
161
162/* I2S INTF CTL */
163#define MSM_INTF_PRIM 0
164#define MSM_INTF_SECN 1
165#define MSM_INTF_BOTH 2
166
167/* I2S Dir CTL */
168#define MSM_DIR_RX 0
169#define MSM_DIR_TX 1
170#define MSM_DIR_BOTH 2
171#define MSM_DIR_MAX 3
172
173/* I2S HW Params */
174#define NO_OF_BITS_PER_SAMPLE 16
175#define I2S_MIC_SCLK_RATE 1536000
176static int msm9615_i2s_rx_ch = 1;
177static int msm9615_i2s_tx_ch = 1;
178static int msm9615_i2s_spk_control;
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700179
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -0700180/* SIF mux bit mask & shift */
181#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK 0x30000
182#define LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT 0x10
183#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK 0x3
184#define LPASS_SIF_MUX_CTL_SEC_MUX_SEL_SHFT 0x0
185
186#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK 0x3
187#define LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT 0x2
188#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK 0x3
189#define LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT 0x0
190
191static u32 spare_shadow;
192static u32 sif_shadow;
193
Shiv Maliyappanahallia23ea702012-06-01 15:19:46 -0700194static atomic_t msm9615_auxpcm_ref;
195static atomic_t msm9615_sec_auxpcm_ref;
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -0700196
197struct msm_i2s_mux_ctl {
198 const u8 sifconfig;
199 const u8 spareconfig;
200};
201struct msm_clk {
202 struct clk *osr_clk;
203 struct clk *bit_clk;
204 int clk_enable;
205};
206struct msm_i2s_clk {
207 struct msm_clk rx_clk;
208 struct msm_clk tx_clk;
209};
210struct msm_i2s_ctl {
211 struct msm_i2s_clk prim_clk;
212 struct msm_i2s_clk sec_clk;
213 struct msm_i2s_mux_ctl mux_ctl[MSM_DIR_MAX];
214 u8 intf_status[MSM_INTF_BOTH][MSM_DIR_BOTH];
215 void *sif_virt_addr;
216 void *spare_virt_addr;
217};
218static struct msm_i2s_ctl msm9x15_i2s_ctl = {
219 {{NULL, NULL, 0}, {NULL, NULL, 0} }, /* prim_clk */
220 {{NULL, NULL, 0}, {NULL, NULL, 0} }, /* sec_clk */
221 /* mux_ctl */
222 {
223 /* Rx path only */
224 { MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_DISABLE },
225 /* Tx path only */
226 { MSM_SIF_FUNC_I2S_MIC, MSM_LPAIF_SPARE_DISABLE },
227 /* Rx + Tx path only */
228 { MSM_SIF_FUNC_I2S_SPKR, MSM_LPAIF_SPARE_BOTH_ENABLE },
229 },
230 /* intf_status */
231 {
232 /* Prim I2S */
233 {0, 0},
234 /* Sec I2S */
235 {0, 0}
236 },
237 /* sif_virt_addr */
238 NULL,
239 /* spare_virt_addr */
240 NULL,
241};
242
243enum msm9x15_set_i2s_clk {
244 MSM_I2S_CLK_SET_FALSE,
245 MSM_I2S_CLK_SET_TRUE,
246 MSM_I2S_CLK_SET_RATE0,
247};
248/*
249 * Added for I2S
250 */
251
252static u32 top_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(3);
253static u32 bottom_spk_pamp_gpio = PM8018_GPIO_PM_TO_SYS(5);
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -0700254
255void *sif_virt_addr;
256void *secpcm_portslc_virt_addr;
257
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800258static int mdm9615_spk_control;
259static int mdm9615_ext_bottom_spk_pamp;
260static int mdm9615_ext_top_spk_pamp;
261static int mdm9615_slim_0_rx_ch = 1;
262static int mdm9615_slim_0_tx_ch = 1;
263
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -0700264static int mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800265static int mdm9615_btsco_ch = 1;
266
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -0700267static int mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
268
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800269static struct clk *codec_clk;
270static int clk_users;
271
272static int mdm9615_headset_gpios_configured;
273
274static struct snd_soc_jack hs_jack;
275static struct snd_soc_jack button_jack;
276
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700277static int mdm9615_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
278 bool dapm);
279static struct tabla_mbhc_config mbhc_cfg = {
280 .headset_jack = &hs_jack,
281 .button_jack = &button_jack,
282 .read_fw_bin = false,
283 .calibration = NULL,
284 .micbias = TABLA_MICBIAS2,
285 .mclk_cb_fn = mdm9615_enable_codec_ext_clk,
286 .mclk_rate = TABLA_EXT_CLK_RATE,
287 .gpio = 0,
288 .gpio_irq = 0,
289 .gpio_level_insert = 1,
290};
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800291
292static void mdm9615_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
293{
294 int ret = 0;
295
296 struct pm_gpio param = {
297 .direction = PM_GPIO_DIR_OUT,
298 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
299 .output_value = 1,
300 .pull = PM_GPIO_PULL_NO,
301 .vin_sel = PM_GPIO_VIN_S4,
302 .out_strength = PM_GPIO_STRENGTH_MED,
303 .function = PM_GPIO_FUNC_NORMAL,
304 };
305
306 if (spk_amp_gpio == bottom_spk_pamp_gpio) {
307
308 ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
309 if (ret) {
310 pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
311 __func__, bottom_spk_pamp_gpio);
312 return;
313 }
314 ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
315 if (ret)
316 pr_err("%s: Failed to configure Bottom Spk Ampl"
317 " gpio %u\n", __func__, bottom_spk_pamp_gpio);
318 else {
319 pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
320 gpio_direction_output(bottom_spk_pamp_gpio, 1);
321 }
322
323 } else if (spk_amp_gpio == top_spk_pamp_gpio) {
324
325 ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
326 if (ret) {
327 pr_err("%s: Error requesting GPIO %d\n", __func__,
328 top_spk_pamp_gpio);
329 return;
330 }
331 ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
332 if (ret)
333 pr_err("%s: Failed to configure Top Spk Ampl"
334 " gpio %u\n", __func__, top_spk_pamp_gpio);
335 else {
336 pr_debug("%s: enable Top spkr amp gpio\n", __func__);
337 gpio_direction_output(top_spk_pamp_gpio, 1);
338 }
339 } else {
340 pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
341 " gpio = %u\n", __func__, spk_amp_gpio);
342 return;
343 }
344}
345
346static void mdm9615_ext_spk_power_amp_on(u32 spk)
347{
348 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
349
350 if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
351 (mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
352
353 pr_debug("%s() External Bottom Speaker Ampl already "
354 "turned on. spk = 0x%08x\n", __func__, spk);
355 return;
356 }
357
358 mdm9615_ext_bottom_spk_pamp |= spk;
359
360 if ((mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
361 (mdm9615_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
362
363 mdm9615_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
364 pr_debug("%s: slepping 4 ms after turning on external "
365 " Bottom Speaker Ampl\n", __func__);
366 usleep_range(4000, 4000);
367 }
368
369 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
370
371 if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
372 (mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
373
374 pr_debug("%s() External Top Speaker Ampl already"
375 "turned on. spk = 0x%08x\n", __func__, spk);
376 return;
377 }
378
379 mdm9615_ext_top_spk_pamp |= spk;
380
381 if ((mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
382 (mdm9615_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
383
384 mdm9615_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
385 pr_debug("%s: sleeping 4 ms after turning on "
386 " external Top Speaker Ampl\n", __func__);
387 usleep_range(4000, 4000);
388 }
389 } else {
390
391 pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
392 __func__, spk);
393 return;
394 }
395}
396
397static void mdm9615_ext_spk_power_amp_off(u32 spk)
398{
399 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
400
401 if (!mdm9615_ext_bottom_spk_pamp)
402 return;
403
404 gpio_direction_output(bottom_spk_pamp_gpio, 0);
405 gpio_free(bottom_spk_pamp_gpio);
406 mdm9615_ext_bottom_spk_pamp = 0;
407
408 pr_debug("%s: sleeping 4 ms after turning off external Bottom"
409 " Speaker Ampl\n", __func__);
410
411 usleep_range(4000, 4000);
412
413 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
414
415 if (!mdm9615_ext_top_spk_pamp)
416 return;
417
418 gpio_direction_output(top_spk_pamp_gpio, 0);
419 gpio_free(top_spk_pamp_gpio);
420 mdm9615_ext_top_spk_pamp = 0;
421
422 pr_debug("%s: sleeping 4 ms after turning off external Top"
423 " Spkaker Ampl\n", __func__);
424
425 usleep_range(4000, 4000);
426 } else {
427
428 pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
429 __func__, spk);
430 return;
431 }
432}
433
434static void mdm9615_ext_control(struct snd_soc_codec *codec)
435{
436 struct snd_soc_dapm_context *dapm = &codec->dapm;
437
438 pr_debug("%s: mdm9615_spk_control = %d", __func__, mdm9615_spk_control);
439 if (mdm9615_spk_control == MDM9615_SPK_ON) {
440 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
441 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
442 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
443 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
444 } else {
445 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
446 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
447 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
448 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
449 }
450
451 snd_soc_dapm_sync(dapm);
452}
453
454static int mdm9615_get_spk(struct snd_kcontrol *kcontrol,
455 struct snd_ctl_elem_value *ucontrol)
456{
457 pr_debug("%s: mdm9615_spk_control = %d", __func__, mdm9615_spk_control);
458 ucontrol->value.integer.value[0] = mdm9615_spk_control;
459 return 0;
460}
461static int mdm9615_set_spk(struct snd_kcontrol *kcontrol,
462 struct snd_ctl_elem_value *ucontrol)
463{
464 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
465
466 pr_debug("%s()\n", __func__);
467 if (mdm9615_spk_control == ucontrol->value.integer.value[0])
468 return 0;
469
470 mdm9615_spk_control = ucontrol->value.integer.value[0];
471 mdm9615_ext_control(codec);
472 return 1;
473}
474static int mdm9615_spkramp_event(struct snd_soc_dapm_widget *w,
475 struct snd_kcontrol *k, int event)
476{
477 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
478
479 if (SND_SOC_DAPM_EVENT_ON(event)) {
480 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
481 mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
482 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
483 mdm9615_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
484 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
485 mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
486 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
487 mdm9615_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
488 else {
489 pr_err("%s() Invalid Speaker Widget = %s\n",
490 __func__, w->name);
491 return -EINVAL;
492 }
493
494 } else {
495 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
496 mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
497 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
498 mdm9615_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
499 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
500 mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
501 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
502 mdm9615_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
503 else {
504 pr_err("%s() Invalid Speaker Widget = %s\n",
505 __func__, w->name);
506 return -EINVAL;
507 }
508 }
509 return 0;
510}
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700511static int mdm9615_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
512 bool dapm)
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800513{
514 pr_debug("%s: enable = %d\n", __func__, enable);
515 if (enable) {
516 clk_users++;
517 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
518 if (clk_users != 1)
519 return 0;
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -0700520 if (IS_ERR(codec_clk)) {
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800521
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800522 pr_err("%s: Error setting Tabla MCLK\n", __func__);
523 clk_users--;
524 return -EINVAL;
525 }
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -0700526 clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
527 clk_prepare_enable(codec_clk);
528 tabla_mclk_enable(codec, 1, dapm);
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800529 } else {
530 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
531 if (clk_users == 0)
532 return 0;
533 clk_users--;
534 if (!clk_users) {
535 pr_debug("%s: disabling MCLK. clk_users = %d\n",
536 __func__, clk_users);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700537 tabla_mclk_enable(codec, 0, dapm);
Asish Bhattacharya4776d962012-04-25 12:08:09 +0530538 clk_disable_unprepare(codec_clk);
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800539 }
540 }
541 return 0;
542}
543
544static int mdm9615_mclk_event(struct snd_soc_dapm_widget *w,
545 struct snd_kcontrol *kcontrol, int event)
546{
547 pr_debug("%s: event = %d\n", __func__, event);
548
549 switch (event) {
550 case SND_SOC_DAPM_PRE_PMU:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700551 return mdm9615_enable_codec_ext_clk(w->codec, 1, true);
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800552 case SND_SOC_DAPM_POST_PMD:
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700553 return mdm9615_enable_codec_ext_clk(w->codec, 0, true);
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800554 }
555 return 0;
556}
557
558static const struct snd_soc_dapm_widget mdm9615_dapm_widgets[] = {
559
560 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
561 mdm9615_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
562
563 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", mdm9615_spkramp_event),
564 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", mdm9615_spkramp_event),
565
566 SND_SOC_DAPM_SPK("Ext Spk Top Pos", mdm9615_spkramp_event),
567 SND_SOC_DAPM_SPK("Ext Spk Top Neg", mdm9615_spkramp_event),
568
569 SND_SOC_DAPM_MIC("Handset Mic", NULL),
570 SND_SOC_DAPM_MIC("Headset Mic", NULL),
571 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
572 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
573 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
574
575 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
576 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
577 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
578 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
579 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
580 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
581
582};
583
584static const struct snd_soc_dapm_route common_audio_map[] = {
585
586 {"RX_BIAS", NULL, "MCLK"},
587 {"LDO_H", NULL, "MCLK"},
588
589 /* Speaker path */
590 {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
591 {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
592
593 {"Ext Spk Top Pos", NULL, "LINEOUT2"},
594 {"Ext Spk Top Neg", NULL, "LINEOUT4"},
595
596 /* Microphone path */
597 {"AMIC1", NULL, "MIC BIAS1 External"},
598 {"MIC BIAS1 External", NULL, "Handset Mic"},
599
600 {"AMIC2", NULL, "MIC BIAS2 External"},
601 {"MIC BIAS2 External", NULL, "Headset Mic"},
602
603 /**
604 * AMIC3 and AMIC4 inputs are connected to ANC microphones
605 * These mics are biased differently on CDP and FLUID
606 * routing entries below are based on bias arrangement
607 * on FLUID.
608 */
609 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
610 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
611
612 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
613 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
614
615 {"HEADPHONE", NULL, "LDO_H"},
616
617 /**
618 * The digital Mic routes are setup considering
619 * fluid as default device.
620 */
621
622 /**
623 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
624 * Digital Mic GM5 on CDP mainboard.
625 * Conncted to DMIC2 Input on Tabla codec.
626 */
627 {"DMIC2", NULL, "MIC BIAS1 External"},
628 {"MIC BIAS1 External", NULL, "Digital Mic1"},
629
630 /**
631 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
632 * Digital Mic GM6 on CDP mainboard.
633 * Conncted to DMIC1 Input on Tabla codec.
634 */
635 {"DMIC1", NULL, "MIC BIAS1 External"},
636 {"MIC BIAS1 External", NULL, "Digital Mic2"},
637
638 /**
639 * Digital Mic3. Back Bottom Digital Mic on Fluid.
640 * Digital Mic GM1 on CDP mainboard.
641 * Conncted to DMIC4 Input on Tabla codec.
642 */
643 {"DMIC4", NULL, "MIC BIAS3 External"},
644 {"MIC BIAS3 External", NULL, "Digital Mic3"},
645
646 /**
647 * Digital Mic4. Back top Digital Mic on Fluid.
648 * Digital Mic GM2 on CDP mainboard.
649 * Conncted to DMIC3 Input on Tabla codec.
650 */
651 {"DMIC3", NULL, "MIC BIAS3 External"},
652 {"MIC BIAS3 External", NULL, "Digital Mic4"},
653
654 /**
655 * Digital Mic5. Front top Digital Mic on Fluid.
656 * Digital Mic GM3 on CDP mainboard.
657 * Conncted to DMIC5 Input on Tabla codec.
658 */
659 {"DMIC5", NULL, "MIC BIAS4 External"},
660 {"MIC BIAS4 External", NULL, "Digital Mic5"},
661
662 /* Tabla digital Mic6 - back bottom digital Mic on Liquid and
663 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
664 */
665 {"DMIC6", NULL, "MIC BIAS4 External"},
666 {"MIC BIAS4 External", NULL, "Digital Mic6"},
667};
668
669static const char *spk_function[] = {"Off", "On"};
670static const char *slim0_rx_ch_text[] = {"One", "Two"};
671static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
672
673static const struct soc_enum mdm9615_enum[] = {
674 SOC_ENUM_SINGLE_EXT(2, spk_function),
675 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
676 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
677};
678
679static const char *btsco_rate_text[] = {"8000", "16000"};
680static const struct soc_enum mdm9615_btsco_enum[] = {
681 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
682};
683
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -0700684static const char * const auxpcm_rate_text[] = {"rate_8000", "rate_16000"};
685static const struct soc_enum mdm9615_auxpcm_enum[] = {
686 SOC_ENUM_SINGLE_EXT(2, auxpcm_rate_text),
687};
688
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800689static int mdm9615_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
690 struct snd_ctl_elem_value *ucontrol)
691{
692 pr_debug("%s: mdm9615_slim_0_rx_ch = %d\n", __func__,
693 mdm9615_slim_0_rx_ch);
694 ucontrol->value.integer.value[0] = mdm9615_slim_0_rx_ch - 1;
695 return 0;
696}
697
698static int mdm9615_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
699 struct snd_ctl_elem_value *ucontrol)
700{
701 mdm9615_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
702
703 pr_debug("%s: mdm9615_slim_0_rx_ch = %d\n", __func__,
704 mdm9615_slim_0_rx_ch);
705 return 1;
706}
707
708static int mdm9615_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
709 struct snd_ctl_elem_value *ucontrol)
710{
711 pr_debug("%s: mdm9615_slim_0_tx_ch = %d\n", __func__,
712 mdm9615_slim_0_tx_ch);
713 ucontrol->value.integer.value[0] = mdm9615_slim_0_tx_ch - 1;
714 return 0;
715}
716
717static int mdm9615_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
718 struct snd_ctl_elem_value *ucontrol)
719{
720 mdm9615_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
721
722 pr_debug("%s: mdm9615_slim_0_tx_ch = %d\n", __func__,
723 mdm9615_slim_0_tx_ch);
724 return 1;
725}
726
727static int mdm9615_btsco_rate_get(struct snd_kcontrol *kcontrol,
728 struct snd_ctl_elem_value *ucontrol)
729{
730 pr_debug("%s: mdm9615_btsco_rate = %d", __func__, mdm9615_btsco_rate);
731 ucontrol->value.integer.value[0] = mdm9615_btsco_rate;
732 return 0;
733}
734
735static int mdm9615_btsco_rate_put(struct snd_kcontrol *kcontrol,
736 struct snd_ctl_elem_value *ucontrol)
737{
738 switch (ucontrol->value.integer.value[0]) {
739 case 0:
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -0700740 mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800741 break;
742 case 1:
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -0700743 mdm9615_btsco_rate = SAMPLE_RATE_16KHZ;
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800744 break;
745 default:
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -0700746 mdm9615_btsco_rate = SAMPLE_RATE_8KHZ;
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800747 break;
748 }
749 pr_debug("%s: mdm9615_btsco_rate = %d\n", __func__, mdm9615_btsco_rate);
750 return 0;
751}
752
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -0700753static int mdm9615_auxpcm_rate_get(struct snd_kcontrol *kcontrol,
754 struct snd_ctl_elem_value *ucontrol)
755{
756 pr_debug("%s: mdm9615_auxpcm_rate = %d", __func__,
757 mdm9615_auxpcm_rate);
758 ucontrol->value.integer.value[0] = mdm9615_auxpcm_rate;
759 return 0;
760}
761
762static int mdm9615_auxpcm_rate_put(struct snd_kcontrol *kcontrol,
763 struct snd_ctl_elem_value *ucontrol)
764{
765 switch (ucontrol->value.integer.value[0]) {
766 case 0:
767 mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
768 break;
769 case 1:
770 mdm9615_auxpcm_rate = SAMPLE_RATE_16KHZ;
771 break;
772 default:
773 mdm9615_auxpcm_rate = SAMPLE_RATE_8KHZ;
774 break;
775 }
776 pr_debug("%s: mdm9615_auxpcm_rate = %d\n"
777 "ucontrol->value.integer.value[0] = %d\n", __func__,
778 mdm9615_auxpcm_rate,
779 (int)ucontrol->value.integer.value[0]);
780 return 0;
781}
782
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800783static const struct snd_kcontrol_new tabla_mdm9615_controls[] = {
784 SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], mdm9615_get_spk,
785 mdm9615_set_spk),
786 SOC_ENUM_EXT("SLIM_0_RX Channels", mdm9615_enum[1],
787 mdm9615_slim_0_rx_ch_get, mdm9615_slim_0_rx_ch_put),
788 SOC_ENUM_EXT("SLIM_0_TX Channels", mdm9615_enum[2],
789 mdm9615_slim_0_tx_ch_get, mdm9615_slim_0_tx_ch_put),
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800790 SOC_ENUM_EXT("Internal BTSCO SampleRate", mdm9615_btsco_enum[0],
Steve Mucklef132c6c2012-06-06 18:30:57 -0700791 mdm9615_btsco_rate_get, mdm9615_btsco_rate_put),
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -0700792 SOC_ENUM_EXT("AUX PCM SampleRate", mdm9615_auxpcm_enum[0],
793 mdm9615_auxpcm_rate_get, mdm9615_auxpcm_rate_put),
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800794};
795
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800796static void *def_tabla_mbhc_cal(void)
797{
798 void *tabla_cal;
799 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
800 u16 *btn_low, *btn_high;
801 u8 *n_ready, *n_cic, *gain;
802
803 tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
804 TABLA_MBHC_DEF_RLOADS),
805 GFP_KERNEL);
806 if (!tabla_cal) {
807 pr_err("%s: out of memory\n", __func__);
808 return NULL;
809 }
810
811#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
812 S(t_ldoh, 100);
813 S(t_bg_fast_settle, 100);
814 S(t_shutdown_plug_rem, 255);
815 S(mbhc_nsa, 4);
816 S(mbhc_navg, 4);
817#undef S
818#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
819 S(mic_current, TABLA_PID_MIC_5_UA);
820 S(hph_current, TABLA_PID_MIC_5_UA);
821 S(t_mic_pid, 100);
822 S(t_ins_complete, 250);
823 S(t_ins_retry, 200);
824#undef S
825#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
826 S(v_no_mic, 30);
827 S(v_hs_max, 1550);
828#undef S
829#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
830 S(c[0], 62);
831 S(c[1], 124);
832 S(nc, 1);
833 S(n_meas, 3);
834 S(mbhc_nsc, 11);
835 S(n_btn_meas, 1);
836 S(n_btn_con, 2);
837 S(num_btn, TABLA_MBHC_DEF_BUTTONS);
838 S(v_btn_press_delta_sta, 100);
839 S(v_btn_press_delta_cic, 50);
840#undef S
841 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
842 btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
843 btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
844 btn_low[0] = -50;
845 btn_high[0] = 10;
846 btn_low[1] = 11;
847 btn_high[1] = 38;
848 btn_low[2] = 39;
849 btn_high[2] = 64;
850 btn_low[3] = 65;
851 btn_high[3] = 91;
852 btn_low[4] = 92;
853 btn_high[4] = 115;
854 btn_low[5] = 116;
855 btn_high[5] = 141;
856 btn_low[6] = 142;
857 btn_high[6] = 163;
858 btn_low[7] = 164;
859 btn_high[7] = 250;
860 n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
861 n_ready[0] = 48;
862 n_ready[1] = 38;
863 n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
864 n_cic[0] = 60;
865 n_cic[1] = 47;
866 gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
867 gain[0] = 11;
868 gain[1] = 9;
869
870 return tabla_cal;
871}
872
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -0700873static int msm9615_i2s_set_spk(struct snd_kcontrol *kcontrol,
874 struct snd_ctl_elem_value *ucontrol)
875{
876 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
877
878 pr_debug("%s()\n", __func__);
879 if (msm9615_i2s_spk_control == ucontrol->value.integer.value[0])
880 return 0;
881
882 msm9615_i2s_spk_control = ucontrol->value.integer.value[0];
883 mdm9615_ext_control(codec);
884 return 1;
885}
886
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800887static int mdm9615_hw_params(struct snd_pcm_substream *substream,
888 struct snd_pcm_hw_params *params)
889{
890 struct snd_soc_pcm_runtime *rtd = substream->private_data;
891 struct snd_soc_dai *codec_dai = rtd->codec_dai;
892 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
893 int ret = 0;
894 unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
895 unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
896
897 pr_debug("%s: ch=%d\n", __func__,
898 mdm9615_slim_0_rx_ch);
899 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
900 ret = snd_soc_dai_get_channel_map(codec_dai,
901 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
902 if (ret < 0) {
903 pr_err("%s: failed to get codec chan map\n", __func__);
904 goto end;
905 }
906
907 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
908 mdm9615_slim_0_rx_ch, rx_ch);
909 if (ret < 0) {
910 pr_err("%s: failed to set cpu chan map\n", __func__);
911 goto end;
912 }
913 ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
914 mdm9615_slim_0_rx_ch, rx_ch);
915 if (ret < 0) {
916 pr_err("%s: failed to set codec channel map\n",
917 __func__);
918 goto end;
919 }
920 } else {
921 ret = snd_soc_dai_get_channel_map(codec_dai,
922 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
923 if (ret < 0) {
924 pr_err("%s: failed to get codec chan map\n", __func__);
925 goto end;
926 }
927 ret = snd_soc_dai_set_channel_map(cpu_dai,
928 mdm9615_slim_0_tx_ch, tx_ch, 0 , 0);
929 if (ret < 0) {
930 pr_err("%s: failed to set cpu chan map\n", __func__);
931 goto end;
932 }
933 ret = snd_soc_dai_set_channel_map(codec_dai,
934 mdm9615_slim_0_tx_ch, tx_ch, 0, 0);
935 if (ret < 0) {
936 pr_err("%s: failed to set codec channel map\n",
937 __func__);
938 goto end;
939 }
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -0800940 }
941end:
942 return ret;
943}
944
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -0700945static int msm9615_i2s_rx_ch_get(struct snd_kcontrol *kcontrol,
946 struct snd_ctl_elem_value *ucontrol)
947{
948 pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
949 msm9615_i2s_rx_ch);
950 ucontrol->value.integer.value[0] = msm9615_i2s_rx_ch - 1;
951 return 0;
952}
953
954static int msm9615_i2s_rx_ch_put(struct snd_kcontrol *kcontrol,
955 struct snd_ctl_elem_value *ucontrol)
956{
957 msm9615_i2s_rx_ch = ucontrol->value.integer.value[0] + 1;
958
959 pr_debug("%s: msm9615_i2s_rx_ch = %d\n", __func__,
960 msm9615_i2s_rx_ch);
961 return 1;
962}
963
964static int msm9615_i2s_tx_ch_get(struct snd_kcontrol *kcontrol,
965 struct snd_ctl_elem_value *ucontrol)
966{
967 pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
968 msm9615_i2s_tx_ch);
969 ucontrol->value.integer.value[0] = msm9615_i2s_tx_ch - 1;
970 return 0;
971}
972
973static int msm9615_i2s_tx_ch_put(struct snd_kcontrol *kcontrol,
974 struct snd_ctl_elem_value *ucontrol)
975{
976 msm9615_i2s_tx_ch = ucontrol->value.integer.value[0] + 1;
977
978 pr_debug("%s: msm9615_i2s_tx_ch = %d\n", __func__,
979 msm9615_i2s_tx_ch);
980 return 1;
981}
982
983static int msm9615_i2s_get_spk(struct snd_kcontrol *kcontrol,
984 struct snd_ctl_elem_value *ucontrol)
985{
986 pr_debug("%s: msm9615_spk_control = %d", __func__, mdm9615_spk_control);
987 ucontrol->value.integer.value[0] = msm9615_i2s_spk_control;
988 return 0;
989}
990
991static const struct snd_kcontrol_new tabla_msm9615_i2s_controls[] = {
992 SOC_ENUM_EXT("Speaker Function", mdm9615_enum[0], msm9615_i2s_get_spk,
993 msm9615_i2s_set_spk),
994 SOC_ENUM_EXT("PRI_RX Channels", mdm9615_enum[1],
995 msm9615_i2s_rx_ch_get, msm9615_i2s_rx_ch_put),
996 SOC_ENUM_EXT("PRI_TX Channels", mdm9615_enum[2],
997 msm9615_i2s_tx_ch_get, msm9615_i2s_tx_ch_put),
998};
999
1000static int msm9615_i2s_audrx_init(struct snd_soc_pcm_runtime *rtd)
1001{
1002 int err;
1003 struct snd_soc_codec *codec = rtd->codec;
1004 struct snd_soc_dapm_context *dapm = &codec->dapm;
1005 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07001006
1007 snd_soc_dapm_new_controls(dapm, mdm9615_dapm_widgets,
1008 ARRAY_SIZE(mdm9615_dapm_widgets));
1009
1010 snd_soc_dapm_add_routes(dapm, common_audio_map,
1011 ARRAY_SIZE(common_audio_map));
1012 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
1013 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
1014 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
1015 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
1016
1017 snd_soc_dapm_sync(dapm);
1018
1019 err = snd_soc_jack_new(codec, "Headset Jack",
1020 (SND_JACK_HEADSET | SND_JACK_OC_HPHL|
1021 SND_JACK_OC_HPHR), &hs_jack);
1022 if (err) {
1023 pr_err("failed to create new jack\n");
1024 return err;
1025 }
1026 err = snd_soc_jack_new(codec, "Button Jack",
1027 TABLA_JACK_BUTTON_MASK, &button_jack);
1028 if (err) {
1029 pr_err("failed to create new jack\n");
1030 return err;
1031 }
1032 codec_clk = clk_get(cpu_dai->dev, "osr_clk");
1033 err = tabla_hs_detect(codec, &mbhc_cfg);
1034 return err;
1035}
1036
1037static int msm9615_i2s_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
1038 struct snd_pcm_hw_params *params)
1039{
1040 struct snd_interval *rate = hw_param_interval(params,
1041 SNDRV_PCM_HW_PARAM_RATE);
1042 struct snd_interval *channels = hw_param_interval(params,
1043 SNDRV_PCM_HW_PARAM_CHANNELS);
1044 rate->min = rate->max = 48000;
1045 channels->min = channels->max = msm9615_i2s_rx_ch;
1046
1047 return 0;
1048}
1049
1050static int msm9615_i2s_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
1051 struct snd_pcm_hw_params *params)
1052{
1053 struct snd_interval *rate = hw_param_interval(params,
1054 SNDRV_PCM_HW_PARAM_RATE);
1055
1056 struct snd_interval *channels = hw_param_interval(params,
1057 SNDRV_PCM_HW_PARAM_CHANNELS);
1058 rate->min = rate->max = 48000;
1059
1060 channels->min = channels->max = msm9615_i2s_tx_ch;
1061
1062 return 0;
1063}
1064
1065static int mdm9615_i2s_free_gpios(u8 i2s_intf, u8 i2s_dir)
1066{
1067 struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
1068 if (i2s_intf == MSM_INTF_PRIM) {
1069 if (i2s_dir == MSM_DIR_RX)
1070 gpio_free(GPIO_PRIM_I2S_DOUT);
1071 if (i2s_dir == MSM_DIR_TX)
1072 gpio_free(GPIO_PRIM_I2S_DIN);
1073 if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
1074 pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
1075 gpio_free(GPIO_PRIM_I2S_SCK);
1076 gpio_free(GPIO_PRIM_I2S_WS);
1077 }
1078 } else if (i2s_intf == MSM_INTF_SECN) {
1079 if (i2s_dir == MSM_DIR_RX)
1080 gpio_free(GPIO_SEC_I2S_DOUT);
1081 if (i2s_dir == MSM_DIR_TX)
1082 gpio_free(GPIO_SEC_I2S_DIN);
1083 if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
1084 pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
1085 gpio_free(GPIO_SEC_I2S_WS);
1086 gpio_free(GPIO_SEC_I2S_SCK);
1087 }
1088 }
1089 return 0;
1090}
1091
1092int msm9615_i2s_intf_dir_sel(const char *cpu_dai_name,
1093 u8 *i2s_intf, u8 *i2s_dir)
1094{
1095 int ret = 0;
1096 if (i2s_intf == NULL || i2s_dir == NULL || cpu_dai_name == NULL) {
1097 ret = 1;
1098 goto err;
1099 }
1100 if (!strncmp(cpu_dai_name, "msm-dai-q6.0", 12)) {
1101 *i2s_intf = MSM_INTF_PRIM;
1102 *i2s_dir = MSM_DIR_RX;
1103 } else if (!strncmp(cpu_dai_name, "msm-dai-q6.1", 12)) {
1104 *i2s_intf = MSM_INTF_PRIM;
1105 *i2s_dir = MSM_DIR_TX;
1106 } else if (!strncmp(cpu_dai_name, "msm-dai-q6.4", 12)) {
1107 *i2s_intf = MSM_INTF_SECN;
1108 *i2s_dir = MSM_DIR_RX;
1109 } else if (!strncmp(cpu_dai_name, "msm-dai-q6.5", 12)) {
1110 *i2s_intf = MSM_INTF_SECN;
1111 *i2s_dir = MSM_DIR_TX;
1112 } else {
1113 pr_err("Error in I2S cpu dai name\n");
1114 ret = 1;
1115 }
1116err:
1117 return ret;
1118}
1119
1120int msm9615_enable_i2s_gpio(u8 i2s_intf, u8 i2s_dir)
1121{
1122 u8 ret = 0;
1123 struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
1124 if (i2s_intf == MSM_INTF_PRIM) {
1125 if (i2s_dir == MSM_DIR_TX) {
1126 ret = gpio_request(GPIO_PRIM_I2S_DIN, "I2S_PRIM_DIN");
1127 if (ret) {
1128 pr_err("%s: Failed to request gpio %d\n",
1129 __func__, GPIO_PRIM_I2S_DIN);
1130 goto err;
1131 }
1132 } else if (i2s_dir == MSM_DIR_RX) {
1133 ret = gpio_request(GPIO_PRIM_I2S_DOUT,
1134 "I2S_PRIM_DOUT");
1135 if (ret) {
1136 pr_err("%s: Failed to request gpio %d\n",
1137 __func__, GPIO_PRIM_I2S_DOUT);
1138 goto err;
1139 }
1140 } else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
1141 pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
1142 ret = gpio_request(GPIO_PRIM_I2S_SCK, "I2S_PRIM_SCK");
1143 if (ret) {
1144 pr_err("%s: Failed to request gpio %d\n",
1145 __func__, GPIO_PRIM_I2S_SCK);
1146 goto err;
1147 }
1148 ret = gpio_request(GPIO_PRIM_I2S_WS, "I2S_PRIM_WS");
1149 if (ret) {
1150 pr_err("%s: Failed to request gpio %d\n",
1151 __func__, GPIO_PRIM_I2S_WS);
1152 goto err;
1153 }
1154 }
1155 } else if (i2s_intf == MSM_INTF_SECN) {
1156 if (i2s_dir == MSM_DIR_RX) {
1157 ret = gpio_request(GPIO_SEC_I2S_DOUT, "I2S_SEC_DOUT");
1158 if (ret) {
1159 pr_err("%s: Failed to request gpio %d\n",
1160 __func__, GPIO_SEC_I2S_DOUT);
1161 goto err;
1162 }
1163 } else if (i2s_dir == MSM_DIR_TX) {
1164 ret = gpio_request(GPIO_SEC_I2S_DIN, "I2S_SEC_DIN");
1165 if (ret) {
1166 pr_err("%s: Failed to request gpio %d\n",
1167 __func__, GPIO_SEC_I2S_DIN);
1168 goto err;
1169 }
1170 } else if (pintf->intf_status[i2s_intf][MSM_DIR_TX] == 0 &&
1171 pintf->intf_status[i2s_intf][MSM_DIR_RX] == 0) {
1172 ret = gpio_request(GPIO_SEC_I2S_SCK, "I2S_SEC_SCK");
1173 if (ret) {
1174 pr_err("%s: Failed to request gpio %d\n",
1175 __func__, GPIO_SEC_I2S_SCK);
1176 goto err;
1177 }
1178 ret = gpio_request(GPIO_SEC_I2S_WS, "I2S_SEC_WS");
1179 if (ret) {
1180 pr_err("%s: Failed to request gpio %d\n",
1181 __func__, GPIO_SEC_I2S_WS);
1182 goto err;
1183 }
1184 }
1185 }
1186err:
1187 return ret;
1188}
1189
1190static int msm9615_set_i2s_osr_bit_clk(struct snd_soc_dai *cpu_dai,
1191 u8 i2s_intf, u8 i2s_dir,
1192 enum msm9x15_set_i2s_clk enable)
1193{
1194
1195 struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
1196 struct msm_i2s_clk *pclk = &pintf->prim_clk;
1197 struct msm_clk *clk_ctl = &pclk->rx_clk;
1198 u8 ret = 0;
1199 pr_debug("Dev name %s Intf =%d, Dir = %d, Enable=%d\n",
1200 cpu_dai->name, i2s_intf, i2s_dir, enable);
1201 if (i2s_intf == MSM_INTF_PRIM)
1202 pclk = &pintf->prim_clk;
1203 else if (i2s_intf == MSM_INTF_SECN)
1204 pclk = &pintf->sec_clk;
1205
1206 if (i2s_dir == MSM_DIR_TX)
1207 clk_ctl = &pclk->tx_clk;
1208 else if (i2s_dir == MSM_DIR_RX)
1209 clk_ctl = &pclk->rx_clk;
1210
1211 if (enable == MSM_I2S_CLK_SET_TRUE ||
1212 enable == MSM_I2S_CLK_SET_RATE0) {
1213 if (clk_ctl->clk_enable != 0) {
1214 pr_info("%s: I2S Clk is already enabled"
1215 "clk users %d\n", __func__,
1216 clk_ctl->clk_enable);
1217 ret = 0;
1218 goto err;
1219 }
1220 clk_ctl->osr_clk = clk_get(cpu_dai->dev, "osr_clk");
1221 if (IS_ERR(clk_ctl->osr_clk)) {
1222 pr_err("%s: Fail to get OSR CLK\n", __func__);
1223 ret = -EINVAL;
1224 goto err;
1225 }
1226 ret = clk_prepare(clk_ctl->osr_clk);
1227 if (ret != 0) {
1228 pr_err("Unable to prepare i2s_spkr_osr_clk\n");
1229 goto err;
1230 }
1231 clk_set_rate(clk_ctl->osr_clk, TABLA_EXT_CLK_RATE);
1232 ret = clk_enable(clk_ctl->osr_clk);
1233 if (ret != 0) {
1234 pr_err("Fail to enable i2s_spkr_osr_clk\n");
1235 clk_unprepare(clk_ctl->osr_clk);
1236 goto err;
1237 }
1238 clk_ctl->bit_clk = clk_get(cpu_dai->dev, "bit_clk");
1239 if (IS_ERR(clk_ctl->bit_clk)) {
1240 pr_err("Fail to get i2s_spkr_bit_clk\n");
1241 clk_disable(clk_ctl->osr_clk);
1242 clk_unprepare(clk_ctl->osr_clk);
1243 clk_put(clk_ctl->osr_clk);
1244 ret = -EINVAL;
1245 goto err;
1246 }
1247 ret = clk_prepare(clk_ctl->bit_clk);
1248 if (ret != 0) {
1249 clk_disable(clk_ctl->osr_clk);
1250 clk_unprepare(clk_ctl->osr_clk);
1251 clk_put(clk_ctl->osr_clk);
1252 pr_err("Fail to prepare i2s_spkr_osr_clk\n");
1253 goto err;
1254 }
1255 if (enable == MSM_I2S_CLK_SET_RATE0)
1256 clk_set_rate(clk_ctl->bit_clk, 0);
1257 else
1258 clk_set_rate(clk_ctl->bit_clk, 8);
1259 ret = clk_enable(clk_ctl->bit_clk);
1260 if (ret != 0) {
1261 clk_disable(clk_ctl->osr_clk);
1262 clk_unprepare(clk_ctl->osr_clk);
1263 clk_put(clk_ctl->osr_clk);
1264 clk_unprepare(clk_ctl->bit_clk);
1265 pr_err("Unable to enable i2s_spkr_osr_clk\n");
1266 goto err;
1267 }
1268 clk_ctl->clk_enable++;
1269 } else if (enable == MSM_I2S_CLK_SET_FALSE &&
1270 clk_ctl->clk_enable != 0) {
1271 clk_disable(clk_ctl->osr_clk);
1272 clk_disable(clk_ctl->bit_clk);
1273 clk_unprepare(clk_ctl->osr_clk);
1274 clk_unprepare(clk_ctl->bit_clk);
1275 clk_put(clk_ctl->bit_clk);
1276 clk_put(clk_ctl->osr_clk);
1277 clk_ctl->bit_clk = NULL;
1278 clk_ctl->osr_clk = NULL;
1279 clk_ctl->clk_enable--;
1280 ret = 0;
1281 }
1282err:
1283 return ret;
1284}
1285
1286void msm9615_config_i2s_sif_mux(u8 value)
1287{
1288 struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
1289 sif_shadow = 0x00000;
1290 sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_PRI_MUX_SEL_BMSK) |
1291 (value << LPASS_SIF_MUX_CTL_PRI_MUX_SEL_SHFT);
1292 iowrite32(sif_shadow, pintf->sif_virt_addr);
1293 /* Dont read SIF register. Device crashes. */
1294 pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
1295}
1296
1297void msm9615_config_i2s_spare_mux(u8 value, u8 i2s_intf)
1298{
1299 struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
1300 if (i2s_intf == MSM_INTF_PRIM) {
1301 /* Configure Primary SIF */
1302 spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_BMSK
1303 ) | (value << LPAIF_SPARE_MUX_CTL_PRI_MUX_SEL_SHFT);
1304 }
1305 if (i2s_intf == MSM_INTF_SECN) {
1306 /*Secondary interface configuration*/
1307 spare_shadow = (spare_shadow & LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_BMSK
1308 ) | (value << LPAIF_SPARE_MUX_CTL_SEC_MUX_SEL_SHFT);
1309 }
1310 iowrite32(spare_shadow, pintf->spare_virt_addr);
1311 /* Dont read SPARE register. Device crashes. */
1312 pr_debug("%s( ): SPARE Reg =0x%x\n", __func__, spare_shadow);
1313}
1314
1315static int msm9615_i2s_hw_params(struct snd_pcm_substream *substream,
1316 struct snd_pcm_hw_params *params)
1317{
1318 int rate = params_rate(params);
1319 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1320 struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
1321 struct msm_i2s_clk *pclk = &pintf->prim_clk;
1322 struct msm_clk *clk_ctl = &pclk->rx_clk;
1323 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1324 int bit_clk_set = 0;
1325 u8 i2s_intf, i2s_dir;
1326 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
1327 if (!msm9615_i2s_intf_dir_sel(cpu_dai->name,
1328 &i2s_intf, &i2s_dir)) {
1329 bit_clk_set = TABLA_EXT_CLK_RATE /
1330 (rate * 2 * NO_OF_BITS_PER_SAMPLE);
1331 if (bit_clk_set != 8) {
1332 if (i2s_intf == MSM_INTF_PRIM)
1333 pclk = &pintf->prim_clk;
1334 else if (i2s_intf == MSM_INTF_SECN)
1335 pclk = &pintf->sec_clk;
1336 clk_ctl = &pclk->rx_clk;
1337 pr_debug("%s( ): New rate = %d",
1338 __func__, bit_clk_set);
1339 clk_set_rate(clk_ctl->bit_clk, bit_clk_set);
1340 }
1341 }
1342 } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
1343 bit_clk_set = I2S_MIC_SCLK_RATE / (rate * 2 *
1344 NO_OF_BITS_PER_SAMPLE);
1345 /* Not required to modify TX rate.
1346 * Speaker clock are looped back
1347 * to Mic.
1348 */
1349 }
1350 return 1;
1351}
1352
1353static int msm9615_i2s_startup(struct snd_pcm_substream *substream)
1354{
1355 u8 ret = 0;
1356 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1357 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1358 struct snd_soc_dai *codec_dai = rtd->codec_dai;
1359 struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
1360 u8 i2s_intf, i2s_dir;
1361 if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
1362 pr_debug("%s( ): cpu name = %s intf =%d dir = %d\n",
1363 __func__, cpu_dai->name, i2s_intf, i2s_dir);
1364 pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
1365 pintf->intf_status[i2s_intf][MSM_DIR_RX],
1366 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
1367 msm9615_enable_i2s_gpio(i2s_intf, i2s_dir);
1368 if (i2s_dir == MSM_DIR_TX) {
1369 if (pintf->intf_status[i2s_intf][MSM_DIR_RX] > 0) {
1370 /* This means that Rx is enabled before */
1371 ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
1372 i2s_intf, i2s_dir,
1373 MSM_I2S_CLK_SET_RATE0);
1374 if (ret != 0) {
1375 pr_err("%s: Fail enable I2S clock\n",
1376 __func__);
1377 return -EINVAL;
1378 }
1379 msm9615_config_i2s_sif_mux(
1380 pintf->mux_ctl[MSM_DIR_BOTH].sifconfig);
1381 msm9615_config_i2s_spare_mux(
1382 pintf->mux_ctl[MSM_DIR_BOTH].spareconfig,
1383 i2s_intf);
1384 ret = snd_soc_dai_set_fmt(cpu_dai,
1385 SND_SOC_DAIFMT_CBM_CFM);
1386 if (ret < 0)
1387 pr_err("set fmt cpu dai failed\n");
1388 ret = snd_soc_dai_set_fmt(codec_dai,
1389 SND_SOC_DAIFMT_CBS_CFS);
1390 if (ret < 0)
1391 pr_err("set fmt codec dai failed\n");
1392 } else if (pintf->intf_status[i2s_intf][i2s_dir] == 0) {
1393 /* This means that Rx is
1394 * not enabled before.
1395 * only Tx will be used.
1396 */
1397 ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
1398 i2s_intf, i2s_dir,
1399 MSM_I2S_CLK_SET_TRUE);
1400 if (ret != 0) {
1401 pr_err("%s: Fail Tx I2S clock\n",
1402 __func__);
1403 return -EINVAL;
1404 }
1405 msm9615_config_i2s_sif_mux(
1406 pintf->mux_ctl[MSM_DIR_TX].sifconfig);
1407 msm9615_config_i2s_spare_mux(
1408 pintf->mux_ctl[MSM_DIR_TX].spareconfig,
1409 i2s_intf);
1410 ret = snd_soc_dai_set_fmt(cpu_dai,
1411 SND_SOC_DAIFMT_CBS_CFS);
1412 if (ret < 0)
1413 pr_err("set fmt cpu dai failed\n");
1414 ret = snd_soc_dai_set_fmt(codec_dai,
1415 SND_SOC_DAIFMT_CBS_CFS);
1416 if (ret < 0)
1417 pr_err("set fmt codec dai failed\n");
1418 }
1419 } else if (i2s_dir == MSM_DIR_RX) {
1420 if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0) {
1421 pr_err("%s: Error shutdown Tx first\n",
1422 __func__);
1423 return -EINVAL;
1424 } else if (pintf->intf_status[i2s_intf][i2s_dir]
1425 == 0) {
1426 ret = msm9615_set_i2s_osr_bit_clk(cpu_dai,
1427 i2s_intf, i2s_dir,
1428 MSM_I2S_CLK_SET_TRUE);
1429 if (ret != 0) {
1430 pr_err("%s: Fail Rx I2S clock\n",
1431 __func__);
1432 return -EINVAL;
1433 }
1434 msm9615_config_i2s_sif_mux(
1435 pintf->mux_ctl[MSM_DIR_RX].sifconfig);
1436 msm9615_config_i2s_spare_mux(
1437 pintf->mux_ctl[MSM_DIR_RX].spareconfig,
1438 i2s_intf);
1439 ret = snd_soc_dai_set_fmt(cpu_dai,
1440 SND_SOC_DAIFMT_CBS_CFS);
1441 if (ret < 0)
1442 pr_err("set fmt cpu dai failed\n");
1443 ret = snd_soc_dai_set_fmt(codec_dai,
1444 SND_SOC_DAIFMT_CBS_CFS);
1445 if (ret < 0)
1446 pr_err("set fmt codec dai failed\n");
1447 }
1448 }
1449 pintf->intf_status[i2s_intf][i2s_dir]++;
1450 } else {
1451 pr_err("%s: Err in i2s_intf_dir_sel\n", __func__);
1452 return -EINVAL;
1453 }
1454 pr_debug("Exit %s() Enable status Rx =%d Tx = %d\n", __func__,
1455 pintf->intf_status[i2s_intf][MSM_DIR_RX],
1456 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
1457 return ret;
1458}
1459
1460static void msm9615_i2s_shutdown(struct snd_pcm_substream *substream)
1461{
1462 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1463 struct msm_i2s_ctl *pintf = &msm9x15_i2s_ctl;
1464 u8 i2s_intf = 0, i2s_dir = 0, ret = 0;
1465 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1466 pr_debug("%s( ): Enable status Rx =%d Tx = %d\n",
1467 __func__, pintf->intf_status[i2s_intf][MSM_DIR_RX],
1468 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
1469 if (!msm9615_i2s_intf_dir_sel(cpu_dai->name, &i2s_intf, &i2s_dir)) {
1470 pr_debug("%s( ): intf =%d dir = %d\n", __func__,
1471 i2s_intf, i2s_dir);
1472 if (i2s_dir == MSM_DIR_RX)
1473 if (pintf->intf_status[i2s_intf][MSM_DIR_TX] > 0)
1474 pr_err("%s: Shutdown Tx First then by RX\n",
1475 __func__);
1476 ret = msm9615_set_i2s_osr_bit_clk(cpu_dai, i2s_intf, i2s_dir,
1477 MSM_I2S_CLK_SET_FALSE);
1478 if (ret != 0)
1479 pr_err("%s: Cannot disable I2S clock\n",
1480 __func__);
1481 pintf->intf_status[i2s_intf][i2s_dir]--;
1482 mdm9615_i2s_free_gpios(i2s_intf, i2s_dir);
1483 }
1484 pr_debug("%s( ): Enable status Rx =%d Tx = %d\n", __func__,
1485 pintf->intf_status[i2s_intf][MSM_DIR_RX],
1486 pintf->intf_status[i2s_intf][MSM_DIR_TX]);
1487}
1488
1489static struct snd_soc_ops msm9615_i2s_be_ops = {
1490 .startup = msm9615_i2s_startup,
1491 .shutdown = msm9615_i2s_shutdown,
1492 .hw_params = msm9615_i2s_hw_params,
1493};
1494
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001495static int mdm9615_audrx_init(struct snd_soc_pcm_runtime *rtd)
1496{
1497 int err;
1498 struct snd_soc_codec *codec = rtd->codec;
1499 struct snd_soc_dapm_context *dapm = &codec->dapm;
1500 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
1501
1502 pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
1503
1504 rtd->pmdown_time = 0;
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001505
1506 snd_soc_dapm_new_controls(dapm, mdm9615_dapm_widgets,
1507 ARRAY_SIZE(mdm9615_dapm_widgets));
1508
1509 snd_soc_dapm_add_routes(dapm, common_audio_map,
1510 ARRAY_SIZE(common_audio_map));
1511
1512 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
1513 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
1514 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
1515 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
1516
1517 snd_soc_dapm_sync(dapm);
1518
1519 err = snd_soc_jack_new(codec, "Headset Jack",
1520 (SND_JACK_HEADSET | SND_JACK_OC_HPHL |
1521 SND_JACK_OC_HPHR),
1522 &hs_jack);
1523 if (err) {
1524 pr_err("failed to create new jack\n");
1525 return err;
1526 }
1527
1528 err = snd_soc_jack_new(codec, "Button Jack",
1529 TABLA_JACK_BUTTON_MASK, &button_jack);
1530 if (err) {
1531 pr_err("failed to create new jack\n");
1532 return err;
1533 }
1534 codec_clk = clk_get(cpu_dai->dev, "osr_clk");
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001535
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001536 err = tabla_hs_detect(codec, &mbhc_cfg);
1537
1538 return err;
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001539}
1540
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001541static int mdm9615_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
1542 struct snd_pcm_hw_params *params)
1543{
1544 struct snd_interval *rate = hw_param_interval(params,
1545 SNDRV_PCM_HW_PARAM_RATE);
1546
1547 struct snd_interval *channels = hw_param_interval(params,
1548 SNDRV_PCM_HW_PARAM_CHANNELS);
1549
1550 pr_debug("%s()\n", __func__);
1551 rate->min = rate->max = 48000;
1552 channels->min = channels->max = mdm9615_slim_0_rx_ch;
1553
1554 return 0;
1555}
1556
1557static int mdm9615_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
1558 struct snd_pcm_hw_params *params)
1559{
1560 struct snd_interval *rate = hw_param_interval(params,
1561 SNDRV_PCM_HW_PARAM_RATE);
1562
1563 struct snd_interval *channels = hw_param_interval(params,
1564 SNDRV_PCM_HW_PARAM_CHANNELS);
1565
1566 pr_debug("%s()\n", __func__);
1567 rate->min = rate->max = 48000;
1568 channels->min = channels->max = mdm9615_slim_0_tx_ch;
1569
1570 return 0;
1571}
1572
1573static int mdm9615_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
1574 struct snd_pcm_hw_params *params)
1575{
1576 struct snd_interval *rate = hw_param_interval(params,
1577 SNDRV_PCM_HW_PARAM_RATE);
1578
1579 struct snd_interval *channels = hw_param_interval(params,
1580 SNDRV_PCM_HW_PARAM_CHANNELS);
1581
1582 rate->min = rate->max = mdm9615_btsco_rate;
1583 channels->min = channels->max = mdm9615_btsco_ch;
1584
1585 return 0;
1586}
1587static int mdm9615_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
1588 struct snd_pcm_hw_params *params)
1589{
1590 struct snd_interval *rate = hw_param_interval(params,
1591 SNDRV_PCM_HW_PARAM_RATE);
1592
1593 struct snd_interval *channels = hw_param_interval(params,
1594 SNDRV_PCM_HW_PARAM_CHANNELS);
1595
Shiv Maliyappanahalli8d4f1592012-06-07 10:35:53 -07001596 rate->min = rate->max = mdm9615_auxpcm_rate;
1597 /* PCM only supports mono output */
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001598 channels->min = channels->max = 1;
1599
1600 return 0;
1601}
1602static int mdm9615_aux_pcm_get_gpios(void)
1603{
1604 int ret = 0;
1605
1606 pr_debug("%s\n", __func__);
1607
1608 ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
1609 if (ret < 0) {
1610 pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
1611 __func__, GPIO_AUX_PCM_DOUT);
1612 goto fail_dout;
1613 }
1614
1615 ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
1616 if (ret < 0) {
1617 pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
1618 __func__, GPIO_AUX_PCM_DIN);
1619 goto fail_din;
1620 }
1621
1622 ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
1623 if (ret < 0) {
1624 pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
1625 __func__, GPIO_AUX_PCM_SYNC);
1626 goto fail_sync;
1627 }
1628 ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
1629 if (ret < 0) {
1630 pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
1631 __func__, GPIO_AUX_PCM_CLK);
1632 goto fail_clk;
1633 }
1634
1635 return 0;
1636
1637fail_clk:
1638 gpio_free(GPIO_AUX_PCM_SYNC);
1639fail_sync:
1640 gpio_free(GPIO_AUX_PCM_DIN);
1641fail_din:
1642 gpio_free(GPIO_AUX_PCM_DOUT);
1643fail_dout:
1644
1645 return ret;
1646}
1647
1648static int mdm9615_aux_pcm_free_gpios(void)
1649{
1650 gpio_free(GPIO_AUX_PCM_DIN);
1651 gpio_free(GPIO_AUX_PCM_DOUT);
1652 gpio_free(GPIO_AUX_PCM_SYNC);
1653 gpio_free(GPIO_AUX_PCM_CLK);
1654
1655 return 0;
1656}
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07001657
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -07001658static int mdm9615_sec_aux_pcm_get_gpios(void)
1659{
1660 int ret = 0;
1661
1662 pr_debug("%s\n", __func__);
1663
1664 ret = gpio_request(GPIO_SEC_AUX_PCM_DOUT, "SEC_AUX PCM DOUT");
1665 if (ret < 0) {
1666 pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM DOUT",
1667 __func__, GPIO_SEC_AUX_PCM_DOUT);
1668 goto fail_dout;
1669 }
1670
1671 ret = gpio_request(GPIO_SEC_AUX_PCM_DIN, "SEC_AUX PCM DIN");
1672 if (ret < 0) {
1673 pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM DIN",
1674 __func__, GPIO_SEC_AUX_PCM_DIN);
1675 goto fail_din;
1676 }
1677
1678 ret = gpio_request(GPIO_SEC_AUX_PCM_SYNC, "SEC_AUX PCM SYNC");
1679 if (ret < 0) {
1680 pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM SYNC",
1681 __func__, GPIO_SEC_AUX_PCM_SYNC);
1682 goto fail_sync;
1683 }
1684
1685 ret = gpio_request(GPIO_SEC_AUX_PCM_CLK, "SEC_AUX PCM CLK");
1686 if (ret < 0) {
1687 pr_err("%s: Failed to request gpio(%d): SEC_AUX PCM CLK",
1688 __func__, GPIO_SEC_AUX_PCM_CLK);
1689 goto fail_clk;
1690 }
1691
1692 return 0;
1693
1694fail_clk:
1695 gpio_free(GPIO_SEC_AUX_PCM_SYNC);
1696fail_sync:
1697 gpio_free(GPIO_SEC_AUX_PCM_DIN);
1698fail_din:
1699 gpio_free(GPIO_SEC_AUX_PCM_DOUT);
1700fail_dout:
1701
1702 return ret;
1703}
1704
1705static int mdm9615_sec_aux_pcm_free_gpios(void)
1706{
1707 gpio_free(GPIO_SEC_AUX_PCM_DIN);
1708 gpio_free(GPIO_SEC_AUX_PCM_DOUT);
1709 gpio_free(GPIO_SEC_AUX_PCM_SYNC);
1710 gpio_free(GPIO_SEC_AUX_PCM_CLK);
1711
1712 return 0;
1713}
1714
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001715static int mdm9615_startup(struct snd_pcm_substream *substream)
1716{
1717 pr_debug("%s(): substream = %s stream = %d\n", __func__,
1718 substream->name, substream->stream);
1719 return 0;
1720}
1721
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -07001722void msm9615_config_sif_mux(u8 value)
1723{
1724 u32 sif_shadow = 0x00000;
1725
1726 sif_shadow = (sif_shadow & LPASS_SIF_MUX_CTL_SEC_MUX_SEL_BMSK) |
1727 (value << LPASS_SIF_MUX_CTL_SEC_MUX_SEL_SHFT);
1728 iowrite32(sif_shadow, sif_virt_addr);
1729 /* Dont read SIF register. Device crashes. */
1730 pr_debug("%s() SIF Reg = 0x%x\n", __func__, sif_shadow);
1731}
1732
1733void msm9615_config_port_select(void)
1734{
1735 pr_debug("%s() port select defualt = 0x%x\n",
1736 __func__, ioread32(secpcm_portslc_virt_addr));
1737 iowrite32(SEC_PCM_PORT_SLC_VALUE, secpcm_portslc_virt_addr);
1738 pr_debug("%s() port select after updating = 0x%x\n",
1739 __func__, ioread32(secpcm_portslc_virt_addr));
1740}
1741
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001742static int mdm9615_auxpcm_startup(struct snd_pcm_substream *substream)
1743{
1744 int ret = 0;
1745
1746 pr_debug("%s(): substream = %s\n", __func__, substream->name);
Shiv Maliyappanahallia23ea702012-06-01 15:19:46 -07001747 if (atomic_inc_return(&msm9615_auxpcm_ref) == 1) {
1748 ret = mdm9615_aux_pcm_get_gpios();
1749 if (ret < 0) {
1750 pr_err("%s: Aux PCM GPIO request failed\n", __func__);
1751 return -EINVAL;
1752 }
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001753 }
1754 return 0;
1755}
1756
1757static void mdm9615_auxpcm_shutdown(struct snd_pcm_substream *substream)
1758{
1759
1760 pr_debug("%s(): substream = %s\n", __func__, substream->name);
Shiv Maliyappanahallia23ea702012-06-01 15:19:46 -07001761 if (atomic_dec_return(&msm9615_auxpcm_ref) == 0)
1762 mdm9615_aux_pcm_free_gpios();
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001763}
1764
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -07001765static int mdm9615_sec_auxpcm_startup(struct snd_pcm_substream *substream)
1766{
1767 int ret = 0;
1768
1769 pr_debug("%s(): substream = %s\n", __func__, substream->name);
1770 if (atomic_inc_return(&msm9615_sec_auxpcm_ref) == 1) {
1771 ret = mdm9615_sec_aux_pcm_get_gpios();
1772 if (ret < 0) {
1773 pr_err("%s: SEC Aux PCM GPIO request failed\n",
1774 __func__);
1775 return -EINVAL;
1776 }
1777 msm9615_config_sif_mux(MSM_SIF_FUNC_PCM);
1778 msm9615_config_port_select();
1779 }
1780 return 0;
1781}
1782
1783static void mdm9615_sec_auxpcm_shutdown(struct snd_pcm_substream *substream)
1784{
1785 pr_debug("%s(): substream = %s\n", __func__, substream->name);
1786 if (atomic_dec_return(&msm9615_sec_auxpcm_ref) == 0)
1787 mdm9615_sec_aux_pcm_free_gpios();
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001788}
1789
1790static void mdm9615_shutdown(struct snd_pcm_substream *substream)
1791{
1792 pr_debug("%s(): substream = %s stream = %d\n", __func__,
1793 substream->name, substream->stream);
1794}
1795
1796static struct snd_soc_ops mdm9615_be_ops = {
1797 .startup = mdm9615_startup,
1798 .hw_params = mdm9615_hw_params,
1799 .shutdown = mdm9615_shutdown,
1800};
1801
1802static struct snd_soc_ops mdm9615_auxpcm_be_ops = {
1803 .startup = mdm9615_auxpcm_startup,
1804 .shutdown = mdm9615_auxpcm_shutdown,
1805};
1806
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -07001807static struct snd_soc_ops mdm9615_sec_auxpcm_be_ops = {
1808 .startup = mdm9615_sec_auxpcm_startup,
1809 .shutdown = mdm9615_sec_auxpcm_shutdown,
1810};
1811
1812
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001813/* Digital audio interface glue - connects codec <---> CPU */
1814static struct snd_soc_dai_link mdm9615_dai_common[] = {
1815 /* FrontEnd DAI Links */
1816 {
1817 .name = "MDM9615 Media1",
1818 .stream_name = "MultiMedia1",
1819 .cpu_dai_name = "MultiMedia1",
1820 .platform_name = "msm-pcm-dsp",
1821 .dynamic = 1,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001822 .codec_dai_name = "snd-soc-dummy-dai",
1823 .codec_name = "snd-soc-dummy",
1824 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
1825 .ignore_suspend = 1,
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001826 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
1827 },
1828 {
1829 .name = "MDM9615 Media2",
1830 .stream_name = "MultiMedia2",
1831 .cpu_dai_name = "MultiMedia2",
1832 .platform_name = "msm-pcm-dsp",
1833 .dynamic = 1,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001834 .codec_dai_name = "snd-soc-dummy-dai",
1835 .codec_name = "snd-soc-dummy",
1836 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
1837 .ignore_suspend = 1,
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001838 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
1839 },
1840 {
1841 .name = "Circuit-Switch Voice",
1842 .stream_name = "CS-Voice",
1843 .cpu_dai_name = "CS-VOICE",
1844 .platform_name = "msm-pcm-voice",
1845 .dynamic = 1,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001846 .codec_dai_name = "snd-soc-dummy-dai",
1847 .codec_name = "snd-soc-dummy",
1848 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
1849 .ignore_suspend = 1,
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001850 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
1851 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1852 .ignore_suspend = 1,
1853 },
1854 {
1855 .name = "MSM VoIP",
1856 .stream_name = "VoIP",
1857 .cpu_dai_name = "VoIP",
1858 .platform_name = "msm-voip-dsp",
1859 .dynamic = 1,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001860 .codec_dai_name = "snd-soc-dummy-dai",
1861 .codec_name = "snd-soc-dummy",
1862 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
1863 .ignore_suspend = 1,
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001864 .be_id = MSM_FRONTEND_DAI_VOIP,
1865 },
1866 /* Hostless PMC purpose */
1867 {
1868 .name = "SLIMBUS_0 Hostless",
1869 .stream_name = "SLIMBUS_0 Hostless",
1870 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
1871 .platform_name = "msm-pcm-hostless",
1872 .dynamic = 1,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001873 .codec_dai_name = "snd-soc-dummy-dai",
1874 .codec_name = "snd-soc-dummy",
1875 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001876 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1877 .ignore_suspend = 1,
1878 /* .be_id = do not care */
1879 },
1880 {
1881 .name = "MSM AFE-PCM RX",
1882 .stream_name = "AFE-PROXY RX",
1883 .cpu_dai_name = "msm-dai-q6.241",
1884 .codec_name = "msm-stub-codec.1",
1885 .codec_dai_name = "msm-stub-rx",
1886 .platform_name = "msm-pcm-afe",
1887 .ignore_suspend = 1,
1888 },
1889 {
1890 .name = "MSM AFE-PCM TX",
1891 .stream_name = "AFE-PROXY TX",
1892 .cpu_dai_name = "msm-dai-q6.240",
1893 .codec_name = "msm-stub-codec.1",
1894 .codec_dai_name = "msm-stub-tx",
1895 .platform_name = "msm-pcm-afe",
1896 .ignore_suspend = 1,
1897 },
1898 {
1899 .name = "AUXPCM Hostless",
1900 .stream_name = "AUXPCM Hostless",
1901 .cpu_dai_name = "AUXPCM_HOSTLESS",
1902 .platform_name = "msm-pcm-hostless",
1903 .dynamic = 1,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001904 .codec_dai_name = "snd-soc-dummy-dai",
1905 .codec_name = "snd-soc-dummy",
1906 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001907 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1908 .ignore_suspend = 1,
1909 },
Venkat Sudhirdf2745b2012-04-09 23:55:45 -07001910 {
1911 .name = "VoLTE",
1912 .stream_name = "VoLTE",
1913 .cpu_dai_name = "VoLTE",
1914 .platform_name = "msm-pcm-voice",
1915 .dynamic = 1,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001916 .codec_dai_name = "snd-soc-dummy-dai",
1917 .codec_name = "snd-soc-dummy",
1918 .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
Venkat Sudhirdf2745b2012-04-09 23:55:45 -07001919 .be_id = MSM_FRONTEND_DAI_VOLTE,
1920 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1921 .ignore_suspend = 1,
1922 },
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001923 /* Backend BT DAI Links */
1924 {
1925 .name = LPASS_BE_INT_BT_SCO_RX,
1926 .stream_name = "Internal BT-SCO Playback",
1927 .cpu_dai_name = "msm-dai-q6.12288",
1928 .platform_name = "msm-pcm-routing",
1929 .codec_name = "msm-stub-codec.1",
1930 .codec_dai_name = "msm-stub-rx",
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001931 .no_pcm = 1,
1932 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
1933 .be_hw_params_fixup = mdm9615_btsco_be_hw_params_fixup,
1934 },
1935 {
1936 .name = LPASS_BE_INT_BT_SCO_TX,
1937 .stream_name = "Internal BT-SCO Capture",
1938 .cpu_dai_name = "msm-dai-q6.12289",
1939 .platform_name = "msm-pcm-routing",
1940 .codec_name = "msm-stub-codec.1",
1941 .codec_dai_name = "msm-stub-tx",
1942 .no_pcm = 1,
1943 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
1944 .be_hw_params_fixup = mdm9615_btsco_be_hw_params_fixup,
1945 },
1946
1947 /* Backend AFE DAI Links */
1948 {
1949 .name = LPASS_BE_AFE_PCM_RX,
1950 .stream_name = "AFE Playback",
1951 .cpu_dai_name = "msm-dai-q6.224",
1952 .platform_name = "msm-pcm-routing",
1953 .codec_name = "msm-stub-codec.1",
1954 .codec_dai_name = "msm-stub-rx",
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001955 .no_pcm = 1,
1956 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
1957 },
1958 {
1959 .name = LPASS_BE_AFE_PCM_TX,
1960 .stream_name = "AFE Capture",
1961 .cpu_dai_name = "msm-dai-q6.225",
1962 .platform_name = "msm-pcm-routing",
1963 .codec_name = "msm-stub-codec.1",
1964 .codec_dai_name = "msm-stub-tx",
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001965 .no_pcm = 1,
1966 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
1967 },
1968 /* AUX PCM Backend DAI Links */
1969 {
1970 .name = LPASS_BE_AUXPCM_RX,
1971 .stream_name = "AUX PCM Playback",
1972 .cpu_dai_name = "msm-dai-q6.2",
1973 .platform_name = "msm-pcm-routing",
1974 .codec_name = "msm-stub-codec.1",
1975 .codec_dai_name = "msm-stub-rx",
1976 .no_pcm = 1,
1977 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
1978 .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
1979 .ops = &mdm9615_auxpcm_be_ops,
1980 },
1981 {
1982 .name = LPASS_BE_AUXPCM_TX,
1983 .stream_name = "AUX PCM Capture",
1984 .cpu_dai_name = "msm-dai-q6.3",
1985 .platform_name = "msm-pcm-routing",
1986 .codec_name = "msm-stub-codec.1",
1987 .codec_dai_name = "msm-stub-tx",
1988 .no_pcm = 1,
1989 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
1990 .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
Shiv Maliyappanahallia23ea702012-06-01 15:19:46 -07001991 .ops = &mdm9615_auxpcm_be_ops,
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08001992 },
1993
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -07001994 /* SECONDARY AUX PCM Backend DAI Links */
1995 {
1996 .name = LPASS_BE_SEC_AUXPCM_RX,
1997 .stream_name = "SEC AUX PCM Playback",
1998 .cpu_dai_name = "msm-dai-q6.12",
1999 .platform_name = "msm-pcm-routing",
2000 .codec_name = "msm-stub-codec.1",
2001 .codec_dai_name = "msm-stub-rx",
2002 .no_pcm = 1,
2003 .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_RX,
2004 .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
2005 .ops = &mdm9615_sec_auxpcm_be_ops,
2006 },
2007 {
2008 .name = LPASS_BE_SEC_AUXPCM_TX,
2009 .stream_name = "SEC AUX PCM Capture",
2010 .cpu_dai_name = "msm-dai-q6.13",
2011 .platform_name = "msm-pcm-routing",
2012 .codec_name = "msm-stub-codec.1",
2013 .codec_dai_name = "msm-stub-tx",
2014 .no_pcm = 1,
2015 .be_id = MSM_BACKEND_DAI_SEC_AUXPCM_TX,
2016 .be_hw_params_fixup = mdm9615_auxpcm_be_params_fixup,
2017 .ops = &mdm9615_sec_auxpcm_be_ops,
2018 },
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002019};
2020
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002021static struct snd_soc_dai_link mdm9615_dai_i2s_tabla[] = {
2022 /* Backend I2S DAI Links */
2023 {
2024 .name = LPASS_BE_PRI_I2S_RX,
2025 .stream_name = "Primary I2S Playback",
2026 .cpu_dai_name = "msm-dai-q6.0",
2027 .platform_name = "msm-pcm-routing",
2028 .codec_name = "tabla_codec",
2029 .codec_dai_name = "tabla_i2s_rx1",
2030 .no_pcm = 1,
2031 .be_id = MSM_BACKEND_DAI_PRI_I2S_RX,
2032 .init = &msm9615_i2s_audrx_init,
2033 .be_hw_params_fixup = msm9615_i2s_rx_be_hw_params_fixup,
2034 .ops = &msm9615_i2s_be_ops,
2035 },
2036 {
2037 .name = LPASS_BE_PRI_I2S_TX,
2038 .stream_name = "Primary I2S Capture",
2039 .cpu_dai_name = "msm-dai-q6.1",
2040 .platform_name = "msm-pcm-routing",
2041 .codec_name = "tabla_codec",
2042 .codec_dai_name = "tabla_i2s_tx1",
2043 .no_pcm = 1,
2044 .be_id = MSM_BACKEND_DAI_PRI_I2S_TX,
2045 .be_hw_params_fixup = msm9615_i2s_tx_be_hw_params_fixup,
2046 .ops = &msm9615_i2s_be_ops,
2047 },
2048};
2049
2050static struct snd_soc_dai_link mdm9615_dai_slimbus_tabla[] = {
2051 /* Backend SlimBus DAI Links */
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002052 {
2053 .name = LPASS_BE_SLIMBUS_0_RX,
2054 .stream_name = "Slimbus Playback",
2055 .cpu_dai_name = "msm-dai-q6.16384",
2056 .platform_name = "msm-pcm-routing",
2057 .codec_name = "tabla_codec",
2058 .codec_dai_name = "tabla_rx1",
2059 .no_pcm = 1,
2060 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
2061 .init = &mdm9615_audrx_init,
2062 .be_hw_params_fixup = mdm9615_slim_0_rx_be_hw_params_fixup,
2063 .ops = &mdm9615_be_ops,
2064 },
2065 {
2066 .name = LPASS_BE_SLIMBUS_0_TX,
2067 .stream_name = "Slimbus Capture",
2068 .cpu_dai_name = "msm-dai-q6.16385",
2069 .platform_name = "msm-pcm-routing",
2070 .codec_name = "tabla_codec",
2071 .codec_dai_name = "tabla_tx1",
2072 .no_pcm = 1,
2073 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
2074 .be_hw_params_fixup = mdm9615_slim_0_tx_be_hw_params_fixup,
2075 .ops = &mdm9615_be_ops,
2076 },
2077};
2078
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002079static struct snd_soc_dai_link mdm9615_i2s_dai[
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002080 ARRAY_SIZE(mdm9615_dai_common) +
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002081 ARRAY_SIZE(mdm9615_dai_i2s_tabla)];
2082
2083static struct snd_soc_dai_link mdm9615_slimbus_dai[
2084 ARRAY_SIZE(mdm9615_dai_common) +
2085 ARRAY_SIZE(mdm9615_dai_slimbus_tabla)];
2086
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002087
2088static struct snd_soc_card snd_soc_card_mdm9615 = {
2089 .name = "mdm9615-tabla-snd-card",
Steve Mucklef132c6c2012-06-06 18:30:57 -07002090 .controls = tabla_mdm9615_controls,
2091 .num_controls = ARRAY_SIZE(tabla_mdm9615_controls),
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002092};
2093
2094static struct platform_device *mdm9615_snd_device;
2095
2096static int mdm9615_configure_headset_mic_gpios(void)
2097{
2098 int ret;
2099 struct pm_gpio param = {
2100 .direction = PM_GPIO_DIR_OUT,
2101 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
2102 .output_value = 1,
2103 .pull = PM_GPIO_PULL_NO,
2104 .vin_sel = PM_GPIO_VIN_S4,
2105 .out_strength = PM_GPIO_STRENGTH_MED,
2106 .function = PM_GPIO_FUNC_NORMAL,
2107 };
2108
2109 ret = gpio_request(PM8018_GPIO_PM_TO_SYS(23), "AV_SWITCH");
2110 if (ret) {
2111 pr_err("%s: Failed to request gpio %d\n", __func__,
2112 PM8018_GPIO_PM_TO_SYS(23));
2113 return ret;
2114 }
2115
2116 ret = pm8xxx_gpio_config(PM8018_GPIO_PM_TO_SYS(23), &param);
2117 if (ret)
2118 pr_err("%s: Failed to configure gpio %d\n", __func__,
2119 PM8018_GPIO_PM_TO_SYS(23));
2120 else
2121 gpio_direction_output(PM8018_GPIO_PM_TO_SYS(23), 0);
2122
2123 ret = gpio_request(PM8018_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
2124 if (ret) {
2125 pr_err("%s: Failed to request gpio %d\n", __func__,
2126 PM8018_GPIO_PM_TO_SYS(35));
2127 gpio_free(PM8018_GPIO_PM_TO_SYS(23));
2128 return ret;
2129 }
2130 ret = pm8xxx_gpio_config(PM8018_GPIO_PM_TO_SYS(35), &param);
2131 if (ret)
2132 pr_err("%s: Failed to configure gpio %d\n", __func__,
2133 PM8018_GPIO_PM_TO_SYS(35));
2134 else
2135 gpio_direction_output(PM8018_GPIO_PM_TO_SYS(35), 0);
2136
2137 return 0;
2138}
2139static void mdm9615_free_headset_mic_gpios(void)
2140{
2141 if (mdm9615_headset_gpios_configured) {
2142 gpio_free(PM8018_GPIO_PM_TO_SYS(23));
2143 gpio_free(PM8018_GPIO_PM_TO_SYS(35));
2144 }
2145}
2146
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002147void __init install_codec_i2s_gpio(void)
2148{
2149 msm_gpiomux_install(msm9615_audio_prim_i2s_codec_configs,
2150 ARRAY_SIZE(msm9615_audio_prim_i2s_codec_configs));
2151}
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002152static int __init mdm9615_audio_init(void)
2153{
2154 int ret;
2155
2156 if (!cpu_is_msm9615()) {
2157 pr_err("%s: Not the right machine type\n", __func__);
2158 return -ENODEV ;
2159 }
2160
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002161 mbhc_cfg.calibration = def_tabla_mbhc_cal();
2162 if (!mbhc_cfg.calibration) {
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002163 pr_err("Calibration data allocation failed\n");
2164 return -ENOMEM;
2165 }
2166
2167 mdm9615_snd_device = platform_device_alloc("soc-audio", 0);
2168 if (!mdm9615_snd_device) {
2169 pr_err("Platform device allocation failed\n");
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002170 kfree(mbhc_cfg.calibration);
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002171 return -ENOMEM;
2172 }
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002173 pr_err("%s: Interface Type = %d\n", __func__,
2174 wcd9xxx_get_intf_type());
2175 if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_SLIMBUS) {
2176 memcpy(mdm9615_slimbus_dai, mdm9615_dai_common,
2177 sizeof(mdm9615_dai_common));
2178 memcpy(mdm9615_slimbus_dai + ARRAY_SIZE(mdm9615_dai_common),
2179 mdm9615_dai_slimbus_tabla,
2180 sizeof(mdm9615_dai_slimbus_tabla));
2181 snd_soc_card_mdm9615.dai_link = mdm9615_slimbus_dai;
2182 snd_soc_card_mdm9615.num_links =
2183 ARRAY_SIZE(mdm9615_slimbus_dai);
2184 } else if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C) {
2185 install_codec_i2s_gpio();
2186 memcpy(mdm9615_i2s_dai, mdm9615_dai_common,
2187 sizeof(mdm9615_dai_common));
2188 memcpy(mdm9615_i2s_dai + ARRAY_SIZE(mdm9615_dai_common),
2189 mdm9615_dai_i2s_tabla,
2190 sizeof(mdm9615_dai_i2s_tabla));
2191 snd_soc_card_mdm9615.dai_link = mdm9615_i2s_dai;
2192 snd_soc_card_mdm9615.num_links =
2193 ARRAY_SIZE(mdm9615_i2s_dai);
Shiv Maliyappanahallia23ea702012-06-01 15:19:46 -07002194 } else{
2195 snd_soc_card_mdm9615.dai_link = mdm9615_dai_common;
2196 snd_soc_card_mdm9615.num_links =
2197 ARRAY_SIZE(mdm9615_dai_common);
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002198 }
Shiv Maliyappanahallia23ea702012-06-01 15:19:46 -07002199
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002200 platform_set_drvdata(mdm9615_snd_device, &snd_soc_card_mdm9615);
2201 ret = platform_device_add(mdm9615_snd_device);
2202 if (ret) {
2203 platform_device_put(mdm9615_snd_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002204 kfree(mbhc_cfg.calibration);
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002205 return ret;
2206 }
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002207 if (mdm9615_configure_headset_mic_gpios()) {
2208 pr_err("%s Fail to configure headset mic gpios\n", __func__);
2209 mdm9615_headset_gpios_configured = 0;
2210 } else
2211 mdm9615_headset_gpios_configured = 1;
2212
Shiv Maliyappanahallia23ea702012-06-01 15:19:46 -07002213 atomic_set(&msm9615_auxpcm_ref, 0);
2214 atomic_set(&msm9615_sec_auxpcm_ref, 0);
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002215 msm9x15_i2s_ctl.sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
2216 msm9x15_i2s_ctl.spare_virt_addr = ioremap(LPAIF_SPARE_ADDR, 4);
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -07002217 sif_virt_addr = ioremap(LPASS_SIF_MUX_ADDR, 4);
2218 secpcm_portslc_virt_addr = ioremap(SEC_PCM_PORT_SLC_ADDR, 4);
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002219
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002220 return ret;
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002221}
2222module_init(mdm9615_audio_init);
2223
2224static void __exit mdm9615_audio_exit(void)
2225{
2226 if (!cpu_is_msm9615()) {
2227 pr_err("%s: Not the right machine type\n", __func__);
2228 return ;
2229 }
2230 mdm9615_free_headset_mic_gpios();
2231 platform_device_unregister(mdm9615_snd_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07002232 kfree(mbhc_cfg.calibration);
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002233 iounmap(msm9x15_i2s_ctl.sif_virt_addr);
2234 iounmap(msm9x15_i2s_ctl.spare_virt_addr);
Shiv Maliyappanahallia416ee22012-06-01 16:02:35 -07002235 iounmap(sif_virt_addr);
2236 iounmap(secpcm_portslc_virt_addr);
Venkat Sudhirdb7aa2b2012-05-15 15:06:14 -07002237
Shiv Maliyappanahallif94fba32012-01-05 19:34:38 -08002238}
2239module_exit(mdm9615_audio_exit);
2240
2241MODULE_DESCRIPTION("ALSA SoC MDM9615");
2242MODULE_LICENSE("GPL v2");