Current code doesn't really enable the usb clocks so if they're disabled when booting linux, the kernel/machine will hang as soon as someone is trying to read a usb register Signed-off-by: Arnaud Patard Index: tst-usb/arch/arm/mach-mx5/clock-mx51-mx53.c =================================================================== --- tst-usb.orig/arch/arm/mach-mx5/clock-mx51-mx53.c 2010-12-20 15:38:40.000000000 +0100 +++ tst-usb/arch/arm/mach-mx5/clock-mx51-mx53.c 2010-12-20 15:40:10.000000000 +0100 @@ -954,6 +954,41 @@ .parent = &pll2_sw_clk, .get_rate = clk_usboh3_get_rate, .set_parent = clk_usboh3_set_parent, + .enable = _clk_ccgr_enable, + .disable = _clk_ccgr_disable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, +}; + +static struct clk usb_ahb_clk = { + .parent = &ipg_clk, + .enable = _clk_ccgr_enable, + .disable = _clk_ccgr_disable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, +}; + +static int clk_usb_phy1_set_parent(struct clk *clk, struct clk *parent) +{ + u32 reg; + + reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; + + if (parent == &pll3_sw_clk) + reg |= 1 << MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_CSCMR1); + + return 0; +} + +static struct clk usb_phy1_clk = { + .parent = &pll3_sw_clk, + .set_parent = clk_usb_phy1_set_parent, + .enable = _clk_ccgr_enable, + .enable_reg = MXC_CCM_CCGR2, + .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, + .disable = _clk_ccgr_disable, }; /* eCSPI */ @@ -1094,9 +1129,12 @@ _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) _REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk) _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", ahb_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_ahb_clk) + _REGISTER_CLOCK("mxc-ehci.0", "usb_phy1", usb_phy1_clk) _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk) - _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", ahb_clk) + _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_ahb_clk) + _REGISTER_CLOCK("mxc-ehci.2", "usb", usboh3_clk) + _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_ahb_clk) _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) _REGISTER_CLOCK("imx-keypad.0", NULL, kpp_clk) @@ -1170,6 +1208,9 @@ mx51_revision(); clk_disable(&iim_clk); + /* move usb_phy_clk to 24MHz */ + clk_set_parent(&usb_phy1_clk, &osc_clk); + /* set the usboh3_clk parent to pll2_sw_clk */ clk_set_parent(&usboh3_clk, &pll2_sw_clk); Index: tst-usb/drivers/usb/host/ehci-mxc.c =================================================================== --- tst-usb.orig/drivers/usb/host/ehci-mxc.c 2010-12-20 15:38:43.000000000 +0100 +++ tst-usb/drivers/usb/host/ehci-mxc.c 2010-12-20 15:40:10.000000000 +0100 @@ -28,7 +28,7 @@ #define ULPI_VIEWPORT_OFFSET 0x170 struct ehci_mxc_priv { - struct clk *usbclk, *ahbclk; + struct clk *usbclk, *ahbclk, *phy1clk; struct usb_hcd *hcd; }; @@ -168,17 +168,6 @@ goto err_ioremap; } - /* call platform specific init function */ - if (pdata->init) { - ret = pdata->init(pdev); - if (ret) { - dev_err(dev, "platform init failed\n"); - goto err_init; - } - /* platforms need some time to settle changed IO settings */ - mdelay(10); - } - /* enable clocks */ priv->usbclk = clk_get(dev, "usb"); if (IS_ERR(priv->usbclk)) { @@ -196,6 +185,28 @@ clk_enable(priv->ahbclk); } + /* "dr" device has its own clock */ + if (pdev->id == 0) { + priv->phy1clk = clk_get(dev, "usb_phy1"); + if (IS_ERR(priv->phy1clk)) { + ret = PTR_ERR(priv->phy1clk); + goto err_clk_phy; + } + clk_enable(priv->phy1clk); + } + + + /* call platform specific init function */ + if (pdata->init) { + ret = pdata->init(pdev); + if (ret) { + dev_err(dev, "platform init failed\n"); + goto err_init; + } + /* platforms need some time to settle changed IO settings */ + mdelay(10); + } + /* setup specific usb hw */ ret = mxc_initialize_usb_hw(pdev->id, pdata->flags); if (ret < 0) @@ -233,6 +244,11 @@ if (pdata && pdata->exit) pdata->exit(pdev); err_init: + if (priv->phy1clk) { + clk_disable(priv->phy1clk); + clk_put(priv->phy1clk); + } +err_clk_phy: if (priv->ahbclk) { clk_disable(priv->ahbclk); clk_put(priv->ahbclk); @@ -276,6 +292,10 @@ clk_disable(priv->ahbclk); clk_put(priv->ahbclk); } + if (priv->phy1clk) { + clk_disable(priv->phy1clk); + clk_put(priv->phy1clk); + } kfree(priv);