linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310
@ 2010-04-07 15:05 Igor Grinberg
  2010-04-07 15:05 ` [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for " Igor Grinberg
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Igor Grinberg @ 2010-04-07 15:05 UTC (permalink / raw)
  To: linux-arm-kernel

The USB port 2 on PXA310 is an OTG port which can be utilized by OHCI controller
in host mode and by high-speed USB device controller in device mode.
Enabling this port in host mode only still requires manipulation of UDC and
OTG controller registers for proper USB PHY initialization.
This patch series add a minimalistic implementation of PHY configuration mechanism
that can be used across PXA310 based platforms.

Igor Grinberg (2):
  [ARM] pxa: add minimal ULPI functionality for USB host port 2 on
    PXA310.
  [ARM] pxa/cm-x300: enable USB host port 2 on modules with PXA310 cpu.

 arch/arm/mach-pxa/Makefile      |    1 +
 arch/arm/mach-pxa/cm-x300.c     |   65 +++++++++++
 arch/arm/mach-pxa/pxa310-ulpi.c |  240 +++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-pxa/pxa310-ulpi.h |   85 ++++++++++++++
 4 files changed, 391 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.c
 create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.h

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for USB host port 2 on PXA310.
  2010-04-07 15:05 [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310 Igor Grinberg
@ 2010-04-07 15:05 ` Igor Grinberg
  2010-04-13 20:18   ` Eric Miao
  2010-04-13 22:06   ` Daniel Mack
  2010-04-07 15:05 ` [PATCH 2/2] [ARM] pxa/cm-x300: enable USB host port 2 on modules with PXA310 cpu Igor Grinberg
  2010-04-12  5:52 ` [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310 Mike Rapoport
  2 siblings, 2 replies; 8+ messages in thread
From: Igor Grinberg @ 2010-04-07 15:05 UTC (permalink / raw)
  To: linux-arm-kernel


Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
---
 arch/arm/mach-pxa/Makefile      |    1 +
 arch/arm/mach-pxa/pxa310-ulpi.c |  240 +++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-pxa/pxa310-ulpi.h |   85 ++++++++++++++
 3 files changed, 326 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.c
 create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.h

diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 86bc87b..76d52f4 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_PXA25x)		+= mfp-pxa2xx.o pxa2xx.o pxa25x.o
 obj-$(CONFIG_PXA27x)		+= mfp-pxa2xx.o pxa2xx.o pxa27x.o
 obj-$(CONFIG_PXA3xx)		+= mfp-pxa3xx.o pxa3xx.o smemc.o
 obj-$(CONFIG_CPU_PXA300)	+= pxa300.o
+obj-$(CONFIG_CPU_PXA310)	+= pxa310-ulpi.o
 obj-$(CONFIG_CPU_PXA320)	+= pxa320.o
 obj-$(CONFIG_CPU_PXA930)	+= pxa930.o
 
diff --git a/arch/arm/mach-pxa/pxa310-ulpi.c b/arch/arm/mach-pxa/pxa310-ulpi.c
new file mode 100644
index 0000000..ab82db8
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa310-ulpi.c
@@ -0,0 +1,240 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa310-ulpi.c
+ *
+ * PXA310 ULPI USB host implementation.
+ *
+ * Copyright (C) 2010 CompuLab Ltd.
+ *
+ * Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include <mach/regs-u2d.h>
+
+#include "pxa310-ulpi.h"
+
+static void __iomem *u2d_mmio_base;
+
+static inline unsigned int u2d_readl(unsigned int off)
+{
+	return __raw_readl(u2d_mmio_base + off);
+}
+
+static inline void u2d_writel(unsigned int off, unsigned int val)
+{
+	__raw_writel(val, u2d_mmio_base + off);
+}
+
+static inline enum u2d_phy_mode ulpi_get_phymode(void)
+{
+	return (u2d_readl(U2DOTGUSR) & 0xF0000000) >> 28;
+}
+
+static bool ulpi_is_in_sync_mode(void)
+{
+	enum u2d_phy_mode state = ulpi_get_phymode();
+
+	return (state == SYNCH) || (state == PRE_SYNCH);
+}
+
+static int ulpi_poll(void)
+{
+	int timeout = 50000;
+
+	while (timeout--) {
+		if (!(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RUN))
+			return 0;
+
+		cpu_relax();
+	}
+
+	pr_warning("%s: ULPI access timed out!\n", __func__);
+
+	return -ETIMEDOUT;
+}
+
+static int ulpi_reg_read(u8 reg, u8 *value)
+{
+	int err = 0;
+
+	if (!ulpi_is_in_sync_mode()) {
+		pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
+		return -EBUSY;
+	}
+
+	u2d_writel(U2DOTGUCR,
+		   U2DOTGUCR_RUN | U2DOTGUCR_RNW | (reg << U2DOTGUCR_ADDR_S));
+	msleep(5);
+
+	err = ulpi_poll();
+	if (err)
+		return err;
+
+	*value = (u8)(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA);
+
+	return 0;
+}
+
+static int ulpi_reg_write(u8 reg, u8 value)
+{
+	int err;
+
+	if (!ulpi_is_in_sync_mode()) {
+		pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
+		return -EBUSY;
+	}
+
+	u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | (reg << U2DOTGUCR_ADDR_S)
+					    | (value << U2DOTGUCR_WDATA_S));
+	msleep(5);
+
+	err = ulpi_poll();
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static int u2d_clk_enable(void)
+{
+	int err;
+	struct clk *u2d_clk;
+
+	u2d_clk = clk_get(NULL, "U2DCLK");
+	if (IS_ERR(u2d_clk)) {
+		err = PTR_ERR(u2d_clk);
+		pr_err("%s: failed to get U2DCLK: %d\n", __func__, err);
+		return err;
+	}
+	clk_enable(u2d_clk);
+
+	return 0;
+}
+
+static void u2d_otg_host_init(void)
+{
+	u32 u2dotgcr;
+
+	/* setup OTG controller registers */
+	u2dotgcr = u2d_readl(U2DOTGCR);
+	u2dotgcr |= U2DOTGCR_ULAF | U2DOTGCR_UTMID;
+	u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
+	u2d_writel(U2DOTGCR, u2dotgcr);
+	msleep(5);
+	u2d_writel(U2DOTGCR, u2dotgcr | U2DOTGCR_ULE);
+	msleep(5);
+
+	/* no OTG interrupts in host mode */
+	u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~U2DOTGICR_MASK);
+}
+
+static void u2d_ulpi_rtsm(void)
+{
+	u32 u2dotgcr;
+
+	/* put PHY to sync mode */
+	u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_RTSM);
+	msleep(10);
+
+	/* setup OTG sync mode */
+	u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_ULAF;
+	u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
+	u2d_writel(U2DOTGCR, u2dotgcr);
+}
+
+static void u2d_disable_otg_device(void)
+{
+	/* disable USB2 Device controller */
+	u2d_writel(U2DCR, u2d_readl(U2DCR) & ~U2DCR_UDE);
+	u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_UTMID);
+
+	/* disable the otg interrupts */
+	u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~U2DOTGICR_MASK);
+}
+
+static int u2d_set_ulpi_serial(enum u2d_phy_mode mode)
+{
+	int err = 0;
+	u32 u2dotgcr;
+
+	/* enable the 15K Ohm pull-down resistor on D+ */
+	err = ulpi_reg_write(ULPI_OTG_CONTROL_SET, ULPI_OC_DPPULLDOWN);
+	if (err)
+		return err;
+
+	/* enable the 15K Ohm pull-down resistor on D- */
+	err = ulpi_reg_write(ULPI_OTG_CONTROL_SET, ULPI_OC_DMPULLDOWN);
+	if (err)
+		return err;
+
+	/* drive 5V on VBUS */
+	err = ulpi_reg_write(ULPI_OTG_CONTROL_SET, ULPI_OC_DRVVBUS);
+	if (err)
+		return err;
+
+	/* configure UHC for 6/3-pin serial mode */
+	if (mode == SER_6PIN)
+		u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) & ~U2DP3CR_P2SS);
+	else if (mode == SER_3PIN)
+		u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) | U2DP3CR_P2SS);
+
+	/* put PHY into host mode */
+	err = ulpi_reg_write(ULPI_FUNCTION_CONTROL_SET, 0x45);
+	if (err)
+		return err;
+
+	/* set PHY to serial 6/3 pin mode */
+	if (mode == SER_6PIN)
+		err = ulpi_reg_write(ULPI_INTERFACE_CONTROL, ULPI_IC_6PIN);
+	else if (mode == SER_3PIN)
+		err = ulpi_reg_write(ULPI_INTERFACE_CONTROL, ULPI_IC_3PIN);
+	if (err)
+		return err;
+
+	/* enable the serial mode */
+	u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_SMAF;
+	u2d_writel(U2DOTGCR, u2dotgcr & ~(U2DOTGCR_ULAF | U2DOTGCR_CKAF));
+
+	return 0;
+}
+
+int pxa310_ulpi_init(enum u2d_phy_mode mode)
+{
+	int err;
+
+	err = u2d_clk_enable();
+	if (err)
+		goto err_out;
+
+	u2d_mmio_base = ioremap(U2D_PHYS_BASE, 0x1300);
+	if (u2d_mmio_base == NULL) {
+		pr_err("%s: failed to remap U2D registers address space\n",
+			__func__);
+		err = -ENOMEM;
+		goto err_out;
+	}
+
+	u2d_otg_host_init();
+	u2d_ulpi_rtsm();
+	u2d_disable_otg_device();
+
+	err = u2d_set_ulpi_serial(mode);
+	if (err)
+		goto err_out;
+
+	return 0;
+
+err_out:
+	pr_err("%s: ULPI init failed: %d\n", __func__, err);
+	return err;
+}
diff --git a/arch/arm/mach-pxa/pxa310-ulpi.h b/arch/arm/mach-pxa/pxa310-ulpi.h
new file mode 100644
index 0000000..87558f0
--- /dev/null
+++ b/arch/arm/mach-pxa/pxa310-ulpi.h
@@ -0,0 +1,85 @@
+/*
+ * linux/arch/arm/mach-pxa/pxa310-ulpi.h
+ *
+ * PXA310 ULPI USB host header file.
+ *
+ * Copyright (C) 2010 CompuLab Ltd.
+ *
+ * Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __PXA310_ULPI__
+#define __PXA310_ULPI__
+
+/* OTG Interrupts */
+#define U2DOTGICR_MASK		0x37F7F
+
+/* PXA310 USB OTG Controller */
+#define ULPI_VENDOR_LOW		0x0
+#define ULPI_VENDOR_HIGH		0x1
+#define ULPI_PRODUCT_LOW		0x2
+#define ULPI_PRODUCT_HIGH		0x3
+#define ULPI_FUNCTION_CONTROL		0x4
+#define ULPI_FUNCTION_CONTROL_SET	0x5
+#define ULPI_FUNCTION_CONTROL_CLEAR	0x6
+#define ULPI_INTERFACE_CONTROL		0x7
+#define ULPI_INTERFACE_CONTROL_SET	0x8
+#define ULPI_INTERFACE_CONTROL_CLEAR	0x9
+#define ULPI_OTG_CONTROL		0xA
+#define ULPI_OTG_CONTROL_SET		0xB
+#define ULPI_OTG_CONTROL_CLEAR		0xC
+#define ULPI_INT_RISE			0xD
+#define ULPI_INT_RISE_SET		0xE
+#define ULPI_INT_RISE_CLEAR		0xF
+#define ULPI_INT_FALL			0x10
+#define ULPI_INT_FALL_SET		0x11
+#define ULPI_INT_FALL_CLEAR		0x12
+#define ULPI_INT_STATUS		0x13
+#define ULPI_INT_LATCH			0x14
+#define ULPI_DEBUG			0x15
+#define ULPI_SCRATCH			0x16
+#define ULPI_SCRATCH_SET		0x17
+#define ULPI_SCRATCH_CLEAR		0x18
+
+#define ULPI_FC_RESET		(1 << 5)	/* XCVR Reset */
+#define ULPI_FC_SUSPENDM	(1 << 6)	/* XCVR SuspendM, Low Power Mode */
+
+#define ULPI_IC_6PIN		(1 << 0)	/* XCVR 6 pin mode */
+#define ULPI_IC_3PIN		(1 << 1)	/* XCVR 3 pin mode */
+#define ULPI_IC_CARKIT		(1 << 2)	/* Carkit mode */
+#define ULPI_IC_CLKSUSPENDM	(1 << 3)	/* Active low clock suspend */
+
+#define ULPI_OC_IDPULLUP	(1 << 0)	/* ID Pull Up, enable sampling of ID line */
+#define ULPI_OC_DPPULLDOWN	(1 << 1)	/* Enable the 15K Ohm pull down resistor on D+ */
+#define ULPI_OC_DMPULLDOWN	(1 << 2)	/* Enable the 15K Ohm pull down resistor on D- */
+#define ULPI_OC_DISCHRGVBUS	(1 << 3)	/* Discharge Vbus */
+#define ULPI_OC_CHRGVBUS	(1 << 4)	/* Charge Vbus, for Vbus pulsing SRP */
+#define ULPI_OC_DRVVBUS	(1 << 5)	/* Drive 5V on Vbus */
+#define ULPI_OC_DRVVBUSEXT	(1 << 6)	/* Drive Vbus using external supply */
+
+#define ULPI_INT_HOSTDISCON	(1 << 0)	/* Host Disconnect */
+#define ULPI_INT_VBUSVALID	(1 << 1)	/* Vbus Valid */
+#define ULPI_INT_SESSIONVALID	(1 << 2)	/* Session Valid */
+#define ULPI_INT_SESSIONEND	(1 << 3)	/* Session End */
+#define ULPI_INT_IDGND		(1 << 4)	/* current status of IDGND */
+
+#define U2DOTGUCR_ADDR_S	(16)
+#define U2DOTGUCR_WDATA_S	(8)
+
+#define U2D_PHYS_BASE   0x54100000
+
+enum u2d_phy_mode {
+	SYNCH		= 0,
+	CARKIT		= (1 << 0),
+	SER_3PIN	= (1 << 1),
+	SER_6PIN	= (1 << 2),
+	LOWPOWER	= (1 << 3),
+	PRE_SYNCH	= (1 << 4),
+};
+
+int pxa310_ulpi_init(enum u2d_phy_mode);
+
+#endif /* __PXA310_ULPI__ */
-- 
1.6.4.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] [ARM] pxa/cm-x300: enable USB host port 2 on modules with PXA310 cpu.
  2010-04-07 15:05 [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310 Igor Grinberg
  2010-04-07 15:05 ` [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for " Igor Grinberg
@ 2010-04-07 15:05 ` Igor Grinberg
  2010-04-12  5:52 ` [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310 Mike Rapoport
  2 siblings, 0 replies; 8+ messages in thread
From: Igor Grinberg @ 2010-04-07 15:05 UTC (permalink / raw)
  To: linux-arm-kernel


Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
Signed-off-by: Mike Rapoport <mike@compulab.co.il>
---
 arch/arm/mach-pxa/cm-x300.c |   65 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 65 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-pxa/cm-x300.c b/arch/arm/mach-pxa/cm-x300.c
index d37cfa1..e8f02a7 100644
--- a/arch/arm/mach-pxa/cm-x300.c
+++ b/arch/arm/mach-pxa/cm-x300.c
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 
 #include <linux/gpio.h>
 #include <linux/dm9000.h>
@@ -52,6 +53,7 @@
 
 #include "generic.h"
 #include "devices.h"
+#include "pxa310-ulpi.h"
 
 #define CM_X300_ETH_PHYS	0x08000010
 
@@ -65,6 +67,8 @@
 #define GPIO97_RTC_RD		(97)
 #define GPIO98_RTC_IO		(98)
 
+#define GPIO127_ULPI_PHY_RST	(127)
+
 static mfp_cfg_t cm_x3xx_mfp_cfg[] __initdata = {
 	/* LCD */
 	GPIO54_LCD_LDD_0,
@@ -470,12 +474,73 @@ static inline void cm_x300_init_mmc(void) {}
 #endif
 
 #if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static int cm_x300_ulpi_clk_enable(void)
+{
+	int err;
+	struct clk *pout_clk;
+
+	/* CLK_POUT is connected to the ULPI PHY */
+	pout_clk = clk_get(NULL, "CLK_POUT");
+	if (IS_ERR(pout_clk)) {
+		err = PTR_ERR(pout_clk);
+		pr_err("%s: failed to get CLK_POUT: %d\n", __func__, err);
+		return err;
+	}
+	clk_enable(pout_clk);
+
+	return 0;
+}
+
+static int cm_x300_ulpi_phy_reset(void)
+{
+	int err;
+
+	/* reset the PHY */
+	err = gpio_request(GPIO127_ULPI_PHY_RST, "ulpi reset");
+	if (err) {
+		pr_err("%s: failed to request ULPI reset GPIO: %d\n",
+		       __func__, err);
+		return err;
+	}
+
+	gpio_direction_output(GPIO127_ULPI_PHY_RST, 0);
+	msleep(10);
+	gpio_set_value(GPIO127_ULPI_PHY_RST, 1);
+	msleep(10);
+
+	gpio_free(GPIO127_ULPI_PHY_RST);
+
+	return 0;
+}
+
+static int cm_x300_ulpi_init(void)
+{
+	int err;
+
+	err = cm_x300_ulpi_clk_enable();
+	if (err)
+		return err;
+
+	err = cm_x300_ulpi_phy_reset();
+	if (err) {
+		pr_err("%s: ULPI PHY init failed!\n", __func__);
+		return err;
+	}
+
+	err = pxa310_ulpi_init(SER_6PIN);
+
+	return err;
+}
+
 static int cm_x300_ohci_init(struct device *dev)
 {
 	if (cpu_is_pxa300())
 		UP2OCR = UP2OCR_HXS
 			| UP2OCR_HXOE | UP2OCR_DMPDE | UP2OCR_DPPDE;
 
+	if (cpu_is_pxa310())
+		cm_x300_ulpi_init();
+
 	return 0;
 }
 
-- 
1.6.4.4

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310
  2010-04-07 15:05 [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310 Igor Grinberg
  2010-04-07 15:05 ` [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for " Igor Grinberg
  2010-04-07 15:05 ` [PATCH 2/2] [ARM] pxa/cm-x300: enable USB host port 2 on modules with PXA310 cpu Igor Grinberg
@ 2010-04-12  5:52 ` Mike Rapoport
  2 siblings, 0 replies; 8+ messages in thread
From: Mike Rapoport @ 2010-04-12  5:52 UTC (permalink / raw)
  To: linux-arm-kernel

Eric,
Any comments?

Igor Grinberg wrote:
> The USB port 2 on PXA310 is an OTG port which can be utilized by OHCI controller
> in host mode and by high-speed USB device controller in device mode.
> Enabling this port in host mode only still requires manipulation of UDC and
> OTG controller registers for proper USB PHY initialization.
> This patch series add a minimalistic implementation of PHY configuration mechanism
> that can be used across PXA310 based platforms.
> 
> Igor Grinberg (2):
>   [ARM] pxa: add minimal ULPI functionality for USB host port 2 on
>     PXA310.
>   [ARM] pxa/cm-x300: enable USB host port 2 on modules with PXA310 cpu.
> 
>  arch/arm/mach-pxa/Makefile      |    1 +
>  arch/arm/mach-pxa/cm-x300.c     |   65 +++++++++++
>  arch/arm/mach-pxa/pxa310-ulpi.c |  240 +++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-pxa/pxa310-ulpi.h |   85 ++++++++++++++
>  4 files changed, 391 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.c
>  create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.h
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel


-- 
Sincerely yours,
Mike.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for USB host port 2 on PXA310.
  2010-04-07 15:05 ` [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for " Igor Grinberg
@ 2010-04-13 20:18   ` Eric Miao
  2010-04-13 22:06   ` Daniel Mack
  1 sibling, 0 replies; 8+ messages in thread
From: Eric Miao @ 2010-04-13 20:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 7, 2010 at 11:05 PM, Igor Grinberg <grinberg@compulab.co.il> wrote:
>
> Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
> Signed-off-by: Mike Rapoport <mike@compulab.co.il>

Include Jing as she's ULPI expert. I myself do not understand the
ULPI well enough.

One general comment though, do we need to make this a dedicated
OTG driver within drivers/usb/otg/? as I know it's OTG capable, but
might be hybrid somehow on pxa310.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for USB host port 2 on PXA310.
  2010-04-07 15:05 ` [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for " Igor Grinberg
  2010-04-13 20:18   ` Eric Miao
@ 2010-04-13 22:06   ` Daniel Mack
  2010-04-13 22:47     ` Eric Miao
  1 sibling, 1 reply; 8+ messages in thread
From: Daniel Mack @ 2010-04-13 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 07, 2010 at 06:05:22PM +0300, Igor Grinberg wrote:
> Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
> Signed-off-by: Mike Rapoport <mike@compulab.co.il>
> ---
>  arch/arm/mach-pxa/Makefile      |    1 +
>  arch/arm/mach-pxa/pxa310-ulpi.c |  240 +++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-pxa/pxa310-ulpi.h |   85 ++++++++++++++
>  3 files changed, 326 insertions(+), 0 deletions(-)
>  create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.c
>  create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.h

The USB OTG/ULPI framework could well be reused for that I think. All
that you would need is a struct otg_io_access_ops with two function
pointers to read and write registers. Then you can use otg_ulpi_create()
to set up an ULPI compliant device connected to the bus.

Have a look at the MXC code, I believe adopting that framework is better
than re-inventing it.

Daniel



> diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
> index 86bc87b..76d52f4 100644
> --- a/arch/arm/mach-pxa/Makefile
> +++ b/arch/arm/mach-pxa/Makefile
> @@ -21,6 +21,7 @@ obj-$(CONFIG_PXA25x)		+= mfp-pxa2xx.o pxa2xx.o pxa25x.o
>  obj-$(CONFIG_PXA27x)		+= mfp-pxa2xx.o pxa2xx.o pxa27x.o
>  obj-$(CONFIG_PXA3xx)		+= mfp-pxa3xx.o pxa3xx.o smemc.o
>  obj-$(CONFIG_CPU_PXA300)	+= pxa300.o
> +obj-$(CONFIG_CPU_PXA310)	+= pxa310-ulpi.o
>  obj-$(CONFIG_CPU_PXA320)	+= pxa320.o
>  obj-$(CONFIG_CPU_PXA930)	+= pxa930.o
>  
> diff --git a/arch/arm/mach-pxa/pxa310-ulpi.c b/arch/arm/mach-pxa/pxa310-ulpi.c
> new file mode 100644
> index 0000000..ab82db8
> --- /dev/null
> +++ b/arch/arm/mach-pxa/pxa310-ulpi.c
> @@ -0,0 +1,240 @@
> +/*
> + * linux/arch/arm/mach-pxa/pxa310-ulpi.c
> + *
> + * PXA310 ULPI USB host implementation.
> + *
> + * Copyright (C) 2010 CompuLab Ltd.
> + *
> + * Igor Grinberg <grinberg@compulab.co.il>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/delay.h>
> +#include <linux/clk.h>
> +
> +#include <mach/regs-u2d.h>
> +
> +#include "pxa310-ulpi.h"
> +
> +static void __iomem *u2d_mmio_base;
> +
> +static inline unsigned int u2d_readl(unsigned int off)
> +{
> +	return __raw_readl(u2d_mmio_base + off);
> +}
> +
> +static inline void u2d_writel(unsigned int off, unsigned int val)
> +{
> +	__raw_writel(val, u2d_mmio_base + off);
> +}
> +
> +static inline enum u2d_phy_mode ulpi_get_phymode(void)
> +{
> +	return (u2d_readl(U2DOTGUSR) & 0xF0000000) >> 28;
> +}
> +
> +static bool ulpi_is_in_sync_mode(void)
> +{
> +	enum u2d_phy_mode state = ulpi_get_phymode();
> +
> +	return (state == SYNCH) || (state == PRE_SYNCH);
> +}
> +
> +static int ulpi_poll(void)
> +{
> +	int timeout = 50000;
> +
> +	while (timeout--) {
> +		if (!(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RUN))
> +			return 0;
> +
> +		cpu_relax();
> +	}
> +
> +	pr_warning("%s: ULPI access timed out!\n", __func__);
> +
> +	return -ETIMEDOUT;
> +}
> +
> +static int ulpi_reg_read(u8 reg, u8 *value)
> +{
> +	int err = 0;
> +
> +	if (!ulpi_is_in_sync_mode()) {
> +		pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
> +		return -EBUSY;
> +	}
> +
> +	u2d_writel(U2DOTGUCR,
> +		   U2DOTGUCR_RUN | U2DOTGUCR_RNW | (reg << U2DOTGUCR_ADDR_S));
> +	msleep(5);
> +
> +	err = ulpi_poll();
> +	if (err)
> +		return err;
> +
> +	*value = (u8)(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA);
> +
> +	return 0;
> +}
> +
> +static int ulpi_reg_write(u8 reg, u8 value)
> +{
> +	int err;
> +
> +	if (!ulpi_is_in_sync_mode()) {
> +		pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
> +		return -EBUSY;
> +	}
> +
> +	u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | (reg << U2DOTGUCR_ADDR_S)
> +					    | (value << U2DOTGUCR_WDATA_S));
> +	msleep(5);
> +
> +	err = ulpi_poll();
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +static int u2d_clk_enable(void)
> +{
> +	int err;
> +	struct clk *u2d_clk;
> +
> +	u2d_clk = clk_get(NULL, "U2DCLK");
> +	if (IS_ERR(u2d_clk)) {
> +		err = PTR_ERR(u2d_clk);
> +		pr_err("%s: failed to get U2DCLK: %d\n", __func__, err);
> +		return err;
> +	}
> +	clk_enable(u2d_clk);
> +
> +	return 0;
> +}
> +
> +static void u2d_otg_host_init(void)
> +{
> +	u32 u2dotgcr;
> +
> +	/* setup OTG controller registers */
> +	u2dotgcr = u2d_readl(U2DOTGCR);
> +	u2dotgcr |= U2DOTGCR_ULAF | U2DOTGCR_UTMID;
> +	u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
> +	u2d_writel(U2DOTGCR, u2dotgcr);
> +	msleep(5);
> +	u2d_writel(U2DOTGCR, u2dotgcr | U2DOTGCR_ULE);
> +	msleep(5);
> +
> +	/* no OTG interrupts in host mode */
> +	u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~U2DOTGICR_MASK);
> +}
> +
> +static void u2d_ulpi_rtsm(void)
> +{
> +	u32 u2dotgcr;
> +
> +	/* put PHY to sync mode */
> +	u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_RTSM);
> +	msleep(10);
> +
> +	/* setup OTG sync mode */
> +	u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_ULAF;
> +	u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
> +	u2d_writel(U2DOTGCR, u2dotgcr);
> +}
> +
> +static void u2d_disable_otg_device(void)
> +{
> +	/* disable USB2 Device controller */
> +	u2d_writel(U2DCR, u2d_readl(U2DCR) & ~U2DCR_UDE);
> +	u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_UTMID);
> +
> +	/* disable the otg interrupts */
> +	u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~U2DOTGICR_MASK);
> +}
> +
> +static int u2d_set_ulpi_serial(enum u2d_phy_mode mode)
> +{
> +	int err = 0;
> +	u32 u2dotgcr;
> +
> +	/* enable the 15K Ohm pull-down resistor on D+ */
> +	err = ulpi_reg_write(ULPI_OTG_CONTROL_SET, ULPI_OC_DPPULLDOWN);
> +	if (err)
> +		return err;
> +
> +	/* enable the 15K Ohm pull-down resistor on D- */
> +	err = ulpi_reg_write(ULPI_OTG_CONTROL_SET, ULPI_OC_DMPULLDOWN);
> +	if (err)
> +		return err;
> +
> +	/* drive 5V on VBUS */
> +	err = ulpi_reg_write(ULPI_OTG_CONTROL_SET, ULPI_OC_DRVVBUS);
> +	if (err)
> +		return err;
> +
> +	/* configure UHC for 6/3-pin serial mode */
> +	if (mode == SER_6PIN)
> +		u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) & ~U2DP3CR_P2SS);
> +	else if (mode == SER_3PIN)
> +		u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) | U2DP3CR_P2SS);
> +
> +	/* put PHY into host mode */
> +	err = ulpi_reg_write(ULPI_FUNCTION_CONTROL_SET, 0x45);
> +	if (err)
> +		return err;
> +
> +	/* set PHY to serial 6/3 pin mode */
> +	if (mode == SER_6PIN)
> +		err = ulpi_reg_write(ULPI_INTERFACE_CONTROL, ULPI_IC_6PIN);
> +	else if (mode == SER_3PIN)
> +		err = ulpi_reg_write(ULPI_INTERFACE_CONTROL, ULPI_IC_3PIN);
> +	if (err)
> +		return err;
> +
> +	/* enable the serial mode */
> +	u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_SMAF;
> +	u2d_writel(U2DOTGCR, u2dotgcr & ~(U2DOTGCR_ULAF | U2DOTGCR_CKAF));
> +
> +	return 0;
> +}
> +
> +int pxa310_ulpi_init(enum u2d_phy_mode mode)
> +{
> +	int err;
> +
> +	err = u2d_clk_enable();
> +	if (err)
> +		goto err_out;
> +
> +	u2d_mmio_base = ioremap(U2D_PHYS_BASE, 0x1300);
> +	if (u2d_mmio_base == NULL) {
> +		pr_err("%s: failed to remap U2D registers address space\n",
> +			__func__);
> +		err = -ENOMEM;
> +		goto err_out;
> +	}
> +
> +	u2d_otg_host_init();
> +	u2d_ulpi_rtsm();
> +	u2d_disable_otg_device();
> +
> +	err = u2d_set_ulpi_serial(mode);
> +	if (err)
> +		goto err_out;
> +
> +	return 0;
> +
> +err_out:
> +	pr_err("%s: ULPI init failed: %d\n", __func__, err);
> +	return err;
> +}
> diff --git a/arch/arm/mach-pxa/pxa310-ulpi.h b/arch/arm/mach-pxa/pxa310-ulpi.h
> new file mode 100644
> index 0000000..87558f0
> --- /dev/null
> +++ b/arch/arm/mach-pxa/pxa310-ulpi.h
> @@ -0,0 +1,85 @@
> +/*
> + * linux/arch/arm/mach-pxa/pxa310-ulpi.h
> + *
> + * PXA310 ULPI USB host header file.
> + *
> + * Copyright (C) 2010 CompuLab Ltd.
> + *
> + * Igor Grinberg <grinberg@compulab.co.il>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +#ifndef __PXA310_ULPI__
> +#define __PXA310_ULPI__
> +
> +/* OTG Interrupts */
> +#define U2DOTGICR_MASK		0x37F7F
> +
> +/* PXA310 USB OTG Controller */
> +#define ULPI_VENDOR_LOW		0x0
> +#define ULPI_VENDOR_HIGH		0x1
> +#define ULPI_PRODUCT_LOW		0x2
> +#define ULPI_PRODUCT_HIGH		0x3
> +#define ULPI_FUNCTION_CONTROL		0x4
> +#define ULPI_FUNCTION_CONTROL_SET	0x5
> +#define ULPI_FUNCTION_CONTROL_CLEAR	0x6
> +#define ULPI_INTERFACE_CONTROL		0x7
> +#define ULPI_INTERFACE_CONTROL_SET	0x8
> +#define ULPI_INTERFACE_CONTROL_CLEAR	0x9
> +#define ULPI_OTG_CONTROL		0xA
> +#define ULPI_OTG_CONTROL_SET		0xB
> +#define ULPI_OTG_CONTROL_CLEAR		0xC
> +#define ULPI_INT_RISE			0xD
> +#define ULPI_INT_RISE_SET		0xE
> +#define ULPI_INT_RISE_CLEAR		0xF
> +#define ULPI_INT_FALL			0x10
> +#define ULPI_INT_FALL_SET		0x11
> +#define ULPI_INT_FALL_CLEAR		0x12
> +#define ULPI_INT_STATUS		0x13
> +#define ULPI_INT_LATCH			0x14
> +#define ULPI_DEBUG			0x15
> +#define ULPI_SCRATCH			0x16
> +#define ULPI_SCRATCH_SET		0x17
> +#define ULPI_SCRATCH_CLEAR		0x18
> +
> +#define ULPI_FC_RESET		(1 << 5)	/* XCVR Reset */
> +#define ULPI_FC_SUSPENDM	(1 << 6)	/* XCVR SuspendM, Low Power Mode */
> +
> +#define ULPI_IC_6PIN		(1 << 0)	/* XCVR 6 pin mode */
> +#define ULPI_IC_3PIN		(1 << 1)	/* XCVR 3 pin mode */
> +#define ULPI_IC_CARKIT		(1 << 2)	/* Carkit mode */
> +#define ULPI_IC_CLKSUSPENDM	(1 << 3)	/* Active low clock suspend */
> +
> +#define ULPI_OC_IDPULLUP	(1 << 0)	/* ID Pull Up, enable sampling of ID line */
> +#define ULPI_OC_DPPULLDOWN	(1 << 1)	/* Enable the 15K Ohm pull down resistor on D+ */
> +#define ULPI_OC_DMPULLDOWN	(1 << 2)	/* Enable the 15K Ohm pull down resistor on D- */
> +#define ULPI_OC_DISCHRGVBUS	(1 << 3)	/* Discharge Vbus */
> +#define ULPI_OC_CHRGVBUS	(1 << 4)	/* Charge Vbus, for Vbus pulsing SRP */
> +#define ULPI_OC_DRVVBUS	(1 << 5)	/* Drive 5V on Vbus */
> +#define ULPI_OC_DRVVBUSEXT	(1 << 6)	/* Drive Vbus using external supply */
> +
> +#define ULPI_INT_HOSTDISCON	(1 << 0)	/* Host Disconnect */
> +#define ULPI_INT_VBUSVALID	(1 << 1)	/* Vbus Valid */
> +#define ULPI_INT_SESSIONVALID	(1 << 2)	/* Session Valid */
> +#define ULPI_INT_SESSIONEND	(1 << 3)	/* Session End */
> +#define ULPI_INT_IDGND		(1 << 4)	/* current status of IDGND */
> +
> +#define U2DOTGUCR_ADDR_S	(16)
> +#define U2DOTGUCR_WDATA_S	(8)
> +
> +#define U2D_PHYS_BASE   0x54100000
> +
> +enum u2d_phy_mode {
> +	SYNCH		= 0,
> +	CARKIT		= (1 << 0),
> +	SER_3PIN	= (1 << 1),
> +	SER_6PIN	= (1 << 2),
> +	LOWPOWER	= (1 << 3),
> +	PRE_SYNCH	= (1 << 4),
> +};
> +
> +int pxa310_ulpi_init(enum u2d_phy_mode);
> +
> +#endif /* __PXA310_ULPI__ */
> -- 
> 1.6.4.4
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for USB host port 2 on PXA310.
  2010-04-13 22:06   ` Daniel Mack
@ 2010-04-13 22:47     ` Eric Miao
  2010-04-14 15:03       ` Igor Grinberg
  0 siblings, 1 reply; 8+ messages in thread
From: Eric Miao @ 2010-04-13 22:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Apr 14, 2010 at 6:06 AM, Daniel Mack <daniel@caiaq.de> wrote:
> On Wed, Apr 07, 2010 at 06:05:22PM +0300, Igor Grinberg wrote:
>> Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
>> Signed-off-by: Mike Rapoport <mike@compulab.co.il>
>> ---
>> ?arch/arm/mach-pxa/Makefile ? ? ?| ? ?1 +
>> ?arch/arm/mach-pxa/pxa310-ulpi.c | ?240 +++++++++++++++++++++++++++++++++++++++
>> ?arch/arm/mach-pxa/pxa310-ulpi.h | ? 85 ++++++++++++++
>> ?3 files changed, 326 insertions(+), 0 deletions(-)
>> ?create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.c
>> ?create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.h
>
> The USB OTG/ULPI framework could well be reused for that I think. All
> that you would need is a struct otg_io_access_ops with two function
> pointers to read and write registers. Then you can use otg_ulpi_create()
> to set up an ULPI compliant device connected to the bus.
>

Right, that's what I'm thinking as well esp. since ULPI is a standard
(ok, kinds of) and I'm not seeing too much specialty of pxa3xx ULPI
except for the way to access registers. Cannot remember the detail
but the OTG might be a hybrid model on pxa310, and might be a
little bit different from others.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for USB host port 2 on PXA310.
  2010-04-13 22:47     ` Eric Miao
@ 2010-04-14 15:03       ` Igor Grinberg
  0 siblings, 0 replies; 8+ messages in thread
From: Igor Grinberg @ 2010-04-14 15:03 UTC (permalink / raw)
  To: linux-arm-kernel



On 04/14/10 01:47, Eric Miao wrote:
> On Wed, Apr 14, 2010 at 6:06 AM, Daniel Mack <daniel@caiaq.de> wrote:
>   
>> On Wed, Apr 07, 2010 at 06:05:22PM +0300, Igor Grinberg wrote:
>>     
>>> Signed-off-by: Igor Grinberg <grinberg@compulab.co.il>
>>> Signed-off-by: Mike Rapoport <mike@compulab.co.il>
>>> ---
>>>  arch/arm/mach-pxa/Makefile      |    1 +
>>>  arch/arm/mach-pxa/pxa310-ulpi.c |  240 +++++++++++++++++++++++++++++++++++++++
>>>  arch/arm/mach-pxa/pxa310-ulpi.h |   85 ++++++++++++++
>>>  3 files changed, 326 insertions(+), 0 deletions(-)
>>>  create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.c
>>>  create mode 100644 arch/arm/mach-pxa/pxa310-ulpi.h
>>>       
>> The USB OTG/ULPI framework could well be reused for that I think. All
>> that you would need is a struct otg_io_access_ops with two function
>> pointers to read and write registers. Then you can use otg_ulpi_create()
>> to set up an ULPI compliant device connected to the bus.
>>
>>     
> Right, that's what I'm thinking as well esp. since ULPI is a standard
> (ok, kinds of) and I'm not seeing too much specialty of pxa3xx ULPI
> except for the way to access registers. Cannot remember the detail
> but the OTG might be a hybrid model on pxa310, and might be a
> little bit different from others.
>
>   
Eric, Daniel,

Thanks for the comments.
So, the only right way is to patch OHCI to support the
otg_io_access_ops, isn't it?
Ok. I'll send a v2 in a couple of days.

Thanks,
Igor

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2010-04-14 15:03 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-07 15:05 [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310 Igor Grinberg
2010-04-07 15:05 ` [PATCH 1/2] [ARM] pxa: add minimal ULPI functionality for " Igor Grinberg
2010-04-13 20:18   ` Eric Miao
2010-04-13 22:06   ` Daniel Mack
2010-04-13 22:47     ` Eric Miao
2010-04-14 15:03       ` Igor Grinberg
2010-04-07 15:05 ` [PATCH 2/2] [ARM] pxa/cm-x300: enable USB host port 2 on modules with PXA310 cpu Igor Grinberg
2010-04-12  5:52 ` [RFC PATCH 0/2] pxa: enable USB host port 2 on PXA310 Mike Rapoport

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).