]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/usb/otg/gpio_vbus.c
1c26c94513e9e5bd14299d1ae046125a6d1cce07
[net-next-2.6.git] / drivers / usb / otg / gpio_vbus.c
1 /*
2  * gpio-vbus.c - simple GPIO VBUS sensing driver for B peripheral devices
3  *
4  * Copyright (c) 2008 Philipp Zabel <philipp.zabel@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/platform_device.h>
13 #include <linux/gpio.h>
14 #include <linux/interrupt.h>
15 #include <linux/usb.h>
16 #include <linux/workqueue.h>
17
18 #include <linux/regulator/consumer.h>
19
20 #include <linux/usb/gadget.h>
21 #include <linux/usb/gpio_vbus.h>
22 #include <linux/usb/otg.h>
23
24
25 /*
26  * A simple GPIO VBUS sensing driver for B peripheral only devices
27  * with internal transceivers. It can control a D+ pullup GPIO and
28  * a regulator to limit the current drawn from VBUS.
29  *
30  * Needs to be loaded before the UDC driver that will use it.
31  */
32 struct gpio_vbus_data {
33         struct otg_transceiver otg;
34         struct device          *dev;
35         struct regulator       *vbus_draw;
36         int                     vbus_draw_enabled;
37         unsigned                mA;
38         struct work_struct      work;
39 };
40
41
42 /*
43  * This driver relies on "both edges" triggering.  VBUS has 100 msec to
44  * stabilize, so the peripheral controller driver may need to cope with
45  * some bouncing due to current surges (e.g. charging local capacitance)
46  * and contact chatter.
47  *
48  * REVISIT in desperate straits, toggling between rising and falling
49  * edges might be workable.
50  */
51 #define VBUS_IRQ_FLAGS \
52         ( IRQF_SAMPLE_RANDOM | IRQF_SHARED \
53         | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING )
54
55
56 /* interface to regulator framework */
57 static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
58 {
59         struct regulator *vbus_draw = gpio_vbus->vbus_draw;
60         int enabled;
61
62         if (!vbus_draw)
63                 return;
64
65         enabled = gpio_vbus->vbus_draw_enabled;
66         if (mA) {
67                 regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
68                 if (!enabled) {
69                         regulator_enable(vbus_draw);
70                         gpio_vbus->vbus_draw_enabled = 1;
71                 }
72         } else {
73                 if (enabled) {
74                         regulator_disable(vbus_draw);
75                         gpio_vbus->vbus_draw_enabled = 0;
76                 }
77         }
78         gpio_vbus->mA = mA;
79 }
80
81 static int is_vbus_powered(struct gpio_vbus_mach_info *pdata)
82 {
83         int vbus;
84
85         vbus = gpio_get_value(pdata->gpio_vbus);
86         if (pdata->gpio_vbus_inverted)
87                 vbus = !vbus;
88
89         return vbus;
90 }
91
92 static void gpio_vbus_work(struct work_struct *work)
93 {
94         struct gpio_vbus_data *gpio_vbus =
95                 container_of(work, struct gpio_vbus_data, work);
96         struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
97         int gpio;
98
99         if (!gpio_vbus->otg.gadget)
100                 return;
101
102         /* Peripheral controllers which manage the pullup themselves won't have
103          * gpio_pullup configured here.  If it's configured here, we'll do what
104          * isp1301_omap::b_peripheral() does and enable the pullup here... although
105          * that may complicate usb_gadget_{,dis}connect() support.
106          */
107         gpio = pdata->gpio_pullup;
108         if (is_vbus_powered(pdata)) {
109                 gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL;
110                 usb_gadget_vbus_connect(gpio_vbus->otg.gadget);
111
112                 /* drawing a "unit load" is *always* OK, except for OTG */
113                 set_vbus_draw(gpio_vbus, 100);
114
115                 /* optionally enable D+ pullup */
116                 if (gpio_is_valid(gpio))
117                         gpio_set_value(gpio, !pdata->gpio_pullup_inverted);
118         } else {
119                 /* optionally disable D+ pullup */
120                 if (gpio_is_valid(gpio))
121                         gpio_set_value(gpio, pdata->gpio_pullup_inverted);
122
123                 set_vbus_draw(gpio_vbus, 0);
124
125                 usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget);
126                 gpio_vbus->otg.state = OTG_STATE_B_IDLE;
127         }
128 }
129
130 /* VBUS change IRQ handler */
131 static irqreturn_t gpio_vbus_irq(int irq, void *data)
132 {
133         struct platform_device *pdev = data;
134         struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
135         struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
136
137         dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
138                 is_vbus_powered(pdata) ? "supplied" : "inactive",
139                 gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none");
140
141         if (gpio_vbus->otg.gadget)
142                 schedule_work(&gpio_vbus->work);
143
144         return IRQ_HANDLED;
145 }
146
147 /* OTG transceiver interface */
148
149 /* bind/unbind the peripheral controller */
150 static int gpio_vbus_set_peripheral(struct otg_transceiver *otg,
151                                 struct usb_gadget *gadget)
152 {
153         struct gpio_vbus_data *gpio_vbus;
154         struct gpio_vbus_mach_info *pdata;
155         struct platform_device *pdev;
156         int gpio, irq;
157
158         gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
159         pdev = to_platform_device(gpio_vbus->dev);
160         pdata = gpio_vbus->dev->platform_data;
161         irq = gpio_to_irq(pdata->gpio_vbus);
162         gpio = pdata->gpio_pullup;
163
164         if (!gadget) {
165                 dev_dbg(&pdev->dev, "unregistering gadget '%s'\n",
166                         otg->gadget->name);
167
168                 /* optionally disable D+ pullup */
169                 if (gpio_is_valid(gpio))
170                         gpio_set_value(gpio, pdata->gpio_pullup_inverted);
171
172                 set_vbus_draw(gpio_vbus, 0);
173
174                 usb_gadget_vbus_disconnect(otg->gadget);
175                 otg->state = OTG_STATE_UNDEFINED;
176
177                 otg->gadget = NULL;
178                 return 0;
179         }
180
181         otg->gadget = gadget;
182         dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name);
183
184         /* initialize connection state */
185         gpio_vbus_irq(irq, pdev);
186         return 0;
187 }
188
189 /* effective for B devices, ignored for A-peripheral */
190 static int gpio_vbus_set_power(struct otg_transceiver *otg, unsigned mA)
191 {
192         struct gpio_vbus_data *gpio_vbus;
193
194         gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
195
196         if (otg->state == OTG_STATE_B_PERIPHERAL)
197                 set_vbus_draw(gpio_vbus, mA);
198         return 0;
199 }
200
201 /* for non-OTG B devices: set/clear transceiver suspend mode */
202 static int gpio_vbus_set_suspend(struct otg_transceiver *otg, int suspend)
203 {
204         struct gpio_vbus_data *gpio_vbus;
205
206         gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
207
208         /* draw max 0 mA from vbus in suspend mode; or the previously
209          * recorded amount of current if not suspended
210          *
211          * NOTE: high powered configs (mA > 100) may draw up to 2.5 mA
212          * if they're wake-enabled ... we don't handle that yet.
213          */
214         return gpio_vbus_set_power(otg, suspend ? 0 : gpio_vbus->mA);
215 }
216
217 /* platform driver interface */
218
219 static int __init gpio_vbus_probe(struct platform_device *pdev)
220 {
221         struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
222         struct gpio_vbus_data *gpio_vbus;
223         struct resource *res;
224         int err, gpio, irq;
225
226         if (!pdata || !gpio_is_valid(pdata->gpio_vbus))
227                 return -EINVAL;
228         gpio = pdata->gpio_vbus;
229
230         gpio_vbus = kzalloc(sizeof(struct gpio_vbus_data), GFP_KERNEL);
231         if (!gpio_vbus)
232                 return -ENOMEM;
233
234         platform_set_drvdata(pdev, gpio_vbus);
235         gpio_vbus->dev = &pdev->dev;
236         gpio_vbus->otg.label = "gpio-vbus";
237         gpio_vbus->otg.state = OTG_STATE_UNDEFINED;
238         gpio_vbus->otg.set_peripheral = gpio_vbus_set_peripheral;
239         gpio_vbus->otg.set_power = gpio_vbus_set_power;
240         gpio_vbus->otg.set_suspend = gpio_vbus_set_suspend;
241
242         err = gpio_request(gpio, "vbus_detect");
243         if (err) {
244                 dev_err(&pdev->dev, "can't request vbus gpio %d, err: %d\n",
245                         gpio, err);
246                 goto err_gpio;
247         }
248         gpio_direction_input(gpio);
249
250         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
251         if (res) {
252                 irq = res->start;
253                 res->flags &= IRQF_TRIGGER_MASK;
254                 res->flags |= IRQF_SAMPLE_RANDOM | IRQF_SHARED;
255         } else
256                 irq = gpio_to_irq(gpio);
257
258         /* if data line pullup is in use, initialize it to "not pulling up" */
259         gpio = pdata->gpio_pullup;
260         if (gpio_is_valid(gpio)) {
261                 err = gpio_request(gpio, "udc_pullup");
262                 if (err) {
263                         dev_err(&pdev->dev,
264                                 "can't request pullup gpio %d, err: %d\n",
265                                 gpio, err);
266                         gpio_free(pdata->gpio_vbus);
267                         goto err_gpio;
268                 }
269                 gpio_direction_output(gpio, pdata->gpio_pullup_inverted);
270         }
271
272         err = request_irq(irq, gpio_vbus_irq, VBUS_IRQ_FLAGS,
273                 "vbus_detect", pdev);
274         if (err) {
275                 dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
276                         irq, err);
277                 goto err_irq;
278         }
279         INIT_WORK(&gpio_vbus->work, gpio_vbus_work);
280
281         /* only active when a gadget is registered */
282         err = otg_set_transceiver(&gpio_vbus->otg);
283         if (err) {
284                 dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
285                         err);
286                 goto err_otg;
287         }
288
289         gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw");
290         if (IS_ERR(gpio_vbus->vbus_draw)) {
291                 dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n",
292                         PTR_ERR(gpio_vbus->vbus_draw));
293                 gpio_vbus->vbus_draw = NULL;
294         }
295
296         return 0;
297 err_otg:
298         free_irq(irq, &pdev->dev);
299 err_irq:
300         if (gpio_is_valid(pdata->gpio_pullup))
301                 gpio_free(pdata->gpio_pullup);
302         gpio_free(pdata->gpio_vbus);
303 err_gpio:
304         platform_set_drvdata(pdev, NULL);
305         kfree(gpio_vbus);
306         return err;
307 }
308
309 static int __exit gpio_vbus_remove(struct platform_device *pdev)
310 {
311         struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
312         struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
313         int gpio = pdata->gpio_vbus;
314
315         regulator_put(gpio_vbus->vbus_draw);
316
317         otg_set_transceiver(NULL);
318
319         free_irq(gpio_to_irq(gpio), &pdev->dev);
320         if (gpio_is_valid(pdata->gpio_pullup))
321                 gpio_free(pdata->gpio_pullup);
322         gpio_free(gpio);
323         platform_set_drvdata(pdev, NULL);
324         kfree(gpio_vbus);
325
326         return 0;
327 }
328
329 /* NOTE:  the gpio-vbus device may *NOT* be hotplugged */
330
331 MODULE_ALIAS("platform:gpio-vbus");
332
333 static struct platform_driver gpio_vbus_driver = {
334         .driver = {
335                 .name  = "gpio-vbus",
336                 .owner = THIS_MODULE,
337         },
338         .remove  = __exit_p(gpio_vbus_remove),
339 };
340
341 static int __init gpio_vbus_init(void)
342 {
343         return platform_driver_probe(&gpio_vbus_driver, gpio_vbus_probe);
344 }
345 module_init(gpio_vbus_init);
346
347 static void __exit gpio_vbus_exit(void)
348 {
349         platform_driver_unregister(&gpio_vbus_driver);
350 }
351 module_exit(gpio_vbus_exit);
352
353 MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver");
354 MODULE_AUTHOR("Philipp Zabel");
355 MODULE_LICENSE("GPL");