blob: a081253709bcae7e5959b36d456a2abdea47d0fd [file] [log] [blame]
Asish Bhattacharyab86c3472012-02-15 08:31:52 +05301/* 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/pm8921.h>
17#include <linux/platform_device.h>
18#include <linux/gpio.h>
19#include <linux/mfd/pm8xxx/pm8921.h>
20#include <linux/slab.h>
21#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/wcd9304.h"
31
32/* 8930 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 MSM8930_SPK_ON 1
38#define MSM8930_SPK_OFF 0
39
40#define msm8930_SLIM_0_RX_MAX_CHANNELS 2
41#define msm8930_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 SITAR_EXT_CLK_RATE 12288000
57
58#define SITAR_MBHC_DEF_BUTTONS 3
59#define SITAR_MBHC_DEF_RLOADS 5
60
61static int msm8930_spk_control;
62static int msm8930_slim_0_rx_ch = 1;
63static int msm8930_slim_0_tx_ch = 1;
64
65static int msm8930_btsco_rate = BTSCO_RATE_8KHZ;
66static int msm8930_btsco_ch = 1;
67
68static struct clk *codec_clk;
69static int clk_users;
70
71static int msm8930_headset_gpios_configured;
72
73static struct snd_soc_jack hs_jack;
74static struct snd_soc_jack button_jack;
75
76struct sitar_mbhc_calibration sitar_calib = {
77 .bias = SITAR_MICBIAS2,
78 .tldoh = 100,
79 .bg_fast_settle = 100,
80 .mic_current = SITAR_PID_MIC_5_UA,
81 .mic_pid = 100,
82 .hph_current = SITAR_PID_MIC_5_UA,
83 .setup_plug_removal_delay = 1000000,
84 .shutdown_plug_removal = 100000,
85};
86
87static void msm8930_ext_control(struct snd_soc_codec *codec)
88{
89 struct snd_soc_dapm_context *dapm = &codec->dapm;
90
91 pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
92 if (msm8930_spk_control == MSM8930_SPK_ON) {
93 snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
94 snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
95 } else {
96 snd_soc_dapm_disable_pin(dapm, "Ext Spk Left Pos");
97 snd_soc_dapm_disable_pin(dapm, "Ext Spk Right Pos");
98 }
99
100 snd_soc_dapm_sync(dapm);
101}
102
103static int msm8930_get_spk(struct snd_kcontrol *kcontrol,
104 struct snd_ctl_elem_value *ucontrol)
105{
106 pr_debug("%s: msm8930_spk_control = %d", __func__, msm8930_spk_control);
107 ucontrol->value.integer.value[0] = msm8930_spk_control;
108 return 0;
109}
110static int msm8930_set_spk(struct snd_kcontrol *kcontrol,
111 struct snd_ctl_elem_value *ucontrol)
112{
113 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
114
115 pr_debug("%s()\n", __func__);
116 if (msm8930_spk_control == ucontrol->value.integer.value[0])
117 return 0;
118
119 msm8930_spk_control = ucontrol->value.integer.value[0];
120 msm8930_ext_control(codec);
121 return 1;
122}
123
124static int msm8930_spkramp_event(struct snd_soc_dapm_widget *w,
125 struct snd_kcontrol *k, int event)
126{
127 pr_debug("%s() %x\n", __func__, SND_SOC_DAPM_EVENT_ON(event));
128 /* TODO: add external speaker power amps support */
129 return 0;
130}
131int msm8930_enable_codec_ext_clk(
132 struct snd_soc_codec *codec, int enable)
133{
134 pr_debug("%s: enable = %d\n", __func__, enable);
135 if (enable) {
136 clk_users++;
137 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
138 if (clk_users != 1)
139 return 0;
140
141 if (codec_clk) {
142 clk_set_rate(codec_clk, SITAR_EXT_CLK_RATE);
143 clk_enable(codec_clk);
144 sitar_mclk_enable(codec, 1);
145 } else {
146 pr_err("%s: Error setting Tabla MCLK\n", __func__);
147 clk_users--;
148 return -EINVAL;
149 }
150 } else {
151 pr_debug("%s: clk_users = %d\n", __func__, clk_users);
152 if (clk_users == 0)
153 return 0;
154 clk_users--;
155 if (!clk_users) {
156 pr_debug("%s: disabling MCLK. clk_users = %d\n",
157 __func__, clk_users);
158 clk_disable(codec_clk);
159 sitar_mclk_enable(codec, 0);
160 }
161 }
162 return 0;
163}
164
165static int msm8930_mclk_event(struct snd_soc_dapm_widget *w,
166 struct snd_kcontrol *kcontrol, int event)
167{
168 pr_debug("%s: event = %d\n", __func__, event);
169
170 switch (event) {
171 case SND_SOC_DAPM_PRE_PMU:
172 return msm8930_enable_codec_ext_clk(w->codec, 1);
173 case SND_SOC_DAPM_POST_PMD:
174 return msm8930_enable_codec_ext_clk(w->codec, 0);
175 }
176 return 0;
177}
178
179static const struct snd_soc_dapm_widget msm8930_dapm_widgets[] = {
180
181 SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0,
182 msm8930_mclk_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
183
184 SND_SOC_DAPM_SPK("Ext Spk Left Pos", msm8930_spkramp_event),
185 SND_SOC_DAPM_SPK("Ext Spk Right Pos", msm8930_spkramp_event),
186
187 SND_SOC_DAPM_MIC("Handset Mic", NULL),
188 SND_SOC_DAPM_MIC("Headset Mic", NULL),
189 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
190 SND_SOC_DAPM_MIC("ANCRight Headset Mic", NULL),
191 SND_SOC_DAPM_MIC("ANCLeft Headset Mic", NULL),
192
193 SND_SOC_DAPM_MIC("Digital Mic1", NULL),
194 SND_SOC_DAPM_MIC("Digital Mic2", NULL),
195 SND_SOC_DAPM_MIC("Digital Mic3", NULL),
196 SND_SOC_DAPM_MIC("Digital Mic4", NULL),
197
198};
199
200static const struct snd_soc_dapm_route common_audio_map[] = {
201
202 {"RX_BIAS", NULL, "MCLK"},
203 {"LDO_H", NULL, "MCLK"},
204
205 {"MIC BIAS1 Internal1", NULL, "MCLK"},
206 {"MIC BIAS2 Internal1", NULL, "MCLK"},
207
208 /* Speaker path */
209 {"Ext Spk Left Pos", NULL, "LINEOUT1"},
210 {"Ext Spk Right Pos", NULL, "LINEOUT2"},
211
212
213 {"AMIC2", NULL, "MIC BIAS2 Internal1"},
214 {"MIC BIAS2 Internal1", NULL, "Headset Mic"},
215
216 /* Microphone path */
217 {"AMIC1", NULL, "MIC BIAS1 Internal1"},
218 {"MIC BIAS1 Internal1", NULL, "Handset Mic"},
219
220 {"HEADPHONE", NULL, "LDO_H"},
221
222 /**
223 * The digital Mic routes are setup considering
224 * fluid as default device.
225 */
226
227 /**
228 * Digital Mic1. Front Bottom left Digital Mic on Fluid and MTP.
229 * Digital Mic GM5 on CDP mainboard.
230 * Conncted to DMIC2 Input on Tabla codec.
231 */
232 {"DMIC1", NULL, "MIC BIAS1 External"},
233 {"MIC BIAS1 External", NULL, "Digital Mic1"},
234
235 /**
236 * Digital Mic2. Front Bottom right Digital Mic on Fluid and MTP.
237 * Digital Mic GM6 on CDP mainboard.
238 * Conncted to DMIC1 Input on Tabla codec.
239 */
240 {"DMIC2", NULL, "MIC BIAS1 External"},
241 {"MIC BIAS1 External", NULL, "Digital Mic2"},
242 /**
243 * Digital Mic3. Back Bottom Digital Mic on Fluid.
244 * Digital Mic GM1 on CDP mainboard.
245 * Conncted to DMIC4 Input on Tabla codec.
246 */
247 {"DMIC3", NULL, "MIC BIAS2 External"},
248 {"MIC BIAS2 External", NULL, "Digital Mic3"},
249
250 /**
251 * Digital Mic4. Back top Digital Mic on Fluid.
252 * Digital Mic GM2 on CDP mainboard.
253 * Conncted to DMIC3 Input on Tabla codec.
254 */
255 {"DMIC4", NULL, "MIC BIAS2 External"},
256 {"MIC BIAS2 External", NULL, "Digital Mic4"},
257
258
259};
260
261static const char *spk_function[] = {"Off", "On"};
262static const char *slim0_rx_ch_text[] = {"One", "Two"};
263static const char *slim0_tx_ch_text[] = {"One", "Two", "Three", "Four"};
264
265static const struct soc_enum msm8930_enum[] = {
266 SOC_ENUM_SINGLE_EXT(2, spk_function),
267 SOC_ENUM_SINGLE_EXT(2, slim0_rx_ch_text),
268 SOC_ENUM_SINGLE_EXT(4, slim0_tx_ch_text),
269};
270
271static const char *btsco_rate_text[] = {"8000", "16000"};
272static const struct soc_enum msm8930_btsco_enum[] = {
273 SOC_ENUM_SINGLE_EXT(2, btsco_rate_text),
274};
275
276static int msm8930_slim_0_rx_ch_get(struct snd_kcontrol *kcontrol,
277 struct snd_ctl_elem_value *ucontrol)
278{
279 pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
280 msm8930_slim_0_rx_ch);
281 ucontrol->value.integer.value[0] = msm8930_slim_0_rx_ch - 1;
282 return 0;
283}
284
285static int msm8930_slim_0_rx_ch_put(struct snd_kcontrol *kcontrol,
286 struct snd_ctl_elem_value *ucontrol)
287{
288 msm8930_slim_0_rx_ch = ucontrol->value.integer.value[0] + 1;
289
290 pr_debug("%s: msm8930_slim_0_rx_ch = %d\n", __func__,
291 msm8930_slim_0_rx_ch);
292 return 1;
293}
294
295static int msm8930_slim_0_tx_ch_get(struct snd_kcontrol *kcontrol,
296 struct snd_ctl_elem_value *ucontrol)
297{
298 pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
299 msm8930_slim_0_tx_ch);
300 ucontrol->value.integer.value[0] = msm8930_slim_0_tx_ch - 1;
301 return 0;
302}
303
304static int msm8930_slim_0_tx_ch_put(struct snd_kcontrol *kcontrol,
305 struct snd_ctl_elem_value *ucontrol)
306{
307 msm8930_slim_0_tx_ch = ucontrol->value.integer.value[0] + 1;
308
309 pr_debug("%s: msm8930_slim_0_tx_ch = %d\n", __func__,
310 msm8930_slim_0_tx_ch);
311 return 1;
312}
313
314static int msm8930_btsco_rate_get(struct snd_kcontrol *kcontrol,
315 struct snd_ctl_elem_value *ucontrol)
316{
317 pr_debug("%s: msm8930_btsco_rate = %d", __func__, msm8930_btsco_rate);
318 ucontrol->value.integer.value[0] = msm8930_btsco_rate;
319 return 0;
320}
321
322static int msm8930_btsco_rate_put(struct snd_kcontrol *kcontrol,
323 struct snd_ctl_elem_value *ucontrol)
324{
325 switch (ucontrol->value.integer.value[0]) {
326 case 0:
327 msm8930_btsco_rate = BTSCO_RATE_8KHZ;
328 break;
329 case 1:
330 msm8930_btsco_rate = BTSCO_RATE_16KHZ;
331 break;
332 default:
333 msm8930_btsco_rate = BTSCO_RATE_8KHZ;
334 break;
335 }
336 pr_debug("%s: msm8930_btsco_rate = %d\n", __func__, msm8930_btsco_rate);
337 return 0;
338}
339
340static const struct snd_kcontrol_new sitar_msm8930_controls[] = {
341 SOC_ENUM_EXT("Speaker Function", msm8930_enum[0], msm8930_get_spk,
342 msm8930_set_spk),
343 SOC_ENUM_EXT("SLIM_0_RX Channels", msm8930_enum[1],
344 msm8930_slim_0_rx_ch_get, msm8930_slim_0_rx_ch_put),
345 SOC_ENUM_EXT("SLIM_0_TX Channels", msm8930_enum[2],
346 msm8930_slim_0_tx_ch_get, msm8930_slim_0_tx_ch_put),
347};
348
349static const struct snd_kcontrol_new int_btsco_rate_mixer_controls[] = {
350 SOC_ENUM_EXT("Internal BTSCO SampleRate", msm8930_btsco_enum[0],
351 msm8930_btsco_rate_get, msm8930_btsco_rate_put),
352};
353
354static int msm8930_btsco_init(struct snd_soc_pcm_runtime *rtd)
355{
356 int err = 0;
357 struct snd_soc_platform *platform = rtd->platform;
358
359 err = snd_soc_add_platform_controls(platform,
360 int_btsco_rate_mixer_controls,
361 ARRAY_SIZE(int_btsco_rate_mixer_controls));
362 if (err < 0)
363 return err;
364 return 0;
365}
366
367static int msm8930_hw_params(struct snd_pcm_substream *substream,
368 struct snd_pcm_hw_params *params)
369{
370 struct snd_soc_pcm_runtime *rtd = substream->private_data;
371 struct snd_soc_dai *codec_dai = rtd->codec_dai;
372 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
373 int ret = 0;
374 unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
375 unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
376
377 pr_debug("%s: ch=%d\n", __func__,
378 msm8930_slim_0_rx_ch);
379 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
380 ret = snd_soc_dai_get_channel_map(codec_dai,
381 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
382 if (ret < 0) {
383 pr_err("%s: failed to get codec chan map\n", __func__);
384 goto end;
385 }
386
387 ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
388 msm8930_slim_0_rx_ch, rx_ch);
389 if (ret < 0) {
390 pr_err("%s: failed to set cpu chan map\n", __func__);
391 goto end;
392 }
393 ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
394 msm8930_slim_0_rx_ch, rx_ch);
395 if (ret < 0) {
396 pr_err("%s: failed to set codec channel map\n",
397 __func__);
398 goto end;
399 }
400 } else {
401 ret = snd_soc_dai_get_channel_map(codec_dai,
402 &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
403 if (ret < 0) {
404 pr_err("%s: failed to get codec chan map\n", __func__);
405 goto end;
406 }
407 ret = snd_soc_dai_set_channel_map(cpu_dai,
408 msm8930_slim_0_tx_ch, tx_ch, 0 , 0);
409 if (ret < 0) {
410 pr_err("%s: failed to set cpu chan map\n", __func__);
411 goto end;
412 }
413 ret = snd_soc_dai_set_channel_map(codec_dai,
414 msm8930_slim_0_tx_ch, tx_ch, 0, 0);
415 if (ret < 0) {
416 pr_err("%s: failed to set codec channel map\n",
417 __func__);
418 goto end;
419 }
420
421 }
422end:
423 return ret;
424}
425
426static int msm8930_audrx_init(struct snd_soc_pcm_runtime *rtd)
427{
428 int err;
429 struct snd_soc_codec *codec = rtd->codec;
430 struct snd_soc_dapm_context *dapm = &codec->dapm;
431 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
432
433 pr_debug("%s()\n", __func__);
434
435
436 rtd->pmdown_time = 0;
437
438 err = snd_soc_add_controls(codec, sitar_msm8930_controls,
439 ARRAY_SIZE(sitar_msm8930_controls));
440 if (err < 0)
441 return err;
442
443 snd_soc_dapm_new_controls(dapm, msm8930_dapm_widgets,
444 ARRAY_SIZE(msm8930_dapm_widgets));
445
446 snd_soc_dapm_add_routes(dapm, common_audio_map,
447 ARRAY_SIZE(common_audio_map));
448
449 snd_soc_dapm_enable_pin(dapm, "Ext Spk Left Pos");
450 snd_soc_dapm_enable_pin(dapm, "Ext Spk Right Pos");
451
452 snd_soc_dapm_sync(dapm);
453
454 err = snd_soc_jack_new(codec, "Headset Jack",
455 (SND_JACK_HEADSET | SND_JACK_OC_HPHL | SND_JACK_OC_HPHR),
456 &hs_jack);
457 if (err) {
458 pr_err("failed to create new jack\n");
459 return err;
460 }
461
462 err = snd_soc_jack_new(codec, "Button Jack",
463 SND_JACK_BTN_0, &button_jack);
464 if (err) {
465 pr_err("failed to create new jack\n");
466 return err;
467 }
468 codec_clk = clk_get(cpu_dai->dev, "osr_clk");
469 sitar_hs_detect(codec, &hs_jack, &button_jack, &sitar_calib);
470 return 0;
471}
472
473static struct snd_soc_dsp_link lpa_fe_media = {
474 .playback = true,
475 .trigger = {
476 SND_SOC_DSP_TRIGGER_POST,
477 SND_SOC_DSP_TRIGGER_POST
478 },
479};
480
481static struct snd_soc_dsp_link fe_media = {
482 .playback = true,
483 .capture = true,
484 .trigger = {
485 SND_SOC_DSP_TRIGGER_POST,
486 SND_SOC_DSP_TRIGGER_POST
487 },
488};
489
490static struct snd_soc_dsp_link slimbus0_hl_media = {
491 .playback = true,
492 .capture = true,
493 .trigger = {
494 SND_SOC_DSP_TRIGGER_POST,
495 SND_SOC_DSP_TRIGGER_POST
496 },
497};
498
499static struct snd_soc_dsp_link int_fm_hl_media = {
500 .playback = true,
501 .capture = true,
502 .trigger = {
503 SND_SOC_DSP_TRIGGER_POST,
504 SND_SOC_DSP_TRIGGER_POST
505 },
506};
507
508/* bi-directional media definition for hostless PCM device */
509static struct snd_soc_dsp_link bidir_hl_media = {
510 .playback = true,
511 .capture = true,
512 .trigger = {
513 SND_SOC_DSP_TRIGGER_POST,
514 SND_SOC_DSP_TRIGGER_POST
515 },
516};
517
518static struct snd_soc_dsp_link hdmi_rx_hl = {
519 .playback = true,
520 .trigger = {
521 SND_SOC_DSP_TRIGGER_POST,
522 SND_SOC_DSP_TRIGGER_POST
523 },
524};
525
526static int msm8930_slim_0_rx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
527 struct snd_pcm_hw_params *params)
528{
529 struct snd_interval *rate = hw_param_interval(params,
530 SNDRV_PCM_HW_PARAM_RATE);
531
532 struct snd_interval *channels = hw_param_interval(params,
533 SNDRV_PCM_HW_PARAM_CHANNELS);
534
535 pr_debug("%s()\n", __func__);
536 rate->min = rate->max = 48000;
537 channels->min = channels->max = msm8930_slim_0_rx_ch;
538
539 return 0;
540}
541
542static int msm8930_slim_0_tx_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
543 struct snd_pcm_hw_params *params)
544{
545 struct snd_interval *rate = hw_param_interval(params,
546 SNDRV_PCM_HW_PARAM_RATE);
547
548 struct snd_interval *channels = hw_param_interval(params,
549 SNDRV_PCM_HW_PARAM_CHANNELS);
550
551 pr_debug("%s()\n", __func__);
552 rate->min = rate->max = 48000;
553 channels->min = channels->max = msm8930_slim_0_tx_ch;
554
555 return 0;
556}
557
558static int msm8930_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
559 struct snd_pcm_hw_params *params)
560{
561 struct snd_interval *rate = hw_param_interval(params,
562 SNDRV_PCM_HW_PARAM_RATE);
563
564 pr_debug("%s()\n", __func__);
565 rate->min = rate->max = 48000;
566
567 return 0;
568}
569
570static int msm8930_hdmi_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
571 struct snd_pcm_hw_params *params)
572{
573 struct snd_interval *rate = hw_param_interval(params,
574 SNDRV_PCM_HW_PARAM_RATE);
575
576 struct snd_interval *channels = hw_param_interval(params,
577 SNDRV_PCM_HW_PARAM_CHANNELS);
578
579 rate->min = rate->max = 48000;
580 channels->min = channels->max = 2;
581
582 return 0;
583}
584
585static int msm8930_btsco_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
586 struct snd_pcm_hw_params *params)
587{
588 struct snd_interval *rate = hw_param_interval(params,
589 SNDRV_PCM_HW_PARAM_RATE);
590
591 struct snd_interval *channels = hw_param_interval(params,
592 SNDRV_PCM_HW_PARAM_CHANNELS);
593
594 rate->min = rate->max = msm8930_btsco_rate;
595 channels->min = channels->max = msm8930_btsco_ch;
596
597 return 0;
598}
599static int msm8930_auxpcm_be_params_fixup(struct snd_soc_pcm_runtime *rtd,
600 struct snd_pcm_hw_params *params)
601{
602 struct snd_interval *rate = hw_param_interval(params,
603 SNDRV_PCM_HW_PARAM_RATE);
604
605 struct snd_interval *channels = hw_param_interval(params,
606 SNDRV_PCM_HW_PARAM_CHANNELS);
607
608 /* PCM only supports mono output with 8khz sample rate */
609 rate->min = rate->max = 8000;
610 channels->min = channels->max = 1;
611
612 return 0;
613}
614static int msm8930_aux_pcm_get_gpios(void)
615{
616 int ret = 0;
617
618 pr_debug("%s\n", __func__);
619
620 ret = gpio_request(GPIO_AUX_PCM_DOUT, "AUX PCM DOUT");
621 if (ret < 0) {
622 pr_err("%s: Failed to request gpio(%d): AUX PCM DOUT",
623 __func__, GPIO_AUX_PCM_DOUT);
624 goto fail_dout;
625 }
626
627 ret = gpio_request(GPIO_AUX_PCM_DIN, "AUX PCM DIN");
628 if (ret < 0) {
629 pr_err("%s: Failed to request gpio(%d): AUX PCM DIN",
630 __func__, GPIO_AUX_PCM_DIN);
631 goto fail_din;
632 }
633
634 ret = gpio_request(GPIO_AUX_PCM_SYNC, "AUX PCM SYNC");
635 if (ret < 0) {
636 pr_err("%s: Failed to request gpio(%d): AUX PCM SYNC",
637 __func__, GPIO_AUX_PCM_SYNC);
638 goto fail_sync;
639 }
640 ret = gpio_request(GPIO_AUX_PCM_CLK, "AUX PCM CLK");
641 if (ret < 0) {
642 pr_err("%s: Failed to request gpio(%d): AUX PCM CLK",
643 __func__, GPIO_AUX_PCM_CLK);
644 goto fail_clk;
645 }
646
647 return 0;
648
649fail_clk:
650 gpio_free(GPIO_AUX_PCM_SYNC);
651fail_sync:
652 gpio_free(GPIO_AUX_PCM_DIN);
653fail_din:
654 gpio_free(GPIO_AUX_PCM_DOUT);
655fail_dout:
656
657 return ret;
658}
659
660static int msm8930_aux_pcm_free_gpios(void)
661{
662 gpio_free(GPIO_AUX_PCM_DIN);
663 gpio_free(GPIO_AUX_PCM_DOUT);
664 gpio_free(GPIO_AUX_PCM_SYNC);
665 gpio_free(GPIO_AUX_PCM_CLK);
666
667 return 0;
668}
669static int msm8930_startup(struct snd_pcm_substream *substream)
670{
671 pr_debug("%s(): substream = %s stream = %d\n", __func__,
672 substream->name, substream->stream);
673 return 0;
674}
675
676static int msm8930_auxpcm_startup(struct snd_pcm_substream *substream)
677{
678 int ret = 0;
679
680 pr_debug("%s(): substream = %s\n", __func__, substream->name);
681 ret = msm8930_aux_pcm_get_gpios();
682 if (ret < 0) {
683 pr_err("%s: Aux PCM GPIO request failed\n", __func__);
684 return -EINVAL;
685 }
686 return 0;
687}
688
689static void msm8930_auxpcm_shutdown(struct snd_pcm_substream *substream)
690{
691
692 pr_debug("%s(): substream = %s\n", __func__, substream->name);
693 msm8930_aux_pcm_free_gpios();
694}
695
696static void msm8930_shutdown(struct snd_pcm_substream *substream)
697{
698 pr_debug("%s(): substream = %s stream = %d\n", __func__,
699 substream->name, substream->stream);
700}
701
702static struct snd_soc_ops msm8930_be_ops = {
703 .startup = msm8930_startup,
704 .hw_params = msm8930_hw_params,
705 .shutdown = msm8930_shutdown,
706};
707
708static struct snd_soc_ops msm8930_auxpcm_be_ops = {
709 .startup = msm8930_auxpcm_startup,
710 .shutdown = msm8930_auxpcm_shutdown,
711};
712
713/* Digital audio interface glue - connects codec <---> CPU */
714static struct snd_soc_dai_link msm8930_dai[] = {
715 /* FrontEnd DAI Links */
716 {
717 .name = "MSM8930 Media1",
718 .stream_name = "MultiMedia1",
719 .cpu_dai_name = "MultiMedia1",
720 .platform_name = "msm-pcm-dsp",
721 .dynamic = 1,
722 .dsp_link = &fe_media,
723 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA1
724 },
725 {
726 .name = "MSM8930 Media2",
727 .stream_name = "MultiMedia2",
728 .cpu_dai_name = "MultiMedia2",
729 .platform_name = "msm-pcm-dsp",
730 .dynamic = 1,
731 .dsp_link = &fe_media,
732 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA2,
733 },
734 {
735 .name = "Circuit-Switch Voice",
736 .stream_name = "CS-Voice",
737 .cpu_dai_name = "CS-VOICE",
738 .platform_name = "msm-pcm-voice",
739 .dynamic = 1,
740 .dsp_link = &fe_media,
741 .be_id = MSM_FRONTEND_DAI_CS_VOICE,
742 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
743 .ignore_suspend = 1,
744 },
745 {
746 .name = "MSM VoIP",
747 .stream_name = "VoIP",
748 .cpu_dai_name = "VoIP",
749 .platform_name = "msm-voip-dsp",
750 .dynamic = 1,
751 .dsp_link = &fe_media,
752 .be_id = MSM_FRONTEND_DAI_VOIP,
753 },
754 {
755 .name = "MSM8930 LPA",
756 .stream_name = "LPA",
757 .cpu_dai_name = "MultiMedia3",
758 .platform_name = "msm-pcm-lpa",
759 .dynamic = 1,
760 .dsp_link = &lpa_fe_media,
761 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA3,
762 },
763 /* Hostless PMC purpose */
764 {
765 .name = "SLIMBUS_0 Hostless",
766 .stream_name = "SLIMBUS_0 Hostless",
767 .cpu_dai_name = "SLIMBUS0_HOSTLESS",
768 .platform_name = "msm-pcm-hostless",
769 .dynamic = 1,
770 .dsp_link = &slimbus0_hl_media,
771 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
772 .ignore_suspend = 1,
773 /* .be_id = do not care */
774 },
775 {
776 .name = "INT_FM Hostless",
777 .stream_name = "INT_FM Hostless",
778 .cpu_dai_name = "INT_FM_HOSTLESS",
779 .platform_name = "msm-pcm-hostless",
780 .dynamic = 1,
781 .dsp_link = &int_fm_hl_media,
782 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
783 .ignore_suspend = 1,
784 /* .be_id = do not care */
785 },
786 {
787 .name = "MSM AFE-PCM RX",
788 .stream_name = "AFE-PROXY RX",
789 .cpu_dai_name = "msm-dai-q6.241",
790 .codec_name = "msm-stub-codec.1",
791 .codec_dai_name = "msm-stub-rx",
792 .platform_name = "msm-pcm-afe",
793 .ignore_suspend = 1,
794 },
795 {
796 .name = "MSM AFE-PCM TX",
797 .stream_name = "AFE-PROXY TX",
798 .cpu_dai_name = "msm-dai-q6.240",
799 .codec_name = "msm-stub-codec.1",
800 .codec_dai_name = "msm-stub-tx",
801 .platform_name = "msm-pcm-afe",
802 .ignore_suspend = 1,
803 },
804 {
805 .name = "MSM8930 Compr",
806 .stream_name = "COMPR",
807 .cpu_dai_name = "MultiMedia4",
808 .platform_name = "msm-compr-dsp",
809 .dynamic = 1,
810 .dsp_link = &lpa_fe_media,
811 .be_id = MSM_FRONTEND_DAI_MULTIMEDIA4,
812 },
813 {
814 .name = "AUXPCM Hostless",
815 .stream_name = "AUXPCM Hostless",
816 .cpu_dai_name = "AUXPCM_HOSTLESS",
817 .platform_name = "msm-pcm-hostless",
818 .dynamic = 1,
819 .dsp_link = &bidir_hl_media,
820 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
821 .ignore_suspend = 1,
822 },
823 /* HDMI Hostless */
824 {
825 .name = "HDMI_RX_HOSTLESS",
826 .stream_name = "HDMI_RX_HOSTLESS",
827 .cpu_dai_name = "HDMI_HOSTLESS",
828 .platform_name = "msm-pcm-hostless",
829 .dynamic = 1,
830 .dsp_link = &hdmi_rx_hl,
831 .no_host_mode = SND_SOC_DAI_LINK_NO_HOST,
832 .no_codec = 1,
833 .ignore_suspend = 1,
834 },
835 /* Backend DAI Links */
836 {
837 .name = LPASS_BE_SLIMBUS_0_RX,
838 .stream_name = "Slimbus Playback",
839 .cpu_dai_name = "msm-dai-q6.16384",
840 .platform_name = "msm-pcm-routing",
841 .codec_name = "sitar_codec",
842 .codec_dai_name = "sitar_rx1",
843 .no_pcm = 1,
844 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_RX,
845 .init = &msm8930_audrx_init,
846 .be_hw_params_fixup = msm8930_slim_0_rx_be_hw_params_fixup,
847 .ops = &msm8930_be_ops,
848 },
849 {
850 .name = LPASS_BE_SLIMBUS_0_TX,
851 .stream_name = "Slimbus Capture",
852 .cpu_dai_name = "msm-dai-q6.16385",
853 .platform_name = "msm-pcm-routing",
854 .codec_name = "sitar_codec",
855 .codec_dai_name = "sitar_tx1",
856 .no_pcm = 1,
857 .be_id = MSM_BACKEND_DAI_SLIMBUS_0_TX,
858 .be_hw_params_fixup = msm8930_slim_0_tx_be_hw_params_fixup,
859 .ops = &msm8930_be_ops,
860 },
861 /* Backend BT/FM DAI Links */
862 {
863 .name = LPASS_BE_INT_BT_SCO_RX,
864 .stream_name = "Internal BT-SCO Playback",
865 .cpu_dai_name = "msm-dai-q6.12288",
866 .platform_name = "msm-pcm-routing",
867 .codec_name = "msm-stub-codec.1",
868 .codec_dai_name = "msm-stub-rx",
869 .init = &msm8930_btsco_init,
870 .no_pcm = 1,
871 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_RX,
872 .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
873 },
874 {
875 .name = LPASS_BE_INT_BT_SCO_TX,
876 .stream_name = "Internal BT-SCO Capture",
877 .cpu_dai_name = "msm-dai-q6.12289",
878 .platform_name = "msm-pcm-routing",
879 .codec_name = "msm-stub-codec.1",
880 .codec_dai_name = "msm-stub-tx",
881 .no_pcm = 1,
882 .be_id = MSM_BACKEND_DAI_INT_BT_SCO_TX,
883 .be_hw_params_fixup = msm8930_btsco_be_hw_params_fixup,
884 },
885 {
886 .name = LPASS_BE_INT_FM_RX,
887 .stream_name = "Internal FM Playback",
888 .cpu_dai_name = "msm-dai-q6.12292",
889 .platform_name = "msm-pcm-routing",
890 .codec_name = "msm-stub-codec.1",
891 .codec_dai_name = "msm-stub-rx",
892 .no_pcm = 1,
893 .be_id = MSM_BACKEND_DAI_INT_FM_RX,
894 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
895 },
896 {
897 .name = LPASS_BE_INT_FM_TX,
898 .stream_name = "Internal FM Capture",
899 .cpu_dai_name = "msm-dai-q6.12293",
900 .platform_name = "msm-pcm-routing",
901 .codec_name = "msm-stub-codec.1",
902 .codec_dai_name = "msm-stub-tx",
903 .no_pcm = 1,
904 .be_id = MSM_BACKEND_DAI_INT_FM_TX,
905 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
906 },
907 /* HDMI BACK END DAI Link */
908 {
909 .name = LPASS_BE_HDMI,
910 .stream_name = "HDMI Playback",
911 .cpu_dai_name = "msm-dai-q6-hdmi.8",
912 .platform_name = "msm-pcm-routing",
913 .codec_name = "msm-stub-codec.1",
914 .codec_dai_name = "msm-stub-rx",
915 .no_pcm = 1,
916 .no_codec = 1,
917 .be_id = MSM_BACKEND_DAI_HDMI_RX,
918 .be_hw_params_fixup = msm8930_hdmi_be_hw_params_fixup,
919 },
920 /* Backend AFE DAI Links */
921 {
922 .name = LPASS_BE_AFE_PCM_RX,
923 .stream_name = "AFE Playback",
924 .cpu_dai_name = "msm-dai-q6.224",
925 .platform_name = "msm-pcm-routing",
926 .codec_name = "msm-stub-codec.1",
927 .codec_dai_name = "msm-stub-rx",
928 .no_codec = 1,
929 .no_pcm = 1,
930 .be_id = MSM_BACKEND_DAI_AFE_PCM_RX,
931 },
932 {
933 .name = LPASS_BE_AFE_PCM_TX,
934 .stream_name = "AFE Capture",
935 .cpu_dai_name = "msm-dai-q6.225",
936 .platform_name = "msm-pcm-routing",
937 .codec_name = "msm-stub-codec.1",
938 .codec_dai_name = "msm-stub-tx",
939 .no_codec = 1,
940 .no_pcm = 1,
941 .be_id = MSM_BACKEND_DAI_AFE_PCM_TX,
942 },
943 /* AUX PCM Backend DAI Links */
944 {
945 .name = LPASS_BE_AUXPCM_RX,
946 .stream_name = "AUX PCM Playback",
947 .cpu_dai_name = "msm-dai-q6.2",
948 .platform_name = "msm-pcm-routing",
949 .codec_name = "msm-stub-codec.1",
950 .codec_dai_name = "msm-stub-rx",
951 .no_pcm = 1,
952 .be_id = MSM_BACKEND_DAI_AUXPCM_RX,
953 .be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
954 .ops = &msm8930_auxpcm_be_ops,
955 },
956 {
957 .name = LPASS_BE_AUXPCM_TX,
958 .stream_name = "AUX PCM Capture",
959 .cpu_dai_name = "msm-dai-q6.3",
960 .platform_name = "msm-pcm-routing",
961 .codec_name = "msm-stub-codec.1",
962 .codec_dai_name = "msm-stub-tx",
963 .no_pcm = 1,
964 .be_id = MSM_BACKEND_DAI_AUXPCM_TX,
965 .be_hw_params_fixup = msm8930_auxpcm_be_params_fixup,
966 },
967 /* Incall Music BACK END DAI Link */
968 {
969 .name = LPASS_BE_VOICE_PLAYBACK_TX,
970 .stream_name = "Voice Farend Playback",
971 .cpu_dai_name = "msm-dai-q6.32773",
972 .platform_name = "msm-pcm-routing",
973 .codec_name = "msm-stub-codec.1",
974 .codec_dai_name = "msm-stub-rx",
975 .no_pcm = 1,
976 .no_codec = 1,
977 .be_id = MSM_BACKEND_DAI_VOICE_PLAYBACK_TX,
978 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
979 },
980 /* Incall Record Uplink BACK END DAI Link */
981 {
982 .name = LPASS_BE_INCALL_RECORD_TX,
983 .stream_name = "Voice Uplink Capture",
984 .cpu_dai_name = "msm-dai-q6.32772",
985 .platform_name = "msm-pcm-routing",
986 .codec_name = "msm-stub-codec.1",
987 .codec_dai_name = "msm-stub-tx",
988 .no_pcm = 1,
989 .no_codec = 1,
990 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
991 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
992 },
993 /* Incall Record Downlink BACK END DAI Link */
994 {
995 .name = LPASS_BE_INCALL_RECORD_RX,
996 .stream_name = "Voice Downlink Capture",
997 .cpu_dai_name = "msm-dai-q6.32771",
998 .platform_name = "msm-pcm-routing",
999 .codec_name = "msm-stub-codec.1",
1000 .codec_dai_name = "msm-stub-tx",
1001 .no_pcm = 1,
1002 .no_codec = 1,
1003 .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
1004 .be_hw_params_fixup = msm8930_be_hw_params_fixup,
1005 },
1006};
1007
1008struct snd_soc_card snd_soc_card_msm8930 = {
1009 .name = "msm8930-sitar-snd-card",
1010 .dai_link = msm8930_dai,
1011 .num_links = ARRAY_SIZE(msm8930_dai),
1012};
1013
1014static struct platform_device *msm8930_snd_device;
1015
1016static int msm8930_configure_headset_mic_gpios(void)
1017{
1018 int ret;
1019 ret = gpio_request(80, "US_EURO_SWITCH");
1020 if (ret) {
1021 pr_err("%s: Failed to request gpio 80\n", __func__);
1022 return ret;
1023 }
1024 ret = gpio_direction_output(80, 0);
1025 if (ret) {
1026 pr_err("%s: Unable to set direction\n", __func__);
1027 gpio_free(80);
1028 }
1029 msm8930_headset_gpios_configured = 0;
1030 return 0;
1031}
1032static void msm8930_free_headset_mic_gpios(void)
1033{
1034 if (msm8930_headset_gpios_configured)
1035 gpio_free(80);
1036}
1037
1038static int __init msm8930_audio_init(void)
1039{
1040 int ret;
1041
1042 if (!cpu_is_msm8930()) {
1043 pr_err("%s: Not the right machine type\n", __func__);
1044 return -ENODEV ;
1045 }
1046
1047 msm8930_snd_device = platform_device_alloc("soc-audio", 0);
1048 if (!msm8930_snd_device) {
1049 pr_err("Platform device allocation failed\n");
1050 return -ENOMEM;
1051 }
1052
1053 platform_set_drvdata(msm8930_snd_device, &snd_soc_card_msm8930);
1054 ret = platform_device_add(msm8930_snd_device);
1055 if (ret) {
1056 platform_device_put(msm8930_snd_device);
1057 return ret;
1058 }
1059
1060 if (msm8930_configure_headset_mic_gpios()) {
1061 pr_err("%s Fail to configure headset mic gpios\n", __func__);
1062 msm8930_headset_gpios_configured = 0;
1063 } else
1064 msm8930_headset_gpios_configured = 1;
1065
1066 return ret;
1067
1068}
1069module_init(msm8930_audio_init);
1070
1071static void __exit msm8930_audio_exit(void)
1072{
1073 if (!cpu_is_msm8930()) {
1074 pr_err("%s: Not the right machine type\n", __func__);
1075 return ;
1076 }
1077 msm8930_free_headset_mic_gpios();
1078 platform_device_unregister(msm8930_snd_device);
1079}
1080module_exit(msm8930_audio_exit);
1081
1082MODULE_DESCRIPTION("ALSA SoC MSM8930");
1083MODULE_LICENSE("GPL v2");