diff options
-rw-r--r-- | drivers/usb/otg/otg_id.c | 59 | ||||
-rw-r--r-- | include/linux/usb/otg_id.h | 2 |
2 files changed, 61 insertions, 0 deletions
diff --git a/drivers/usb/otg/otg_id.c b/drivers/usb/otg/otg_id.c index ce22b4621308..8037edbf3141 100644 --- a/drivers/usb/otg/otg_id.c +++ b/drivers/usb/otg/otg_id.c @@ -26,6 +26,8 @@ static struct plist_head otg_id_plist = static struct otg_id_notifier_block *otg_id_active; static bool otg_id_cancelling; static bool otg_id_inited; +static int otg_id_suspended; +static bool otg_id_pending; static void otg_id_cancel(void) { @@ -139,8 +141,65 @@ void otg_id_notify(void) if (otg_id_cancelling) goto out; + if (otg_id_suspended != 0) { + otg_id_pending = true; + goto out; + } + __otg_id_notify(); +out: + mutex_unlock(&otg_id_lock); +} + +/** + * otg_id_suspend + * + * Mark the otg_id subsystem as going into suspend. From here on out, + * any notifications will be deferred until the last otg_id client resumes. + * If there is a pending notification when calling this function, it will + * return a negative errno and expects that the caller will abort suspend. + * Returs 0 on success. + */ +int otg_id_suspend(void) +{ + int ret = 0; + + mutex_lock(&otg_id_lock); + + /* + * if there's a pending notification, tell the caller to abort suspend + */ + if (otg_id_suspended != 0 && otg_id_pending) { + pr_info("otg_id: pending notification, should abort suspend\n"); + ret = -EBUSY; + goto out; + } + otg_id_suspended++; +out: + mutex_unlock(&otg_id_lock); + return ret; +} + +/** + * otg_id_resume + * + * Inform the otg_id subsystem that a client is resuming. If this is the + * last client to be resumed and there's a pending notification, + * otg_id_notify() is called. + */ +void otg_id_resume(void) +{ + mutex_lock(&otg_id_lock); + if (WARN(!otg_id_suspended, "unbalanced otg_id_resume\n")) + goto out; + if (--otg_id_suspended == 0) { + if (otg_id_pending) { + pr_info("otg_id: had pending notification\n"); + otg_id_pending = false; + __otg_id_notify(); + } + } out: mutex_unlock(&otg_id_lock); } diff --git a/include/linux/usb/otg_id.h b/include/linux/usb/otg_id.h index 46a44637c117..f9f5189a73b7 100644 --- a/include/linux/usb/otg_id.h +++ b/include/linux/usb/otg_id.h @@ -52,5 +52,7 @@ int otg_id_register_notifier(struct otg_id_notifier_block *otg_id_nb); void otg_id_unregister_notifier(struct otg_id_notifier_block *otg_id_nb); void otg_id_notify(void); +int otg_id_suspend(void); +void otg_id_resume(void); #endif /* __LINUX_USB_OTG_ID_H */ |