Lines Matching +full:otg +full:- +full:gpio
1 // SPDX-License-Identifier: GPL-2.0
3 * gpio-vbus.c - simple GPIO VBUS sensing driver for B peripheral devices
10 #include <linux/gpio/consumer.h>
20 #include <linux/usb/otg.h>
24 * A simple GPIO VBUS sensing driver for B peripheral only devices
25 * with internal transceivers. It can control a D+ pullup GPIO and
60 struct regulator *vbus_draw = gpio_vbus->vbus_draw; in set_vbus_draw()
67 enabled = gpio_vbus->vbus_draw_enabled; in set_vbus_draw()
74 gpio_vbus->vbus_draw_enabled = 1; in set_vbus_draw()
81 gpio_vbus->vbus_draw_enabled = 0; in set_vbus_draw()
84 gpio_vbus->mA = mA; in set_vbus_draw()
89 return gpiod_get_value(gpio_vbus->vbus_gpiod); in is_vbus_powered()
98 if (!gpio_vbus->phy.otg->gadget) in gpio_vbus_work()
102 if ((vbus ^ gpio_vbus->vbus) == 0) in gpio_vbus_work()
104 gpio_vbus->vbus = vbus; in gpio_vbus_work()
107 * a pullup GPIO configured here. If it's configured here, we'll do in gpio_vbus_work()
114 gpio_vbus->phy.otg->state = OTG_STATE_B_PERIPHERAL; in gpio_vbus_work()
115 gpio_vbus->phy.last_event = status; in gpio_vbus_work()
116 usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget); in gpio_vbus_work()
118 /* drawing a "unit load" is *always* OK, except for OTG */ in gpio_vbus_work()
122 if (gpio_vbus->pullup_gpiod) in gpio_vbus_work()
123 gpiod_set_value(gpio_vbus->pullup_gpiod, 1); in gpio_vbus_work()
125 atomic_notifier_call_chain(&gpio_vbus->phy.notifier, in gpio_vbus_work()
126 status, gpio_vbus->phy.otg->gadget); in gpio_vbus_work()
127 usb_phy_set_event(&gpio_vbus->phy, USB_EVENT_ENUMERATED); in gpio_vbus_work()
130 if (gpio_vbus->pullup_gpiod) in gpio_vbus_work()
131 gpiod_set_value(gpio_vbus->pullup_gpiod, 0); in gpio_vbus_work()
135 usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget); in gpio_vbus_work()
137 gpio_vbus->phy.otg->state = OTG_STATE_B_IDLE; in gpio_vbus_work()
138 gpio_vbus->phy.last_event = status; in gpio_vbus_work()
140 atomic_notifier_call_chain(&gpio_vbus->phy.notifier, in gpio_vbus_work()
141 status, gpio_vbus->phy.otg->gadget); in gpio_vbus_work()
142 usb_phy_set_event(&gpio_vbus->phy, USB_EVENT_NONE); in gpio_vbus_work()
151 struct usb_otg *otg = gpio_vbus->phy.otg; in gpio_vbus_irq() local
153 dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n", in gpio_vbus_irq()
155 otg->gadget ? otg->gadget->name : "none"); in gpio_vbus_irq()
157 if (otg->gadget) in gpio_vbus_irq()
158 schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100)); in gpio_vbus_irq()
163 /* OTG transceiver interface */
166 static int gpio_vbus_set_peripheral(struct usb_otg *otg, in gpio_vbus_set_peripheral() argument
172 gpio_vbus = container_of(otg->usb_phy, struct gpio_vbus_data, phy); in gpio_vbus_set_peripheral()
173 pdev = to_platform_device(gpio_vbus->dev); in gpio_vbus_set_peripheral()
176 dev_dbg(&pdev->dev, "unregistering gadget '%s'\n", in gpio_vbus_set_peripheral()
177 otg->gadget->name); in gpio_vbus_set_peripheral()
180 if (gpio_vbus->pullup_gpiod) in gpio_vbus_set_peripheral()
181 gpiod_set_value(gpio_vbus->pullup_gpiod, 0); in gpio_vbus_set_peripheral()
185 usb_gadget_vbus_disconnect(otg->gadget); in gpio_vbus_set_peripheral()
186 otg->state = OTG_STATE_UNDEFINED; in gpio_vbus_set_peripheral()
188 otg->gadget = NULL; in gpio_vbus_set_peripheral()
192 otg->gadget = gadget; in gpio_vbus_set_peripheral()
193 dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name); in gpio_vbus_set_peripheral()
196 gpio_vbus->vbus = 0; /* start with disconnected */ in gpio_vbus_set_peripheral()
197 gpio_vbus_irq(gpio_vbus->irq, pdev); in gpio_vbus_set_peripheral()
201 /* effective for B devices, ignored for A-peripheral */
208 if (phy->otg->state == OTG_STATE_B_PERIPHERAL) in gpio_vbus_set_power()
213 /* for non-OTG B devices: set/clear transceiver suspend mode */
224 * if they're wake-enabled ... we don't handle that yet. in gpio_vbus_set_suspend()
226 return gpio_vbus_set_power(phy, suspend ? 0 : gpio_vbus->mA); in gpio_vbus_set_suspend()
235 struct device *dev = &pdev->dev; in gpio_vbus_probe()
239 gpio_vbus = devm_kzalloc(&pdev->dev, sizeof(struct gpio_vbus_data), in gpio_vbus_probe()
242 return -ENOMEM; in gpio_vbus_probe()
244 gpio_vbus->phy.otg = devm_kzalloc(&pdev->dev, sizeof(struct usb_otg), in gpio_vbus_probe()
246 if (!gpio_vbus->phy.otg) in gpio_vbus_probe()
247 return -ENOMEM; in gpio_vbus_probe()
250 gpio_vbus->dev = &pdev->dev; in gpio_vbus_probe()
251 gpio_vbus->phy.label = "gpio-vbus"; in gpio_vbus_probe()
252 gpio_vbus->phy.dev = gpio_vbus->dev; in gpio_vbus_probe()
253 gpio_vbus->phy.set_power = gpio_vbus_set_power; in gpio_vbus_probe()
254 gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend; in gpio_vbus_probe()
256 gpio_vbus->phy.otg->state = OTG_STATE_UNDEFINED; in gpio_vbus_probe()
257 gpio_vbus->phy.otg->usb_phy = &gpio_vbus->phy; in gpio_vbus_probe()
258 gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral; in gpio_vbus_probe()
260 /* Look up the VBUS sensing GPIO */ in gpio_vbus_probe()
261 gpio_vbus->vbus_gpiod = devm_gpiod_get(dev, "vbus", GPIOD_IN); in gpio_vbus_probe()
262 if (IS_ERR(gpio_vbus->vbus_gpiod)) { in gpio_vbus_probe()
263 err = PTR_ERR(gpio_vbus->vbus_gpiod); in gpio_vbus_probe()
264 dev_err(&pdev->dev, "can't request vbus gpio, err: %d\n", err); in gpio_vbus_probe()
267 gpiod_set_consumer_name(gpio_vbus->vbus_gpiod, "vbus_detect"); in gpio_vbus_probe()
271 irq = res->start; in gpio_vbus_probe()
272 irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; in gpio_vbus_probe()
274 irq = gpiod_to_irq(gpio_vbus->vbus_gpiod); in gpio_vbus_probe()
278 gpio_vbus->irq = irq; in gpio_vbus_probe()
281 * The VBUS sensing GPIO should have a pulldown, which will normally be in gpio_vbus_probe()
282 * part of a resistor ladder turning a 4.0V-5.25V level on VBUS into a in gpio_vbus_probe()
283 * value the GPIO detects as active. Some systems will use comparators. in gpio_vbus_probe()
284 * Get the optional D+ or D- pullup GPIO. If the data line pullup is in gpio_vbus_probe()
287 gpio_vbus->pullup_gpiod = devm_gpiod_get_optional(dev, "pullup", in gpio_vbus_probe()
289 if (IS_ERR(gpio_vbus->pullup_gpiod)) { in gpio_vbus_probe()
290 err = PTR_ERR(gpio_vbus->pullup_gpiod); in gpio_vbus_probe()
291 dev_err(&pdev->dev, "can't request pullup gpio, err: %d\n", in gpio_vbus_probe()
295 if (gpio_vbus->pullup_gpiod) in gpio_vbus_probe()
296 gpiod_set_consumer_name(gpio_vbus->pullup_gpiod, "udc_pullup"); in gpio_vbus_probe()
298 err = devm_request_irq(&pdev->dev, irq, gpio_vbus_irq, irqflags, in gpio_vbus_probe()
301 dev_err(&pdev->dev, "can't request irq %i, err: %d\n", in gpio_vbus_probe()
306 INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work); in gpio_vbus_probe()
308 gpio_vbus->vbus_draw = devm_regulator_get(&pdev->dev, "vbus_draw"); in gpio_vbus_probe()
309 if (IS_ERR(gpio_vbus->vbus_draw)) { in gpio_vbus_probe()
310 dev_dbg(&pdev->dev, "can't get vbus_draw regulator, err: %ld\n", in gpio_vbus_probe()
311 PTR_ERR(gpio_vbus->vbus_draw)); in gpio_vbus_probe()
312 gpio_vbus->vbus_draw = NULL; in gpio_vbus_probe()
316 err = usb_add_phy(&gpio_vbus->phy, USB_PHY_TYPE_USB2); in gpio_vbus_probe()
318 dev_err(&pdev->dev, "can't register transceiver, err: %d\n", in gpio_vbus_probe()
332 device_init_wakeup(&pdev->dev, 0); in gpio_vbus_remove()
333 cancel_delayed_work_sync(&gpio_vbus->work); in gpio_vbus_remove()
335 usb_remove_phy(&gpio_vbus->phy); in gpio_vbus_remove()
344 enable_irq_wake(gpio_vbus->irq); in gpio_vbus_pm_suspend()
354 disable_irq_wake(gpio_vbus->irq); in gpio_vbus_pm_resume()
365 MODULE_ALIAS("platform:gpio-vbus");
368 * NOTE: this driver matches against "gpio-usb-b-connector" for
373 .compatible = "gpio-usb-b-connector",
381 .name = "gpio-vbus",
393 MODULE_DESCRIPTION("simple GPIO controlled OTG transceiver driver");