blob: c64a3ffc44958d628c1c6d679db977f2093f78e2 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2008-2010, Code Aurora Forum. All rights reserved.
2 *
3 * All source code in this file is licensed under the following license except
4 * where indicated.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 *
14 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, you can find it at http://www.fsf.org.
17 */
18
19
20#include <linux/init.h>
21#include <linux/err.h>
22#include <linux/module.h>
23#include <linux/moduleparam.h>
24#include <linux/time.h>
25#include <linux/wait.h>
26#include <linux/platform_device.h>
27#include <sound/core.h>
28#include <sound/soc.h>
29#include <sound/soc-dapm.h>
30#include <sound/pcm.h>
31#include <sound/initval.h>
32#include <sound/control.h>
33#include <asm/dma.h>
34#include <linux/dma-mapping.h>
35#include <linux/android_pmem.h>
36#include <linux/slab.h>
37#include "msm7kv2-pcm.h"
38#include <mach/qdsp5v2/audio_dev_ctl.h>
39#include <mach/debug_mm.h>
40
41#define HOSTPCM_STREAM_ID 5
42
43struct snd_msm {
44 struct snd_card *card;
45 struct snd_pcm *pcm;
46};
47
48int copy_count;
49
50static struct snd_pcm_hardware msm_pcm_playback_hardware = {
51 .info = SNDRV_PCM_INFO_MMAP |
52 SNDRV_PCM_INFO_MMAP_VALID |
53 SNDRV_PCM_INFO_INTERLEAVED,
54 .formats = USE_FORMATS,
55 .rates = USE_RATE,
56 .rate_min = USE_RATE_MIN,
57 .rate_max = 48000,
58 .channels_min = 1,
59 .channels_max = 2,
60 .buffer_bytes_max = MAX_BUFFER_PLAYBACK_SIZE,
61 .period_bytes_min = BUFSZ,
62 .period_bytes_max = BUFSZ,
63 .periods_min = 2,
64 .periods_max = 2,
65 .fifo_size = 0,
66};
67
68static struct snd_pcm_hardware msm_pcm_capture_hardware = {
69 .info = SNDRV_PCM_INFO_INTERLEAVED,
70 .formats = USE_FORMATS,
71 .rates = USE_RATE,
72 .rate_min = 8000,
73 .rate_max = 48000,
74 .channels_min = 1,
75 .channels_max = 2,
76 .buffer_bytes_max = MAX_BUFFER_CAPTURE_SIZE,
77 .period_bytes_min = 4096,
78 .period_bytes_max = 4096,
79 .periods_min = 4,
80 .periods_max = 4,
81 .fifo_size = 0,
82};
83
84/* Conventional and unconventional sample rate supported */
85static unsigned int supported_sample_rates[] = {
86 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
87};
88
89static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
90 .count = ARRAY_SIZE(supported_sample_rates),
91 .list = supported_sample_rates,
92 .mask = 0,
93};
94static void alsa_out_listener(u32 evt_id, union auddev_evt_data *evt_payload,
95 void *private_data)
96{
97 struct msm_audio *prtd = (struct msm_audio *) private_data;
98 MM_DBG("evt_id = 0x%8x\n", evt_id);
99 switch (evt_id) {
100 case AUDDEV_EVT_DEV_RDY:
101 MM_DBG("AUDDEV_EVT_DEV_RDY\n");
102 prtd->source |= (0x1 << evt_payload->routing_id);
103 if (prtd->running == 1 && prtd->enabled == 1)
104 audpp_route_stream(prtd->session_id, prtd->source);
105 break;
106 case AUDDEV_EVT_DEV_RLS:
107 MM_DBG("AUDDEV_EVT_DEV_RLS\n");
108 prtd->source &= ~(0x1 << evt_payload->routing_id);
109 if (prtd->running == 1 && prtd->enabled == 1)
110 audpp_route_stream(prtd->session_id, prtd->source);
111 break;
112 case AUDDEV_EVT_STREAM_VOL_CHG:
113 prtd->vol_pan.volume = evt_payload->session_vol;
114 MM_DBG("AUDDEV_EVT_STREAM_VOL_CHG, stream vol %d\n",
115 prtd->vol_pan.volume);
116 if (prtd->running)
117 audpp_set_volume_and_pan(prtd->session_id,
118 prtd->vol_pan.volume,
119 0, POPP);
120 break;
121 default:
122 MM_DBG("Unknown Event\n");
123 break;
124 }
125}
126
127static void alsa_in_listener(u32 evt_id, union auddev_evt_data *evt_payload,
128 void *private_data)
129{
130 struct msm_audio *prtd = (struct msm_audio *) private_data;
131 MM_DBG("evt_id = 0x%8x\n", evt_id);
132
133 switch (evt_id) {
134 case AUDDEV_EVT_DEV_RDY: {
135 MM_DBG("AUDDEV_EVT_DEV_RDY\n");
136 prtd->source |= (0x1 << evt_payload->routing_id);
137
138 if ((prtd->running == 1) && (prtd->enabled == 1))
139 alsa_in_record_config(prtd, 1);
140
141 break;
142 }
143 case AUDDEV_EVT_DEV_RLS: {
144 MM_DBG("AUDDEV_EVT_DEV_RLS\n");
145 prtd->source &= ~(0x1 << evt_payload->routing_id);
146
147 if (!prtd->running || !prtd->enabled)
148 break;
149
150 /* Turn off as per source */
151 if (prtd->source)
152 alsa_in_record_config(prtd, 1);
153 else
154 /* Turn off all */
155 alsa_in_record_config(prtd, 0);
156
157 break;
158 }
159 case AUDDEV_EVT_FREQ_CHG: {
160 MM_DBG("Encoder Driver got sample rate change event\n");
161 MM_DBG("sample rate %d\n", evt_payload->freq_info.sample_rate);
162 MM_DBG("dev_type %d\n", evt_payload->freq_info.dev_type);
163 MM_DBG("acdb_dev_id %d\n", evt_payload->freq_info.acdb_dev_id);
164 if (prtd->running == 1) {
165 /* Stop Recording sample rate does not match
166 with device sample rate */
167 if (evt_payload->freq_info.sample_rate !=
168 prtd->samp_rate) {
169 alsa_in_record_config(prtd, 0);
170 prtd->abort = 1;
171 wake_up(&the_locks.read_wait);
172 }
173 }
174 break;
175 }
176 default:
177 MM_DBG("Unknown Event\n");
178 break;
179 }
180}
181
182static void msm_pcm_enqueue_data(struct snd_pcm_substream *substream)
183{
184 struct snd_pcm_runtime *runtime = substream->runtime;
185 struct msm_audio *prtd = runtime->private_data;
186 unsigned int period_size;
187
188 MM_DBG("prtd->out_tail =%d mmap_flag=%d\n",
189 prtd->out_tail, prtd->mmap_flag);
190 period_size = snd_pcm_lib_period_bytes(substream);
191 alsa_dsp_send_buffer(prtd, prtd->out_tail, period_size);
192 prtd->out_tail ^= 1;
193 ++copy_count;
194 prtd->period++;
195 if (unlikely(prtd->period >= runtime->periods))
196 prtd->period = 0;
197
198}
199
200static void event_handler(void *data)
201{
202 struct msm_audio *prtd = data;
203 MM_DBG("\n");
204 snd_pcm_period_elapsed(prtd->substream);
205 if (prtd->mmap_flag) {
206 if (prtd->dir == SNDRV_PCM_STREAM_CAPTURE)
207 return;
208 if (!prtd->stopped)
209 msm_pcm_enqueue_data(prtd->substream);
210 else
211 prtd->out_needed++;
212 }
213}
214
215static int msm_pcm_playback_prepare(struct snd_pcm_substream *substream)
216{
217 struct snd_pcm_runtime *runtime = substream->runtime;
218 struct msm_audio *prtd = runtime->private_data;
219
220 MM_DBG("\n");
221 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
222 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
223 prtd->pcm_irq_pos = 0;
224 prtd->pcm_buf_pos = 0;
225 if (prtd->enabled)
226 return 0;
227
228 MM_DBG("\n");
229 /* rate and channels are sent to audio driver */
230 prtd->out_sample_rate = runtime->rate;
231 prtd->out_channel_mode = runtime->channels;
232 prtd->data = prtd->substream->dma_buffer.area;
233 prtd->phys = prtd->substream->dma_buffer.addr;
234 prtd->out[0].data = prtd->data + 0;
235 prtd->out[0].addr = prtd->phys + 0;
236 prtd->out[0].size = BUFSZ;
237 prtd->out[1].data = prtd->data + BUFSZ;
238 prtd->out[1].addr = prtd->phys + BUFSZ;
239 prtd->out[1].size = BUFSZ;
240
241 if (prtd->enabled | !(prtd->mmap_flag))
242 return 0;
243
244 prtd->out[0].used = prtd->pcm_count;
245 prtd->out[1].used = prtd->pcm_count;
246
247 mutex_lock(&the_locks.lock);
248 alsa_audio_configure(prtd);
249 mutex_unlock(&the_locks.lock);
250
251 return 0;
252}
253
254static int msm_pcm_capture_prepare(struct snd_pcm_substream *substream)
255{
256 struct snd_pcm_runtime *runtime = substream->runtime;
257 struct msm_audio *prtd = runtime->private_data;
258 int ret = 0;
259 uint32_t freq;
260 MM_DBG("\n");
261 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
262 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
263 prtd->pcm_irq_pos = 0;
264 prtd->pcm_buf_pos = 0;
265
266 /* rate and channels are sent to audio driver */
267 prtd->type = ENC_TYPE_WAV;
268 prtd->samp_rate = runtime->rate;
269 prtd->channel_mode = (runtime->channels - 1);
270 prtd->buffer_size = prtd->channel_mode ? STEREO_DATA_SIZE : \
271 MONO_DATA_SIZE;
272
273 if (prtd->enabled)
274 return 0;
275
276 freq = prtd->samp_rate;
277
278 prtd->data = prtd->substream->dma_buffer.area;
279 prtd->phys = prtd->substream->dma_buffer.addr;
280 MM_DBG("prtd->data =%08x\n", (unsigned int)prtd->data);
281 MM_DBG("prtd->phys =%08x\n", (unsigned int)prtd->phys);
282
283 mutex_lock(&the_locks.lock);
284 ret = alsa_audio_configure(prtd);
285 mutex_unlock(&the_locks.lock);
286 if (ret)
287 return ret;
288 ret = wait_event_interruptible(the_locks.enable_wait,
289 prtd->running != 0);
290 MM_DBG("state prtd->running = %d ret = %d\n", prtd->running, ret);
291
292 if (prtd->running == 0)
293 ret = -ENODEV;
294 else
295 ret = 0;
296 prtd->enabled = 1;
297
298 return ret;
299}
300
301static int msm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
302{
303 struct snd_pcm_runtime *runtime = substream->runtime;
304 struct msm_audio *prtd = runtime->private_data;
305 unsigned long flag = 0;
306 int ret = 0;
307
308 MM_DBG("\n");
309 switch (cmd) {
310 case SNDRV_PCM_TRIGGER_START:
311 case SNDRV_PCM_TRIGGER_RESUME:
312 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
313 if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
314 || !prtd->mmap_flag)
315 break;
316 if (!prtd->out_needed) {
317 prtd->stopped = 0;
318 break;
319 }
320 spin_lock_irqsave(&the_locks.write_dsp_lock, flag);
321 if (prtd->running == 1) {
322 if (prtd->stopped == 1) {
323 prtd->stopped = 0;
324 prtd->period = 0;
325 if (prtd->pcm_irq_pos == 0) {
326 prtd->out_tail = 0;
327 msm_pcm_enqueue_data(prtd->substream);
328 prtd->out_needed--;
329 } else {
330 prtd->out_tail = 1;
331 msm_pcm_enqueue_data(prtd->substream);
332 prtd->out_needed--;
333 }
334 if (prtd->out_needed) {
335 prtd->out_tail ^= 1;
336 msm_pcm_enqueue_data(prtd->substream);
337 prtd->out_needed--;
338 }
339 }
340 }
341 spin_unlock_irqrestore(&the_locks.write_dsp_lock, flag);
342 break;
343 case SNDRV_PCM_TRIGGER_STOP:
344 case SNDRV_PCM_TRIGGER_SUSPEND:
345 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
346 if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE)
347 || !prtd->mmap_flag)
348 break;
349 prtd->stopped = 1;
350 break;
351 default:
352 ret = -EINVAL;
353 break;
354 }
355
356 return ret;
357}
358
359struct msm_audio_event_callbacks snd_msm_audio_ops = {
360 .playback = event_handler,
361 .capture = event_handler,
362};
363
364static int msm_pcm_open(struct snd_pcm_substream *substream)
365{
366 struct snd_pcm_runtime *runtime = substream->runtime;
367 struct msm_audio *prtd;
368 int ret = 0;
369 int i = 0;
370 int session_attrb, sessionid;
371
372 MM_DBG("\n");
373 prtd = kzalloc(sizeof(struct msm_audio), GFP_KERNEL);
374 if (prtd == NULL) {
375 ret = -ENOMEM;
376 return ret;
377 }
378 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
379 if (prtd->opened) {
380 kfree(prtd);
381 return -EBUSY;
382 }
383 runtime->hw = msm_pcm_playback_hardware;
384 prtd->dir = SNDRV_PCM_STREAM_PLAYBACK;
385 prtd->eos_ack = 0;
386 prtd->session_id = HOSTPCM_STREAM_ID;
387 prtd->device_events = AUDDEV_EVT_DEV_RDY |
388 AUDDEV_EVT_STREAM_VOL_CHG |
389 AUDDEV_EVT_DEV_RLS;
390 prtd->source = msm_snddev_route_dec(prtd->session_id);
391 MM_ERR("Register device event listener\n");
392 ret = auddev_register_evt_listner(prtd->device_events,
393 AUDDEV_CLNT_DEC, prtd->session_id,
394 alsa_out_listener, (void *) prtd);
395 if (ret) {
396 MM_ERR("failed to register device event listener\n");
397 goto evt_error;
398 }
399 } else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
400 runtime->hw = msm_pcm_capture_hardware;
401 prtd->dir = SNDRV_PCM_STREAM_CAPTURE;
402 session_attrb = ENC_TYPE_WAV;
403 sessionid = audpreproc_aenc_alloc(session_attrb,
404 &prtd->module_name, &prtd->queue_id);
405 if (sessionid < 0) {
406 MM_ERR("AUDREC not available\n");
407 kfree(prtd);
408 return -ENODEV;
409 }
410 prtd->session_id = sessionid;
411 MM_DBG("%s\n", prtd->module_name);
412 ret = msm_adsp_get(prtd->module_name, &prtd->audrec,
413 &alsa_audrec_adsp_ops, prtd);
414 if (ret < 0) {
415 audpreproc_aenc_free(prtd->session_id);
416 kfree(prtd);
417 return -ENODEV;
418 }
419
420 prtd->abort = 0;
421 prtd->device_events = AUDDEV_EVT_DEV_RDY | AUDDEV_EVT_DEV_RLS |
422 AUDDEV_EVT_FREQ_CHG;
423 prtd->source = msm_snddev_route_enc(prtd->session_id);
424 MM_ERR("Register device event listener\n");
425 ret = auddev_register_evt_listner(prtd->device_events,
426 AUDDEV_CLNT_ENC, prtd->session_id,
427 alsa_in_listener, (void *) prtd);
428 if (ret) {
429 MM_ERR("failed to register device event listener\n");
430 audpreproc_aenc_free(prtd->session_id);
431 msm_adsp_put(prtd->audrec);
432 goto evt_error;
433 }
434 }
435 prtd->substream = substream;
436 ret = snd_pcm_hw_constraint_list(runtime, 0,
437 SNDRV_PCM_HW_PARAM_RATE,
438 &constraints_sample_rates);
439 if (ret < 0)
440 MM_ERR("snd_pcm_hw_constraint_list failed\n");
441 /* Ensure that buffer size is a multiple of period size */
442 ret = snd_pcm_hw_constraint_integer(runtime,
443 SNDRV_PCM_HW_PARAM_PERIODS);
444 if (ret < 0)
445 MM_ERR("snd_pcm_hw_constraint_integer failed\n");
446
447 prtd->ops = &snd_msm_audio_ops;
448 prtd->out[0].used = BUF_INVALID_LEN;
449 prtd->out[1].used = 0;
450 prtd->out_head = 1; /* point to second buffer on startup */
451 prtd->out_tail = 0;
452 prtd->dsp_cnt = 0;
453 prtd->in_head = 0;
454 prtd->in_tail = 0;
455 prtd->in_count = 0;
456 prtd->out_needed = 0;
457 for (i = 0; i < FRAME_NUM; i++) {
458 prtd->in[i].size = 0;
459 prtd->in[i].read = 0;
460 }
461 prtd->vol_pan.volume = 0x2000;
462 prtd->vol_pan.pan = 0x0;
463 prtd->opened = 1;
464 runtime->private_data = prtd;
465
466 copy_count = 0;
467 return 0;
468evt_error:
469 kfree(prtd);
470 return ret;
471}
472
473static int msm_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
474 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
475{
476 int ret = 0;
477 int fbytes = 0;
478
479 struct snd_pcm_runtime *runtime = substream->runtime;
480 struct msm_audio *prtd = runtime->private_data;
481
482 fbytes = frames_to_bytes(runtime, frames);
483 MM_DBG("%d\n", fbytes);
484 ret = alsa_send_buffer(prtd, buf, fbytes, NULL);
485 ++copy_count;
486 prtd->pcm_buf_pos += fbytes;
487 if (copy_count == 1) {
488 mutex_lock(&the_locks.lock);
489 ret = alsa_audio_configure(prtd);
490 mutex_unlock(&the_locks.lock);
491 }
492 return ret;
493}
494
495static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
496{
497 struct snd_pcm_runtime *runtime = substream->runtime;
498 struct msm_audio *prtd = runtime->private_data;
499
500 int ret = 0;
501
502 MM_DBG("\n");
503 if ((!prtd->mmap_flag) && prtd->enabled) {
504 ret = wait_event_interruptible(the_locks.eos_wait,
505 (!(prtd->out[0].used) && !(prtd->out[1].used)));
506
507 if (ret < 0)
508 goto done;
509 }
510
511 /* PCM DMAMISS message is sent only once in
512 * hpcm interface. So, wait for buffer complete
513 * and teos flag.
514 */
515 if (prtd->enabled)
516 ret = wait_event_interruptible(the_locks.eos_wait,
517 prtd->eos_ack);
518
519done:
520 alsa_audio_disable(prtd);
521 auddev_unregister_evt_listner(AUDDEV_CLNT_DEC, prtd->session_id);
522 kfree(prtd);
523
524 return 0;
525}
526
527static int msm_pcm_capture_copy(struct snd_pcm_substream *substream,
528 int channel, snd_pcm_uframes_t hwoff, void __user *buf,
529 snd_pcm_uframes_t frames)
530{
531 int ret = 0, rc1 = 0, rc2 = 0;
532 int fbytes = 0;
533 struct snd_pcm_runtime *runtime = substream->runtime;
534 struct msm_audio *prtd = substream->runtime->private_data;
535
536 int monofbytes = 0;
537 char *bufferp = NULL;
538
539 if (prtd->abort)
540 return -EPERM;
541
542 fbytes = frames_to_bytes(runtime, frames);
543 MM_DBG("%d\n", fbytes);
544 monofbytes = fbytes / 2;
545 if (runtime->channels == 2) {
546 ret = alsa_buffer_read(prtd, buf, fbytes, NULL);
547 } else {
548 bufferp = buf;
549 rc1 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
550 bufferp = buf + monofbytes ;
551 rc2 = alsa_buffer_read(prtd, bufferp, monofbytes, NULL);
552 ret = rc1 + rc2;
553 }
554 prtd->pcm_buf_pos += fbytes;
555 MM_DBG("prtd->pcm_buf_pos =%d, prtd->mmap_flag =%d\n",
556 prtd->pcm_buf_pos, prtd->mmap_flag);
557 return ret;
558}
559
560static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
561{
562 struct snd_pcm_runtime *runtime = substream->runtime;
563 struct msm_audio *prtd = runtime->private_data;
564 int ret = 0;
565
566 MM_DBG("\n");
567 ret = msm_snddev_withdraw_freq(prtd->session_id,
568 SNDDEV_CAP_TX, AUDDEV_CLNT_ENC);
569 MM_DBG("msm_snddev_withdraw_freq\n");
570 auddev_unregister_evt_listner(AUDDEV_CLNT_ENC, prtd->session_id);
571 prtd->abort = 0;
572 wake_up(&the_locks.enable_wait);
573 alsa_audrec_disable(prtd);
574 audpreproc_aenc_free(prtd->session_id);
575 msm_adsp_put(prtd->audrec);
576 kfree(prtd);
577 return 0;
578}
579
580static int msm_pcm_copy(struct snd_pcm_substream *substream, int a,
581 snd_pcm_uframes_t hwoff, void __user *buf, snd_pcm_uframes_t frames)
582{
583 int ret = 0;
584
585 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
586 ret = msm_pcm_playback_copy(substream, a, hwoff, buf, frames);
587 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
588 ret = msm_pcm_capture_copy(substream, a, hwoff, buf, frames);
589 return ret;
590}
591
592static int msm_pcm_close(struct snd_pcm_substream *substream)
593{
594 int ret = 0;
595
596 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
597 ret = msm_pcm_playback_close(substream);
598 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
599 ret = msm_pcm_capture_close(substream);
600 return ret;
601}
602static int msm_pcm_prepare(struct snd_pcm_substream *substream)
603{
604 int ret = 0;
605
606 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
607 ret = msm_pcm_playback_prepare(substream);
608 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
609 ret = msm_pcm_capture_prepare(substream);
610 return ret;
611}
612
613static snd_pcm_uframes_t msm_pcm_pointer(struct snd_pcm_substream *substream)
614{
615
616 struct snd_pcm_runtime *runtime = substream->runtime;
617 struct msm_audio *prtd = runtime->private_data;
618
619 MM_DBG("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
620 if (prtd->pcm_irq_pos == prtd->pcm_size)
621 prtd->pcm_irq_pos = 0;
622 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
623}
624
625int msm_pcm_mmap(struct snd_pcm_substream *substream,
626 struct vm_area_struct *vma)
627{
628 struct snd_pcm_runtime *runtime = substream->runtime;
629 struct msm_audio *prtd = runtime->private_data;
630
631 prtd->out_head = 0; /* point to First buffer on startup */
632 prtd->mmap_flag = 1;
633 runtime->dma_bytes = snd_pcm_lib_period_bytes(substream)*2;
634 dma_mmap_coherent(substream->pcm->card->dev, vma,
635 runtime->dma_area,
636 runtime->dma_addr,
637 runtime->dma_bytes);
638 return 0;
639}
640
641int msm_pcm_hw_params(struct snd_pcm_substream *substream,
642 struct snd_pcm_hw_params *params)
643{
644 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
645 return 0;
646}
647
648static struct snd_pcm_ops msm_pcm_ops = {
649 .open = msm_pcm_open,
650 .copy = msm_pcm_copy,
651 .hw_params = msm_pcm_hw_params,
652 .close = msm_pcm_close,
653 .ioctl = snd_pcm_lib_ioctl,
654 .prepare = msm_pcm_prepare,
655 .trigger = msm_pcm_trigger,
656 .pointer = msm_pcm_pointer,
657 .mmap = msm_pcm_mmap,
658};
659
660static int pcm_preallocate_buffer(struct snd_pcm *pcm,
661 int stream)
662{
663 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
664 struct snd_dma_buffer *buf = &substream->dma_buffer;
665 size_t size;
666 if (!stream)
667 size = PLAYBACK_DMASZ;
668 else
669 size = CAPTURE_DMASZ;
670
671 buf->dev.type = SNDRV_DMA_TYPE_DEV;
672 buf->dev.dev = pcm->card->dev;
673 buf->private_data = NULL;
674 buf->area = dma_alloc_coherent(pcm->card->dev, size,
675 &buf->addr, GFP_KERNEL);
676 if (!buf->area)
677 return -ENOMEM;
678
679 buf->bytes = size;
680 return 0;
681}
682
683static void msm_pcm_free_buffers(struct snd_pcm *pcm)
684{
685 struct snd_pcm_substream *substream;
686 struct snd_dma_buffer *buf;
687 int stream;
688
689 for (stream = 0; stream < 2; stream++) {
690 substream = pcm->streams[stream].substream;
691 if (!substream)
692 continue;
693
694 buf = &substream->dma_buffer;
695 if (!buf->area)
696 continue;
697
698 dma_free_coherent(pcm->card->dev, buf->bytes,
699 buf->area, buf->addr);
700 buf->area = NULL;
701 }
702}
703
704static int msm_pcm_new(struct snd_soc_pcm_runtime *rtd)
705{
706 int ret = 0;
707 struct snd_card *card = rtd->card->snd_card;
708 struct snd_pcm *pcm = rtd->pcm;
709
710 ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, 1);
711 if (ret)
712 return ret;
713 ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, 1);
714 if (ret)
715 return ret;
716 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &msm_pcm_ops);
717 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &msm_pcm_ops);
718
719 if (!card->dev->coherent_dma_mask)
720 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
721
722 ret = pcm_preallocate_buffer(pcm,
723 SNDRV_PCM_STREAM_PLAYBACK);
724 if (ret)
725 return ret;
726 ret = pcm_preallocate_buffer(pcm,
727 SNDRV_PCM_STREAM_CAPTURE);
728 if (ret)
729 msm_pcm_free_buffers(pcm);
730 return ret;
731}
732
733struct snd_soc_platform_driver msm_soc_platform = {
734 .ops = &msm_pcm_ops,
735 .pcm_new = msm_pcm_new,
736 .pcm_free = msm_pcm_free_buffers,
737};
738EXPORT_SYMBOL(msm_soc_platform);
739
740static __devinit int msm_pcm_probe(struct platform_device *pdev)
741{
742 return snd_soc_register_platform(&pdev->dev,
743 &msm_soc_platform);
744}
745
746static int msm_pcm_remove(struct platform_device *pdev)
747{
748 snd_soc_unregister_platform(&pdev->dev);
749 return 0;
750}
751
752static struct platform_driver msm_pcm_driver = {
753 .driver = {
754 .name = "msm-dsp-audio",
755 .owner = THIS_MODULE,
756 },
757 .probe = msm_pcm_probe,
758 .remove = __devexit_p(msm_pcm_remove),
759};
760
761static int __init msm_soc_platform_init(void)
762{
763 return platform_driver_register(&msm_pcm_driver);
764}
765module_init(msm_soc_platform_init);
766
767static void __exit msm_soc_platform_exit(void)
768{
769 platform_driver_unregister(&msm_pcm_driver);
770}
771module_exit(msm_soc_platform_exit);
772
773MODULE_DESCRIPTION("PCM module platform driver");
774MODULE_LICENSE("GPL v2");