remove lots of double-semicolons
[safe/jmp/linux-2.6] / sound / soc / au1x / dbdma2.c
1 /*
2  * Au12x0/Au1550 PSC ALSA ASoC audio support.
3  *
4  * (c) 2007-2008 MSC Vertriebsges.m.b.H.,
5  *      Manuel Lauss <mano@roarinelk.homelinux.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  *
11  * DMA glue for Au1x-PSC audio.
12  *
13  * NOTE: all of these drivers can only work with a SINGLE instance
14  *       of a PSC. Multiple independent audio devices are impossible
15  *       with ASoC v1.
16  */
17
18
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/platform_device.h>
22 #include <linux/slab.h>
23 #include <linux/dma-mapping.h>
24
25 #include <sound/core.h>
26 #include <sound/pcm.h>
27 #include <sound/pcm_params.h>
28 #include <sound/soc.h>
29
30 #include <asm/mach-au1x00/au1000.h>
31 #include <asm/mach-au1x00/au1xxx_dbdma.h>
32 #include <asm/mach-au1x00/au1xxx_psc.h>
33
34 #include "psc.h"
35
36 /*#define PCM_DEBUG*/
37
38 #define MSG(x...)       printk(KERN_INFO "au1xpsc_pcm: " x)
39 #ifdef PCM_DEBUG
40 #define DBG             MSG
41 #else
42 #define DBG(x...)       do {} while (0)
43 #endif
44
45 struct au1xpsc_audio_dmadata {
46         /* DDMA control data */
47         unsigned int ddma_id;           /* DDMA direction ID for this PSC */
48         u32 ddma_chan;                  /* DDMA context */
49
50         /* PCM context (for irq handlers) */
51         struct snd_pcm_substream *substream;
52         unsigned long curr_period;      /* current segment DDMA is working on */
53         unsigned long q_period;         /* queue period(s) */
54         unsigned long dma_area;         /* address of queued DMA area */
55         unsigned long dma_area_s;       /* start address of DMA area */
56         unsigned long pos;              /* current byte position being played */
57         unsigned long periods;          /* number of SG segments in total */
58         unsigned long period_bytes;     /* size in bytes of one SG segment */
59
60         /* runtime data */
61         int msbits;
62 };
63
64 /* instance data. There can be only one, MacLeod!!!! */
65 static struct au1xpsc_audio_dmadata *au1xpsc_audio_pcmdma[2];
66
67 /*
68  * These settings are somewhat okay, at least on my machine audio plays
69  * almost skip-free. Especially the 64kB buffer seems to help a LOT.
70  */
71 #define AU1XPSC_PERIOD_MIN_BYTES        1024
72 #define AU1XPSC_BUFFER_MIN_BYTES        65536
73
74 #define AU1XPSC_PCM_FMTS                                        \
75         (SNDRV_PCM_FMTBIT_S8     | SNDRV_PCM_FMTBIT_U8 |        \
76          SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |    \
77          SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE |    \
78          SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |    \
79          SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE |    \
80          0)
81
82 /* PCM hardware DMA capabilities - platform specific */
83 static const struct snd_pcm_hardware au1xpsc_pcm_hardware = {
84         .info             = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
85                             SNDRV_PCM_INFO_INTERLEAVED,
86         .formats          = AU1XPSC_PCM_FMTS,
87         .period_bytes_min = AU1XPSC_PERIOD_MIN_BYTES,
88         .period_bytes_max = 4096 * 1024 - 1,
89         .periods_min      = 2,
90         .periods_max      = 4096,       /* 2 to as-much-as-you-like */
91         .buffer_bytes_max = 4096 * 1024 - 1,
92         .fifo_size        = 16,         /* fifo entries of AC97/I2S PSC */
93 };
94
95 static void au1x_pcm_queue_tx(struct au1xpsc_audio_dmadata *cd)
96 {
97         au1xxx_dbdma_put_source_flags(cd->ddma_chan,
98                                 (void *)phys_to_virt(cd->dma_area),
99                                 cd->period_bytes, DDMA_FLAGS_IE);
100
101         /* update next-to-queue period */
102         ++cd->q_period;
103         cd->dma_area += cd->period_bytes;
104         if (cd->q_period >= cd->periods) {
105                 cd->q_period = 0;
106                 cd->dma_area = cd->dma_area_s;
107         }
108 }
109
110 static void au1x_pcm_queue_rx(struct au1xpsc_audio_dmadata *cd)
111 {
112         au1xxx_dbdma_put_dest_flags(cd->ddma_chan,
113                                 (void *)phys_to_virt(cd->dma_area),
114                                 cd->period_bytes, DDMA_FLAGS_IE);
115
116         /* update next-to-queue period */
117         ++cd->q_period;
118         cd->dma_area += cd->period_bytes;
119         if (cd->q_period >= cd->periods) {
120                 cd->q_period = 0;
121                 cd->dma_area = cd->dma_area_s;
122         }
123 }
124
125 static void au1x_pcm_dmatx_cb(int irq, void *dev_id)
126 {
127         struct au1xpsc_audio_dmadata *cd = dev_id;
128
129         cd->pos += cd->period_bytes;
130         if (++cd->curr_period >= cd->periods) {
131                 cd->pos = 0;
132                 cd->curr_period = 0;
133         }
134         snd_pcm_period_elapsed(cd->substream);
135         au1x_pcm_queue_tx(cd);
136 }
137
138 static void au1x_pcm_dmarx_cb(int irq, void *dev_id)
139 {
140         struct au1xpsc_audio_dmadata *cd = dev_id;
141
142         cd->pos += cd->period_bytes;
143         if (++cd->curr_period >= cd->periods) {
144                 cd->pos = 0;
145                 cd->curr_period = 0;
146         }
147         snd_pcm_period_elapsed(cd->substream);
148         au1x_pcm_queue_rx(cd);
149 }
150
151 static void au1x_pcm_dbdma_free(struct au1xpsc_audio_dmadata *pcd)
152 {
153         if (pcd->ddma_chan) {
154                 au1xxx_dbdma_stop(pcd->ddma_chan);
155                 au1xxx_dbdma_reset(pcd->ddma_chan);
156                 au1xxx_dbdma_chan_free(pcd->ddma_chan);
157                 pcd->ddma_chan = 0;
158                 pcd->msbits = 0;
159         }
160 }
161
162 /* in case of missing DMA ring or changed TX-source / RX-dest bit widths,
163  * allocate (or reallocate) a 2-descriptor DMA ring with bit depth according
164  * to ALSA-supplied sample depth.  This is due to limitations in the dbdma api
165  * (cannot adjust source/dest widths of already allocated descriptor ring).
166  */
167 static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd,
168                                  int stype, int msbits)
169 {
170         /* DMA only in 8/16/32 bit widths */
171         if (msbits == 24)
172                 msbits = 32;
173
174         /* check current config: correct bits and descriptors allocated? */
175         if ((pcd->ddma_chan) && (msbits == pcd->msbits))
176                 goto out;       /* all ok! */
177
178         au1x_pcm_dbdma_free(pcd);
179
180         if (stype == PCM_RX)
181                 pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id,
182                                         DSCR_CMD0_ALWAYS,
183                                         au1x_pcm_dmarx_cb, (void *)pcd);
184         else
185                 pcd->ddma_chan = au1xxx_dbdma_chan_alloc(DSCR_CMD0_ALWAYS,
186                                         pcd->ddma_id,
187                                         au1x_pcm_dmatx_cb, (void *)pcd);
188
189         if (!pcd->ddma_chan)
190                 return -ENOMEM;
191
192         au1xxx_dbdma_set_devwidth(pcd->ddma_chan, msbits);
193         au1xxx_dbdma_ring_alloc(pcd->ddma_chan, 2);
194
195         pcd->msbits = msbits;
196
197         au1xxx_dbdma_stop(pcd->ddma_chan);
198         au1xxx_dbdma_reset(pcd->ddma_chan);
199
200 out:
201         return 0;
202 }
203
204 static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
205                                  struct snd_pcm_hw_params *params)
206 {
207         struct snd_pcm_runtime *runtime = substream->runtime;
208         struct au1xpsc_audio_dmadata *pcd;
209         int stype, ret;
210
211         ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
212         if (ret < 0)
213                 goto out;
214
215         stype = SUBSTREAM_TYPE(substream);
216         pcd = au1xpsc_audio_pcmdma[stype];
217
218         DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
219             "runtime->min_align %d\n",
220                 (unsigned long)runtime->dma_area,
221                 (unsigned long)runtime->dma_addr, runtime->dma_bytes,
222                 runtime->min_align);
223
224         DBG("bits %d  frags %d  frag_bytes %d  is_rx %d\n", params->msbits,
225                 params_periods(params), params_period_bytes(params), stype);
226
227         ret = au1x_pcm_dbdma_realloc(pcd, stype, params->msbits);
228         if (ret) {
229                 MSG("DDMA channel (re)alloc failed!\n");
230                 goto out;
231         }
232
233         pcd->substream = substream;
234         pcd->period_bytes = params_period_bytes(params);
235         pcd->periods = params_periods(params);
236         pcd->dma_area_s = pcd->dma_area = (unsigned long)runtime->dma_addr;
237         pcd->q_period = 0;
238         pcd->curr_period = 0;
239         pcd->pos = 0;
240
241         ret = 0;
242 out:
243         return ret;
244 }
245
246 static int au1xpsc_pcm_hw_free(struct snd_pcm_substream *substream)
247 {
248         snd_pcm_lib_free_pages(substream);
249         return 0;
250 }
251
252 static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
253 {
254         struct au1xpsc_audio_dmadata *pcd =
255                         au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)];
256
257         au1xxx_dbdma_reset(pcd->ddma_chan);
258
259         if (SUBSTREAM_TYPE(substream) == PCM_RX) {
260                 au1x_pcm_queue_rx(pcd);
261                 au1x_pcm_queue_rx(pcd);
262         } else {
263                 au1x_pcm_queue_tx(pcd);
264                 au1x_pcm_queue_tx(pcd);
265         }
266
267         return 0;
268 }
269
270 static int au1xpsc_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
271 {
272         u32 c = au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->ddma_chan;
273
274         switch (cmd) {
275         case SNDRV_PCM_TRIGGER_START:
276         case SNDRV_PCM_TRIGGER_RESUME:
277                 au1xxx_dbdma_start(c);
278                 break;
279         case SNDRV_PCM_TRIGGER_STOP:
280         case SNDRV_PCM_TRIGGER_SUSPEND:
281                 au1xxx_dbdma_stop(c);
282                 break;
283         default:
284                 return -EINVAL;
285         }
286         return 0;
287 }
288
289 static snd_pcm_uframes_t
290 au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
291 {
292         return bytes_to_frames(substream->runtime,
293                 au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]->pos);
294 }
295
296 static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
297 {
298         snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware);
299         return 0;
300 }
301
302 static int au1xpsc_pcm_close(struct snd_pcm_substream *substream)
303 {
304         au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[SUBSTREAM_TYPE(substream)]);
305         return 0;
306 }
307
308 struct snd_pcm_ops au1xpsc_pcm_ops = {
309         .open           = au1xpsc_pcm_open,
310         .close          = au1xpsc_pcm_close,
311         .ioctl          = snd_pcm_lib_ioctl,
312         .hw_params      = au1xpsc_pcm_hw_params,
313         .hw_free        = au1xpsc_pcm_hw_free,
314         .prepare        = au1xpsc_pcm_prepare,
315         .trigger        = au1xpsc_pcm_trigger,
316         .pointer        = au1xpsc_pcm_pointer,
317 };
318
319 static void au1xpsc_pcm_free_dma_buffers(struct snd_pcm *pcm)
320 {
321         snd_pcm_lib_preallocate_free_for_all(pcm);
322 }
323
324 static int au1xpsc_pcm_new(struct snd_card *card,
325                            struct snd_soc_dai *dai,
326                            struct snd_pcm *pcm)
327 {
328         snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
329                 card->dev, AU1XPSC_BUFFER_MIN_BYTES, (4096 * 1024) - 1);
330
331         return 0;
332 }
333
334 static int au1xpsc_pcm_probe(struct platform_device *pdev)
335 {
336         struct resource *r;
337         int ret;
338
339         if (au1xpsc_audio_pcmdma[PCM_TX] || au1xpsc_audio_pcmdma[PCM_RX])
340                 return -EBUSY;
341
342         /* TX DMA */
343         au1xpsc_audio_pcmdma[PCM_TX]
344                 = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
345         if (!au1xpsc_audio_pcmdma[PCM_TX])
346                 return -ENOMEM;
347
348         r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
349         if (!r) {
350                 ret = -ENODEV;
351                 goto out1;
352         }
353         (au1xpsc_audio_pcmdma[PCM_TX])->ddma_id = r->start;
354
355         /* RX DMA */
356         au1xpsc_audio_pcmdma[PCM_RX]
357                 = kzalloc(sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
358         if (!au1xpsc_audio_pcmdma[PCM_RX])
359                 return -ENOMEM;
360
361         r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
362         if (!r) {
363                 ret = -ENODEV;
364                 goto out2;
365         }
366         (au1xpsc_audio_pcmdma[PCM_RX])->ddma_id = r->start;
367
368         return 0;
369
370 out2:
371         kfree(au1xpsc_audio_pcmdma[PCM_RX]);
372         au1xpsc_audio_pcmdma[PCM_RX] = NULL;
373 out1:
374         kfree(au1xpsc_audio_pcmdma[PCM_TX]);
375         au1xpsc_audio_pcmdma[PCM_TX] = NULL;
376         return ret;
377 }
378
379 static int au1xpsc_pcm_remove(struct platform_device *pdev)
380 {
381         int i;
382
383         for (i = 0; i < 2; i++) {
384                 if (au1xpsc_audio_pcmdma[i]) {
385                         au1x_pcm_dbdma_free(au1xpsc_audio_pcmdma[i]);
386                         kfree(au1xpsc_audio_pcmdma[i]);
387                         au1xpsc_audio_pcmdma[i] = NULL;
388                 }
389         }
390
391         return 0;
392 }
393
394 /* au1xpsc audio platform */
395 struct snd_soc_platform au1xpsc_soc_platform = {
396         .name           = "au1xpsc-pcm-dbdma",
397         .probe          = au1xpsc_pcm_probe,
398         .remove         = au1xpsc_pcm_remove,
399         .pcm_ops        = &au1xpsc_pcm_ops,
400         .pcm_new        = au1xpsc_pcm_new,
401         .pcm_free       = au1xpsc_pcm_free_dma_buffers,
402 };
403 EXPORT_SYMBOL_GPL(au1xpsc_soc_platform);
404
405 static int __init au1xpsc_audio_dbdma_init(void)
406 {
407         au1xpsc_audio_pcmdma[PCM_TX] = NULL;
408         au1xpsc_audio_pcmdma[PCM_RX] = NULL;
409         return snd_soc_register_platform(&au1xpsc_soc_platform);
410 }
411
412 static void __exit au1xpsc_audio_dbdma_exit(void)
413 {
414         snd_soc_unregister_platform(&au1xpsc_soc_platform);
415 }
416
417 module_init(au1xpsc_audio_dbdma_init);
418 module_exit(au1xpsc_audio_dbdma_exit);
419
420 MODULE_LICENSE("GPL");
421 MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
422 MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>");