diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2009-01-25 02:54:31 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-03-24 19:20:26 -0400 |
commit | c2344f13b59e007d782a3e591ebc551bc583a8b7 (patch) | |
tree | 17eda364b35d5c064c47e45b50487912844a0fa3 | |
parent | dd44be6b17ac52238aa6c7f46b906d9fb76e7052 (diff) |
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>
-rw-r--r-- | drivers/usb/otg/gpio_vbus.c | 42 | ||||
-rw-r--r-- | include/linux/usb/gadget.h | 6 | ||||
-rw-r--r-- | include/linux/usb/otg.h | 4 |
3 files changed, 39 insertions, 13 deletions
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c index 63a6036f04be..1c26c94513e9 100644 --- a/drivers/usb/otg/gpio_vbus.c +++ b/drivers/usb/otg/gpio_vbus.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/gpio.h> | 13 | #include <linux/gpio.h> |
14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
15 | #include <linux/usb.h> | 15 | #include <linux/usb.h> |
16 | #include <linux/workqueue.h> | ||
16 | 17 | ||
17 | #include <linux/regulator/consumer.h> | 18 | #include <linux/regulator/consumer.h> |
18 | 19 | ||
@@ -34,6 +35,7 @@ struct gpio_vbus_data { | |||
34 | struct regulator *vbus_draw; | 35 | struct regulator *vbus_draw; |
35 | int vbus_draw_enabled; | 36 | int vbus_draw_enabled; |
36 | unsigned mA; | 37 | unsigned mA; |
38 | struct work_struct work; | ||
37 | }; | 39 | }; |
38 | 40 | ||
39 | 41 | ||
@@ -76,24 +78,26 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA) | |||
76 | gpio_vbus->mA = mA; | 78 | gpio_vbus->mA = mA; |
77 | } | 79 | } |
78 | 80 | ||
79 | /* VBUS change IRQ handler */ | 81 | static int is_vbus_powered(struct gpio_vbus_mach_info *pdata) |
80 | static irqreturn_t gpio_vbus_irq(int irq, void *data) | ||
81 | { | 82 | { |
82 | struct platform_device *pdev = data; | 83 | int vbus; |
83 | struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; | ||
84 | struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); | ||
85 | int gpio, vbus; | ||
86 | 84 | ||
87 | vbus = gpio_get_value(pdata->gpio_vbus); | 85 | vbus = gpio_get_value(pdata->gpio_vbus); |
88 | if (pdata->gpio_vbus_inverted) | 86 | if (pdata->gpio_vbus_inverted) |
89 | vbus = !vbus; | 87 | vbus = !vbus; |
90 | 88 | ||
91 | dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n", | 89 | return vbus; |
92 | vbus ? "supplied" : "inactive", | 90 | } |
93 | gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none"); | 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; | ||
94 | 98 | ||
95 | if (!gpio_vbus->otg.gadget) | 99 | if (!gpio_vbus->otg.gadget) |
96 | return IRQ_HANDLED; | 100 | return; |
97 | 101 | ||
98 | /* Peripheral controllers which manage the pullup themselves won't have | 102 | /* Peripheral controllers which manage the pullup themselves won't have |
99 | * gpio_pullup configured here. If it's configured here, we'll do what | 103 | * gpio_pullup configured here. If it's configured here, we'll do what |
@@ -101,7 +105,7 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data) | |||
101 | * that may complicate usb_gadget_{,dis}connect() support. | 105 | * that may complicate usb_gadget_{,dis}connect() support. |
102 | */ | 106 | */ |
103 | gpio = pdata->gpio_pullup; | 107 | gpio = pdata->gpio_pullup; |
104 | if (vbus) { | 108 | if (is_vbus_powered(pdata)) { |
105 | gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL; | 109 | gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL; |
106 | usb_gadget_vbus_connect(gpio_vbus->otg.gadget); | 110 | usb_gadget_vbus_connect(gpio_vbus->otg.gadget); |
107 | 111 | ||
@@ -121,6 +125,21 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data) | |||
121 | usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget); | 125 | usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget); |
122 | gpio_vbus->otg.state = OTG_STATE_B_IDLE; | 126 | gpio_vbus->otg.state = OTG_STATE_B_IDLE; |
123 | } | 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); | ||
124 | 143 | ||
125 | return IRQ_HANDLED; | 144 | return IRQ_HANDLED; |
126 | } | 145 | } |
@@ -257,6 +276,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) | |||
257 | irq, err); | 276 | irq, err); |
258 | goto err_irq; | 277 | goto err_irq; |
259 | } | 278 | } |
279 | INIT_WORK(&gpio_vbus->work, gpio_vbus_work); | ||
260 | 280 | ||
261 | /* only active when a gadget is registered */ | 281 | /* only active when a gadget is registered */ |
262 | err = otg_set_transceiver(&gpio_vbus->otg); | 282 | err = otg_set_transceiver(&gpio_vbus->otg); |
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 0460a746480c..bbf45d500b6d 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h | |||
@@ -598,6 +598,7 @@ static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget) | |||
598 | /** | 598 | /** |
599 | * usb_gadget_vbus_connect - Notify controller that VBUS is powered | 599 | * usb_gadget_vbus_connect - Notify controller that VBUS is powered |
600 | * @gadget:The device which now has VBUS power. | 600 | * @gadget:The device which now has VBUS power. |
601 | * Context: can sleep | ||
601 | * | 602 | * |
602 | * This call is used by a driver for an external transceiver (or GPIO) | 603 | * This call is used by a driver for an external transceiver (or GPIO) |
603 | * that detects a VBUS power session starting. Common responses include | 604 | * that detects a VBUS power session starting. Common responses include |
@@ -636,6 +637,7 @@ static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA) | |||
636 | /** | 637 | /** |
637 | * usb_gadget_vbus_disconnect - notify controller about VBUS session end | 638 | * usb_gadget_vbus_disconnect - notify controller about VBUS session end |
638 | * @gadget:the device whose VBUS supply is being described | 639 | * @gadget:the device whose VBUS supply is being described |
640 | * Context: can sleep | ||
639 | * | 641 | * |
640 | * This call is used by a driver for an external transceiver (or GPIO) | 642 | * This call is used by a driver for an external transceiver (or GPIO) |
641 | * that detects a VBUS power session ending. Common responses include | 643 | * that detects a VBUS power session ending. Common responses include |
@@ -792,19 +794,20 @@ struct usb_gadget_driver { | |||
792 | /** | 794 | /** |
793 | * usb_gadget_register_driver - register a gadget driver | 795 | * usb_gadget_register_driver - register a gadget driver |
794 | * @driver:the driver being registered | 796 | * @driver:the driver being registered |
797 | * Context: can sleep | ||
795 | * | 798 | * |
796 | * Call this in your gadget driver's module initialization function, | 799 | * Call this in your gadget driver's module initialization function, |
797 | * to tell the underlying usb controller driver about your driver. | 800 | * to tell the underlying usb controller driver about your driver. |
798 | * The driver's bind() function will be called to bind it to a | 801 | * The driver's bind() function will be called to bind it to a |
799 | * gadget before this registration call returns. It's expected that | 802 | * gadget before this registration call returns. It's expected that |
800 | * the bind() functions will be in init sections. | 803 | * the bind() functions will be in init sections. |
801 | * This function must be called in a context that can sleep. | ||
802 | */ | 804 | */ |
803 | int usb_gadget_register_driver(struct usb_gadget_driver *driver); | 805 | int usb_gadget_register_driver(struct usb_gadget_driver *driver); |
804 | 806 | ||
805 | /** | 807 | /** |
806 | * usb_gadget_unregister_driver - unregister a gadget driver | 808 | * usb_gadget_unregister_driver - unregister a gadget driver |
807 | * @driver:the driver being unregistered | 809 | * @driver:the driver being unregistered |
810 | * Context: can sleep | ||
808 | * | 811 | * |
809 | * Call this in your gadget driver's module cleanup function, | 812 | * Call this in your gadget driver's module cleanup function, |
810 | * to tell the underlying usb controller that your driver is | 813 | * to tell the underlying usb controller that your driver is |
@@ -813,7 +816,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver); | |||
813 | * to unbind() and clean up any device state, before this procedure | 816 | * to unbind() and clean up any device state, before this procedure |
814 | * finally returns. It's expected that the unbind() functions | 817 | * finally returns. It's expected that the unbind() functions |
815 | * will in in exit sections, so may not be linked in some kernels. | 818 | * will in in exit sections, so may not be linked in some kernels. |
816 | * This function must be called in a context that can sleep. | ||
817 | */ | 819 | */ |
818 | int usb_gadget_unregister_driver(struct usb_gadget_driver *driver); | 820 | int usb_gadget_unregister_driver(struct usb_gadget_driver *driver); |
819 | 821 | ||
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h index 94df4fe6c6c0..60a52576fd5c 100644 --- a/include/linux/usb/otg.h +++ b/include/linux/usb/otg.h | |||
@@ -86,6 +86,7 @@ extern int otg_set_transceiver(struct otg_transceiver *); | |||
86 | extern struct otg_transceiver *otg_get_transceiver(void); | 86 | extern struct otg_transceiver *otg_get_transceiver(void); |
87 | extern void otg_put_transceiver(struct otg_transceiver *); | 87 | extern void otg_put_transceiver(struct otg_transceiver *); |
88 | 88 | ||
89 | /* Context: can sleep */ | ||
89 | static inline int | 90 | static inline int |
90 | otg_start_hnp(struct otg_transceiver *otg) | 91 | otg_start_hnp(struct otg_transceiver *otg) |
91 | { | 92 | { |
@@ -102,6 +103,8 @@ otg_set_host(struct otg_transceiver *otg, struct usb_bus *host) | |||
102 | 103 | ||
103 | 104 | ||
104 | /* for usb peripheral controller drivers */ | 105 | /* for usb peripheral controller drivers */ |
106 | |||
107 | /* Context: can sleep */ | ||
105 | static inline int | 108 | static inline int |
106 | otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph) | 109 | otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph) |
107 | { | 110 | { |
@@ -114,6 +117,7 @@ otg_set_power(struct otg_transceiver *otg, unsigned mA) | |||
114 | return otg->set_power(otg, mA); | 117 | return otg->set_power(otg, mA); |
115 | } | 118 | } |
116 | 119 | ||
120 | /* Context: can sleep */ | ||
117 | static inline int | 121 | static inline int |
118 | otg_set_suspend(struct otg_transceiver *otg, int suspend) | 122 | otg_set_suspend(struct otg_transceiver *otg, int suspend) |
119 | { | 123 | { |