Skip to content

Commit 178a0bc

Browse files
xdarklightgregkh
authored andcommitted
usb: core: hcd: integrate the PHY wrapper into the HCD core
This integrates the PHY wrapper into the core hcd infrastructure. Multiple PHYs which are part of the HCD's device tree node are now managed (= powered on/off when needed), by the new usb_phy_roothub code. Suspend and resume is also supported, however not for runtime/auto-suspend (which is triggered for example when no devices are connected to the USB bus). This is needed on some SoCs (for example Amlogic Meson GXL) because if the PHYs are disabled during auto-suspend then devices which are plugged in afterwards are not seen by the host. One example where this is required is the Amlogic GXL and GXM SoCs: They are using a dwc3 USB controller with up to three ports enabled on the internal roothub. Each port has it's own PHY which must be enabled (if one of the PHYs is left disabled then none of the USB ports works at all). The new logic works on the Amlogic GXL and GXM SoCs because the dwc3 driver internally creates a xhci-hcd which then registers a HCD which then triggers our new PHY wrapper. USB controller drivers can opt out of this by setting "skip_phy_initialization" in struct usb_hcd to true. This is identical to how it works for a single USB PHY, so the "multiple PHY" handling is disabled for drivers that opted out of the management logic of a single PHY. Signed-off-by: Martin Blumenstingl <[email protected]> Acked-by: Alan Stern <[email protected]> Acked-by: Chunfeng Yun <[email protected]> Tested-by: Yixun Lan <[email protected]> Tested-by: Neil Armstrong <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 07dbff0 commit 178a0bc

File tree

2 files changed

+32
-0
lines changed

2 files changed

+32
-0
lines changed

drivers/usb/core/hcd.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/usb/otg.h>
3838

3939
#include "usb.h"
40+
#include "phy.h"
4041

4142

4243
/*-------------------------------------------------------------------------*/
@@ -2260,6 +2261,9 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
22602261
usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
22612262
hcd->state = HC_STATE_SUSPENDED;
22622263

2264+
if (!PMSG_IS_AUTO(msg))
2265+
usb_phy_roothub_power_off(hcd->phy_roothub);
2266+
22632267
/* Did we race with a root-hub wakeup event? */
22642268
if (rhdev->do_remote_wakeup) {
22652269
char buffer[6];
@@ -2296,6 +2300,13 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
22962300
dev_dbg(&rhdev->dev, "skipped %s of dead bus\n", "resume");
22972301
return 0;
22982302
}
2303+
2304+
if (!PMSG_IS_AUTO(msg)) {
2305+
status = usb_phy_roothub_power_on(hcd->phy_roothub);
2306+
if (status)
2307+
return status;
2308+
}
2309+
22992310
if (!hcd->driver->bus_resume)
23002311
return -ENOENT;
23012312
if (HCD_RH_RUNNING(hcd))
@@ -2333,6 +2344,7 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
23332344
}
23342345
} else {
23352346
hcd->state = old_state;
2347+
usb_phy_roothub_power_off(hcd->phy_roothub);
23362348
dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
23372349
"resume", status);
23382350
if (status != -ESHUTDOWN)
@@ -2769,6 +2781,18 @@ int usb_add_hcd(struct usb_hcd *hcd,
27692781
}
27702782
}
27712783

2784+
if (!hcd->skip_phy_initialization) {
2785+
hcd->phy_roothub = usb_phy_roothub_init(hcd->self.sysdev);
2786+
if (IS_ERR(hcd->phy_roothub)) {
2787+
retval = PTR_ERR(hcd->phy_roothub);
2788+
goto err_phy_roothub_init;
2789+
}
2790+
2791+
retval = usb_phy_roothub_power_on(hcd->phy_roothub);
2792+
if (retval)
2793+
goto err_usb_phy_roothub_power_on;
2794+
}
2795+
27722796
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
27732797

27742798
/* Keep old behaviour if authorized_default is not in [0, 1]. */
@@ -2933,6 +2957,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
29332957
err_register_bus:
29342958
hcd_buffer_destroy(hcd);
29352959
err_create_buf:
2960+
usb_phy_roothub_power_off(hcd->phy_roothub);
2961+
err_usb_phy_roothub_power_on:
2962+
usb_phy_roothub_exit(hcd->phy_roothub);
2963+
err_phy_roothub_init:
29362964
if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
29372965
phy_power_off(hcd->phy);
29382966
phy_exit(hcd->phy);
@@ -3017,6 +3045,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
30173045
usb_deregister_bus(&hcd->self);
30183046
hcd_buffer_destroy(hcd);
30193047

3048+
usb_phy_roothub_power_off(hcd->phy_roothub);
3049+
usb_phy_roothub_exit(hcd->phy_roothub);
3050+
30203051
if (IS_ENABLED(CONFIG_GENERIC_PHY) && hcd->remove_phy && hcd->phy) {
30213052
phy_power_off(hcd->phy);
30223053
phy_exit(hcd->phy);

include/linux/usb/hcd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ struct usb_hcd {
104104
*/
105105
struct usb_phy *usb_phy;
106106
struct phy *phy;
107+
struct usb_phy_roothub *phy_roothub;
107108

108109
/* Flags that need to be manipulated atomically because they can
109110
* change while the host controller is running. Always use

0 commit comments

Comments
 (0)