aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/driver.c14
-rw-r--r--drivers/usb/core/hub.c9
-rw-r--r--drivers/usb/core/usb.h5
3 files changed, 28 insertions, 0 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 14b83f2a4e87..adf5ca8a2396 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1700,6 +1700,20 @@ int usb_runtime_idle(struct device *dev)
return 0;
}
+int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+ int ret = -EPERM;
+
+ if (hcd->driver->set_usb2_hw_lpm) {
+ ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);
+ if (!ret)
+ udev->usb2_hw_lpm_enabled = enable;
+ }
+
+ return ret;
+}
+
#endif /* CONFIG_USB_SUSPEND */
struct bus_type usb_bus_type = {
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 4ffc3d1bd9e7..d6cc83249341 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2392,6 +2392,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
}
}
+ /* disable USB2 hardware LPM */
+ if (udev->usb2_hw_lpm_enabled == 1)
+ usb_set_usb2_hardware_lpm(udev, 0);
+
/* see 7.1.7.6 */
if (hub_is_superspeed(hub->hdev))
status = set_port_feature(hub->hdev,
@@ -2603,7 +2607,12 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
if (status < 0) {
dev_dbg(&udev->dev, "can't resume, status %d\n", status);
hub_port_logical_disconnect(hub, port1);
+ } else {
+ /* Try to enable USB2 hardware LPM */
+ if (udev->usb2_hw_lpm_capable == 1)
+ usb_set_usb2_hardware_lpm(udev, 1);
}
+
return status;
}
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 0d023cd2c149..3888778582c4 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -82,6 +82,7 @@ extern int usb_remote_wakeup(struct usb_device *dev);
extern int usb_runtime_suspend(struct device *dev);
extern int usb_runtime_resume(struct device *dev);
extern int usb_runtime_idle(struct device *dev);
+extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
#else
@@ -96,6 +97,10 @@ static inline int usb_remote_wakeup(struct usb_device *udev)
return 0;
}
+static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+{
+ return 0;
+}
#endif
extern struct bus_type usb_bus_type;