blob: 48ce610f9d9c649017299ee68313f01750ed6955 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, 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/init.h>
14#include <linux/err.h>
15#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/time.h>
18#include <linux/wait.h>
19#include <linux/platform_device.h>
20#include <linux/dma-mapping.h>
21#include <linux/msm_audio.h>
22#include <sound/core.h>
23#include <sound/soc.h>
24#include <sound/soc-dapm.h>
25#include <sound/pcm.h>
26#include <sound/tlv.h>
27#include <sound/initval.h>
28#include <sound/control.h>
29#include <sound/q6afe.h>
30#include <asm/dma.h>
31#include <asm/mach-types.h>
32#include <mach/qdsp6v2/audio_dev_ctl.h>
Neema Shetty90189b82011-06-27 14:58:37 -070033#include <mach/qdsp6v2/q6voice.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070034
35#define LOOPBACK_ENABLE 0x1
36#define LOOPBACK_DISABLE 0x0
37
38#include "msm8x60-pcm.h"
39
40static struct platform_device *msm_audio_snd_device;
41struct audio_locks the_locks;
42EXPORT_SYMBOL(the_locks);
43struct msm_volume msm_vol_ctl;
44EXPORT_SYMBOL(msm_vol_ctl);
45struct pcm_session session_route;
46EXPORT_SYMBOL(session_route);
47static struct snd_kcontrol_new snd_msm_controls[];
48
49char snddev_name[AUDIO_DEV_CTL_MAX_DEV][44];
50#define MSM_MAX_VOLUME 0x2000
51#define MSM_VOLUME_STEP ((MSM_MAX_VOLUME+17)/100) /* 17 added to avoid
52 more deviation */
53static int device_index; /* Count of Device controls */
54static int simple_control; /* Count of simple controls*/
55static int src_dev;
56static int dst_dev;
57static int loopback_status;
58
59static int msm_scontrol_count_info(struct snd_kcontrol *kcontrol,
60 struct snd_ctl_elem_info *uinfo)
61{
62 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
63 uinfo->count = 1;
64 return 0;
65}
66
67static int msm_scontrol_count_get(struct snd_kcontrol *kcontrol,
68 struct snd_ctl_elem_value *ucontrol)
69{
70 ucontrol->value.integer.value[0] = simple_control;
71 return 0;
72}
73
74static int msm_v_call_info(struct snd_kcontrol *kcontrol,
75 struct snd_ctl_elem_info *uinfo)
76{
77 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
Neema Shetty90189b82011-06-27 14:58:37 -070078 uinfo->count = 2; /* start, session_id */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070079 uinfo->value.integer.min = 0;
Neema Shetty90189b82011-06-27 14:58:37 -070080 uinfo->value.integer.max = SESSION_ID_BASE + MAX_VOC_SESSIONS;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081 return 0;
82}
83
84static int msm_v_call_get(struct snd_kcontrol *kcontrol,
85 struct snd_ctl_elem_value *ucontrol)
86{
87 ucontrol->value.integer.value[0] = 0;
Neema Shetty90189b82011-06-27 14:58:37 -070088 ucontrol->value.integer.value[1] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070089 return 0;
90}
91
92static int msm_v_call_put(struct snd_kcontrol *kcontrol,
93 struct snd_ctl_elem_value *ucontrol)
94{
95 int start = ucontrol->value.integer.value[0];
Neema Shetty90189b82011-06-27 14:58:37 -070096 u32 session_id = ucontrol->value.integer.value[1];
97
98 if ((session_id != 0) &&
99 ((session_id < SESSION_ID_BASE) ||
100 (session_id >= SESSION_ID_BASE + MAX_VOC_SESSIONS))) {
101 pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
102
103 return -EINVAL;
104 }
105
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106 if (start)
107 broadcast_event(AUDDEV_EVT_START_VOICE, DEVICE_IGNORE,
Neema Shetty90189b82011-06-27 14:58:37 -0700108 session_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109 else
110 broadcast_event(AUDDEV_EVT_END_VOICE, DEVICE_IGNORE,
Neema Shetty90189b82011-06-27 14:58:37 -0700111 session_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700112 return 0;
113}
114
115static int msm_v_mute_info(struct snd_kcontrol *kcontrol,
116 struct snd_ctl_elem_info *uinfo)
117{
118 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
Neema Shetty90189b82011-06-27 14:58:37 -0700119 uinfo->count = 3; /* dir, mute, session_id */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700120 uinfo->value.integer.min = 0;
Neema Shetty90189b82011-06-27 14:58:37 -0700121 uinfo->value.integer.max = SESSION_ID_BASE + MAX_VOC_SESSIONS;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 return 0;
123}
124
125static int msm_v_mute_get(struct snd_kcontrol *kcontrol,
126 struct snd_ctl_elem_value *ucontrol)
127{
128 ucontrol->value.integer.value[0] = 0;
Neema Shetty90189b82011-06-27 14:58:37 -0700129 ucontrol->value.integer.value[1] = 0;
130 ucontrol->value.integer.value[2] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131 return 0;
132}
133
134static int msm_v_mute_put(struct snd_kcontrol *kcontrol,
135 struct snd_ctl_elem_value *ucontrol)
136{
137 int dir = ucontrol->value.integer.value[0];
138 int mute = ucontrol->value.integer.value[1];
Neema Shetty90189b82011-06-27 14:58:37 -0700139 u32 session_id = ucontrol->value.integer.value[2];
140
141 if ((session_id != 0) &&
142 ((session_id < SESSION_ID_BASE) ||
143 (session_id >= SESSION_ID_BASE + MAX_VOC_SESSIONS))) {
144 pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
145
146 return -EINVAL;
147 }
148
149 return msm_set_voice_mute(dir, mute, session_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700150}
151
152static int msm_v_volume_info(struct snd_kcontrol *kcontrol,
153 struct snd_ctl_elem_info *uinfo)
154{
155 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
Neema Shetty90189b82011-06-27 14:58:37 -0700156 uinfo->count = 3; /* dir, volume, session_id */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700157 uinfo->value.integer.min = 0;
Neema Shetty90189b82011-06-27 14:58:37 -0700158 uinfo->value.integer.max = SESSION_ID_BASE + MAX_VOC_SESSIONS;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159 return 0;
160}
161
162static int msm_v_volume_get(struct snd_kcontrol *kcontrol,
163 struct snd_ctl_elem_value *ucontrol)
164{
165 ucontrol->value.integer.value[0] = 0;
Neema Shetty90189b82011-06-27 14:58:37 -0700166 ucontrol->value.integer.value[1] = 0;
167 ucontrol->value.integer.value[2] = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700168 return 0;
169}
170
171static int msm_v_volume_put(struct snd_kcontrol *kcontrol,
172 struct snd_ctl_elem_value *ucontrol)
173{
174 int dir = ucontrol->value.integer.value[0];
175 int volume = ucontrol->value.integer.value[1];
Neema Shetty90189b82011-06-27 14:58:37 -0700176 u32 session_id = ucontrol->value.integer.value[2];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700177
Neema Shetty90189b82011-06-27 14:58:37 -0700178 if ((session_id != 0) &&
179 ((session_id < SESSION_ID_BASE) ||
180 (session_id >= SESSION_ID_BASE + MAX_VOC_SESSIONS))) {
181 pr_err("%s: Invalid session_id 0x%x\n", __func__, session_id);
182
183 return -EINVAL;
184 }
185
186 return msm_set_voice_vol(dir, volume, session_id);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187}
188
189static int msm_volume_info(struct snd_kcontrol *kcontrol,
190 struct snd_ctl_elem_info *uinfo)
191{
192 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
193 uinfo->count = 2; /* Volume */
194 uinfo->value.integer.min = 0;
195 uinfo->value.integer.max = 16383;
196 return 0;
197}
198static int msm_volume_get(struct snd_kcontrol *kcontrol,
199 struct snd_ctl_elem_value *ucontrol)
200{
201 ucontrol->value.integer.value[0] = 0;
202 return 0;
203}
204
205static int msm_volume_put(struct snd_kcontrol *kcontrol,
206 struct snd_ctl_elem_value *ucontrol)
207{
208 int ret = 0;
209 int session_id = ucontrol->value.integer.value[0];
210 int volume = ucontrol->value.integer.value[1];
211 int factor = ucontrol->value.integer.value[2];
212 u64 session_mask = 0;
213
214 if (factor > 10000)
215 return -EINVAL;
216
217 if ((volume < 0) || (volume/factor > 100))
218 return -EINVAL;
219
220 volume = (MSM_VOLUME_STEP * volume);
221
222 /* Convert back to original decimal point by removing the 10-base factor
223 * and discard the fractional portion
224 */
225
226 volume = volume/factor;
227
228 if (volume > MSM_MAX_VOLUME)
229 volume = MSM_MAX_VOLUME;
230
231 /* Only Decoder volume control supported */
232 session_mask = (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
233 ((int)AUDDEV_CLNT_DEC-1));
234 msm_vol_ctl.volume = volume;
235 pr_debug("%s:session_id %d, volume %d", __func__, session_id, volume);
236 broadcast_event(AUDDEV_EVT_STREAM_VOL_CHG, DEVICE_IGNORE,
237 session_mask);
238
239 return ret;
240}
241
242static int msm_voice_info(struct snd_kcontrol *kcontrol,
243 struct snd_ctl_elem_info *uinfo)
244{
245 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
246 uinfo->count = 3; /* Device */
247
248 uinfo->value.integer.min = 0;
249 uinfo->value.integer.max = msm_snddev_devcount();
250 return 0;
251}
252
253static int msm_voice_put(struct snd_kcontrol *kcontrol,
254 struct snd_ctl_elem_value *ucontrol)
255{
256 int rc = 0;
257 uint32_t rx_dev_id;
258 uint32_t tx_dev_id;
259 struct msm_snddev_info *rx_dev_info;
260 struct msm_snddev_info *tx_dev_info;
261 int set = ucontrol->value.integer.value[2];
262 u64 session_mask;
263
264 if (!set)
265 return -EPERM;
266 /* Rx Device Routing */
267 rx_dev_id = ucontrol->value.integer.value[0];
268 rx_dev_info = audio_dev_ctrl_find_dev(rx_dev_id);
269
270 if (IS_ERR(rx_dev_info)) {
271 pr_err("%s:pass invalid dev_id\n", __func__);
272 rc = PTR_ERR(rx_dev_info);
273 return rc;
274 }
275
276 if (!(rx_dev_info->capability & SNDDEV_CAP_RX)) {
277 pr_err("%s:First Dev is supposed to be RX\n", __func__);
278 return -EFAULT;
279 }
280
281 pr_debug("%s:route cfg %d STREAM_VOICE_RX type\n",
282 __func__, rx_dev_id);
283
284 msm_set_voc_route(rx_dev_info, AUDIO_ROUTE_STREAM_VOICE_RX,
285 rx_dev_id);
286
287 session_mask = ((u64)0x1) << (MAX_BIT_PER_CLIENT * \
288 ((int)AUDDEV_CLNT_VOC-1));
289
290 broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, rx_dev_id, session_mask);
291
292
293 /* Tx Device Routing */
294 tx_dev_id = ucontrol->value.integer.value[1];
295 tx_dev_info = audio_dev_ctrl_find_dev(tx_dev_id);
296
297 if (IS_ERR(tx_dev_info)) {
298 pr_err("%s:pass invalid dev_id\n", __func__);
299 rc = PTR_ERR(tx_dev_info);
300 return rc;
301 }
302
303 if (!(tx_dev_info->capability & SNDDEV_CAP_TX)) {
304 pr_err("%s:Second Dev is supposed to be Tx\n", __func__);
305 return -EFAULT;
306 }
307
308 pr_debug("%s:route cfg %d %d type\n",
309 __func__, tx_dev_id, AUDIO_ROUTE_STREAM_VOICE_TX);
310
311 msm_set_voc_route(tx_dev_info, AUDIO_ROUTE_STREAM_VOICE_TX,
312 tx_dev_id);
313
314 broadcast_event(AUDDEV_EVT_DEV_CHG_VOICE, tx_dev_id, session_mask);
315
316 if (rx_dev_info->opened)
317 broadcast_event(AUDDEV_EVT_DEV_RDY, rx_dev_id, session_mask);
318
319 if (tx_dev_info->opened)
320 broadcast_event(AUDDEV_EVT_DEV_RDY, tx_dev_id, session_mask);
321
322 return rc;
323}
324
325static int msm_voice_get(struct snd_kcontrol *kcontrol,
326 struct snd_ctl_elem_value *ucontrol)
327{
328 ucontrol->value.integer.value[0] = 0;
329 /* TODO: query Device list */
330 return 0;
331}
332
333static int msm_device_info(struct snd_kcontrol *kcontrol,
334 struct snd_ctl_elem_info *uinfo)
335{
336 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
337 uinfo->count = 1; /* Device */
338
339 uinfo->value.integer.min = 0;
340 uinfo->value.integer.max = msm_snddev_devcount();
341 return 0;
342}
343
344static int msm_device_put(struct snd_kcontrol *kcontrol,
345 struct snd_ctl_elem_value *ucontrol)
346{
347 int rc = 0;
348 int set = 0;
349 struct msm_audio_route_config route_cfg;
350 struct msm_snddev_info *dev_info;
351 struct msm_snddev_info *dst_dev_info;
352 struct msm_snddev_info *src_dev_info;
353 int tx_freq = 0;
354 int rx_freq = 0;
355 u32 set_freq = 0;
356
357 set = ucontrol->value.integer.value[0];
358 route_cfg.dev_id = ucontrol->id.numid - device_index;
359 dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
360 if (IS_ERR(dev_info)) {
361 pr_err("%s:pass invalid dev_id\n", __func__);
362 rc = PTR_ERR(dev_info);
363 return rc;
364 }
365 pr_info("%s:device %s set %d\n", __func__, dev_info->name, set);
366
367 if (set) {
368 if (!dev_info->opened) {
369 set_freq = dev_info->sample_rate;
370 if (!msm_device_is_voice(route_cfg.dev_id)) {
371 msm_get_voc_freq(&tx_freq, &rx_freq);
372 if (dev_info->capability & SNDDEV_CAP_TX)
373 set_freq = tx_freq;
374
375 if (set_freq == 0)
376 set_freq = dev_info->sample_rate;
377 } else
378 set_freq = dev_info->sample_rate;
379
380
381 pr_err("%s:device freq =%d\n", __func__, set_freq);
382 rc = dev_info->dev_ops.set_freq(dev_info, set_freq);
383 if (rc < 0) {
384 pr_err("%s:device freq failed!\n", __func__);
385 return rc;
386 }
387 dev_info->set_sample_rate = rc;
388 rc = 0;
389 rc = dev_info->dev_ops.open(dev_info);
390 if (rc < 0) {
391 pr_err("%s:Enabling %s failed\n",
392 __func__, dev_info->name);
393 return rc;
394 }
395 dev_info->opened = 1;
396 broadcast_event(AUDDEV_EVT_DEV_RDY, route_cfg.dev_id,
397 SESSION_IGNORE);
398 if ((route_cfg.dev_id == src_dev) ||
399 (route_cfg.dev_id == dst_dev)) {
400 dst_dev_info = audio_dev_ctrl_find_dev(
401 dst_dev);
402 if (IS_ERR(dst_dev_info)) {
403 pr_err("dst_dev:%s:pass invalid"
404 "dev_id\n", __func__);
405 rc = PTR_ERR(dst_dev_info);
406 return rc;
407 }
408 src_dev_info = audio_dev_ctrl_find_dev(
409 src_dev);
410 if (IS_ERR(src_dev_info)) {
411 pr_err("src_dev:%s:pass invalid"
412 "dev_id\n", __func__);
413 rc = PTR_ERR(src_dev_info);
414 return rc;
415 }
416 if ((dst_dev_info->opened) &&
417 (src_dev_info->opened)) {
418 pr_debug("%d: Enable afe_loopback\n",
419 __LINE__);
420 afe_loopback(LOOPBACK_ENABLE,
421 dst_dev_info->copp_id,
422 src_dev_info->copp_id);
423 loopback_status = 1;
424 }
425 }
426 }
427 } else {
428 if (dev_info->opened) {
429 broadcast_event(AUDDEV_EVT_REL_PENDING,
430 route_cfg.dev_id,
431 SESSION_IGNORE);
432 rc = dev_info->dev_ops.close(dev_info);
433 if (rc < 0) {
434 pr_err("%s:Snd device failed close!\n",
435 __func__);
436 return rc;
437 } else {
438 dev_info->opened = 0;
439 broadcast_event(AUDDEV_EVT_DEV_RLS,
440 route_cfg.dev_id,
441 SESSION_IGNORE);
442 }
443 if (loopback_status == 1) {
444 if ((route_cfg.dev_id == src_dev) ||
445 (route_cfg.dev_id == dst_dev)) {
446 dst_dev_info = audio_dev_ctrl_find_dev(
447 dst_dev);
448 if (IS_ERR(dst_dev_info)) {
449 pr_err("dst_dev:%s:pass invalid"
450 "dev_id\n", __func__);
451 rc = PTR_ERR(dst_dev_info);
452 return rc;
453 }
454 src_dev_info = audio_dev_ctrl_find_dev(
455 src_dev);
456 if (IS_ERR(src_dev_info)) {
457 pr_err("src_dev:%s:pass invalid"
458 "dev_id\n", __func__);
459 rc = PTR_ERR(src_dev_info);
460 return rc;
461 }
462 pr_debug("%d: Disable afe_loopback\n",
463 __LINE__);
464 afe_loopback(LOOPBACK_DISABLE,
465 dst_dev_info->copp_id,
466 src_dev_info->copp_id);
467 loopback_status = 0;
468 }
469 }
470 }
471
472 }
473 return rc;
474}
475
476static int msm_device_get(struct snd_kcontrol *kcontrol,
477 struct snd_ctl_elem_value *ucontrol)
478{
479 int rc = 0;
480 struct msm_audio_route_config route_cfg;
481 struct msm_snddev_info *dev_info;
482
483 route_cfg.dev_id = ucontrol->id.numid - device_index;
484 dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
485
486 if (IS_ERR(dev_info)) {
487 pr_err("%s:pass invalid dev_id\n", __func__);
488 rc = PTR_ERR(dev_info);
489 return rc;
490 }
491
492 ucontrol->value.integer.value[0] = dev_info->copp_id;
493 ucontrol->value.integer.value[1] = dev_info->capability;
494
495 return 0;
496}
497
498static int msm_route_info(struct snd_kcontrol *kcontrol,
499 struct snd_ctl_elem_info *uinfo)
500{
501 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
502 uinfo->count = 3; /* Device */
503
504 uinfo->value.integer.min = 0;
505 uinfo->value.integer.max = msm_snddev_devcount();
506 return 0;
507}
508
509static int msm_route_get(struct snd_kcontrol *kcontrol,
510 struct snd_ctl_elem_value *ucontrol)
511{
512 ucontrol->value.integer.value[0] = 0;
513 /* TODO: query Device list */
514 return 0;
515}
516
517static int msm_route_put(struct snd_kcontrol *kcontrol,
518 struct snd_ctl_elem_value *ucontrol)
519{
520 int rc = 0;
521 int enc_freq = 0;
522 int requested_freq = 0;
523 struct msm_audio_route_config route_cfg;
524 struct msm_snddev_info *dev_info;
525 int session_id = ucontrol->value.integer.value[0];
526 int set = ucontrol->value.integer.value[2];
527 u64 session_mask = 0;
528 route_cfg.dev_id = ucontrol->value.integer.value[1];
529
530 if (ucontrol->id.numid == 2)
531 route_cfg.stream_type = AUDIO_ROUTE_STREAM_PLAYBACK;
532 else
533 route_cfg.stream_type = AUDIO_ROUTE_STREAM_REC;
534
535 pr_debug("%s:route cfg %d %d type for popp %d\n",
536 __func__, route_cfg.dev_id, route_cfg.stream_type, session_id);
537 dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
538
539 if (IS_ERR(dev_info)) {
540 pr_err("%s:pass invalid dev_id\n", __func__);
541 rc = PTR_ERR(dev_info);
542 return rc;
543 }
544 if (route_cfg.stream_type == AUDIO_ROUTE_STREAM_PLAYBACK) {
545 rc = msm_snddev_set_dec(session_id, dev_info->copp_id, set,
546 dev_info->sample_rate, dev_info->channel_mode);
547 session_mask =
548 (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
549 ((int)AUDDEV_CLNT_DEC-1));
550 if (!set) {
551 if (dev_info->opened)
552 broadcast_event(AUDDEV_EVT_DEV_RLS,
553 route_cfg.dev_id,
554 session_mask);
555 dev_info->sessions &= ~(session_mask);
556 } else {
557 dev_info->sessions = dev_info->sessions | session_mask;
558 if (dev_info->opened)
559 broadcast_event(AUDDEV_EVT_DEV_RDY,
560 route_cfg.dev_id,
561 session_mask);
562 }
563 } else {
564
565 rc = msm_snddev_set_enc(session_id, dev_info->copp_id, set,
566 dev_info->sample_rate, dev_info->channel_mode);
567 session_mask =
568 (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
569 ((int)AUDDEV_CLNT_ENC-1));
570 if (!set) {
571 if (dev_info->opened)
572 broadcast_event(AUDDEV_EVT_DEV_RLS,
573 route_cfg.dev_id,
574 session_mask);
575 dev_info->sessions &= ~(session_mask);
576 } else {
577 dev_info->sessions = dev_info->sessions | session_mask;
578 enc_freq = msm_snddev_get_enc_freq(session_id);
579 requested_freq = enc_freq;
580 if (enc_freq > 0) {
581 rc = msm_snddev_request_freq(&enc_freq,
582 session_id,
583 SNDDEV_CAP_TX,
584 AUDDEV_CLNT_ENC);
585 pr_debug("%s:sample rate configured %d\
586 sample rate requested %d \n",
587 __func__, enc_freq, requested_freq);
588 if ((rc <= 0) || (enc_freq != requested_freq)) {
589 pr_debug("%s:msm_snddev_withdraw_freq\n",
590 __func__);
591 rc = msm_snddev_withdraw_freq
592 (session_id,
593 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
594 broadcast_event(AUDDEV_EVT_FREQ_CHG,
595 route_cfg.dev_id,
596 SESSION_IGNORE);
597 }
598 }
599 if (dev_info->opened)
600 broadcast_event(AUDDEV_EVT_DEV_RDY,
601 route_cfg.dev_id,
602 session_mask);
603 }
604 }
605
606 if (rc < 0) {
607 pr_err("%s:device could not be assigned!\n", __func__);
608 return -EFAULT;
609 }
610
611 return rc;
612}
613
614static int msm_device_volume_info(struct snd_kcontrol *kcontrol,
615 struct snd_ctl_elem_info *uinfo)
616{
617 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
618 uinfo->count = 2;
619 uinfo->value.integer.min = 0;
620 uinfo->value.integer.max = 100;
621 return 0;
622}
623
624static int msm_device_volume_get(struct snd_kcontrol *kcontrol,
625 struct snd_ctl_elem_value *ucontrol)
626{
627 struct msm_snddev_info *dev_info;
628
629 int dev_id = ucontrol->value.integer.value[0];
630
631 dev_info = audio_dev_ctrl_find_dev(dev_id);
632 ucontrol->value.integer.value[0] = dev_info->dev_volume;
633
634 return 0;
635}
636
637static int msm_device_volume_put(struct snd_kcontrol *kcontrol,
638 struct snd_ctl_elem_value *ucontrol)
639{
640 int rc = -EPERM;
641 struct msm_snddev_info *dev_info;
642
643 int dev_id = ucontrol->value.integer.value[0];
644 int volume = ucontrol->value.integer.value[1];
645
646 pr_debug("%s:dev_id = %d, volume = %d\n", __func__, dev_id, volume);
647
648 dev_info = audio_dev_ctrl_find_dev(dev_id);
649
650 if (IS_ERR(dev_info)) {
651 rc = PTR_ERR(dev_info);
652 pr_err("%s: audio_dev_ctrl_find_dev failed. %ld \n",
653 __func__, PTR_ERR(dev_info));
654 return rc;
655 }
656
657 pr_debug("%s:dev_name = %s dev_id = %d, volume = %d\n",
658 __func__, dev_info->name, dev_id, volume);
659
660 if (dev_info->dev_ops.set_device_volume)
661 rc = dev_info->dev_ops.set_device_volume(dev_info, volume);
662 else {
663 pr_info("%s : device %s does not support device volume "
664 "control.", __func__, dev_info->name);
665 return -EPERM;
666 }
667
668 return rc;
669}
670
671static int msm_reset_info(struct snd_kcontrol *kcontrol,
672 struct snd_ctl_elem_info *uinfo)
673{
674 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
675 uinfo->count = 1;
676 uinfo->value.integer.min = 0;
677 uinfo->value.integer.max = 0;
678 return 0;
679}
680
681static int msm_reset_get(struct snd_kcontrol *kcontrol,
682 struct snd_ctl_elem_value *ucontrol)
683{
684 ucontrol->value.integer.value[0] = 0;
685 return 0;
686}
687
688static int msm_reset_put(struct snd_kcontrol *kcontrol,
689 struct snd_ctl_elem_value *ucontrol)
690{
691 pr_err("%s:Resetting all devices\n", __func__);
692 return msm_reset_all_device();
693}
694
695static int msm_anc_info(struct snd_kcontrol *kcontrol,
696 struct snd_ctl_elem_info *uinfo)
697{
698 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
699 uinfo->count = 1;
700 uinfo->value.integer.min = 0;
701 uinfo->value.integer.max = 1;
702 return 0;
703}
704
705static int msm_anc_get(struct snd_kcontrol *kcontrol,
706 struct snd_ctl_elem_value *ucontrol)
707{
708 ucontrol->value.integer.value[0] = 0;
709 return 0;
710}
711
712static int msm_anc_put(struct snd_kcontrol *kcontrol,
713 struct snd_ctl_elem_value *ucontrol)
714{
715 int rc = -EPERM;
716 struct msm_snddev_info *dev_info;
717
718 int dev_id = ucontrol->value.integer.value[0];
719 int enable = ucontrol->value.integer.value[1];
720
721 pr_debug("%s: dev_id = %d, enable = %d\n", __func__, dev_id, enable);
722 dev_info = audio_dev_ctrl_find_dev(dev_id);
723
724 if (IS_ERR(dev_info)) {
725 rc = PTR_ERR(dev_info);
726 pr_err("%s: audio_dev_ctrl_find_dev failed. %ld\n",
727 __func__, PTR_ERR(dev_info));
728 return rc;
729 }
730
731 if (dev_info->dev_ops.enable_anc) {
732 rc = dev_info->dev_ops.enable_anc(dev_info, enable);
733 } else {
734 pr_info("%s : device %s does not support anc control.",
735 __func__, dev_info->name);
736 return -EPERM;
737 }
738
739 return rc;
740}
741
742static int pcm_route_info(struct snd_kcontrol *kcontrol,
743 struct snd_ctl_elem_info *uinfo)
744{
745 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
746 /*
747 * First parameter is session id ~ subdevice number
748 * Second parameter is device id.
749 */
750 uinfo->count = 3;
751 uinfo->value.integer.min = 0;
752 uinfo->value.integer.max = msm_snddev_devcount();
753 return 0;
754}
755
756static int pcm_route_get_rx(struct snd_kcontrol *kcontrol,
757 struct snd_ctl_elem_value *ucontrol)
758{
759 return 0;
760}
761
762static int pcm_route_get_tx(struct snd_kcontrol *kcontrol,
763 struct snd_ctl_elem_value *ucontrol)
764{
765 return 0;
766}
767
768static int pcm_route_put_rx(struct snd_kcontrol *kcontrol,
769 struct snd_ctl_elem_value *ucontrol)
770{
771 int session_id = 0;
772 int set = 0;
773 struct msm_audio_route_config route_cfg;
774 struct msm_snddev_info *dev_info;
775 u64 session_mask = 0;
776
777 /*
778 * session id is incremented by one and stored as session id 0
779 * is being used by dsp currently. whereas user space would use
780 * subdevice number as session id.
781 */
782 session_id = ucontrol->value.integer.value[0];
783 route_cfg.dev_id = ucontrol->value.integer.value[1];
784 set = ucontrol->value.integer.value[2];
785
786 dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
787 if (IS_ERR(dev_info)) {
788 pr_err("pass invalid dev_id %d\n", route_cfg.dev_id);
789 return PTR_ERR(dev_info);
790 }
791 if (!(dev_info->capability & SNDDEV_CAP_RX))
792 return -EINVAL;
793 session_mask =
794 (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
795 ((int)AUDDEV_CLNT_DEC-1));
796 if (!set) {
797 session_route.playback_session[session_id][dev_info->copp_id]
798 = DEVICE_IGNORE;
799 broadcast_event(AUDDEV_EVT_DEV_RLS,
800 route_cfg.dev_id,
801 session_mask);
802 dev_info->sessions &= ~(session_mask);
803 return 0;
804 }
805 pr_debug("%s:Routing playback session %d to %s\n",
806 __func__, (session_id),
807 dev_info->name);
808 session_route.playback_session[session_id][dev_info->copp_id] =
809 dev_info->copp_id;
810 if (dev_info->opened) {
811 dev_info->sessions = dev_info->sessions | session_mask;
812 broadcast_event(AUDDEV_EVT_DEV_RDY,
813 route_cfg.dev_id,
814 session_mask);
815 } else {
816 broadcast_event(AUDDEV_EVT_DEV_RLS,
817 route_cfg.dev_id,
818 session_mask);
819 dev_info->sessions &= ~(session_mask);
820 }
821 return 0;
822}
823
824static int pcm_route_put_tx(struct snd_kcontrol *kcontrol,
825 struct snd_ctl_elem_value *ucontrol)
826{
827 int session_id = 0;
828 int set = 0;
829 struct msm_audio_route_config route_cfg;
830 struct msm_snddev_info *dev_info;
831 u64 session_mask = 0;
832
833 session_id = ucontrol->value.integer.value[0];
834 route_cfg.dev_id = ucontrol->value.integer.value[1];
835 set = ucontrol->value.integer.value[2];
836
837 dev_info = audio_dev_ctrl_find_dev(route_cfg.dev_id);
838 if (IS_ERR(dev_info)) {
839 pr_err("pass invalid dev_id %d\n", route_cfg.dev_id);
840 return PTR_ERR(dev_info);
841 }
842 pr_debug("%s:Routing capture session %d to %s\n", __func__,
843 session_id,
844 dev_info->name);
845 if (!(dev_info->capability & SNDDEV_CAP_TX))
846 return -EINVAL;
847 session_mask =
848 (((u64)0x1) << session_id) << (MAX_BIT_PER_CLIENT * \
849 ((int)AUDDEV_CLNT_ENC-1));
850 if (!set) {
851 session_route.capture_session[session_id][dev_info->copp_id]
852 = DEVICE_IGNORE;
853 broadcast_event(AUDDEV_EVT_DEV_RLS,
854 route_cfg.dev_id,
855 session_mask);
856 dev_info->sessions &= ~(session_mask);
857 return 0;
858 }
859
860 session_route.capture_session[session_id][dev_info->copp_id] =
861 dev_info->copp_id;
862 if (dev_info->opened) {
863 dev_info->sessions = dev_info->sessions | session_mask;
864 broadcast_event(AUDDEV_EVT_DEV_RDY,
865 route_cfg.dev_id,
866 session_mask);
867 } else {
868 broadcast_event(AUDDEV_EVT_DEV_RLS,
869 route_cfg.dev_id,
870 session_mask);
871 dev_info->sessions &= ~(session_mask);
872 }
873 return 0;
874}
875
876static int msm_loopback_info(struct snd_kcontrol *kcontrol,
877 struct snd_ctl_elem_info *uinfo)
878{
879 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
880 uinfo->count = 3;
881 uinfo->value.integer.min = 0;
882 uinfo->value.integer.max = msm_snddev_devcount();
883 return 0;
884}
885
886static int msm_loopback_get(struct snd_kcontrol *kcontrol,
887 struct snd_ctl_elem_value *ucontrol)
888{
889 ucontrol->value.integer.value[0] = 0;
890 return 0;
891}
892
893static int msm_loopback_put(struct snd_kcontrol *kcontrol,
894 struct snd_ctl_elem_value *ucontrol)
895{
896 int rc = 0;
897 struct msm_snddev_info *src_dev_info = NULL; /* TX device */
898 struct msm_snddev_info *dst_dev_info = NULL; /* RX device */
899 int dst_dev_id = ucontrol->value.integer.value[0];
900 int src_dev_id = ucontrol->value.integer.value[1];
901 int set = ucontrol->value.integer.value[2];
902
903 pr_debug("%s: dst=%d :src=%d set=%d\n", __func__,
904 dst_dev_id, src_dev_id, set);
905
906 dst_dev_info = audio_dev_ctrl_find_dev(dst_dev_id);
907 if (IS_ERR(dst_dev_info)) {
908 pr_err("dst_dev:%s:pass invalid dev_id\n", __func__);
909 rc = PTR_ERR(dst_dev_info);
910 return rc;
911 }
912 if (!(dst_dev_info->capability & SNDDEV_CAP_RX)) {
913 pr_err("Destination device %d is not RX device\n",
914 dst_dev_id);
915 return -EFAULT;
916 }
917
918 src_dev_info = audio_dev_ctrl_find_dev(src_dev_id);
919 if (IS_ERR(src_dev_info)) {
920 pr_err("src_dev:%s:pass invalid dev_id\n", __func__);
921 rc = PTR_ERR(src_dev_info);
922 return rc;
923 }
924 if (!(src_dev_info->capability & SNDDEV_CAP_TX)) {
925 pr_err("Source device %d is not TX device\n", src_dev_id);
926 return -EFAULT;
927 }
928
929 if (set) {
930 pr_debug("%s:%d:Enabling AFE_Loopback\n", __func__, __LINE__);
931 src_dev = src_dev_id;
932 dst_dev = dst_dev_id;
933 loopback_status = 1;
934 if ((dst_dev_info->opened) && (src_dev_info->opened))
935 rc = afe_loopback(LOOPBACK_ENABLE,
936 dst_dev_info->copp_id,
937 src_dev_info->copp_id);
938 } else {
939 pr_debug("%s:%d:Disabling AFE_Loopback\n", __func__, __LINE__);
940 src_dev = DEVICE_IGNORE;
941 dst_dev = DEVICE_IGNORE;
942 loopback_status = 0;
943 rc = afe_loopback(LOOPBACK_DISABLE,
944 dst_dev_info->copp_id,
945 src_dev_info->copp_id);
946 }
947 return rc;
948}
Laxminath Kasam885f5102011-07-14 10:20:21 +0530949static int msm_device_mute_info(struct snd_kcontrol *kcontrol,
950 struct snd_ctl_elem_info *uinfo)
951{
952 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
953 uinfo->count = 2;
954 uinfo->value.integer.min = 0;
955 uinfo->value.integer.max = msm_snddev_devcount();
956 return 0;
957}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958
Laxminath Kasam885f5102011-07-14 10:20:21 +0530959static int msm_device_mute_get(struct snd_kcontrol *kcontrol,
960 struct snd_ctl_elem_value *ucontrol)
961{
962 return 0;
963}
964
965static int msm_device_mute_put(struct snd_kcontrol *kcontrol,
966 struct snd_ctl_elem_value *ucontrol)
967{
968 int dev_id = ucontrol->value.integer.value[0];
969 int mute = ucontrol->value.integer.value[1];
970 struct msm_snddev_info *dev_info;
971 int rc = 0;
972 u16 gain = 0x2000;
973
974 dev_info = audio_dev_ctrl_find_dev(dev_id);
975 if (IS_ERR(dev_info)) {
976 rc = PTR_ERR(dev_info);
977 pr_err("%s: audio_dev_ctrl_find_dev failed. %ld\n",
978 __func__, PTR_ERR(dev_info));
979 return rc;
980 }
981 if (!(dev_info->capability & SNDDEV_CAP_TX)) {
982 rc = -EINVAL;
983 return rc;
984 }
985 if (mute)
986 gain = 0;
987
988 pr_debug("%s:dev_name = %s dev_id = %d, gain = %hX\n",
989 __func__, dev_info->name, dev_id, gain);
990 rc = afe_apply_gain(dev_info->copp_id, gain);
991 if (rc < 0) {
992 pr_err("%s : device %s not able to set device gain "
993 "control.", __func__, dev_info->name);
994 return rc;
995 }
996 pr_debug("Muting/Unmuting device id %d(%s)\n", dev_id, dev_info->name);
997
998 return rc;
999}
Neema Shetty90189b82011-06-27 14:58:37 -07001000
1001static int msm_voc_session_info(struct snd_kcontrol *kcontrol,
1002 struct snd_ctl_elem_info *uinfo)
1003{
1004 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1005 uinfo->count = 1;
1006 uinfo->value.integer.min = 0;
1007 uinfo->value.integer.max = SESSION_ID_BASE + MAX_VOC_SESSIONS;
1008 return 0;
1009}
1010
1011static int msm_voice_session_get(struct snd_kcontrol *kcontrol,
1012 struct snd_ctl_elem_value *ucontrol)
1013{
1014 ucontrol->value.integer.value[0] =
1015 voice_get_session_id("Voice session");
1016 return 0;
1017}
1018
1019static int msm_voip_session_get(struct snd_kcontrol *kcontrol,
1020 struct snd_ctl_elem_value *ucontrol)
1021{
1022 ucontrol->value.integer.value[0] = voice_get_session_id("VoIP session");
1023 return 0;
1024}
1025
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026static struct snd_kcontrol_new snd_dev_controls[AUDIO_DEV_CTL_MAX_DEV];
1027
1028static int snd_dev_ctl_index(int idx)
1029{
1030 struct msm_snddev_info *dev_info;
1031
1032 dev_info = audio_dev_ctrl_find_dev(idx);
1033 if (IS_ERR(dev_info)) {
1034 pr_err("%s:pass invalid dev_id\n", __func__);
1035 return PTR_ERR(dev_info);
1036 }
1037 if (sizeof(dev_info->name) <= 44)
1038 sprintf(&snddev_name[idx][0] , "%s", dev_info->name);
1039
1040 snd_dev_controls[idx].iface = SNDRV_CTL_ELEM_IFACE_MIXER;
1041 snd_dev_controls[idx].access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1042 snd_dev_controls[idx].name = &snddev_name[idx][0];
1043 snd_dev_controls[idx].index = idx;
1044 snd_dev_controls[idx].info = msm_device_info;
1045 snd_dev_controls[idx].get = msm_device_get;
1046 snd_dev_controls[idx].put = msm_device_put;
1047 snd_dev_controls[idx].private_value = 0;
1048 return 0;
1049
1050}
1051
1052#define MSM_EXT(xname, fp_info, fp_get, fp_put, addr) \
1053{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1054 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
1055 .name = xname, \
1056 .info = fp_info,\
1057 .get = fp_get, .put = fp_put, \
1058 .private_value = addr, \
1059}
1060
1061/* If new controls are to be added which would be constant across the
1062 * different targets, please add to the structure
1063 * snd_msm_controls. Please do not add any controls to the structure
1064 * snd_msm_secondary_controls defined below unless they are msm8x60
1065 * specific.
1066 */
1067
1068static struct snd_kcontrol_new snd_msm_controls[] = {
1069 MSM_EXT("Count", msm_scontrol_count_info, msm_scontrol_count_get, \
1070 NULL, 0),
1071 MSM_EXT("Stream", msm_route_info, msm_route_get, \
1072 msm_route_put, 0),
1073 MSM_EXT("Record", msm_route_info, msm_route_get, \
1074 msm_route_put, 0),
1075 MSM_EXT("Voice", msm_voice_info, msm_voice_get, \
1076 msm_voice_put, 0),
1077 MSM_EXT("Volume", msm_volume_info, msm_volume_get, \
1078 msm_volume_put, 0),
1079 MSM_EXT("VoiceVolume", msm_v_volume_info, msm_v_volume_get, \
1080 msm_v_volume_put, 0),
1081 MSM_EXT("VoiceMute", msm_v_mute_info, msm_v_mute_get, \
1082 msm_v_mute_put, 0),
1083 MSM_EXT("Voice Call", msm_v_call_info, msm_v_call_get, \
1084 msm_v_call_put, 0),
1085 MSM_EXT("Device_Volume", msm_device_volume_info,
1086 msm_device_volume_get, msm_device_volume_put, 0),
1087 MSM_EXT("Reset", msm_reset_info,
1088 msm_reset_get, msm_reset_put, 0),
1089 MSM_EXT("ANC", msm_anc_info, msm_anc_get, msm_anc_put, 0),
Laxminath Kasam885f5102011-07-14 10:20:21 +05301090 MSM_EXT("Device_Mute", msm_device_mute_info,
1091 msm_device_mute_get, msm_device_mute_put, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092};
1093
1094static struct snd_kcontrol_new snd_msm_secondary_controls[] = {
1095 MSM_EXT("PCM Playback Sink",
1096 pcm_route_info, pcm_route_get_rx, pcm_route_put_rx, 0),
1097 MSM_EXT("PCM Capture Source",
1098 pcm_route_info, pcm_route_get_tx, pcm_route_put_tx, 0),
1099 MSM_EXT("Sound Device Loopback", msm_loopback_info,
1100 msm_loopback_get, msm_loopback_put, 0),
Neema Shetty90189b82011-06-27 14:58:37 -07001101 MSM_EXT("VoiceVolume Ext",
1102 msm_v_volume_info, msm_v_volume_get, msm_v_volume_put, 0),
1103 MSM_EXT("VoiceMute Ext",
1104 msm_v_mute_info, msm_v_mute_get, msm_v_mute_put, 0),
1105 MSM_EXT("Voice Call Ext",
1106 msm_v_call_info, msm_v_call_get, msm_v_call_put, 0),
1107 MSM_EXT("Voice session",
1108 msm_voc_session_info, msm_voice_session_get, NULL, 0),
1109 MSM_EXT("VoIP session",
1110 msm_voc_session_info, msm_voip_session_get, NULL, 0),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111};
1112
1113static int msm_new_mixer(struct snd_soc_codec *codec)
1114{
1115 unsigned int idx;
1116 int err;
1117 int dev_cnt;
1118
1119 strcpy(codec->card->snd_card->mixername, "MSM Mixer");
1120 for (idx = 0; idx < ARRAY_SIZE(snd_msm_controls); idx++) {
1121 err = snd_ctl_add(codec->card->snd_card,
1122 snd_ctl_new1(&snd_msm_controls[idx],
1123 NULL));
1124 if (err < 0)
1125 pr_err("%s:ERR adding ctl\n", __func__);
1126 }
1127
1128 for (idx = 0; idx < ARRAY_SIZE(snd_msm_secondary_controls); idx++) {
1129 err = snd_ctl_add(codec->card->snd_card,
1130 snd_ctl_new1(&snd_msm_secondary_controls[idx],
1131 NULL));
1132 if (err < 0)
1133 pr_err("%s:ERR adding secondary ctl\n", __func__);
1134 }
1135 dev_cnt = msm_snddev_devcount();
1136
1137 for (idx = 0; idx < dev_cnt; idx++) {
1138 if (!snd_dev_ctl_index(idx)) {
1139 err = snd_ctl_add(codec->card->snd_card,
1140 snd_ctl_new1(&snd_dev_controls[idx],
1141 NULL));
1142 if (err < 0)
1143 pr_err("%s:ERR adding ctl\n", __func__);
1144 } else
1145 return 0;
1146 }
1147 simple_control = ARRAY_SIZE(snd_msm_controls)
1148 + ARRAY_SIZE(snd_msm_secondary_controls);
1149 device_index = simple_control + 1;
1150 return 0;
1151}
1152
1153static int msm_soc_dai_init(
1154 struct snd_soc_pcm_runtime *rtd)
1155{
1156
1157 int ret = 0;
1158 struct snd_soc_codec *codec = rtd->codec;
1159
1160 init_waitqueue_head(&the_locks.enable_wait);
1161 init_waitqueue_head(&the_locks.eos_wait);
1162 init_waitqueue_head(&the_locks.write_wait);
1163 init_waitqueue_head(&the_locks.read_wait);
1164 memset(&session_route, DEVICE_IGNORE, sizeof(struct pcm_session));
1165
1166 ret = msm_new_mixer(codec);
1167 if (ret < 0)
1168 pr_err("%s: ALSA MSM Mixer Fail\n", __func__);
1169
1170 return ret;
1171}
1172
1173static struct snd_soc_dai_link msm_dai[] = {
1174{
1175 .name = "MSM Primary I2S",
1176 .stream_name = "DSP 1",
1177 .cpu_dai_name = "msm-cpu-dai.0",
1178 .platform_name = "msm-dsp-audio.0",
1179 .codec_name = "msm-codec-dai.0",
1180 .codec_dai_name = "msm-codec-dai",
1181 .init = &msm_soc_dai_init,
1182},
1183#ifdef CONFIG_MSM_8x60_VOIP
1184{
1185 .name = "MSM Primary Voip",
1186 .stream_name = "MVS",
1187 .cpu_dai_name = "mvs-cpu-dai.0",
1188 .platform_name = "msm-mvs-audio.0",
1189 .codec_name = "mvs-codec-dai.0",
1190 .codec_dai_name = "mvs-codec-dai",
1191},
1192#endif
1193};
1194
1195static struct snd_soc_card snd_soc_card_msm = {
1196 .name = "msm-audio",
1197 .dai_link = msm_dai,
1198 .num_links = ARRAY_SIZE(msm_dai),
1199};
1200
1201static int __init msm_audio_init(void)
1202{
1203 int ret;
1204
1205 msm_audio_snd_device = platform_device_alloc("soc-audio", -1);
1206 if (!msm_audio_snd_device)
1207 return -ENOMEM;
1208
1209 platform_set_drvdata(msm_audio_snd_device, &snd_soc_card_msm);
1210 ret = platform_device_add(msm_audio_snd_device);
1211 if (ret) {
1212 platform_device_put(msm_audio_snd_device);
1213 return ret;
1214 }
1215
1216 src_dev = DEVICE_IGNORE;
1217 dst_dev = DEVICE_IGNORE;
1218
1219 return ret;
1220}
1221
1222static void __exit msm_audio_exit(void)
1223{
1224 platform_device_unregister(msm_audio_snd_device);
1225}
1226
1227module_init(msm_audio_init);
1228module_exit(msm_audio_exit);
1229
1230MODULE_DESCRIPTION("PCM module");
1231MODULE_LICENSE("GPL v2");