diff options
Diffstat (limited to 'drivers/usb/gadget/s3c_udc_otg.c')
-rw-r--r-- | drivers/usb/gadget/s3c_udc_otg.c | 66 |
1 files changed, 63 insertions, 3 deletions
diff --git a/drivers/usb/gadget/s3c_udc_otg.c b/drivers/usb/gadget/s3c_udc_otg.c index 6703973..a4f33cd 100644 --- a/drivers/usb/gadget/s3c_udc_otg.c +++ b/drivers/usb/gadget/s3c_udc_otg.c @@ -218,6 +218,21 @@ udc_proc_read(char *page, char **start, off_t off, int count, #include "s3c_udc_otg_xfer_dma.c" /* +* udc_core_disconnect +* Ask On Connection - Vzw requirement +*/ +static void udc_core_disconect(struct s3c_udc *dev) +{ + u32 uTemp; + + printk(KERN_DEBUG "usb: %s -dev->softconnect=%d\n", + __func__, dev->softconnect); + uTemp = __raw_readl(dev->regs + S3C_UDC_OTG_DCTL); + uTemp |= SOFT_DISCONNECT; + __raw_writel(uTemp, dev->regs + S3C_UDC_OTG_DCTL); +} + +/* * udc_disable - disable USB device controller */ static void udc_disable(struct s3c_udc *dev) @@ -307,6 +322,18 @@ int s3c_vbus_enable(struct usb_gadget *gadget, int is_active) { unsigned long flags; struct s3c_udc *dev = container_of(gadget, struct s3c_udc, gadget); + mutex_lock(&dev->mutex); + + if (dev->is_usb_ready) { + printk(KERN_DEBUG "usb: %s, ready u_e: %d, is_active: %d\n", + __func__, dev->udc_enabled, is_active); + } else { /* USB is not ready to enable USB PHY */ + printk(KERN_DEBUG "usb: %s, not ready u_e: %d, is_active: %d\n", + __func__, dev->udc_enabled, is_active); + dev->udc_enabled = is_active; + mutex_unlock(&dev->mutex); + return 0; + } if (dev->udc_enabled != is_active) { dev->udc_enabled = is_active; @@ -324,11 +351,14 @@ int s3c_vbus_enable(struct usb_gadget *gadget, int is_active) wake_lock_timeout(&dev->usbd_wake_lock, HZ * 5); wake_lock_timeout(&dev->usb_cb_wake_lock, HZ * 5); } else { - printk(KERN_DEBUG "usb: %s is_active=%d(udc_enable)\n", - __func__, is_active); + printk(KERN_DEBUG "usb: %s is_active=%d(udc_enable)," + "softconnect=%d\n", + __func__, is_active, dev->softconnect); wake_lock(&dev->usb_cb_wake_lock); udc_reinit(dev); udc_enable(dev); + if (!dev->softconnect) + udc_core_disconect(dev); } } else { printk(KERN_DEBUG "usb: %s, udc_enabled : %d, is_active : %d\n", @@ -336,7 +366,7 @@ int s3c_vbus_enable(struct usb_gadget *gadget, int is_active) } - + mutex_unlock(&dev->mutex); return 0; } @@ -894,6 +924,9 @@ static void s3c_udc_soft_disconnect(void) static int s3c_udc_pullup(struct usb_gadget *gadget, int is_on) { + struct s3c_udc *dev = container_of(gadget, struct s3c_udc, gadget); + dev->softconnect = is_on; + if (is_on) s3c_udc_soft_connect(); else @@ -1157,6 +1190,27 @@ static struct s3c_udc memory = { }, }; +static void usb_ready(struct work_struct *work) +{ + struct s3c_udc *dev = + container_of(work, struct s3c_udc, usb_ready_work.work); + + if (!dev) { + printk(KERN_DEBUG "usb: %s dev is NULL\n", __func__); + return ; + } + + printk(KERN_DEBUG "usb: %s udc_enable=%d\n", + __func__, dev->udc_enabled); + + dev->is_usb_ready = true; + + if (dev->udc_enabled) { + dev->udc_enabled = 0; + s3c_vbus_enable(&dev->gadget, 1); + } +} + /* * probe - binds to the platform device */ @@ -1262,6 +1316,10 @@ static int s3c_udc_probe(struct platform_device *pdev) create_proc_files(); + INIT_DELAYED_WORK(&dev->usb_ready_work, usb_ready); + schedule_delayed_work(&dev->usb_ready_work, msecs_to_jiffies(15000)); + mutex_init(&dev->mutex); + return retval; err_clk: clk_put(dev->clk); @@ -1298,6 +1356,8 @@ static int s3c_udc_remove(struct platform_device *pdev) the_controller = 0; wake_lock_destroy(&dev->usbd_wake_lock); wake_lock_destroy(&dev->usb_cb_wake_lock); + cancel_delayed_work(&dev->usb_ready_work); + mutex_destroy(&dev->mutex); return 0; } |