power: first sketch at delivering wakeup reason to userland via /proc interface
[htc-msm-2-6-32:leviathan-incoming.git] / sound / soc / msm / qsd8k-pcm.c
1 /* linux/sound/soc/msm/qsd8k-pcm.c
2  *
3  * Copyright (c) 2009, Code Aurora Forum. All rights reserved.
4  *
5  * All source code in this file is licensed under the following license except
6  * where indicated.
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License version 2 as published
10  * by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15  *
16  * See the GNU General Public License for more details.
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you can find it at http://www.fsf.org.
19  */
20
21 #include <linux/init.h>
22 #include <linux/err.h>
23 #include <linux/module.h>
24 #include <linux/moduleparam.h>
25 #include <linux/time.h>
26 #include <linux/wait.h>
27 #include <linux/platform_device.h>
28 #include <linux/interrupt.h>
29 #include <sound/core.h>
30 #include <sound/soc.h>
31 #include <sound/soc-dapm.h>
32 #include <sound/pcm.h>
33 #include <sound/pcm_params.h>
34 #include <sound/initval.h>
35 #include <sound/control.h>
36 #include <asm/dma.h>
37 #include <linux/dma-mapping.h>
38
39 #include "qsd-pcm.h"
40 static void snd_qsd_timer(unsigned long data);
41
42 static void snd_qsd_timer(unsigned long data)
43 {
44         struct qsd_audio *prtd = (struct qsd_audio *)data;
45
46         pr_debug("prtd->buffer_cnt = %d\n", prtd->buffer_cnt);
47         pr_debug("prtd->intcnt = %d\n", prtd->intcnt);
48         if (!prtd->enabled)
49                 return;
50         prtd->timerintcnt++;
51         if (prtd->start) {
52                 if (prtd->intcnt) {
53                         prtd->pcm_irq_pos += prtd->pcm_count;
54                         prtd->intcnt--;
55                 }
56                 snd_pcm_period_elapsed(prtd->substream);
57         }
58         if (prtd->enabled) {
59                 prtd->timer.expires +=  prtd->expiry_delta;
60                 add_timer(&prtd->timer);
61         }
62 }
63
64 static int rc = 1;
65
66 struct snd_qsd {
67         struct snd_card *card;
68         struct snd_pcm *pcm;
69 };
70
71 struct qsd_ctl qsd_glb_ctl;
72 EXPORT_SYMBOL(qsd_glb_ctl);
73 struct audio_locks the_locks;
74 EXPORT_SYMBOL(the_locks);
75
76 static unsigned convert_dsp_samp_index(unsigned index)
77 {
78         switch (index) {
79         case 48000:
80                 return 3;
81         case 44100:
82                 return 4;
83         case 32000:
84                 return 5;
85         case 24000:
86                 return 6;
87         case 22050:
88                 return 7;
89         case 16000:
90                 return 8;
91         case 12000:
92                 return 9;
93         case 11025:
94                 return 10;
95         case 8000:
96                 return 11;
97         default:
98                 return 3;
99         }
100 }
101
102 static struct snd_pcm_hardware qsd_pcm_playback_hardware = {
103         .info = SNDRV_PCM_INFO_INTERLEAVED,
104         .formats = USE_FORMATS,
105         .rates = USE_RATE,
106         .rate_min = USE_RATE_MIN,
107         .rate_max = USE_RATE_MAX,
108         .channels_min = USE_CHANNELS_MIN,
109         .channels_max = USE_CHANNELS_MAX,
110         .buffer_bytes_max = MAX_BUFFER_SIZE,
111         .period_bytes_min = MIN_PERIOD_SIZE,
112         .period_bytes_max = MAX_PERIOD_SIZE,
113         .periods_min = USE_PERIODS_MIN,
114         .periods_max = USE_PERIODS_MAX,
115         .fifo_size = 0,
116 };
117
118 static struct snd_pcm_hardware qsd_pcm_capture_hardware = {
119         .info = SNDRV_PCM_INFO_INTERLEAVED,
120         .formats = USE_FORMATS,
121         .rates = USE_RATE,
122         .rate_min = USE_RATE_MIN,
123         .rate_max = USE_RATE_MAX,
124         .channels_min = USE_CHANNELS_MIN,
125         .channels_max = USE_CHANNELS_MAX,
126         .buffer_bytes_max = MAX_BUFFER_SIZE,
127         .period_bytes_min = MIN_PERIOD_SIZE,
128         .period_bytes_max = MAX_PERIOD_SIZE,
129         .periods_min = USE_PERIODS_MIN,
130         .periods_max = USE_PERIODS_MAX,
131         .fifo_size = 0,
132 };
133
134 int qsd_audio_volume_update(struct qsd_audio *prtd)
135 {
136
137         int rc = 0;
138         struct cad_flt_cfg_strm_vol cad_strm_volume;
139         struct cad_filter_struct flt;
140
141         pr_debug("qsd_audio_volume_update: updating volume");
142         memset(&cad_strm_volume, 0, sizeof(struct cad_flt_cfg_strm_vol));
143         memset(&flt, 0, sizeof(struct cad_filter_struct));
144
145         cad_strm_volume.volume = qsd_glb_ctl.strm_volume;
146         flt.filter_type = CAD_DEVICE_FILTER_TYPE_VOL;
147         flt.format_block = &cad_strm_volume;
148         flt.cmd = CAD_FILTER_CONFIG_STREAM_VOLUME;
149         flt.format_block_len = sizeof(struct cad_flt_cfg_strm_vol);
150
151         rc = cad_ioctl(prtd->cad_w_handle,
152                 CAD_IOCTL_CMD_SET_STREAM_FILTER_CONFIG,
153                 &flt,
154                 sizeof(struct cad_filter_struct));
155         if (rc)
156                 pr_debug("cad_ioctl() set volume failed\n");
157         return rc;
158 }
159
160 static int qsd_pcm_playback_prepare(struct snd_pcm_substream *substream)
161 {
162         struct snd_pcm_runtime *runtime = substream->runtime;
163         struct qsd_audio *prtd = runtime->private_data;
164
165         struct cad_stream_device_struct_type cad_stream_dev;
166         struct cad_stream_info_struct_type cad_stream_info;
167         struct cad_write_pcm_format_struct_type cad_write_pcm_fmt;
168         u32 stream_device[1];
169         unsigned long expiry = 0;
170         pr_debug("qsd_pcm_playback_prepare\n");
171         prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
172         prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
173         prtd->pcm_irq_pos = 0;
174         prtd->pcm_buf_pos = 0;
175         atomic_set(&prtd->copy_count, 0);
176         if (prtd->enabled)
177                 return 0;
178         prtd->start = 0;
179         prtd->intcnt = 0;
180
181         cad_stream_info.app_type = CAD_STREAM_APP_PLAYBACK;
182         cad_stream_info.priority = 0;
183         cad_stream_info.buf_mem_type = CAD_STREAM_BUF_MEM_HEAP;
184         cad_stream_info.ses_buf_max_size = prtd->pcm_count;
185
186         rc = cad_ioctl(prtd->cad_w_handle, CAD_IOCTL_CMD_SET_STREAM_INFO,
187                        &cad_stream_info,
188                        sizeof(struct cad_stream_info_struct_type));
189         if (rc)
190                 pr_debug("cad ioctl failed\n");
191
192         cad_write_pcm_fmt.us_ver_id = CAD_WRITE_PCM_VERSION_10;
193         cad_write_pcm_fmt.pcm.us_sample_rate =
194             convert_dsp_samp_index(runtime->rate);
195         cad_write_pcm_fmt.pcm.us_channel_config = runtime->channels;
196         cad_write_pcm_fmt.pcm.us_width = 1;
197         cad_write_pcm_fmt.pcm.us_sign = 0;
198
199         rc = cad_ioctl(prtd->cad_w_handle, CAD_IOCTL_CMD_SET_STREAM_CONFIG,
200                        &cad_write_pcm_fmt,
201                        sizeof(struct cad_write_pcm_format_struct_type));
202         if (rc)
203                 pr_debug("cad ioctl failed\n");
204
205         stream_device[0] = CAD_HW_DEVICE_ID_DEFAULT_RX ;
206         cad_stream_dev.device = (u32 *) &stream_device[0];
207         cad_stream_dev.device_len = 1;
208
209         rc = cad_ioctl(prtd->cad_w_handle, CAD_IOCTL_CMD_SET_STREAM_DEVICE,
210                        &cad_stream_dev,
211                        sizeof(struct cad_stream_device_struct_type));
212         if (rc)
213                 pr_debug("cad ioctl  failed\n");
214
215         rc = cad_ioctl(prtd->cad_w_handle, CAD_IOCTL_CMD_STREAM_START,
216                 NULL, 0);
217         if (rc)
218                 pr_debug("cad ioctl failed\n");
219         else {
220                 prtd->enabled = 1;
221                 expiry = ((unsigned long)((prtd->pcm_count * 1000)
222                         /(runtime->rate * runtime->channels * 2)));
223                 expiry -= (expiry % 10) ;
224                 prtd->timer.expires = jiffies + (msecs_to_jiffies(expiry));
225                 prtd->expiry_delta = (msecs_to_jiffies(expiry));
226                 if (!prtd->expiry_delta)
227                         prtd->expiry_delta = 1;
228                 setup_timer(&prtd->timer, snd_qsd_timer, (unsigned long)prtd);
229                 add_timer(&prtd->timer);
230         }
231         return rc;
232 }
233
234 static int qsd_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
235 {
236         int ret = 0;
237         struct snd_pcm_runtime *runtime = substream->runtime;
238
239         struct qsd_audio *prtd = runtime->private_data;
240         switch (cmd) {
241         case SNDRV_PCM_TRIGGER_START:
242                 pr_info("TRIGGER_START\n");
243                 prtd->start = 1;
244                 break;
245         case SNDRV_PCM_TRIGGER_RESUME:
246         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
247                 break;
248         case SNDRV_PCM_TRIGGER_STOP:
249                 prtd->start = 0;
250                 pr_info("TRIGGER_STOP\n");
251                 break;
252         case SNDRV_PCM_TRIGGER_SUSPEND:
253         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
254                 break;
255         default:
256                 ret = -EINVAL;
257         }
258
259         return ret;
260 }
261
262 static snd_pcm_uframes_t
263 qsd_pcm_playback_pointer(struct snd_pcm_substream *substream)
264 {
265         struct snd_pcm_runtime *runtime = substream->runtime;
266         struct qsd_audio *prtd = runtime->private_data;
267         snd_pcm_uframes_t pcm_frame;
268         pr_debug("qsd_pcm_playback_pointer %d %d %d \n",
269                         prtd->pcm_irq_pos, prtd->pcm_size, prtd->intcnt);
270
271         if (prtd->pcm_irq_pos >= prtd->pcm_size)
272                 prtd->pcm_irq_pos = 0;
273         pcm_frame =  bytes_to_frames(runtime, (prtd->pcm_irq_pos));
274         pr_debug("qsd_pcm_playback_pointer %d\n", (int)pcm_frame);
275
276         return pcm_frame;
277 }
278
279 void alsa_event_cb_playback(u32 event, void *evt_packet,
280                         u32 evt_packet_len, void *client_data)
281 {
282         struct qsd_audio *prtd = client_data;
283         pr_debug("alsa_event_cb_playback \n");
284         if (event == CAD_EVT_STATUS_EOS) {
285
286                 prtd->eos_ack = 1;
287                 pr_info("EOS Received\n");
288                 wake_up(&the_locks.eos_wait);
289                 return ;
290         }
291         prtd->intcnt++;
292         return ;
293 }
294
295 void alsa_event_cb_capture(u32 event, void *evt_packet,
296                         u32 evt_packet_len, void *client_data)
297 {
298         struct qsd_audio *prtd = client_data;
299         prtd->intcnt++;
300         pr_debug("alsa_event_cb_capture pcm_irq_pos = %d\n", prtd->pcm_irq_pos);
301 }
302
303 static int hw_rule_periodsize_by_rate(struct snd_pcm_hw_params *params,
304                                         struct snd_pcm_hw_rule *rule)
305 {
306         struct snd_interval *ps = hw_param_interval(params,
307                                                 SNDRV_PCM_HW_PARAM_PERIOD_SIZE);
308         struct snd_interval *r = hw_param_interval(params,
309                                                 SNDRV_PCM_HW_PARAM_RATE);
310         struct snd_interval ch;
311
312         if (!ps || !r)
313                 return 0;
314
315         snd_interval_any(&ch);
316
317         if (r->min > 8000) {
318                 ch.min = 512;
319                 pr_debug("Minimum period size is adjusted to 512\n");
320                 return snd_interval_refine(ps, &ch);
321         }
322         return 0;
323 }
324
325 static int qsd_pcm_open(struct snd_pcm_substream *substream)
326 {
327         struct snd_pcm_runtime *runtime = substream->runtime;
328         struct qsd_audio *prtd;
329         struct cad_event_struct_type alsa_event;
330         int ret = 0;
331
332         prtd = kzalloc(sizeof(struct qsd_audio), GFP_KERNEL);
333         if (prtd == NULL) {
334                 ret = -ENOMEM;
335                 return ret;
336         }
337         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
338                 pr_debug("Stream = SNDRV_PCM_STREAM_PLAYBACK\n");
339                 runtime->hw = qsd_pcm_playback_hardware;
340                 prtd->dir = SNDRV_PCM_STREAM_PLAYBACK;
341                 prtd->cos.op_code = CAD_OPEN_OP_WRITE;
342         } else {
343                 pr_debug("Stream = SNDRV_PCM_STREAM_CAPTURE\n");
344                 runtime->hw = qsd_pcm_capture_hardware;
345                 prtd->dir = SNDRV_PCM_STREAM_CAPTURE;
346                 prtd->cos.op_code = CAD_OPEN_OP_READ;
347         }
348         prtd->substream = substream;
349
350         /* Ensure that buffer size is a multiple of period size */
351         ret = snd_pcm_hw_constraint_integer(runtime,
352                                             SNDRV_PCM_HW_PARAM_PERIODS);
353         if (ret < 0) {
354                 kfree(prtd);
355                 return ret;
356         }
357
358         ret = snd_pcm_hw_rule_add(substream->runtime, 0,
359                         SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
360                         hw_rule_periodsize_by_rate, substream,
361                         SNDRV_PCM_HW_PARAM_RATE, -1);
362
363         if (ret < 0) {
364                 kfree(prtd);
365                 return ret;
366         }
367
368         runtime->private_data = prtd;
369
370         prtd->cos.format = CAD_FORMAT_PCM;
371
372         prtd->cad_w_handle = cad_open(&prtd->cos);
373
374         if  (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
375                 alsa_event.callback = &alsa_event_cb_capture;
376         else
377                 alsa_event.callback = &alsa_event_cb_playback;
378
379         alsa_event.client_data = prtd;
380
381         ret = cad_ioctl(prtd->cad_w_handle,
382                 CAD_IOCTL_CMD_SET_STREAM_EVENT_LSTR,
383                 &alsa_event, sizeof(struct cad_event_struct_type));
384         if (ret) {
385                 cad_close(prtd->cad_w_handle);
386                 kfree(prtd);
387                 return ret;
388         }
389
390         prtd->enabled = 0;
391
392         return 0;
393 }
394
395 static int qsd_pcm_playback_copy(struct snd_pcm_substream *substream, int a,
396                                  snd_pcm_uframes_t hwoff, void __user *buf,
397                                  snd_pcm_uframes_t frames)
398 {
399         int fbytes = 0;
400         size_t xfer;
401         int rc;
402
403         struct snd_pcm_runtime *runtime = substream->runtime;
404         struct qsd_audio *prtd = runtime->private_data;
405
406         pr_debug("qsd_pcm_playback_copy\n");
407         fbytes = frames_to_bytes(runtime, frames);
408         prtd->cbs.buffer = (void *)buf;
409         prtd->cbs.phys_addr = 0;
410         prtd->cbs.max_size = fbytes;
411         prtd->cbs.actual_size = fbytes;
412
413         prtd->pcm_buf_pos += fbytes;
414         xfer = cad_write(prtd->cad_w_handle, &prtd->cbs);
415
416         if (xfer < 0)
417                 return xfer;
418
419         prtd->buffer_cnt++;
420
421         if (qsd_glb_ctl.update) {
422                 rc = qsd_audio_volume_update(prtd);
423                 qsd_glb_ctl.update = 0;
424         }
425
426         return 0;
427 }
428
429 static int qsd_pcm_playback_close(struct snd_pcm_substream *substream)
430 {
431         struct snd_pcm_runtime *runtime = substream->runtime;
432         struct qsd_audio *prtd = runtime->private_data;
433         int ret = 0;
434
435         if (prtd->enabled) {
436                 cad_ioctl(prtd->cad_w_handle,
437                         CAD_IOCTL_CMD_STREAM_END_OF_STREAM,
438                         NULL, 0);
439
440                 ret = wait_event_interruptible(the_locks.eos_wait,
441                                         prtd->eos_ack);
442
443                 if (!prtd->eos_ack)
444                         pr_err("EOS Failed\n");
445
446         }
447
448         prtd->enabled = 0;
449         del_timer_sync(&prtd->timer);
450         prtd->eos_ack = 0;
451         cad_close(prtd->cad_w_handle);
452
453         /*
454          * TODO: Deregister the async callback handler.
455          * Currently cad provides no interface to do so.
456          */
457         kfree(prtd);
458
459         return ret;
460 }
461
462 static int qsd_pcm_capture_copy(struct snd_pcm_substream *substream, int a,
463                                  snd_pcm_uframes_t hwoff, void __user *buf,
464                                  snd_pcm_uframes_t frames)
465 {
466         int fbytes = 0;
467         size_t xfer;
468         int rc = 0;
469
470         struct snd_pcm_runtime *runtime = substream->runtime;
471         struct qsd_audio *prtd = runtime->private_data;
472
473         fbytes = frames_to_bytes(runtime, frames);
474         fbytes = fbytes;
475
476         prtd->cbs.buffer = (void *)buf;
477         prtd->cbs.phys_addr = 0;
478         prtd->cbs.max_size = fbytes;
479         prtd->cbs.actual_size = fbytes;
480
481         xfer = cad_read(prtd->cad_w_handle, &prtd->cbs);
482
483         prtd->pcm_buf_pos += fbytes;
484         if (xfer < fbytes)
485                 return -EIO;
486
487         return rc;
488 }
489
490 static snd_pcm_uframes_t
491 qsd_pcm_capture_pointer(struct snd_pcm_substream *substream)
492 {
493         struct snd_pcm_runtime *runtime = substream->runtime;
494         struct qsd_audio *prtd = runtime->private_data;
495
496         return bytes_to_frames(runtime, (prtd->pcm_irq_pos));
497 }
498
499 static int qsd_pcm_capture_close(struct snd_pcm_substream *substream)
500 {
501         struct snd_pcm_runtime *runtime = substream->runtime;
502         struct qsd_audio *prtd = runtime->private_data;
503
504         prtd->enabled = 0;
505         del_timer_sync(&prtd->timer);
506         cad_close(prtd->cad_w_handle);
507
508         /*
509          * TODO: Deregister the async callback handler.
510          * Currently cad provides no interface to do so.
511          */
512         kfree(prtd);
513
514         return 0;
515 }
516
517 static int qsd_pcm_capture_prepare(struct snd_pcm_substream *substream)
518 {
519         struct snd_pcm_runtime *runtime = substream->runtime;
520         struct qsd_audio *prtd = runtime->private_data;
521         int rc = 0;
522
523         struct cad_stream_device_struct_type cad_stream_dev;
524         struct cad_stream_info_struct_type cad_stream_info;
525         struct cad_write_pcm_format_struct_type cad_write_pcm_fmt;
526         u32 stream_device[1];
527         unsigned long expiry = 0;
528
529         prtd->pcm_size = snd_pcm_lib_buffer_bytes(substream);
530         prtd->pcm_count = snd_pcm_lib_period_bytes(substream);
531         prtd->pcm_irq_pos = 0;
532         prtd->pcm_buf_pos = 0;
533
534         cad_stream_info.app_type = CAD_STREAM_APP_RECORD;
535         cad_stream_info.priority = 0;
536         cad_stream_info.buf_mem_type = CAD_STREAM_BUF_MEM_HEAP;
537         cad_stream_info.ses_buf_max_size = prtd->pcm_count;
538
539         if (prtd->enabled)
540                 return 0;
541
542         rc = cad_ioctl(prtd->cad_w_handle, CAD_IOCTL_CMD_SET_STREAM_INFO,
543                 &cad_stream_info,
544                 sizeof(struct cad_stream_info_struct_type));
545         if (rc)
546                 return rc;
547
548         cad_write_pcm_fmt.us_ver_id = CAD_WRITE_PCM_VERSION_10;
549         cad_write_pcm_fmt.pcm.us_sample_rate =
550             convert_dsp_samp_index(runtime->rate);
551         cad_write_pcm_fmt.pcm.us_channel_config = runtime->channels;
552         cad_write_pcm_fmt.pcm.us_width = 1;
553         cad_write_pcm_fmt.pcm.us_sign = 0;
554
555         rc = cad_ioctl(prtd->cad_w_handle, CAD_IOCTL_CMD_SET_STREAM_CONFIG,
556                &cad_write_pcm_fmt,
557                sizeof(struct cad_write_pcm_format_struct_type));
558         if (rc)
559                 return rc;
560
561         stream_device[0] = CAD_HW_DEVICE_ID_DEFAULT_TX ;
562         cad_stream_dev.device = (u32 *) &stream_device[0];
563         cad_stream_dev.device_len = 1;
564
565         rc = cad_ioctl(prtd->cad_w_handle, CAD_IOCTL_CMD_SET_STREAM_DEVICE,
566                &cad_stream_dev,
567                sizeof(struct cad_stream_device_struct_type));
568         if (rc)
569                 return rc;
570
571         rc = cad_ioctl(prtd->cad_w_handle, CAD_IOCTL_CMD_STREAM_START,
572                         NULL, 0);
573         if (!rc) {
574                 prtd->enabled = 1;
575                 expiry = ((unsigned long)((prtd->pcm_count * 1000)
576                         /(runtime->rate * runtime->channels * 2)));
577                 expiry -= (expiry % 10) ;
578                 prtd->timer.expires = jiffies + (msecs_to_jiffies(expiry));
579                 prtd->expiry_delta = (msecs_to_jiffies(expiry));
580                 if (!prtd->expiry_delta)
581                         prtd->expiry_delta = 1;
582                 setup_timer(&prtd->timer, snd_qsd_timer, (unsigned long)prtd);
583                 add_timer(&prtd->timer);
584         }
585         return rc;
586 }
587
588
589 static int qsd_pcm_copy(struct snd_pcm_substream *substream, int a,
590                         snd_pcm_uframes_t hwoff, void __user *buf,
591                         snd_pcm_uframes_t frames)
592 {
593         int ret = 0;
594
595         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
596                 ret = qsd_pcm_playback_copy(substream, a, hwoff, buf, frames);
597         else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
598                 ret = qsd_pcm_capture_copy(substream, a, hwoff, buf, frames);
599         return ret;
600 }
601
602 static int qsd_pcm_close(struct snd_pcm_substream *substream)
603 {
604         int ret = 0;
605
606         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
607                 ret = qsd_pcm_playback_close(substream);
608         else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
609                 ret = qsd_pcm_capture_close(substream);
610         return ret;
611 }
612 static int qsd_pcm_prepare(struct snd_pcm_substream *substream)
613 {
614         int ret = 0;
615         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
616                 ret = qsd_pcm_playback_prepare(substream);
617         else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
618                 ret = qsd_pcm_capture_prepare(substream);
619         return ret;
620 }
621
622 static snd_pcm_uframes_t qsd_pcm_pointer(struct snd_pcm_substream *substream)
623 {
624         snd_pcm_uframes_t ret = 0;
625
626         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
627                 ret = qsd_pcm_playback_pointer(substream);
628         else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
629                 ret = qsd_pcm_capture_pointer(substream);
630         return ret;
631 }
632
633 int qsd_pcm_hw_params(struct snd_pcm_substream *substream,
634                       struct snd_pcm_hw_params *params)
635 {
636         struct snd_pcm_runtime *runtime = substream->runtime;
637
638         if (substream->pcm->device & 1) {
639                 runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
640                 runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
641         }
642         return 0;
643 }
644
645 struct snd_pcm_ops qsd_pcm_ops = {
646         .open = qsd_pcm_open,
647         .copy = qsd_pcm_copy,
648         .hw_params = qsd_pcm_hw_params,
649         .close = qsd_pcm_close,
650         .ioctl = snd_pcm_lib_ioctl,
651         .prepare = qsd_pcm_prepare,
652         .trigger = qsd_pcm_trigger,
653         .pointer = qsd_pcm_pointer,
654 };
655 EXPORT_SYMBOL_GPL(qsd_pcm_ops);
656
657 static int qsd_pcm_remove(struct platform_device *devptr)
658 {
659         struct snd_soc_device *socdev = platform_get_drvdata(devptr);
660         snd_soc_free_pcms(socdev);
661         kfree(socdev->codec);
662         platform_set_drvdata(devptr, NULL);
663         return 0;
664 }
665
666 static int qsd_pcm_new(struct snd_card *card,
667                         struct snd_soc_dai *codec_dai,
668                         struct snd_pcm *pcm)
669 {
670         int ret;
671         if (!card->dev->coherent_dma_mask)
672                 card->dev->coherent_dma_mask = DMA_32BIT_MASK;
673
674         ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
675                                 PLAYBACK_STREAMS);
676         if (ret)
677                 return ret;
678         ret = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE,
679                                 CAPTURE_STREAMS);
680         if (ret)
681                 return ret;
682         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &qsd_pcm_ops);
683         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &qsd_pcm_ops);
684
685         return ret;
686 }
687
688 struct snd_soc_platform qsd_soc_platform = {
689         .name           = "qsd-audio",
690         .remove         = qsd_pcm_remove,
691         .pcm_ops        = &qsd_pcm_ops,
692         .pcm_new        = qsd_pcm_new,
693 };
694 EXPORT_SYMBOL(qsd_soc_platform);
695
696 static int __init qsd_soc_platform_init(void)
697 {
698         return snd_soc_register_platform(&qsd_soc_platform);
699 }
700 module_init(qsd_soc_platform_init);
701
702 static void __exit qsd_soc_platform_exit(void)
703 {
704         snd_soc_unregister_platform(&qsd_soc_platform);
705 }
706 module_exit(qsd_soc_platform_exit);
707
708 MODULE_DESCRIPTION("PCM module platform driver");
709 MODULE_LICENSE("GPL v2");