aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/chipidea
diff options
context:
space:
mode:
authorMichael Grzeschik <m.grzeschik@pengutronix.de>2013-06-13 17:59:56 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-06-17 13:47:09 -0700
commit40dcd0e8067b35e247f74409d79443634daf35ac (patch)
tree91b9e6678ad1b2bd72e45d3e35a9266aaefa016f /drivers/usb/chipidea
parentusb: add devicetree helpers for determining dr_mode and phy_type (diff)
downloadlinux-dev-40dcd0e8067b35e247f74409d79443634daf35ac.tar.xz
linux-dev-40dcd0e8067b35e247f74409d79443634daf35ac.zip
usb: chipidea: add PTW, PTS and STS handling
This patch makes it possible to configure the PTW, PTS and STS bits inside the portsc register for host and device mode before the driver starts and the phy can be addressed as hardware implementation is designed. Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/chipidea')
-rw-r--r--drivers/usb/chipidea/bits.h16
-rw-r--r--drivers/usb/chipidea/core.c48
2 files changed, 63 insertions, 1 deletions
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index 050de8562a04..aefa0261220c 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -48,10 +48,24 @@
#define PORTSC_SUSP BIT(7)
#define PORTSC_HSP BIT(9)
#define PORTSC_PTC (0x0FUL << 16)
+/* PTS and PTW for non lpm version only */
+#define PORTSC_PTS(d) \
+ ((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
+#define PORTSC_PTW BIT(28)
+#define PORTSC_STS BIT(29)
/* DEVLC */
#define DEVLC_PSPD (0x03UL << 25)
-#define DEVLC_PSPD_HS (0x02UL << 25)
+#define DEVLC_PSPD_HS (0x02UL << 25)
+#define DEVLC_PTW BIT(27)
+#define DEVLC_STS BIT(28)
+#define DEVLC_PTS(d) (((d) & 0x7) << 29)
+
+/* Encoding for DEVLC_PTS and PORTSC_PTS */
+#define PTS_UTMI 0
+#define PTS_ULPI 2
+#define PTS_SERIAL 3
+#define PTS_HSIC 4
/* OTGSC */
#define OTGSC_IDPU BIT(5)
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index a40e944401d2..a25f6b68550f 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -63,6 +63,8 @@
#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/chipidea.h>
+#include <linux/usb/of.h>
+#include <linux/phy.h>
#include "ci.h"
#include "udc.h"
@@ -207,6 +209,45 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
return 0;
}
+static void hw_phymode_configure(struct ci13xxx *ci)
+{
+ u32 portsc, lpm, sts;
+
+ switch (ci->platdata->phy_mode) {
+ case USBPHY_INTERFACE_MODE_UTMI:
+ portsc = PORTSC_PTS(PTS_UTMI);
+ lpm = DEVLC_PTS(PTS_UTMI);
+ break;
+ case USBPHY_INTERFACE_MODE_UTMIW:
+ portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW;
+ lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW;
+ break;
+ case USBPHY_INTERFACE_MODE_ULPI:
+ portsc = PORTSC_PTS(PTS_ULPI);
+ lpm = DEVLC_PTS(PTS_ULPI);
+ break;
+ case USBPHY_INTERFACE_MODE_SERIAL:
+ portsc = PORTSC_PTS(PTS_SERIAL);
+ lpm = DEVLC_PTS(PTS_SERIAL);
+ sts = 1;
+ break;
+ case USBPHY_INTERFACE_MODE_HSIC:
+ portsc = PORTSC_PTS(PTS_HSIC);
+ lpm = DEVLC_PTS(PTS_HSIC);
+ break;
+ default:
+ return;
+ }
+
+ if (ci->hw_bank.lpm) {
+ hw_write(ci, OP_DEVLC, DEVLC_PTS(7) | DEVLC_PTW, lpm);
+ hw_write(ci, OP_DEVLC, DEVLC_STS, sts);
+ } else {
+ hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc);
+ hw_write(ci, OP_PORTSC, PORTSC_STS, sts);
+ }
+}
+
/**
* hw_device_reset: resets chip (execute without interruption)
* @ci: the controller
@@ -223,6 +264,7 @@ int hw_device_reset(struct ci13xxx *ci, u32 mode)
while (hw_read(ci, OP_USBCMD, USBCMD_RST))
udelay(10); /* not RTOS friendly */
+ hw_phymode_configure(ci);
if (ci->platdata->notify_event)
ci->platdata->notify_event(ci,
@@ -369,6 +411,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (!dev->of_node && dev->parent)
+ dev->of_node = dev->parent->of_node;
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
@@ -408,6 +453,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (!ci->platdata->phy_mode)
+ ci->platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
+
/* initialize role(s) before the interrupt is requested */
ret = ci_hdrc_host_init(ci);
if (ret)