aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/otg/otg_id.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-22 10:38:37 -0500
commitfcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch)
treea57612d1888735a2ec7972891b68c1ac5ec8faea /drivers/usb/otg/otg_id.c
parent8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff)
Added missing tegra files.HEADmaster
Diffstat (limited to 'drivers/usb/otg/otg_id.c')
-rw-r--r--drivers/usb/otg/otg_id.c205
1 files changed, 205 insertions, 0 deletions
diff --git a/drivers/usb/otg/otg_id.c b/drivers/usb/otg/otg_id.c
new file mode 100644
index 00000000000..8037edbf314
--- /dev/null
+++ b/drivers/usb/otg/otg_id.c
@@ -0,0 +1,205 @@
1/*
2 * Copyright (C) 2011 Google, Inc.
3 *
4 * Author:
5 * Colin Cross <ccross@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#include <linux/kernel.h>
19#include <linux/mutex.h>
20#include <linux/notifier.h>
21#include <linux/usb/otg_id.h>
22
23static DEFINE_MUTEX(otg_id_lock);
24static struct plist_head otg_id_plist =
25 PLIST_HEAD_INIT(otg_id_plist);
26static struct otg_id_notifier_block *otg_id_active;
27static bool otg_id_cancelling;
28static bool otg_id_inited;
29static int otg_id_suspended;
30static bool otg_id_pending;
31
32static void otg_id_cancel(void)
33{
34 if (otg_id_active) {
35 otg_id_cancelling = true;
36 mutex_unlock(&otg_id_lock);
37
38 otg_id_active->cancel(otg_id_active);
39
40 mutex_lock(&otg_id_lock);
41 otg_id_cancelling = false;
42 }
43}
44
45static void __otg_id_notify(void)
46{
47 int ret;
48 struct otg_id_notifier_block *otg_id_nb;
49 bool proxy_wait = false;
50 if (plist_head_empty(&otg_id_plist))
51 return;
52
53 plist_for_each_entry(otg_id_nb, &otg_id_plist, p) {
54 if (proxy_wait) {
55 if (otg_id_nb->proxy_wait)
56 ret = otg_id_nb->proxy_wait(otg_id_nb);
57 } else {
58 ret = otg_id_nb->detect(otg_id_nb);
59 }
60 if (ret == OTG_ID_HANDLED) {
61 otg_id_active = otg_id_nb;
62 return;
63 }
64 if (ret == OTG_ID_PROXY_WAIT)
65 proxy_wait = true;
66
67 }
68
69 WARN(1, "otg id event not handled");
70 otg_id_active = NULL;
71}
72
73int otg_id_init(void)
74{
75 mutex_lock(&otg_id_lock);
76
77 otg_id_inited = true;
78 __otg_id_notify();
79
80 mutex_unlock(&otg_id_lock);
81 return 0;
82}
83late_initcall(otg_id_init);
84
85/**
86 * otg_id_register_notifier
87 * @otg_id_nb: notifier block containing priority and callback function
88 *
89 * Register a notifier that will be called on any USB cable state change.
90 * The priority determines the order the callback will be called in, a higher
91 * number will be called first. A callback function needs to determine the
92 * type of USB cable that is connected. If it can determine the type, it
93 * should notify the appropriate drivers (for example, call an otg notifier
94 * with USB_EVENT_VBUS), and return OTG_ID_HANDLED. Once a callback has
95 * returned OTG_ID_HANDLED, it is responsible for calling otg_id_notify() when
96 * the detected USB cable is disconnected.
97 */
98int otg_id_register_notifier(struct otg_id_notifier_block *otg_id_nb)
99{
100 plist_node_init(&otg_id_nb->p, otg_id_nb->priority);
101
102 mutex_lock(&otg_id_lock);
103 plist_add(&otg_id_nb->p, &otg_id_plist);
104
105 if (otg_id_inited) {
106 otg_id_cancel();
107 __otg_id_notify();
108 }
109
110 mutex_unlock(&otg_id_lock);
111
112 return 0;
113}
114
115void otg_id_unregister_notifier(struct otg_id_notifier_block *otg_id_nb)
116{
117 mutex_lock(&otg_id_lock);
118
119 plist_del(&otg_id_nb->p, &otg_id_plist);
120
121 if (otg_id_inited && (otg_id_active == otg_id_nb)) {
122 otg_id_cancel();
123 __otg_id_notify();
124 }
125
126 mutex_unlock(&otg_id_lock);
127}
128
129/**
130 * otg_id_notify
131 *
132 * Notify listeners on any USB cable state change.
133 *
134 * A driver may only call otg_id_notify if it returned OTG_ID_HANDLED the last
135 * time it's notifier was called, and it's cancel function has not been called.
136 */
137void otg_id_notify(void)
138{
139 mutex_lock(&otg_id_lock);
140
141 if (otg_id_cancelling)
142 goto out;
143
144 if (otg_id_suspended != 0) {
145 otg_id_pending = true;
146 goto out;
147 }
148
149 __otg_id_notify();
150out:
151 mutex_unlock(&otg_id_lock);
152}
153
154/**
155 * otg_id_suspend
156 *
157 * Mark the otg_id subsystem as going into suspend. From here on out,
158 * any notifications will be deferred until the last otg_id client resumes.
159 * If there is a pending notification when calling this function, it will
160 * return a negative errno and expects that the caller will abort suspend.
161 * Returs 0 on success.
162 */
163int otg_id_suspend(void)
164{
165 int ret = 0;
166
167 mutex_lock(&otg_id_lock);
168
169 /*
170 * if there's a pending notification, tell the caller to abort suspend
171 */
172 if (otg_id_suspended != 0 && otg_id_pending) {
173 pr_info("otg_id: pending notification, should abort suspend\n");
174 ret = -EBUSY;
175 goto out;
176 }
177
178 otg_id_suspended++;
179out:
180 mutex_unlock(&otg_id_lock);
181 return ret;
182}
183
184/**
185 * otg_id_resume
186 *
187 * Inform the otg_id subsystem that a client is resuming. If this is the
188 * last client to be resumed and there's a pending notification,
189 * otg_id_notify() is called.
190 */
191void otg_id_resume(void)
192{
193 mutex_lock(&otg_id_lock);
194 if (WARN(!otg_id_suspended, "unbalanced otg_id_resume\n"))
195 goto out;
196 if (--otg_id_suspended == 0) {
197 if (otg_id_pending) {
198 pr_info("otg_id: had pending notification\n");
199 otg_id_pending = false;
200 __otg_id_notify();
201 }
202 }
203out:
204 mutex_unlock(&otg_id_lock);
205}