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