1
2
3
4
5
6
7
8
9
10
11
12
13#include <linux/module.h>
14#include <linux/interrupt.h>
15#include <linux/init.h>
16#include <linux/spinlock.h>
17#include <linux/errno.h>
18
19#include <asm/system.h>
20#include <asm/irq.h>
21#include <mach/hardware.h>
22#include <mach/dma.h>
23
24
25#undef DEBUG
26#ifdef DEBUG
27#define DPRINTK( s, arg... ) printk( "dma<%p>: " s, regs , ##arg )
28#else
29#define DPRINTK( x... )
30#endif
31
32
33typedef struct {
34 const char *device_id;
35 u_long device;
36 dma_callback_t callback;
37 void *data;
38} sa1100_dma_t;
39
40static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS];
41
42static DEFINE_SPINLOCK(dma_list_lock);
43
44
45static irqreturn_t dma_irq_handler(int irq, void *dev_id)
46{
47 dma_regs_t *dma_regs = dev_id;
48 sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7);
49 int status = dma_regs->RdDCSR;
50
51 if (status & (DCSR_ERROR)) {
52 printk(KERN_CRIT "DMA on \"%s\" caused an error\n", dma->device_id);
53 dma_regs->ClrDCSR = DCSR_ERROR;
54 }
55
56 dma_regs->ClrDCSR = status & (DCSR_DONEA | DCSR_DONEB);
57 if (dma->callback) {
58 if (status & DCSR_DONEA)
59 dma->callback(dma->data);
60 if (status & DCSR_DONEB)
61 dma->callback(dma->data);
62 }
63 return IRQ_HANDLED;
64}
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95int sa1100_request_dma (dma_device_t device, const char *device_id,
96 dma_callback_t callback, void *data,
97 dma_regs_t **dma_regs)
98{
99 sa1100_dma_t *dma = NULL;
100 dma_regs_t *regs;
101 int i, err;
102
103 *dma_regs = NULL;
104
105 err = 0;
106 spin_lock(&dma_list_lock);
107 for (i = 0; i < SA1100_DMA_CHANNELS; i++) {
108 if (dma_chan[i].device == device) {
109 err = -EBUSY;
110 break;
111 } else if (!dma_chan[i].device && !dma) {
112 dma = &dma_chan[i];
113 }
114 }
115 if (!err) {
116 if (dma)
117 dma->device = device;
118 else
119 err = -ENOSR;
120 }
121 spin_unlock(&dma_list_lock);
122 if (err)
123 return err;
124
125 i = dma - dma_chan;
126 regs = (dma_regs_t *)&DDAR(i);
127 err = request_irq(IRQ_DMA0 + i, dma_irq_handler, IRQF_DISABLED,
128 device_id, regs);
129 if (err) {
130 printk(KERN_ERR
131 "%s: unable to request IRQ %d for %s\n",
132 __func__, IRQ_DMA0 + i, device_id);
133 dma->device = 0;
134 return err;
135 }
136
137 *dma_regs = regs;
138 dma->device_id = device_id;
139 dma->callback = callback;
140 dma->data = data;
141
142 regs->ClrDCSR =
143 (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
144 DCSR_IE | DCSR_ERROR | DCSR_RUN);
145 regs->DDAR = device;
146
147 return 0;
148}
149
150
151
152
153
154
155
156
157
158
159
160void sa1100_free_dma(dma_regs_t *regs)
161{
162 int i;
163
164 for (i = 0; i < SA1100_DMA_CHANNELS; i++)
165 if (regs == (dma_regs_t *)&DDAR(i))
166 break;
167 if (i >= SA1100_DMA_CHANNELS) {
168 printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
169 return;
170 }
171
172 if (!dma_chan[i].device) {
173 printk(KERN_ERR "%s: Trying to free free DMA\n", __func__);
174 return;
175 }
176
177 regs->ClrDCSR =
178 (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
179 DCSR_IE | DCSR_ERROR | DCSR_RUN);
180 free_irq(IRQ_DMA0 + i, regs);
181 dma_chan[i].device = 0;
182}
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217int sa1100_start_dma(dma_regs_t *regs, dma_addr_t dma_ptr, u_int size)
218{
219 unsigned long flags;
220 u_long status;
221 int ret;
222
223 if (dma_ptr & 3)
224 printk(KERN_WARNING "DMA: unaligned start address (0x%08lx)\n",
225 (unsigned long)dma_ptr);
226
227 if (size > MAX_DMA_SIZE)
228 return -EOVERFLOW;
229
230 local_irq_save(flags);
231 status = regs->RdDCSR;
232
233
234 if ((status & (DCSR_STRTA | DCSR_STRTB)) == (DCSR_STRTA | DCSR_STRTB)) {
235 DPRINTK("start: st %#x busy\n", status);
236 ret = -EBUSY;
237 goto out;
238 }
239
240 if (((status & DCSR_BIU) && (status & DCSR_STRTB)) ||
241 (!(status & DCSR_BIU) && !(status & DCSR_STRTA))) {
242 if (status & DCSR_DONEA) {
243
244 ret = -EAGAIN;
245 goto out;
246 }
247 regs->DBSA = dma_ptr;
248 regs->DBTA = size;
249 regs->SetDCSR = DCSR_STRTA | DCSR_IE | DCSR_RUN;
250 DPRINTK("start a=%#x s=%d on A\n", dma_ptr, size);
251 } else {
252 if (status & DCSR_DONEB) {
253
254 ret = -EAGAIN;
255 goto out;
256 }
257 regs->DBSB = dma_ptr;
258 regs->DBTB = size;
259 regs->SetDCSR = DCSR_STRTB | DCSR_IE | DCSR_RUN;
260 DPRINTK("start a=%#x s=%d on B\n", dma_ptr, size);
261 }
262 ret = 0;
263
264out:
265 local_irq_restore(flags);
266 return ret;
267}
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287dma_addr_t sa1100_get_dma_pos(dma_regs_t *regs)
288{
289 int status;
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304 status = regs->RdDCSR;
305 if ((!(status & DCSR_BIU) && (status & DCSR_STRTA)) ||
306 ( (status & DCSR_BIU) && !(status & DCSR_STRTB)))
307 return regs->DBSA;
308 else
309 return regs->DBSB;
310}
311
312
313
314
315
316
317
318
319
320
321
322
323
324void sa1100_reset_dma(dma_regs_t *regs)
325{
326 int i;
327
328 for (i = 0; i < SA1100_DMA_CHANNELS; i++)
329 if (regs == (dma_regs_t *)&DDAR(i))
330 break;
331 if (i >= SA1100_DMA_CHANNELS) {
332 printk(KERN_ERR "%s: bad DMA identifier\n", __func__);
333 return;
334 }
335
336 regs->ClrDCSR =
337 (DCSR_DONEA | DCSR_DONEB | DCSR_STRTA | DCSR_STRTB |
338 DCSR_IE | DCSR_ERROR | DCSR_RUN);
339 regs->DDAR = dma_chan[i].device;
340}
341
342
343EXPORT_SYMBOL(sa1100_request_dma);
344EXPORT_SYMBOL(sa1100_free_dma);
345EXPORT_SYMBOL(sa1100_start_dma);
346EXPORT_SYMBOL(sa1100_get_dma_pos);
347EXPORT_SYMBOL(sa1100_reset_dma);
348
349