usb: chipidea: add PTW, PTS and STS handling
authorMichael Grzeschik <m.grzeschik@pengutronix.de>
Thu, 13 Jun 2013 14:59:56 +0000 (17:59 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Jun 2013 20:47:09 +0000 (13:47 -0700)
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>
Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
drivers/usb/chipidea/bits.h
drivers/usb/chipidea/core.c
include/linux/usb/chipidea.h

index 1c04a4c9515f981e570fe778b748bfeb3d5b3e92..184a8e0f26dcaf9cb3e2ba4609498852ed3fb899 100644 (file)
@@ -5,6 +5,11 @@ Required properties:
 - reg: Should contain registers location and length
 - interrupts: Should contain controller interrupt
 
+Recommended properies:
+- phy_type: the type of the phy connected to the core. Should be one
+  of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
+  property the PORTSC register won't be touched
+
 Optional properties:
 - fsl,usbphy: phandler of usb phy that connects to the only one port
 - fsl,usbmisc: phandler of non-core register device, with one argument
index 050de8562a04b482da6a2cfb3d707609aff6b66d..aefa0261220c048322a62059ddc35f9df047e7bb 100644 (file)
 #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)
index a40e944401d2b6260acbf314a64694282af0f6d2..a25f6b68550f853f5bcd6ce662436260c46c3cfb 100644 (file)
@@ -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)
index 544825dde82305daeb4d7cf156901921ed73efcb..1a2aa18488043741ee25ac5ab7aee502dd79d8aa 100644 (file)
@@ -14,6 +14,7 @@ struct ci13xxx_platform_data {
        uintptr_t        capoffset;
        unsigned         power_budget;
        struct usb_phy  *phy;
+       enum usb_phy_interface phy_mode;
        unsigned long    flags;
 #define CI13XXX_REGS_SHARED            BIT(0)
 #define CI13XXX_REQUIRE_TRANSCEIVER    BIT(1)