]>
Commit | Line | Data |
---|---|---|
55716d26 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
3c9059d7 JB |
2 | /* |
3 | * LocalPlus Bus FIFO driver for the Freescale MPC52xx. | |
4 | * | |
5 | * Copyright (C) 2009 Secret Lab Technologies Ltd. | |
6 | * | |
3c9059d7 JB |
7 | * Todo: |
8 | * - Add support for multiple requests to be queued. | |
9 | */ | |
10 | ||
11 | #include <linux/interrupt.h> | |
12 | #include <linux/kernel.h> | |
13 | #include <linux/of.h> | |
14 | #include <linux/of_platform.h> | |
15 | #include <linux/spinlock.h> | |
7dfe293c | 16 | #include <linux/module.h> |
3c9059d7 JB |
17 | #include <asm/io.h> |
18 | #include <asm/prom.h> | |
19 | #include <asm/mpc52xx.h> | |
20 | #include <asm/time.h> | |
21 | ||
9a322993 PDM |
22 | #include <linux/fsl/bestcomm/bestcomm.h> |
23 | #include <linux/fsl/bestcomm/bestcomm_priv.h> | |
24 | #include <linux/fsl/bestcomm/gen_bd.h> | |
3c9059d7 JB |
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 | /** | |
25985edc | 60 | * mpc52xx_lpbfifo_kick - Trigger the next block of data to be transferred |
3c9059d7 JB |
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 */ | |
9d9fd887 AG |
172 | if (!lpbfifo.req->defer_xfer_start) |
173 | out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01); | |
3c9059d7 JB |
174 | if (dma) |
175 | bcom_enable(lpbfifo.bcom_cur_task); | |
176 | } | |
177 | ||
178 | /** | |
179 | * mpc52xx_lpbfifo_irq - IRQ handler for LPB FIFO | |
180 | * | |
181 | * On transmit, the dma completion irq triggers before the fifo completion | |
182 | * triggers. Handle the dma completion here instead of the LPB FIFO Bestcomm | |
25985edc | 183 | * task completion irq because everything is not really done until the LPB FIFO |
3c9059d7 JB |
184 | * completion irq triggers. |
185 | * | |
186 | * In other words: | |
187 | * For DMA, on receive, the "Fat Lady" is the bestcom completion irq. on | |
188 | * transmit, the fifo completion irq is the "Fat Lady". The opera (or in this | |
189 | * case the DMA/FIFO operation) is not finished until the "Fat Lady" sings. | |
190 | * | |
191 | * Reasons for entering this routine: | |
192 | * 1) PIO mode rx and tx completion irq | |
193 | * 2) DMA interrupt mode tx completion irq | |
194 | * 3) DMA polled mode tx | |
195 | * | |
196 | * Exit conditions: | |
197 | * 1) Transfer aborted | |
198 | * 2) FIFO complete without DMA; more data to do | |
25985edc | 199 | * 3) FIFO complete without DMA; all data transferred |
3c9059d7 JB |
200 | * 4) FIFO complete using DMA |
201 | * | |
202 | * Condition 1 can occur regardless of whether or not DMA is used. | |
203 | * It requires executing the callback to report the error and exiting | |
204 | * immediately. | |
205 | * | |
206 | * Condition 2 requires programming the FIFO with the next block of data | |
207 | * | |
208 | * Condition 3 requires executing the callback to report completion | |
209 | * | |
210 | * Condition 4 means the same as 3, except that we also retrieve the bcom | |
211 | * buffer so DMA doesn't get clogged up. | |
212 | * | |
213 | * To make things trickier, the spinlock must be dropped before | |
214 | * executing the callback, otherwise we could end up with a deadlock | |
215 | * or nested spinlock condition. The out path is non-trivial, so | |
216 | * extra fiddling is done to make sure all paths lead to the same | |
217 | * outbound code. | |
218 | */ | |
219 | static irqreturn_t mpc52xx_lpbfifo_irq(int irq, void *dev_id) | |
220 | { | |
221 | struct mpc52xx_lpbfifo_request *req; | |
222 | u32 status = in_8(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS); | |
223 | void __iomem *reg; | |
224 | u32 *data; | |
225 | int count, i; | |
226 | int do_callback = 0; | |
227 | u32 ts; | |
228 | unsigned long flags; | |
229 | int dma, write, poll_dma; | |
230 | ||
231 | spin_lock_irqsave(&lpbfifo.lock, flags); | |
232 | ts = get_tbl(); | |
233 | ||
234 | req = lpbfifo.req; | |
235 | if (!req) { | |
236 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
237 | pr_err("bogus LPBFIFO IRQ\n"); | |
238 | return IRQ_HANDLED; | |
239 | } | |
240 | ||
241 | dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); | |
242 | write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; | |
243 | poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; | |
244 | ||
245 | if (dma && !write) { | |
246 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
77d84ff8 | 247 | pr_err("bogus LPBFIFO IRQ (dma and not writing)\n"); |
3c9059d7 JB |
248 | return IRQ_HANDLED; |
249 | } | |
250 | ||
251 | if ((status & 0x01) == 0) { | |
252 | goto out; | |
253 | } | |
254 | ||
255 | /* check abort bit */ | |
256 | if (status & 0x10) { | |
257 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | |
258 | do_callback = 1; | |
259 | goto out; | |
260 | } | |
261 | ||
262 | /* Read result from hardware */ | |
263 | count = in_be32(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS); | |
264 | count &= 0x00ffffff; | |
265 | ||
266 | if (!dma && !write) { | |
267 | /* copy the data out of the FIFO */ | |
268 | reg = lpbfifo.regs + LPBFIFO_REG_FIFO_DATA; | |
269 | data = req->data + req->pos; | |
270 | for (i = 0; i < count; i += 4) | |
271 | *data++ = in_be32(reg); | |
272 | } | |
273 | ||
274 | /* Update transfer position and count */ | |
275 | req->pos += count; | |
276 | ||
277 | /* Decide what to do next */ | |
278 | if (req->size - req->pos) | |
279 | mpc52xx_lpbfifo_kick(req); /* more work to do */ | |
280 | else | |
281 | do_callback = 1; | |
282 | ||
283 | out: | |
284 | /* Clear the IRQ */ | |
285 | out_8(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS, 0x01); | |
286 | ||
287 | if (dma && (status & 0x11)) { | |
288 | /* | |
289 | * Count the DMA as complete only when the FIFO completion | |
290 | * status or abort bits are set. | |
291 | * | |
292 | * (status & 0x01) should always be the case except sometimes | |
293 | * when using polled DMA. | |
294 | * | |
295 | * (status & 0x10) {transfer aborted}: This case needs more | |
296 | * testing. | |
297 | */ | |
298 | bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL); | |
299 | } | |
300 | req->last_byte = ((u8 *)req->data)[req->size - 1]; | |
301 | ||
302 | /* When the do_callback flag is set; it means the transfer is finished | |
303 | * so set the FIFO as idle */ | |
304 | if (do_callback) | |
305 | lpbfifo.req = NULL; | |
306 | ||
307 | if (irq != 0) /* don't increment on polled case */ | |
308 | req->irq_count++; | |
309 | ||
310 | req->irq_ticks += get_tbl() - ts; | |
311 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
312 | ||
313 | /* Spinlock is released; it is now safe to call the callback */ | |
314 | if (do_callback && req->callback) | |
315 | req->callback(req); | |
316 | ||
317 | return IRQ_HANDLED; | |
318 | } | |
319 | ||
320 | /** | |
321 | * mpc52xx_lpbfifo_bcom_irq - IRQ handler for LPB FIFO Bestcomm task | |
322 | * | |
323 | * Only used when receiving data. | |
324 | */ | |
325 | static irqreturn_t mpc52xx_lpbfifo_bcom_irq(int irq, void *dev_id) | |
326 | { | |
327 | struct mpc52xx_lpbfifo_request *req; | |
328 | unsigned long flags; | |
329 | u32 status; | |
330 | u32 ts; | |
331 | ||
332 | spin_lock_irqsave(&lpbfifo.lock, flags); | |
333 | ts = get_tbl(); | |
334 | ||
335 | req = lpbfifo.req; | |
336 | if (!req || (req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA)) { | |
337 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
338 | return IRQ_HANDLED; | |
339 | } | |
340 | ||
341 | if (irq != 0) /* don't increment on polled case */ | |
342 | req->irq_count++; | |
343 | ||
344 | if (!bcom_buffer_done(lpbfifo.bcom_cur_task)) { | |
345 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
346 | ||
347 | req->buffer_not_done_cnt++; | |
348 | if ((req->buffer_not_done_cnt % 1000) == 0) | |
349 | pr_err("transfer stalled\n"); | |
350 | ||
351 | return IRQ_HANDLED; | |
352 | } | |
353 | ||
354 | bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL); | |
355 | ||
356 | req->last_byte = ((u8 *)req->data)[req->size - 1]; | |
357 | ||
358 | req->pos = status & 0x00ffffff; | |
359 | ||
360 | /* Mark the FIFO as idle */ | |
361 | lpbfifo.req = NULL; | |
362 | ||
363 | /* Release the lock before calling out to the callback. */ | |
364 | req->irq_ticks += get_tbl() - ts; | |
365 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
366 | ||
367 | if (req->callback) | |
368 | req->callback(req); | |
369 | ||
370 | return IRQ_HANDLED; | |
371 | } | |
372 | ||
373 | /** | |
374 | * mpc52xx_lpbfifo_bcom_poll - Poll for DMA completion | |
375 | */ | |
376 | void mpc52xx_lpbfifo_poll(void) | |
377 | { | |
378 | struct mpc52xx_lpbfifo_request *req = lpbfifo.req; | |
379 | int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); | |
380 | int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; | |
381 | ||
382 | /* | |
383 | * For more information, see comments on the "Fat Lady" | |
384 | */ | |
385 | if (dma && write) | |
386 | mpc52xx_lpbfifo_irq(0, NULL); | |
387 | else | |
388 | mpc52xx_lpbfifo_bcom_irq(0, NULL); | |
389 | } | |
390 | EXPORT_SYMBOL(mpc52xx_lpbfifo_poll); | |
391 | ||
392 | /** | |
393 | * mpc52xx_lpbfifo_submit - Submit an LPB FIFO transfer request. | |
394 | * @req: Pointer to request structure | |
395 | */ | |
396 | int mpc52xx_lpbfifo_submit(struct mpc52xx_lpbfifo_request *req) | |
397 | { | |
398 | unsigned long flags; | |
399 | ||
400 | if (!lpbfifo.regs) | |
401 | return -ENODEV; | |
402 | ||
403 | spin_lock_irqsave(&lpbfifo.lock, flags); | |
404 | ||
405 | /* If the req pointer is already set, then a transfer is in progress */ | |
406 | if (lpbfifo.req) { | |
407 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
408 | return -EBUSY; | |
409 | } | |
410 | ||
411 | /* Setup the transfer */ | |
412 | lpbfifo.req = req; | |
413 | req->irq_count = 0; | |
414 | req->irq_ticks = 0; | |
415 | req->buffer_not_done_cnt = 0; | |
416 | req->pos = 0; | |
417 | ||
418 | mpc52xx_lpbfifo_kick(req); | |
419 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
420 | return 0; | |
421 | } | |
422 | EXPORT_SYMBOL(mpc52xx_lpbfifo_submit); | |
423 | ||
9d9fd887 AG |
424 | int mpc52xx_lpbfifo_start_xfer(struct mpc52xx_lpbfifo_request *req) |
425 | { | |
426 | unsigned long flags; | |
427 | ||
428 | if (!lpbfifo.regs) | |
429 | return -ENODEV; | |
430 | ||
431 | spin_lock_irqsave(&lpbfifo.lock, flags); | |
432 | ||
433 | /* | |
434 | * If the req pointer is already set and a transfer was | |
435 | * started on submit, then this transfer is in progress | |
436 | */ | |
437 | if (lpbfifo.req && !lpbfifo.req->defer_xfer_start) { | |
438 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
439 | return -EBUSY; | |
440 | } | |
441 | ||
442 | /* | |
443 | * If the req was previously submitted but not | |
444 | * started, start it now | |
445 | */ | |
446 | if (lpbfifo.req && lpbfifo.req == req && | |
447 | lpbfifo.req->defer_xfer_start) { | |
448 | out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01); | |
449 | } | |
450 | ||
451 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
452 | return 0; | |
453 | } | |
454 | EXPORT_SYMBOL(mpc52xx_lpbfifo_start_xfer); | |
455 | ||
3c9059d7 JB |
456 | void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req) |
457 | { | |
458 | unsigned long flags; | |
459 | ||
460 | spin_lock_irqsave(&lpbfifo.lock, flags); | |
461 | if (lpbfifo.req == req) { | |
462 | /* Put it into reset and clear the state */ | |
463 | bcom_gen_bd_rx_reset(lpbfifo.bcom_rx_task); | |
464 | bcom_gen_bd_tx_reset(lpbfifo.bcom_tx_task); | |
465 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | |
466 | lpbfifo.req = NULL; | |
467 | } | |
468 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | |
469 | } | |
470 | EXPORT_SYMBOL(mpc52xx_lpbfifo_abort); | |
471 | ||
cad5cef6 | 472 | static int mpc52xx_lpbfifo_probe(struct platform_device *op) |
3c9059d7 JB |
473 | { |
474 | struct resource res; | |
475 | int rc = -ENOMEM; | |
476 | ||
477 | if (lpbfifo.dev != NULL) | |
478 | return -ENOSPC; | |
479 | ||
61c7a080 | 480 | lpbfifo.irq = irq_of_parse_and_map(op->dev.of_node, 0); |
3c9059d7 JB |
481 | if (!lpbfifo.irq) |
482 | return -ENODEV; | |
483 | ||
61c7a080 | 484 | if (of_address_to_resource(op->dev.of_node, 0, &res)) |
3c9059d7 JB |
485 | return -ENODEV; |
486 | lpbfifo.regs_phys = res.start; | |
61c7a080 | 487 | lpbfifo.regs = of_iomap(op->dev.of_node, 0); |
3c9059d7 JB |
488 | if (!lpbfifo.regs) |
489 | return -ENOMEM; | |
490 | ||
491 | spin_lock_init(&lpbfifo.lock); | |
492 | ||
493 | /* Put FIFO into reset */ | |
494 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | |
495 | ||
496 | /* Register the interrupt handler */ | |
497 | rc = request_irq(lpbfifo.irq, mpc52xx_lpbfifo_irq, 0, | |
498 | "mpc52xx-lpbfifo", &lpbfifo); | |
499 | if (rc) | |
500 | goto err_irq; | |
501 | ||
502 | /* Request the Bestcomm receive (fifo --> memory) task and IRQ */ | |
503 | lpbfifo.bcom_rx_task = | |
504 | bcom_gen_bd_rx_init(2, res.start + LPBFIFO_REG_FIFO_DATA, | |
505 | BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC, | |
506 | 16*1024*1024); | |
507 | if (!lpbfifo.bcom_rx_task) | |
508 | goto err_bcom_rx; | |
509 | ||
510 | rc = request_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), | |
511 | mpc52xx_lpbfifo_bcom_irq, 0, | |
512 | "mpc52xx-lpbfifo-rx", &lpbfifo); | |
513 | if (rc) | |
514 | goto err_bcom_rx_irq; | |
515 | ||
ed01f64b RF |
516 | lpbfifo.dma_irqs_enabled = 1; |
517 | ||
3c9059d7 JB |
518 | /* Request the Bestcomm transmit (memory --> fifo) task and IRQ */ |
519 | lpbfifo.bcom_tx_task = | |
520 | bcom_gen_bd_tx_init(2, res.start + LPBFIFO_REG_FIFO_DATA, | |
521 | BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC); | |
522 | if (!lpbfifo.bcom_tx_task) | |
523 | goto err_bcom_tx; | |
524 | ||
525 | lpbfifo.dev = &op->dev; | |
526 | return 0; | |
527 | ||
528 | err_bcom_tx: | |
529 | free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); | |
530 | err_bcom_rx_irq: | |
531 | bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task); | |
532 | err_bcom_rx: | |
533 | err_irq: | |
534 | iounmap(lpbfifo.regs); | |
535 | lpbfifo.regs = NULL; | |
536 | ||
537 | dev_err(&op->dev, "mpc52xx_lpbfifo_probe() failed\n"); | |
538 | return -ENODEV; | |
539 | } | |
540 | ||
541 | ||
cad5cef6 | 542 | static int mpc52xx_lpbfifo_remove(struct platform_device *op) |
3c9059d7 JB |
543 | { |
544 | if (lpbfifo.dev != &op->dev) | |
545 | return 0; | |
546 | ||
547 | /* Put FIFO in reset */ | |
548 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | |
549 | ||
550 | /* Release the bestcomm transmit task */ | |
551 | free_irq(bcom_get_task_irq(lpbfifo.bcom_tx_task), &lpbfifo); | |
552 | bcom_gen_bd_tx_release(lpbfifo.bcom_tx_task); | |
553 | ||
554 | /* Release the bestcomm receive task */ | |
555 | free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); | |
556 | bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task); | |
557 | ||
558 | free_irq(lpbfifo.irq, &lpbfifo); | |
559 | iounmap(lpbfifo.regs); | |
560 | lpbfifo.regs = NULL; | |
561 | lpbfifo.dev = NULL; | |
562 | ||
563 | return 0; | |
564 | } | |
565 | ||
ce6d73c9 | 566 | static const struct of_device_id mpc52xx_lpbfifo_match[] = { |
3c9059d7 JB |
567 | { .compatible = "fsl,mpc5200-lpbfifo", }, |
568 | {}, | |
569 | }; | |
7e610890 | 570 | MODULE_DEVICE_TABLE(of, mpc52xx_lpbfifo_match); |
3c9059d7 | 571 | |
00006124 | 572 | static struct platform_driver mpc52xx_lpbfifo_driver = { |
4018294b GL |
573 | .driver = { |
574 | .name = "mpc52xx-lpbfifo", | |
4018294b GL |
575 | .of_match_table = mpc52xx_lpbfifo_match, |
576 | }, | |
3c9059d7 | 577 | .probe = mpc52xx_lpbfifo_probe, |
cad5cef6 | 578 | .remove = mpc52xx_lpbfifo_remove, |
3c9059d7 | 579 | }; |
6c27b203 | 580 | module_platform_driver(mpc52xx_lpbfifo_driver); |