upload tizen1.0 source
[kernel/linux-2.6.36.git] / sound / soc / s3c24xx / s3c-dma-wrapper.c
1 /*
2  * s3c-dma-wrapper.c  --  S3C DMA Platform Wrapper Driver
3  *
4  * Copyright (c) 2010 Samsung Electronics Co. Ltd
5  *      Jaswinder Singh <jassi.brar@samsung.com>
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  */
12
13 #include <sound/soc.h>
14 #include "s3c-dma.h"
15 #include "s3c-idma.h"
16 #include "s3c64xx-i2s.h"
17
18 static struct snd_soc_platform *s3c_wrpdma_get_platform(
19                                 struct snd_pcm_substream *substream)
20 {
21         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
22 #ifdef CONFIG_SND_S5P_RP
23                 /* GDMA for Legacy Audio, IDMA for SRP Audio(dedicated codec) */
24                 return &s3c24xx_soc_platform;
25 #elif defined CONFIG_S5P_INTERNAL_DMA
26                 struct snd_soc_pcm_runtime *rtd = substream->private_data;
27                 if (!rtd) {
28                         printk(KERN_ERR "%s, no pcm runtime data\n", __func__);
29                         return &s3c24xx_soc_platform;
30                 }
31                 /* Use IDMA for Generic Audio and GDMA for External Audio */
32                 if (strcmp(rtd->dai->stream_name, MC1N2_HIFI_STREAM_NAME) != 0)
33                         return &s3c24xx_soc_platform;
34                 else
35                         return &idma_soc_platform;
36 #else
37                 /* GDMA for Generic Audio */
38                 return &s3c24xx_soc_platform;
39 #endif
40         } else {
41                 /* Capture is possible via GDMA only */
42                 return &s3c24xx_soc_platform;
43         }
44 }
45
46 static int s3c_wrpdma_hw_params(struct snd_pcm_substream *substream,
47                 struct snd_pcm_hw_params *params)
48 {
49         struct snd_soc_platform *platform = s3c_wrpdma_get_platform(substream);
50
51         if (platform->pcm_ops->hw_params)
52                 return platform->pcm_ops->hw_params(substream, params);
53         else
54                 return 0;
55 }
56
57 static int s3c_wrpdma_hw_free(struct snd_pcm_substream *substream)
58 {
59         struct snd_soc_platform *platform = s3c_wrpdma_get_platform(substream);
60
61         if (platform->pcm_ops->hw_free)
62                 return platform->pcm_ops->hw_free(substream);
63         else
64                 return 0;
65 }
66
67 static int s3c_wrpdma_prepare(struct snd_pcm_substream *substream)
68 {
69         struct snd_soc_platform *platform = s3c_wrpdma_get_platform(substream);
70
71         if (platform->pcm_ops->prepare)
72                 return platform->pcm_ops->prepare(substream);
73         else
74                 return 0;
75 }
76
77 static int s3c_wrpdma_trigger(struct snd_pcm_substream *substream, int cmd)
78 {
79         struct snd_soc_platform *platform = s3c_wrpdma_get_platform(substream);
80
81         switch (cmd) {
82         case SNDRV_PCM_TRIGGER_START:
83         case SNDRV_PCM_TRIGGER_RESUME:
84         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
85                 s5p_i2s_do_resume_stream(substream);
86                 break;
87         default:
88                 break;
89         }
90
91         if (platform->pcm_ops->trigger)
92                 return platform->pcm_ops->trigger(substream, cmd);
93         else
94                 return 0;
95 }
96
97 static snd_pcm_uframes_t s3c_wrpdma_pointer(struct snd_pcm_substream *substream)
98 {
99         struct snd_soc_platform *platform = s3c_wrpdma_get_platform(substream);
100
101         if (platform->pcm_ops->pointer)
102                 return platform->pcm_ops->pointer(substream);
103         else
104                 return 0;
105 }
106
107 static int s3c_wrpdma_open(struct snd_pcm_substream *substream)
108 {
109         struct snd_soc_platform *platform = s3c_wrpdma_get_platform(substream);
110
111         if (platform->pcm_ops->open)
112                 return platform->pcm_ops->open(substream);
113         else
114                 return 0;
115 }
116
117 static int s3c_wrpdma_close(struct snd_pcm_substream *substream)
118 {
119         struct snd_soc_platform *platform = s3c_wrpdma_get_platform(substream);
120
121         if (platform->pcm_ops->close)
122                 return platform->pcm_ops->close(substream);
123         else
124                 return 0;
125 }
126
127 static int s3c_wrpdma_ioctl(struct snd_pcm_substream *substream,
128                 unsigned int cmd, void *arg)
129 {
130         struct snd_soc_platform *platform = s3c_wrpdma_get_platform(substream);
131
132         if (platform->pcm_ops->ioctl)
133                 return platform->pcm_ops->ioctl(substream, cmd, arg);
134         else
135                 return 0;
136 }
137
138 static int s3c_wrpdma_mmap(struct snd_pcm_substream *substream,
139                 struct vm_area_struct *vma)
140 {
141         struct snd_soc_platform *platform = s3c_wrpdma_get_platform(substream);
142
143         if (platform->pcm_ops->mmap)
144                 return platform->pcm_ops->mmap(substream, vma);
145         else
146                 return 0;
147 }
148
149 static struct snd_pcm_ops s3c_wrpdma_ops = {
150         .open           = s3c_wrpdma_open,
151         .close          = s3c_wrpdma_close,
152         .ioctl          = s3c_wrpdma_ioctl,
153         .hw_params      = s3c_wrpdma_hw_params,
154         .hw_free        = s3c_wrpdma_hw_free,
155         .prepare        = s3c_wrpdma_prepare,
156         .trigger        = s3c_wrpdma_trigger,
157         .pointer        = s3c_wrpdma_pointer,
158         .mmap           = s3c_wrpdma_mmap,
159 };
160
161 static void s3c_wrpdma_pcm_free(struct snd_pcm *pcm)
162 {
163         struct snd_soc_platform *gdma_platform;
164 #ifdef CONFIG_S5P_INTERNAL_DMA
165         struct snd_soc_platform *idma_platform;
166 #endif
167
168 #ifdef CONFIG_S5P_INTERNAL_DMA
169         idma_platform = &idma_soc_platform;
170         if (idma_platform->pcm_free)
171                 idma_platform->pcm_free(pcm);
172 #endif
173         gdma_platform = &s3c24xx_soc_platform;
174         if (gdma_platform->pcm_free)
175                 gdma_platform->pcm_free(pcm);
176 }
177
178 static int s3c_wrpdma_pcm_new(struct snd_card *card,
179                 struct snd_soc_dai *dai, struct snd_pcm *pcm)
180 {
181         struct snd_soc_platform *gdma_platform;
182 #ifdef CONFIG_S5P_INTERNAL_DMA
183         struct snd_soc_platform *idma_platform;
184 #endif
185
186         /* sec_fifo i/f always use internal h/w buffers
187          * irrespective of the xfer method (iDMA or SysDMA) */
188
189 #ifdef CONFIG_S5P_INTERNAL_DMA
190         idma_platform = &idma_soc_platform;
191         if (idma_platform->pcm_new)
192                 idma_platform->pcm_new(card, dai, pcm);
193 #endif
194         gdma_platform  = &s3c24xx_soc_platform;
195         if (gdma_platform->pcm_new)
196                 gdma_platform->pcm_new(card, dai, pcm);
197
198         return 0;
199 }
200
201 struct snd_soc_platform s3c_dma_wrapper = {
202         .name           = "samsung-audio",
203         .pcm_ops        = &s3c_wrpdma_ops,
204         .pcm_new        = s3c_wrpdma_pcm_new,
205         .pcm_free       = s3c_wrpdma_pcm_free,
206 };
207 EXPORT_SYMBOL_GPL(s3c_dma_wrapper);
208
209 static int __init s3c_dma_wrapper_init(void)
210 {
211         return snd_soc_register_platform(&s3c_dma_wrapper);
212 }
213 module_init(s3c_dma_wrapper_init);
214
215 static void __exit s3c_dma_wrapper_exit(void)
216 {
217         snd_soc_unregister_platform(&s3c_dma_wrapper);
218 }
219 module_exit(s3c_dma_wrapper_exit);
220
221 MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
222 MODULE_DESCRIPTION("Audio DMA wrapper module");
223 MODULE_LICENSE("GPL");