mirror of
https://github.com/FEX-Emu/linux.git
synced 2025-02-06 11:19:56 +00:00
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>
This commit is contained in:
parent
dd44be6b17
commit
c2344f13b5
@ -13,6 +13,7 @@
|
|||||||
#include <linux/gpio.h>
|
#include <linux/gpio.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ struct gpio_vbus_data {
|
|||||||
struct regulator *vbus_draw;
|
struct regulator *vbus_draw;
|
||||||
int vbus_draw_enabled;
|
int vbus_draw_enabled;
|
||||||
unsigned mA;
|
unsigned mA;
|
||||||
|
struct work_struct work;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -76,24 +78,26 @@ static void set_vbus_draw(struct gpio_vbus_data *gpio_vbus, unsigned mA)
|
|||||||
gpio_vbus->mA = mA;
|
gpio_vbus->mA = mA;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* VBUS change IRQ handler */
|
static int is_vbus_powered(struct gpio_vbus_mach_info *pdata)
|
||||||
static irqreturn_t gpio_vbus_irq(int irq, void *data)
|
|
||||||
{
|
{
|
||||||
struct platform_device *pdev = data;
|
int vbus;
|
||||||
struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
|
|
||||||
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
|
|
||||||
int gpio, vbus;
|
|
||||||
|
|
||||||
vbus = gpio_get_value(pdata->gpio_vbus);
|
vbus = gpio_get_value(pdata->gpio_vbus);
|
||||||
if (pdata->gpio_vbus_inverted)
|
if (pdata->gpio_vbus_inverted)
|
||||||
vbus = !vbus;
|
vbus = !vbus;
|
||||||
|
|
||||||
dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
|
return vbus;
|
||||||
vbus ? "supplied" : "inactive",
|
}
|
||||||
gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none");
|
|
||||||
|
static void gpio_vbus_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct gpio_vbus_data *gpio_vbus =
|
||||||
|
container_of(work, struct gpio_vbus_data, work);
|
||||||
|
struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
|
||||||
|
int gpio;
|
||||||
|
|
||||||
if (!gpio_vbus->otg.gadget)
|
if (!gpio_vbus->otg.gadget)
|
||||||
return IRQ_HANDLED;
|
return;
|
||||||
|
|
||||||
/* Peripheral controllers which manage the pullup themselves won't have
|
/* Peripheral controllers which manage the pullup themselves won't have
|
||||||
* gpio_pullup configured here. If it's configured here, we'll do what
|
* 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)
|
|||||||
* that may complicate usb_gadget_{,dis}connect() support.
|
* that may complicate usb_gadget_{,dis}connect() support.
|
||||||
*/
|
*/
|
||||||
gpio = pdata->gpio_pullup;
|
gpio = pdata->gpio_pullup;
|
||||||
if (vbus) {
|
if (is_vbus_powered(pdata)) {
|
||||||
gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL;
|
gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL;
|
||||||
usb_gadget_vbus_connect(gpio_vbus->otg.gadget);
|
usb_gadget_vbus_connect(gpio_vbus->otg.gadget);
|
||||||
|
|
||||||
@ -121,6 +125,21 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data)
|
|||||||
usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget);
|
usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget);
|
||||||
gpio_vbus->otg.state = OTG_STATE_B_IDLE;
|
gpio_vbus->otg.state = OTG_STATE_B_IDLE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* VBUS change IRQ handler */
|
||||||
|
static irqreturn_t gpio_vbus_irq(int irq, void *data)
|
||||||
|
{
|
||||||
|
struct platform_device *pdev = data;
|
||||||
|
struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
|
||||||
|
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
|
||||||
|
is_vbus_powered(pdata) ? "supplied" : "inactive",
|
||||||
|
gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none");
|
||||||
|
|
||||||
|
if (gpio_vbus->otg.gadget)
|
||||||
|
schedule_work(&gpio_vbus->work);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
@ -257,6 +276,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
|
|||||||
irq, err);
|
irq, err);
|
||||||
goto err_irq;
|
goto err_irq;
|
||||||
}
|
}
|
||||||
|
INIT_WORK(&gpio_vbus->work, gpio_vbus_work);
|
||||||
|
|
||||||
/* only active when a gadget is registered */
|
/* only active when a gadget is registered */
|
||||||
err = otg_set_transceiver(&gpio_vbus->otg);
|
err = otg_set_transceiver(&gpio_vbus->otg);
|
||||||
|
@ -598,6 +598,7 @@ static inline int usb_gadget_clear_selfpowered(struct usb_gadget *gadget)
|
|||||||
/**
|
/**
|
||||||
* usb_gadget_vbus_connect - Notify controller that VBUS is powered
|
* usb_gadget_vbus_connect - Notify controller that VBUS is powered
|
||||||
* @gadget:The device which now has VBUS power.
|
* @gadget:The device which now has VBUS power.
|
||||||
|
* Context: can sleep
|
||||||
*
|
*
|
||||||
* This call is used by a driver for an external transceiver (or GPIO)
|
* This call is used by a driver for an external transceiver (or GPIO)
|
||||||
* that detects a VBUS power session starting. Common responses include
|
* 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)
|
|||||||
/**
|
/**
|
||||||
* usb_gadget_vbus_disconnect - notify controller about VBUS session end
|
* usb_gadget_vbus_disconnect - notify controller about VBUS session end
|
||||||
* @gadget:the device whose VBUS supply is being described
|
* @gadget:the device whose VBUS supply is being described
|
||||||
|
* Context: can sleep
|
||||||
*
|
*
|
||||||
* This call is used by a driver for an external transceiver (or GPIO)
|
* This call is used by a driver for an external transceiver (or GPIO)
|
||||||
* that detects a VBUS power session ending. Common responses include
|
* that detects a VBUS power session ending. Common responses include
|
||||||
@ -792,19 +794,20 @@ struct usb_gadget_driver {
|
|||||||
/**
|
/**
|
||||||
* usb_gadget_register_driver - register a gadget driver
|
* usb_gadget_register_driver - register a gadget driver
|
||||||
* @driver:the driver being registered
|
* @driver:the driver being registered
|
||||||
|
* Context: can sleep
|
||||||
*
|
*
|
||||||
* Call this in your gadget driver's module initialization function,
|
* Call this in your gadget driver's module initialization function,
|
||||||
* to tell the underlying usb controller driver about your driver.
|
* to tell the underlying usb controller driver about your driver.
|
||||||
* The driver's bind() function will be called to bind it to a
|
* The driver's bind() function will be called to bind it to a
|
||||||
* gadget before this registration call returns. It's expected that
|
* gadget before this registration call returns. It's expected that
|
||||||
* the bind() functions will be in init sections.
|
* the bind() functions will be in init sections.
|
||||||
* This function must be called in a context that can sleep.
|
|
||||||
*/
|
*/
|
||||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver);
|
int usb_gadget_register_driver(struct usb_gadget_driver *driver);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* usb_gadget_unregister_driver - unregister a gadget driver
|
* usb_gadget_unregister_driver - unregister a gadget driver
|
||||||
* @driver:the driver being unregistered
|
* @driver:the driver being unregistered
|
||||||
|
* Context: can sleep
|
||||||
*
|
*
|
||||||
* Call this in your gadget driver's module cleanup function,
|
* Call this in your gadget driver's module cleanup function,
|
||||||
* to tell the underlying usb controller that your driver is
|
* to tell the underlying usb controller that your driver is
|
||||||
@ -813,7 +816,6 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver);
|
|||||||
* to unbind() and clean up any device state, before this procedure
|
* to unbind() and clean up any device state, before this procedure
|
||||||
* finally returns. It's expected that the unbind() functions
|
* finally returns. It's expected that the unbind() functions
|
||||||
* will in in exit sections, so may not be linked in some kernels.
|
* will in in exit sections, so may not be linked in some kernels.
|
||||||
* This function must be called in a context that can sleep.
|
|
||||||
*/
|
*/
|
||||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
|
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver);
|
||||||
|
|
||||||
|
@ -86,6 +86,7 @@ extern int otg_set_transceiver(struct otg_transceiver *);
|
|||||||
extern struct otg_transceiver *otg_get_transceiver(void);
|
extern struct otg_transceiver *otg_get_transceiver(void);
|
||||||
extern void otg_put_transceiver(struct otg_transceiver *);
|
extern void otg_put_transceiver(struct otg_transceiver *);
|
||||||
|
|
||||||
|
/* Context: can sleep */
|
||||||
static inline int
|
static inline int
|
||||||
otg_start_hnp(struct otg_transceiver *otg)
|
otg_start_hnp(struct otg_transceiver *otg)
|
||||||
{
|
{
|
||||||
@ -102,6 +103,8 @@ otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
|
|||||||
|
|
||||||
|
|
||||||
/* for usb peripheral controller drivers */
|
/* for usb peripheral controller drivers */
|
||||||
|
|
||||||
|
/* Context: can sleep */
|
||||||
static inline int
|
static inline int
|
||||||
otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph)
|
otg_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *periph)
|
||||||
{
|
{
|
||||||
@ -114,6 +117,7 @@ otg_set_power(struct otg_transceiver *otg, unsigned mA)
|
|||||||
return otg->set_power(otg, mA);
|
return otg->set_power(otg, mA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Context: can sleep */
|
||||||
static inline int
|
static inline int
|
||||||
otg_set_suspend(struct otg_transceiver *otg, int suspend)
|
otg_set_suspend(struct otg_transceiver *otg, int suspend)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user