USB: m66592-udc: Add support for SH7722 USBF
authorYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Thu, 22 Nov 2007 12:00:30 +0000 (21:00 +0900)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 1 Feb 2008 22:34:48 +0000 (14:34 -0800)
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>
drivers/usb/gadget/Kconfig
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/m66592-udc.h

index 77a3759d6fc7552c83f01139cff84d46f6f85b2c..e706882a8e6ffbc27d7b0bdcd472c4ad5099b35c 100644 (file)
@@ -220,6 +220,16 @@ config USB_M66592
        default USB_GADGET
        select USB_GADGET_SELECTED
 
+config SUPERH_BUILT_IN_M66592
+       boolean "Enable SuperH built-in USB like the M66592"
+       depends on USB_GADGET_M66592 && CPU_SUBTYPE_SH7722
+       help
+          SH7722 has USB like the M66592.
+
+          The transfer rate is very slow when use "Ethernet Gadget".
+          However, this problem is improved if change a value of
+          NET_IP_ALIGN to 4.
+
 config USB_GADGET_GOKU
        boolean "Toshiba TC86C001 'Goku-S'"
        depends on PCI
index ebc5536aa271d8ad78b76dcf701670ee76b1982c..154007aa8d30938db7c82d22f72428dfe2190f7d 100644 (file)
@@ -36,9 +36,14 @@ MODULE_DESCRIPTION("M66592 USB gadget driver");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Yoshihiro Shimoda");
 
-#define DRIVER_VERSION "29 May 2007"
+#define DRIVER_VERSION "18 Oct 2007"
 
 /* module parameters */
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+static unsigned short endian = M66592_LITTLE;
+module_param(endian, ushort, 0644);
+MODULE_PARM_DESC(endian, "data endian: big=0, little=0 (default=0)");
+#else
 static unsigned short clock = M66592_XTAL24;
 module_param(clock, ushort, 0644);
 MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
@@ -56,6 +61,7 @@ static unsigned short irq_sense = M66592_INTL;
 module_param(irq_sense, ushort, 0644);
 MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 "
                "(default=2)");
+#endif
 
 static const char udc_name[] = "m66592_udc";
 static const char *m66592_ep_name[] = {
@@ -360,6 +366,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
                        ep->fifosel = M66592_D0FIFOSEL;
                        ep->fifoctr = M66592_D0FIFOCTR;
                        ep->fifotrn = M66592_D0FIFOTRN;
+#if !defined(CONFIG_SUPERH_BUILT_IN_M66592)
                } else if (m66592->num_dma == 1) {
                        m66592->num_dma++;
                        ep->use_dma = 1;
@@ -367,6 +374,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
                        ep->fifosel = M66592_D1FIFOSEL;
                        ep->fifoctr = M66592_D1FIFOCTR;
                        ep->fifotrn = M66592_D1FIFOTRN;
+#endif
                } else {
                        ep->use_dma = 0;
                        ep->fifoaddr = M66592_CFIFO;
@@ -611,6 +619,28 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
        }
 }
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+static void init_controller(struct m66592 *m66592)
+{
+       usbf_start_clock();
+       m66592_bset(m66592, M66592_HSE, M66592_SYSCFG);         /* High spd */
+       m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+       m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+       m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+
+       /* This is a workaound for SH7722 2nd cut */
+       m66592_bset(m66592, 0x8000, M66592_DVSTCTR);
+       m66592_bset(m66592, 0x1000, M66592_TESTMODE);
+       m66592_bclr(m66592, 0x8000, M66592_DVSTCTR);
+
+       m66592_bset(m66592, M66592_INTL, M66592_INTENB1);
+
+       m66592_write(m66592, 0, M66592_CFBCFG);
+       m66592_write(m66592, 0, M66592_D0FBCFG);
+       m66592_bset(m66592, endian, M66592_CFBCFG);
+       m66592_bset(m66592, endian, M66592_D0FBCFG);
+}
+#else  /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 static void init_controller(struct m66592 *m66592)
 {
        m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
@@ -636,9 +666,13 @@ static void init_controller(struct m66592 *m66592)
        m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
                        M66592_DMA0CFG);
 }
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 
 static void disable_controller(struct m66592 *m66592)
 {
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       usbf_stop_clock();
+#else
        m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
        udelay(1);
        m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
@@ -646,15 +680,20 @@ static void disable_controller(struct m66592 *m66592)
        m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
        udelay(1);
        m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
+#endif
 }
 
 static void m66592_start_xclock(struct m66592 *m66592)
 {
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       usbf_start_clock();
+#else
        u16 tmp;
 
        tmp = m66592_read(m66592, M66592_SYSCFG);
        if (!(tmp & M66592_XCKE))
                m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+#endif
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1142,6 +1181,19 @@ static irqreturn_t m66592_irq(int irq, void *_m66592)
        intsts0 = m66592_read(m66592, M66592_INTSTS0);
        intenb0 = m66592_read(m66592, M66592_INTENB0);
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       if (!intsts0 && !intenb0) {
+               /*
+                * When USB clock stops, it cannot read register. Even if a
+                * clock stops, the interrupt occurs. So this driver turn on
+                * a clock by this timing and do re-reading of register.
+                */
+               m66592_start_xclock(m66592);
+               intsts0 = m66592_read(m66592, M66592_INTSTS0);
+               intenb0 = m66592_read(m66592, M66592_INTENB0);
+       }
+#endif
+
        savepipe = m66592_read(m66592, M66592_CFIFOSEL);
 
        mask0 = intsts0 & intenb0;
@@ -1485,6 +1537,7 @@ static int __exit m66592_remove(struct platform_device *pdev)
        iounmap(m66592->reg);
        free_irq(platform_get_irq(pdev, 0), m66592);
        m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+       usbf_stop_clock();
        kfree(m66592);
        return 0;
 }
index bfa0c645f229b97752c5362c8503cf1e8f8e46f3..17b792b7f6bfc43d3879fc316b188f0a12ae36f4 100644 (file)
 #define   M66592_P_TST_J        0x0001         /* PERI TEST J */
 #define   M66592_P_TST_NORMAL   0x0000         /* PERI Normal Mode */
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+#define M66592_CFBCFG          0x0A
+#define M66592_D0FBCFG         0x0C
+#define M66592_LITTLE          0x0100  /* b8: Little endian mode */
+#else
 #define M66592_PINCFG          0x0A
 #define M66592_LDRV            0x8000  /* b15: Drive Current Adjust */
 #define M66592_BIGEND          0x0100  /* b8: Big endian mode */
@@ -91,6 +96,7 @@
 #define M66592_PKTM            0x0020  /* b5: Packet mode */
 #define M66592_DENDE           0x0010  /* b4: Dend enable */
 #define M66592_OBUS            0x0004  /* b2: OUTbus mode */
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 
 #define M66592_CFIFO           0x10
 #define M66592_D0FIFO          0x14
 #define M66592_REW             0x4000  /* b14: Buffer rewind */
 #define M66592_DCLRM           0x2000  /* b13: DMA buffer clear mode */
 #define M66592_DREQE           0x1000  /* b12: DREQ output enable */
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+#define M66592_MBW             0x0800  /* b11: Maximum bit width for FIFO */
+#else
 #define M66592_MBW             0x0400  /* b10: Maximum bit width for FIFO */
 #define   M66592_MBW_8          0x0000   /*  8bit */
 #define   M66592_MBW_16                 0x0400   /* 16bit */
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 #define M66592_TRENB           0x0200  /* b9: Transaction counter enable */
 #define M66592_TRCLR           0x0100  /* b8: Transaction counter clear */
 #define M66592_DEZPM           0x0080  /* b7: Zero-length packet mode */
@@ -530,8 +540,13 @@ static inline void m66592_read_fifo(struct m66592 *m66592,
 {
        unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       len = (len + 3) / 4;
+       insl(fifoaddr, buf, len);
+#else
        len = (len + 1) / 2;
        insw(fifoaddr, buf, len);
+#endif
 }
 
 static inline void m66592_write(struct m66592 *m66592, u16 val,
@@ -545,6 +560,24 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
                void *buf, unsigned long len)
 {
        unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+       unsigned long count;
+       unsigned char *pb;
+       int i;
+
+       count = len / 4;
+       outsl(fifoaddr, buf, count);
+
+       if (len & 0x00000003) {
+               pb = buf + count * 4;
+               for (i = 0; i < (len & 0x00000003); i++) {
+                       if (m66592_read(m66592, M66592_CFBCFG)) /* little */
+                               outb(pb[i], fifoaddr + (3 - i));
+                       else
+                               outb(pb[i], fifoaddr + i);
+               }
+       }
+#else
        unsigned long odd = len & 0x0001;
 
        len = len / 2;
@@ -553,6 +586,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
                unsigned char *p = buf + len*2;
                outb(*p, fifoaddr);
        }
+#endif /* #if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
 }
 
 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,
 #define m66592_bset(m66592, val, offset)       \
                        m66592_mdfy(m66592, val, 0, offset)
 
+#if defined(CONFIG_SUPERH_BUILT_IN_M66592)
+#include <asm/io.h>
+#define MSTPCR2                0xA4150038      /* for SH7722 */
+#define MSTPCR2_USB    0x00000800
+
+static inline void usbf_start_clock(void)
+{
+       ctrl_outl(ctrl_inl(MSTPCR2) & ~MSTPCR2_USB, MSTPCR2);
+}
+
+static inline void usbf_stop_clock(void)
+{
+       ctrl_outl(ctrl_inl(MSTPCR2) | MSTPCR2_USB, MSTPCR2);
+}
+
+#else
+#define usbf_start_clock(x)
+#define usbf_stop_clock(x)
+#endif /* if defined(CONFIG_SUPERH_BUILT_IN_M66592) */
+
 #endif /* ifndef __M66592_UDC_H__ */