diff options
author | Arnaud Patard (Rtp) <arnaud.patard@rtp-net.org> | 2010-12-20 10:48:58 -0500 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2011-01-03 04:20:23 -0500 |
commit | 711669e5b80b6f2d88f61ed8a9681f83d8cbd201 (patch) | |
tree | bfb50f071e2d539e310aeb3767bfbce54267420f | |
parent | 8305ed75d1418f02933a48bcabdbb5032d885628 (diff) |
mx51: fix usb clock support
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 <arnaud.patard@rtp-net.org>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r-- | arch/arm/mach-mx5/clock-mx51-mx53.c | 45 | ||||
-rw-r--r-- | drivers/usb/host/ehci-mxc.c | 44 |
2 files changed, 75 insertions, 14 deletions
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c index 9fc65bbc9d77..2f9eae213094 100644 --- a/arch/arm/mach-mx5/clock-mx51-mx53.c +++ b/arch/arm/mach-mx5/clock-mx51-mx53.c | |||
@@ -954,6 +954,41 @@ static struct clk usboh3_clk = { | |||
954 | .parent = &pll2_sw_clk, | 954 | .parent = &pll2_sw_clk, |
955 | .get_rate = clk_usboh3_get_rate, | 955 | .get_rate = clk_usboh3_get_rate, |
956 | .set_parent = clk_usboh3_set_parent, | 956 | .set_parent = clk_usboh3_set_parent, |
957 | .enable = _clk_ccgr_enable, | ||
958 | .disable = _clk_ccgr_disable, | ||
959 | .enable_reg = MXC_CCM_CCGR2, | ||
960 | .enable_shift = MXC_CCM_CCGRx_CG14_OFFSET, | ||
961 | }; | ||
962 | |||
963 | static struct clk usb_ahb_clk = { | ||
964 | .parent = &ipg_clk, | ||
965 | .enable = _clk_ccgr_enable, | ||
966 | .disable = _clk_ccgr_disable, | ||
967 | .enable_reg = MXC_CCM_CCGR2, | ||
968 | .enable_shift = MXC_CCM_CCGRx_CG13_OFFSET, | ||
969 | }; | ||
970 | |||
971 | static int clk_usb_phy1_set_parent(struct clk *clk, struct clk *parent) | ||
972 | { | ||
973 | u32 reg; | ||
974 | |||
975 | reg = __raw_readl(MXC_CCM_CSCMR1) & ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL; | ||
976 | |||
977 | if (parent == &pll3_sw_clk) | ||
978 | reg |= 1 << MXC_CCM_CSCMR1_USB_PHY_CLK_SEL_OFFSET; | ||
979 | |||
980 | __raw_writel(reg, MXC_CCM_CSCMR1); | ||
981 | |||
982 | return 0; | ||
983 | } | ||
984 | |||
985 | static struct clk usb_phy1_clk = { | ||
986 | .parent = &pll3_sw_clk, | ||
987 | .set_parent = clk_usb_phy1_set_parent, | ||
988 | .enable = _clk_ccgr_enable, | ||
989 | .enable_reg = MXC_CCM_CCGR2, | ||
990 | .enable_shift = MXC_CCM_CCGRx_CG0_OFFSET, | ||
991 | .disable = _clk_ccgr_disable, | ||
957 | }; | 992 | }; |
958 | 993 | ||
959 | /* eCSPI */ | 994 | /* eCSPI */ |
@@ -1094,9 +1129,12 @@ static struct clk_lookup mx51_lookups[] = { | |||
1094 | _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) | 1129 | _REGISTER_CLOCK("imx-i2c.1", NULL, i2c2_clk) |
1095 | _REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk) | 1130 | _REGISTER_CLOCK("imx-i2c.2", NULL, hsi2c_clk) |
1096 | _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk) | 1131 | _REGISTER_CLOCK("mxc-ehci.0", "usb", usboh3_clk) |
1097 | _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", ahb_clk) | 1132 | _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_ahb_clk) |
1133 | _REGISTER_CLOCK("mxc-ehci.0", "usb_phy1", usb_phy1_clk) | ||
1098 | _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk) | 1134 | _REGISTER_CLOCK("mxc-ehci.1", "usb", usboh3_clk) |
1099 | _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", ahb_clk) | 1135 | _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_ahb_clk) |
1136 | _REGISTER_CLOCK("mxc-ehci.2", "usb", usboh3_clk) | ||
1137 | _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_ahb_clk) | ||
1100 | _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) | 1138 | _REGISTER_CLOCK("fsl-usb2-udc", "usb", usboh3_clk) |
1101 | _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) | 1139 | _REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", ahb_clk) |
1102 | _REGISTER_CLOCK("imx-keypad.0", NULL, kpp_clk) | 1140 | _REGISTER_CLOCK("imx-keypad.0", NULL, kpp_clk) |
@@ -1170,6 +1208,9 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc, | |||
1170 | mx51_revision(); | 1208 | mx51_revision(); |
1171 | clk_disable(&iim_clk); | 1209 | clk_disable(&iim_clk); |
1172 | 1210 | ||
1211 | /* move usb_phy_clk to 24MHz */ | ||
1212 | clk_set_parent(&usb_phy1_clk, &osc_clk); | ||
1213 | |||
1173 | /* set the usboh3_clk parent to pll2_sw_clk */ | 1214 | /* set the usboh3_clk parent to pll2_sw_clk */ |
1174 | clk_set_parent(&usboh3_clk, &pll2_sw_clk); | 1215 | clk_set_parent(&usboh3_clk, &pll2_sw_clk); |
1175 | 1216 | ||
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c index bce85055019a..a22d2df769a9 100644 --- a/drivers/usb/host/ehci-mxc.c +++ b/drivers/usb/host/ehci-mxc.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #define ULPI_VIEWPORT_OFFSET 0x170 | 28 | #define ULPI_VIEWPORT_OFFSET 0x170 |
29 | 29 | ||
30 | struct ehci_mxc_priv { | 30 | struct ehci_mxc_priv { |
31 | struct clk *usbclk, *ahbclk; | 31 | struct clk *usbclk, *ahbclk, *phy1clk; |
32 | struct usb_hcd *hcd; | 32 | struct usb_hcd *hcd; |
33 | }; | 33 | }; |
34 | 34 | ||
@@ -168,17 +168,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
168 | goto err_ioremap; | 168 | goto err_ioremap; |
169 | } | 169 | } |
170 | 170 | ||
171 | /* call platform specific init function */ | ||
172 | if (pdata->init) { | ||
173 | ret = pdata->init(pdev); | ||
174 | if (ret) { | ||
175 | dev_err(dev, "platform init failed\n"); | ||
176 | goto err_init; | ||
177 | } | ||
178 | /* platforms need some time to settle changed IO settings */ | ||
179 | mdelay(10); | ||
180 | } | ||
181 | |||
182 | /* enable clocks */ | 171 | /* enable clocks */ |
183 | priv->usbclk = clk_get(dev, "usb"); | 172 | priv->usbclk = clk_get(dev, "usb"); |
184 | if (IS_ERR(priv->usbclk)) { | 173 | if (IS_ERR(priv->usbclk)) { |
@@ -196,6 +185,28 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) | |||
196 | clk_enable(priv->ahbclk); | 185 | clk_enable(priv->ahbclk); |
197 | } | 186 | } |
198 | 187 | ||
188 | /* "dr" device has its own clock */ | ||
189 | if (pdev->id == 0) { | ||
190 | priv->phy1clk = clk_get(dev, "usb_phy1"); | ||
191 | if (IS_ERR(priv->phy1clk)) { | ||
192 | ret = PTR_ERR(priv->phy1clk); | ||
193 | goto err_clk_phy; | ||
194 | } | ||
195 | clk_enable(priv->phy1clk); | ||
196 | } | ||
197 | |||
198 | |||
199 | /* call platform specific init function */ | ||
200 | if (pdata->init) { | ||
201 | ret = pdata->init(pdev); | ||
202 | if (ret) { | ||
203 | dev_err(dev, "platform init failed\n"); | ||
204 | goto err_init; | ||
205 | } | ||
206 | /* platforms need some time to settle changed IO settings */ | ||
207 | mdelay(10); | ||
208 | } | ||
209 | |||
199 | /* setup specific usb hw */ | 210 | /* setup specific usb hw */ |
200 | ret = mxc_initialize_usb_hw(pdev->id, pdata->flags); | 211 | ret = mxc_initialize_usb_hw(pdev->id, pdata->flags); |
201 | if (ret < 0) | 212 | if (ret < 0) |
@@ -230,6 +241,11 @@ err_add: | |||
230 | if (pdata && pdata->exit) | 241 | if (pdata && pdata->exit) |
231 | pdata->exit(pdev); | 242 | pdata->exit(pdev); |
232 | err_init: | 243 | err_init: |
244 | if (priv->phy1clk) { | ||
245 | clk_disable(priv->phy1clk); | ||
246 | clk_put(priv->phy1clk); | ||
247 | } | ||
248 | err_clk_phy: | ||
233 | if (priv->ahbclk) { | 249 | if (priv->ahbclk) { |
234 | clk_disable(priv->ahbclk); | 250 | clk_disable(priv->ahbclk); |
235 | clk_put(priv->ahbclk); | 251 | clk_put(priv->ahbclk); |
@@ -273,6 +289,10 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev) | |||
273 | clk_disable(priv->ahbclk); | 289 | clk_disable(priv->ahbclk); |
274 | clk_put(priv->ahbclk); | 290 | clk_put(priv->ahbclk); |
275 | } | 291 | } |
292 | if (priv->phy1clk) { | ||
293 | clk_disable(priv->phy1clk); | ||
294 | clk_put(priv->phy1clk); | ||
295 | } | ||
276 | 296 | ||
277 | kfree(priv); | 297 | kfree(priv); |
278 | 298 | ||