[ARM] 3752/1: fix versatile flash resource map
[deliverable/linux.git] / arch / arm / mach-s3c2410 / dma.c
CommitLineData
1da177e4
LT
1/* linux/arch/arm/mach-bast/dma.c
2 *
3 * (c) 2003-2005 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2410 DMA core
7 *
8 * http://www.simtec.co.uk/products/EB2410ITX/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * Changelog:
15 * 27-Feb-2005 BJD Added kmem cache for dma descriptors
16 * 18-Nov-2004 BJD Removed error for loading onto stopped channel
17 * 10-Nov-2004 BJD Ensure all external symbols exported for modules
18 * 10-Nov-2004 BJD Use sys_device and sysdev_class for power management
19 * 08-Aug-2004 BJD Apply rmk's suggestions
20 * 21-Jul-2004 BJD Ported to linux 2.6
21 * 12-Jul-2004 BJD Finished re-write and change of API
22 * 06-Jul-2004 BJD Rewrote dma code to try and cope with various problems
23 * 23-May-2003 BJD Created file
24 * 19-Aug-2003 BJD Cleanup, header fix, added URL
25 *
26 * This file is based on the Sangwook Lee/Samsung patches, re-written due
27 * to various ommisions from the code (such as flexible dma configuration)
28 * for use with the BAST system board.
29 *
30 * The re-write is pretty much complete, and should be good enough for any
31 * possible DMA function
32 */
33
1da177e4
LT
34
35#ifdef CONFIG_S3C2410_DMA_DEBUG
36#define DEBUG
37#endif
38
39#include <linux/module.h>
40#include <linux/init.h>
41#include <linux/sched.h>
42#include <linux/spinlock.h>
43#include <linux/interrupt.h>
44#include <linux/sysdev.h>
45#include <linux/slab.h>
46#include <linux/errno.h>
47#include <linux/delay.h>
48
49#include <asm/system.h>
50#include <asm/irq.h>
51#include <asm/hardware.h>
52#include <asm/io.h>
53#include <asm/dma.h>
54
55#include <asm/mach/dma.h>
56#include <asm/arch/map.h>
57
58/* io map for dma */
59static void __iomem *dma_base;
60static kmem_cache_t *dma_kmem;
61
62/* dma channel state information */
63s3c2410_dma_chan_t s3c2410_chans[S3C2410_DMA_CHANNELS];
64
65/* debugging functions */
66
67#define BUF_MAGIC (0xcafebabe)
68
69#define dmawarn(fmt...) printk(KERN_DEBUG fmt)
70
71#define dma_regaddr(chan, reg) ((chan)->regs + (reg))
72
73#if 1
74#define dma_wrreg(chan, reg, val) writel((val), (chan)->regs + (reg))
75#else
76static inline void
77dma_wrreg(s3c2410_dma_chan_t *chan, int reg, unsigned long val)
78{
79 pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
80 writel(val, dma_regaddr(chan, reg));
81}
82
83#endif
84
85#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
86
87/* captured register state for debug */
88
89struct s3c2410_dma_regstate {
90 unsigned long dcsrc;
91 unsigned long disrc;
92 unsigned long dstat;
93 unsigned long dcon;
94 unsigned long dmsktrig;
95};
96
97#ifdef CONFIG_S3C2410_DMA_DEBUG
98
99/* dmadbg_showregs
100 *
101 * simple debug routine to print the current state of the dma registers
102*/
103
104static void
105dmadbg_capture(s3c2410_dma_chan_t *chan, struct s3c2410_dma_regstate *regs)
106{
107 regs->dcsrc = dma_rdreg(chan, S3C2410_DMA_DCSRC);
108 regs->disrc = dma_rdreg(chan, S3C2410_DMA_DISRC);
109 regs->dstat = dma_rdreg(chan, S3C2410_DMA_DSTAT);
110 regs->dcon = dma_rdreg(chan, S3C2410_DMA_DCON);
111 regs->dmsktrig = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
112}
113
114static void
115dmadbg_showregs(const char *fname, int line, s3c2410_dma_chan_t *chan,
116 struct s3c2410_dma_regstate *regs)
117{
118 printk(KERN_DEBUG "dma%d: %s:%d: DCSRC=%08lx, DISRC=%08lx, DSTAT=%08lx DMT=%02lx, DCON=%08lx\n",
119 chan->number, fname, line,
120 regs->dcsrc, regs->disrc, regs->dstat, regs->dmsktrig,
121 regs->dcon);
122}
123
124static void
125dmadbg_showchan(const char *fname, int line, s3c2410_dma_chan_t *chan)
126{
127 struct s3c2410_dma_regstate state;
128
129 dmadbg_capture(chan, &state);
130
131 printk(KERN_DEBUG "dma%d: %s:%d: ls=%d, cur=%p, %p %p\n",
132 chan->number, fname, line, chan->load_state,
133 chan->curr, chan->next, chan->end);
134
135 dmadbg_showregs(fname, line, chan, &state);
136}
137
138#define dbg_showregs(chan) dmadbg_showregs(__FUNCTION__, __LINE__, (chan))
139#define dbg_showchan(chan) dmadbg_showchan(__FUNCTION__, __LINE__, (chan))
140#else
141#define dbg_showregs(chan) do { } while(0)
142#define dbg_showchan(chan) do { } while(0)
143#endif /* CONFIG_S3C2410_DMA_DEBUG */
144
145#define check_channel(chan) \
146 do { if ((chan) >= S3C2410_DMA_CHANNELS) { \
147 printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \
148 return -EINVAL; \
149 } } while(0)
150
151
152/* s3c2410_dma_stats_timeout
153 *
154 * Update DMA stats from timeout info
155*/
156
157static void
158s3c2410_dma_stats_timeout(s3c2410_dma_stats_t *stats, int val)
159{
160 if (stats == NULL)
161 return;
162
163 if (val > stats->timeout_longest)
164 stats->timeout_longest = val;
165 if (val < stats->timeout_shortest)
166 stats->timeout_shortest = val;
167
168 stats->timeout_avg += val;
169}
170
171/* s3c2410_dma_waitforload
172 *
173 * wait for the DMA engine to load a buffer, and update the state accordingly
174*/
175
176static int
177s3c2410_dma_waitforload(s3c2410_dma_chan_t *chan, int line)
178{
179 int timeout = chan->load_timeout;
180 int took;
181
182 if (chan->load_state != S3C2410_DMALOAD_1LOADED) {
183 printk(KERN_ERR "dma%d: s3c2410_dma_waitforload() called in loadstate %d from line %d\n", chan->number, chan->load_state, line);
184 return 0;
185 }
186
187 if (chan->stats != NULL)
188 chan->stats->loads++;
189
190 while (--timeout > 0) {
191 if ((dma_rdreg(chan, S3C2410_DMA_DSTAT) << (32-20)) != 0) {
192 took = chan->load_timeout - timeout;
193
194 s3c2410_dma_stats_timeout(chan->stats, took);
195
196 switch (chan->load_state) {
197 case S3C2410_DMALOAD_1LOADED:
198 chan->load_state = S3C2410_DMALOAD_1RUNNING;
199 break;
200
201 default:
202 printk(KERN_ERR "dma%d: unknown load_state in s3c2410_dma_waitforload() %d\n", chan->number, chan->load_state);
203 }
204
205 return 1;
206 }
207 }
208
209 if (chan->stats != NULL) {
210 chan->stats->timeout_failed++;
211 }
212
213 return 0;
214}
215
216
217
218/* s3c2410_dma_loadbuffer
219 *
220 * load a buffer, and update the channel state
221*/
222
223static inline int
224s3c2410_dma_loadbuffer(s3c2410_dma_chan_t *chan,
225 s3c2410_dma_buf_t *buf)
226{
227 unsigned long reload;
228
229 pr_debug("s3c2410_chan_loadbuffer: loading buff %p (0x%08lx,0x%06x)\n",
230 buf, (unsigned long)buf->data, buf->size);
231
232 if (buf == NULL) {
233 dmawarn("buffer is NULL\n");
234 return -EINVAL;
235 }
236
237 /* check the state of the channel before we do anything */
238
239 if (chan->load_state == S3C2410_DMALOAD_1LOADED) {
240 dmawarn("load_state is S3C2410_DMALOAD_1LOADED\n");
241 }
242
243 if (chan->load_state == S3C2410_DMALOAD_1LOADED_1RUNNING) {
244 dmawarn("state is S3C2410_DMALOAD_1LOADED_1RUNNING\n");
245 }
246
247 /* it would seem sensible if we are the last buffer to not bother
248 * with the auto-reload bit, so that the DMA engine will not try
249 * and load another transfer after this one has finished...
250 */
251 if (chan->load_state == S3C2410_DMALOAD_NONE) {
252 pr_debug("load_state is none, checking for noreload (next=%p)\n",
253 buf->next);
254 reload = (buf->next == NULL) ? S3C2410_DCON_NORELOAD : 0;
255 } else {
256 pr_debug("load_state is %d => autoreload\n", chan->load_state);
257 reload = S3C2410_DCON_AUTORELOAD;
258 }
259
260 writel(buf->data, chan->addr_reg);
261
262 dma_wrreg(chan, S3C2410_DMA_DCON,
263 chan->dcon | reload | (buf->size/chan->xfer_unit));
264
265 chan->next = buf->next;
266
267 /* update the state of the channel */
268
269 switch (chan->load_state) {
270 case S3C2410_DMALOAD_NONE:
271 chan->load_state = S3C2410_DMALOAD_1LOADED;
272 break;
273
274 case S3C2410_DMALOAD_1RUNNING:
275 chan->load_state = S3C2410_DMALOAD_1LOADED_1RUNNING;
276 break;
277
278 default:
279 dmawarn("dmaload: unknown state %d in loadbuffer\n",
280 chan->load_state);
281 break;
282 }
283
284 return 0;
285}
286
287/* s3c2410_dma_call_op
288 *
289 * small routine to call the op routine with the given op if it has been
290 * registered
291*/
292
293static void
294s3c2410_dma_call_op(s3c2410_dma_chan_t *chan, s3c2410_chan_op_t op)
295{
296 if (chan->op_fn != NULL) {
297 (chan->op_fn)(chan, op);
298 }
299}
300
301/* s3c2410_dma_buffdone
302 *
303 * small wrapper to check if callback routine needs to be called, and
304 * if so, call it
305*/
306
307static inline void
308s3c2410_dma_buffdone(s3c2410_dma_chan_t *chan, s3c2410_dma_buf_t *buf,
309 s3c2410_dma_buffresult_t result)
310{
311 pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
312 chan->callback_fn, buf, buf->id, buf->size, result);
313
314 if (chan->callback_fn != NULL) {
315 (chan->callback_fn)(chan, buf->id, buf->size, result);
316 }
317}
318
319/* s3c2410_dma_start
320 *
321 * start a dma channel going
322*/
323
324static int s3c2410_dma_start(s3c2410_dma_chan_t *chan)
325{
326 unsigned long tmp;
327 unsigned long flags;
328
329 pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);
330
331 local_irq_save(flags);
332
333 if (chan->state == S3C2410_DMA_RUNNING) {
334 pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
335 local_irq_restore(flags);
336 return 0;
337 }
338
339 chan->state = S3C2410_DMA_RUNNING;
340
341 /* check wether there is anything to load, and if not, see
342 * if we can find anything to load
343 */
344
345 if (chan->load_state == S3C2410_DMALOAD_NONE) {
346 if (chan->next == NULL) {
347 printk(KERN_ERR "dma%d: channel has nothing loaded\n",
348 chan->number);
349 chan->state = S3C2410_DMA_IDLE;
350 local_irq_restore(flags);
351 return -EINVAL;
352 }
353
354 s3c2410_dma_loadbuffer(chan, chan->next);
355 }
356
357 dbg_showchan(chan);
358
359 /* enable the channel */
360
361 if (!chan->irq_enabled) {
362 enable_irq(chan->irq);
363 chan->irq_enabled = 1;
364 }
365
366 /* start the channel going */
367
368 tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
369 tmp &= ~S3C2410_DMASKTRIG_STOP;
370 tmp |= S3C2410_DMASKTRIG_ON;
371 dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);
372
373 pr_debug("wrote %08lx to DMASKTRIG\n", tmp);
374
375#if 0
376 /* the dma buffer loads should take care of clearing the AUTO
377 * reloading feature */
378 tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
379 tmp &= ~S3C2410_DCON_NORELOAD;
380 dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
381#endif
382
383 s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);
384
385 dbg_showchan(chan);
386
387 local_irq_restore(flags);
388 return 0;
389}
390
391/* s3c2410_dma_canload
392 *
393 * work out if we can queue another buffer into the DMA engine
394*/
395
396static int
397s3c2410_dma_canload(s3c2410_dma_chan_t *chan)
398{
399 if (chan->load_state == S3C2410_DMALOAD_NONE ||
400 chan->load_state == S3C2410_DMALOAD_1RUNNING)
401 return 1;
402
403 return 0;
404}
405
406
407/* s3c2410_dma_enqueue
408 *
409 * queue an given buffer for dma transfer.
410 *
411 * id the device driver's id information for this buffer
412 * data the physical address of the buffer data
413 * size the size of the buffer in bytes
414 *
415 * If the channel is not running, then the flag S3C2410_DMAF_AUTOSTART
416 * is checked, and if set, the channel is started. If this flag isn't set,
417 * then an error will be returned.
418 *
419 * It is possible to queue more than one DMA buffer onto a channel at
420 * once, and the code will deal with the re-loading of the next buffer
421 * when necessary.
422*/
423
424int s3c2410_dma_enqueue(unsigned int channel, void *id,
425 dma_addr_t data, int size)
426{
427 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
428 s3c2410_dma_buf_t *buf;
429 unsigned long flags;
430
431 check_channel(channel);
432
433 pr_debug("%s: id=%p, data=%08x, size=%d\n",
434 __FUNCTION__, id, (unsigned int)data, size);
435
436 buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
437 if (buf == NULL) {
53776eb4 438 pr_debug("%s: out of memory (%ld alloc)\n",
1da177e4
LT
439 __FUNCTION__, sizeof(*buf));
440 return -ENOMEM;
441 }
442
443 pr_debug("%s: new buffer %p\n", __FUNCTION__, buf);
444
445 //dbg_showchan(chan);
446
447 buf->next = NULL;
448 buf->data = buf->ptr = data;
449 buf->size = size;
450 buf->id = id;
451 buf->magic = BUF_MAGIC;
452
453 local_irq_save(flags);
454
455 if (chan->curr == NULL) {
456 /* we've got nothing loaded... */
457 pr_debug("%s: buffer %p queued onto empty channel\n",
458 __FUNCTION__, buf);
459
460 chan->curr = buf;
461 chan->end = buf;
462 chan->next = NULL;
463 } else {
464 pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
465 chan->number, __FUNCTION__, buf);
466
467 if (chan->end == NULL)
468 pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
469 chan->number, __FUNCTION__, chan);
470
471 chan->end->next = buf;
472 chan->end = buf;
473 }
474
475 /* if necessary, update the next buffer field */
476 if (chan->next == NULL)
477 chan->next = buf;
478
479 /* check to see if we can load a buffer */
480 if (chan->state == S3C2410_DMA_RUNNING) {
481 if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
482 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
483 printk(KERN_ERR "dma%d: loadbuffer:"
484 "timeout loading buffer\n",
485 chan->number);
486 dbg_showchan(chan);
487 local_irq_restore(flags);
488 return -EINVAL;
489 }
490 }
491
492 while (s3c2410_dma_canload(chan) && chan->next != NULL) {
493 s3c2410_dma_loadbuffer(chan, chan->next);
494 }
495 } else if (chan->state == S3C2410_DMA_IDLE) {
496 if (chan->flags & S3C2410_DMAF_AUTOSTART) {
497 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_START);
498 }
499 }
500
501 local_irq_restore(flags);
502 return 0;
503}
504
505EXPORT_SYMBOL(s3c2410_dma_enqueue);
506
507static inline void
508s3c2410_dma_freebuf(s3c2410_dma_buf_t *buf)
509{
510 int magicok = (buf->magic == BUF_MAGIC);
511
512 buf->magic = -1;
513
514 if (magicok) {
515 kmem_cache_free(dma_kmem, buf);
516 } else {
517 printk("s3c2410_dma_freebuf: buff %p with bad magic\n", buf);
518 }
519}
520
521/* s3c2410_dma_lastxfer
522 *
523 * called when the system is out of buffers, to ensure that the channel
524 * is prepared for shutdown.
525*/
526
527static inline void
528s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan)
529{
530 pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
531 chan->number, chan->load_state);
532
533 switch (chan->load_state) {
534 case S3C2410_DMALOAD_NONE:
535 break;
536
537 case S3C2410_DMALOAD_1LOADED:
538 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
539 /* flag error? */
540 printk(KERN_ERR "dma%d: timeout waiting for load\n",
541 chan->number);
542 return;
543 }
544 break;
545
546 default:
547 pr_debug("dma%d: lastxfer: unhandled load_state %d with no next",
548 chan->number, chan->load_state);
549 return;
550
551 }
552
553 /* hopefully this'll shut the damned thing up after the transfer... */
554 dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
555}
556
557
558#define dmadbg2(x...)
559
560static irqreturn_t
561s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
562{
563 s3c2410_dma_chan_t *chan = (s3c2410_dma_chan_t *)devpw;
564 s3c2410_dma_buf_t *buf;
565
566 buf = chan->curr;
567
568 dbg_showchan(chan);
569
570 /* modify the channel state */
571
572 switch (chan->load_state) {
573 case S3C2410_DMALOAD_1RUNNING:
574 /* TODO - if we are running only one buffer, we probably
575 * want to reload here, and then worry about the buffer
576 * callback */
577
578 chan->load_state = S3C2410_DMALOAD_NONE;
579 break;
580
581 case S3C2410_DMALOAD_1LOADED:
582 /* iirc, we should go back to NONE loaded here, we
583 * had a buffer, and it was never verified as being
584 * loaded.
585 */
586
587 chan->load_state = S3C2410_DMALOAD_NONE;
588 break;
589
590 case S3C2410_DMALOAD_1LOADED_1RUNNING:
591 /* we'll worry about checking to see if another buffer is
592 * ready after we've called back the owner. This should
593 * ensure we do not wait around too long for the DMA
594 * engine to start the next transfer
595 */
596
597 chan->load_state = S3C2410_DMALOAD_1LOADED;
598 break;
599
600 case S3C2410_DMALOAD_NONE:
601 printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
602 chan->number);
603 break;
604
605 default:
606 printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
607 chan->number, chan->load_state);
608 break;
609 }
610
611 if (buf != NULL) {
612 /* update the chain to make sure that if we load any more
613 * buffers when we call the callback function, things should
614 * work properly */
615
616 chan->curr = buf->next;
617 buf->next = NULL;
618
619 if (buf->magic != BUF_MAGIC) {
620 printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
621 chan->number, __FUNCTION__, buf);
622 return IRQ_HANDLED;
623 }
624
625 s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);
626
627 /* free resouces */
628 s3c2410_dma_freebuf(buf);
629 } else {
630 }
631
632 if (chan->next != NULL) {
633 unsigned long flags;
634
635 switch (chan->load_state) {
636 case S3C2410_DMALOAD_1RUNNING:
637 /* don't need to do anything for this state */
638 break;
639
640 case S3C2410_DMALOAD_NONE:
641 /* can load buffer immediately */
642 break;
643
644 case S3C2410_DMALOAD_1LOADED:
645 if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
646 /* flag error? */
647 printk(KERN_ERR "dma%d: timeout waiting for load\n",
648 chan->number);
649 return IRQ_HANDLED;
650 }
651
652 break;
653
654 case S3C2410_DMALOAD_1LOADED_1RUNNING:
655 goto no_load;
656
657 default:
658 printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
659 chan->number, chan->load_state);
660 return IRQ_HANDLED;
661 }
662
663 local_irq_save(flags);
664 s3c2410_dma_loadbuffer(chan, chan->next);
665 local_irq_restore(flags);
666 } else {
667 s3c2410_dma_lastxfer(chan);
668
669 /* see if we can stop this channel.. */
670 if (chan->load_state == S3C2410_DMALOAD_NONE) {
671 pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
672 chan->number, jiffies);
673 s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
674 }
675 }
676
677 no_load:
678 return IRQ_HANDLED;
679}
680
681
682
683/* s3c2410_request_dma
684 *
685 * get control of an dma channel
686*/
687
688int s3c2410_dma_request(unsigned int channel, s3c2410_dma_client_t *client,
689 void *dev)
690{
691 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
692 unsigned long flags;
693 int err;
694
695 pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
696 channel, client->name, dev);
697
698 check_channel(channel);
699
700 local_irq_save(flags);
701
702 dbg_showchan(chan);
703
704 if (chan->in_use) {
705 if (client != chan->client) {
706 printk(KERN_ERR "dma%d: already in use\n", channel);
707 local_irq_restore(flags);
708 return -EBUSY;
709 } else {
710 printk(KERN_ERR "dma%d: client already has channel\n", channel);
711 }
712 }
713
714 chan->client = client;
715 chan->in_use = 1;
716
717 if (!chan->irq_claimed) {
718 pr_debug("dma%d: %s : requesting irq %d\n",
719 channel, __FUNCTION__, chan->irq);
720
52e405ea 721 err = request_irq(chan->irq, s3c2410_dma_irq, IRQF_DISABLED,
1da177e4
LT
722 client->name, (void *)chan);
723
724 if (err) {
725 chan->in_use = 0;
726 local_irq_restore(flags);
727
728 printk(KERN_ERR "%s: cannot get IRQ %d for DMA %d\n",
729 client->name, chan->irq, chan->number);
730 return err;
731 }
732
733 chan->irq_claimed = 1;
734 chan->irq_enabled = 1;
735 }
736
737 local_irq_restore(flags);
738
739 /* need to setup */
740
741 pr_debug("%s: channel initialised, %p\n", __FUNCTION__, chan);
742
743 return 0;
744}
745
746EXPORT_SYMBOL(s3c2410_dma_request);
747
748/* s3c2410_dma_free
749 *
750 * release the given channel back to the system, will stop and flush
751 * any outstanding transfers, and ensure the channel is ready for the
752 * next claimant.
753 *
754 * Note, although a warning is currently printed if the freeing client
755 * info is not the same as the registrant's client info, the free is still
756 * allowed to go through.
757*/
758
759int s3c2410_dma_free(dmach_t channel, s3c2410_dma_client_t *client)
760{
761 s3c2410_dma_chan_t *chan = &s3c2410_chans[channel];
762 unsigned long flags;
763
764 check_channel(channel);
765
766 local_irq_save(flags);
767
768
769 if (chan->client != client) {
770 printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
771 channel, chan->client, client);
772 }
773
774 /* sort out stopping and freeing the channel */
775
776 if (chan->state != S3C2410_DMA_IDLE) {
777 pr_debug("%s: need to stop dma channel %p\n",
778 __FUNCTION__, chan);
779
780 /* possibly flush the channel */
781 s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STOP);
782 }
783
784 chan->client = NULL;
785 chan->in_use = 0;
786