Skip to contentSkip to conversation

usb: lpc32xx: add host USB driver

PATCH Superseded slemieux.tyco at gmail.com 3 participants 4 messages Jul 17, 2015 – Jul 18, 2015

Subsystems (4)

v1 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH 3/3 usb: lpc32xx: add host USB driver

From: Sylvain Lemieux <[email protected]>

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

Updated 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 use of volatile in register definition taken from "lpc3250.h" header file.
5) Update driver for latest u-boot USB interface (board_usb init & board_usb_cleanup).
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/include/asm/arch-lpc32xx/clk.h |  12 ++
 drivers/usb/host/Makefile               |   1 +
 drivers/usb/host/ohci-lpc32xx.c         | 304 ++++++++++++++++++++++++++++++++
 3 files changed, 317 insertions(+)
 create mode 100644 drivers/usb/host/ohci-lpc32xx.c
arch/arm/include/asm/arch-lpc32xx/clk.h +12 -0
index 663f6bc..d21310e 100644
@@ -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);
drivers/usb/host/Makefile +1 -0
index 4d35d3e..9dfdc94 100644
@@ -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
drivers/usb/host/ohci-lpc32xx.c new file +304 -0

304 lines not on this page · raw message

Signature · 1 line
1.8.3.1
#1 lore raw

PATCH 3/3 usb: lpc32xx: add host USB driver

Quoted 1 line · slemieux.tyco at gmail.com

From: Sylvain Lemieux <[email protected]>

Hi!

Quoted 15 lines

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

Updated 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 use of volatile in register definition taken from "lpc3250.h" header file.
5) Update driver for latest u-boot USB interface (board_usb init & board_usb_cleanup). 6) Use the peripheral clock to compute the I2C divider.

[...]

Quoted 17 lines
drivers/usb/host/ohci-lpc32xx.c new file +17 -0
+static int i2c_wait_reset(int timeout)
+{
+	while (timeout > 0 && (readl(&otg->otg_i2c.otg_i2c_ctrl) & I2C_RESET)) {
+		udelay(1000);
+		timeout--;
+	}
+
+	return timeout <= 0;
+}
+
+static int isp1301_set_value(int reg, int value)
+{
+	int n = 0;
+
+	/* send isp1301 address */
+	writel((ISP1301_I2C_ADDR << 1) | I2C_START_BIT,
+	       &otg->otg_i2c.otg_i2c_txrx);

drivers/usb/host/ohci-lpc32xx.c line 150

Quoted 10 lines
drivers/usb/host/ohci-lpc32xx.c new file +10 -0
+
+	/* offset to write to */
+	writel((reg & 0xff) | I2C_WRITE, &otg->otg_i2c.otg_i2c_txrx);
+	/* value to write */
+	writel((value & 0xff) | I2C_STOP_BIT, &otg->otg_i2c.otg_i2c_txrx);
+
+	/* wait for transmit done (TDI) */
+	while (((readl(&otg->otg_i2c.otg_i2c_stat) & I2C_TDI) != I2C_TDI) &&
+	       n++ < 100000)
+		;

Can you please rework the timeouts to use get_timer() ? It looks like this:

start = get_timer(0);

do {
	if (readl(...) == FOO)
		break;
	udelay(1);	/* Don't do tightloop and poke WDT */
} while (get_timer(start) < DELAY_IN_MSECS);

drivers/usb/host/ohci-lpc32xx.c line 161

Quoted 10 lines
drivers/usb/host/ohci-lpc32xx.c new file +10 -0
+	if (n >= 100000) {
+		printf("isp1301_set_value: ERROR TDI not set\n");
+		return -1;
+	}
+
+	/* clear TDI */
+	setbits_le32(&otg->otg_i2c.otg_i2c_stat, I2C_TDI);
+
+	return 0;
+}

Don't you want to split this code out and make it into an actual i2c controller? Then, the USB driver would use regular i2c_*() calls to configure the device on the other end of the i2c bus. That'd be really cool and convenient.

[...]

Quoted 8 lines
drivers/usb/host/ohci-lpc32xx.c new file +8 -0
+int board_usb_init(int index, enum usb_init_type init)
+{
+	/* Remove warning. */
+	(void)index;
+
+	if (init != USB_INIT_HOST)
+		return -1;
+

drivers/usb/host/ohci-lpc32xx.c line 252

Quoted 10 lines
drivers/usb/host/ohci-lpc32xx.c new file +10 -0
+	/* 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);
+
+		while (readl(&otg->otg_clk_sts) != OTG_CLK_I2C_EN)
+			;

Ew..., such ugly infinite loops are a big no-no, please add a timeout here.

[...]

#2 lore raw

PATCH 3/3 usb: lpc32xx: add host USB driver

Hi Mark,

Thanks for the feedback;

Quoted 64 lines

From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Marek Vasut
Sent: 17-Jul-15 6:09 PM

Quoted 1 line · slemieux.tyco at gmail.com

From: Sylvain Lemieux <[email protected]>

Hi!

Quoted 15 lines

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

Updated 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 use of volatile in register definition taken from "lpc3250.h" header file.
5) Update driver for latest u-boot USB interface (board_usb init & board_usb_cleanup). 6) Use the peripheral clock to compute the I2C divider.

[...]

Quoted 17 lines
drivers/usb/host/ohci-lpc32xx.c new file +17 -0
+static int i2c_wait_reset(int timeout)
+{
+   while (timeout > 0 && (readl(&otg->otg_i2c.otg_i2c_ctrl) & I2C_RESET)) {
+           udelay(1000);
+           timeout--;
+   }
+
+   return timeout <= 0;
+}
+
+static int isp1301_set_value(int reg, int value)
+{
+   int n = 0;
+
+   /* send isp1301 address */
+   writel((ISP1301_I2C_ADDR << 1) | I2C_START_BIT,
+          &otg->otg_i2c.otg_i2c_txrx);

drivers/usb/host/ohci-lpc32xx.c line 150

Quoted 10 lines
drivers/usb/host/ohci-lpc32xx.c new file +10 -0
+
+   /* offset to write to */
+   writel((reg & 0xff) | I2C_WRITE, &otg->otg_i2c.otg_i2c_txrx);
+   /* value to write */
+   writel((value & 0xff) | I2C_STOP_BIT, &otg->otg_i2c.otg_i2c_txrx);
+
+   /* wait for transmit done (TDI) */
+   while (((readl(&otg->otg_i2c.otg_i2c_stat) & I2C_TDI) != I2C_TDI) &&
+          n++ < 100000)
+           ;

Can you please rework the timeouts to use get_timer() ? It looks like this:

start = get_timer(0);

do {
      if (readl(...) == FOO)
              break;
      udelay(1);      /* Don't do tightloop and poke WDT */
} while (get_timer(start) < DELAY_IN_MSECS);
Quoted 11 lines

drivers/usb/host/ohci-lpc32xx.c line 161

Quoted 10 lines
drivers/usb/host/ohci-lpc32xx.c new file +10 -0
+   if (n >= 100000) {
+           printf("isp1301_set_value: ERROR TDI not set\n");
+           return -1;
+   }
+
+   /* clear TDI */
+   setbits_le32(&otg->otg_i2c.otg_i2c_stat, I2C_TDI);
+
+   return 0;
+}

The initial posting was a porting effort only;
no problem, I will do the rework.

Quoted 4 lines

Don't you want to split this code out and make it into an actual i2c controller? Then, the USB driver would use regular i2c_*() calls to configure the device on the other end of the i2c bus. That'd be really cool and convenient.

I can look at this; but, I will not be able to do it before the following week. I will ensure to post my update before the merge window close.

There is already a LPC32xx I2C available in u-boot;
minor change will be require (ex. source clock is different for the USB I2C).

Quoted 14 lines

[...]

Quoted 12 lines
drivers/usb/host/ohci-lpc32xx.c new file +12 -0
+int board_usb_init(int index, enum usb_init_type init)
+{
+   /* Remove warning. */
+   (void)index;
+
+   if (init != USB_INIT_HOST)
+           return -1;
+
+   /* enable AHB slave USB clock */
+   setbits_le32(&clk_pwr->usb_ctrl,
+                CLK_USBCTRL_HCLK_EN | CLK_USBCTRL_BUS_KEEPER);
+
Quoted 9 lines

drivers/usb/host/ohci-lpc32xx.c line 252

Quoted 6 lines
drivers/usb/host/ohci-lpc32xx.c new file +6 -0
+   /* 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);
+
+           while (readl(&otg->otg_clk_sts) != OTG_CLK_I2C_EN)
+                   ;

Ew..., such ugly infinite loops are a big no-no, please add a timeout here.

Will do as part of the rework to improve the result of this porting effort.

Sylvain

________________________________

This e-mail contains privileged and confidential information intended for the use of the addressees named above. If you are not the intended recipient of this e-mail, you are hereby notified that you must not disseminate, copy or take any action in respect of any information contained in it. If you have received this e-mail in error, please notify the sender immediately by e-mail and immediately destroy this e-mail and its attachments.

#3 lore raw

PATCH 3/3 usb: lpc32xx: add host USB driver

Quoted 1 line · SYLVAIN

Hi Mark,

Hi!

Quoted 7 lines

Thanks for the feedback;

Quoted 5 lines

From: U-Boot [mailto:u-boot-bounces at lists.denx.de] On Behalf Of Marek Vasut Sent: 17-Jul-15 6:09 PM

Quoted 1 line · slemieux.tyco at gmail.com

From: Sylvain Lemieux <[email protected]>

[...]

Quoted 19 lines
Quoted 19 lines
Quoted 4 lines
(quoted diff) +2 -0
+   /* wait for transmit done (TDI) */
+   while (((readl(&otg->otg_i2c.otg_i2c_stat) & I2C_TDI) != I2C_TDI)

&& + n++ < 100000)
+ ;

Can you please rework the timeouts to use get_timer() ? It looks like this:

start = get_timer(0);
do {

      if (readl(...) == FOO)
      
              break;
      
      udelay(1);      /* Don't do tightloop and poke WDT */

} while (get_timer(start) < DELAY_IN_MSECS);

Quoted 13 lines
Quoted 10 lines

drivers/usb/host/ohci-lpc32xx.c line 161

Quoted 10 lines
drivers/usb/host/ohci-lpc32xx.c new file +10 -0
+   if (n >= 100000) {
+           printf("isp1301_set_value: ERROR TDI not set\n");
+           return -1;
+   }
+
+   /* clear TDI */
+   setbits_le32(&otg->otg_i2c.otg_i2c_stat, I2C_TDI);
+
+   return 0;
+}

The initial posting was a porting effort only;
no problem, I will do the rework.

Cool, thanks!

Quoted 7 lines
Quoted 4 lines

Don't you want to split this code out and make it into an actual i2c controller? Then, the USB driver would use regular i2c_*() calls to configure the device on the other end of the i2c bus. That'd be really cool and convenient.

I can look at this; but, I will not be able to do it before the following week. I will ensure to post my update before the merge window close.

No worries, thanks!

Quoted 3 lines

There is already a LPC32xx I2C available in u-boot;
minor change will be require (ex. source clock is different for the USB I2C).

Then that's even better, you'll have less code to take care of.

Quoted 24 lines
Quoted 15 lines

[...]

Quoted 13 lines
drivers/usb/host/ohci-lpc32xx.c new file +13 -0
+int board_usb_init(int index, enum usb_init_type init)
+{
+   /* Remove warning. */
+   (void)index;
+
+   if (init != USB_INIT_HOST)
+           return -1;
+
+   /* 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 */
Quoted 8 lines

drivers/usb/host/ohci-lpc32xx.c line 252

Quoted 5 lines

+ if ((readl(&otg->otg_clk_sts) & OTG_CLK_I2C_EN) != OTG_CLK_I2C_EN)
{ + writel(OTG_CLK_I2C_EN, &otg->otg_clk_ctrl);

drivers/usb/host/ohci-lpc32xx.c new file +3 -0
+
+           while (readl(&otg->otg_clk_sts) != OTG_CLK_I2C_EN)
+                   ;

Ew..., such ugly infinite loops are a big no-no, please add a timeout here.

Quoted 1 line

Will do as part of the rework to improve the result of this porting effort.

Thanks!