diff options
author | Peter Chen <peter.chen@freescale.com> | 2014-03-13 04:59:25 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 09:58:02 -0400 |
commit | 6e872f8e04da0a8cbf7be1d437998a06f3739f88 (patch) | |
tree | e47c3f3bc80c8dc15ab05edd872bef5a5a54af3b | |
parent | 5b28098e08a824a7761c542b8c8ed9f90a97774d (diff) |
ENGR00303795-2 usb: chipidea: coordinate usb phy initialization for different phy type
For internal PHY (like UTMI), the phy clock may from internal pll,
it is on/off on the fly, the access PORTSC.PTS will hang without
phy clock. So, the usb_phy_init which will open phy clock needs to
be called before hw_phymode_configure.
See: http://marc.info/?l=linux-arm-kernel&m=139350618732108&w=2
For external PHY (like ulpi), it needs to configure portsc.pts before
visit viewport, or the viewport can't be visited. so phy_phymode_configure
needs to be called before usb_phy_init.
See: cd0b42c2a6d2a74244f0053f8960f5dad5842278
It may not the best solution, but it can work for all situations.
Cc: Sascha Hauer <s.hauer@pengutronix.de>
Cc: Chris Ruehl <chris.ruehl@gtsys.com.hk>
Cc: shc_work@mail.ru
Cc: denis@eukrea.com
Cc: festevam@gmail.com
Signed-off-by: Peter Chen <peter.chen@freescale.com>
-rw-r--r-- | drivers/usb/chipidea/core.c | 43 |
1 files changed, 38 insertions, 5 deletions
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 54e0830ed04c..0f86ed7429d6 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c | |||
@@ -289,6 +289,43 @@ static void hw_phymode_configure(struct ci_hdrc *ci) | |||
289 | } | 289 | } |
290 | 290 | ||
291 | /** | 291 | /** |
292 | * ci_usb_phy_init: initialize phy according to different phy type | ||
293 | * @ci: the controller | ||
294 | * | ||
295 | * This function returns an error code if usb_phy_init has failed | ||
296 | */ | ||
297 | static int ci_usb_phy_init(struct ci_hdrc *ci) | ||
298 | { | ||
299 | int ret; | ||
300 | |||
301 | switch (ci->platdata->phy_mode) { | ||
302 | case USBPHY_INTERFACE_MODE_UTMI: | ||
303 | case USBPHY_INTERFACE_MODE_UTMIW: | ||
304 | case USBPHY_INTERFACE_MODE_HSIC: | ||
305 | ret = usb_phy_init(ci->transceiver); | ||
306 | if (!ret) | ||
307 | hw_wait_phy_stable(); | ||
308 | else | ||
309 | return ret; | ||
310 | hw_phymode_configure(ci); | ||
311 | break; | ||
312 | case USBPHY_INTERFACE_MODE_ULPI: | ||
313 | case USBPHY_INTERFACE_MODE_SERIAL: | ||
314 | hw_phymode_configure(ci); | ||
315 | ret = usb_phy_init(ci->transceiver); | ||
316 | if (ret) | ||
317 | return ret; | ||
318 | break; | ||
319 | default: | ||
320 | ret = usb_phy_init(ci->transceiver); | ||
321 | if (!ret) | ||
322 | hw_wait_phy_stable(); | ||
323 | } | ||
324 | |||
325 | return ret; | ||
326 | } | ||
327 | |||
328 | /** | ||
292 | * hw_device_reset: resets chip (execute without interruption) | 329 | * hw_device_reset: resets chip (execute without interruption) |
293 | * @ci: the controller | 330 | * @ci: the controller |
294 | * | 331 | * |
@@ -589,8 +626,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) | |||
589 | return -ENODEV; | 626 | return -ENODEV; |
590 | } | 627 | } |
591 | 628 | ||
592 | hw_phymode_configure(ci); | ||
593 | |||
594 | if (ci->platdata->phy) | 629 | if (ci->platdata->phy) |
595 | ci->transceiver = ci->platdata->phy; | 630 | ci->transceiver = ci->platdata->phy; |
596 | else | 631 | else |
@@ -610,12 +645,10 @@ static int ci_hdrc_probe(struct platform_device *pdev) | |||
610 | return -EPROBE_DEFER; | 645 | return -EPROBE_DEFER; |
611 | } | 646 | } |
612 | 647 | ||
613 | ret = usb_phy_init(ci->transceiver); | 648 | ret = ci_usb_phy_init(ci); |
614 | if (ret) { | 649 | if (ret) { |
615 | dev_err(dev, "unable to init phy: %d\n", ret); | 650 | dev_err(dev, "unable to init phy: %d\n", ret); |
616 | return ret; | 651 | return ret; |
617 | } else { | ||
618 | hw_wait_phy_stable(); | ||
619 | } | 652 | } |
620 | 653 | ||
621 | ci->hw_bank.phys = res->start; | 654 | ci->hw_bank.phys = res->start; |