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 /drivers/usb | |
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/otg/gpio_vbus.c | 42 |
1 files changed, 31 insertions, 11 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); |