diff mbox

[U-Boot,v4,5/5] usb: lpc32xx: add host USB driver

Message ID 1438722282-3736-6-git-send-email-slemieux.tyco@gmail.com
State Superseded
Headers show

Commit Message

Sylvain Lemieux Aug. 4, 2015, 9:04 p.m. UTC
From: Sylvain Lemieux <slemieux@tycoint.com>

Incorporate USB driver from legacy LPCLinux NXP BSP.
The files taken from the legacy patch are:
- lpc32xx USB driver
- lpc3250 header file USB registers definition.

The legacy driver was updated and clean-up as part
of the integration with the latest u-boot.

Signed-off-by: Sylvain Lemieux <slemieux@tycoint.com>
---
Changes from v3 to v4:
* Addressed Marek's comments on LPC32xx USB driver:
  - use same "wait_for_bit()" implementation as
    drivers/usb/host/dwc2.c
  - use a const variable to define a mask to make
    the code more clear to read.
* Fixed legacy USB driver; use "otg_clk_sts" register
  to verify clock status instead of control register.

Changes from v2 to v3:
* Addressed Marek's comments on LPC32xx USB driver:
  - use "get_timer()" to handle timeout (usbpll_setup).
  - submit i2c driver update into a separate patch.
  - use "u32" for 4 bytes registers definition.
  - Move pin mux code to setup file (i.e. "device.c").
* Updated ISP1301 register definition (set & clear) instead 
  of using an extra mask for the clear address.

Changes from v1 to v2:
* Addressed Marek's comments on LPC32xx USB driver:
  - use "get_timer()" to handle timeout.
  - Split USB and I2C driver.
* Updated LPC32xx I2C driver to support the I2C that is part
  of the USB module.
* Removed ISP1301 USB transceiver I2C registers definition
  that are not used.
* Use "cpu" initialization & stop functions API instead of the "board" API.

Update to the legacy driver to integrate with the latest u-boot:
1) Fixed checkpatch script output in legacy code.
2) Use LPC32xx definition from "cpu.h" and "clk.h".
3) Incorporate USB specific register definition from "lpc3250.h"
   header file from legacy BSP patch from LPCLinux.
4) Use u-boot API for register access to remove the volatile
   in register definition taken from "lpc3250.h" header file.
5) Update driver for latest u-boot USB API.
6) Use the peripheral clock to compute the I2C divider.

The legacy BSP patch (u-boot-2009.03_lpc32x0-v1.07.patch.tar.bz2)
was downloaded from the LPCLinux Web site.

 arch/arm/cpu/arm926ejs/lpc32xx/devices.c      |   6 +
 arch/arm/include/asm/arch-lpc32xx/clk.h       |  12 ++
 arch/arm/include/asm/arch-lpc32xx/sys_proto.h |   1 +
 drivers/usb/host/Makefile                     |   1 +
 drivers/usb/host/ohci-lpc32xx.c               | 242 ++++++++++++++++++++++++++
 5 files changed, 262 insertions(+)
 create mode 100644 drivers/usb/host/ohci-lpc32xx.c

Comments

Marek Vasut Aug. 4, 2015, 9:33 p.m. UTC | #1
On Tuesday, August 04, 2015 at 11:04:42 PM, slemieux.tyco@gmail.com wrote:
> From: Sylvain Lemieux <slemieux@tycoint.com>
> 
> Incorporate USB driver from legacy LPCLinux NXP BSP.
> The files taken from the legacy patch are:
> - lpc32xx USB driver
> - lpc3250 header file USB registers definition.
> 
> The legacy driver was updated and clean-up as part
> of the integration with the latest u-boot.
> 
> Signed-off-by: Sylvain Lemieux <slemieux@tycoint.com>
> ---

Hi!

> +static int wait_for_bit(void *reg, const uint32_t mask, bool set)
> +{
> +	unsigned int timeout = 1000000;
> +	uint32_t val;
> +
> +	while (--timeout) {

Where did the get_timer() stuff disappear ? :'-(

> +		val = readl(reg);
> +		if (!set)
> +			val = ~val;
> +
> +		if ((val & mask) == mask)
> +			return 0;
> +
> +		udelay(1);
> +	}
> +
> +	debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n",
> +	      __func__, reg, mask, set);
> +
> +	return -ETIMEDOUT;
> +}

[...]

> +static int usbpll_setup(void)
> +{
> +	uint32_t ret;

u32, please fix all around.

> +	/* make sure clocks are disabled */
> +	clrbits_le32(&clk_pwr->usb_ctrl,
> +		     CLK_USBCTRL_CLK_EN1 | CLK_USBCTRL_CLK_EN2);
> +
> +	/* start PLL clock input */
> +	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_CLK_EN1);
> +
> +	/* Setup PLL. */
> +	setbits_le32(&clk_pwr->usb_ctrl,
> +		     CLK_USBCTRL_FDBK_PLUS1(192 - 1));
> +	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_POSTDIV_2POW(0x01));
> +	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_PWRUP);
> +
> +	ret = wait_for_bit(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_STS, 1);
> +	if (ret)
> +		return -1;
> +
> +	/* enable PLL output */
> +	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_CLK_EN2);
> +
> +	return 0;
> +}

[...]

> +	ret = wait_for_bit(&otg->otg_clk_sts, mask, 1);
> +	if (ret)
> +		return -1;

return ret; should be just find in these cases.

> +	setbits_le32(&otg->otg_sts_ctrl, OTG_HOST_EN);
> +	isp1301_set_value(ISP1301_I2C_OTG_CONTROL_1_SET, OTG1_VBUS_DRV);
> +
> +	return 0;
> +}
> +
> +int usb_cpu_stop(void)
> +{
> +	/* vbus off */
> +	isp1301_set_value(ISP1301_I2C_OTG_CONTROL_1_SET, OTG1_VBUS_DRV);
> +
> +	clrbits_le32(&otg->otg_sts_ctrl, OTG_HOST_EN);
> +
> +	clrbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_HCLK_EN);
> +
> +	return 0;
> +}
> +
> +int usb_cpu_init_fail(void)
> +{
> +	return usb_cpu_stop();
> +}
LEMIEUX, SYLVAIN Aug. 5, 2015, 10:54 a.m. UTC | #2
Hi Marek,

Is it OK to only submit the patch that need to be update as a new
version or I always have to resubmit the complete set of patches?

See comments and question below.


Sylvain

> -----Original Message-----
> From: Marek Vasut [mailto:marex@denx.de]
>
> On Tuesday, August 04, 2015 at 11:04:42 PM, slemieux.tyco@gmail.com wrote:
> > From: Sylvain Lemieux <slemieux@tycoint.com>
> >
> > Incorporate USB driver from legacy LPCLinux NXP BSP.
> > The files taken from the legacy patch are:
> > - lpc32xx USB driver
> > - lpc3250 header file USB registers definition.
> >
> > The legacy driver was updated and clean-up as part
> > of the integration with the latest u-boot.
> >
> > Signed-off-by: Sylvain Lemieux <slemieux@tycoint.com>
> > ---
>
> Hi!
>
> > +static int wait_for_bit(void *reg, const uint32_t mask, bool set)
> > +{
> > +   unsigned int timeout = 1000000;
> > +   uint32_t val;
> > +
> > +   while (--timeout) {
>
> Where did the get_timer() stuff disappear ? :'-(

I reused the "wait_for_bit()" from " drivers/usb/host/dwc2.c";
this implement does not use "get_timer()".

Should I update this driver implementation of "wait_for_bit()" to use
"get_timer()" or keep it the same as the implementation from "dwc2.c"?

>
> > +           val = readl(reg);
> > +           if (!set)
> > +                   val = ~val;
> > +
> > +           if ((val & mask) == mask)
> > +                   return 0;
> > +
> > +           udelay(1);
> > +   }
> > +
> > +   debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n",
> > +         __func__, reg, mask, set);
> > +
> > +   return -ETIMEDOUT;
> > +}
>
> [...]
>
> > +static int usbpll_setup(void)
> > +{
> > +   uint32_t ret;
>
> u32, please fix all around.

Will do.

>
> > +   /* make sure clocks are disabled */
> > +   clrbits_le32(&clk_pwr->usb_ctrl,
> > +                CLK_USBCTRL_CLK_EN1 | CLK_USBCTRL_CLK_EN2);
> > +
> > +   /* start PLL clock input */
> > +   setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_CLK_EN1);
> > +
> > +   /* Setup PLL. */
> > +   setbits_le32(&clk_pwr->usb_ctrl,
> > +                CLK_USBCTRL_FDBK_PLUS1(192 - 1));
> > +   setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_POSTDIV_2POW(0x01));
> > +   setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_PWRUP);
> > +
> > +   ret = wait_for_bit(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_STS, 1);
> > +   if (ret)
> > +           return -1;
> > +
> > +   /* enable PLL output */
> > +   setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_CLK_EN2);
> > +
> > +   return 0;
> > +}
>
> [...]
>
> > +   ret = wait_for_bit(&otg->otg_clk_sts, mask, 1);
> > +   if (ret)
> > +           return -1;
>
> return ret; should be just find in these cases.
>
Will do.

> > +   setbits_le32(&otg->otg_sts_ctrl, OTG_HOST_EN);
> > +   isp1301_set_value(ISP1301_I2C_OTG_CONTROL_1_SET, OTG1_VBUS_DRV);
> > +
> > +   return 0;
> > +}
> > +
> > +int usb_cpu_stop(void)
> > +{
> > +   /* vbus off */
> > +   isp1301_set_value(ISP1301_I2C_OTG_CONTROL_1_SET, OTG1_VBUS_DRV);
> > +
> > +   clrbits_le32(&otg->otg_sts_ctrl, OTG_HOST_EN);
> > +
> > +   clrbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_HCLK_EN);
> > +
> > +   return 0;
> > +}
> > +
> > +int usb_cpu_init_fail(void)
> > +{
> > +   return usb_cpu_stop();
> > +}
Marek Vasut Aug. 5, 2015, 1:10 p.m. UTC | #3
On Wednesday, August 05, 2015 at 12:54:38 PM, LEMIEUX, SYLVAIN wrote:
> Hi Marek,
> 
> Is it OK to only submit the patch that need to be update as a new
> version or I always have to resubmit the complete set of patches?

It's OK to submit just the patch, see "Sending updated patch versions"
at http://www.denx.de/wiki/U-Boot/Patches#General_Patch_Submission_Rules

> See comments and question below.
> 
> 
> Sylvain
> 
> > -----Original Message-----
> > From: Marek Vasut [mailto:marex@denx.de]
> > 
> > On Tuesday, August 04, 2015 at 11:04:42 PM, slemieux.tyco@gmail.com wrote:
> > > From: Sylvain Lemieux <slemieux@tycoint.com>
> > > 
> > > Incorporate USB driver from legacy LPCLinux NXP BSP.
> > > The files taken from the legacy patch are:
> > > - lpc32xx USB driver
> > > - lpc3250 header file USB registers definition.
> > > 
> > > The legacy driver was updated and clean-up as part
> > > of the integration with the latest u-boot.
> > > 
> > > Signed-off-by: Sylvain Lemieux <slemieux@tycoint.com>
> > > ---
> > 
> > Hi!
> > 
> > > +static int wait_for_bit(void *reg, const uint32_t mask, bool set)
> > > +{
> > > +   unsigned int timeout = 1000000;
> > > +   uint32_t val;
> > > +
> > > +   while (--timeout) {
> > 
> > Where did the get_timer() stuff disappear ? :'-(
> 
> I reused the "wait_for_bit()" from " drivers/usb/host/dwc2.c";
> this implement does not use "get_timer()".
> 
> Should I update this driver implementation of "wait_for_bit()" to use
> "get_timer()" or keep it the same as the implementation from "dwc2.c"?

If you feel like it, that'd be nice. Sorry for not being explicit about
keeping the get_timer() .

> > > +           val = readl(reg);
> > > +           if (!set)
> > > +                   val = ~val;
> > > +
> > > +           if ((val & mask) == mask)
> > > +                   return 0;
> > > +
> > > +           udelay(1);
> > > +   }
> > > +
> > > +   debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n",
> > > +         __func__, reg, mask, set);
> > > +
> > > +   return -ETIMEDOUT;
> > > +}
> > 

[...]
diff mbox

Patch

diff --git a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
index 0d2ef7a..3da0952 100644
--- a/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
+++ b/arch/arm/cpu/arm926ejs/lpc32xx/devices.c
@@ -82,6 +82,12 @@  void lpc32xx_i2c_init(unsigned int devnum)
 	writel(ctrl, &clk->i2cclk_ctrl);
 }
 
+void lpc32xx_usb_init(void)
+{
+	/* Do not route the UART 5 Tx/Rx pins to the USB D+ and USB D- pins. */
+	clrbits_le32(&ctrl->ctrl, UART_CTRL_UART5_USB_MODE);
+}
+
 U_BOOT_DEVICE(lpc32xx_gpios) = {
 	.name = "gpio_lpc32xx"
 };
diff --git a/arch/arm/include/asm/arch-lpc32xx/clk.h b/arch/arm/include/asm/arch-lpc32xx/clk.h
index 663f6bc..d21310e 100644
--- a/arch/arm/include/asm/arch-lpc32xx/clk.h
+++ b/arch/arm/include/asm/arch-lpc32xx/clk.h
@@ -167,6 +167,18 @@  struct clk_pm_regs {
 /* SDRAMCLK register bits */
 #define CLK_SDRAM_DDR_SEL		(1 << 1)
 
+/* USB control register definitions */
+#define CLK_USBCTRL_PLL_STS		(1 << 0)
+#define CLK_USBCTRL_FDBK_PLUS1(n)	(((n) & 0xFF) << 1)
+#define CLK_USBCTRL_POSTDIV_2POW(n)	(((n) & 0x3) << 11)
+#define CLK_USBCTRL_PLL_PWRUP		(1 << 16)
+#define CLK_USBCTRL_CLK_EN1		(1 << 17)
+#define CLK_USBCTRL_CLK_EN2		(1 << 18)
+#define CLK_USBCTRL_BUS_KEEPER		(0x1 << 19)
+#define CLK_USBCTRL_USBHSTND_EN		(1 << 21)
+#define CLK_USBCTRL_USBDVND_EN		(1 << 22)
+#define CLK_USBCTRL_HCLK_EN		(1 << 24)
+
 unsigned int get_sys_clk_rate(void);
 unsigned int get_hclk_pll_rate(void);
 unsigned int get_hclk_clk_div(void);
diff --git a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
index 7f997d9..ca7790a 100644
--- a/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
+++ b/arch/arm/include/asm/arch-lpc32xx/sys_proto.h
@@ -14,6 +14,7 @@  void lpc32xx_mac_init(void);
 void lpc32xx_mlc_nand_init(void);
 void lpc32xx_slc_nand_init(void);
 void lpc32xx_dma_init(void);
+void lpc32xx_usb_init(void);
 void lpc32xx_i2c_init(unsigned int devnum);
 void lpc32xx_ssp_init(void);
 #if defined(CONFIG_SPL_BUILD)
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 4d35d3e..9dfdc94 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -20,6 +20,7 @@  obj-$(CONFIG_USB_SL811HS) += sl811-hcd.o
 obj-$(CONFIG_USB_OHCI_S3C24XX) += ohci-s3c24xx.o
 obj-$(CONFIG_USB_OHCI_EP93XX) += ohci-ep93xx.o
 obj-$(CONFIG_USB_OHCI_SUNXI) += ohci-sunxi.o
+obj-$(CONFIG_USB_OHCI_LPC32XX) += ohci-lpc32xx.o
 
 # echi
 obj-$(CONFIG_USB_EHCI) += ehci-hcd.o
diff --git a/drivers/usb/host/ohci-lpc32xx.c b/drivers/usb/host/ohci-lpc32xx.c
new file mode 100644
index 0000000..ec87e01
--- /dev/null
+++ b/drivers/usb/host/ohci-lpc32xx.c
@@ -0,0 +1,242 @@ 
+/*
+ * Copyright (C) 2008-2015 by NXP Semiconductors
+ * All rights reserved.
+ *
+ * @Author: Based on code by Kevin Wells
+ * @Descr: USB driver - Embedded Artists LPC3250 OEM Board support functions
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clk.h>
+#include <usb.h>
+#include <i2c.h>
+
+/*
+ * Notes:
+ *
+ * Only bitfield masks/values which are actually used by the driver
+ * are defined.
+ */
+
+/* OTG I2C controller module register structures */
+struct otgi2c_regs {
+	u32 otg_i2c_txrx;   /* OTG I2C Tx/Rx Data FIFO */
+	u32 otg_i2c_stat;   /* OTG I2C Status Register */
+	u32 otg_i2c_ctrl;   /* OTG I2C Control Register */
+	u32 otg_i2c_clk_hi; /* OTG I2C Clock Divider high */
+	u32 otg_i2c_clk_lo; /* OTG I2C Clock Divider low */
+};
+
+/* OTG controller module register structures */
+struct otg_regs {
+	u32 reserved1[64];
+	u32 otg_int_sts;    /* OTG int status register */
+	u32 otg_int_enab;   /* OTG int enable register */
+	u32 otg_int_set;    /* OTG int set register */
+	u32 otg_int_clr;    /* OTG int clear register */
+	u32 otg_sts_ctrl;   /* OTG status/control register */
+	u32 otg_timer;      /* OTG timer register */
+	u32 reserved2[122];
+	struct otgi2c_regs otg_i2c;
+	u32 reserved3[824];
+	u32 otg_clk_ctrl;   /* OTG clock control reg */
+	u32 otg_clk_sts;    /* OTG clock status reg */
+};
+
+/* otg_sts_ctrl register definitions */
+#define OTG_HOST_EN			(1 << 0) /* Enable host mode */
+
+/* otg_clk_ctrl and otg_clk_sts register definitions */
+#define OTG_CLK_AHB_EN			(1 << 4) /* Enable AHB clock */
+#define OTG_CLK_OTG_EN			(1 << 3) /* Enable OTG clock */
+#define OTG_CLK_I2C_EN			(1 << 2) /* Enable I2C clock */
+#define OTG_CLK_HOST_EN			(1 << 0) /* Enable host clock */
+
+/* ISP1301 USB transceiver I2C registers */
+#define MC1_SPEED_REG			(1 << 0)
+#define MC1_DAT_SE0			(1 << 2)
+#define MC1_UART_EN			(1 << 6)
+
+#define MC2_SPD_SUSP_CTRL		(1 << 1)
+#define MC2_BI_DI			(1 << 2)
+#define MC2_PSW_EN			(1 << 6)
+
+#define OTG1_DP_PULLUP			(1 << 0)
+#define OTG1_DM_PULLUP			(1 << 1)
+#define OTG1_DP_PULLDOWN		(1 << 2)
+#define OTG1_DM_PULLDOWN		(1 << 3)
+#define OTG1_VBUS_DRV			(1 << 5)
+
+#define ISP1301_I2C_ADDR		CONFIG_USB_ISP1301_I2C_ADDR
+
+#define ISP1301_I2C_MODE_CONTROL_1_SET		0x04
+#define ISP1301_I2C_MODE_CONTROL_1_CLR		0x05
+#define ISP1301_I2C_MODE_CONTROL_2_SET		0x12
+#define ISP1301_I2C_MODE_CONTROL_2_CLR		0x13
+#define ISP1301_I2C_OTG_CONTROL_1_SET		0x06
+#define ISP1301_I2C_OTG_CONTROL_1_CLR		0x07
+#define ISP1301_I2C_INTERRUPT_LATCH_CLR		0x0B
+#define ISP1301_I2C_INTERRUPT_FALLING_CLR	0x0D
+#define ISP1301_I2C_INTERRUPT_RISING_CLR	0x0F
+
+static struct otg_regs *otg = (struct otg_regs *)USB_BASE;
+static struct clk_pm_regs *clk_pwr = (struct clk_pm_regs *)CLK_PM_BASE;
+
+static int wait_for_bit(void *reg, const uint32_t mask, bool set)
+{
+	unsigned int timeout = 1000000;
+	uint32_t val;
+
+	while (--timeout) {
+		val = readl(reg);
+		if (!set)
+			val = ~val;
+
+		if ((val & mask) == mask)
+			return 0;
+
+		udelay(1);
+	}
+
+	debug("%s: Timeout (reg=%p mask=%08x wait_set=%i)\n",
+	      __func__, reg, mask, set);
+
+	return -ETIMEDOUT;
+}
+
+static int isp1301_set_value(int reg, u8 value)
+{
+	return i2c_write(ISP1301_I2C_ADDR, reg, 1, &value, 1);
+}
+
+static void isp1301_configure(void)
+{
+	i2c_set_bus_num(I2C_2);
+
+	/* LPC32XX only supports DAT_SE0 USB mode */
+	/* This sequence is important */
+
+	/* Disable transparent UART mode first */
+	isp1301_set_value(ISP1301_I2C_MODE_CONTROL_1_CLR, MC1_UART_EN);
+
+	isp1301_set_value(ISP1301_I2C_MODE_CONTROL_1_CLR, ~MC1_SPEED_REG);
+	isp1301_set_value(ISP1301_I2C_MODE_CONTROL_1_SET, MC1_SPEED_REG);
+	isp1301_set_value(ISP1301_I2C_MODE_CONTROL_2_CLR, ~0);
+	isp1301_set_value(ISP1301_I2C_MODE_CONTROL_2_SET,
+			  MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL);
+
+	isp1301_set_value(ISP1301_I2C_OTG_CONTROL_1_CLR, ~0);
+	isp1301_set_value(ISP1301_I2C_MODE_CONTROL_1_SET, MC1_DAT_SE0);
+	isp1301_set_value(ISP1301_I2C_OTG_CONTROL_1_SET,
+			  OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
+	isp1301_set_value(ISP1301_I2C_OTG_CONTROL_1_CLR,
+			  OTG1_DM_PULLUP | OTG1_DP_PULLUP);
+	isp1301_set_value(ISP1301_I2C_INTERRUPT_LATCH_CLR, ~0);
+	isp1301_set_value(ISP1301_I2C_INTERRUPT_FALLING_CLR, ~0);
+	isp1301_set_value(ISP1301_I2C_INTERRUPT_RISING_CLR, ~0);
+
+	/* Enable usb_need_clk clock after transceiver is initialized */
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_USBDVND_EN);
+}
+
+static int usbpll_setup(void)
+{
+	uint32_t ret;
+
+	/* make sure clocks are disabled */
+	clrbits_le32(&clk_pwr->usb_ctrl,
+		     CLK_USBCTRL_CLK_EN1 | CLK_USBCTRL_CLK_EN2);
+
+	/* start PLL clock input */
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_CLK_EN1);
+
+	/* Setup PLL. */
+	setbits_le32(&clk_pwr->usb_ctrl,
+		     CLK_USBCTRL_FDBK_PLUS1(192 - 1));
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_POSTDIV_2POW(0x01));
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_PWRUP);
+
+	ret = wait_for_bit(&clk_pwr->usb_ctrl, CLK_USBCTRL_PLL_STS, 1);
+	if (ret)
+		return -1;
+
+	/* enable PLL output */
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_CLK_EN2);
+
+	return 0;
+}
+
+int usb_cpu_init(void)
+{
+	unsigned long start;
+	uint32_t ret;
+
+	/* USB pins routing setup is done by "lpc32xx_usb_init()" and should
+	 * be call by board "board_init()" or "misc_init_r()" functions. */
+
+	/* enable AHB slave USB clock */
+	setbits_le32(&clk_pwr->usb_ctrl,
+		     CLK_USBCTRL_HCLK_EN | CLK_USBCTRL_BUS_KEEPER);
+
+	/* enable I2C clock in OTG block if it isn't */
+	if ((readl(&otg->otg_clk_sts) & OTG_CLK_I2C_EN) != OTG_CLK_I2C_EN) {
+		writel(OTG_CLK_I2C_EN, &otg->otg_clk_ctrl);
+
+		start = get_timer(0);
+		while (1) {
+			if (readl(&otg->otg_clk_sts) == OTG_CLK_I2C_EN)
+				break;
+
+			if (get_timer(start) > 100)
+				return -1;
+
+			udelay(1);
+		}
+	}
+
+	/* Configure ISP1301 */
+	isp1301_configure();
+
+	/* setup USB clocks and PLL */
+	if (usbpll_setup() == -1)
+		return -1;
+
+	/* enable usb_host_need_clk */
+	setbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_USBHSTND_EN);
+
+	/* enable all needed USB clocks */
+	const u32 mask = OTG_CLK_AHB_EN | OTG_CLK_OTG_EN |
+			 OTG_CLK_I2C_EN | OTG_CLK_HOST_EN;
+	writel(mask, &otg->otg_clk_ctrl);
+
+	ret = wait_for_bit(&otg->otg_clk_sts, mask, 1);
+	if (ret)
+		return -1;
+
+	setbits_le32(&otg->otg_sts_ctrl, OTG_HOST_EN);
+	isp1301_set_value(ISP1301_I2C_OTG_CONTROL_1_SET, OTG1_VBUS_DRV);
+
+	return 0;
+}
+
+int usb_cpu_stop(void)
+{
+	/* vbus off */
+	isp1301_set_value(ISP1301_I2C_OTG_CONTROL_1_SET, OTG1_VBUS_DRV);
+
+	clrbits_le32(&otg->otg_sts_ctrl, OTG_HOST_EN);
+
+	clrbits_le32(&clk_pwr->usb_ctrl, CLK_USBCTRL_HCLK_EN);
+
+	return 0;
+}
+
+int usb_cpu_init_fail(void)
+{
+	return usb_cpu_stop();
+}