summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>2008-04-10 21:05:58 +0900
committerGreg Kroah-Hartman <gregkh@suse.de>2008-04-24 21:16:49 -0700
commit9424ea29658ce5bcdcf527ddf9617b9507ddf1aa (patch)
treeb733f3cd7991d964810b32d7a555bdf9826a63e8
parent29fab0cd897519be9009ba8c898410ab83b378e9 (diff)
USB: r8a66597-hcd: Add support for SH7366 USB host
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>
-rw-r--r--drivers/usb/host/Kconfig6
-rw-r--r--drivers/usb/host/r8a66597-hcd.c115
-rw-r--r--drivers/usb/host/r8a66597.h45
3 files changed, 129 insertions, 37 deletions
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 27f295b7805..0b87480dd71 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -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.
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index bb48f42bd7c..f4fa93dabdd 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -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);
diff --git a/drivers/usb/host/r8a66597.h b/drivers/usb/host/r8a66597.h
index f46f7dd944a..84ee0141731 100644
--- a/drivers/usb/host/r8a66597.h
+++ b/drivers/usb/host/r8a66597.h
@@ -187,7 +187,11 @@
#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 */
@@ -395,7 +399,11 @@
#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;