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