1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * gpio-vbus.c - simple GPIO VBUS sensing driver for B peripheral devices |
4 | * |
5 | * Copyright (c) 2008 Philipp Zabel <philipp.zabel@gmail.com> |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/platform_device.h> |
10 | #include <linux/gpio/consumer.h> |
11 | #include <linux/module.h> |
12 | #include <linux/slab.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/usb.h> |
15 | #include <linux/workqueue.h> |
16 | |
17 | #include <linux/regulator/consumer.h> |
18 | |
19 | #include <linux/usb/gadget.h> |
20 | #include <linux/usb/otg.h> |
21 | |
22 | |
23 | /* |
24 | * A simple GPIO VBUS sensing driver for B peripheral only devices |
25 | * with internal transceivers. It can control a D+ pullup GPIO and |
26 | * a regulator to limit the current drawn from VBUS. |
27 | * |
28 | * Needs to be loaded before the UDC driver that will use it. |
29 | */ |
30 | struct gpio_vbus_data { |
31 | struct gpio_desc *vbus_gpiod; |
32 | struct gpio_desc *pullup_gpiod; |
33 | struct usb_phy phy; |
34 | struct device *dev; |
35 | struct regulator *vbus_draw; |
36 | int vbus_draw_enabled; |
37 | unsigned mA; |
38 | struct delayed_work work; |
39 | int vbus; |
40 | int irq; |
41 | }; |
42 | |
43 | |
44 | /* |
45 | * This driver relies on "both edges" triggering. VBUS has 100 msec to |
46 | * stabilize, so the peripheral controller driver may need to cope with |
47 | * some bouncing due to current surges (e.g. charging local capacitance) |
48 | * and contact chatter. |
49 | * |
50 | * REVISIT in desperate straits, toggling between rising and falling |
51 | * edges might be workable. |
52 | */ |
53 | #define VBUS_IRQ_FLAGS \ |
54 | (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) |
55 | |
56 | |
57 | /* interface to regulator framework */ |
58 | static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA) |
59 | { |
60 | struct regulator *vbus_draw = gpio_vbus->vbus_draw; |
61 | int enabled; |
62 | int ret; |
63 | |
64 | if (!vbus_draw) |
65 | return; |
66 | |
67 | enabled = gpio_vbus->vbus_draw_enabled; |
68 | if (mA) { |
69 | regulator_set_current_limit(regulator: vbus_draw, min_uA: 0, max_uA: 1000 * mA); |
70 | if (!enabled) { |
71 | ret = regulator_enable(regulator: vbus_draw); |
72 | if (ret < 0) |
73 | return; |
74 | gpio_vbus->vbus_draw_enabled = 1; |
75 | } |
76 | } else { |
77 | if (enabled) { |
78 | ret = regulator_disable(regulator: vbus_draw); |
79 | if (ret < 0) |
80 | return; |
81 | gpio_vbus->vbus_draw_enabled = 0; |
82 | } |
83 | } |
84 | gpio_vbus->mA = mA; |
85 | } |
86 | |
87 | static int is_vbus_powered(struct gpio_vbus_data *gpio_vbus) |
88 | { |
89 | return gpiod_get_value(desc: gpio_vbus->vbus_gpiod); |
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.work); |
96 | int status, vbus; |
97 | |
98 | if (!gpio_vbus->phy.otg->gadget) |
99 | return; |
100 | |
101 | vbus = is_vbus_powered(gpio_vbus); |
102 | if ((vbus ^ gpio_vbus->vbus) == 0) |
103 | return; |
104 | gpio_vbus->vbus = vbus; |
105 | |
106 | /* Peripheral controllers which manage the pullup themselves won't have |
107 | * a pullup GPIO configured here. If it's configured here, we'll do |
108 | * what isp1301_omap::b_peripheral() does and enable the pullup here... |
109 | * although that may complicate usb_gadget_{,dis}connect() support. |
110 | */ |
111 | |
112 | if (vbus) { |
113 | status = USB_EVENT_VBUS; |
114 | gpio_vbus->phy.otg->state = OTG_STATE_B_PERIPHERAL; |
115 | gpio_vbus->phy.last_event = status; |
116 | usb_gadget_vbus_connect(gadget: gpio_vbus->phy.otg->gadget); |
117 | |
118 | /* drawing a "unit load" is *always* OK, except for OTG */ |
119 | set_vbus_draw(gpio_vbus, mA: 100); |
120 | |
121 | /* optionally enable D+ pullup */ |
122 | if (gpio_vbus->pullup_gpiod) |
123 | gpiod_set_value(desc: gpio_vbus->pullup_gpiod, value: 1); |
124 | |
125 | atomic_notifier_call_chain(nh: &gpio_vbus->phy.notifier, |
126 | val: status, v: gpio_vbus->phy.otg->gadget); |
127 | usb_phy_set_event(x: &gpio_vbus->phy, event: USB_EVENT_ENUMERATED); |
128 | } else { |
129 | /* optionally disable D+ pullup */ |
130 | if (gpio_vbus->pullup_gpiod) |
131 | gpiod_set_value(desc: gpio_vbus->pullup_gpiod, value: 0); |
132 | |
133 | set_vbus_draw(gpio_vbus, mA: 0); |
134 | |
135 | usb_gadget_vbus_disconnect(gadget: gpio_vbus->phy.otg->gadget); |
136 | status = USB_EVENT_NONE; |
137 | gpio_vbus->phy.otg->state = OTG_STATE_B_IDLE; |
138 | gpio_vbus->phy.last_event = status; |
139 | |
140 | atomic_notifier_call_chain(nh: &gpio_vbus->phy.notifier, |
141 | val: status, v: gpio_vbus->phy.otg->gadget); |
142 | usb_phy_set_event(x: &gpio_vbus->phy, event: USB_EVENT_NONE); |
143 | } |
144 | } |
145 | |
146 | /* VBUS change IRQ handler */ |
147 | static irqreturn_t gpio_vbus_irq(int irq, void *data) |
148 | { |
149 | struct platform_device *pdev = data; |
150 | struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); |
151 | struct usb_otg *otg = gpio_vbus->phy.otg; |
152 | |
153 | dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n" , |
154 | is_vbus_powered(gpio_vbus) ? "supplied" : "inactive" , |
155 | otg->gadget ? otg->gadget->name : "none" ); |
156 | |
157 | if (otg->gadget) |
158 | schedule_delayed_work(dwork: &gpio_vbus->work, delay: msecs_to_jiffies(m: 100)); |
159 | |
160 | return IRQ_HANDLED; |
161 | } |
162 | |
163 | /* OTG transceiver interface */ |
164 | |
165 | /* bind/unbind the peripheral controller */ |
166 | static int gpio_vbus_set_peripheral(struct usb_otg *otg, |
167 | struct usb_gadget *gadget) |
168 | { |
169 | struct gpio_vbus_data *gpio_vbus; |
170 | struct platform_device *pdev; |
171 | |
172 | gpio_vbus = container_of(otg->usb_phy, struct gpio_vbus_data, phy); |
173 | pdev = to_platform_device(gpio_vbus->dev); |
174 | |
175 | if (!gadget) { |
176 | dev_dbg(&pdev->dev, "unregistering gadget '%s'\n" , |
177 | otg->gadget->name); |
178 | |
179 | /* optionally disable D+ pullup */ |
180 | if (gpio_vbus->pullup_gpiod) |
181 | gpiod_set_value(desc: gpio_vbus->pullup_gpiod, value: 0); |
182 | |
183 | set_vbus_draw(gpio_vbus, mA: 0); |
184 | |
185 | usb_gadget_vbus_disconnect(gadget: otg->gadget); |
186 | otg->state = OTG_STATE_UNDEFINED; |
187 | |
188 | otg->gadget = NULL; |
189 | return 0; |
190 | } |
191 | |
192 | otg->gadget = gadget; |
193 | dev_dbg(&pdev->dev, "registered gadget '%s'\n" , gadget->name); |
194 | |
195 | /* initialize connection state */ |
196 | gpio_vbus->vbus = 0; /* start with disconnected */ |
197 | gpio_vbus_irq(irq: gpio_vbus->irq, data: pdev); |
198 | return 0; |
199 | } |
200 | |
201 | /* effective for B devices, ignored for A-peripheral */ |
202 | static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA) |
203 | { |
204 | struct gpio_vbus_data *gpio_vbus; |
205 | |
206 | gpio_vbus = container_of(phy, struct gpio_vbus_data, phy); |
207 | |
208 | if (phy->otg->state == OTG_STATE_B_PERIPHERAL) |
209 | set_vbus_draw(gpio_vbus, mA); |
210 | return 0; |
211 | } |
212 | |
213 | /* for non-OTG B devices: set/clear transceiver suspend mode */ |
214 | static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend) |
215 | { |
216 | struct gpio_vbus_data *gpio_vbus; |
217 | |
218 | gpio_vbus = container_of(phy, struct gpio_vbus_data, phy); |
219 | |
220 | /* draw max 0 mA from vbus in suspend mode; or the previously |
221 | * recorded amount of current if not suspended |
222 | * |
223 | * NOTE: high powered configs (mA > 100) may draw up to 2.5 mA |
224 | * if they're wake-enabled ... we don't handle that yet. |
225 | */ |
226 | return gpio_vbus_set_power(phy, mA: suspend ? 0 : gpio_vbus->mA); |
227 | } |
228 | |
229 | /* platform driver interface */ |
230 | |
231 | static int gpio_vbus_probe(struct platform_device *pdev) |
232 | { |
233 | struct gpio_vbus_data *gpio_vbus; |
234 | struct resource *res; |
235 | struct device *dev = &pdev->dev; |
236 | int err, irq; |
237 | unsigned long irqflags; |
238 | |
239 | gpio_vbus = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct gpio_vbus_data), |
240 | GFP_KERNEL); |
241 | if (!gpio_vbus) |
242 | return -ENOMEM; |
243 | |
244 | gpio_vbus->phy.otg = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct usb_otg), |
245 | GFP_KERNEL); |
246 | if (!gpio_vbus->phy.otg) |
247 | return -ENOMEM; |
248 | |
249 | platform_set_drvdata(pdev, data: gpio_vbus); |
250 | gpio_vbus->dev = &pdev->dev; |
251 | gpio_vbus->phy.label = "gpio-vbus" ; |
252 | gpio_vbus->phy.dev = gpio_vbus->dev; |
253 | gpio_vbus->phy.set_power = gpio_vbus_set_power; |
254 | gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend; |
255 | |
256 | gpio_vbus->phy.otg->state = OTG_STATE_UNDEFINED; |
257 | gpio_vbus->phy.otg->usb_phy = &gpio_vbus->phy; |
258 | gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral; |
259 | |
260 | /* Look up the VBUS sensing GPIO */ |
261 | gpio_vbus->vbus_gpiod = devm_gpiod_get(dev, con_id: "vbus" , flags: GPIOD_IN); |
262 | if (IS_ERR(ptr: gpio_vbus->vbus_gpiod)) { |
263 | err = PTR_ERR(ptr: gpio_vbus->vbus_gpiod); |
264 | dev_err(&pdev->dev, "can't request vbus gpio, err: %d\n" , err); |
265 | return err; |
266 | } |
267 | gpiod_set_consumer_name(desc: gpio_vbus->vbus_gpiod, name: "vbus_detect" ); |
268 | |
269 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
270 | if (res) { |
271 | irq = res->start; |
272 | irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; |
273 | } else { |
274 | irq = gpiod_to_irq(desc: gpio_vbus->vbus_gpiod); |
275 | irqflags = VBUS_IRQ_FLAGS; |
276 | } |
277 | |
278 | gpio_vbus->irq = irq; |
279 | |
280 | /* |
281 | * The VBUS sensing GPIO should have a pulldown, which will normally be |
282 | * part of a resistor ladder turning a 4.0V-5.25V level on VBUS into a |
283 | * value the GPIO detects as active. Some systems will use comparators. |
284 | * Get the optional D+ or D- pullup GPIO. If the data line pullup is |
285 | * in use, initialize it to "not pulling up" |
286 | */ |
287 | gpio_vbus->pullup_gpiod = devm_gpiod_get_optional(dev, con_id: "pullup" , |
288 | flags: GPIOD_OUT_LOW); |
289 | if (IS_ERR(ptr: gpio_vbus->pullup_gpiod)) { |
290 | err = PTR_ERR(ptr: gpio_vbus->pullup_gpiod); |
291 | dev_err(&pdev->dev, "can't request pullup gpio, err: %d\n" , |
292 | err); |
293 | return err; |
294 | } |
295 | if (gpio_vbus->pullup_gpiod) |
296 | gpiod_set_consumer_name(desc: gpio_vbus->pullup_gpiod, name: "udc_pullup" ); |
297 | |
298 | err = devm_request_irq(dev: &pdev->dev, irq, handler: gpio_vbus_irq, irqflags, |
299 | devname: "vbus_detect" , dev_id: pdev); |
300 | if (err) { |
301 | dev_err(&pdev->dev, "can't request irq %i, err: %d\n" , |
302 | irq, err); |
303 | return err; |
304 | } |
305 | |
306 | INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work); |
307 | |
308 | gpio_vbus->vbus_draw = devm_regulator_get(dev: &pdev->dev, id: "vbus_draw" ); |
309 | if (IS_ERR(ptr: gpio_vbus->vbus_draw)) { |
310 | dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n" , |
311 | PTR_ERR(gpio_vbus->vbus_draw)); |
312 | gpio_vbus->vbus_draw = NULL; |
313 | } |
314 | |
315 | /* only active when a gadget is registered */ |
316 | err = usb_add_phy(&gpio_vbus->phy, type: USB_PHY_TYPE_USB2); |
317 | if (err) { |
318 | dev_err(&pdev->dev, "can't register transceiver, err: %d\n" , |
319 | err); |
320 | return err; |
321 | } |
322 | |
323 | /* TODO: wakeup could be enabled here with device_init_wakeup(dev, 1) */ |
324 | |
325 | return 0; |
326 | } |
327 | |
328 | static void gpio_vbus_remove(struct platform_device *pdev) |
329 | { |
330 | struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); |
331 | |
332 | device_init_wakeup(dev: &pdev->dev, enable: 0); |
333 | cancel_delayed_work_sync(dwork: &gpio_vbus->work); |
334 | |
335 | usb_remove_phy(&gpio_vbus->phy); |
336 | } |
337 | |
338 | #ifdef CONFIG_PM |
339 | static int gpio_vbus_pm_suspend(struct device *dev) |
340 | { |
341 | struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev); |
342 | |
343 | if (device_may_wakeup(dev)) |
344 | enable_irq_wake(irq: gpio_vbus->irq); |
345 | |
346 | return 0; |
347 | } |
348 | |
349 | static int gpio_vbus_pm_resume(struct device *dev) |
350 | { |
351 | struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev); |
352 | |
353 | if (device_may_wakeup(dev)) |
354 | disable_irq_wake(irq: gpio_vbus->irq); |
355 | |
356 | return 0; |
357 | } |
358 | |
359 | static const struct dev_pm_ops gpio_vbus_dev_pm_ops = { |
360 | .suspend = gpio_vbus_pm_suspend, |
361 | .resume = gpio_vbus_pm_resume, |
362 | }; |
363 | #endif |
364 | |
365 | MODULE_ALIAS("platform:gpio-vbus" ); |
366 | |
367 | /* |
368 | * NOTE: this driver matches against "gpio-usb-b-connector" for |
369 | * devices that do NOT support role switch. |
370 | */ |
371 | static const struct of_device_id gpio_vbus_of_match[] = { |
372 | { |
373 | .compatible = "gpio-usb-b-connector" , |
374 | }, |
375 | {}, |
376 | }; |
377 | |
378 | static struct platform_driver gpio_vbus_driver = { |
379 | .driver = { |
380 | .name = "gpio-vbus" , |
381 | #ifdef CONFIG_PM |
382 | .pm = &gpio_vbus_dev_pm_ops, |
383 | #endif |
384 | .of_match_table = gpio_vbus_of_match, |
385 | }, |
386 | .probe = gpio_vbus_probe, |
387 | .remove_new = gpio_vbus_remove, |
388 | }; |
389 | |
390 | module_platform_driver(gpio_vbus_driver); |
391 | |
392 | MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver" ); |
393 | MODULE_AUTHOR("Philipp Zabel" ); |
394 | MODULE_LICENSE("GPL" ); |
395 | |