blob: 11ac3308dda296eae15ce9005147d9b77f79079b [file] [log] [blame]
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -08001/* Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
Asish Bhattacharya305d1752011-11-01 20:38:26 +05302 *
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
14#include <linux/init.h>
15#include <linux/err.h>
16#include <linux/module.h>
17#include <linux/moduleparam.h>
18#include <linux/time.h>
19#include <linux/wait.h>
20#include <linux/platform_device.h>
21#include <linux/slab.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/initval.h>
27#include <sound/control.h>
28#include <asm/dma.h>
29#include <linux/dma-mapping.h>
30#include <linux/android_pmem.h>
31
32#include "msm-compr-q6.h"
33#include "msm-pcm-routing.h"
34
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -080035struct snd_msm {
36 struct msm_audio *prtd;
37 unsigned volume;
38};
39static struct snd_msm compressed_audio = {NULL, 0x2000} ;
40
Asish Bhattacharya305d1752011-11-01 20:38:26 +053041static struct audio_locks the_locks;
42
43static struct snd_pcm_hardware msm_compr_hardware_playback = {
44 .info = (SNDRV_PCM_INFO_MMAP |
45 SNDRV_PCM_INFO_BLOCK_TRANSFER |
46 SNDRV_PCM_INFO_MMAP_VALID |
47 SNDRV_PCM_INFO_INTERLEAVED |
48 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
49 .formats = SNDRV_PCM_FMTBIT_S16_LE,
50 .rates = SNDRV_PCM_RATE_8000_48000,
51 .rate_min = 8000,
52 .rate_max = 48000,
53 .channels_min = 1,
54 .channels_max = 2,
55 .buffer_bytes_max = 1200 * 1024 * 2,
Krishnankutty Kolathappillya966f452012-01-12 12:28:36 -080056 .period_bytes_min = 4800,
Asish Bhattacharya305d1752011-11-01 20:38:26 +053057 .period_bytes_max = 1200 * 1024,
58 .periods_min = 2,
Krishnankutty Kolathappillya966f452012-01-12 12:28:36 -080059 .periods_max = 512,
Asish Bhattacharya305d1752011-11-01 20:38:26 +053060 .fifo_size = 0,
61};
62
63/* Conventional and unconventional sample rate supported */
64static unsigned int supported_sample_rates[] = {
65 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
66};
67
68static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
69 .count = ARRAY_SIZE(supported_sample_rates),
70 .list = supported_sample_rates,
71 .mask = 0,
72};
73
74static void compr_event_handler(uint32_t opcode,
75 uint32_t token, uint32_t *payload, void *priv)
76{
77 struct compr_audio *compr = priv;
78 struct msm_audio *prtd = &compr->prtd;
79 struct snd_pcm_substream *substream = prtd->substream;
80 struct snd_pcm_runtime *runtime = substream->runtime;
81 struct audio_aio_write_param param;
82 struct audio_buffer *buf = NULL;
83 int i = 0;
84
85 pr_debug("%s opcode =%08x\n", __func__, opcode);
86 switch (opcode) {
87 case ASM_DATA_EVENT_WRITE_DONE: {
88 uint32_t *ptrmem = (uint32_t *)&param;
89 pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
90 pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
91 prtd->pcm_irq_pos += prtd->pcm_count;
92 if (atomic_read(&prtd->start))
93 snd_pcm_period_elapsed(substream);
94 atomic_inc(&prtd->out_count);
95 wake_up(&the_locks.write_wait);
96 if (!atomic_read(&prtd->start)) {
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +053097 atomic_set(&prtd->pending_buffer, 1);
Asish Bhattacharya305d1752011-11-01 20:38:26 +053098 break;
99 } else
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530100 atomic_set(&prtd->pending_buffer, 0);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530101
102 if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
103 break;
104 buf = prtd->audio_client->port[IN].buf;
105 pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
106 __func__, prtd->pcm_count, prtd->out_head);
107 pr_debug("%s:writing buffer[%d] from 0x%08x\n",
108 __func__, prtd->out_head,
109 ((unsigned int)buf[0].phys
110 + (prtd->out_head * prtd->pcm_count)));
111
112 param.paddr = (unsigned long)buf[0].phys
113 + (prtd->out_head * prtd->pcm_count);
114 param.len = prtd->pcm_count;
115 param.msw_ts = 0;
116 param.lsw_ts = 0;
117 param.flags = NO_TIMESTAMP;
118 param.uid = (unsigned long)buf[0].phys
119 + (prtd->out_head * prtd->pcm_count);
120 for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
121 i++, ++ptrmem)
122 pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
123 if (q6asm_async_write(prtd->audio_client,
124 &param) < 0)
125 pr_err("%s:q6asm_async_write failed\n",
126 __func__);
127 else
128 prtd->out_head =
129 (prtd->out_head + 1) & (runtime->periods - 1);
130 break;
131 }
132 case ASM_DATA_CMDRSP_EOS:
133 pr_debug("ASM_DATA_CMDRSP_EOS\n");
134 prtd->cmd_ack = 1;
135 wake_up(&the_locks.eos_wait);
136 break;
137 case APR_BASIC_RSP_RESULT: {
138 switch (payload[0]) {
139 case ASM_SESSION_CMD_RUN: {
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530140 if (!atomic_read(&prtd->pending_buffer))
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530141 break;
142 pr_debug("%s:writing %d bytes"
143 " of buffer[%d] to dsp\n",
144 __func__, prtd->pcm_count, prtd->out_head);
145 buf = prtd->audio_client->port[IN].buf;
146 pr_debug("%s:writing buffer[%d] from 0x%08x\n",
147 __func__, prtd->out_head,
148 ((unsigned int)buf[0].phys
149 + (prtd->out_head * prtd->pcm_count)));
150 param.paddr = (unsigned long)buf[prtd->out_head].phys;
151 param.len = prtd->pcm_count;
152 param.msw_ts = 0;
153 param.lsw_ts = 0;
154 param.flags = NO_TIMESTAMP;
155 param.uid = (unsigned long)buf[prtd->out_head].phys;
156 if (q6asm_async_write(prtd->audio_client,
157 &param) < 0)
158 pr_err("%s:q6asm_async_write failed\n",
159 __func__);
160 else
161 prtd->out_head =
162 (prtd->out_head + 1)
163 & (runtime->periods - 1);
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530164 atomic_set(&prtd->pending_buffer, 0);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530165 }
166 break;
167 case ASM_STREAM_CMD_FLUSH:
168 pr_debug("ASM_STREAM_CMD_FLUSH\n");
169 prtd->cmd_ack = 1;
170 wake_up(&the_locks.eos_wait);
171 break;
172 default:
173 break;
174 }
175 break;
176 }
177 default:
178 pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
179 break;
180 }
181}
182
183static int msm_compr_playback_prepare(struct snd_pcm_substream *substream)
184{
185 struct snd_pcm_runtime *runtime = substream->runtime;
186 struct compr_audio *compr = runtime->private_data;
187 struct msm_audio *prtd = &compr->prtd;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800188 struct asm_aac_cfg aac_cfg;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530189 int ret;
190
191 pr_debug("%s\n", __func__);
192 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
193 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
194 prtd->pcm_irq_pos = 0;
195 /* rate and channels are sent to audio driver */
196 prtd->samp_rate = runtime->rate;
197 prtd->channel_mode = runtime->channels;
198 prtd->out_head = 0;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800199 atomic_set(&prtd->out_count, runtime->periods);
200
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530201 if (prtd->enabled)
202 return 0;
203
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800204 switch (compr->info.codec_param.codec.id) {
205 case SND_AUDIOCODEC_MP3:
206 ret = q6asm_media_format_block(prtd->audio_client,
207 compr->codec);
208 if (ret < 0)
209 pr_info("%s: CMD Format block failed\n", __func__);
210 break;
211 case SND_AUDIOCODEC_AAC:
212 pr_debug("SND_AUDIOCODEC_AAC\n");
213 memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
214 aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
215 aac_cfg.format = 0x03;
216 aac_cfg.ch_cfg = runtime->channels;
217 aac_cfg.sample_rate = runtime->rate;
218 ret = q6asm_media_format_block_aac(prtd->audio_client,
219 &aac_cfg);
220 if (ret < 0)
221 pr_err("%s: CMD Format block failed\n", __func__);
222 break;
223 default:
224 return -EINVAL;
225 }
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530226
227 prtd->enabled = 1;
228 prtd->cmd_ack = 0;
229
230 return 0;
231}
232
233static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
234{
235 int ret = 0;
236 struct snd_pcm_runtime *runtime = substream->runtime;
237 struct compr_audio *compr = runtime->private_data;
238 struct msm_audio *prtd = &compr->prtd;
239
240 pr_debug("%s\n", __func__);
241 switch (cmd) {
242 case SNDRV_PCM_TRIGGER_START:
243 prtd->pcm_irq_pos = 0;
244 case SNDRV_PCM_TRIGGER_RESUME:
245 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
246 pr_debug("%s: Trigger start\n", __func__);
247 q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
248 atomic_set(&prtd->start, 1);
249 break;
250 case SNDRV_PCM_TRIGGER_STOP:
251 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
252 atomic_set(&prtd->start, 0);
253 break;
254 case SNDRV_PCM_TRIGGER_SUSPEND:
255 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
256 pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
257 q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
258 atomic_set(&prtd->start, 0);
259 break;
260 default:
261 ret = -EINVAL;
262 break;
263 }
264
265 return ret;
266}
267
268static void populate_codec_list(struct compr_audio *compr,
269 struct snd_pcm_runtime *runtime)
270{
271 pr_debug("%s\n", __func__);
272 /* MP3 Block */
273 compr->info.compr_cap.num_codecs = 1;
274 compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
275 compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
276 compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
277 compr->info.compr_cap.max_fragments = runtime->hw.periods_max;
278 compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800279 compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530280 /* Add new codecs here */
281}
282
283static int msm_compr_open(struct snd_pcm_substream *substream)
284{
285 struct snd_pcm_runtime *runtime = substream->runtime;
286 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
287 struct compr_audio *compr;
288 struct msm_audio *prtd;
289 int ret = 0;
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -0800290 struct asm_softpause_params softpause = {
291 .enable = SOFT_PAUSE_ENABLE,
292 .period = SOFT_PAUSE_PERIOD,
293 .step = SOFT_PAUSE_STEP,
294 .rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
295 };
296 struct asm_softvolume_params softvol = {
297 .period = SOFT_VOLUME_PERIOD,
298 .step = SOFT_VOLUME_STEP,
299 .rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
300 };
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530301
302 /* Capture path */
303 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
304 return -EINVAL;
305
306 pr_debug("%s\n", __func__);
307 compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
308 if (compr == NULL) {
309 pr_err("Failed to allocate memory for msm_audio\n");
310 return -ENOMEM;
311 }
312 prtd = &compr->prtd;
313 prtd->substream = substream;
314 prtd->audio_client = q6asm_audio_client_alloc(
315 (app_cb)compr_event_handler, compr);
316 if (!prtd->audio_client) {
317 pr_info("%s: Could not allocate memory\n", __func__);
318 kfree(prtd);
319 return -ENOMEM;
320 }
321 runtime->hw = msm_compr_hardware_playback;
322
323 pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
324
325 prtd->session_id = prtd->audio_client->session;
326 msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
327 prtd->session_id, substream->stream);
328
329 prtd->cmd_ack = 1;
330
331 ret = snd_pcm_hw_constraint_list(runtime, 0,
332 SNDRV_PCM_HW_PARAM_RATE,
333 &constraints_sample_rates);
334 if (ret < 0)
335 pr_info("snd_pcm_hw_constraint_list failed\n");
336 /* Ensure that buffer size is a multiple of period size */
337 ret = snd_pcm_hw_constraint_integer(runtime,
338 SNDRV_PCM_HW_PARAM_PERIODS);
339 if (ret < 0)
340 pr_info("snd_pcm_hw_constraint_integer failed\n");
341
342 prtd->dsp_cnt = 0;
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530343 atomic_set(&prtd->pending_buffer, 1);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530344 compr->codec = FORMAT_MP3;
345 populate_codec_list(compr, runtime);
346 runtime->private_data = compr;
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -0800347 compressed_audio.prtd = &compr->prtd;
348 ret = compressed_set_volume(compressed_audio.volume);
349 if (ret < 0)
350 pr_err("%s : Set Volume failed : %d", __func__, ret);
351
352 ret = q6asm_set_softpause(compressed_audio.prtd->audio_client,
353 &softpause);
354 if (ret < 0)
355 pr_err("%s: Send SoftPause Param failed ret=%d\n",
356 __func__, ret);
357 ret = q6asm_set_softvolume(compressed_audio.prtd->audio_client,
358 &softvol);
359 if (ret < 0)
360 pr_err("%s: Send SoftVolume Param failed ret=%d\n",
361 __func__, ret);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530362
363 return 0;
364}
365
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -0800366int compressed_set_volume(unsigned volume)
367{
368 int rc = 0;
369 if (compressed_audio.prtd && compressed_audio.prtd->audio_client) {
370 rc = q6asm_set_volume(compressed_audio.prtd->audio_client,
371 volume);
372 if (rc < 0) {
373 pr_err("%s: Send Volume command failed"
374 " rc=%d\n", __func__, rc);
375 }
376 }
377 compressed_audio.volume = volume;
378 return rc;
379}
380
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530381static int msm_compr_playback_close(struct snd_pcm_substream *substream)
382{
383 struct snd_pcm_runtime *runtime = substream->runtime;
384 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
385 struct compr_audio *compr = runtime->private_data;
386 struct msm_audio *prtd = &compr->prtd;
387 int dir = 0;
388
389 pr_debug("%s\n", __func__);
390
391 dir = IN;
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530392 atomic_set(&prtd->pending_buffer, 0);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530393 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -0800394 compressed_audio.prtd = NULL;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530395 q6asm_audio_client_buf_free_contiguous(dir,
396 prtd->audio_client);
397
398 msm_pcm_routing_dereg_phy_stream(soc_prtd->dai_link->be_id,
399 SNDRV_PCM_STREAM_PLAYBACK);
400 q6asm_audio_client_free(prtd->audio_client);
401 kfree(prtd);
402 return 0;
403}
404
405static int msm_compr_close(struct snd_pcm_substream *substream)
406{
407 int ret = 0;
408
409 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
410 ret = msm_compr_playback_close(substream);
411 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
412 ret = EINVAL;
413 return ret;
414}
415static int msm_compr_prepare(struct snd_pcm_substream *substream)
416{
417 int ret = 0;
418
419 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
420 ret = msm_compr_playback_prepare(substream);
421 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
422 ret = EINVAL;
423 return ret;
424}
425
426static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream)
427{
428
429 struct snd_pcm_runtime *runtime = substream->runtime;
430 struct compr_audio *compr = runtime->private_data;
431 struct msm_audio *prtd = &compr->prtd;
432
433 if (prtd->pcm_irq_pos >= prtd->pcm_size)
434 prtd->pcm_irq_pos = 0;
435
436 pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
437 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
438}
439
440static int msm_compr_mmap(struct snd_pcm_substream *substream,
441 struct vm_area_struct *vma)
442{
443 int result = 0;
444 struct snd_pcm_runtime *runtime = substream->runtime;
445 struct compr_audio *compr = runtime->private_data;
446 struct msm_audio *prtd = &compr->prtd;
447
448 pr_debug("%s\n", __func__);
449 prtd->mmap_flag = 1;
450 if (runtime->dma_addr && runtime->dma_bytes) {
451 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
452 result = remap_pfn_range(vma, vma->vm_start,
453 runtime->dma_addr >> PAGE_SHIFT,
454 runtime->dma_bytes,
455 vma->vm_page_prot);
456 } else {
457 pr_err("Physical address or size of buf is NULL");
458 return -EINVAL;
459 }
460 return result;
461}
462
463static int msm_compr_hw_params(struct snd_pcm_substream *substream,
464 struct snd_pcm_hw_params *params)
465{
466 struct snd_pcm_runtime *runtime = substream->runtime;
467 struct compr_audio *compr = runtime->private_data;
468 struct msm_audio *prtd = &compr->prtd;
469 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
470 struct audio_buffer *buf;
471 int dir, ret;
472
473 pr_debug("%s\n", __func__);
474 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
475 dir = IN;
476 else
477 return -EINVAL;
478
479 ret = q6asm_open_write(prtd->audio_client, compr->codec);
480 if (ret < 0) {
481 pr_err("%s: Session out open failed\n", __func__);
482 return -ENOMEM;
483 }
484 ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
485 if (ret < 0) {
486 pr_err("%s: Set IO mode failed\n", __func__);
487 return -ENOMEM;
488 }
489
490 ret = q6asm_audio_client_buf_alloc_contiguous(dir,
491 prtd->audio_client,
492 runtime->hw.period_bytes_min,
493 runtime->hw.periods_max);
494 if (ret < 0) {
495 pr_err("Audio Start: Buffer Allocation failed "
496 "rc = %d\n", ret);
497 return -ENOMEM;
498 }
499 buf = prtd->audio_client->port[dir].buf;
500
501 pr_debug("%s:buf = %p\n", __func__, buf);
502 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
503 dma_buf->dev.dev = substream->pcm->card->dev;
504 dma_buf->private_data = NULL;
505 dma_buf->area = buf[0].data;
506 dma_buf->addr = buf[0].phys;
507 dma_buf->bytes = runtime->hw.buffer_bytes_max;
508 if (!dma_buf->area)
509 return -ENOMEM;
510
511 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
512 return 0;
513}
514
515static int msm_compr_ioctl(struct snd_pcm_substream *substream,
516 unsigned int cmd, void *arg)
517{
518 int rc = 0;
519 struct snd_pcm_runtime *runtime = substream->runtime;
520 struct compr_audio *compr = runtime->private_data;
521 struct msm_audio *prtd = &compr->prtd;
Asish Bhattacharya8664b252011-12-30 05:43:23 +0530522 uint64_t timestamp;
523 uint64_t temp;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530524
525 switch (cmd) {
Asish Bhattacharya8664b252011-12-30 05:43:23 +0530526 case SNDRV_COMPRESS_TSTAMP: {
527 struct snd_compr_tstamp tstamp;
528 pr_debug("SNDRV_COMPRESS_TSTAMP\n");
529
530 memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
531 timestamp = q6asm_get_session_time(prtd->audio_client);
532 if (timestamp < 0) {
533 pr_err("%s: Get Session Time return value =%lld\n",
534 __func__, timestamp);
535 return -EAGAIN;
536 }
537 temp = (timestamp * 2 * runtime->channels);
538 temp = temp * (runtime->rate/1000);
539 temp = div_u64(temp, 1000);
540 tstamp.sampling_rate = runtime->rate;
541 tstamp.rendered = (size_t)(temp & 0xFFFFFFFF);
542 tstamp.decoded = (size_t)((temp >> 32) & 0xFFFFFFFF);
543 tstamp.timestamp = timestamp;
544 pr_debug("%s: bytes_consumed:lsb = %d, msb = %d,"
545 "timestamp = %lld,\n",
546 __func__, tstamp.rendered, tstamp.decoded,
547 tstamp.timestamp);
548 if (copy_to_user((void *) arg, &tstamp,
549 sizeof(struct snd_compr_tstamp)))
550 return -EFAULT;
551 return 0;
552 }
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530553 case SNDRV_COMPRESS_GET_CAPS:
554 pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
555 if (copy_to_user((void *) arg, &compr->info.compr_cap,
556 sizeof(struct snd_compr_caps))) {
557 rc = -EFAULT;
558 pr_err("%s: ERROR: copy to user\n", __func__);
559 return rc;
560 }
561 return 0;
562 case SNDRV_COMPRESS_SET_PARAMS:
563 pr_debug("SNDRV_COMPRESS_SET_PARAMS: ");
564 if (copy_from_user(&compr->info.codec_param, (void *) arg,
565 sizeof(struct snd_compr_params))) {
566 rc = -EFAULT;
567 pr_err("%s: ERROR: copy from user\n", __func__);
568 return rc;
569 }
570 switch (compr->info.codec_param.codec.id) {
571 case SND_AUDIOCODEC_MP3:
572 /* For MP3 we dont need any other parameter */
573 pr_debug("SND_AUDIOCODEC_MP3\n");
574 compr->codec = FORMAT_MP3;
575 break;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800576 case SND_AUDIOCODEC_AAC:
577 pr_debug("SND_AUDIOCODEC_AAC\n");
578 compr->codec = FORMAT_MPEG4_AAC;
579 break;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530580 default:
581 pr_debug("FORMAT_LINEAR_PCM\n");
582 compr->codec = FORMAT_LINEAR_PCM;
583 break;
584 }
585 return 0;
586 case SNDRV_PCM_IOCTL1_RESET:
587 prtd->cmd_ack = 0;
588 rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
589 if (rc < 0)
590 pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
591 rc = wait_event_timeout(the_locks.eos_wait,
592 prtd->cmd_ack, 5 * HZ);
593 if (rc < 0)
594 pr_err("Flush cmd timeout\n");
595 prtd->pcm_irq_pos = 0;
596 break;
597 default:
598 break;
599 }
600 return snd_pcm_lib_ioctl(substream, cmd, arg);
601}
602
603static struct snd_pcm_ops msm_compr_ops = {
604 .open = msm_compr_open,
605 .hw_params = msm_compr_hw_params,
606 .close = msm_compr_close,
607 .ioctl = msm_compr_ioctl,
608 .prepare = msm_compr_prepare,
609 .trigger = msm_compr_trigger,
610 .pointer = msm_compr_pointer,
611 .mmap = msm_compr_mmap,
612};
613
614static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
615{
616 struct snd_card *card = rtd->card->snd_card;
617 int ret = 0;
618
619 if (!card->dev->coherent_dma_mask)
620 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
621 return ret;
622}
623
624static struct snd_soc_platform_driver msm_soc_platform = {
625 .ops = &msm_compr_ops,
626 .pcm_new = msm_asoc_pcm_new,
627};
628
629static __devinit int msm_compr_probe(struct platform_device *pdev)
630{
631 pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
632 return snd_soc_register_platform(&pdev->dev,
633 &msm_soc_platform);
634}
635
636static int msm_compr_remove(struct platform_device *pdev)
637{
638 snd_soc_unregister_platform(&pdev->dev);
639 return 0;
640}
641
642static struct platform_driver msm_compr_driver = {
643 .driver = {
644 .name = "msm-compr-dsp",
645 .owner = THIS_MODULE,
646 },
647 .probe = msm_compr_probe,
648 .remove = __devexit_p(msm_compr_remove),
649};
650
651static int __init msm_soc_platform_init(void)
652{
653 init_waitqueue_head(&the_locks.enable_wait);
654 init_waitqueue_head(&the_locks.eos_wait);
655 init_waitqueue_head(&the_locks.write_wait);
656 init_waitqueue_head(&the_locks.read_wait);
657
658 return platform_driver_register(&msm_compr_driver);
659}
660module_init(msm_soc_platform_init);
661
662static void __exit msm_soc_platform_exit(void)
663{
664 platform_driver_unregister(&msm_compr_driver);
665}
666module_exit(msm_soc_platform_exit);
667
668MODULE_DESCRIPTION("PCM module platform driver");
669MODULE_LICENSE("GPL v2");