usb: chipidea: imx: configure imx for ULPI phy
authorFabien Lahoudere <fabien.lahoudere@collabora.co.uk>
Mon, 26 Sep 2016 11:14:19 +0000 (13:14 +0200)
committerPeter Chen <peter.chen@nxp.com>
Mon, 14 Nov 2016 02:03:40 +0000 (10:03 +0800)
In order to use ULPI phy with usb host 2 and 3, we need to configure
controller register to enable ULPI features.

Each USB controller have different behaviour, so in order to avoid to have
several "swicth(data->index)" and lock/unlock, we prefer to get the index
switch and then test for features if they exist for this index.
This patch also remove useless test of reg and val. Those two values cannot
be NULL.

Signed-off-by: Fabien Lahoudere <fabien.lahoudere@collabora.co.uk>
Signed-off-by: Peter Chen <peter.chen@nxp.com>
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/ci_hdrc_imx.h
drivers/usb/chipidea/usbmisc_imx.c

index 099179457f60c0247af8c49c4084b7f77d30e98f..5f4a8157fad84e41f1c8e0f614739937e4fb97e7 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/dma-mapping.h>
 #include <linux/usb/chipidea.h>
+#include <linux/usb/of.h>
 #include <linux/clk.h>
 
 #include "ci.h"
@@ -146,6 +147,9 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
        if (of_find_property(np, "external-vbus-divider", NULL))
                data->evdo = 1;
 
+       if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI)
+               data->ulpi = 1;
+
        return data;
 }
 
index 409aa5ca8dda1405aaf9c94ca16d363be386c810..d666c9f036bae6fe8c90483b0308e6bba1a0a949 100644 (file)
@@ -19,6 +19,7 @@ struct imx_usbmisc_data {
        unsigned int disable_oc:1; /* over current detect disabled */
        unsigned int oc_polarity:1; /* over current polarity if oc enabled */
        unsigned int evdo:1; /* set external vbus divider option */
+       unsigned int ulpi:1; /* connected to an ULPI phy */
 };
 
 int imx_usbmisc_init(struct imx_usbmisc_data *);
index 20d02a5e418d936231fcb091e183c6f939d16701..11f51bde44e5f6f1bdca144fdea821a96e5ef2ff 100644 (file)
 
 #define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
 #define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c
+#define MX53_USB_CTRL_1_OFFSET         0x10
+#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK (0x11 << 2)
+#define MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI BIT(2)
+#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK (0x11 << 6)
+#define MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI BIT(6)
 #define MX53_USB_UH2_CTRL_OFFSET       0x14
 #define MX53_USB_UH3_CTRL_OFFSET       0x18
 #define MX53_BM_OVER_CUR_DIS_H1                BIT(5)
 #define MX53_BM_OVER_CUR_DIS_OTG       BIT(8)
 #define MX53_BM_OVER_CUR_DIS_UHx       BIT(30)
+#define MX53_USB_CTRL_1_UH2_ULPI_EN    BIT(26)
+#define MX53_USB_CTRL_1_UH3_ULPI_EN    BIT(27)
+#define MX53_USB_UHx_CTRL_WAKE_UP_EN   BIT(7)
+#define MX53_USB_UHx_CTRL_ULPI_INT_EN  BIT(8)
 #define MX53_USB_PHYCTRL1_PLLDIV_MASK  0x3
 #define MX53_USB_PLL_DIV_24_MHZ                0x01
 
@@ -199,31 +208,69 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
        val |= MX53_USB_PLL_DIV_24_MHZ;
        writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
 
-       if (data->disable_oc) {
-               spin_lock_irqsave(&usbmisc->lock, flags);
-               switch (data->index) {
-               case 0:
+       spin_lock_irqsave(&usbmisc->lock, flags);
+
+       switch (data->index) {
+       case 0:
+               if (data->disable_oc) {
                        reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
                        val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
-                       break;
-               case 1:
+                       writel(val, reg);
+               }
+               break;
+       case 1:
+               if (data->disable_oc) {
                        reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
                        val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
-                       break;
-               case 2:
+                       writel(val, reg);
+               }
+               break;
+       case 2:
+               if (data->ulpi) {
+                       /* set USBH2 into ULPI-mode. */
+                       reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET;
+                       val = readl(reg) | MX53_USB_CTRL_1_UH2_ULPI_EN;
+                       /* select ULPI clock */
+                       val &= ~MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_MASK;
+                       val |= MX53_USB_CTRL_1_H2_XCVR_CLK_SEL_ULPI;
+                       writel(val, reg);
+                       /* Set interrupt wake up enable */
+                       reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
+                       val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
+                               | MX53_USB_UHx_CTRL_ULPI_INT_EN;
+                       writel(val, reg);
+               }
+               if (data->disable_oc) {
                        reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
                        val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
-                       break;
-               case 3:
+                       writel(val, reg);
+               }
+               break;
+       case 3:
+               if (data->ulpi) {
+                       /* set USBH3 into ULPI-mode. */
+                       reg = usbmisc->base + MX53_USB_CTRL_1_OFFSET;
+                       val = readl(reg) | MX53_USB_CTRL_1_UH3_ULPI_EN;
+                       /* select ULPI clock */
+                       val &= ~MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_MASK;
+                       val |= MX53_USB_CTRL_1_H3_XCVR_CLK_SEL_ULPI;
+                       writel(val, reg);
+                       /* Set interrupt wake up enable */
                        reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
-                       val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
-                       break;
+                       val = readl(reg) | MX53_USB_UHx_CTRL_WAKE_UP_EN
+                               | MX53_USB_UHx_CTRL_ULPI_INT_EN;
+                       writel(val, reg);
                }
-               if (reg && val)
+               if (data->disable_oc) {
+                       reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
+                       val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
                        writel(val, reg);
-               spin_unlock_irqrestore(&usbmisc->lock, flags);
+               }
+               break;
        }
 
+       spin_unlock_irqrestore(&usbmisc->lock, flags);
+
        return 0;
 }