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