correct email address of Manfred Spraul
[linux-2.6] / arch / arm / mach-imx / dma.c
1 /*
2  *  linux/arch/arm/mach-imx/dma.c
3  *
4  *  imx DMA registration and IRQ dispatching
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License version 2 as
8  *  published by the Free Software Foundation.
9  *
10  *  03/03/2004 Sascha Hauer <sascha@saschahauer.de>
11  *             initial version heavily inspired by
12  *             linux/arch/arm/mach-pxa/dma.c
13  */
14
15 #include <linux/module.h>
16 #include <linux/init.h>
17 #include <linux/kernel.h>
18 #include <linux/interrupt.h>
19 #include <linux/errno.h>
20
21 #include <asm/system.h>
22 #include <asm/irq.h>
23 #include <asm/hardware.h>
24 #include <asm/dma.h>
25
26 static struct dma_channel {
27         char *name;
28         void (*irq_handler) (int, void *, struct pt_regs *);
29         void (*err_handler) (int, void *, struct pt_regs *);
30         void *data;
31 } dma_channels[11];
32
33 /* set err_handler to NULL to have the standard info-only error handler */
34 int
35 imx_request_dma(char *name, imx_dma_prio prio,
36                 void (*irq_handler) (int, void *, struct pt_regs *),
37                 void (*err_handler) (int, void *, struct pt_regs *), void *data)
38 {
39         unsigned long flags;
40         int i, found = 0;
41
42         /* basic sanity checks */
43         if (!name || !irq_handler)
44                 return -EINVAL;
45
46         local_irq_save(flags);
47
48         /* try grabbing a DMA channel with the requested priority */
49         for (i = prio; i < prio + (prio == DMA_PRIO_LOW) ? 8 : 4; i++) {
50                 if (!dma_channels[i].name) {
51                         found = 1;
52                         break;
53                 }
54         }
55
56         if (!found) {
57                 /* requested prio group is full, try hier priorities */
58                 for (i = prio - 1; i >= 0; i--) {
59                         if (!dma_channels[i].name) {
60                                 found = 1;
61                                 break;
62                         }
63                 }
64         }
65
66         if (found) {
67                 DIMR &= ~(1 << i);
68                 dma_channels[i].name = name;
69                 dma_channels[i].irq_handler = irq_handler;
70                 dma_channels[i].err_handler = err_handler;
71                 dma_channels[i].data = data;
72         } else {
73                 printk(KERN_WARNING "No more available DMA channels for %s\n",
74                        name);
75                 i = -ENODEV;
76         }
77
78         local_irq_restore(flags);
79         return i;
80 }
81
82 void
83 imx_free_dma(int dma_ch)
84 {
85         unsigned long flags;
86
87         if (!dma_channels[dma_ch].name) {
88                 printk(KERN_CRIT
89                        "%s: trying to free channel %d which is already freed\n",
90                        __FUNCTION__, dma_ch);
91                 return;
92         }
93
94         local_irq_save(flags);
95         DIMR &= ~(1 << dma_ch);
96         dma_channels[dma_ch].name = NULL;
97         local_irq_restore(flags);
98 }
99
100 static irqreturn_t
101 dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
102 {
103         int i, disr = DISR;
104         struct dma_channel *channel;
105         unsigned int err_mask = DBTOSR | DRTOSR | DSESR | DBOSR;
106
107         DISR = disr;
108         for (i = 0; i < 11; i++) {
109                 channel = &dma_channels[i];
110
111                 if ( (err_mask & 1<<i) && channel->name && channel->err_handler) {
112                         channel->err_handler(i, channel->data, regs);
113                         continue;
114                 }
115
116                 if (DBTOSR & (1 << i)) {
117                         printk(KERN_WARNING
118                                "Burst timeout on channel %d (%s)\n",
119                                i, channel->name);
120                         DBTOSR |= (1 << i);
121                 }
122                 if (DRTOSR & (1 << i)) {
123                         printk(KERN_WARNING
124                                "Request timeout on channel %d (%s)\n",
125                                i, channel->name);
126                         DRTOSR |= (1 << i);
127                 }
128                 if (DSESR & (1 << i)) {
129                         printk(KERN_WARNING
130                                "Transfer timeout on channel %d (%s)\n",
131                                i, channel->name);
132                         DSESR |= (1 << i);
133                 }
134                 if (DBOSR & (1 << i)) {
135                         printk(KERN_WARNING
136                                "Buffer overflow timeout on channel %d (%s)\n",
137                                i, channel->name);
138                         DBOSR |= (1 << i);
139                 }
140         }
141         return IRQ_HANDLED;
142 }
143
144 static irqreturn_t
145 dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
146 {
147         int i, disr = DISR;
148
149         DISR = disr;
150         for (i = 0; i < 11; i++) {
151                 if (disr & (1 << i)) {
152                         struct dma_channel *channel = &dma_channels[i];
153                         if (channel->name && channel->irq_handler) {
154                                 channel->irq_handler(i, channel->data, regs);
155                         } else {
156                                 /*
157                                  * IRQ for an unregistered DMA channel:
158                                  * let's clear the interrupts and disable it.
159                                  */
160                                 printk(KERN_WARNING
161                                        "spurious IRQ for DMA channel %d\n", i);
162                         }
163                 }
164         }
165         return IRQ_HANDLED;
166 }
167
168 static int __init
169 imx_dma_init(void)
170 {
171         int ret;
172
173         /* reset DMA module */
174         DCR = DCR_DRST;
175
176         ret = request_irq(DMA_INT, dma_irq_handler, 0, "DMA", NULL);
177         if (ret) {
178                 printk(KERN_CRIT "Wow!  Can't register IRQ for DMA\n");
179                 return ret;
180         }
181
182         ret = request_irq(DMA_ERR, dma_err_handler, 0, "DMA", NULL);
183         if (ret) {
184                 printk(KERN_CRIT "Wow!  Can't register ERRIRQ for DMA\n");
185                 free_irq(DMA_INT, NULL);
186         }
187
188         /* enable DMA module */
189         DCR = DCR_DEN;
190
191         /* clear all interrupts */
192         DISR = 0x3ff;
193
194         /* enable interrupts */
195         DIMR = 0;
196
197         return ret;
198 }
199
200 arch_initcall(imx_dma_init);
201
202 EXPORT_SYMBOL(imx_request_dma);
203 EXPORT_SYMBOL(imx_free_dma);