(attached)
commit f68adda658590c264b6cb72ca1059a92d796fa58
Author: Mike Westerhof <[email protected]>
Date:   Wed May 13 20:11:06 2009 -0500

    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 <[email protected]>

diff --git a/arch/arm/plat-s3c24xx/include/plat/udc.h 
b/arch/arm/plat-s3c24xx/include/plat/udc.h
index 546bb40..763aeba 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 891bab7..c8dca97 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);

Reply via email to