diff options
author | Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com> | 2011-09-30 07:07:38 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-10-13 13:38:39 -0400 |
commit | b8a56e17e18cca2402b390c10b8d7f3cd0f6265b (patch) | |
tree | 7587857c374fd360257814b24ed83d96e3b0019d | |
parent | 12158f4280b4d42ef03b70a47d11b48dd8aad511 (diff) |
usb: gadget: r8a66597-udc: add support for SUDMAC
SH7757 has a USB function with internal DMA controller (SUDMAC).
This patch supports the SUDMAC. The SUDMAC is incompatible with
general-purpose DMAC. So, it doesn't use dmaengine.
Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/gadget/r8a66597-udc.c | 364 | ||||
-rw-r--r-- | drivers/usb/gadget/r8a66597-udc.h | 26 | ||||
-rw-r--r-- | include/linux/usb/r8a66597.h | 60 |
3 files changed, 430 insertions, 20 deletions
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index 34abb12a88e8..035879b98dd9 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c | |||
@@ -18,13 +18,14 @@ | |||
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/dma-mapping.h> | ||
21 | 22 | ||
22 | #include <linux/usb/ch9.h> | 23 | #include <linux/usb/ch9.h> |
23 | #include <linux/usb/gadget.h> | 24 | #include <linux/usb/gadget.h> |
24 | 25 | ||
25 | #include "r8a66597-udc.h" | 26 | #include "r8a66597-udc.h" |
26 | 27 | ||
27 | #define DRIVER_VERSION "2009-08-18" | 28 | #define DRIVER_VERSION "2011-09-26" |
28 | 29 | ||
29 | static const char udc_name[] = "r8a66597_udc"; | 30 | static const char udc_name[] = "r8a66597_udc"; |
30 | static const char *r8a66597_ep_name[] = { | 31 | static const char *r8a66597_ep_name[] = { |
@@ -184,6 +185,54 @@ static inline void control_reg_sqclr(struct r8a66597 *r8a66597, u16 pipenum) | |||
184 | } | 185 | } |
185 | } | 186 | } |
186 | 187 | ||
188 | static void control_reg_sqset(struct r8a66597 *r8a66597, u16 pipenum) | ||
189 | { | ||
190 | unsigned long offset; | ||
191 | |||
192 | pipe_stop(r8a66597, pipenum); | ||
193 | |||
194 | if (pipenum == 0) { | ||
195 | r8a66597_bset(r8a66597, SQSET, DCPCTR); | ||
196 | } else if (pipenum < R8A66597_MAX_NUM_PIPE) { | ||
197 | offset = get_pipectr_addr(pipenum); | ||
198 | r8a66597_bset(r8a66597, SQSET, offset); | ||
199 | } else { | ||
200 | dev_err(r8a66597_to_dev(r8a66597), | ||
201 | "unexpect pipe num(%d)\n", pipenum); | ||
202 | } | ||
203 | } | ||
204 | |||
205 | static u16 control_reg_sqmon(struct r8a66597 *r8a66597, u16 pipenum) | ||
206 | { | ||
207 | unsigned long offset; | ||
208 | |||
209 | if (pipenum == 0) { | ||
210 | return r8a66597_read(r8a66597, DCPCTR) & SQMON; | ||
211 | } else if (pipenum < R8A66597_MAX_NUM_PIPE) { | ||
212 | offset = get_pipectr_addr(pipenum); | ||
213 | return r8a66597_read(r8a66597, offset) & SQMON; | ||
214 | } else { | ||
215 | dev_err(r8a66597_to_dev(r8a66597), | ||
216 | "unexpect pipe num(%d)\n", pipenum); | ||
217 | } | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static u16 save_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum) | ||
223 | { | ||
224 | return control_reg_sqmon(r8a66597, pipenum); | ||
225 | } | ||
226 | |||
227 | static void restore_usb_toggle(struct r8a66597 *r8a66597, u16 pipenum, | ||
228 | u16 toggle) | ||
229 | { | ||
230 | if (toggle) | ||
231 | control_reg_sqset(r8a66597, pipenum); | ||
232 | else | ||
233 | control_reg_sqclr(r8a66597, pipenum); | ||
234 | } | ||
235 | |||
187 | static inline int get_buffer_size(struct r8a66597 *r8a66597, u16 pipenum) | 236 | static inline int get_buffer_size(struct r8a66597 *r8a66597, u16 pipenum) |
188 | { | 237 | { |
189 | u16 tmp; | 238 | u16 tmp; |
@@ -220,18 +269,51 @@ static inline unsigned short mbw_value(struct r8a66597 *r8a66597) | |||
220 | return MBW_16; | 269 | return MBW_16; |
221 | } | 270 | } |
222 | 271 | ||
272 | static void r8a66597_change_curpipe(struct r8a66597 *r8a66597, u16 pipenum, | ||
273 | u16 isel, u16 fifosel) | ||
274 | { | ||
275 | u16 tmp, mask, loop; | ||
276 | int i = 0; | ||
277 | |||
278 | if (!pipenum) { | ||
279 | mask = ISEL | CURPIPE; | ||
280 | loop = isel; | ||
281 | } else { | ||
282 | mask = CURPIPE; | ||
283 | loop = pipenum; | ||
284 | } | ||
285 | r8a66597_mdfy(r8a66597, loop, mask, fifosel); | ||
286 | |||
287 | do { | ||
288 | tmp = r8a66597_read(r8a66597, fifosel); | ||
289 | if (i++ > 1000000) { | ||
290 | dev_err(r8a66597_to_dev(r8a66597), | ||
291 | "r8a66597: register%x, loop %x " | ||
292 | "is timeout\n", fifosel, loop); | ||
293 | break; | ||
294 | } | ||
295 | ndelay(1); | ||
296 | } while ((tmp & mask) != loop); | ||
297 | } | ||
298 | |||
223 | static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) | 299 | static inline void pipe_change(struct r8a66597 *r8a66597, u16 pipenum) |
224 | { | 300 | { |
225 | struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; | 301 | struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; |
226 | 302 | ||
227 | if (ep->use_dma) | 303 | if (ep->use_dma) |
228 | return; | 304 | r8a66597_bclr(r8a66597, DREQE, ep->fifosel); |
229 | 305 | ||
230 | r8a66597_mdfy(r8a66597, pipenum, CURPIPE, ep->fifosel); | 306 | r8a66597_mdfy(r8a66597, pipenum, CURPIPE, ep->fifosel); |
231 | 307 | ||
232 | ndelay(450); | 308 | ndelay(450); |
233 | 309 | ||
234 | r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel); | 310 | if (r8a66597_is_sudmac(r8a66597) && ep->use_dma) |
311 | r8a66597_bclr(r8a66597, mbw_value(r8a66597), ep->fifosel); | ||
312 | else | ||
313 | r8a66597_bset(r8a66597, mbw_value(r8a66597), ep->fifosel); | ||
314 | |||
315 | if (ep->use_dma) | ||
316 | r8a66597_bset(r8a66597, DREQE, ep->fifosel); | ||
235 | } | 317 | } |
236 | 318 | ||
237 | static int pipe_buffer_setting(struct r8a66597 *r8a66597, | 319 | static int pipe_buffer_setting(struct r8a66597 *r8a66597, |
@@ -336,9 +418,15 @@ static void r8a66597_ep_setting(struct r8a66597 *r8a66597, | |||
336 | ep->fifoaddr = CFIFO; | 418 | ep->fifoaddr = CFIFO; |
337 | ep->fifosel = CFIFOSEL; | 419 | ep->fifosel = CFIFOSEL; |
338 | ep->fifoctr = CFIFOCTR; | 420 | ep->fifoctr = CFIFOCTR; |
339 | ep->fifotrn = 0; | ||
340 | 421 | ||
341 | ep->pipectr = get_pipectr_addr(pipenum); | 422 | ep->pipectr = get_pipectr_addr(pipenum); |
423 | if (is_bulk_pipe(pipenum) || is_isoc_pipe(pipenum)) { | ||
424 | ep->pipetre = get_pipetre_addr(pipenum); | ||
425 | ep->pipetrn = get_pipetrn_addr(pipenum); | ||
426 | } else { | ||
427 | ep->pipetre = 0; | ||
428 | ep->pipetrn = 0; | ||
429 | } | ||
342 | ep->pipenum = pipenum; | 430 | ep->pipenum = pipenum; |
343 | ep->ep.maxpacket = usb_endpoint_maxp(desc); | 431 | ep->ep.maxpacket = usb_endpoint_maxp(desc); |
344 | r8a66597->pipenum2ep[pipenum] = ep; | 432 | r8a66597->pipenum2ep[pipenum] = ep; |
@@ -498,6 +586,124 @@ static void start_ep0_write(struct r8a66597_ep *ep, | |||
498 | } | 586 | } |
499 | } | 587 | } |
500 | 588 | ||
589 | static void disable_fifosel(struct r8a66597 *r8a66597, u16 pipenum, | ||
590 | u16 fifosel) | ||
591 | { | ||
592 | u16 tmp; | ||
593 | |||
594 | tmp = r8a66597_read(r8a66597, fifosel) & CURPIPE; | ||
595 | if (tmp == pipenum) | ||
596 | r8a66597_change_curpipe(r8a66597, 0, 0, fifosel); | ||
597 | } | ||
598 | |||
599 | static void change_bfre_mode(struct r8a66597 *r8a66597, u16 pipenum, | ||
600 | int enable) | ||
601 | { | ||
602 | struct r8a66597_ep *ep = r8a66597->pipenum2ep[pipenum]; | ||
603 | u16 tmp, toggle; | ||
604 | |||
605 | /* check current BFRE bit */ | ||
606 | r8a66597_write(r8a66597, pipenum, PIPESEL); | ||
607 | tmp = r8a66597_read(r8a66597, PIPECFG) & R8A66597_BFRE; | ||
608 | if ((enable && tmp) || (!enable && !tmp)) | ||
609 | return; | ||
610 | |||
611 | /* change BFRE bit */ | ||
612 | pipe_stop(r8a66597, pipenum); | ||
613 | disable_fifosel(r8a66597, pipenum, CFIFOSEL); | ||
614 | disable_fifosel(r8a66597, pipenum, D0FIFOSEL); | ||
615 | disable_fifosel(r8a66597, pipenum, D1FIFOSEL); | ||
616 | |||
617 | toggle = save_usb_toggle(r8a66597, pipenum); | ||
618 | |||
619 | r8a66597_write(r8a66597, pipenum, PIPESEL); | ||
620 | if (enable) | ||
621 | r8a66597_bset(r8a66597, R8A66597_BFRE, PIPECFG); | ||
622 | else | ||
623 | r8a66597_bclr(r8a66597, R8A66597_BFRE, PIPECFG); | ||
624 | |||
625 | /* initialize for internal BFRE flag */ | ||
626 | r8a66597_bset(r8a66597, ACLRM, ep->pipectr); | ||
627 | r8a66597_bclr(r8a66597, ACLRM, ep->pipectr); | ||
628 | |||
629 | restore_usb_toggle(r8a66597, pipenum, toggle); | ||
630 | } | ||
631 | |||
632 | static int sudmac_alloc_channel(struct r8a66597 *r8a66597, | ||
633 | struct r8a66597_ep *ep, | ||
634 | struct r8a66597_request *req) | ||
635 | { | ||
636 | struct r8a66597_dma *dma; | ||
637 | |||
638 | if (!r8a66597_is_sudmac(r8a66597)) | ||
639 | return -ENODEV; | ||
640 | |||
641 | /* Check transfer type */ | ||
642 | if (!is_bulk_pipe(ep->pipenum)) | ||
643 | return -EIO; | ||
644 | |||
645 | if (r8a66597->dma.used) | ||
646 | return -EBUSY; | ||
647 | |||
648 | /* set SUDMAC parameters */ | ||
649 | dma = &r8a66597->dma; | ||
650 | dma->used = 1; | ||
651 | if (ep->desc->bEndpointAddress & USB_DIR_IN) { | ||
652 | dma->dir = 1; | ||
653 | } else { | ||
654 | dma->dir = 0; | ||
655 | change_bfre_mode(r8a66597, ep->pipenum, 1); | ||
656 | } | ||
657 | |||
658 | /* set r8a66597_ep paramters */ | ||
659 | ep->use_dma = 1; | ||
660 | ep->dma = dma; | ||
661 | ep->fifoaddr = D0FIFO; | ||
662 | ep->fifosel = D0FIFOSEL; | ||
663 | ep->fifoctr = D0FIFOCTR; | ||
664 | |||
665 | /* dma mapping */ | ||
666 | req->req.dma = dma_map_single(r8a66597_to_dev(ep->r8a66597), | ||
667 | req->req.buf, req->req.length, | ||
668 | dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); | ||
669 | |||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static void sudmac_free_channel(struct r8a66597 *r8a66597, | ||
674 | struct r8a66597_ep *ep, | ||
675 | struct r8a66597_request *req) | ||
676 | { | ||
677 | if (!r8a66597_is_sudmac(r8a66597)) | ||
678 | return; | ||
679 | |||
680 | dma_unmap_single(r8a66597_to_dev(ep->r8a66597), | ||
681 | req->req.dma, req->req.length, | ||
682 | ep->dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); | ||
683 | |||
684 | r8a66597_bclr(r8a66597, DREQE, ep->fifosel); | ||
685 | r8a66597_change_curpipe(r8a66597, 0, 0, ep->fifosel); | ||
686 | |||
687 | ep->dma->used = 0; | ||
688 | ep->use_dma = 0; | ||
689 | ep->fifoaddr = CFIFO; | ||
690 | ep->fifosel = CFIFOSEL; | ||
691 | ep->fifoctr = CFIFOCTR; | ||
692 | } | ||
693 | |||
694 | static void sudmac_start(struct r8a66597 *r8a66597, struct r8a66597_ep *ep, | ||
695 | struct r8a66597_request *req) | ||
696 | { | ||
697 | BUG_ON(req->req.length == 0); | ||
698 | |||
699 | r8a66597_sudmac_write(r8a66597, LBA_WAIT, CH0CFG); | ||
700 | r8a66597_sudmac_write(r8a66597, req->req.dma, CH0BA); | ||
701 | r8a66597_sudmac_write(r8a66597, req->req.length, CH0BBC); | ||
702 | r8a66597_sudmac_write(r8a66597, CH0ENDE, DINTCTRL); | ||
703 | |||
704 | r8a66597_sudmac_write(r8a66597, DEN, CH0DEN); | ||
705 | } | ||
706 | |||
501 | static void start_packet_write(struct r8a66597_ep *ep, | 707 | static void start_packet_write(struct r8a66597_ep *ep, |
502 | struct r8a66597_request *req) | 708 | struct r8a66597_request *req) |
503 | { | 709 | { |
@@ -508,11 +714,29 @@ static void start_packet_write(struct r8a66597_ep *ep, | |||
508 | disable_irq_empty(r8a66597, ep->pipenum); | 714 | disable_irq_empty(r8a66597, ep->pipenum); |
509 | pipe_start(r8a66597, ep->pipenum); | 715 | pipe_start(r8a66597, ep->pipenum); |
510 | 716 | ||
511 | tmp = r8a66597_read(r8a66597, ep->fifoctr); | 717 | if (req->req.length == 0) { |
512 | if (unlikely((tmp & FRDY) == 0)) | 718 | transfer_complete(ep, req, 0); |
513 | pipe_irq_enable(r8a66597, ep->pipenum); | 719 | } else { |
514 | else | 720 | r8a66597_write(r8a66597, ~(1 << ep->pipenum), BRDYSTS); |
515 | irq_packet_write(ep, req); | 721 | if (sudmac_alloc_channel(r8a66597, ep, req) < 0) { |
722 | /* PIO mode */ | ||
723 | pipe_change(r8a66597, ep->pipenum); | ||
724 | disable_irq_empty(r8a66597, ep->pipenum); | ||
725 | pipe_start(r8a66597, ep->pipenum); | ||
726 | tmp = r8a66597_read(r8a66597, ep->fifoctr); | ||
727 | if (unlikely((tmp & FRDY) == 0)) | ||
728 | pipe_irq_enable(r8a66597, ep->pipenum); | ||
729 | else | ||
730 | irq_packet_write(ep, req); | ||
731 | } else { | ||
732 | /* DMA mode */ | ||
733 | pipe_change(r8a66597, ep->pipenum); | ||
734 | disable_irq_nrdy(r8a66597, ep->pipenum); | ||
735 | pipe_start(r8a66597, ep->pipenum); | ||
736 | enable_irq_nrdy(r8a66597, ep->pipenum); | ||
737 | sudmac_start(r8a66597, ep, req); | ||
738 | } | ||
739 | } | ||
516 | } | 740 | } |
517 | 741 | ||
518 | static void start_packet_read(struct r8a66597_ep *ep, | 742 | static void start_packet_read(struct r8a66597_ep *ep, |
@@ -527,17 +751,26 @@ static void start_packet_read(struct r8a66597_ep *ep, | |||
527 | pipe_start(r8a66597, pipenum); | 751 | pipe_start(r8a66597, pipenum); |
528 | pipe_irq_enable(r8a66597, pipenum); | 752 | pipe_irq_enable(r8a66597, pipenum); |
529 | } else { | 753 | } else { |
530 | if (ep->use_dma) { | 754 | pipe_stop(r8a66597, pipenum); |
531 | r8a66597_bset(r8a66597, TRCLR, ep->fifosel); | 755 | if (ep->pipetre) { |
532 | pipe_change(r8a66597, pipenum); | 756 | enable_irq_nrdy(r8a66597, pipenum); |
533 | r8a66597_bset(r8a66597, TRENB, ep->fifosel); | 757 | r8a66597_write(r8a66597, TRCLR, ep->pipetre); |
534 | r8a66597_write(r8a66597, | 758 | r8a66597_write(r8a66597, |
535 | (req->req.length + ep->ep.maxpacket - 1) | 759 | DIV_ROUND_UP(req->req.length, ep->ep.maxpacket), |
536 | / ep->ep.maxpacket, | 760 | ep->pipetrn); |
537 | ep->fifotrn); | 761 | r8a66597_bset(r8a66597, TRENB, ep->pipetre); |
762 | } | ||
763 | |||
764 | if (sudmac_alloc_channel(r8a66597, ep, req) < 0) { | ||
765 | /* PIO mode */ | ||
766 | change_bfre_mode(r8a66597, ep->pipenum, 0); | ||
767 | pipe_start(r8a66597, pipenum); /* trigger once */ | ||
768 | pipe_irq_enable(r8a66597, pipenum); | ||
769 | } else { | ||
770 | pipe_change(r8a66597, pipenum); | ||
771 | sudmac_start(r8a66597, ep, req); | ||
772 | pipe_start(r8a66597, pipenum); /* trigger once */ | ||
538 | } | 773 | } |
539 | pipe_start(r8a66597, pipenum); /* trigger once */ | ||
540 | pipe_irq_enable(r8a66597, pipenum); | ||
541 | } | 774 | } |
542 | } | 775 | } |
543 | 776 | ||
@@ -694,6 +927,9 @@ __acquires(r8a66597->lock) | |||
694 | if (!list_empty(&ep->queue)) | 927 | if (!list_empty(&ep->queue)) |
695 | restart = 1; | 928 | restart = 1; |
696 | 929 | ||
930 | if (ep->use_dma) | ||
931 | sudmac_free_channel(ep->r8a66597, ep, req); | ||
932 | |||
697 | spin_unlock(&ep->r8a66597->lock); | 933 | spin_unlock(&ep->r8a66597->lock); |
698 | req->req.complete(&ep->ep, &req->req); | 934 | req->req.complete(&ep->ep, &req->req); |
699 | spin_lock(&ep->r8a66597->lock); | 935 | spin_lock(&ep->r8a66597->lock); |
@@ -1170,6 +1406,65 @@ __acquires(r8a66597->lock) | |||
1170 | } | 1406 | } |
1171 | } | 1407 | } |
1172 | 1408 | ||
1409 | static void sudmac_finish(struct r8a66597 *r8a66597, struct r8a66597_ep *ep) | ||
1410 | { | ||
1411 | u16 pipenum; | ||
1412 | struct r8a66597_request *req; | ||
1413 | u32 len; | ||
1414 | int i = 0; | ||
1415 | |||
1416 | pipenum = ep->pipenum; | ||
1417 | pipe_change(r8a66597, pipenum); | ||
1418 | |||
1419 | while (!(r8a66597_read(r8a66597, ep->fifoctr) & FRDY)) { | ||
1420 | udelay(1); | ||
1421 | if (unlikely(i++ >= 10000)) { /* timeout = 10 msec */ | ||
1422 | dev_err(r8a66597_to_dev(r8a66597), | ||
1423 | "%s: FRDY was not set (%d)\n", | ||
1424 | __func__, pipenum); | ||
1425 | return; | ||
1426 | } | ||
1427 | } | ||
1428 | |||
1429 | r8a66597_bset(r8a66597, BCLR, ep->fifoctr); | ||
1430 | req = get_request_from_ep(ep); | ||
1431 | |||
1432 | /* prepare parameters */ | ||
1433 | len = r8a66597_sudmac_read(r8a66597, CH0CBC); | ||
1434 | req->req.actual += len; | ||
1435 | |||
1436 | /* clear */ | ||
1437 | r8a66597_sudmac_write(r8a66597, CH0STCLR, DSTSCLR); | ||
1438 | |||
1439 | /* check transfer finish */ | ||
1440 | if ((!req->req.zero && (req->req.actual == req->req.length)) | ||
1441 | || (len % ep->ep.maxpacket)) { | ||
1442 | if (ep->dma->dir) { | ||
1443 | disable_irq_ready(r8a66597, pipenum); | ||
1444 | enable_irq_empty(r8a66597, pipenum); | ||
1445 | } else { | ||
1446 | /* Clear the interrupt flag for next transfer */ | ||
1447 | r8a66597_write(r8a66597, ~(1 << pipenum), BRDYSTS); | ||
1448 | transfer_complete(ep, req, 0); | ||
1449 | } | ||
1450 | } | ||
1451 | } | ||
1452 | |||
1453 | static void r8a66597_sudmac_irq(struct r8a66597 *r8a66597) | ||
1454 | { | ||
1455 | u32 irqsts; | ||
1456 | struct r8a66597_ep *ep; | ||
1457 | u16 pipenum; | ||
1458 | |||
1459 | irqsts = r8a66597_sudmac_read(r8a66597, DINTSTS); | ||
1460 | if (irqsts & CH0ENDS) { | ||
1461 | r8a66597_sudmac_write(r8a66597, CH0ENDC, DINTSTSCLR); | ||
1462 | pipenum = (r8a66597_read(r8a66597, D0FIFOSEL) & CURPIPE); | ||
1463 | ep = r8a66597->pipenum2ep[pipenum]; | ||
1464 | sudmac_finish(r8a66597, ep); | ||
1465 | } | ||
1466 | } | ||
1467 | |||
1173 | static irqreturn_t r8a66597_irq(int irq, void *_r8a66597) | 1468 | static irqreturn_t r8a66597_irq(int irq, void *_r8a66597) |
1174 | { | 1469 | { |
1175 | struct r8a66597 *r8a66597 = _r8a66597; | 1470 | struct r8a66597 *r8a66597 = _r8a66597; |
@@ -1180,6 +1475,9 @@ static irqreturn_t r8a66597_irq(int irq, void *_r8a66597) | |||
1180 | u16 savepipe; | 1475 | u16 savepipe; |
1181 | u16 mask0; | 1476 | u16 mask0; |
1182 | 1477 | ||
1478 | if (r8a66597_is_sudmac(r8a66597)) | ||
1479 | r8a66597_sudmac_irq(r8a66597); | ||
1480 | |||
1183 | spin_lock(&r8a66597->lock); | 1481 | spin_lock(&r8a66597->lock); |
1184 | 1482 | ||
1185 | intsts0 = r8a66597_read(r8a66597, INTSTS0); | 1483 | intsts0 = r8a66597_read(r8a66597, INTSTS0); |
@@ -1556,6 +1854,8 @@ static int __exit r8a66597_remove(struct platform_device *pdev) | |||
1556 | usb_del_gadget_udc(&r8a66597->gadget); | 1854 | usb_del_gadget_udc(&r8a66597->gadget); |
1557 | del_timer_sync(&r8a66597->timer); | 1855 | del_timer_sync(&r8a66597->timer); |
1558 | iounmap(r8a66597->reg); | 1856 | iounmap(r8a66597->reg); |
1857 | if (r8a66597->pdata->sudmac) | ||
1858 | iounmap(r8a66597->sudmac_reg); | ||
1559 | free_irq(platform_get_irq(pdev, 0), r8a66597); | 1859 | free_irq(platform_get_irq(pdev, 0), r8a66597); |
1560 | r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); | 1860 | r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req); |
1561 | #ifdef CONFIG_HAVE_CLK | 1861 | #ifdef CONFIG_HAVE_CLK |
@@ -1572,6 +1872,26 @@ static void nop_completion(struct usb_ep *ep, struct usb_request *r) | |||
1572 | { | 1872 | { |
1573 | } | 1873 | } |
1574 | 1874 | ||
1875 | static int __init r8a66597_sudmac_ioremap(struct r8a66597 *r8a66597, | ||
1876 | struct platform_device *pdev) | ||
1877 | { | ||
1878 | struct resource *res; | ||
1879 | |||
1880 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sudmac"); | ||
1881 | if (!res) { | ||
1882 | dev_err(&pdev->dev, "platform_get_resource error(sudmac).\n"); | ||
1883 | return -ENODEV; | ||
1884 | } | ||
1885 | |||
1886 | r8a66597->sudmac_reg = ioremap(res->start, resource_size(res)); | ||
1887 | if (r8a66597->sudmac_reg == NULL) { | ||
1888 | dev_err(&pdev->dev, "ioremap error(sudmac).\n"); | ||
1889 | return -ENOMEM; | ||
1890 | } | ||
1891 | |||
1892 | return 0; | ||
1893 | } | ||
1894 | |||
1575 | static int __init r8a66597_probe(struct platform_device *pdev) | 1895 | static int __init r8a66597_probe(struct platform_device *pdev) |
1576 | { | 1896 | { |
1577 | #ifdef CONFIG_HAVE_CLK | 1897 | #ifdef CONFIG_HAVE_CLK |
@@ -1649,6 +1969,11 @@ static int __init r8a66597_probe(struct platform_device *pdev) | |||
1649 | clk_enable(r8a66597->clk); | 1969 | clk_enable(r8a66597->clk); |
1650 | } | 1970 | } |
1651 | #endif | 1971 | #endif |
1972 | if (r8a66597->pdata->sudmac) { | ||
1973 | ret = r8a66597_sudmac_ioremap(r8a66597, pdev); | ||
1974 | if (ret < 0) | ||
1975 | goto clean_up2; | ||
1976 | } | ||
1652 | 1977 | ||
1653 | disable_controller(r8a66597); /* make sure controller is disabled */ | 1978 | disable_controller(r8a66597); /* make sure controller is disabled */ |
1654 | 1979 | ||
@@ -1681,7 +2006,6 @@ static int __init r8a66597_probe(struct platform_device *pdev) | |||
1681 | r8a66597->ep[0].fifoaddr = CFIFO; | 2006 | r8a66597->ep[0].fifoaddr = CFIFO; |
1682 | r8a66597->ep[0].fifosel = CFIFOSEL; | 2007 | r8a66597->ep[0].fifosel = CFIFOSEL; |
1683 | r8a66597->ep[0].fifoctr = CFIFOCTR; | 2008 | r8a66597->ep[0].fifoctr = CFIFOCTR; |
1684 | r8a66597->ep[0].fifotrn = 0; | ||
1685 | r8a66597->ep[0].pipectr = get_pipectr_addr(0); | 2009 | r8a66597->ep[0].pipectr = get_pipectr_addr(0); |
1686 | r8a66597->pipenum2ep[0] = &r8a66597->ep[0]; | 2010 | r8a66597->pipenum2ep[0] = &r8a66597->ep[0]; |
1687 | r8a66597->epaddr2ep[0] = &r8a66597->ep[0]; | 2011 | r8a66597->epaddr2ep[0] = &r8a66597->ep[0]; |
@@ -1714,6 +2038,8 @@ clean_up2: | |||
1714 | #endif | 2038 | #endif |
1715 | clean_up: | 2039 | clean_up: |
1716 | if (r8a66597) { | 2040 | if (r8a66597) { |
2041 | if (r8a66597->sudmac_reg) | ||
2042 | iounmap(r8a66597->sudmac_reg); | ||
1717 | if (r8a66597->ep0_req) | 2043 | if (r8a66597->ep0_req) |
1718 | r8a66597_free_request(&r8a66597->ep[0].ep, | 2044 | r8a66597_free_request(&r8a66597->ep[0].ep, |
1719 | r8a66597->ep0_req); | 2045 | r8a66597->ep0_req); |
diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 832ee59c8e45..8e3de61cd4b8 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h | |||
@@ -43,6 +43,7 @@ | |||
43 | ((pipenum >= R8A66597_BASE_PIPENUM_ISOC) && \ | 43 | ((pipenum >= R8A66597_BASE_PIPENUM_ISOC) && \ |
44 | (pipenum < (R8A66597_BASE_PIPENUM_ISOC + R8A66597_MAX_NUM_ISOC))) | 44 | (pipenum < (R8A66597_BASE_PIPENUM_ISOC + R8A66597_MAX_NUM_ISOC))) |
45 | 45 | ||
46 | #define r8a66597_is_sudmac(r8a66597) (r8a66597->pdata->sudmac) | ||
46 | struct r8a66597_pipe_info { | 47 | struct r8a66597_pipe_info { |
47 | u16 pipe; | 48 | u16 pipe; |
48 | u16 epnum; | 49 | u16 epnum; |
@@ -60,6 +61,7 @@ struct r8a66597_request { | |||
60 | struct r8a66597_ep { | 61 | struct r8a66597_ep { |
61 | struct usb_ep ep; | 62 | struct usb_ep ep; |
62 | struct r8a66597 *r8a66597; | 63 | struct r8a66597 *r8a66597; |
64 | struct r8a66597_dma *dma; | ||
63 | 65 | ||
64 | struct list_head queue; | 66 | struct list_head queue; |
65 | unsigned busy:1; | 67 | unsigned busy:1; |
@@ -75,13 +77,20 @@ struct r8a66597_ep { | |||
75 | unsigned char fifoaddr; | 77 | unsigned char fifoaddr; |
76 | unsigned char fifosel; | 78 | unsigned char fifosel; |
77 | unsigned char fifoctr; | 79 | unsigned char fifoctr; |
78 | unsigned char fifotrn; | ||
79 | unsigned char pipectr; | 80 | unsigned char pipectr; |
81 | unsigned char pipetre; | ||
82 | unsigned char pipetrn; | ||
83 | }; | ||
84 | |||
85 | struct r8a66597_dma { | ||
86 | unsigned used:1; | ||
87 | unsigned dir:1; /* 1 = IN(write), 0 = OUT(read) */ | ||
80 | }; | 88 | }; |
81 | 89 | ||
82 | struct r8a66597 { | 90 | struct r8a66597 { |
83 | spinlock_t lock; | 91 | spinlock_t lock; |
84 | void __iomem *reg; | 92 | void __iomem *reg; |
93 | void __iomem *sudmac_reg; | ||
85 | 94 | ||
86 | #ifdef CONFIG_HAVE_CLK | 95 | #ifdef CONFIG_HAVE_CLK |
87 | struct clk *clk; | 96 | struct clk *clk; |
@@ -94,6 +103,7 @@ struct r8a66597 { | |||
94 | struct r8a66597_ep ep[R8A66597_MAX_NUM_PIPE]; | 103 | struct r8a66597_ep ep[R8A66597_MAX_NUM_PIPE]; |
95 | struct r8a66597_ep *pipenum2ep[R8A66597_MAX_NUM_PIPE]; | 104 | struct r8a66597_ep *pipenum2ep[R8A66597_MAX_NUM_PIPE]; |
96 | struct r8a66597_ep *epaddr2ep[16]; | 105 | struct r8a66597_ep *epaddr2ep[16]; |
106 | struct r8a66597_dma dma; | ||
97 | 107 | ||
98 | struct timer_list timer; | 108 | struct timer_list timer; |
99 | struct usb_request *ep0_req; /* for internal request */ | 109 | struct usb_request *ep0_req; /* for internal request */ |
@@ -251,7 +261,21 @@ static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata) | |||
251 | return clock; | 261 | return clock; |
252 | } | 262 | } |
253 | 263 | ||
264 | static inline u32 r8a66597_sudmac_read(struct r8a66597 *r8a66597, | ||
265 | unsigned long offset) | ||
266 | { | ||
267 | return ioread32(r8a66597->sudmac_reg + offset); | ||
268 | } | ||
269 | |||
270 | static inline void r8a66597_sudmac_write(struct r8a66597 *r8a66597, u32 val, | ||
271 | unsigned long offset) | ||
272 | { | ||
273 | iowrite32(val, r8a66597->sudmac_reg + offset); | ||
274 | } | ||
275 | |||
254 | #define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2) | 276 | #define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2) |
277 | #define get_pipetre_addr(pipenum) (PIPE1TRE + (pipenum - 1) * 4) | ||
278 | #define get_pipetrn_addr(pipenum) (PIPE1TRN + (pipenum - 1) * 4) | ||
255 | 279 | ||
256 | #define enable_irq_ready(r8a66597, pipenum) \ | 280 | #define enable_irq_ready(r8a66597, pipenum) \ |
257 | enable_pipe_irq(r8a66597, pipenum, BRDYENB) | 281 | enable_pipe_irq(r8a66597, pipenum, BRDYENB) |
diff --git a/include/linux/usb/r8a66597.h b/include/linux/usb/r8a66597.h index b6b8660d0c68..55805f9dcf21 100644 --- a/include/linux/usb/r8a66597.h +++ b/include/linux/usb/r8a66597.h | |||
@@ -48,6 +48,9 @@ struct r8a66597_platdata { | |||
48 | 48 | ||
49 | /* (external controller only) set one = WR0_N shorted to WR1_N */ | 49 | /* (external controller only) set one = WR0_N shorted to WR1_N */ |
50 | unsigned wr0_shorted_to_wr1:1; | 50 | unsigned wr0_shorted_to_wr1:1; |
51 | |||
52 | /* set one = using SUDMAC */ | ||
53 | unsigned sudmac:1; | ||
51 | }; | 54 | }; |
52 | 55 | ||
53 | /* Register definitions */ | 56 | /* Register definitions */ |
@@ -417,5 +420,62 @@ struct r8a66597_platdata { | |||
417 | #define USBSPD 0x00C0 | 420 | #define USBSPD 0x00C0 |
418 | #define RTPORT 0x0001 | 421 | #define RTPORT 0x0001 |
419 | 422 | ||
423 | /* SUDMAC registers */ | ||
424 | #define CH0CFG 0x00 | ||
425 | #define CH1CFG 0x04 | ||
426 | #define CH0BA 0x10 | ||
427 | #define CH1BA 0x14 | ||
428 | #define CH0BBC 0x18 | ||
429 | #define CH1BBC 0x1C | ||
430 | #define CH0CA 0x20 | ||
431 | #define CH1CA 0x24 | ||
432 | #define CH0CBC 0x28 | ||
433 | #define CH1CBC 0x2C | ||
434 | #define CH0DEN 0x30 | ||
435 | #define CH1DEN 0x34 | ||
436 | #define DSTSCLR 0x38 | ||
437 | #define DBUFCTRL 0x3C | ||
438 | #define DINTCTRL 0x40 | ||
439 | #define DINTSTS 0x44 | ||
440 | #define DINTSTSCLR 0x48 | ||
441 | #define CH0SHCTRL 0x50 | ||
442 | #define CH1SHCTRL 0x54 | ||
443 | |||
444 | /* SUDMAC Configuration Registers */ | ||
445 | #define SENDBUFM 0x1000 /* b12: Transmit Buffer Mode */ | ||
446 | #define RCVENDM 0x0100 /* b8: Receive Data Transfer End Mode */ | ||
447 | #define LBA_WAIT 0x0030 /* b5-4: Local Bus Access Wait */ | ||
448 | |||
449 | /* DMA Enable Registers */ | ||
450 | #define DEN 0x0001 /* b1: DMA Transfer Enable */ | ||
451 | |||
452 | /* DMA Status Clear Register */ | ||
453 | #define CH1STCLR 0x0002 /* b2: Ch1 DMA Status Clear */ | ||
454 | #define CH0STCLR 0x0001 /* b1: Ch0 DMA Status Clear */ | ||
455 | |||
456 | /* DMA Buffer Control Register */ | ||
457 | #define CH1BUFW 0x0200 /* b9: Ch1 DMA Buffer Data Transfer Enable */ | ||
458 | #define CH0BUFW 0x0100 /* b8: Ch0 DMA Buffer Data Transfer Enable */ | ||
459 | #define CH1BUFS 0x0002 /* b2: Ch1 DMA Buffer Data Status */ | ||
460 | #define CH0BUFS 0x0001 /* b1: Ch0 DMA Buffer Data Status */ | ||
461 | |||
462 | /* DMA Interrupt Control Register */ | ||
463 | #define CH1ERRE 0x0200 /* b9: Ch1 SHwy Res Err Detect Int Enable */ | ||
464 | #define CH0ERRE 0x0100 /* b8: Ch0 SHwy Res Err Detect Int Enable */ | ||
465 | #define CH1ENDE 0x0002 /* b2: Ch1 DMA Transfer End Int Enable */ | ||
466 | #define CH0ENDE 0x0001 /* b1: Ch0 DMA Transfer End Int Enable */ | ||
467 | |||
468 | /* DMA Interrupt Status Register */ | ||
469 | #define CH1ERRS 0x0200 /* b9: Ch1 SHwy Res Err Detect Int Status */ | ||
470 | #define CH0ERRS 0x0100 /* b8: Ch0 SHwy Res Err Detect Int Status */ | ||
471 | #define CH1ENDS 0x0002 /* b2: Ch1 DMA Transfer End Int Status */ | ||
472 | #define CH0ENDS 0x0001 /* b1: Ch0 DMA Transfer End Int Status */ | ||
473 | |||
474 | /* DMA Interrupt Status Clear Register */ | ||
475 | #define CH1ERRC 0x0200 /* b9: Ch1 SHwy Res Err Detect Int Stat Clear */ | ||
476 | #define CH0ERRC 0x0100 /* b8: Ch0 SHwy Res Err Detect Int Stat Clear */ | ||
477 | #define CH1ENDC 0x0002 /* b2: Ch1 DMA Transfer End Int Stat Clear */ | ||
478 | #define CH0ENDC 0x0001 /* b1: Ch0 DMA Transfer End Int Stat Clear */ | ||
479 | |||
420 | #endif /* __LINUX_USB_R8A66597_H */ | 480 | #endif /* __LINUX_USB_R8A66597_H */ |
421 | 481 | ||