In order to use ULPI phy (smsc 3315) we have to configure imx53 ULPI mode in usbmisc_imx.c. It takes configuration from device tree through ci_hdrc_imx.*. ... usbphy2: usbphy@2 { compatible = "usb-nop-xceiv"; reset-gpios = <&gpio4 4 GPIO_ACTIVE_LOW>; clock-names = "main_clk"; /* * Hardware uses CKO2 at 24MHz at several places. Set the parent * clock of CKO2 to OSC. */ clock-frequency = <24000000>; clocks = <&clks IMX5_CLK_CKO2>; assigned-clocks = <&clks IMX5_CLK_CKO2_SEL>, <&clks IMX5_CLK_OSC>; assigned-clock-parents = <&clks IMX5_CLK_OSC>; status = "okay"; }; ... &usbh2 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usbh2>; phy_type = "ulpi"; disable-int60ck; dr_mode = "host"; fsl,usbphy = <&usbphy2>; vbus-supply = <®_usbh2_vbus>; status = "okay"; }; ... After those changes, the system freeze when in hw_phymode_configure() when doing : hw_write(ci, OP_PORTSC, PORTSC_PTS(7) | PORTSC_PTW, portsc); If we call calling usb_phy_init() before hw_phymode_configure() (see core.c), the freeze is solved and we can enumerate USB device and everything works fine Signed-off-by: Fabien Lahoudere <fabien.lahoudere@xxxxxxxxxxxxxxx> --- drivers/usb/chipidea/ci_hdrc_imx.c | 7 +++ drivers/usb/chipidea/ci_hdrc_imx.h | 2 + drivers/usb/chipidea/core.c | 2 +- drivers/usb/chipidea/usbmisc_imx.c | 101 +++++++++++++++++++++++++++++++------ 4 files changed, 96 insertions(+), 16 deletions(-) diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 0991794..89a9d98 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -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,12 @@ 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_find_property(np, "disable-int60ck", NULL)) + data->disable_int60ck = 1; + + if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) + data->ulpi = 1; + return data; } diff --git a/drivers/usb/chipidea/ci_hdrc_imx.h b/drivers/usb/chipidea/ci_hdrc_imx.h index 409aa5ca8..43bafae 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.h +++ b/drivers/usb/chipidea/ci_hdrc_imx.h @@ -19,6 +19,8 @@ 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 */ + unsigned int disable_int60ck:1; /* disable 60 MHZ clock */ }; int imx_usbmisc_init(struct imx_usbmisc_data *); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 69426e6..21218f8 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -383,6 +383,7 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) case USBPHY_INTERFACE_MODE_UTMI: case USBPHY_INTERFACE_MODE_UTMIW: case USBPHY_INTERFACE_MODE_HSIC: + case USBPHY_INTERFACE_MODE_ULPI: ret = _ci_usb_phy_init(ci); if (!ret) hw_wait_phy_stable(); @@ -390,7 +391,6 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) return ret; hw_phymode_configure(ci); break; - case USBPHY_INTERFACE_MODE_ULPI: case USBPHY_INTERFACE_MODE_SERIAL: hw_phymode_configure(ci); ret = _ci_usb_phy_init(ci); diff --git a/drivers/usb/chipidea/usbmisc_imx.c b/drivers/usb/chipidea/usbmisc_imx.c index 20d02a5..54d348a 100644 --- a/drivers/usb/chipidea/usbmisc_imx.c +++ b/drivers/usb/chipidea/usbmisc_imx.c @@ -46,11 +46,23 @@ #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_USB_CLKONOFF_CTRL_OFFSET 0x24 +#define MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF BIT(21) +#define MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF BIT(22) #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 @@ -190,6 +202,9 @@ static int usbmisc_imx53_init(struct imx_usbmisc_data *data) unsigned long flags; u32 val = 0; + printk (KERN_INFO"%s/%s:%d usbmisc->base = %p\n", __FILE__, __func__, __LINE__, usbmisc->base); + //dump_stack(); + if (data->index > 3) return -EINVAL; @@ -199,31 +214,87 @@ 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) { + spin_lock_irqsave(&usbmisc->lock, flags); + + switch (data->index) { case 0: - reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; - val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; + if (data->disable_oc) { + reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; + val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG; + if (reg && val) + writel(val, reg); + } break; case 1: - reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; - val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; + if (data->disable_oc) { + reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET; + val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1; + if (reg && val) + writel(val, reg); + } break; case 2: - reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; - val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; + 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_int60ck) { + reg = usbmisc->base + + MX53_USB_CLKONOFF_CTRL_OFFSET; + val = readl(reg) + | MX53_USB_CLKONOFF_CTRL_H2_INT60CKOFF; + writel(val, reg); + } + if (data->disable_oc) { + reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET; + val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; + if (reg && val) + writel(val, reg); + } break; case 3: - reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; - val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; + 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_USB_UHx_CTRL_WAKE_UP_EN + | MX53_USB_UHx_CTRL_ULPI_INT_EN; + writel(val, reg); + } + if (data->disable_int60ck) { + reg = usbmisc->base + + MX53_USB_CLKONOFF_CTRL_OFFSET; + val = readl(reg) + | MX53_USB_CLKONOFF_CTRL_H3_INT60CKOFF; + writel(val, reg); + } + if (data->disable_oc) { + reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET; + val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx; + if (reg && val) + writel(val, reg); + } break; - } - if (reg && val) - writel(val, reg); - spin_unlock_irqrestore(&usbmisc->lock, flags); } + spin_unlock_irqrestore(&usbmisc->lock, flags); + return 0; } -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html