All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/3] r8a66597-hcd: Add support for SH7366 USB host
@ 2008-04-10 12:05 Yoshihiro Shimoda
  0 siblings, 0 replies; only message in thread
From: Yoshihiro Shimoda @ 2008-04-10 12:05 UTC (permalink / raw)
  To: linux-sh

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>
---
 drivers/usb/host/Kconfig        |    6 +
 drivers/usb/host/r8a66597-hcd.c |  126 +++++++++++++++++++++---------
 drivers/usb/host/r8a66597.h     |   45 ++++++++++
 3 files changed, 142 insertions(+), 35 deletions(-)

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 27f295b..0b87480 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 c14fe49..bab170c 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -50,10 +50,12 @@ MODULE_AUTHOR("Yoshihiro Shimoda");
 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: 48MHz2768, 24MHz\x16384, 12MHz=0 "
 		"(default=0)");
+#endif

 static unsigned short vif = LDRV;
 module_param(vif, ushort, 0644);
@@ -105,11 +107,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);
@@ -131,13 +144,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_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);

-	r8a66597_bset(r8a66597, DCFM | DRPD, SYSCFG0);
-	r8a66597_bset(r8a66597, DRPD, SYSCFG1);
+	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);
@@ -145,53 +208,45 @@ 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);
+	for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++)
+		r8a66597_disable_port(r8a66597, port);

-	do {
-		tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
-		udelay(640);
-	} while (tmp = EDGESTS);
+	r8a66597_clock_disable(r8a66597);
+}

-	r8a66597_bclr(r8a66597, DCFM | DRPD, SYSCFG0);
-	r8a66597_bclr(r8a66597, DRPD, SYSCFG1);
-	r8a66597_bclr(r8a66597, HSE, SYSCFG0);
-	r8a66597_bclr(r8a66597, HSE, SYSCFG1);
+static int get_parent_r8a66597_address(struct r8a66597 *r8a66597,
+				       struct usb_device *udev)
+{
+	struct r8a66597_device *dev;

-	r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
-	udelay(1);
-	r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
-	r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
-	r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+	if (udev->parent && udev->parent->devnum != 1)
+		udev = udev->parent;
+
+	dev = dev_get_drvdata(&udev->dev);
+	if (dev)
+		return dev->address;
+	else
+		return 0;
 }

 static int get_parent_r8a66597_address(struct r8a66597 *r8a66597,
@@ -710,6 +765,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;

@@ -737,6 +793,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 */
@@ -1053,8 +1110,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 f46f7dd..84ee014 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;

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2008-04-10 12:05 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-04-10 12:05 [PATCH 3/3] r8a66597-hcd: Add support for SH7366 USB host Yoshihiro Shimoda

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.