]> Pileus Git - ~andy/linux/blob - sound/soc/samsung/dma.c
Merge remote-tracking branches 'asoc/topic/ad1836', 'asoc/topic/ad193x', 'asoc/topic...
[~andy/linux] / sound / soc / samsung / dma.c
1 /*
2  * dma.c  --  ALSA Soc Audio Layer
3  *
4  * (c) 2006 Wolfson Microelectronics PLC.
5  * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
6  *
7  * Copyright 2004-2005 Simtec Electronics
8  *      http://armlinux.simtec.co.uk/
9  *      Ben Dooks <ben@simtec.co.uk>
10  *
11  *  This program is free software; you can redistribute  it and/or modify it
12  *  under  the terms of  the GNU General  Public License as published by the
13  *  Free Software Foundation;  either version 2 of the  License, or (at your
14  *  option) any later version.
15  */
16
17 #include <linux/slab.h>
18 #include <linux/dma-mapping.h>
19 #include <linux/module.h>
20
21 #include <sound/soc.h>
22 #include <sound/pcm_params.h>
23
24 #include <asm/dma.h>
25 #include <mach/hardware.h>
26 #include <mach/dma.h>
27
28 #include "dma.h"
29
30 #define ST_RUNNING              (1<<0)
31 #define ST_OPENED               (1<<1)
32
33 static const struct snd_pcm_hardware dma_hardware = {
34         .info                   = SNDRV_PCM_INFO_INTERLEAVED |
35                                     SNDRV_PCM_INFO_BLOCK_TRANSFER |
36                                     SNDRV_PCM_INFO_MMAP |
37                                     SNDRV_PCM_INFO_MMAP_VALID,
38         .buffer_bytes_max       = 128*1024,
39         .period_bytes_min       = PAGE_SIZE,
40         .period_bytes_max       = PAGE_SIZE*2,
41         .periods_min            = 2,
42         .periods_max            = 128,
43         .fifo_size              = 32,
44 };
45
46 struct runtime_data {
47         spinlock_t lock;
48         int state;
49         unsigned int dma_loaded;
50         unsigned int dma_period;
51         dma_addr_t dma_start;
52         dma_addr_t dma_pos;
53         dma_addr_t dma_end;
54         struct s3c_dma_params *params;
55 };
56
57 static void audio_buffdone(void *data);
58
59 /* dma_enqueue
60  *
61  * place a dma buffer onto the queue for the dma system
62  * to handle.
63  */
64 static void dma_enqueue(struct snd_pcm_substream *substream)
65 {
66         struct runtime_data *prtd = substream->runtime->private_data;
67         dma_addr_t pos = prtd->dma_pos;
68         unsigned int limit;
69         struct samsung_dma_prep dma_info;
70
71         pr_debug("Entered %s\n", __func__);
72
73         limit = (prtd->dma_end - prtd->dma_start) / prtd->dma_period;
74
75         pr_debug("%s: loaded %d, limit %d\n",
76                                 __func__, prtd->dma_loaded, limit);
77
78         dma_info.cap = (samsung_dma_has_circular() ? DMA_CYCLIC : DMA_SLAVE);
79         dma_info.direction =
80                 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
81                 ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
82         dma_info.fp = audio_buffdone;
83         dma_info.fp_param = substream;
84         dma_info.period = prtd->dma_period;
85         dma_info.len = prtd->dma_period*limit;
86
87         if (dma_info.cap == DMA_CYCLIC) {
88                 dma_info.buf = pos;
89                 prtd->params->ops->prepare(prtd->params->ch, &dma_info);
90                 prtd->dma_loaded += limit;
91                 return;
92         }
93
94         while (prtd->dma_loaded < limit) {
95                 pr_debug("dma_loaded: %d\n", prtd->dma_loaded);
96
97                 if ((pos + dma_info.period) > prtd->dma_end) {
98                         dma_info.period  = prtd->dma_end - pos;
99                         pr_debug("%s: corrected dma len %ld\n",
100                                         __func__, dma_info.period);
101                 }
102
103                 dma_info.buf = pos;
104                 prtd->params->ops->prepare(prtd->params->ch, &dma_info);
105
106                 prtd->dma_loaded++;
107                 pos += prtd->dma_period;
108                 if (pos >= prtd->dma_end)
109                         pos = prtd->dma_start;
110         }
111
112         prtd->dma_pos = pos;
113 }
114
115 static void audio_buffdone(void *data)
116 {
117         struct snd_pcm_substream *substream = data;
118         struct runtime_data *prtd = substream->runtime->private_data;
119
120         pr_debug("Entered %s\n", __func__);
121
122         if (prtd->state & ST_RUNNING) {
123                 prtd->dma_pos += prtd->dma_period;
124                 if (prtd->dma_pos >= prtd->dma_end)
125                         prtd->dma_pos = prtd->dma_start;
126
127                 if (substream)
128                         snd_pcm_period_elapsed(substream);
129
130                 spin_lock(&prtd->lock);
131                 if (!samsung_dma_has_circular()) {
132                         prtd->dma_loaded--;
133                         dma_enqueue(substream);
134                 }
135                 spin_unlock(&prtd->lock);
136         }
137 }
138
139 static int dma_hw_params(struct snd_pcm_substream *substream,
140         struct snd_pcm_hw_params *params)
141 {
142         struct snd_pcm_runtime *runtime = substream->runtime;
143         struct runtime_data *prtd = runtime->private_data;
144         struct snd_soc_pcm_runtime *rtd = substream->private_data;
145         unsigned long totbytes = params_buffer_bytes(params);
146         struct s3c_dma_params *dma =
147                 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
148         struct samsung_dma_req req;
149         struct samsung_dma_config config;
150
151         pr_debug("Entered %s\n", __func__);
152
153         /* return if this is a bufferless transfer e.g.
154          * codec <--> BT codec or GSM modem -- lg FIXME */
155         if (!dma)
156                 return 0;
157
158         /* this may get called several times by oss emulation
159          * with different params -HW */
160         if (prtd->params == NULL) {
161                 /* prepare DMA */
162                 prtd->params = dma;
163
164                 pr_debug("params %p, client %p, channel %d\n", prtd->params,
165                         prtd->params->client, prtd->params->channel);
166
167                 prtd->params->ops = samsung_dma_get_ops();
168
169                 req.cap = (samsung_dma_has_circular() ?
170                         DMA_CYCLIC : DMA_SLAVE);
171                 req.client = prtd->params->client;
172                 config.direction =
173                         (substream->stream == SNDRV_PCM_STREAM_PLAYBACK
174                         ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
175                 config.width = prtd->params->dma_size;
176                 config.fifo = prtd->params->dma_addr;
177                 prtd->params->ch = prtd->params->ops->request(
178                                 prtd->params->channel, &req, rtd->cpu_dai->dev,
179                                 prtd->params->ch_name);
180                 if (!prtd->params->ch) {
181                         pr_err("Failed to allocate DMA channel\n");
182                         return -ENXIO;
183                 }
184                 prtd->params->ops->config(prtd->params->ch, &config);
185         }
186
187         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
188
189         runtime->dma_bytes = totbytes;
190
191         spin_lock_irq(&prtd->lock);
192         prtd->dma_loaded = 0;
193         prtd->dma_period = params_period_bytes(params);
194         prtd->dma_start = runtime->dma_addr;
195         prtd->dma_pos = prtd->dma_start;
196         prtd->dma_end = prtd->dma_start + totbytes;
197         spin_unlock_irq(&prtd->lock);
198
199         return 0;
200 }
201
202 static int dma_hw_free(struct snd_pcm_substream *substream)
203 {
204         struct runtime_data *prtd = substream->runtime->private_data;
205
206         pr_debug("Entered %s\n", __func__);
207
208         snd_pcm_set_runtime_buffer(substream, NULL);
209
210         if (prtd->params) {
211                 prtd->params->ops->flush(prtd->params->ch);
212                 prtd->params->ops->release(prtd->params->ch,
213                                         prtd->params->client);
214                 prtd->params = NULL;
215         }
216
217         return 0;
218 }
219
220 static int dma_prepare(struct snd_pcm_substream *substream)
221 {
222         struct runtime_data *prtd = substream->runtime->private_data;
223         int ret = 0;
224
225         pr_debug("Entered %s\n", __func__);
226
227         /* return if this is a bufferless transfer e.g.
228          * codec <--> BT codec or GSM modem -- lg FIXME */
229         if (!prtd->params)
230                 return 0;
231
232         /* flush the DMA channel */
233         prtd->params->ops->flush(prtd->params->ch);
234
235         prtd->dma_loaded = 0;
236         prtd->dma_pos = prtd->dma_start;
237
238         /* enqueue dma buffers */
239         dma_enqueue(substream);
240
241         return ret;
242 }
243
244 static int dma_trigger(struct snd_pcm_substream *substream, int cmd)
245 {
246         struct runtime_data *prtd = substream->runtime->private_data;
247         int ret = 0;
248
249         pr_debug("Entered %s\n", __func__);
250
251         spin_lock(&prtd->lock);
252
253         switch (cmd) {
254         case SNDRV_PCM_TRIGGER_START:
255                 prtd->state |= ST_RUNNING;
256                 prtd->params->ops->trigger(prtd->params->ch);
257                 break;
258
259         case SNDRV_PCM_TRIGGER_STOP:
260                 prtd->state &= ~ST_RUNNING;
261                 prtd->params->ops->stop(prtd->params->ch);
262                 break;
263
264         default:
265                 ret = -EINVAL;
266                 break;
267         }
268
269         spin_unlock(&prtd->lock);
270
271         return ret;
272 }
273
274 static snd_pcm_uframes_t
275 dma_pointer(struct snd_pcm_substream *substream)
276 {
277         struct snd_pcm_runtime *runtime = substream->runtime;
278         struct runtime_data *prtd = runtime->private_data;
279         unsigned long res;
280
281         pr_debug("Entered %s\n", __func__);
282
283         res = prtd->dma_pos - prtd->dma_start;
284
285         pr_debug("Pointer offset: %lu\n", res);
286
287         /* we seem to be getting the odd error from the pcm library due
288          * to out-of-bounds pointers. this is maybe due to the dma engine
289          * not having loaded the new values for the channel before being
290          * called... (todo - fix )
291          */
292
293         if (res >= snd_pcm_lib_buffer_bytes(substream)) {
294                 if (res == snd_pcm_lib_buffer_bytes(substream))
295                         res = 0;
296         }
297
298         return bytes_to_frames(substream->runtime, res);
299 }
300
301 static int dma_open(struct snd_pcm_substream *substream)
302 {
303         struct snd_pcm_runtime *runtime = substream->runtime;
304         struct runtime_data *prtd;
305
306         pr_debug("Entered %s\n", __func__);
307
308         snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
309         snd_soc_set_runtime_hwparams(substream, &dma_hardware);
310
311         prtd = kzalloc(sizeof(struct runtime_data), GFP_KERNEL);
312         if (prtd == NULL)
313                 return -ENOMEM;
314
315         spin_lock_init(&prtd->lock);
316
317         runtime->private_data = prtd;
318         return 0;
319 }
320
321 static int dma_close(struct snd_pcm_substream *substream)
322 {
323         struct snd_pcm_runtime *runtime = substream->runtime;
324         struct runtime_data *prtd = runtime->private_data;
325
326         pr_debug("Entered %s\n", __func__);
327
328         if (!prtd)
329                 pr_debug("dma_close called with prtd == NULL\n");
330
331         kfree(prtd);
332
333         return 0;
334 }
335
336 static int dma_mmap(struct snd_pcm_substream *substream,
337         struct vm_area_struct *vma)
338 {
339         struct snd_pcm_runtime *runtime = substream->runtime;
340
341         pr_debug("Entered %s\n", __func__);
342
343         return dma_mmap_writecombine(substream->pcm->card->dev, vma,
344                                      runtime->dma_area,
345                                      runtime->dma_addr,
346                                      runtime->dma_bytes);
347 }
348
349 static struct snd_pcm_ops dma_ops = {
350         .open           = dma_open,
351         .close          = dma_close,
352         .ioctl          = snd_pcm_lib_ioctl,
353         .hw_params      = dma_hw_params,
354         .hw_free        = dma_hw_free,
355         .prepare        = dma_prepare,
356         .trigger        = dma_trigger,
357         .pointer        = dma_pointer,
358         .mmap           = dma_mmap,
359 };
360
361 static int preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
362 {
363         struct snd_pcm_substream *substream = pcm->streams[stream].substream;
364         struct snd_dma_buffer *buf = &substream->dma_buffer;
365         size_t size = dma_hardware.buffer_bytes_max;
366
367         pr_debug("Entered %s\n", __func__);
368
369         buf->dev.type = SNDRV_DMA_TYPE_DEV;
370         buf->dev.dev = pcm->card->dev;
371         buf->private_data = NULL;
372         buf->area = dma_alloc_writecombine(pcm->card->dev, size,
373                                            &buf->addr, GFP_KERNEL);
374         if (!buf->area)
375                 return -ENOMEM;
376         buf->bytes = size;
377         return 0;
378 }
379
380 static void dma_free_dma_buffers(struct snd_pcm *pcm)
381 {
382         struct snd_pcm_substream *substream;
383         struct snd_dma_buffer *buf;
384         int stream;
385
386         pr_debug("Entered %s\n", __func__);
387
388         for (stream = 0; stream < 2; stream++) {
389                 substream = pcm->streams[stream].substream;
390                 if (!substream)
391                         continue;
392
393                 buf = &substream->dma_buffer;
394                 if (!buf->area)
395                         continue;
396
397                 dma_free_writecombine(pcm->card->dev, buf->bytes,
398                                       buf->area, buf->addr);
399                 buf->area = NULL;
400         }
401 }
402
403 static int dma_new(struct snd_soc_pcm_runtime *rtd)
404 {
405         struct snd_card *card = rtd->card->snd_card;
406         struct snd_pcm *pcm = rtd->pcm;
407         int ret;
408
409         pr_debug("Entered %s\n", __func__);
410
411         ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
412         if (ret)
413                 return ret;
414
415         if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
416                 ret = preallocate_dma_buffer(pcm,
417                         SNDRV_PCM_STREAM_PLAYBACK);
418                 if (ret)
419                         goto out;
420         }
421
422         if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
423                 ret = preallocate_dma_buffer(pcm,
424                         SNDRV_PCM_STREAM_CAPTURE);
425                 if (ret)
426                         goto out;
427         }
428 out:
429         return ret;
430 }
431
432 static struct snd_soc_platform_driver samsung_asoc_platform = {
433         .ops            = &dma_ops,
434         .pcm_new        = dma_new,
435         .pcm_free       = dma_free_dma_buffers,
436 };
437
438 void samsung_asoc_init_dma_data(struct snd_soc_dai *dai,
439                                 struct s3c_dma_params *playback,
440                                 struct s3c_dma_params *capture)
441 {
442         snd_soc_dai_init_dma_data(dai, playback, capture);
443 }
444 EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data);
445
446 int samsung_asoc_dma_platform_register(struct device *dev)
447 {
448         return snd_soc_register_platform(dev, &samsung_asoc_platform);
449 }
450 EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register);
451
452 void samsung_asoc_dma_platform_unregister(struct device *dev)
453 {
454         snd_soc_unregister_platform(dev);
455 }
456 EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_unregister);
457
458 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
459 MODULE_DESCRIPTION("Samsung ASoC DMA Driver");
460 MODULE_LICENSE("GPL");