summaryrefslogtreecommitdiff
path: root/drivers/usb/otg
diff options
context:
space:
mode:
authorDima Zavin <dima@android.com>2011-09-09 09:25:05 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:39:04 -0800
commitec2e6c72e4557774ee6913f5c4bb560236f56015 (patch)
treebbe10893bfe071ce7bed39f1e56b94930792869a /drivers/usb/otg
parent76a22ac439a4048bc6bd012253572bb571cc66d9 (diff)
usb: otg_id: add suspend/resume interface
It is possible that while one driver has already suspended, another driver calls otg_id_notify() because it has not yet been suspended. It would then be possible for the suspended driver's detect callback to be called. This is undesirable. Introduce new otg_id_suspend/otg_id_resume functions that keep a suspended count, and if a notification happens while someone is suspended, that notification is deferred until all the drivers are resumed. If the notification happens before the last driver is suspended, that suspend will be aborted and once the final driver resumes through otg_id_resume, the notification will be delivered. Change-Id: I32fd32bec65e366e5f97a25c15255d94773b85b3 Signed-off-by: Dima Zavin <dima@android.com>
Diffstat (limited to 'drivers/usb/otg')
-rw-r--r--drivers/usb/otg/otg_id.c59
1 files changed, 59 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);
}