Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

USB: gpio_vbus: add delayed vbus_session calls

Call usb_gadget_vbus_connect() and ...disconnect() from a
workqueue rather than from an irq handler, allowing msleep()
calls in vbus_session. Update kerneldoc to match.

[ dbrownell@users.sourceforge.net: more kerneldoc updates ]

Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Robert Jarzmik and committed by
Greg Kroah-Hartman
c2344f13 dd44be6b

+39 -13
+31 -11
drivers/usb/otg/gpio_vbus.c
··· 13 13 #include <linux/gpio.h> 14 14 #include <linux/interrupt.h> 15 15 #include <linux/usb.h> 16 + #include <linux/workqueue.h> 16 17 17 18 #include <linux/regulator/consumer.h> 18 19 ··· 35 34 struct regulator *vbus_draw; 36 35 int vbus_draw_enabled; 37 36 unsigned mA; 37 + struct work_struct work; 38 38 }; 39 39 40 40 ··· 78 76 gpio_vbus->mA = mA; 79 77 } 80 78 81 - /* VBUS change IRQ handler */ 82 - static irqreturn_t gpio_vbus_irq(int irq, void *data) 79 + static int is_vbus_powered(struct gpio_vbus_mach_info *pdata) 83 80 { 84 - struct platform_device *pdev = data; 85 - struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; 86 - struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); 87 - int gpio, vbus; 81 + int vbus; 88 82 89 83 vbus = gpio_get_value(pdata->gpio_vbus); 90 84 if (pdata->gpio_vbus_inverted) 91 85 vbus = !vbus; 92 86 93 - dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n", 94 - vbus ? "supplied" : "inactive", 95 - gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none"); 87 + return vbus; 88 + } 89 + 90 + static void gpio_vbus_work(struct work_struct *work) 91 + { 92 + struct gpio_vbus_data *gpio_vbus = 93 + container_of(work, struct gpio_vbus_data, work); 94 + struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data; 95 + int gpio; 96 96 97 97 if (!gpio_vbus->otg.gadget) 98 - return IRQ_HANDLED; 98 + return; 99 99 100 100 /* Peripheral controllers which manage the pullup themselves won't have 101 101 * gpio_pullup configured here. If it's configured here, we'll do what ··· 105 101 * that may complicate usb_gadget_{,dis}connect() support. 106 102 */ 107 103 gpio = pdata->gpio_pullup; 108 - if (vbus) { 104 + if (is_vbus_powered(pdata)) { 109 105 gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL; 110 106 usb_gadget_vbus_connect(gpio_vbus->otg.gadget); 111 107 ··· 125 121 usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget); 126 122 gpio_vbus->otg.state = OTG_STATE_B_IDLE; 127 123 } 124 + } 125 + 126 + /* VBUS change IRQ handler */ 127 + static irqreturn_t gpio_vbus_irq(int irq, void *data) 128 + { 129 + struct platform_device *pdev = data; 130 + struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; 131 + struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); 132 + 133 + dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n", 134 + is_vbus_powered(pdata) ? "supplied" : "inactive", 135 + gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none"); 136 + 137 + if (gpio_vbus->otg.gadget) 138 + schedule_work(&gpio_vbus->work); 128 139 129 140 return IRQ_HANDLED; 130 141 } ··· 276 257 irq, err); 277 258 goto err_irq; 278 259 } 260 + INIT_WORK(&gpio_vbus->work, gpio_vbus_work); 279 261 280 262 /* only active when a gadget is registered */ 281 263 err = otg_set_transceiver(&gpio_vbus->otg);
+4 -2
include/linux/usb/gadget.h
··· 598 598 /** 599 599 * usb_gadget_vbus_connect - Notify controller that VBUS is powered 600 600 * @gadget:The device which now has VBUS power. 601 + * Context: can sleep 601 602 * 602 603 * This call is used by a driver for an external transceiver (or GPIO) 603 604 * that detects a VBUS power session starting. Common responses include ··· 637 636 /** 638 637 * usb_gadget_vbus_disconnect - notify controller about VBUS session end 639 638 * @gadget:the device whose VBUS supply is being described 639 + * Context: can sleep 640 640 * 641 641 * This call is used by a driver for an external transceiver (or GPIO) 642 642 * that detects a VBUS power session ending. Common responses include ··· 794 792 /** 795 793 * usb_gadget_register_driver - register a gadget driver 796 794 * @driver:the driver being registered 795 + * Context: can sleep 797 796 * 798 797 * Call this in your gadget driver's module initialization function, 799 798 * to tell the underlying usb controller driver about your driver. 800 799 * The driver's bind() function will be called to bind it to a 801 800 * gadget before this registration call returns. It's expected that 802 801 * the bind() functions will be in init sections. 803 - * This function must be called in a context that can sleep. 804 802 */ 805 803 int usb_gadget_register_driver(struct usb_gadget_driver *driver); 806 804 807 805 /** 808 806 * usb_gadget_unregister_driver - unregister a gadget driver 809 807 * @driver:the driver being unregistered 808 + * Context: can sleep 810 809 * 811 810 * Call this in your gadget driver's module cleanup function, 812 811 * to tell the underlying usb controller that your driver is ··· 816 813 * to unbind() and clean up any device state, before this procedure 817 814 * finally returns. It's expected that the unbind() functions 818 815 * will in in exit sections, so may not be linked in some kernels. 819 - * This function must be called in a context that can sleep. 820 816 */ 821 817 int usb_gadget_unregister_driver(struct usb_gadget_driver *driver); 822 818
+4
include/linux/usb/otg.h
··· 86 86 extern struct otg_transceiver *otg_get_transceiver(void); 87 87 extern void otg_put_transceiver(struct otg_transceiver *); 88 88 89 + /* Context: can sleep */ 89 90 static inline int 90 91 otg_start_hnp(struct otg_transceiver *otg) 91 92 { ··· 103 102 104 103 105 104 /* for usb peripheral controller drivers */ 105 + 106 + /* Context: can sleep */ 106 107 static inline int 107 108 otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph) 108 109 { ··· 117 114 return otg->set_power(otg, mA); 118 115 } 119 116 117 + /* Context: can sleep */ 120 118 static inline int 121 119 otg_set_suspend(struct otg_transceiver *otg, int suspend) 122 120 {