blob: 3388261ee3a8a31a1444aaee4c15c63722f2010d [file] [log] [blame]
Joonwoo Park0976d012011-12-22 11:48:18 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/clk.h>
14#include <linux/delay.h>
15#include <linux/gpio.h>
16#include <linux/mfd/pm8xxx/pm8921.h>
17#include <linux/platform_device.h>
18#include <linux/gpio.h>
19#include <linux/mfd/pm8xxx/pm8921.h>
Joonwoo Park0976d012011-12-22 11:48:18 -080020#include <linux/slab.h>
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -080021#include <sound/core.h>
22#include <sound/soc.h>
23#include <sound/soc-dapm.h>
24#include <sound/soc-dsp.h>
25#include <sound/pcm.h>
26#include <sound/jack.h>
27#include <asm/mach-types.h>
28#include <mach/socinfo.h>
29#include "msm-pcm-routing.h"
30#include "../codecs/wcd9310.h"
31
32/* 8064 machine driver */
33
34#define PM8921_GPIO_BASE NR_GPIO_IRQS
35#define PM8921_GPIO_PM_TO_SYS(pm_gpio) (pm_gpio - 1 + PM8921_GPIO_BASE)
36
37#define MSM8064_SPK_ON 1
38#define MSM8064_SPK_OFF 0
39
40#define MSM_SLIM_0_RX_MAX_CHANNELS 2
41#define MSM_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 43
52#define GPIO_AUX_PCM_DIN 44
53#define GPIO_AUX_PCM_SYNC 45
54#define GPIO_AUX_PCM_CLK 46
55
Joonwoo Park0976d012011-12-22 11:48:18 -080056#define TABLA_EXT_CLK_RATE 12288000
57
Swaminathan Sathappan4ea7f1a02012-02-29 12:55:55 -080058#define TABLA_MBHC_DEF_BUTTONS 8
Joonwoo Park0976d012011-12-22 11:48:18 -080059#define TABLA_MBHC_DEF_RLOADS 5
60
Neema Shetty3c9d2862012-03-11 01:25:32 -080061/* Shared channel numbers for Slimbus ports that connect APQ to MDM. */
62enum {
63 SLIM_1_RX_1 = 145, /* BT-SCO and USB TX */
64 SLIM_1_TX_1 = 146, /* BT-SCO and USB RX */
65 SLIM_2_RX_1 = 147, /* HDMI RX */
66 SLIM_3_RX_1 = 148, /* In-call recording RX */
67 SLIM_3_RX_2 = 149, /* In-call recording RX */
68 SLIM_4_TX_1 = 150, /* In-call musid delivery TX */
69};
70
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -080071static u32 top_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(18);
72static u32 bottom_spk_pamp_gpio = PM8921_GPIO_PM_TO_SYS(19);
73static int msm_spk_control;
74static int msm_ext_bottom_spk_pamp;
75static int msm_ext_top_spk_pamp;
76static int msm_slim_0_rx_ch = 1;
77static int msm_slim_0_tx_ch = 1;
78
79static int msm_btsco_rate = BTSCO_RATE_8KHZ;
80static int msm_btsco_ch = 1;
81
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -080082static struct clk *codec_clk;
83static int clk_users;
84
85static int msm_headset_gpios_configured;
86
87static struct snd_soc_jack hs_jack;
88static struct snd_soc_jack button_jack;
89
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -070090static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
91 bool dapm);
92
93static struct tabla_mbhc_config mbhc_cfg = {
94 .headset_jack = &hs_jack,
95 .button_jack = &button_jack,
96 .read_fw_bin = false,
97 .calibration = NULL,
98 .micbias = TABLA_MICBIAS2,
99 .mclk_cb_fn = msm_enable_codec_ext_clk,
100 .mclk_rate = TABLA_EXT_CLK_RATE,
101 .gpio = 0, /* MBHC GPIO is not configured */
102 .gpio_irq = 0,
103 .gpio_level_insert = 1,
104};
Joonwoo Park0976d012011-12-22 11:48:18 -0800105
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800106static void msm_enable_ext_spk_amp_gpio(u32 spk_amp_gpio)
107{
108 int ret = 0;
109
110 struct pm_gpio param = {
111 .direction = PM_GPIO_DIR_OUT,
112 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
113 .output_value = 1,
114 .pull = PM_GPIO_PULL_NO,
115 .vin_sel = PM_GPIO_VIN_S4,
116 .out_strength = PM_GPIO_STRENGTH_MED,
117 .
118 function = PM_GPIO_FUNC_NORMAL,
119 };
120
121 if (spk_amp_gpio == bottom_spk_pamp_gpio) {
122
123 ret = gpio_request(bottom_spk_pamp_gpio, "BOTTOM_SPK_AMP");
124 if (ret) {
125 pr_err("%s: Error requesting BOTTOM SPK AMP GPIO %u\n",
126 __func__, bottom_spk_pamp_gpio);
127 return;
128 }
129 ret = pm8xxx_gpio_config(bottom_spk_pamp_gpio, &param);
130 if (ret)
131 pr_err("%s: Failed to configure Bottom Spk Ampl"
132 " gpio %u\n", __func__, bottom_spk_pamp_gpio);
133 else {
134 pr_debug("%s: enable Bottom spkr amp gpio\n", __func__);
135 gpio_direction_output(bottom_spk_pamp_gpio, 1);
136 }
137
138 } else if (spk_amp_gpio == top_spk_pamp_gpio) {
139
140 ret = gpio_request(top_spk_pamp_gpio, "TOP_SPK_AMP");
141 if (ret) {
142 pr_err("%s: Error requesting GPIO %d\n", __func__,
143 top_spk_pamp_gpio);
144 return;
145 }
146 ret = pm8xxx_gpio_config(top_spk_pamp_gpio, &param);
147 if (ret)
148 pr_err("%s: Failed to configure Top Spk Ampl"
149 " gpio %u\n", __func__, top_spk_pamp_gpio);
150 else {
151 pr_debug("%s: enable Top spkr amp gpio\n", __func__);
152 gpio_direction_output(top_spk_pamp_gpio, 1);
153 }
154 } else {
155 pr_err("%s: ERROR : Invalid External Speaker Ampl GPIO."
156 " gpio = %u\n", __func__, spk_amp_gpio);
157 return;
158 }
159}
160
161static void msm_ext_spk_power_amp_on(u32 spk)
162{
163 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
164
165 if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
166 (msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
167
168 pr_debug("%s() External Bottom Speaker Ampl already "
169 "turned on. spk = 0x%08x\n", __func__, spk);
170 return;
171 }
172
173 msm_ext_bottom_spk_pamp |= spk;
174
175 if ((msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_POS) &&
176 (msm_ext_bottom_spk_pamp & BOTTOM_SPK_AMP_NEG)) {
177
178 msm_enable_ext_spk_amp_gpio(bottom_spk_pamp_gpio);
179 pr_debug("%s: slepping 4 ms after turning on external "
180 " Bottom Speaker Ampl\n", __func__);
181 usleep_range(4000, 4000);
182 }
183
184 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
185
186 if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
187 (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
188
189 pr_debug("%s() External Top Speaker Ampl already"
190 "turned on. spk = 0x%08x\n", __func__, spk);
191 return;
192 }
193
194 msm_ext_top_spk_pamp |= spk;
195
196 if ((msm_ext_top_spk_pamp & TOP_SPK_AMP_POS) &&
197 (msm_ext_top_spk_pamp & TOP_SPK_AMP_NEG)) {
198
199 msm_enable_ext_spk_amp_gpio(top_spk_pamp_gpio);
200 pr_debug("%s: sleeping 4 ms after turning on "
201 " external Top Speaker Ampl\n", __func__);
202 usleep_range(4000, 4000);
203 }
204 } else {
205
206 pr_err("%s: ERROR : Invalid External Speaker Ampl. spk = 0x%08x\n",
207 __func__, spk);
208 return;
209 }
210}
211
212static void msm_ext_spk_power_amp_off(u32 spk)
213{
214 if (spk & (BOTTOM_SPK_AMP_POS | BOTTOM_SPK_AMP_NEG)) {
215
216 if (!msm_ext_bottom_spk_pamp)
217 return;
218
219 gpio_direction_output(bottom_spk_pamp_gpio, 0);
220 gpio_free(bottom_spk_pamp_gpio);
221 msm_ext_bottom_spk_pamp = 0;
222
223 pr_debug("%s: sleeping 4 ms after turning off external Bottom"
224 " Speaker Ampl\n", __func__);
225
226 usleep_range(4000, 4000);
227
228 } else if (spk & (TOP_SPK_AMP_POS | TOP_SPK_AMP_NEG)) {
229
230 if (!msm_ext_top_spk_pamp)
231 return;
232
233 gpio_direction_output(top_spk_pamp_gpio, 0);
234 gpio_free(top_spk_pamp_gpio);
235 msm_ext_top_spk_pamp = 0;
236
237 pr_debug("%s: sleeping 4 ms after turning off external Top"
238 " Spkaker Ampl\n", __func__);
239
240 usleep_range(4000, 4000);
241 } else {
242
243 pr_err("%s: ERROR : Invalid Ext Spk Ampl. spk = 0x%08x\n",
244 __func__, spk);
245 return;
246 }
247}
248
249static void msm_ext_control(struct snd_soc_codec *codec)
250{
251 struct snd_soc_dapm_context *dapm = &codec->dapm;
252
253 pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
254 if (msm_spk_control == MSM8064_SPK_ON) {
255 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
256 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
257 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
258 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
259 } else {
260 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Pos");
261 snd_soc_dapm_disable_pin(dapm, "Ext Spk Bottom Neg");
262 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Pos");
263 snd_soc_dapm_disable_pin(dapm, "Ext Spk Top Neg");
264 }
265
266 snd_soc_dapm_sync(dapm);
267}
268
269static int msm_get_spk(struct snd_kcontrol *kcontrol,
270 struct snd_ctl_elem_value *ucontrol)
271{
272 pr_debug("%s: msm_spk_control = %d", __func__, msm_spk_control);
273 ucontrol->value.integer.value[0] = msm_spk_control;
274 return 0;
275}
276static int msm_set_spk(struct snd_kcontrol *kcontrol,
277 struct snd_ctl_elem_value *ucontrol)
278{
279 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
280
281 pr_debug("%s()\n", __func__);
282 if (msm_spk_control == ucontrol->value.integer.value[0])
283 return 0;
284
285 msm_spk_control = ucontrol->value.integer.value[0];
286 msm_ext_control(codec);
287 return 1;
288}
289static int msm_spkramp_event(struct snd_soc_dapm_widget *w,
290 struct snd_kcontrol *k, int event)
291{
292 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
293
294 if (SND_SOC_DAPM_EVENT_ON(event)) {
295 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
296 msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_POS);
297 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
298 msm_ext_spk_power_amp_on(BOTTOM_SPK_AMP_NEG);
299 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
300 msm_ext_spk_power_amp_on(TOP_SPK_AMP_POS);
301 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
302 msm_ext_spk_power_amp_on(TOP_SPK_AMP_NEG);
303 else {
304 pr_err("%s() Invalid Speaker Widget = %s\n",
305 __func__, w->name);
306 return -EINVAL;
307 }
308
309 } else {
310 if (!strncmp(w->name, "Ext Spk Bottom Pos", 18))
311 msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_POS);
312 else if (!strncmp(w->name, "Ext Spk Bottom Neg", 18))
313 msm_ext_spk_power_amp_off(BOTTOM_SPK_AMP_NEG);
314 else if (!strncmp(w->name, "Ext Spk Top Pos", 15))
315 msm_ext_spk_power_amp_off(TOP_SPK_AMP_POS);
316 else if (!strncmp(w->name, "Ext Spk Top Neg", 15))
317 msm_ext_spk_power_amp_off(TOP_SPK_AMP_NEG);
318 else {
319 pr_err("%s() Invalid Speaker Widget = %s\n",
320 __func__, w->name);
321 return -EINVAL;
322 }
323 }
324 return 0;
325}
326
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700327static int msm_enable_codec_ext_clk(struct snd_soc_codec *codec, int enable,
328 bool dapm)
Joonwoo Park0976d012011-12-22 11:48:18 -0800329{
330 pr_debug("%s: enable = %d\n", __func__, enable);
331 if (enable) {
332 clk_users++;
333 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
334 if (clk_users != 1)
335 return 0;
336
Joonwoo Park0976d012011-12-22 11:48:18 -0800337 if (codec_clk) {
338 clk_set_rate(codec_clk, TABLA_EXT_CLK_RATE);
339 clk_enable(codec_clk);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700340 tabla_mclk_enable(codec, 1, dapm);
Joonwoo Park0976d012011-12-22 11:48:18 -0800341 } else {
342 pr_err("%s: Error setting Tabla MCLK\n", __func__);
343 clk_users--;
344 return -EINVAL;
345 }
346 } else {
347 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
348 if (clk_users == 0)
349 return 0;
350 clk_users--;
351 if (!clk_users) {
352 pr_debug("%s: disabling MCLK. clk_users = %d\n",
353 __func__, clk_users);
354 clk_disable(codec_clk);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700355 tabla_mclk_enable(codec, 0, dapm);
Joonwoo Park0976d012011-12-22 11:48:18 -0800356 }
357 }
358 return 0;
359}
360
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800361static int msm_mclk_event(struct snd_soc_dapm_widget *w,
362 struct snd_kcontrol *kcontrol, int event)
363{
364 pr_debug("%s: event = %d\n", __func__, event);
365
366 switch (event) {
367 case SND_SOC_DAPM_PRE_PMU:
368
369 clk_users++;
370 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
371
372 if (clk_users != 1)
373 return 0;
374
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800375 if (codec_clk) {
376 clk_set_rate(codec_clk, 12288000);
377 clk_enable(codec_clk);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700378 tabla_mclk_enable(w->codec, 1, true);
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800379
380 } else {
381 pr_err("%s: Error setting Tabla MCLK\n", __func__);
382 clk_users--;
383 return -EINVAL;
384 }
385 break;
386 case SND_SOC_DAPM_POST_PMD:
387
388 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
389
390 if (clk_users == 0)
391 return 0;
392
393 clk_users--;
394
395 if (!clk_users) {
396 pr_debug("%s: disabling MCLK. clk_users = %d\n",
397 __func__, clk_users);
398
399 clk_disable(codec_clk);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700400 tabla_mclk_enable(w->codec, 0, true);
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800401 }
402 break;
403 }
404 return 0;
405}
406
407static const struct snd_soc_dapm_widget msm_dapm_widgets[] = {
408
409 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
410 msm_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
411
412 SND_SOC_DAPM_SPK("Ext Spk Bottom Pos", msm_spkramp_event),
413 SND_SOC_DAPM_SPK("Ext Spk Bottom Neg", msm_spkramp_event),
414
415 SND_SOC_DAPM_SPK("Ext Spk Top Pos", msm_spkramp_event),
416 SND_SOC_DAPM_SPK("Ext Spk Top Neg", msm_spkramp_event),
417
418 SND_SOC_DAPM_MIC("Handset Mic", NULL),
419 SND_SOC_DAPM_MIC("Headset Mic", NULL),
420 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
421 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
422 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
423
424 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
425 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
426 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
427 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
428 SND_SOC_DAPM_MIC("Digital Mic5", NULL),
429 SND_SOC_DAPM_MIC("Digital Mic6", NULL),
430
431};
432
433static const struct snd_soc_dapm_route common_audio_map[] = {
434
435 {"RX_BIAS", NULL, "MCLK"},
436 {"LDO_H", NULL, "MCLK"},
437
438 /* Speaker path */
439 {"Ext Spk Bottom Pos", NULL, "LINEOUT1"},
440 {"Ext Spk Bottom Neg", NULL, "LINEOUT3"},
441
442 {"Ext Spk Top Pos", NULL, "LINEOUT2"},
443 {"Ext Spk Top Neg", NULL, "LINEOUT4"},
444
445 /* Microphone path */
446 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
447 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
448
449 {"AMIC2", NULL, "MIC BIAS2 External"},
450 {"MIC BIAS2 External", NULL, "Headset Mic"},
451
452 /**
453 * AMIC3 and AMIC4 inputs are connected to ANC microphones
454 * These mics are biased differently on CDP and FLUID
455 * routing entries below are based on bias arrangement
456 * on FLUID.
457 */
458 {"AMIC3", NULL, "MIC BIAS3 Internal1"},
459 {"MIC BIAS3 Internal1", NULL, "ANCRight Headset Mic"},
460
461 {"AMIC4", NULL, "MIC BIAS1 Internal2"},
462 {"MIC BIAS1 Internal2", NULL, "ANCLeft Headset Mic"},
463
464 {"HEADPHONE", NULL, "LDO_H"},
465
466 /**
467 * The digital Mic routes are setup considering
468 * fluid as default device.
469 */
470
471 /**
472 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
473 * Digital Mic GM5 on CDP mainboard.
474 * Conncted to DMIC2 Input on Tabla codec.
475 */
476 {"DMIC2", NULL, "MIC BIAS1 External"},
477 {"MIC BIAS1 External", NULL, "Digital Mic1"},
478
479 /**
480 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
481 * Digital Mic GM6 on CDP mainboard.
482 * Conncted to DMIC1 Input on Tabla codec.
483 */
484 {"DMIC1", NULL, "MIC BIAS1 External"},
485 {"MIC BIAS1 External", NULL, "Digital Mic2"},
486
487 /**
488 * Digital Mic3. Back Bottom Digital Mic on Fluid.
489 * Digital Mic GM1 on CDP mainboard.
490 * Conncted to DMIC4 Input on Tabla codec.
491 */
492 {"DMIC4", NULL, "MIC BIAS3 External"},
493 {"MIC BIAS3 External", NULL, "Digital Mic3"},
494
495 /**
496 * Digital Mic4. Back top Digital Mic on Fluid.
497 * Digital Mic GM2 on CDP mainboard.
498 * Conncted to DMIC3 Input on Tabla codec.
499 */
500 {"DMIC3", NULL, "MIC BIAS3 External"},
501 {"MIC BIAS3 External", NULL, "Digital Mic4"},
502
503 /**
504 * Digital Mic5. Front top Digital Mic on Fluid.
505 * Digital Mic GM3 on CDP mainboard.
506 * Conncted to DMIC5 Input on Tabla codec.
507 */
508 {"DMIC5", NULL, "MIC BIAS4 External"},
509 {"MIC BIAS4 External", NULL, "Digital Mic5"},
510
511 /* Tabla digital Mic6 - back bottom digital Mic on Liquid and
512 * bottom mic on CDP. FLUID/MTP do not have dmic6 installed.
513 */
514 {"DMIC6", NULL, "MIC BIAS4 External"},
515 {"MIC BIAS4 External", NULL, "Digital Mic6"},
516};
517
518static const char *spk_function[] = {"Off", "On"};
519static const char *slim0_rx_ch_text[] = {"One", "Two"};
520static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
521
522static const struct soc_enum msm_enum[] = {
523 SOC_ENUM_SINGLE_EXT(2, spk_function),
524 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
525 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
526};
527
528static const char *btsco_rate_text[] = {"8000", "16000"};
529static const struct soc_enum msm_btsco_enum[] = {
530 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
531};
532
533static int msm_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
534 struct snd_ctl_elem_value *ucontrol)
535{
536 pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
537 msm_slim_0_rx_ch);
538 ucontrol->value.integer.value[0] = msm_slim_0_rx_ch - 1;
539 return 0;
540}
541
542static int msm_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
543 struct snd_ctl_elem_value *ucontrol)
544{
545 msm_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
546
547 pr_debug("%s: msm_slim_0_rx_ch = %d\n", __func__,
548 msm_slim_0_rx_ch);
549 return 1;
550}
551
552static int msm_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
553 struct snd_ctl_elem_value *ucontrol)
554{
555 pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
556 msm_slim_0_tx_ch);
557 ucontrol->value.integer.value[0] = msm_slim_0_tx_ch - 1;
558 return 0;
559}
560
561static int msm_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
562 struct snd_ctl_elem_value *ucontrol)
563{
564 msm_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
565
566 pr_debug("%s: msm_slim_0_tx_ch = %d\n", __func__,
567 msm_slim_0_tx_ch);
568 return 1;
569}
570
571static int msm_btsco_rate_get(struct snd_kcontrol *kcontrol,
572 struct snd_ctl_elem_value *ucontrol)
573{
574 pr_debug("%s: msm_btsco_rate = %d", __func__,
575 msm_btsco_rate);
576 ucontrol->value.integer.value[0] = msm_btsco_rate;
577 return 0;
578}
579
580static int msm_btsco_rate_put(struct snd_kcontrol *kcontrol,
581 struct snd_ctl_elem_value *ucontrol)
582{
583 switch (ucontrol->value.integer.value[0]) {
584 case 0:
585 msm_btsco_rate = BTSCO_RATE_8KHZ;
586 break;
587 case 1:
588 msm_btsco_rate = BTSCO_RATE_16KHZ;
589 break;
590 default:
591 msm_btsco_rate = BTSCO_RATE_8KHZ;
592 break;
593 }
594 pr_debug("%s: msm_btsco_rate = %d\n", __func__,
595 msm_btsco_rate);
596 return 0;
597}
598
599static const struct snd_kcontrol_new tabla_msm_controls[] = {
600 SOC_ENUM_EXT("Speaker Function", msm_enum[0], msm_get_spk,
601 msm_set_spk),
602 SOC_ENUM_EXT("SLIM_0_RX Channels", msm_enum[1],
603 msm_slim_0_rx_ch_get, msm_slim_0_rx_ch_put),
604 SOC_ENUM_EXT("SLIM_0_TX Channels", msm_enum[2],
605 msm_slim_0_tx_ch_get, msm_slim_0_tx_ch_put),
606};
607
608static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
609 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm_btsco_enum[0],
610 msm_btsco_rate_get, msm_btsco_rate_put),
611};
612
613static int msm_btsco_init(struct snd_soc_pcm_runtime *rtd)
614{
615 int err = 0;
616 struct snd_soc_platform *platform = rtd->platform;
617
618 err = snd_soc_add_platform_controls(platform,
619 int_btsco_rate_mixer_controls,
620 ARRAY_SIZE(int_btsco_rate_mixer_controls));
621 if (err < 0)
622 return err;
623 return 0;
624}
625
Joonwoo Park0976d012011-12-22 11:48:18 -0800626static void *def_tabla_mbhc_cal(void)
627{
628 void *tabla_cal;
629 struct tabla_mbhc_btn_detect_cfg *btn_cfg;
630 u16 *btn_low, *btn_high;
Swaminathan Sathappan4ea7f1a02012-02-29 12:55:55 -0800631 u8 *n_ready, *n_cic, *gain;
Joonwoo Park0976d012011-12-22 11:48:18 -0800632
633 tabla_cal = kzalloc(TABLA_MBHC_CAL_SIZE(TABLA_MBHC_DEF_BUTTONS,
634 TABLA_MBHC_DEF_RLOADS),
635 GFP_KERNEL);
636 if (!tabla_cal) {
637 pr_err("%s: out of memory\n", __func__);
638 return NULL;
639 }
640
641#define S(X, Y) ((TABLA_MBHC_CAL_GENERAL_PTR(tabla_cal)->X) = (Y))
642 S(t_ldoh, 100);
643 S(t_bg_fast_settle, 100);
644 S(t_shutdown_plug_rem, 255);
645 S(mbhc_nsa, 4);
646 S(mbhc_navg, 4);
647#undef S
648#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_DET_PTR(tabla_cal)->X) = (Y))
649 S(mic_current, TABLA_PID_MIC_5_UA);
650 S(hph_current, TABLA_PID_MIC_5_UA);
651 S(t_mic_pid, 100);
Swaminathan Sathappan4ea7f1a02012-02-29 12:55:55 -0800652 S(t_ins_complete, 250);
Joonwoo Park0976d012011-12-22 11:48:18 -0800653 S(t_ins_retry, 200);
654#undef S
655#define S(X, Y) ((TABLA_MBHC_CAL_PLUG_TYPE_PTR(tabla_cal)->X) = (Y))
656 S(v_no_mic, 30);
Swaminathan Sathappan4ea7f1a02012-02-29 12:55:55 -0800657 S(v_hs_max, 1550);
Joonwoo Park0976d012011-12-22 11:48:18 -0800658#undef S
659#define S(X, Y) ((TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal)->X) = (Y))
Swaminathan Sathappan4ea7f1a02012-02-29 12:55:55 -0800660 S(c[0], 62);
661 S(c[1], 124);
662 S(nc, 1);
663 S(n_meas, 3);
Joonwoo Park0976d012011-12-22 11:48:18 -0800664 S(mbhc_nsc, 11);
Swaminathan Sathappan4ea7f1a02012-02-29 12:55:55 -0800665 S(n_btn_meas, 1);
666 S(n_btn_con, 2);
Joonwoo Park0976d012011-12-22 11:48:18 -0800667 S(num_btn, TABLA_MBHC_DEF_BUTTONS);
668 S(v_btn_press_delta_sta, 100);
669 S(v_btn_press_delta_cic, 50);
670#undef S
671 btn_cfg = TABLA_MBHC_CAL_BTN_DET_PTR(tabla_cal);
672 btn_low = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_LOW);
673 btn_high = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_V_BTN_HIGH);
Swaminathan Sathappan4ea7f1a02012-02-29 12:55:55 -0800674 btn_low[0] = -50;
675 btn_high[0] = 10;
676 btn_low[1] = 11;
677 btn_high[1] = 38;
678 btn_low[2] = 39;
679 btn_high[2] = 64;
680 btn_low[3] = 65;
681 btn_high[3] = 91;
682 btn_low[4] = 92;
683 btn_high[4] = 115;
684 btn_low[5] = 116;
685 btn_high[5] = 141;
686 btn_low[6] = 142;
687 btn_high[6] = 163;
688 btn_low[7] = 164;
689 btn_high[7] = 250;
690 n_ready = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_READY);
691 n_ready[0] = 48;
692 n_ready[1] = 38;
Joonwoo Park0976d012011-12-22 11:48:18 -0800693 n_cic = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_N_CIC);
Swaminathan Sathappan4ea7f1a02012-02-29 12:55:55 -0800694 n_cic[0] = 60;
695 n_cic[1] = 47;
Joonwoo Park0976d012011-12-22 11:48:18 -0800696 gain = tabla_mbhc_cal_btn_det_mp(btn_cfg, TABLA_BTN_DET_GAIN);
697 gain[0] = 11;
698 gain[1] = 9;
699
700 return tabla_cal;
701}
702
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800703static int msm_hw_params(struct snd_pcm_substream *substream,
704 struct snd_pcm_hw_params *params)
705{
706 struct snd_soc_pcm_runtime *rtd = substream->private_data;
707 struct snd_soc_dai *codec_dai = rtd->codec_dai;
708 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
709 int ret = 0;
710 unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
711 unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
712
713 pr_debug("%s: ch=%d\n", __func__,
714 msm_slim_0_rx_ch);
715 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
716 ret = snd_soc_dai_get_channel_map(codec_dai,
717 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
718 if (ret < 0) {
719 pr_err("%s: failed to get codec chan map\n", __func__);
720 goto end;
721 }
722
723 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
724 msm_slim_0_rx_ch, rx_ch);
725 if (ret < 0) {
726 pr_err("%s: failed to set cpu chan map\n", __func__);
727 goto end;
728 }
729 ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
730 msm_slim_0_rx_ch, rx_ch);
731 if (ret < 0) {
732 pr_err("%s: failed to set codec channel map\n",
733 __func__);
734 goto end;
735 }
736 } else {
737 ret = snd_soc_dai_get_channel_map(codec_dai,
738 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
739 if (ret < 0) {
740 pr_err("%s: failed to get codec chan map\n", __func__);
741 goto end;
742 }
743 ret = snd_soc_dai_set_channel_map(cpu_dai,
744 msm_slim_0_tx_ch, tx_ch, 0 , 0);
745 if (ret < 0) {
746 pr_err("%s: failed to set cpu chan map\n", __func__);
747 goto end;
748 }
749 ret = snd_soc_dai_set_channel_map(codec_dai,
750 msm_slim_0_tx_ch, tx_ch, 0, 0);
751 if (ret < 0) {
752 pr_err("%s: failed to set codec channel map\n",
753 __func__);
754 goto end;
755 }
756
757
758 }
759end:
760 return ret;
761}
762
Helen Zengf3b17fb2012-02-28 15:07:38 -0800763static int msm_stubrx_init(struct snd_soc_pcm_runtime *rtd)
764{
765 rtd->pmdown_time = 0;
766
767 return 0;
768}
769
Neema Shetty3c9d2862012-03-11 01:25:32 -0800770static int msm_slimbus_1_hw_params(struct snd_pcm_substream *substream,
771 struct snd_pcm_hw_params *params)
772{
773 struct snd_soc_pcm_runtime *rtd = substream->private_data;
774 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
775 int ret = 0;
776 unsigned int rx_ch = SLIM_1_RX_1, tx_ch = SLIM_1_TX_1;
777
778 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
779 pr_debug("%s: APQ BT/USB TX -> SLIMBUS_1_RX -> MDM TX shared ch %d\n",
780 __func__, rx_ch);
781
782 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0, 1, &rx_ch);
783 if (ret < 0) {
784 pr_err("%s: Erorr %d setting SLIM_1 RX channel map\n",
785 __func__, ret);
786
787 goto end;
788 }
789 } else {
790 pr_debug("%s: MDM RX -> SLIMBUS_1_TX -> APQ BT/USB Rx shared ch %d\n",
791 __func__, tx_ch);
792
793 ret = snd_soc_dai_set_channel_map(cpu_dai, 1, &tx_ch, 0, 0);
794 if (ret < 0) {
795 pr_err("%s: Erorr %d setting SLIM_1 TX channel map\n",
796 __func__, ret);
797
798 goto end;
799 }
800 }
801
802end:
803 return ret;
804}
805
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800806static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
807{
808 int err;
809 struct snd_soc_codec *codec = rtd->codec;
810 struct snd_soc_dapm_context *dapm = &codec->dapm;
Kuirong Wanga9c3acc2012-02-09 17:00:45 -0800811 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800812
Kuirong Wanga9c3acc2012-02-09 17:00:45 -0800813 pr_debug("%s(), dev_name%s\n", __func__, dev_name(cpu_dai->dev));
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800814
815 /*if (machine_is_msm_liquid()) {
816 top_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(19));
817 bottom_spk_pamp_gpio = (PM8921_GPIO_PM_TO_SYS(18));
818 }*/
819
820 rtd->pmdown_time = 0;
821
822 err = snd_soc_add_controls(codec, tabla_msm_controls,
823 ARRAY_SIZE(tabla_msm_controls));
824 if (err < 0)
825 return err;
826
827 snd_soc_dapm_new_controls(dapm, msm_dapm_widgets,
828 ARRAY_SIZE(msm_dapm_widgets));
829
830 snd_soc_dapm_add_routes(dapm, common_audio_map,
831 ARRAY_SIZE(common_audio_map));
832
833 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Pos");
834 snd_soc_dapm_enable_pin(dapm, "Ext Spk Bottom Neg");
835 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Pos");
836 snd_soc_dapm_enable_pin(dapm, "Ext Spk Top Neg");
837
838 snd_soc_dapm_sync(dapm);
839
840 err = snd_soc_jack_new(codec, "Headset Jack",
841 (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
842 &hs_jack);
843 if (err) {
844 pr_err("failed to create new jack\n");
845 return err;
846 }
847
848 err = snd_soc_jack_new(codec, "Button Jack",
Swaminathan Sathappan4ea7f1a02012-02-29 12:55:55 -0800849 TABLA_JACK_BUTTON_MASK, &button_jack);
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800850 if (err) {
851 pr_err("failed to create new jack\n");
852 return err;
853 }
854
Kuirong Wanga9c3acc2012-02-09 17:00:45 -0800855 codec_clk = clk_get(cpu_dai->dev, "osr_clk");
856
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -0700857 err = tabla_hs_detect(codec, &mbhc_cfg);
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800858
Joonwoo Park03324832012-03-19 19:36:16 -0700859 return err;
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800860}
861
862static struct snd_soc_dsp_link lpa_fe_media = {
863 .playback = true,
864 .trigger = {
865 SND_SOC_DSP_TRIGGER_POST,
866 SND_SOC_DSP_TRIGGER_POST
867 },
868};
869
870static struct snd_soc_dsp_link fe_media = {
871 .playback = true,
872 .capture = true,
873 .trigger = {
874 SND_SOC_DSP_TRIGGER_POST,
875 SND_SOC_DSP_TRIGGER_POST
876 },
877};
878
879static struct snd_soc_dsp_link slimbus0_hl_media = {
880 .playback = true,
881 .capture = true,
882 .trigger = {
883 SND_SOC_DSP_TRIGGER_POST,
884 SND_SOC_DSP_TRIGGER_POST
885 },
886};
887
888static struct snd_soc_dsp_link int_fm_hl_media = {
889 .playback = true,
890 .capture = true,
891 .trigger = {
892 SND_SOC_DSP_TRIGGER_POST,
893 SND_SOC_DSP_TRIGGER_POST
894 },
895};
896
897static int msm_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
898 struct snd_pcm_hw_params *params)
899{
900 struct snd_interval *rate = hw_param_interval(params,
901 SNDRV_PCM_HW_PARAM_RATE);
902
903 struct snd_interval *channels = hw_param_interval(params,
904 SNDRV_PCM_HW_PARAM_CHANNELS);
905
906 pr_debug("%s()\n", __func__);
907 rate->min = rate->max = 48000;
908 channels->min = channels->max = msm_slim_0_rx_ch;
909
910 return 0;
911}
912
913static int msm_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
914 struct snd_pcm_hw_params *params)
915{
916 struct snd_interval *rate = hw_param_interval(params,
917 SNDRV_PCM_HW_PARAM_RATE);
918
919 struct snd_interval *channels = hw_param_interval(params,
920 SNDRV_PCM_HW_PARAM_CHANNELS);
921
922 pr_debug("%s()\n", __func__);
923 rate->min = rate->max = 48000;
924 channels->min = channels->max = msm_slim_0_tx_ch;
925
926 return 0;
927}
928
929static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
930 struct snd_pcm_hw_params *params)
931{
932 struct snd_interval *rate = hw_param_interval(params,
933 SNDRV_PCM_HW_PARAM_RATE);
934
935 pr_debug("%s()\n", __func__);
936 rate->min = rate->max = 48000;
937
938 return 0;
939}
940
Swaminathan Sathappanfd9dbad2012-02-15 16:56:44 -0800941static int msm_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
942 struct snd_pcm_hw_params *params)
943{
944 struct snd_interval *rate = hw_param_interval(params,
945 SNDRV_PCM_HW_PARAM_RATE);
946
947 struct snd_interval *channels = hw_param_interval(params,
948 SNDRV_PCM_HW_PARAM_CHANNELS);
949
950 pr_debug("%s channels->min %u channels->max %u ()\n", __func__,
951 channels->min, channels->max);
952
953 rate->min = rate->max = 48000;
954
955 return 0;
956}
957
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800958static int msm_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
959 struct snd_pcm_hw_params *params)
960{
961 struct snd_interval *rate = hw_param_interval(params,
962 SNDRV_PCM_HW_PARAM_RATE);
963
964 struct snd_interval *channels = hw_param_interval(params,
965 SNDRV_PCM_HW_PARAM_CHANNELS);
966
967 rate->min = rate->max = msm_btsco_rate;
968 channels->min = channels->max = msm_btsco_ch;
969
970 return 0;
971}
972static int msm_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
973 struct snd_pcm_hw_params *params)
974{
975 struct snd_interval *rate = hw_param_interval(params,
976 SNDRV_PCM_HW_PARAM_RATE);
977
978 struct snd_interval *channels = hw_param_interval(params,
979 SNDRV_PCM_HW_PARAM_CHANNELS);
980
981 /* PCM only supports mono output with 8khz sample rate */
982 rate->min = rate->max = 8000;
983 channels->min = channels->max = 1;
984
985 return 0;
986}
Neema Shetty3c9d2862012-03-11 01:25:32 -0800987
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -0800988static int msm_aux_pcm_get_gpios(void)
989{
990 int ret = 0;
991
992 pr_debug("%s\n", __func__);
993
994 ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
995 if (ret < 0) {
996 pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
997 __func__, GPIO_AUX_PCM_DOUT);
998 goto fail_dout;
999 }
1000
1001 ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
1002 if (ret < 0) {
1003 pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
1004 __func__, GPIO_AUX_PCM_DIN);
1005 goto fail_din;
1006 }
1007
1008 ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
1009 if (ret < 0) {
1010 pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
1011 __func__, GPIO_AUX_PCM_SYNC);
1012 goto fail_sync;
1013 }
1014 ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
1015 if (ret < 0) {
1016 pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
1017 __func__, GPIO_AUX_PCM_CLK);
1018 goto fail_clk;
1019 }
1020
1021 return 0;
1022
1023fail_clk:
1024 gpio_free(GPIO_AUX_PCM_SYNC);
1025fail_sync:
1026 gpio_free(GPIO_AUX_PCM_DIN);
1027fail_din:
1028 gpio_free(GPIO_AUX_PCM_DOUT);
1029fail_dout:
1030
1031 return ret;
1032}
1033
1034static int msm_aux_pcm_free_gpios(void)
1035{
1036 gpio_free(GPIO_AUX_PCM_DIN);
1037 gpio_free(GPIO_AUX_PCM_DOUT);
1038 gpio_free(GPIO_AUX_PCM_SYNC);
1039 gpio_free(GPIO_AUX_PCM_CLK);
1040
1041 return 0;
1042}
1043static int msm_startup(struct snd_pcm_substream *substream)
1044{
1045 pr_debug("%s(): substream = %s stream = %d\n", __func__,
1046 substream->name, substream->stream);
1047 return 0;
1048}
1049
1050static int msm_auxpcm_startup(struct snd_pcm_substream *substream)
1051{
1052 int ret = 0;
1053
1054 pr_debug("%s(): substream = %s\n", __func__, substream->name);
1055 ret = msm_aux_pcm_get_gpios();
1056 if (ret < 0) {
1057 pr_err("%s: Aux PCM GPIO request failed\n", __func__);
1058 return -EINVAL;
1059 }
1060 return 0;
1061}
1062
1063static void msm_auxpcm_shutdown(struct snd_pcm_substream *substream)
1064{
1065
1066 pr_debug("%s(): substream = %s\n", __func__, substream->name);
1067 msm_aux_pcm_free_gpios();
1068}
1069
1070static void msm_shutdown(struct snd_pcm_substream *substream)
1071{
1072 pr_debug("%s(): substream = %s stream = %d\n", __func__,
1073 substream->name, substream->stream);
1074}
1075
1076static struct snd_soc_ops msm_be_ops = {
1077 .startup = msm_startup,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001078 .hw_params = msm_hw_params,
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001079 .shutdown = msm_shutdown,
1080};
1081
1082static struct snd_soc_ops msm_auxpcm_be_ops = {
1083 .startup = msm_auxpcm_startup,
1084 .shutdown = msm_auxpcm_shutdown,
1085};
1086
Neema Shetty3c9d2862012-03-11 01:25:32 -08001087static struct snd_soc_ops msm_slimbus_1_be_ops = {
1088 .startup = msm_startup,
1089 .hw_params = msm_slimbus_1_hw_params,
1090 .shutdown = msm_shutdown,
1091};
1092
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001093/* Digital audio interface glue - connects codec <---> CPU */
1094static struct snd_soc_dai_link msm_dai[] = {
1095 /* FrontEnd DAI Links */
1096 {
1097 .name = "MSM8960 Media1",
1098 .stream_name = "MultiMedia1",
1099 .cpu_dai_name = "MultiMedia1",
1100 .platform_name = "msm-pcm-dsp",
1101 .dynamic = 1,
1102 .dsp_link = &fe_media,
1103 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
1104 },
1105 {
1106 .name = "MSM8960 Media2",
1107 .stream_name = "MultiMedia2",
1108 .cpu_dai_name = "MultiMedia2",
1109 .platform_name = "msm-pcm-dsp",
1110 .dynamic = 1,
1111 .dsp_link = &fe_media,
1112 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
1113 },
1114 {
1115 .name = "Circuit-Switch Voice",
1116 .stream_name = "CS-Voice",
1117 .cpu_dai_name = "CS-VOICE",
1118 .platform_name = "msm-pcm-voice",
1119 .dynamic = 1,
1120 .dsp_link = &fe_media,
1121 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
1122 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1123 .ignore_suspend = 1,
1124 },
1125 {
1126 .name = "MSM VoIP",
1127 .stream_name = "VoIP",
1128 .cpu_dai_name = "VoIP",
1129 .platform_name = "msm-voip-dsp",
1130 .dynamic = 1,
1131 .dsp_link = &fe_media,
1132 .be_id = MSM_FRONTEND_DAI_VOIP,
1133 },
1134 {
1135 .name = "MSM8960 LPA",
1136 .stream_name = "LPA",
1137 .cpu_dai_name = "MultiMedia3",
1138 .platform_name = "msm-pcm-lpa",
1139 .dynamic = 1,
1140 .dsp_link = &lpa_fe_media,
1141 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
1142 },
1143 /* Hostless PMC purpose */
1144 {
1145 .name = "SLIMBUS_0 Hostless",
1146 .stream_name = "SLIMBUS_0 Hostless",
1147 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
1148 .platform_name = "msm-pcm-hostless",
1149 .dynamic = 1,
1150 .dsp_link = &slimbus0_hl_media,
1151 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1152 .ignore_suspend = 1,
1153 /* .be_id = do not care */
1154 },
1155 {
1156 .name = "INT_FM Hostless",
1157 .stream_name = "INT_FM Hostless",
1158 .cpu_dai_name = "INT_FM_HOSTLESS",
1159 .platform_name = "msm-pcm-hostless",
1160 .dynamic = 1,
1161 .dsp_link = &int_fm_hl_media,
1162 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1163 .ignore_suspend = 1,
1164 /* .be_id = do not care */
1165 },
1166 {
1167 .name = "MSM AFE-PCM RX",
1168 .stream_name = "AFE-PROXY RX",
1169 .cpu_dai_name = "msm-dai-q6.241",
1170 .codec_name = "msm-stub-codec.1",
1171 .codec_dai_name = "msm-stub-rx",
1172 .platform_name = "msm-pcm-afe",
1173 .ignore_suspend = 1,
1174 },
1175 {
1176 .name = "MSM AFE-PCM TX",
1177 .stream_name = "AFE-PROXY TX",
1178 .cpu_dai_name = "msm-dai-q6.240",
1179 .codec_name = "msm-stub-codec.1",
1180 .codec_dai_name = "msm-stub-tx",
1181 .platform_name = "msm-pcm-afe",
1182 .ignore_suspend = 1,
1183 },
Neema Shettyb9451242012-02-16 15:37:59 -08001184 {
1185 .name = "Voice Stub",
1186 .stream_name = "Voice Stub",
1187 .cpu_dai_name = "VOICE_STUB",
1188 .platform_name = "msm-pcm-hostless",
1189 .dynamic = 1,
1190 .dsp_link = &fe_media,
1191 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
1192 .ignore_suspend = 1,
Neema Shetty3c9d2862012-03-11 01:25:32 -08001193 .be_id = MSM_FRONTEND_DAI_VOICE_STUB,
Neema Shettyb9451242012-02-16 15:37:59 -08001194 },
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001195 /* Backend DAI Links */
1196 {
1197 .name = LPASS_BE_SLIMBUS_0_RX,
1198 .stream_name = "Slimbus Playback",
1199 .cpu_dai_name = "msm-dai-q6.16384",
1200 .platform_name = "msm-pcm-routing",
1201 .codec_name = "tabla_codec",
1202 .codec_dai_name = "tabla_rx1",
1203 .no_pcm = 1,
1204 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
1205 .init = &msm_audrx_init,
1206 .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
1207 .ops = &msm_be_ops,
1208 },
1209 {
1210 .name = LPASS_BE_SLIMBUS_0_TX,
1211 .stream_name = "Slimbus Capture",
1212 .cpu_dai_name = "msm-dai-q6.16385",
1213 .platform_name = "msm-pcm-routing",
1214 .codec_name = "tabla_codec",
1215 .codec_dai_name = "tabla_tx1",
1216 .no_pcm = 1,
1217 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
1218 .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
1219 .ops = &msm_be_ops,
1220 },
1221 /* Backend BT/FM DAI Links */
1222 {
1223 .name = LPASS_BE_INT_BT_SCO_RX,
1224 .stream_name = "Internal BT-SCO Playback",
1225 .cpu_dai_name = "msm-dai-q6.12288",
1226 .platform_name = "msm-pcm-routing",
1227 .codec_name = "msm-stub-codec.1",
1228 .codec_dai_name = "msm-stub-rx",
1229 .init = &msm_btsco_init,
1230 .no_pcm = 1,
1231 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
1232 .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
1233 },
1234 {
1235 .name = LPASS_BE_INT_BT_SCO_TX,
1236 .stream_name = "Internal BT-SCO Capture",
1237 .cpu_dai_name = "msm-dai-q6.12289",
1238 .platform_name = "msm-pcm-routing",
1239 .codec_name = "msm-stub-codec.1",
1240 .codec_dai_name = "msm-stub-tx",
1241 .no_pcm = 1,
1242 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
1243 .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
1244 },
1245 {
1246 .name = LPASS_BE_INT_FM_RX,
1247 .stream_name = "Internal FM Playback",
1248 .cpu_dai_name = "msm-dai-q6.12292",
1249 .platform_name = "msm-pcm-routing",
1250 .codec_name = "msm-stub-codec.1",
1251 .codec_dai_name = "msm-stub-rx",
1252 .no_pcm = 1,
1253 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
1254 .be_hw_params_fixup = msm_be_hw_params_fixup,
1255 },
1256 {
1257 .name = LPASS_BE_INT_FM_TX,
1258 .stream_name = "Internal FM Capture",
1259 .cpu_dai_name = "msm-dai-q6.12293",
1260 .platform_name = "msm-pcm-routing",
1261 .codec_name = "msm-stub-codec.1",
1262 .codec_dai_name = "msm-stub-tx",
1263 .no_pcm = 1,
1264 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
1265 .be_hw_params_fixup = msm_be_hw_params_fixup,
1266 },
1267 /* HDMI BACK END DAI Link */
1268 {
1269 .name = LPASS_BE_HDMI,
1270 .stream_name = "HDMI Playback",
Swaminathan Sathappanfd9dbad2012-02-15 16:56:44 -08001271 .cpu_dai_name = "msm-dai-q6-hdmi.8",
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001272 .platform_name = "msm-pcm-routing",
1273 .codec_name = "msm-stub-codec.1",
1274 .codec_dai_name = "msm-stub-rx",
1275 .no_pcm = 1,
1276 .no_codec = 1,
1277 .be_id = MSM_BACKEND_DAI_HDMI_RX,
Swaminathan Sathappanfd9dbad2012-02-15 16:56:44 -08001278 .be_hw_params_fixup = msm_hdmi_be_hw_params_fixup,
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001279 },
1280 /* Backend AFE DAI Links */
1281 {
1282 .name = LPASS_BE_AFE_PCM_RX,
1283 .stream_name = "AFE Playback",
1284 .cpu_dai_name = "msm-dai-q6.224",
1285 .platform_name = "msm-pcm-routing",
1286 .codec_name = "msm-stub-codec.1",
1287 .codec_dai_name = "msm-stub-rx",
1288 .no_codec = 1,
1289 .no_pcm = 1,
1290 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
1291 },
1292 {
1293 .name = LPASS_BE_AFE_PCM_TX,
1294 .stream_name = "AFE Capture",
1295 .cpu_dai_name = "msm-dai-q6.225",
1296 .platform_name = "msm-pcm-routing",
1297 .codec_name = "msm-stub-codec.1",
1298 .codec_dai_name = "msm-stub-tx",
1299 .no_codec = 1,
1300 .no_pcm = 1,
1301 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
1302 },
1303 /* AUX PCM Backend DAI Links */
1304 {
1305 .name = LPASS_BE_AUXPCM_RX,
1306 .stream_name = "AUX PCM Playback",
1307 .cpu_dai_name = "msm-dai-q6.2",
1308 .platform_name = "msm-pcm-routing",
1309 .codec_name = "msm-stub-codec.1",
1310 .codec_dai_name = "msm-stub-rx",
1311 .no_pcm = 1,
1312 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
1313 .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
1314 .ops = &msm_auxpcm_be_ops,
1315 },
1316 {
1317 .name = LPASS_BE_AUXPCM_TX,
1318 .stream_name = "AUX PCM Capture",
1319 .cpu_dai_name = "msm-dai-q6.3",
1320 .platform_name = "msm-pcm-routing",
1321 .codec_name = "msm-stub-codec.1",
1322 .codec_dai_name = "msm-stub-tx",
1323 .no_pcm = 1,
1324 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
1325 .be_hw_params_fixup = msm_auxpcm_be_params_fixup,
1326 },
Neema Shettyb9451242012-02-16 15:37:59 -08001327 {
1328 .name = LPASS_BE_STUB_RX,
1329 .stream_name = "Stub Playback",
1330 .cpu_dai_name = "msm-dai-stub",
1331 .platform_name = "msm-pcm-routing",
1332 .codec_name = "tabla_codec",
1333 .codec_dai_name = "tabla_rx2",
1334 .no_pcm = 1,
1335 /* .be_id = do not care */
1336 .be_hw_params_fixup = msm_slim_0_rx_be_hw_params_fixup,
Helen Zengf3b17fb2012-02-28 15:07:38 -08001337 .init = &msm_stubrx_init,
Neema Shettyb9451242012-02-16 15:37:59 -08001338 .ops = &msm_be_ops,
1339 },
1340 {
1341 .name = LPASS_BE_STUB_TX,
1342 .stream_name = "Stub Capture",
1343 .cpu_dai_name = "msm-dai-stub",
1344 .platform_name = "msm-pcm-routing",
1345 .codec_name = "tabla_codec",
1346 .codec_dai_name = "tabla_tx1",
1347 .no_pcm = 1,
1348 /* .be_id = do not care */
1349 .be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
1350 .ops = &msm_be_ops,
1351 },
Neema Shetty3c9d2862012-03-11 01:25:32 -08001352 {
1353 .name = LPASS_BE_SLIMBUS_1_RX,
1354 .stream_name = "Slimbus1 Playback",
1355 .cpu_dai_name = "msm-dai-q6.16386",
1356 .platform_name = "msm-pcm-routing",
1357 .codec_name = "msm-stub-codec.1",
1358 .codec_dai_name = "msm-stub-rx",
1359 .no_pcm = 1,
1360 .be_id = MSM_BACKEND_DAI_SLIMBUS_1_RX,
1361 .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
1362 .ops = &msm_slimbus_1_be_ops,
1363
1364 },
1365 {
1366 .name = LPASS_BE_SLIMBUS_1_TX,
1367 .stream_name = "Slimbus1 Capture",
1368 .cpu_dai_name = "msm-dai-q6.16387",
1369 .platform_name = "msm-pcm-routing",
1370 .codec_name = "msm-stub-codec.1",
1371 .codec_dai_name = "msm-stub-tx",
1372 .no_pcm = 1,
1373 .be_id = MSM_BACKEND_DAI_SLIMBUS_1_TX,
1374 .be_hw_params_fixup = msm_btsco_be_hw_params_fixup,
1375 .ops = &msm_slimbus_1_be_ops,
1376 },
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001377};
1378
1379struct snd_soc_card snd_soc_card_msm = {
Swaminathan Sathappanc165a3a2012-02-29 12:44:31 -08001380 .name = "apq8064-tabla-snd-card",
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001381 .dai_link = msm_dai,
1382 .num_links = ARRAY_SIZE(msm_dai),
1383};
1384
1385static struct platform_device *msm_snd_device;
1386
1387static int msm_configure_headset_mic_gpios(void)
1388{
1389 int ret;
1390 struct pm_gpio param = {
1391 .direction = PM_GPIO_DIR_OUT,
1392 .output_buffer = PM_GPIO_OUT_BUF_CMOS,
1393 .output_value = 1,
1394 .pull = PM_GPIO_PULL_NO,
1395 .vin_sel = PM_GPIO_VIN_S4,
1396 .out_strength = PM_GPIO_STRENGTH_MED,
1397 .function = PM_GPIO_FUNC_NORMAL,
1398 };
1399
1400 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(23), "AV_SWITCH");
1401 if (ret) {
1402 pr_err("%s: Failed to request gpio %d\n", __func__,
1403 PM8921_GPIO_PM_TO_SYS(23));
1404 return ret;
1405 }
1406
1407 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(23), &param);
1408 if (ret)
1409 pr_err("%s: Failed to configure gpio %d\n", __func__,
1410 PM8921_GPIO_PM_TO_SYS(23));
1411 else
1412 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(23), 0);
1413
1414 ret = gpio_request(PM8921_GPIO_PM_TO_SYS(35), "US_EURO_SWITCH");
1415 if (ret) {
1416 pr_err("%s: Failed to request gpio %d\n", __func__,
1417 PM8921_GPIO_PM_TO_SYS(35));
1418 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1419 return ret;
1420 }
1421 ret = pm8xxx_gpio_config(PM8921_GPIO_PM_TO_SYS(35), &param);
1422 if (ret)
1423 pr_err("%s: Failed to configure gpio %d\n", __func__,
1424 PM8921_GPIO_PM_TO_SYS(35));
1425 else
1426 gpio_direction_output(PM8921_GPIO_PM_TO_SYS(35), 0);
1427
1428 return 0;
1429}
1430static void msm_free_headset_mic_gpios(void)
1431{
1432 if (msm_headset_gpios_configured) {
1433 gpio_free(PM8921_GPIO_PM_TO_SYS(23));
1434 gpio_free(PM8921_GPIO_PM_TO_SYS(35));
1435 }
1436}
1437
1438static int __init msm_audio_init(void)
1439{
1440 int ret;
1441
1442 if (!cpu_is_apq8064()) {
1443 pr_err("%s: Not the right machine type\n", __func__);
1444 return -ENODEV;
1445 }
1446
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001447 mbhc_cfg.calibration = def_tabla_mbhc_cal();
1448 if (!mbhc_cfg.calibration) {
Joonwoo Park0976d012011-12-22 11:48:18 -08001449 pr_err("Calibration data allocation failed\n");
1450 return -ENOMEM;
1451 }
1452
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001453 msm_snd_device = platform_device_alloc("soc-audio", 0);
1454 if (!msm_snd_device) {
1455 pr_err("Platform device allocation failed\n");
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001456 kfree(mbhc_cfg.calibration);
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001457 return -ENOMEM;
1458 }
1459
1460 platform_set_drvdata(msm_snd_device, &snd_soc_card_msm);
1461 ret = platform_device_add(msm_snd_device);
1462 if (ret) {
1463 platform_device_put(msm_snd_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001464 kfree(mbhc_cfg.calibration);
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001465 return ret;
1466 }
1467
1468 if (msm_configure_headset_mic_gpios()) {
1469 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1470 msm_headset_gpios_configured = 0;
1471 } else
1472 msm_headset_gpios_configured = 1;
1473
1474 return ret;
1475
1476}
1477module_init(msm_audio_init);
1478
1479static void __exit msm_audio_exit(void)
1480{
1481 if (!cpu_is_apq8064()) {
1482 pr_err("%s: Not the right machine type\n", __func__);
1483 return ;
1484 }
1485 msm_free_headset_mic_gpios();
1486 platform_device_unregister(msm_snd_device);
Joonwoo Parkd7cf2e92012-03-19 19:38:23 -07001487 kfree(mbhc_cfg.calibration);
Bharath Ramachandramurthyb8e797f2011-11-30 12:08:42 -08001488}
1489module_exit(msm_audio_exit);
1490
1491MODULE_DESCRIPTION("ALSA SoC msm");
1492MODULE_LICENSE("GPL v2");