@@ -329,6 +329,7 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
int ret = 0;
unsigned long flags;
struct usb_phy *phy;
+ char wsource_name[40];
if (x->type != USB_PHY_TYPE_UNDEFINED) {
dev_err(x->dev, "not accepting initialized PHY %s\n", x->label);
@@ -351,6 +352,10 @@ int usb_add_phy(struct usb_phy *x, enum usb_phy_type type)
x->type = type;
list_add_tail(&x->head, &phy_list);
+ snprintf(wsource_name, sizeof(wsource_name), "vbus-%s",
+ dev_name(x->dev));
+ wakeup_source_init(&x->wsource, wsource_name);
+
out:
spin_unlock_irqrestore(&phy_lock, flags);
return ret;
@@ -402,6 +407,7 @@ void usb_remove_phy(struct usb_phy *x)
spin_lock_irqsave(&phy_lock, flags);
if (x) {
+ wakeup_source_trash(&x->wsource);
list_for_each_entry(phy_bind, &phy_bind_list, list)
if (phy_bind->phy == x)
phy_bind->phy = NULL;
@@ -446,13 +452,32 @@ int usb_bind_phy(const char *dev_name, u8 index,
EXPORT_SYMBOL_GPL(usb_bind_phy);
/**
- * usb_phy_set_event - set event to phy event
+ * usb_phy_set_event - set event to phy event and
+ * hold/temporarily hold wakeupsource
* @x: the phy returned by usb_get_phy();
*
- * This sets event to phy event
+ * This holds per-PHY wakeupsource/timed wakeupsource
*/
void usb_phy_set_event(struct usb_phy *x, unsigned long event)
{
+
x->last_event = event;
+
+ switch (event) {
+ case USB_EVENT_ENUMERATED:
+ __pm_stay_awake(&x->wsource);
+ break;
+
+ case USB_EVENT_NONE:
+ case USB_EVENT_ID:
+ case USB_EVENT_VBUS:
+ case USB_EVENT_CHARGER:
+ __pm_wakeup_event(&x->wsource,
+ USB_PHY_DEFAULT_WAKEUP_SRC_TIMEOUT);
+ break;
+
+ default:
+ break;
+ }
}
EXPORT_SYMBOL_GPL(usb_phy_set_event);
@@ -12,6 +12,8 @@
#include <linux/notifier.h>
#include <linux/usb.h>
+#define USB_PHY_DEFAULT_WAKEUP_SRC_TIMEOUT msecs_to_jiffies(2000)
+
enum usb_phy_interface {
USBPHY_INTERFACE_MODE_UNKNOWN,
USBPHY_INTERFACE_MODE_UTMI,
@@ -89,6 +91,9 @@ struct usb_phy {
/* for notification of usb_phy_events */
struct atomic_notifier_head notifier;
+ /* wakeup source */
+ struct wakeup_source wsource;
+
/* to pass extra port status to the root hub */
u16 port_status;
u16 port_change;