]>
Commit | Line | Data |
---|---|---|
3c9059d7 JB |
1 | /* |
2 | * LocalPlus Bus FIFO driver for the Freescale MPC52xx. | |
3 | * | |
4 | * Copyright (C) 2009 Secret Lab Technologies Ltd. | |
5 | * | |
6 | * This file is released under the GPLv2 | |
7 | * | |
8 | * Todo: | |
9 | * - Add support for multiple requests to be queued. | |
10 | */ | |
11 | ||
12 | #include <linux/interrupt.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/of.h> | |
15 | #include <linux/of_platform.h> | |
16 | #include <linux/spinlock.h> | |
17 | #include <asm/io.h> | |
18 | #include <asm/prom.h> | |
19 | #include <asm/mpc52xx.h> | |
20 | #include <asm/time.h> | |
21 | ||
22 | #include <sysdev/bestcomm/bestcomm.h> | |
23 | #include <sysdev/bestcomm/bestcomm_priv.h> | |
24 | #include <sysdev/bestcomm/gen_bd.h> | |
25 | ||
26 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); | |
27 | MODULE_DESCRIPTION("MPC5200 LocalPlus FIFO device driver"); | |
28 | MODULE_LICENSE("GPL"); | |
29 | ||
30 | #define LPBFIFO_REG_PACKET_SIZE (0x00) | |
31 | #define LPBFIFO_REG_START_ADDRESS (0x04) | |
32 | #define LPBFIFO_REG_CONTROL (0x08) | |
33 | #define LPBFIFO_REG_ENABLE (0x0C) | |
34 | #define LPBFIFO_REG_BYTES_DONE_STATUS (0x14) | |
35 | #define LPBFIFO_REG_FIFO_DATA (0x40) | |
36 | #define LPBFIFO_REG_FIFO_STATUS (0x44) | |
37 | #define LPBFIFO_REG_FIFO_CONTROL (0x48) | |
38 | #define LPBFIFO_REG_FIFO_ALARM (0x4C) | |
39 | ||
40 | struct mpc52xx_lpbfifo { | |
41 | struct device *dev; | |
42 | phys_addr_t regs_phys; | |
43 | void __iomem *regs; | |
44 | int irq; | |
45 | spinlock_t lock; | |
46 | ||
47 | struct bcom_task *bcom_tx_task; | |
48 | struct bcom_task *bcom_rx_task; | |
49 | struct bcom_task *bcom_cur_task; | |
50 | ||
51 | /* Current state data */ | |
52 | struct mpc52xx_lpbfifo_request *req; | |
53 | int dma_irqs_enabled; | |
54 | }; | |
55 | ||
56 | /* The MPC5200 has only one fifo, so only need one instance structure */ | |
57 | static struct mpc52xx_lpbfifo lpbfifo; | |
58 | ||
59 | /** | |
60 | * mpc52xx_lpbfifo_kick - Trigger the next block of data to be transfered | |
61 | */ | |
62 | static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) | |
63 | { | |
64 | size_t transfer_size = req->size - req->pos; | |
65 | struct bcom_bd *bd; | |
66 | void __iomem *reg; | |
67 | u32 *data; | |
68 | int i; | |
69 | int bit_fields; | |
70 | int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); | |
71 | int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; | |
72 | int poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; | |
73 | ||
74 | /* Set and clear the reset bits; is good practice in User Manual */ | |
75 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | |
76 | ||
77 | /* set master enable bit */ | |
78 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000001); | |
79 | if (!dma) { | |
80 | /* While the FIFO can be setup for transfer sizes as large as | |
81 | * 16M-1, the FIFO itself is only 512 bytes deep and it does | |
82 | * not generate interrupts for FIFO full events (only transfer | |
83 | * complete will raise an IRQ). Therefore when not using | |
84 | * Bestcomm to drive the FIFO it needs to either be polled, or | |
85 | * transfers need to constrained to the size of the fifo. | |
86 | * | |
87 | * This driver restricts the size of the transfer | |
88 | */ | |
89 | if (transfer_size > 512) | |
90 | transfer_size = 512; | |
91 | ||
92 | /* Load the FIFO with data */ | |
93 | if (write) { | |
94 | reg = lpbfifo.regs + LPBFIFO_REG_FIFO_DATA; | |
95 | data = req->data + req->pos; | |
96 | for (i = 0; i < transfer_size; i += 4) | |
97 | out_be32(reg, *data++); | |
98 | } | |
99 | ||
100 | /* Unmask both error and completion irqs */ | |
101 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000301); | |
102 | } else { | |
103 | /* Choose the correct direction | |
104 | * | |
105 | * Configure the watermarks so DMA will always complete correctly. | |
106 | * It may be worth experimenting with the ALARM value to see if | |
107 | * there is a performance impacit. However, if it is wrong there | |
108 | * is a risk of DMA not transferring the last chunk of data | |
109 | */ | |
110 | if (write) { | |
111 | out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1e4); | |
112 | out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 7); | |
113 | lpbfifo.bcom_cur_task = lpbfifo.bcom_tx_task; | |
114 | } else { | |
115 | out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1ff); | |
116 | out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 0); | |
117 | lpbfifo.bcom_cur_task = lpbfifo.bcom_rx_task; | |
118 | ||
119 | if (poll_dma) { | |
120 | if (lpbfifo.dma_irqs_enabled) { | |
121 | disable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task)); | |
122 | lpbfifo.dma_irqs_enabled = 0; | |
123 | } | |
124 | } else { | |
125 | if (!lpbfifo.dma_irqs_enabled) { | |
126 | enable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task)); | |
127 | lpbfifo.dma_irqs_enabled = 1; | |
128 | } | |
129 | } | |
130 | } | |
131 | ||
132 | bd = bcom_prepare_next_buffer(lpbfifo.bcom_cur_task); | |
133 | bd->status = transfer_size; | |
134 | if (!write) { | |
135 | /* | |
136 | * In the DMA read case, the DMA doesn't complete, | |
137 | * possibly due to incorrect watermarks in the ALARM | |
138 | * and CONTROL regs. For now instead of trying to | |
139 | * determine the right watermarks that will make this | |
140 | * work, just increase the number of bytes the FIFO is | |
141 | * expecting. | |
142 | * | |
143 | * When submitting another operation, the FIFO will get | |
144 | * reset, so the condition of the FIFO waiting for a | |
145 | * non-existent 4 bytes will get cleared. | |
146 | */ | |
147 | transfer_size += 4; /* BLECH! */ | |
148 | } | |
149 | bd->data[0] = req->data_phys + req->pos; | |
150 | bcom_submit_next_buffer(lpbfifo.bcom_cur_task, NULL); | |
151 | ||
152 | /* error irq & master enabled bit */ | |
153 | bit_fields = 0x00000201; | |
154 | ||
155 | /* Unmask irqs */ | |
156 | if (write && (!poll_dma)) | |
157 | bit_fields |= 0x00000100; /* completion irq too */ | |
158 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, bit_fields); | |
159 | } | |
160 | ||
161 | /* Set transfer size, width, chip select and READ mode */ | |
162 | out_be32(lpbfifo.regs + LPBFIFO_REG_START_ADDRESS, | |
163 | req->offset + req->pos); | |
164 | out_be32(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, transfer_size); | |
165 | ||
166 | bit_fields = req->cs << 24 | 0x000008; | |
167 | if (!write) | |
168 | bit_fields |= 0x010000; /* read mode */ | |
169 | out_be32(lpbfifo.regs + LPBFIFO_REG_CONTROL, bit_fields); | |
170 | ||
171 | /* Kick it off */ | |
172 | out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01); | |
173 | if (dma) | |
174 | bcom_enable(lpbfifo.bcom_cur_task); | |
175 | } | |
176 | ||
177 | /** | |
178 | * mpc52xx_lpbfifo_irq - IRQ handler for LPB FIFO | |
179 | * | |
180 | * On transmit, the dma completion irq triggers before the fifo completion | |
181 | * triggers. Handle the dma completion here instead of the LPB FIFO Bestcomm | |
182 | * task completion irq becuase everyting is not really done until the LPB FIFO | |
183 | * completion irq triggers. | |
184 | * | |
185 | * In other words: | |
186 | * For DMA, on receive, the "Fat Lady" is the bestcom completion irq. on | |
187 | * transmit, the fifo completion irq is the "Fat Lady". The opera (or in this | |
188 | * case the DMA/FIFO operation) is not finished until the "Fat Lady" sings. | |
189 | * | |
190 | * Reasons for entering this routine: | |
191 | * 1) PIO mode rx and tx completion irq | |
192 | * 2) DMA interrupt mode tx completion irq | |
193 | * 3) DMA polled mode tx | |
194 | * | |
195 | * Exit conditions: | |
196 | * 1) Transfer aborted | |
197 | * 2) FIFO complete without DMA; more data to do | |
198 | * 3) FIFO complete without DMA; all data transfered | |
199 | * 4) FIFO complete using DMA | |
200 | * | |
201 | * Condition 1 can occur regardless of whether or not DMA is used. | |
202 | * It requires executing the callback to report the error and exiting | |
203 | * immediately. | |
204 | * | |
205 | * Condition 2 requires programming the FIFO with the next block of data | |
206 | * | |
207 | * Condition 3 requires executing the callback to report completion | |
208 | * | |
209 | * Condition 4 means the same as 3, except that we also retrieve the bcom | |
210 | * buffer so DMA doesn't get clogged up. | |
211 | * | |
212 | * To make things trickier, the spinlock must be dropped before | |
213 | * executing the callback, otherwise we could end up with a deadlock | |
214 | * or nested spinlock condition. The out path is non-trivial, so | |
215 | * extra fiddling is done to make sure all paths lead to the same | |
216 | * outbound code. | |
217 | */ | |
218 | static irqreturn_t mpc52xx_lpbfifo_irq(int irq, void *dev_id) | |
219 | { | |
220 | struct mpc52xx_lpbfifo_request *req; | |
221 | u32 status = in_8(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS); | |
222 | void __iomem *reg; | |
223 | u32 *data; | |
224 | int count, i; | |
225 | int do_callback = 0; | |
226 | u32 ts; | |
227 | unsigned long flags; | |
228 | int dma, write, poll_dma; | |
229 | ||
230 | spin_lock_irqsave(&lpbfifo.lock, flags); | |
231 | ts = get_tbl(); | |
232 | ||
233 | req = lpbfifo.req; | |
234 | if (!req) { | |
235 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
236 | pr_err("bogus LPBFIFO IRQ\n"); | |
237 | return IRQ_HANDLED; | |
238 | } | |
239 | ||
240 | dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); | |
241 | write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; | |
242 | poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; | |
243 | ||
244 | if (dma && !write) { | |
245 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
246 | pr_err("bogus LPBFIFO IRQ (dma and not writting)\n"); | |
247 | return IRQ_HANDLED; | |
248 | } | |
249 | ||
250 | if ((status & 0x01) == 0) { | |
251 | goto out; | |
252 | } | |
253 | ||
254 | /* check abort bit */ | |
255 | if (status & 0x10) { | |
256 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | |
257 | do_callback = 1; | |
258 | goto out; | |
259 | } | |
260 | ||
261 | /* Read result from hardware */ | |
262 | count = in_be32(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS); | |
263 | count &= 0x00ffffff; | |
264 | ||
265 | if (!dma && !write) { | |
266 | /* copy the data out of the FIFO */ | |
267 | reg = lpbfifo.regs + LPBFIFO_REG_FIFO_DATA; | |
268 | data = req->data + req->pos; | |
269 | for (i = 0; i < count; i += 4) | |
270 | *data++ = in_be32(reg); | |
271 | } | |
272 | ||
273 | /* Update transfer position and count */ | |
274 | req->pos += count; | |
275 | ||
276 | /* Decide what to do next */ | |
277 | if (req->size - req->pos) | |
278 | mpc52xx_lpbfifo_kick(req); /* more work to do */ | |
279 | else | |
280 | do_callback = 1; | |
281 | ||
282 | out: | |
283 | /* Clear the IRQ */ | |
284 | out_8(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS, 0x01); | |
285 | ||
286 | if (dma && (status & 0x11)) { | |
287 | /* | |
288 | * Count the DMA as complete only when the FIFO completion | |
289 | * status or abort bits are set. | |
290 | * | |
291 | * (status & 0x01) should always be the case except sometimes | |
292 | * when using polled DMA. | |
293 | * | |
294 | * (status & 0x10) {transfer aborted}: This case needs more | |
295 | * testing. | |
296 | */ | |
297 | bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL); | |
298 | } | |
299 | req->last_byte = ((u8 *)req->data)[req->size - 1]; | |
300 | ||
301 | /* When the do_callback flag is set; it means the transfer is finished | |
302 | * so set the FIFO as idle */ | |
303 | if (do_callback) | |
304 | lpbfifo.req = NULL; | |
305 | ||
306 | if (irq != 0) /* don't increment on polled case */ | |
307 | req->irq_count++; | |
308 | ||
309 | req->irq_ticks += get_tbl() - ts; | |
310 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
311 | ||
312 | /* Spinlock is released; it is now safe to call the callback */ | |
313 | if (do_callback && req->callback) | |
314 | req->callback(req); | |
315 | ||
316 | return IRQ_HANDLED; | |
317 | } | |
318 | ||
319 | /** | |
320 | * mpc52xx_lpbfifo_bcom_irq - IRQ handler for LPB FIFO Bestcomm task | |
321 | * | |
322 | * Only used when receiving data. | |
323 | */ | |
324 | static irqreturn_t mpc52xx_lpbfifo_bcom_irq(int irq, void *dev_id) | |
325 | { | |
326 | struct mpc52xx_lpbfifo_request *req; | |
327 | unsigned long flags; | |
328 | u32 status; | |
329 | u32 ts; | |
330 | ||
331 | spin_lock_irqsave(&lpbfifo.lock, flags); | |
332 | ts = get_tbl(); | |
333 | ||
334 | req = lpbfifo.req; | |
335 | if (!req || (req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA)) { | |
336 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
337 | return IRQ_HANDLED; | |
338 | } | |
339 | ||
340 | if (irq != 0) /* don't increment on polled case */ | |
341 | req->irq_count++; | |
342 | ||
343 | if (!bcom_buffer_done(lpbfifo.bcom_cur_task)) { | |
344 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
345 | ||
346 | req->buffer_not_done_cnt++; | |
347 | if ((req->buffer_not_done_cnt % 1000) == 0) | |
348 | pr_err("transfer stalled\n"); | |
349 | ||
350 | return IRQ_HANDLED; | |
351 | } | |
352 | ||
353 | bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL); | |
354 | ||
355 | req->last_byte = ((u8 *)req->data)[req->size - 1]; | |
356 | ||
357 | req->pos = status & 0x00ffffff; | |
358 | ||
359 | /* Mark the FIFO as idle */ | |
360 | lpbfifo.req = NULL; | |
361 | ||
362 | /* Release the lock before calling out to the callback. */ | |
363 | req->irq_ticks += get_tbl() - ts; | |
364 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
365 | ||
366 | if (req->callback) | |
367 | req->callback(req); | |
368 | ||
369 | return IRQ_HANDLED; | |
370 | } | |
371 | ||
372 | /** | |
373 | * mpc52xx_lpbfifo_bcom_poll - Poll for DMA completion | |
374 | */ | |
375 | void mpc52xx_lpbfifo_poll(void) | |
376 | { | |
377 | struct mpc52xx_lpbfifo_request *req = lpbfifo.req; | |
378 | int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); | |
379 | int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; | |
380 | ||
381 | /* | |
382 | * For more information, see comments on the "Fat Lady" | |
383 | */ | |
384 | if (dma && write) | |
385 | mpc52xx_lpbfifo_irq(0, NULL); | |
386 | else | |
387 | mpc52xx_lpbfifo_bcom_irq(0, NULL); | |
388 | } | |
389 | EXPORT_SYMBOL(mpc52xx_lpbfifo_poll); | |
390 | ||
391 | /** | |
392 | * mpc52xx_lpbfifo_submit - Submit an LPB FIFO transfer request. | |
393 | * @req: Pointer to request structure | |
394 | */ | |
395 | int mpc52xx_lpbfifo_submit(struct mpc52xx_lpbfifo_request *req) | |
396 | { | |
397 | unsigned long flags; | |
398 | ||
399 | if (!lpbfifo.regs) | |
400 | return -ENODEV; | |
401 | ||
402 | spin_lock_irqsave(&lpbfifo.lock, flags); | |
403 | ||
404 | /* If the req pointer is already set, then a transfer is in progress */ | |
405 | if (lpbfifo.req) { | |
406 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
407 | return -EBUSY; | |
408 | } | |
409 | ||
410 | /* Setup the transfer */ | |
411 | lpbfifo.req = req; | |
412 | req->irq_count = 0; | |
413 | req->irq_ticks = 0; | |
414 | req->buffer_not_done_cnt = 0; | |
415 | req->pos = 0; | |
416 | ||
417 | mpc52xx_lpbfifo_kick(req); | |
418 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
419 | return 0; | |
420 | } | |
421 | EXPORT_SYMBOL(mpc52xx_lpbfifo_submit); | |
422 | ||
423 | void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req) | |
424 | { | |
425 | unsigned long flags; | |
426 | ||
427 | spin_lock_irqsave(&lpbfifo.lock, flags); | |
428 | if (lpbfifo.req == req) { | |
429 | /* Put it into reset and clear the state */ | |
430 | bcom_gen_bd_rx_reset(lpbfifo.bcom_rx_task); | |
431 | bcom_gen_bd_tx_reset(lpbfifo.bcom_tx_task); | |
432 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | |
433 | lpbfifo.req = NULL; | |
434 | } | |
435 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
436 | } | |
437 | EXPORT_SYMBOL(mpc52xx_lpbfifo_abort); | |
438 | ||
439 | static int __devinit | |
440 | mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match) | |
441 | { | |
442 | struct resource res; | |
443 | int rc = -ENOMEM; | |
444 | ||
445 | if (lpbfifo.dev != NULL) | |
446 | return -ENOSPC; | |
447 | ||
61c7a080 | 448 | lpbfifo.irq = irq_of_parse_and_map(op->dev.of_node, 0); |
3c9059d7 JB |
449 | if (!lpbfifo.irq) |
450 | return -ENODEV; | |
451 | ||
61c7a080 | 452 | if (of_address_to_resource(op->dev.of_node, 0, &res)) |
3c9059d7 JB |
453 | return -ENODEV; |
454 | lpbfifo.regs_phys = res.start; | |
61c7a080 | 455 | lpbfifo.regs = of_iomap(op->dev.of_node, 0); |
3c9059d7 JB |
456 | if (!lpbfifo.regs) |
457 | return -ENOMEM; | |
458 | ||
459 | spin_lock_init(&lpbfifo.lock); | |
460 | ||
461 | /* Put FIFO into reset */ | |
462 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | |
463 | ||
464 | /* Register the interrupt handler */ | |
465 | rc = request_irq(lpbfifo.irq, mpc52xx_lpbfifo_irq, 0, | |
466 | "mpc52xx-lpbfifo", &lpbfifo); | |
467 | if (rc) | |
468 | goto err_irq; | |
469 | ||
470 | /* Request the Bestcomm receive (fifo --> memory) task and IRQ */ | |
471 | lpbfifo.bcom_rx_task = | |
472 | bcom_gen_bd_rx_init(2, res.start + LPBFIFO_REG_FIFO_DATA, | |
473 | BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC, | |
474 | 16*1024*1024); | |
475 | if (!lpbfifo.bcom_rx_task) | |
476 | goto err_bcom_rx; | |
477 | ||
478 | rc = request_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), | |
479 | mpc52xx_lpbfifo_bcom_irq, 0, | |
480 | "mpc52xx-lpbfifo-rx", &lpbfifo); | |
481 | if (rc) | |
482 | goto err_bcom_rx_irq; | |
483 | ||
ed01f64b RF |
484 | lpbfifo.dma_irqs_enabled = 1; |
485 | ||
3c9059d7 JB |
486 | /* Request the Bestcomm transmit (memory --> fifo) task and IRQ */ |
487 | lpbfifo.bcom_tx_task = | |
488 | bcom_gen_bd_tx_init(2, res.start + LPBFIFO_REG_FIFO_DATA, | |
489 | BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC); | |
490 | if (!lpbfifo.bcom_tx_task) | |
491 | goto err_bcom_tx; | |
492 | ||
493 | lpbfifo.dev = &op->dev; | |
494 | return 0; | |
495 | ||
496 | err_bcom_tx: | |
497 | free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); | |
498 | err_bcom_rx_irq: | |
499 | bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task); | |
500 | err_bcom_rx: | |
501 | err_irq: | |
502 | iounmap(lpbfifo.regs); | |
503 | lpbfifo.regs = NULL; | |
504 | ||
505 | dev_err(&op->dev, "mpc52xx_lpbfifo_probe() failed\n"); | |
506 | return -ENODEV; | |
507 | } | |
508 | ||
509 | ||
510 | static int __devexit mpc52xx_lpbfifo_remove(struct of_device *op) | |
511 | { | |
512 | if (lpbfifo.dev != &op->dev) | |
513 | return 0; | |
514 | ||
515 | /* Put FIFO in reset */ | |
516 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | |
517 | ||
518 | /* Release the bestcomm transmit task */ | |
519 | free_irq(bcom_get_task_irq(lpbfifo.bcom_tx_task), &lpbfifo); | |
520 | bcom_gen_bd_tx_release(lpbfifo.bcom_tx_task); | |
521 | ||
522 | /* Release the bestcomm receive task */ | |
523 | free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); | |
524 | bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task); | |
525 | ||
526 | free_irq(lpbfifo.irq, &lpbfifo); | |
527 | iounmap(lpbfifo.regs); | |
528 | lpbfifo.regs = NULL; | |
529 | lpbfifo.dev = NULL; | |
530 | ||
531 | return 0; | |
532 | } | |
533 | ||
534 | static struct of_device_id mpc52xx_lpbfifo_match[] __devinitconst = { | |
535 | { .compatible = "fsl,mpc5200-lpbfifo", }, | |
536 | {}, | |
537 | }; | |
538 | ||
539 | static struct of_platform_driver mpc52xx_lpbfifo_driver = { | |
540 | .owner = THIS_MODULE, | |
541 | .name = "mpc52xx-lpbfifo", | |
542 | .match_table = mpc52xx_lpbfifo_match, | |
543 | .probe = mpc52xx_lpbfifo_probe, | |
544 | .remove = __devexit_p(mpc52xx_lpbfifo_remove), | |
545 | }; | |
546 | ||
547 | /*********************************************************************** | |
548 | * Module init/exit | |
549 | */ | |
550 | static int __init mpc52xx_lpbfifo_init(void) | |
551 | { | |
552 | pr_debug("Registering LocalPlus bus FIFO driver\n"); | |
553 | return of_register_platform_driver(&mpc52xx_lpbfifo_driver); | |
554 | } | |
555 | module_init(mpc52xx_lpbfifo_init); | |
556 | ||
557 | static void __exit mpc52xx_lpbfifo_exit(void) | |
558 | { | |
559 | pr_debug("Unregistering LocalPlus bus FIFO driver\n"); | |
560 | of_unregister_platform_driver(&mpc52xx_lpbfifo_driver); | |
561 | } | |
562 | module_exit(mpc52xx_lpbfifo_exit); |