diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt index 1c04a4c9515f..184a8e0f26dc 100644 --- a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt +++ b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt @@ -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 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 #include #include +#include +#include #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) diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 544825dde823..1a2aa1848804 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -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)