]> err.no Git - linux-2.6/commitdiff
USB: r8a66597-hcd: Add support for SH7366 USB host
authorYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Thu, 10 Apr 2008 12:05:58 +0000 (21:05 +0900)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 25 Apr 2008 04:16:49 +0000 (21:16 -0700)
R8A66597 is similar to SH7366 USB 2.0 Host/Function module. It can
support SH7366 USB host by changing several R8A66597 code.

Signed-off-by: Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/host/Kconfig
drivers/usb/host/r8a66597-hcd.c
drivers/usb/host/r8a66597.h

index 27f295b78055a21c983c6746cd8e8d4febdc74bb..0b87480dd713af0671575ce9cd055b00350ad384 100644 (file)
@@ -260,3 +260,9 @@ config USB_R8A66597_HCD
          To compile this driver as a module, choose M here: the
          module will be called r8a66597-hcd.
 
+config SUPERH_ON_CHIP_R8A66597
+       boolean "Enable SuperH on-chip USB like the R8A66597"
+       depends on USB_R8A66597_HCD && CPU_SUBTYPE_SH7366
+       help
+          Renesas SuperH processor has USB like the R8A66597.
+          This driver supported processor is SH7366.
index bb48f42bd7cee10f157a8dd94bf48132a9ab6b0a..f4fa93dabdde99d77d3e632876b4d22ba5c80a83 100644 (file)
@@ -51,10 +51,12 @@ MODULE_ALIAS("platform:r8a66597_hcd");
 static const char hcd_name[] = "r8a66597_hcd";
 
 /* module parameters */
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
 static unsigned short clock = XTAL12;
 module_param(clock, ushort, 0644);
 MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
                "(default=0)");
+#endif
 
 static unsigned short vif = LDRV;
 module_param(vif, ushort, 0644);
@@ -106,11 +108,22 @@ static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address,
        r8a66597_write(r8a66597, val, devadd_reg);
 }
 
-static int enable_controller(struct r8a66597 *r8a66597)
+static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
 {
        u16 tmp;
        int i = 0;
 
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+       do {
+               r8a66597_write(r8a66597, SCKE, SYSCFG0);
+               tmp = r8a66597_read(r8a66597, SYSCFG0);
+               if (i++ > 1000) {
+                       err("register access fail.");
+                       return -ENXIO;
+               }
+       } while ((tmp & SCKE) != SCKE);
+       r8a66597_write(r8a66597, 0x04, 0x02);
+#else
        do {
                r8a66597_write(r8a66597, USBE, SYSCFG0);
                tmp = r8a66597_read(r8a66597, SYSCFG0);
@@ -132,13 +145,63 @@ static int enable_controller(struct r8a66597 *r8a66597)
                        return -ENXIO;
                }
        } while ((tmp & SCKE) != SCKE);
+#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
+
+       return 0;
+}
+
+static void r8a66597_clock_disable(struct r8a66597 *r8a66597)
+{
+       r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
+       udelay(1);
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+       r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+       r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+       r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+#endif
+}
+
+static void r8a66597_enable_port(struct r8a66597 *r8a66597, int port)
+{
+       u16 val;
+
+       val = port ? DRPD : DCFM | DRPD;
+       r8a66597_bset(r8a66597, val, get_syscfg_reg(port));
+       r8a66597_bset(r8a66597, HSE, get_syscfg_reg(port));
+
+       r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, get_dmacfg_reg(port));
+       r8a66597_bclr(r8a66597, DTCHE, get_intenb_reg(port));
+       r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+}
+
+static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
+{
+       u16 val, tmp;
 
-       r8a66597_bset(r8a66597, DCFM | DRPD, SYSCFG0);
-       r8a66597_bset(r8a66597, DRPD, SYSCFG1);
+       r8a66597_write(r8a66597, 0, get_intenb_reg(port));
+       r8a66597_write(r8a66597, 0, get_intsts_reg(port));
+
+       r8a66597_port_power(r8a66597, port, 0);
+
+       do {
+               tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
+               udelay(640);
+       } while (tmp == EDGESTS);
+
+       val = port ? DRPD : DCFM | DRPD;
+       r8a66597_bclr(r8a66597, val, get_syscfg_reg(port));
+       r8a66597_bclr(r8a66597, HSE, get_syscfg_reg(port));
+}
+
+static int enable_controller(struct r8a66597 *r8a66597)
+{
+       int ret, port;
+
+       ret = r8a66597_clock_enable(r8a66597);
+       if (ret < 0)
+               return ret;
 
        r8a66597_bset(r8a66597, vif & LDRV, PINCFG);
-       r8a66597_bset(r8a66597, HSE, SYSCFG0);
-       r8a66597_bset(r8a66597, HSE, SYSCFG1);
        r8a66597_bset(r8a66597, USBE, SYSCFG0);
 
        r8a66597_bset(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
@@ -146,53 +209,30 @@ static int enable_controller(struct r8a66597 *r8a66597)
        r8a66597_bset(r8a66597, BRDY0, BRDYENB);
        r8a66597_bset(r8a66597, BEMP0, BEMPENB);
 
-       r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA0CFG);
-       r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA1CFG);
-
        r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
        r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
        r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
-
        r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
 
        r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1);
-       r8a66597_bclr(r8a66597, DTCHE, INTENB1);
-       r8a66597_bset(r8a66597, ATTCHE, INTENB1);
-       r8a66597_bclr(r8a66597, DTCHE, INTENB2);
-       r8a66597_bset(r8a66597, ATTCHE, INTENB2);
+
+       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+               r8a66597_enable_port(r8a66597, port);
 
        return 0;
 }
 
 static void disable_controller(struct r8a66597 *r8a66597)
 {
-       u16 tmp;
+       int port;
 
        r8a66597_write(r8a66597, 0, INTENB0);
-       r8a66597_write(r8a66597, 0, INTENB1);
-       r8a66597_write(r8a66597, 0, INTENB2);
        r8a66597_write(r8a66597, 0, INTSTS0);
-       r8a66597_write(r8a66597, 0, INTSTS1);
-       r8a66597_write(r8a66597, 0, INTSTS2);
-
-       r8a66597_port_power(r8a66597, 0, 0);
-       r8a66597_port_power(r8a66597, 1, 0);
-
-       do {
-               tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
-               udelay(640);
-       } while (tmp == EDGESTS);
 
-       r8a66597_bclr(r8a66597, DCFM | DRPD, SYSCFG0);
-       r8a66597_bclr(r8a66597, DRPD, SYSCFG1);
-       r8a66597_bclr(r8a66597, HSE, SYSCFG0);
-       r8a66597_bclr(r8a66597, HSE, SYSCFG1);
+       for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+               r8a66597_disable_port(r8a66597, port);
 
-       r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
-       udelay(1);
-       r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
-       r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
-       r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+       r8a66597_clock_disable(r8a66597);
 }
 
 static int get_parent_r8a66597_address(struct r8a66597 *r8a66597,
@@ -711,6 +751,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
                                     struct r8a66597_pipe *pipe,
                                     struct urb *urb)
 {
+#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
        int i;
        struct r8a66597_pipe_info *info = &pipe->info;
 
@@ -738,6 +779,7 @@ static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
                        break;
                }
        }
+#endif /* #if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) */
 }
 
 /* this function must be called with interrupt disabled */
@@ -1054,8 +1096,7 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
                r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
                r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
                r8a66597_write(r8a66597, ~BEMP0, BEMPSTS);
-               r8a66597_write(r8a66597, BCLR, CFIFOCTR);
-               r8a66597_write(r8a66597, BVAL, CFIFOCTR);
+               r8a66597_write(r8a66597, BCLR | BVAL, CFIFOCTR);
                enable_irq_empty(r8a66597, 0);
        } else {
                r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
index f46f7dd944a1f5eb7686c1ec73edc4ac1e4b9860..84ee014173151cd4f541cd5b798cf2800682afb7 100644 (file)
 #define        REW             0x4000  /* b14: Buffer rewind */
 #define        DCLRM           0x2000  /* b13: DMA buffer clear mode */
 #define        DREQE           0x1000  /* b12: DREQ output enable */
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+#define        MBW             0x0800
+#else
 #define        MBW             0x0400  /* b10: Maximum bit width for FIFO access */
+#endif
 #define          MBW_8          0x0000   /*  8bit */
 #define          MBW_16         0x0400   /* 16bit */
 #define        BIGEND          0x0100  /* b8: Big endian mode */
 #define R8A66597_MAX_NUM_PIPE          10
 #define R8A66597_BUF_BSIZE             8
 #define R8A66597_MAX_DEVICE            10
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+#define R8A66597_MAX_ROOT_HUB          1
+#else
 #define R8A66597_MAX_ROOT_HUB          2
+#endif
 #define R8A66597_MAX_SAMPLING          5
 #define R8A66597_RH_POLL_TIME          10
 #define R8A66597_MAX_DMA_CHANNEL       2
@@ -530,8 +538,21 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
                                      unsigned long offset, u16 *buf,
                                      int len)
 {
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+       unsigned long fifoaddr = r8a66597->reg + offset;
+       unsigned long count;
+
+       count = len / 4;
+       insl(fifoaddr, buf, count);
+
+       if (len & 0x00000003) {
+               unsigned long tmp = inl(fifoaddr);
+               memcpy((unsigned char *)buf + count * 4, &tmp, len & 0x03);
+       }
+#else
        len = (len + 1) / 2;
        insw(r8a66597->reg + offset, buf, len);
+#endif
 }
 
 static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
@@ -545,6 +566,24 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
                                       int len)
 {
        unsigned long fifoaddr = r8a66597->reg + offset;
+#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
+       unsigned long count;
+       unsigned char *pb;
+       int i;
+
+       count = len / 4;
+       outsl(fifoaddr, buf, count);
+
+       if (len & 0x00000003) {
+               pb = (unsigned char *)buf + count * 4;
+               for (i = 0; i < (len & 0x00000003); i++) {
+                       if (r8a66597_read(r8a66597, CFIFOSEL) & BIGEND)
+                               outb(pb[i], fifoaddr + i);
+                       else
+                               outb(pb[i], fifoaddr + 3 - i);
+               }
+       }
+#else
        int odd = len & 0x0001;
 
        len = len / 2;
@@ -553,6 +592,7 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
                buf = &buf[len];
                outb((unsigned char)*buf, fifoaddr);
        }
+#endif
 }
 
 static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
@@ -585,6 +625,11 @@ static inline unsigned long get_dvstctr_reg(int port)
        return port == 0 ? DVSTCTR0 : DVSTCTR1;
 }
 
+static inline unsigned long get_dmacfg_reg(int port)
+{
+       return port == 0 ? DMA0CFG : DMA1CFG;
+}
+
 static inline unsigned long get_intenb_reg(int port)
 {
        return port == 0 ? INTENB1 : INTENB2;