diff options
author | Lan Tianyu <tianyu.lan@intel.com> | 2013-01-23 04:26:29 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-01-25 10:12:19 -0800 |
commit | 971fcd492cebf544714f12d94549d2f0d2002645 (patch) | |
tree | 553a48486114b3b3b1507cf5dc391f24a464912f /drivers/usb/core/port.c | |
parent | 6802771bba0455a751d8f4ece7587585be3eaa2f (diff) |
usb: add runtime pm support for usb port device
This patch is to add runtime pm callback for usb port device.
Set/clear PORT_POWER feature in the resume/suspend callback.
Add portnum for struct usb_port to record port number. Do
pm_rumtime_get_sync/put(portdev) when a device is plugged/unplugged
to prevent it from being powered off when it is active.
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Lan Tianyu <tianyu.lan@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core/port.c')
-rw-r--r-- | drivers/usb/core/port.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c index 153e799e7320..d288dfed6ccf 100644 --- a/drivers/usb/core/port.c +++ b/drivers/usb/core/port.c @@ -17,6 +17,7 @@ */ #include <linux/slab.h> +#include <linux/pm_qos.h> #include "hub.h" @@ -70,9 +71,50 @@ static void usb_port_device_release(struct device *dev) kfree(port_dev); } +#ifdef CONFIG_USB_SUSPEND +static int usb_port_runtime_resume(struct device *dev) +{ + struct usb_port *port_dev = to_usb_port(dev); + struct usb_device *hdev = to_usb_device(dev->parent->parent); + struct usb_interface *intf = to_usb_interface(dev->parent); + int retval; + + usb_autopm_get_interface(intf); + retval = usb_hub_set_port_power(hdev, port_dev->portnum, true); + usb_autopm_put_interface(intf); + return retval; +} + +static int usb_port_runtime_suspend(struct device *dev) +{ + struct usb_port *port_dev = to_usb_port(dev); + struct usb_device *hdev = to_usb_device(dev->parent->parent); + struct usb_interface *intf = to_usb_interface(dev->parent); + int retval; + + if (dev_pm_qos_flags(&port_dev->dev, PM_QOS_FLAG_NO_POWER_OFF) + == PM_QOS_FLAGS_ALL) + return -EAGAIN; + + usb_autopm_get_interface(intf); + retval = usb_hub_set_port_power(hdev, port_dev->portnum, false); + usb_autopm_put_interface(intf); + return retval; +} +#endif + +static const struct dev_pm_ops usb_port_pm_ops = { +#ifdef CONFIG_USB_SUSPEND + .runtime_suspend = usb_port_runtime_suspend, + .runtime_resume = usb_port_runtime_resume, + .runtime_idle = pm_generic_runtime_idle, +#endif +}; + struct device_type usb_port_device_type = { .name = "usb_port", .release = usb_port_device_release, + .pm = &usb_port_pm_ops, }; int usb_hub_create_port_device(struct usb_hub *hub, int port1) @@ -87,6 +129,7 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) } hub->ports[port1 - 1] = port_dev; + port_dev->portnum = port1; port_dev->dev.parent = hub->intfdev; port_dev->dev.groups = port_dev_group; port_dev->dev.type = &usb_port_device_type; @@ -96,6 +139,9 @@ int usb_hub_create_port_device(struct usb_hub *hub, int port1) if (retval) goto error_register; + pm_runtime_set_active(&port_dev->dev); + pm_runtime_enable(&port_dev->dev); + retval = usb_acpi_register_power_resources(&port_dev->dev); if (retval && retval != -ENODEV) dev_warn(&port_dev->dev, "the port can't register its ACPI power resource.\n"); |