Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9424ea29 authored by Yoshihiro Shimoda's avatar Yoshihiro Shimoda Committed by Greg Kroah-Hartman
Browse files

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: default avatarYoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 29fab0cd
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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.
+78 −37
Original line number Diff line number Diff line
@@ -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) */

	r8a66597_bset(r8a66597, DCFM | DRPD, SYSCFG0);
	r8a66597_bset(r8a66597, DRPD, SYSCFG1);
	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);

	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);
+45 −0
Original line number Diff line number Diff line
@@ -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;