blob: d4045e17ce83fa48491c1bea8640fcec80f289ca [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>
Krishnankutty Kolathappillyf02f9ef2012-04-19 23:40:05 -070032#include <sound/timer.h>
Asish Bhattacharya305d1752011-11-01 20:38:26 +053033
34#include "msm-compr-q6.h"
35#include "msm-pcm-routing.h"
36
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -080037struct snd_msm {
38 struct msm_audio *prtd;
39 unsigned volume;
40};
41static struct snd_msm compressed_audio = {NULL, 0x2000} ;
42
Asish Bhattacharya305d1752011-11-01 20:38:26 +053043static struct audio_locks the_locks;
44
45static struct snd_pcm_hardware msm_compr_hardware_playback = {
46 .info = (SNDRV_PCM_INFO_MMAP |
47 SNDRV_PCM_INFO_BLOCK_TRANSFER |
48 SNDRV_PCM_INFO_MMAP_VALID |
49 SNDRV_PCM_INFO_INTERLEAVED |
50 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
51 .formats = SNDRV_PCM_FMTBIT_S16_LE,
Krishnankutty Kolathappillyfce9dbd2012-03-15 19:52:54 -070052 .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT,
Asish Bhattacharya305d1752011-11-01 20:38:26 +053053 .rate_min = 8000,
54 .rate_max = 48000,
55 .channels_min = 1,
56 .channels_max = 2,
57 .buffer_bytes_max = 1200 * 1024 * 2,
Krishnankutty Kolathappillya966f452012-01-12 12:28:36 -080058 .period_bytes_min = 4800,
Asish Bhattacharya305d1752011-11-01 20:38:26 +053059 .period_bytes_max = 1200 * 1024,
60 .periods_min = 2,
Krishnankutty Kolathappillya966f452012-01-12 12:28:36 -080061 .periods_max = 512,
Asish Bhattacharya305d1752011-11-01 20:38:26 +053062 .fifo_size = 0,
63};
64
65/* Conventional and unconventional sample rate supported */
66static unsigned int supported_sample_rates[] = {
67 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
68};
69
70static struct snd_pcm_hw_constraint_list constraints_sample_rates = {
71 .count = ARRAY_SIZE(supported_sample_rates),
72 .list = supported_sample_rates,
73 .mask = 0,
74};
75
76static void compr_event_handler(uint32_t opcode,
77 uint32_t token, uint32_t *payload, void *priv)
78{
79 struct compr_audio *compr = priv;
80 struct msm_audio *prtd = &compr->prtd;
81 struct snd_pcm_substream *substream = prtd->substream;
82 struct snd_pcm_runtime *runtime = substream->runtime;
83 struct audio_aio_write_param param;
84 struct audio_buffer *buf = NULL;
85 int i = 0;
86
87 pr_debug("%s opcode =%08x\n", __func__, opcode);
88 switch (opcode) {
89 case ASM_DATA_EVENT_WRITE_DONE: {
90 uint32_t *ptrmem = (uint32_t *)&param;
91 pr_debug("ASM_DATA_EVENT_WRITE_DONE\n");
92 pr_debug("Buffer Consumed = 0x%08x\n", *ptrmem);
93 prtd->pcm_irq_pos += prtd->pcm_count;
94 if (atomic_read(&prtd->start))
95 snd_pcm_period_elapsed(substream);
Krishnankutty Kolathappillyf02f9ef2012-04-19 23:40:05 -070096 else
97 if (substream->timer_running)
98 snd_timer_interrupt(substream->timer, 1);
Asish Bhattacharya305d1752011-11-01 20:38:26 +053099 atomic_inc(&prtd->out_count);
100 wake_up(&the_locks.write_wait);
101 if (!atomic_read(&prtd->start)) {
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530102 atomic_set(&prtd->pending_buffer, 1);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530103 break;
104 } else
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530105 atomic_set(&prtd->pending_buffer, 0);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530106 if (runtime->status->hw_ptr >= runtime->control->appl_ptr)
107 break;
108 buf = prtd->audio_client->port[IN].buf;
109 pr_debug("%s:writing %d bytes of buffer[%d] to dsp 2\n",
110 __func__, prtd->pcm_count, prtd->out_head);
111 pr_debug("%s:writing buffer[%d] from 0x%08x\n",
112 __func__, prtd->out_head,
113 ((unsigned int)buf[0].phys
114 + (prtd->out_head * prtd->pcm_count)));
115
116 param.paddr = (unsigned long)buf[0].phys
117 + (prtd->out_head * prtd->pcm_count);
118 param.len = prtd->pcm_count;
119 param.msw_ts = 0;
120 param.lsw_ts = 0;
121 param.flags = NO_TIMESTAMP;
122 param.uid = (unsigned long)buf[0].phys
123 + (prtd->out_head * prtd->pcm_count);
124 for (i = 0; i < sizeof(struct audio_aio_write_param)/4;
125 i++, ++ptrmem)
126 pr_debug("cmd[%d]=0x%08x\n", i, *ptrmem);
127 if (q6asm_async_write(prtd->audio_client,
128 &param) < 0)
129 pr_err("%s:q6asm_async_write failed\n",
130 __func__);
131 else
132 prtd->out_head =
133 (prtd->out_head + 1) & (runtime->periods - 1);
134 break;
135 }
136 case ASM_DATA_CMDRSP_EOS:
137 pr_debug("ASM_DATA_CMDRSP_EOS\n");
138 prtd->cmd_ack = 1;
139 wake_up(&the_locks.eos_wait);
140 break;
141 case APR_BASIC_RSP_RESULT: {
142 switch (payload[0]) {
143 case ASM_SESSION_CMD_RUN: {
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530144 if (!atomic_read(&prtd->pending_buffer))
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530145 break;
146 pr_debug("%s:writing %d bytes"
147 " of buffer[%d] to dsp\n",
148 __func__, prtd->pcm_count, prtd->out_head);
149 buf = prtd->audio_client->port[IN].buf;
150 pr_debug("%s:writing buffer[%d] from 0x%08x\n",
151 __func__, prtd->out_head,
152 ((unsigned int)buf[0].phys
153 + (prtd->out_head * prtd->pcm_count)));
154 param.paddr = (unsigned long)buf[prtd->out_head].phys;
155 param.len = prtd->pcm_count;
156 param.msw_ts = 0;
157 param.lsw_ts = 0;
158 param.flags = NO_TIMESTAMP;
159 param.uid = (unsigned long)buf[prtd->out_head].phys;
160 if (q6asm_async_write(prtd->audio_client,
161 &param) < 0)
162 pr_err("%s:q6asm_async_write failed\n",
163 __func__);
164 else
165 prtd->out_head =
166 (prtd->out_head + 1)
167 & (runtime->periods - 1);
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530168 atomic_set(&prtd->pending_buffer, 0);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530169 }
170 break;
171 case ASM_STREAM_CMD_FLUSH:
172 pr_debug("ASM_STREAM_CMD_FLUSH\n");
173 prtd->cmd_ack = 1;
174 wake_up(&the_locks.eos_wait);
175 break;
176 default:
177 break;
178 }
179 break;
180 }
181 default:
182 pr_debug("Not Supported Event opcode[0x%x]\n", opcode);
183 break;
184 }
185}
186
187static int msm_compr_playback_prepare(struct snd_pcm_substream *substream)
188{
189 struct snd_pcm_runtime *runtime = substream->runtime;
190 struct compr_audio *compr = runtime->private_data;
191 struct msm_audio *prtd = &compr->prtd;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800192 struct asm_aac_cfg aac_cfg;
Aviral Gupta66698c12012-04-28 22:09:48 +0530193 struct asm_wma_cfg wma_cfg;
Aviral Guptac4ee3b02012-05-09 10:53:45 +0530194 struct asm_wmapro_cfg wma_pro_cfg;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530195 int ret;
196
Santosh Mardie27ed782012-03-29 04:20:38 +0530197 pr_debug("compressed stream prepare\n");
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530198 prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
199 prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
200 prtd->pcm_irq_pos = 0;
201 /* rate and channels are sent to audio driver */
202 prtd->samp_rate = runtime->rate;
203 prtd->channel_mode = runtime->channels;
204 prtd->out_head = 0;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800205 atomic_set(&prtd->out_count, runtime->periods);
206
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530207 if (prtd->enabled)
208 return 0;
209
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800210 switch (compr->info.codec_param.codec.id) {
211 case SND_AUDIOCODEC_MP3:
212 ret = q6asm_media_format_block(prtd->audio_client,
213 compr->codec);
214 if (ret < 0)
215 pr_info("%s: CMD Format block failed\n", __func__);
216 break;
217 case SND_AUDIOCODEC_AAC:
218 pr_debug("SND_AUDIOCODEC_AAC\n");
219 memset(&aac_cfg, 0x0, sizeof(struct asm_aac_cfg));
220 aac_cfg.aot = AAC_ENC_MODE_EAAC_P;
221 aac_cfg.format = 0x03;
222 aac_cfg.ch_cfg = runtime->channels;
Aviral Gupta66698c12012-04-28 22:09:48 +0530223 aac_cfg.sample_rate = runtime->rate;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800224 ret = q6asm_media_format_block_aac(prtd->audio_client,
225 &aac_cfg);
226 if (ret < 0)
227 pr_err("%s: CMD Format block failed\n", __func__);
228 break;
Santosh Mardie27ed782012-03-29 04:20:38 +0530229 case SND_AUDIOCODEC_AC3_PASS_THROUGH:
230 pr_debug("compressd playback, no need to send"
231 " the decoder params\n");
232 break;
Aviral Gupta66698c12012-04-28 22:09:48 +0530233 case SND_AUDIOCODEC_WMA:
234 pr_debug("SND_AUDIOCODEC_WMA\n");
235 memset(&wma_cfg, 0x0, sizeof(struct asm_wma_cfg));
236 wma_cfg.format_tag = compr->info.codec_param.codec.format;
237 wma_cfg.ch_cfg = runtime->channels;
238 wma_cfg.sample_rate = runtime->rate;
239 wma_cfg.avg_bytes_per_sec =
240 compr->info.codec_param.codec.bit_rate/8;
241 wma_cfg.block_align = compr->info.codec_param.codec.align;
242 wma_cfg.valid_bits_per_sample =
243 compr->info.codec_param.codec.options.wma.bits_per_sample;
244 wma_cfg.ch_mask =
245 compr->info.codec_param.codec.options.wma.channelmask;
246 wma_cfg.encode_opt =
247 compr->info.codec_param.codec.options.wma.encodeopt;
248 ret = q6asm_media_format_block_wma(prtd->audio_client,
249 &wma_cfg);
250 if (ret < 0)
251 pr_err("%s: CMD Format block failed\n", __func__);
252 break;
Aviral Guptac4ee3b02012-05-09 10:53:45 +0530253 case SND_AUDIOCODEC_WMA_PRO:
254 pr_debug("SND_AUDIOCODEC_WMA_PRO\n");
255 memset(&wma_pro_cfg, 0x0, sizeof(struct asm_wmapro_cfg));
256 wma_pro_cfg.format_tag = compr->info.codec_param.codec.format;
257 wma_pro_cfg.ch_cfg = compr->info.codec_param.codec.ch_in;
258 wma_pro_cfg.sample_rate = runtime->rate;
259 wma_pro_cfg.avg_bytes_per_sec =
260 compr->info.codec_param.codec.bit_rate/8;
261 wma_pro_cfg.block_align = compr->info.codec_param.codec.align;
262 wma_pro_cfg.valid_bits_per_sample =
Santosh Mardid1760792012-06-12 16:23:19 +0530263 compr->info.codec_param.codec\
264 .options.wma.bits_per_sample;
Aviral Guptac4ee3b02012-05-09 10:53:45 +0530265 wma_pro_cfg.ch_mask =
266 compr->info.codec_param.codec.options.wma.channelmask;
267 wma_pro_cfg.encode_opt =
268 compr->info.codec_param.codec.options.wma.encodeopt;
269 ret = q6asm_media_format_block_wmapro(prtd->audio_client,
270 &wma_pro_cfg);
271 if (ret < 0)
272 pr_err("%s: CMD Format block failed\n", __func__);
273 break;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800274 default:
275 return -EINVAL;
276 }
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530277
278 prtd->enabled = 1;
279 prtd->cmd_ack = 0;
280
281 return 0;
282}
283
284static int msm_compr_trigger(struct snd_pcm_substream *substream, int cmd)
285{
286 int ret = 0;
287 struct snd_pcm_runtime *runtime = substream->runtime;
Santosh Mardie27ed782012-03-29 04:20:38 +0530288 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530289 struct compr_audio *compr = runtime->private_data;
290 struct msm_audio *prtd = &compr->prtd;
291
292 pr_debug("%s\n", __func__);
293 switch (cmd) {
294 case SNDRV_PCM_TRIGGER_START:
295 prtd->pcm_irq_pos = 0;
Santosh Mardie27ed782012-03-29 04:20:38 +0530296 if (compr->info.codec_param.codec.id ==
297 SND_AUDIOCODEC_AC3_PASS_THROUGH) {
298 msm_pcm_routing_reg_psthr_stream(
299 soc_prtd->dai_link->be_id,
Santosh Mardid1760792012-06-12 16:23:19 +0530300 prtd->session_id, substream->stream, 1);
Santosh Mardie27ed782012-03-29 04:20:38 +0530301 }
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530302 case SNDRV_PCM_TRIGGER_RESUME:
303 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
304 pr_debug("%s: Trigger start\n", __func__);
305 q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
306 atomic_set(&prtd->start, 1);
307 break;
308 case SNDRV_PCM_TRIGGER_STOP:
309 pr_debug("SNDRV_PCM_TRIGGER_STOP\n");
Santosh Mardid1760792012-06-12 16:23:19 +0530310 if (compr->info.codec_param.codec.id ==
311 SND_AUDIOCODEC_AC3_PASS_THROUGH) {
312 msm_pcm_routing_reg_psthr_stream(
313 soc_prtd->dai_link->be_id,
314 prtd->session_id, substream->stream, 0);
315 }
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530316 atomic_set(&prtd->start, 0);
317 break;
318 case SNDRV_PCM_TRIGGER_SUSPEND:
319 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
320 pr_debug("SNDRV_PCM_TRIGGER_PAUSE\n");
321 q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
322 atomic_set(&prtd->start, 0);
323 break;
324 default:
325 ret = -EINVAL;
326 break;
327 }
328
329 return ret;
330}
331
332static void populate_codec_list(struct compr_audio *compr,
333 struct snd_pcm_runtime *runtime)
334{
335 pr_debug("%s\n", __func__);
336 /* MP3 Block */
337 compr->info.compr_cap.num_codecs = 1;
338 compr->info.compr_cap.min_fragment_size = runtime->hw.period_bytes_min;
339 compr->info.compr_cap.max_fragment_size = runtime->hw.period_bytes_max;
340 compr->info.compr_cap.min_fragments = runtime->hw.periods_min;
341 compr->info.compr_cap.max_fragments = runtime->hw.periods_max;
342 compr->info.compr_cap.codecs[0] = SND_AUDIOCODEC_MP3;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800343 compr->info.compr_cap.codecs[1] = SND_AUDIOCODEC_AAC;
Santosh Mardie27ed782012-03-29 04:20:38 +0530344 compr->info.compr_cap.codecs[2] = SND_AUDIOCODEC_AC3_PASS_THROUGH;
Aviral Gupta66698c12012-04-28 22:09:48 +0530345 compr->info.compr_cap.codecs[3] = SND_AUDIOCODEC_WMA;
Aviral Guptac4ee3b02012-05-09 10:53:45 +0530346 compr->info.compr_cap.codecs[4] = SND_AUDIOCODEC_WMA_PRO;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530347 /* Add new codecs here */
348}
349
350static int msm_compr_open(struct snd_pcm_substream *substream)
351{
352 struct snd_pcm_runtime *runtime = substream->runtime;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530353 struct compr_audio *compr;
354 struct msm_audio *prtd;
355 int ret = 0;
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -0800356 struct asm_softpause_params softpause = {
357 .enable = SOFT_PAUSE_ENABLE,
358 .period = SOFT_PAUSE_PERIOD,
359 .step = SOFT_PAUSE_STEP,
360 .rampingcurve = SOFT_PAUSE_CURVE_LINEAR,
361 };
362 struct asm_softvolume_params softvol = {
363 .period = SOFT_VOLUME_PERIOD,
364 .step = SOFT_VOLUME_STEP,
365 .rampingcurve = SOFT_VOLUME_CURVE_LINEAR,
366 };
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530367
368 /* Capture path */
369 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
370 return -EINVAL;
371
372 pr_debug("%s\n", __func__);
373 compr = kzalloc(sizeof(struct compr_audio), GFP_KERNEL);
374 if (compr == NULL) {
375 pr_err("Failed to allocate memory for msm_audio\n");
376 return -ENOMEM;
377 }
378 prtd = &compr->prtd;
379 prtd->substream = substream;
380 prtd->audio_client = q6asm_audio_client_alloc(
381 (app_cb)compr_event_handler, compr);
382 if (!prtd->audio_client) {
383 pr_info("%s: Could not allocate memory\n", __func__);
384 kfree(prtd);
385 return -ENOMEM;
386 }
387 runtime->hw = msm_compr_hardware_playback;
388
389 pr_info("%s: session ID %d\n", __func__, prtd->audio_client->session);
390
391 prtd->session_id = prtd->audio_client->session;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530392
393 prtd->cmd_ack = 1;
394
395 ret = snd_pcm_hw_constraint_list(runtime, 0,
396 SNDRV_PCM_HW_PARAM_RATE,
397 &constraints_sample_rates);
398 if (ret < 0)
399 pr_info("snd_pcm_hw_constraint_list failed\n");
400 /* Ensure that buffer size is a multiple of period size */
401 ret = snd_pcm_hw_constraint_integer(runtime,
402 SNDRV_PCM_HW_PARAM_PERIODS);
403 if (ret < 0)
404 pr_info("snd_pcm_hw_constraint_integer failed\n");
405
406 prtd->dsp_cnt = 0;
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530407 atomic_set(&prtd->pending_buffer, 1);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530408 compr->codec = FORMAT_MP3;
409 populate_codec_list(compr, runtime);
410 runtime->private_data = compr;
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -0800411 compressed_audio.prtd = &compr->prtd;
412 ret = compressed_set_volume(compressed_audio.volume);
413 if (ret < 0)
414 pr_err("%s : Set Volume failed : %d", __func__, ret);
415
416 ret = q6asm_set_softpause(compressed_audio.prtd->audio_client,
417 &softpause);
418 if (ret < 0)
419 pr_err("%s: Send SoftPause Param failed ret=%d\n",
420 __func__, ret);
421 ret = q6asm_set_softvolume(compressed_audio.prtd->audio_client,
422 &softvol);
423 if (ret < 0)
424 pr_err("%s: Send SoftVolume Param failed ret=%d\n",
425 __func__, ret);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530426
427 return 0;
428}
429
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -0800430int compressed_set_volume(unsigned volume)
431{
432 int rc = 0;
433 if (compressed_audio.prtd && compressed_audio.prtd->audio_client) {
434 rc = q6asm_set_volume(compressed_audio.prtd->audio_client,
435 volume);
436 if (rc < 0) {
437 pr_err("%s: Send Volume command failed"
438 " rc=%d\n", __func__, rc);
439 }
440 }
441 compressed_audio.volume = volume;
442 return rc;
443}
444
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530445static int msm_compr_playback_close(struct snd_pcm_substream *substream)
446{
447 struct snd_pcm_runtime *runtime = substream->runtime;
448 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
449 struct compr_audio *compr = runtime->private_data;
450 struct msm_audio *prtd = &compr->prtd;
451 int dir = 0;
452
453 pr_debug("%s\n", __func__);
454
455 dir = IN;
Asish Bhattacharya31bd80d2012-01-04 02:30:13 +0530456 atomic_set(&prtd->pending_buffer, 0);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530457 q6asm_cmd(prtd->audio_client, CMD_CLOSE);
Krishnankutty Kolathappilly27d7b302012-02-29 21:04:31 -0800458 compressed_audio.prtd = NULL;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530459 q6asm_audio_client_buf_free_contiguous(dir,
460 prtd->audio_client);
Santosh Mardid1760792012-06-12 16:23:19 +0530461 if (!(compr->info.codec_param.codec.id ==
462 SND_AUDIOCODEC_AC3_PASS_THROUGH))
463 msm_pcm_routing_dereg_phy_stream(
464 soc_prtd->dai_link->be_id,
465 SNDRV_PCM_STREAM_PLAYBACK);
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530466 q6asm_audio_client_free(prtd->audio_client);
467 kfree(prtd);
468 return 0;
469}
470
471static int msm_compr_close(struct snd_pcm_substream *substream)
472{
473 int ret = 0;
474
475 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
476 ret = msm_compr_playback_close(substream);
477 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
478 ret = EINVAL;
479 return ret;
480}
481static int msm_compr_prepare(struct snd_pcm_substream *substream)
482{
483 int ret = 0;
484
485 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
486 ret = msm_compr_playback_prepare(substream);
487 else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
488 ret = EINVAL;
489 return ret;
490}
491
492static snd_pcm_uframes_t msm_compr_pointer(struct snd_pcm_substream *substream)
493{
494
495 struct snd_pcm_runtime *runtime = substream->runtime;
496 struct compr_audio *compr = runtime->private_data;
497 struct msm_audio *prtd = &compr->prtd;
498
499 if (prtd->pcm_irq_pos >= prtd->pcm_size)
500 prtd->pcm_irq_pos = 0;
501
502 pr_debug("pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
503 return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
504}
505
506static int msm_compr_mmap(struct snd_pcm_substream *substream,
507 struct vm_area_struct *vma)
508{
509 int result = 0;
510 struct snd_pcm_runtime *runtime = substream->runtime;
511 struct compr_audio *compr = runtime->private_data;
512 struct msm_audio *prtd = &compr->prtd;
513
514 pr_debug("%s\n", __func__);
515 prtd->mmap_flag = 1;
516 if (runtime->dma_addr && runtime->dma_bytes) {
517 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
518 result = remap_pfn_range(vma, vma->vm_start,
519 runtime->dma_addr >> PAGE_SHIFT,
520 runtime->dma_bytes,
521 vma->vm_page_prot);
522 } else {
523 pr_err("Physical address or size of buf is NULL");
524 return -EINVAL;
525 }
526 return result;
527}
528
529static int msm_compr_hw_params(struct snd_pcm_substream *substream,
530 struct snd_pcm_hw_params *params)
531{
532 struct snd_pcm_runtime *runtime = substream->runtime;
Santosh Mardie27ed782012-03-29 04:20:38 +0530533 struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530534 struct compr_audio *compr = runtime->private_data;
535 struct msm_audio *prtd = &compr->prtd;
536 struct snd_dma_buffer *dma_buf = &substream->dma_buffer;
537 struct audio_buffer *buf;
538 int dir, ret;
539
540 pr_debug("%s\n", __func__);
541 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
542 dir = IN;
543 else
544 return -EINVAL;
545
Santosh Mardie27ed782012-03-29 04:20:38 +0530546 switch (compr->info.codec_param.codec.id) {
547 case SND_AUDIOCODEC_AC3_PASS_THROUGH:
548 ret = q6asm_open_write_compressed(prtd->audio_client,
549 compr->codec);
550 if (ret < 0) {
551 pr_err("%s: compressed Session out open failed\n",
552 __func__);
553 return -ENOMEM;
554 }
555 break;
556 default:
557 ret = q6asm_open_write(prtd->audio_client, compr->codec);
558 if (ret < 0) {
559 pr_err("%s: Session out open failed\n", __func__);
560 return -ENOMEM;
561 }
562 msm_pcm_routing_reg_phy_stream(soc_prtd->dai_link->be_id,
563 prtd->session_id, substream->stream);
564
565 break;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530566 }
567 ret = q6asm_set_io_mode(prtd->audio_client, ASYNC_IO_MODE);
568 if (ret < 0) {
569 pr_err("%s: Set IO mode failed\n", __func__);
570 return -ENOMEM;
571 }
572
573 ret = q6asm_audio_client_buf_alloc_contiguous(dir,
574 prtd->audio_client,
575 runtime->hw.period_bytes_min,
576 runtime->hw.periods_max);
577 if (ret < 0) {
578 pr_err("Audio Start: Buffer Allocation failed "
579 "rc = %d\n", ret);
580 return -ENOMEM;
581 }
582 buf = prtd->audio_client->port[dir].buf;
583
584 pr_debug("%s:buf = %p\n", __func__, buf);
585 dma_buf->dev.type = SNDRV_DMA_TYPE_DEV;
586 dma_buf->dev.dev = substream->pcm->card->dev;
587 dma_buf->private_data = NULL;
588 dma_buf->area = buf[0].data;
589 dma_buf->addr = buf[0].phys;
590 dma_buf->bytes = runtime->hw.buffer_bytes_max;
591 if (!dma_buf->area)
592 return -ENOMEM;
593
594 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
595 return 0;
596}
597
598static int msm_compr_ioctl(struct snd_pcm_substream *substream,
599 unsigned int cmd, void *arg)
600{
601 int rc = 0;
602 struct snd_pcm_runtime *runtime = substream->runtime;
603 struct compr_audio *compr = runtime->private_data;
604 struct msm_audio *prtd = &compr->prtd;
Asish Bhattacharya8664b252011-12-30 05:43:23 +0530605 uint64_t timestamp;
606 uint64_t temp;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530607
608 switch (cmd) {
Asish Bhattacharya8664b252011-12-30 05:43:23 +0530609 case SNDRV_COMPRESS_TSTAMP: {
610 struct snd_compr_tstamp tstamp;
611 pr_debug("SNDRV_COMPRESS_TSTAMP\n");
612
613 memset(&tstamp, 0x0, sizeof(struct snd_compr_tstamp));
614 timestamp = q6asm_get_session_time(prtd->audio_client);
615 if (timestamp < 0) {
616 pr_err("%s: Get Session Time return value =%lld\n",
617 __func__, timestamp);
618 return -EAGAIN;
619 }
620 temp = (timestamp * 2 * runtime->channels);
621 temp = temp * (runtime->rate/1000);
622 temp = div_u64(temp, 1000);
623 tstamp.sampling_rate = runtime->rate;
Asish Bhattacharya8664b252011-12-30 05:43:23 +0530624 tstamp.timestamp = timestamp;
Steve Mucklef132c6c2012-06-06 18:30:57 -0700625 pr_debug("%s: bytes_consumed:,"
626 "timestamp = %lld,\n", __func__,
Asish Bhattacharya8664b252011-12-30 05:43:23 +0530627 tstamp.timestamp);
628 if (copy_to_user((void *) arg, &tstamp,
629 sizeof(struct snd_compr_tstamp)))
630 return -EFAULT;
631 return 0;
632 }
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530633 case SNDRV_COMPRESS_GET_CAPS:
634 pr_debug("SNDRV_COMPRESS_GET_CAPS\n");
635 if (copy_to_user((void *) arg, &compr->info.compr_cap,
636 sizeof(struct snd_compr_caps))) {
637 rc = -EFAULT;
638 pr_err("%s: ERROR: copy to user\n", __func__);
639 return rc;
640 }
641 return 0;
642 case SNDRV_COMPRESS_SET_PARAMS:
643 pr_debug("SNDRV_COMPRESS_SET_PARAMS: ");
644 if (copy_from_user(&compr->info.codec_param, (void *) arg,
645 sizeof(struct snd_compr_params))) {
646 rc = -EFAULT;
647 pr_err("%s: ERROR: copy from user\n", __func__);
648 return rc;
649 }
650 switch (compr->info.codec_param.codec.id) {
651 case SND_AUDIOCODEC_MP3:
652 /* For MP3 we dont need any other parameter */
653 pr_debug("SND_AUDIOCODEC_MP3\n");
654 compr->codec = FORMAT_MP3;
655 break;
Krishnankutty Kolathappilly46dded22012-01-12 12:03:34 -0800656 case SND_AUDIOCODEC_AAC:
657 pr_debug("SND_AUDIOCODEC_AAC\n");
658 compr->codec = FORMAT_MPEG4_AAC;
659 break;
Santosh Mardie27ed782012-03-29 04:20:38 +0530660 case SND_AUDIOCODEC_AC3_PASS_THROUGH:
661 pr_debug("SND_AUDIOCODEC_AC3_PASS_THROUGH\n");
662 compr->codec = FORMAT_AC3;
663 break;
Aviral Gupta66698c12012-04-28 22:09:48 +0530664 case SND_AUDIOCODEC_WMA:
665 pr_debug("SND_AUDIOCODEC_WMA\n");
666 compr->codec = FORMAT_WMA_V9;
667 break;
Aviral Guptac4ee3b02012-05-09 10:53:45 +0530668 case SND_AUDIOCODEC_WMA_PRO:
669 pr_debug("SND_AUDIOCODEC_WMA_PRO\n");
670 compr->codec = FORMAT_WMA_V10PRO;
671 break;
Asish Bhattacharya305d1752011-11-01 20:38:26 +0530672 default:
673 pr_debug("FORMAT_LINEAR_PCM\n");
674 compr->codec = FORMAT_LINEAR_PCM;
675 break;
676 }
677 return 0;
678 case SNDRV_PCM_IOCTL1_RESET:
679 prtd->cmd_ack = 0;
680 rc = q6asm_cmd(prtd->audio_client, CMD_FLUSH);
681 if (rc < 0)
682 pr_err("%s: flush cmd failed rc=%d\n", __func__, rc);
683 rc = wait_event_timeout(the_locks.eos_wait,
684 prtd->cmd_ack, 5 * HZ);
685 if (rc < 0)
686 pr_err("Flush cmd timeout\n");
687 prtd->pcm_irq_pos = 0;
688 break;
689 default:
690 break;
691 }
692 return snd_pcm_lib_ioctl(substream, cmd, arg);
693}
694
695static struct snd_pcm_ops msm_compr_ops = {
696 .open = msm_compr_open,
697 .hw_params = msm_compr_hw_params,
698 .close = msm_compr_close,
699 .ioctl = msm_compr_ioctl,
700 .prepare = msm_compr_prepare,
701 .trigger = msm_compr_trigger,
702 .pointer = msm_compr_pointer,
703 .mmap = msm_compr_mmap,
704};
705
706static int msm_asoc_pcm_new(struct snd_soc_pcm_runtime *rtd)
707{
708 struct snd_card *card = rtd->card->snd_card;
709 int ret = 0;
710
711 if (!card->dev->coherent_dma_mask)
712 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
713 return ret;
714}
715
716static struct snd_soc_platform_driver msm_soc_platform = {
717 .ops = &msm_compr_ops,
718 .pcm_new = msm_asoc_pcm_new,
719};
720
721static __devinit int msm_compr_probe(struct platform_device *pdev)
722{
723 pr_info("%s: dev name %s\n", __func__, dev_name(&pdev->dev));
724 return snd_soc_register_platform(&pdev->dev,
725 &msm_soc_platform);
726}
727
728static int msm_compr_remove(struct platform_device *pdev)
729{
730 snd_soc_unregister_platform(&pdev->dev);
731 return 0;
732}
733
734static struct platform_driver msm_compr_driver = {
735 .driver = {
736 .name = "msm-compr-dsp",
737 .owner = THIS_MODULE,
738 },
739 .probe = msm_compr_probe,
740 .remove = __devexit_p(msm_compr_remove),
741};
742
743static int __init msm_soc_platform_init(void)
744{
745 init_waitqueue_head(&the_locks.enable_wait);
746 init_waitqueue_head(&the_locks.eos_wait);
747 init_waitqueue_head(&the_locks.write_wait);
748 init_waitqueue_head(&the_locks.read_wait);
749
750 return platform_driver_register(&msm_compr_driver);
751}
752module_init(msm_soc_platform_init);
753
754static void __exit msm_soc_platform_exit(void)
755{
756 platform_driver_unregister(&msm_compr_driver);
757}
758module_exit(msm_soc_platform_exit);
759
760MODULE_DESCRIPTION("PCM module platform driver");
761MODULE_LICENSE("GPL v2");