diff options
author | Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com> | 2007-11-22 07:00:30 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-01 17:34:48 -0500 |
commit | 8c73aff6d3b772e5f373d78bc34fd47b10b35fef (patch) | |
tree | c6829760527dd59c27acf86b3f935b3659b2c6fa | |
parent | 9da0068a4964540d8d1caa8455fe193b544d846d (diff) |
USB: m66592-udc: Add support for SH7722 USBF
Add support for SuperH SH7722 USB Function.
M66592 is similar to SH7722 USBF. It can support SH7722 USBF by
changing several M66592 code.
Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Acked-by: David Brownell <david-b@pacbell.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/gadget/Kconfig | 10 | ||||
-rw-r--r-- | drivers/usb/gadget/m66592-udc.c | 55 | ||||
-rw-r--r-- | drivers/usb/gadget/m66592-udc.h | 54 |
3 files changed, 118 insertions, 1 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 77a3759d6fc7..e706882a8e6f 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -220,6 +220,16 @@ config USB_M66592 | |||
220 | default USB_GADGET | 220 | default USB_GADGET |
221 | select USB_GADGET_SELECTED | 221 | select USB_GADGET_SELECTED |
222 | 222 | ||
223 | config SUPERH_BUILT_IN_M66592 | ||
224 | boolean "Enable SuperH built-in USB like the M66592" | ||
225 | depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722 | ||
226 | help | ||
227 | SH7722 has USB like the M66592. | ||
228 | |||
229 | The transfer rate is very slow when use "Ethernet Gadget". | ||
230 | However, this problem is improved if change a value of | ||
231 | NET_IP_ALIGN to 4. | ||
232 | |||
223 | config USB_GADGET_GOKU | 233 | config USB_GADGET_GOKU |
224 | boolean "Toshiba TC86C001 'Goku-S'" | 234 | boolean "Toshiba TC86C001 'Goku-S'" |
225 | depends on PCI | 235 | depends on PCI |
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index ebc5536aa271..154007aa8d30 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c | |||
@@ -36,9 +36,14 @@ MODULE_DESCRIPTION("M66592 USB gadget driver"); | |||
36 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
37 | MODULE_AUTHOR("Yoshihiro Shimoda"); | 37 | MODULE_AUTHOR("Yoshihiro Shimoda"); |
38 | 38 | ||
39 | #define DRIVER_VERSION "29 May 2007" | 39 | #define DRIVER_VERSION "18 Oct 2007" |
40 | 40 | ||
41 | /* module parameters */ | 41 | /* module parameters */ |
42 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
43 | static unsigned short endian = M66592_LITTLE; | ||
44 | module_param(endian, ushort, 0644); | ||
45 | MODULE_PARM_DESC(endian, "data endian: big=0, little=0 (default=0)"); | ||
46 | #else | ||
42 | static unsigned short clock = M66592_XTAL24; | 47 | static unsigned short clock = M66592_XTAL24; |
43 | module_param(clock, ushort, 0644); | 48 | module_param(clock, ushort, 0644); |
44 | MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " | 49 | MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " |
@@ -56,6 +61,7 @@ static unsigned short irq_sense = M66592_INTL; | |||
56 | module_param(irq_sense, ushort, 0644); | 61 | module_param(irq_sense, ushort, 0644); |
57 | MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 " | 62 | MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 " |
58 | "(default=2)"); | 63 | "(default=2)"); |
64 | #endif | ||
59 | 65 | ||
60 | static const char udc_name[] = "m66592_udc"; | 66 | static const char udc_name[] = "m66592_udc"; |
61 | static const char *m66592_ep_name[] = { | 67 | static const char *m66592_ep_name[] = { |
@@ -360,6 +366,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, | |||
360 | ep->fifosel = M66592_D0FIFOSEL; | 366 | ep->fifosel = M66592_D0FIFOSEL; |
361 | ep->fifoctr = M66592_D0FIFOCTR; | 367 | ep->fifoctr = M66592_D0FIFOCTR; |
362 | ep->fifotrn = M66592_D0FIFOTRN; | 368 | ep->fifotrn = M66592_D0FIFOTRN; |
369 | #if !defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
363 | } else if (m66592->num_dma == 1) { | 370 | } else if (m66592->num_dma == 1) { |
364 | m66592->num_dma++; | 371 | m66592->num_dma++; |
365 | ep->use_dma = 1; | 372 | ep->use_dma = 1; |
@@ -367,6 +374,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, | |||
367 | ep->fifosel = M66592_D1FIFOSEL; | 374 | ep->fifosel = M66592_D1FIFOSEL; |
368 | ep->fifoctr = M66592_D1FIFOCTR; | 375 | ep->fifoctr = M66592_D1FIFOCTR; |
369 | ep->fifotrn = M66592_D1FIFOTRN; | 376 | ep->fifotrn = M66592_D1FIFOTRN; |
377 | #endif | ||
370 | } else { | 378 | } else { |
371 | ep->use_dma = 0; | 379 | ep->use_dma = 0; |
372 | ep->fifoaddr = M66592_CFIFO; | 380 | ep->fifoaddr = M66592_CFIFO; |
@@ -611,6 +619,28 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req) | |||
611 | } | 619 | } |
612 | } | 620 | } |
613 | 621 | ||
622 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
623 | static void init_controller(struct m66592 *m66592) | ||
624 | { | ||
625 | usbf_start_clock(); | ||
626 | m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ | ||
627 | m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG); | ||
628 | m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); | ||
629 | m66592_bset(m66592, M66592_USBE, M66592_SYSCFG); | ||
630 | |||
631 | /* This is a workaound for SH7722 2nd cut */ | ||
632 | m66592_bset(m66592, 0x8000, M66592_DVSTCTR); | ||
633 | m66592_bset(m66592, 0x1000, M66592_TESTMODE); | ||
634 | m66592_bclr(m66592, 0x8000, M66592_DVSTCTR); | ||
635 | |||
636 | m66592_bset(m66592, M66592_INTL, M66592_INTENB1); | ||
637 | |||
638 | m66592_write(m66592, 0, M66592_CFBCFG); | ||
639 | m66592_write(m66592, 0, M66592_D0FBCFG); | ||
640 | m66592_bset(m66592, endian, M66592_CFBCFG); | ||
641 | m66592_bset(m66592, endian, M66592_D0FBCFG); | ||
642 | } | ||
643 | #else /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ | ||
614 | static void init_controller(struct m66592 *m66592) | 644 | static void init_controller(struct m66592 *m66592) |
615 | { | 645 | { |
616 | m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND), | 646 | m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND), |
@@ -636,9 +666,13 @@ static void init_controller(struct m66592 *m66592) | |||
636 | m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, | 666 | m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, |
637 | M66592_DMA0CFG); | 667 | M66592_DMA0CFG); |
638 | } | 668 | } |
669 | #endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ | ||
639 | 670 | ||
640 | static void disable_controller(struct m66592 *m66592) | 671 | static void disable_controller(struct m66592 *m66592) |
641 | { | 672 | { |
673 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
674 | usbf_stop_clock(); | ||
675 | #else | ||
642 | m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); | 676 | m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG); |
643 | udelay(1); | 677 | udelay(1); |
644 | m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); | 678 | m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG); |
@@ -646,15 +680,20 @@ static void disable_controller(struct m66592 *m66592) | |||
646 | m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG); | 680 | m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG); |
647 | udelay(1); | 681 | udelay(1); |
648 | m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG); | 682 | m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG); |
683 | #endif | ||
649 | } | 684 | } |
650 | 685 | ||
651 | static void m66592_start_xclock(struct m66592 *m66592) | 686 | static void m66592_start_xclock(struct m66592 *m66592) |
652 | { | 687 | { |
688 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
689 | usbf_start_clock(); | ||
690 | #else | ||
653 | u16 tmp; | 691 | u16 tmp; |
654 | 692 | ||
655 | tmp = m66592_read(m66592, M66592_SYSCFG); | 693 | tmp = m66592_read(m66592, M66592_SYSCFG); |
656 | if (!(tmp & M66592_XCKE)) | 694 | if (!(tmp & M66592_XCKE)) |
657 | m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); | 695 | m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG); |
696 | #endif | ||
658 | } | 697 | } |
659 | 698 | ||
660 | /*-------------------------------------------------------------------------*/ | 699 | /*-------------------------------------------------------------------------*/ |
@@ -1142,6 +1181,19 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) | |||
1142 | intsts0 = m66592_read(m66592, M66592_INTSTS0); | 1181 | intsts0 = m66592_read(m66592, M66592_INTSTS0); |
1143 | intenb0 = m66592_read(m66592, M66592_INTENB0); | 1182 | intenb0 = m66592_read(m66592, M66592_INTENB0); |
1144 | 1183 | ||
1184 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
1185 | if (!intsts0 && !intenb0) { | ||
1186 | /* | ||
1187 | * When USB clock stops, it cannot read register. Even if a | ||
1188 | * clock stops, the interrupt occurs. So this driver turn on | ||
1189 | * a clock by this timing and do re-reading of register. | ||
1190 | */ | ||
1191 | m66592_start_xclock(m66592); | ||
1192 | intsts0 = m66592_read(m66592, M66592_INTSTS0); | ||
1193 | intenb0 = m66592_read(m66592, M66592_INTENB0); | ||
1194 | } | ||
1195 | #endif | ||
1196 | |||
1145 | savepipe = m66592_read(m66592, M66592_CFIFOSEL); | 1197 | savepipe = m66592_read(m66592, M66592_CFIFOSEL); |
1146 | 1198 | ||
1147 | mask0 = intsts0 & intenb0; | 1199 | mask0 = intsts0 & intenb0; |
@@ -1485,6 +1537,7 @@ static int __exit m66592_remove(struct platform_device *pdev) | |||
1485 | iounmap(m66592->reg); | 1537 | iounmap(m66592->reg); |
1486 | free_irq(platform_get_irq(pdev, 0), m66592); | 1538 | free_irq(platform_get_irq(pdev, 0), m66592); |
1487 | m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); | 1539 | m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); |
1540 | usbf_stop_clock(); | ||
1488 | kfree(m66592); | 1541 | kfree(m66592); |
1489 | return 0; | 1542 | return 0; |
1490 | } | 1543 | } |
diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index bfa0c645f229..17b792b7f6bf 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h | |||
@@ -72,6 +72,11 @@ | |||
72 | #define M66592_P_TST_J 0x0001 /* PERI TEST J */ | 72 | #define M66592_P_TST_J 0x0001 /* PERI TEST J */ |
73 | #define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ | 73 | #define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ |
74 | 74 | ||
75 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
76 | #define M66592_CFBCFG 0x0A | ||
77 | #define M66592_D0FBCFG 0x0C | ||
78 | #define M66592_LITTLE 0x0100 /* b8: Little endian mode */ | ||
79 | #else | ||
75 | #define M66592_PINCFG 0x0A | 80 | #define M66592_PINCFG 0x0A |
76 | #define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ | 81 | #define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ |
77 | #define M66592_BIGEND 0x0100 /* b8: Big endian mode */ | 82 | #define M66592_BIGEND 0x0100 /* b8: Big endian mode */ |
@@ -91,6 +96,7 @@ | |||
91 | #define M66592_PKTM 0x0020 /* b5: Packet mode */ | 96 | #define M66592_PKTM 0x0020 /* b5: Packet mode */ |
92 | #define M66592_DENDE 0x0010 /* b4: Dend enable */ | 97 | #define M66592_DENDE 0x0010 /* b4: Dend enable */ |
93 | #define M66592_OBUS 0x0004 /* b2: OUTbus mode */ | 98 | #define M66592_OBUS 0x0004 /* b2: OUTbus mode */ |
99 | #endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ | ||
94 | 100 | ||
95 | #define M66592_CFIFO 0x10 | 101 | #define M66592_CFIFO 0x10 |
96 | #define M66592_D0FIFO 0x14 | 102 | #define M66592_D0FIFO 0x14 |
@@ -103,9 +109,13 @@ | |||
103 | #define M66592_REW 0x4000 /* b14: Buffer rewind */ | 109 | #define M66592_REW 0x4000 /* b14: Buffer rewind */ |
104 | #define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ | 110 | #define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ |
105 | #define M66592_DREQE 0x1000 /* b12: DREQ output enable */ | 111 | #define M66592_DREQE 0x1000 /* b12: DREQ output enable */ |
112 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
113 | #define M66592_MBW 0x0800 /* b11: Maximum bit width for FIFO */ | ||
114 | #else | ||
106 | #define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */ | 115 | #define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */ |
107 | #define M66592_MBW_8 0x0000 /* 8bit */ | 116 | #define M66592_MBW_8 0x0000 /* 8bit */ |
108 | #define M66592_MBW_16 0x0400 /* 16bit */ | 117 | #define M66592_MBW_16 0x0400 /* 16bit */ |
118 | #endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ | ||
109 | #define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ | 119 | #define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ |
110 | #define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ | 120 | #define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ |
111 | #define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */ | 121 | #define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */ |
@@ -530,8 +540,13 @@ static inline void m66592_read_fifo(struct m66592 *m66592, | |||
530 | { | 540 | { |
531 | unsigned long fifoaddr = (unsigned long)m66592->reg + offset; | 541 | unsigned long fifoaddr = (unsigned long)m66592->reg + offset; |
532 | 542 | ||
543 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
544 | len = (len + 3) / 4; | ||
545 | insl(fifoaddr, buf, len); | ||
546 | #else | ||
533 | len = (len + 1) / 2; | 547 | len = (len + 1) / 2; |
534 | insw(fifoaddr, buf, len); | 548 | insw(fifoaddr, buf, len); |
549 | #endif | ||
535 | } | 550 | } |
536 | 551 | ||
537 | static inline void m66592_write(struct m66592 *m66592, u16 val, | 552 | static inline void m66592_write(struct m66592 *m66592, u16 val, |
@@ -545,6 +560,24 @@ static inline void m66592_write_fifo(struct m66592 *m66592, | |||
545 | void *buf, unsigned long len) | 560 | void *buf, unsigned long len) |
546 | { | 561 | { |
547 | unsigned long fifoaddr = (unsigned long)m66592->reg + offset; | 562 | unsigned long fifoaddr = (unsigned long)m66592->reg + offset; |
563 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
564 | unsigned long count; | ||
565 | unsigned char *pb; | ||
566 | int i; | ||
567 | |||
568 | count = len / 4; | ||
569 | outsl(fifoaddr, buf, count); | ||
570 | |||
571 | if (len & 0x00000003) { | ||
572 | pb = buf + count * 4; | ||
573 | for (i = 0; i < (len & 0x00000003); i++) { | ||
574 | if (m66592_read(m66592, M66592_CFBCFG)) /* little */ | ||
575 | outb(pb[i], fifoaddr + (3 - i)); | ||
576 | else | ||
577 | outb(pb[i], fifoaddr + i); | ||
578 | } | ||
579 | } | ||
580 | #else | ||
548 | unsigned long odd = len & 0x0001; | 581 | unsigned long odd = len & 0x0001; |
549 | 582 | ||
550 | len = len / 2; | 583 | len = len / 2; |
@@ -553,6 +586,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592, | |||
553 | unsigned char *p = buf + len*2; | 586 | unsigned char *p = buf + len*2; |
554 | outb(*p, fifoaddr); | 587 | outb(*p, fifoaddr); |
555 | } | 588 | } |
589 | #endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ | ||
556 | } | 590 | } |
557 | 591 | ||
558 | static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, | 592 | static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, |
@@ -570,6 +604,26 @@ static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, | |||
570 | #define m66592_bset(m66592, val, offset) \ | 604 | #define m66592_bset(m66592, val, offset) \ |
571 | m66592_mdfy(m66592, val, 0, offset) | 605 | m66592_mdfy(m66592, val, 0, offset) |
572 | 606 | ||
607 | #if defined(CONFIG_SUPERH_BUILT_IN_M66592) | ||
608 | #include <asm/io.h> | ||
609 | #define MSTPCR2 0xA4150038 /* for SH7722 */ | ||
610 | #define MSTPCR2_USB 0x00000800 | ||
611 | |||
612 | static inline void usbf_start_clock(void) | ||
613 | { | ||
614 | ctrl_outl(ctrl_inl(MSTPCR2) & ~MSTPCR2_USB, MSTPCR2); | ||
615 | } | ||
616 | |||
617 | static inline void usbf_stop_clock(void) | ||
618 | { | ||
619 | ctrl_outl(ctrl_inl(MSTPCR2) | MSTPCR2_USB, MSTPCR2); | ||
620 | } | ||
621 | |||
622 | #else | ||
623 | #define usbf_start_clock(x) | ||
624 | #define usbf_stop_clock(x) | ||
625 | #endif /* if defined(CONFIG_SUPERH_BUILT_IN_M66592) */ | ||
626 | |||
573 | #endif /* ifndef __M66592_UDC_H__ */ | 627 | #endif /* ifndef __M66592_UDC_H__ */ |
574 | 628 | ||
575 | 629 | ||