aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Westerhof <mwester@dls.net>2009-05-13 20:11:06 -0500
committerNelson Castillo <arhuaco@freaks-unidos.net>2009-05-15 00:12:31 -0500
commit37d2b0bea0314d0947af19152898c1ca7fe736cc (patch)
tree33e33514913ef7d7460f2d377f4c33566ec841a3
parentaded5330d196644b0f16423dfde9bb2344d991d5 (diff)
This patch adds the option to poll vbus status to the s3c24xx udc driver.
Machines that do not route the USB vbus signal to a GPIO can use this mechanism as an alternate way for the udc driver to detect the usb connect/disconnect state, which is useful (for example) to enable the link up/down state to be determined for the g_ether gadget. Signed-off-by: Mike Westerhof <mwester@dls.net>
-rw-r--r--arch/arm/plat-s3c24xx/include/plat/udc.h1
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c27
2 files changed, 28 insertions, 0 deletions
diff --git a/arch/arm/plat-s3c24xx/include/plat/udc.h b/arch/arm/plat-s3c24xx/include/plat/udc.h
index 546bb4008f4..763aeba628e 100644
--- a/arch/arm/plat-s3c24xx/include/plat/udc.h
+++ b/arch/arm/plat-s3c24xx/include/plat/udc.h
@@ -27,6 +27,7 @@ enum s3c2410_udc_cmd_e {
struct s3c2410_udc_mach_info {
void (*udc_command)(enum s3c2410_udc_cmd_e);
void (*vbus_draw)(unsigned int ma);
+ int (*get_vbus_status)(void);
unsigned int vbus_pin;
unsigned char vbus_pin_inverted;
};
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 891bab74b8c..c8dca979b04 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -74,6 +74,7 @@ static void __iomem *base_addr;
static u64 rsrc_start;
static u64 rsrc_len;
static struct dentry *s3c2410_udc_debugfs_root;
+static struct timer_list vbus_poll_timer;
static inline u32 udc_read(u32 reg)
{
@@ -1526,6 +1527,20 @@ static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
return IRQ_HANDLED;
}
+static void s3c2410_udc_vbus_poll(unsigned long _data)
+{
+ struct s3c2410_udc *data = (struct s3c2410_udc *)_data;
+ int v;
+
+ dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+ if (udc_info && udc_info->get_vbus_status) {
+ v = udc_info->get_vbus_status();
+ if ((v > -1) && (v != data->vbus))
+ s3c2410_udc_vbus_session(&data->gadget, v);
+ mod_timer(&vbus_poll_timer, jiffies + msecs_to_jiffies(900));
+ }
+}
+
static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
{
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
@@ -1683,6 +1698,11 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
goto register_error;
}
+ if (udc_info && udc_info->get_vbus_status && !udc_info->vbus_pin) {
+ mod_timer(&vbus_poll_timer, jiffies + msecs_to_jiffies(50));
+ return 0; /* just return, vbus change will enable udc */
+ }
+
/* Enable udc */
s3c2410_udc_enable(udc);
@@ -1900,6 +1920,11 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
}
dev_dbg(dev, "got irq %i\n", irq);
+ } else if (udc_info && udc_info->get_vbus_status) {
+ udc->vbus = 0;
+ init_timer(&vbus_poll_timer);
+ vbus_poll_timer.function = s3c2410_udc_vbus_poll;
+ vbus_poll_timer.data = (unsigned long) udc;
} else {
udc->vbus = 1;
}
@@ -1948,6 +1973,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
if (udc_info && udc_info->vbus_pin > 0) {
irq = gpio_to_irq(udc_info->vbus_pin);
free_irq(irq, udc);
+ } else if (udc_info && udc_info->get_vbus_status) {
+ del_timer_sync(&vbus_poll_timer);
}
free_irq(IRQ_USBD, udc);