diff options
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 9 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/amd5536udc.c | 49 | ||||
-rw-r--r-- | drivers/usb/gadget/arcotg_udc.c | 451 | ||||
-rw-r--r-- | drivers/usb/gadget/arcotg_udc.h | 11 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 39 | ||||
-rw-r--r-- | drivers/usb/gadget/f_acm.c | 9 | ||||
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 9 |
8 files changed, 190 insertions, 389 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index c29ebda61b2f..a19d73730470 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -791,15 +791,6 @@ config USB_G_PRINTER For more information, see Documentation/usb/gadget_printer.txt which includes sample code for accessing the device file. -config USB_ANDROID - tristate "Android Gadget" - depends on SWITCH - help - The Android gadget provides mass storage and adb transport. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_android". - config USB_CDC_COMPOSITE tristate "CDC Composite Device (Ethernet and ACM)" depends on NET diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 545c0e256e28..477114e43372 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -41,7 +41,6 @@ gadgetfs-objs := inode.o g_file_storage-objs := file_storage.o g_printer-objs := printer.o g_cdc-objs := cdc2.o -g_android-objs := android.o f_adb.o f_mass_storage.o obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_AUDIO) += g_audio.o @@ -52,5 +51,4 @@ obj-$(CONFIG_USB_G_SERIAL) += g_serial.o obj-$(CONFIG_USB_G_PRINTER) += g_printer.o obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o -obj-$(CONFIG_USB_ANDROID) += g_android.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 77352ccc245e..fb0976643a2f 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -1213,7 +1213,12 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) tmp &= AMD_UNMASK_BIT(ep->num); writel(tmp, &dev->regs->ep_irqmsk); } - } + } else if (ep->in) { + /* enable ep irq */ + tmp = readl(&dev->regs->ep_irqmsk); + tmp &= AMD_UNMASK_BIT(ep->num); + writel(tmp, &dev->regs->ep_irqmsk); + } } else if (ep->dma) { @@ -2005,18 +2010,17 @@ __acquires(dev->lock) { int tmp; - /* empty queues and init hardware */ - udc_basic_init(dev); - for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { - empty_req_queue(&dev->ep[tmp]); - } - if (dev->gadget.speed != USB_SPEED_UNKNOWN) { spin_unlock(&dev->lock); driver->disconnect(&dev->gadget); spin_lock(&dev->lock); } - /* init */ + + /* empty queues and init hardware */ + udc_basic_init(dev); + for (tmp = 0; tmp < UDC_EP_NUM; tmp++) + empty_req_queue(&dev->ep[tmp]); + udc_setup_endpoints(dev); } @@ -2478,6 +2482,13 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix) } } + } else if (!use_dma && ep->in) { + /* disable interrupt */ + tmp = readl( + &dev->regs->ep_irqmsk); + tmp |= AMD_BIT(ep->num); + writel(tmp, + &dev->regs->ep_irqmsk); } } /* clear status bits */ @@ -3285,6 +3296,17 @@ static int udc_pci_probe( goto finished; } + spin_lock_init(&dev->lock); + /* udc csr registers base */ + dev->csr = dev->virt_addr + UDC_CSR_ADDR; + /* dev registers base */ + dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR; + /* ep registers base */ + dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR; + /* fifo's base */ + dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR); + dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); + if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq); kfree(dev); @@ -3337,7 +3359,6 @@ static int udc_probe(struct udc *dev) udc_pollstall_timer.data = 0; /* device struct setup */ - spin_lock_init(&dev->lock); dev->gadget.ops = &udc_ops; dev_set_name(&dev->gadget.dev, "gadget"); @@ -3346,16 +3367,6 @@ static int udc_probe(struct udc *dev) dev->gadget.name = name; dev->gadget.is_dualspeed = 1; - /* udc csr registers base */ - dev->csr = dev->virt_addr + UDC_CSR_ADDR; - /* dev registers base */ - dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR; - /* ep registers base */ - dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR; - /* fifo's base */ - dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR); - dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); - /* init registers, interrupts, ... */ startup_registers(dev); diff --git a/drivers/usb/gadget/arcotg_udc.c b/drivers/usb/gadget/arcotg_udc.c index 8e94549f891e..abba4d2ae8d4 100644 --- a/drivers/usb/gadget/arcotg_udc.c +++ b/drivers/usb/gadget/arcotg_udc.c @@ -106,6 +106,19 @@ extern struct resource *otg_get_resources(void); extern void fsl_platform_set_test_mode(struct fsl_usb2_platform_data *pdata, enum usb_test_mode mode); +static inline void +dr_wake_up_enable(struct fsl_udc *udc, bool enable) +{ + struct fsl_usb2_platform_data *pdata; + pdata = udc->pdata; + + if (enable && (!device_may_wakeup(udc_controller->gadget.dev.parent))) + return; + + if (pdata->wake_up_enable) + pdata->wake_up_enable(pdata, enable); +} + #ifdef CONFIG_WORKAROUND_ARCUSB_REG_RW static void safe_writel(u32 val32, void *addr) { @@ -270,12 +283,9 @@ static void done(struct fsl_ep *ep, struct fsl_req *req, int status) static void nuke(struct fsl_ep *ep, int status) { ep->stopped = 1; - /* - * At udc stop mode, the clock is already off - * So flush fifo, should be done at clock on mode. - */ - if (!ep->udc->stopped) - fsl_ep_fifo_flush(&ep->ep); + + /* Flush fifo */ + fsl_ep_fifo_flush(&ep->ep); /* Whether this eq has request linked */ while (!list_empty(&ep->queue)) { @@ -290,83 +300,31 @@ static void nuke(struct fsl_ep *ep, int status) /*------------------------------------------------------------------ Internal Hardware related function ------------------------------------------------------------------*/ -static inline void -dr_wake_up_enable(struct fsl_udc *udc, bool enable) -{ - struct fsl_usb2_platform_data *pdata; - pdata = udc->pdata; - if (pdata && pdata->wake_up_enable) - pdata->wake_up_enable(pdata, enable); -} -static bool clk_stoped = false; -static inline void dr_clk_gate(bool on) +static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable) { - struct fsl_usb2_platform_data *pdata = udc_controller->pdata; + u32 temp; - if (!pdata || !pdata->usb_clock_for_pm) + if (!device_may_wakeup(udc_controller->gadget.dev.parent)) return; - if (on && clk_stoped) { - pdata->usb_clock_for_pm(true); - clk_stoped = false; - } - if (!on && !clk_stoped) { - pdata->usb_clock_for_pm(false); - clk_stoped = true; - } - if (on) - reset_phy(); -} -static void dr_phy_low_power_mode(struct fsl_udc *udc, bool enable) -{ - struct fsl_usb2_platform_data *pdata = udc->pdata; - u32 portsc; + if (enable) { + temp = fsl_readl(&dr_regs->portsc1); + temp |= PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(temp, &dr_regs->portsc1); - if (pdata && pdata->phy_lowpower_suspend) { - pdata->phy_lowpower_suspend(enable); + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(false); } else { - if (enable){ - portsc = fsl_readl(&dr_regs->portsc1); - portsc |= PORTSCX_PHY_LOW_POWER_SPD; - fsl_writel(portsc, &dr_regs->portsc1); - } else { - portsc = fsl_readl(&dr_regs->portsc1); - portsc &= ~PORTSCX_PHY_LOW_POWER_SPD; - fsl_writel(portsc, &dr_regs->portsc1); - } - } -} - - -/* workaroud for some boards, maybe there is a large capacitor between the ground and the Vbus - * that will cause the vbus dropping very slowly when device is detached, - * may cost 2-3 seconds to below 0.8V */ -static void udc_wait_b_session_low(void) -{ - u32 temp; - u32 wait = 5000; /* max wait time is 5000 ms */ - /* if we are in host mode, don't need to care the B session */ - if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) - return; - /* if the udc is dettached , there will be a suspend irq */ - if (udc_controller->usb_state != USB_STATE_SUSPENDED) - return; - temp = fsl_readl(&dr_regs->otgsc); - temp &= ~(OTGSC_B_SESSION_VALID_IRQ_EN ); - fsl_writel(temp, &dr_regs->otgsc); + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(true); - do { - if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID)) - break; - mdelay(1); - wait -= 1; - } while(wait); - if (!wait) - printk("ERROR!!!!!: the vbus can not be lower then 0.8V for 5 seconds, Pls Check your HW design\n"); - temp = fsl_readl(&dr_regs->otgsc); - temp |= (OTGSC_B_SESSION_VALID_IRQ_EN ); - fsl_writel(temp, &dr_regs->otgsc); + /* Due to mx35/mx25's phy's bug */ + reset_phy(); + temp = fsl_readl(&dr_regs->portsc1); + temp &= ~PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(temp, &dr_regs->portsc1); + } } static int dr_controller_setup(struct fsl_udc *udc) @@ -490,20 +448,23 @@ static void dr_controller_run(struct fsl_udc *udc) fsl_writel(temp, &dr_regs->usbintr); - /* enable BSV irq */ - temp = fsl_readl(&dr_regs->otgsc); - temp |= OTGSC_B_SESSION_VALID_IRQ_EN; - fsl_writel(temp, &dr_regs->otgsc); + if (device_may_wakeup(udc_controller->gadget.dev.parent)) { + /* enable BSV irq */ + temp = fsl_readl(&dr_regs->otgsc); + temp |= OTGSC_B_SESSION_VALID_IRQ_EN; + fsl_writel(temp, &dr_regs->otgsc); + } /* If vbus not on and used low power mode */ - if (!(temp & OTGSC_B_SESSION_VALID)) { - /* Set stopped before low power mode */ - udc->stopped = 1; + if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_B_SESSION_VALID) + && device_may_wakeup(udc_controller->gadget.dev.parent)) { /* enable wake up */ dr_wake_up_enable(udc, true); - /* enter lower power mode */ + /* Set stopped before low power mode */ + udc->stopped = 1; + /* close PHY clock */ dr_phy_low_power_mode(udc, true); - printk(KERN_INFO "%s: udc enter low power mode \n", __func__); + printk(KERN_INFO "udc enter low power mode \n"); } else { #ifdef CONFIG_ARCH_MX37 /* @@ -515,11 +476,11 @@ static void dr_controller_run(struct fsl_udc *udc) #endif /* Clear stopped bit */ udc->stopped = 0; - - /* The usb line has already been connected to pc */ + /* Set controller to Run */ temp = fsl_readl(&dr_regs->usbcmd); temp |= USB_CMD_RUN_STOP; fsl_writel(temp, &dr_regs->usbcmd); + printk(KERN_INFO "udc run \n"); } return; @@ -2015,36 +1976,15 @@ static void suspend_irq(struct fsl_udc *udc) udc->driver->suspend(&udc->gadget); } -/* Process Wake up interrupt - * Be careful that some boards will use ID pin to control the VBUS on/off - * in these case, after the device enter the lowpower mode(clk off, - * phy lowpower mode, wakeup enable), then an udisk is attaced to the otg port, - * there will be an Vbus wakeup event and then an ID change wakeup, But the Vbus - * event is not expected, so there is an workaround that will detect the ID, if ID=0 - * we just need the ID event so we can not disable the wakeup - * - * false: host wakeup event - * true: device wakeup event -*/ -static bool wake_up_irq(struct fsl_udc *udc) -{ - /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will - * be delayed max 2 ms to show the real ID pin value - */ - mdelay(3); - - /* if the ID=0, let arc host process the wakeup */ - if (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) { - dr_wake_up_enable(udc_controller, false); - dr_phy_low_power_mode(udc, false); - printk("device wake up event\n"); - return true; - }else {/* wakeup is vbus wake event, but not for device so we need to clear b session */ - int irq_src = fsl_readl(&dr_regs->otgsc) & (~OTGSC_ID_CHANGE_IRQ_STS); - fsl_writel(irq_src, &dr_regs->otgsc); - printk("The host wakeup event, should be handled by host\n"); - return false; - } +/* Process Wake up interrupt */ +static void wake_up_irq(struct fsl_udc *udc) +{ + pr_debug("%s\n", __func__); + + /* disable wake up irq */ + dr_wake_up_enable(udc_controller, false); + + udc->stopped = 0; } static void bus_resume(struct fsl_udc *udc) @@ -2113,48 +2053,43 @@ static void reset_irq(struct fsl_udc *udc) bool try_wake_up_udc(struct fsl_udc *udc) { u32 irq_src; - bool b_device; /* when udc is stopped, only handle wake up irq */ if (udc->stopped) { + if (!device_may_wakeup(&(udc->pdata->pdev->dev))) + return false; + + dr_phy_low_power_mode(udc_controller, false); + /* check to see if wake up irq */ irq_src = fsl_readl(&dr_regs->usbctrl); if (irq_src & USB_CTRL_OTG_WUIR) { - if (wake_up_irq(udc) == false){ - return false; /* host wakeup event */ - } + wake_up_irq(udc); + } else { + dr_phy_low_power_mode(udc_controller, true); } } + if (!device_may_wakeup(udc_controller->gadget.dev.parent)) + return true; + /* check if Vbus change irq */ irq_src = fsl_readl(&dr_regs->otgsc); if (irq_src & OTGSC_B_SESSION_VALID_IRQ_STS) { u32 tmp; - /* Because the IC design needs to remove the glitch on ID so the otgsc bit 8 will - * be delayed max 2 ms to show the real ID pin value, as it needs to use ID to judge - * host or device - */ - mdelay(3); - b_device = (irq_src & OTGSC_STS_USB_ID)? true:false; fsl_writel(irq_src, &dr_regs->otgsc); - if (!b_device) - return false; tmp = fsl_readl(&dr_regs->usbcmd); /* check BSV bit to see if fall or rise */ if (irq_src & OTGSC_B_SESSION_VALID) { - if (udc->suspended) /*let the system pm resume the udc */ - return true; udc->stopped = 0; fsl_writel(tmp | USB_CMD_RUN_STOP, &dr_regs->usbcmd); - printk(KERN_INFO "%s: udc out low power mode\n", __func__); + printk(KERN_INFO "udc out low power mode\n"); } else { - printk(KERN_INFO "%s: udc enter low power mode \n", __func__); - if (udc->driver) - udc->driver->disconnect(&udc->gadget); + printk(KERN_INFO "udc enter low power mode \n"); fsl_writel(tmp & ~USB_CMD_RUN_STOP, &dr_regs->usbcmd); - udc->stopped = 1; /* enable wake up */ dr_wake_up_enable(udc, true); + udc->stopped = 1; /* close USB PHY clock */ dr_phy_low_power_mode(udc, true); return false; @@ -2163,6 +2098,7 @@ bool try_wake_up_udc(struct fsl_udc *udc) return true; } + /* * USB device controller interrupt handler */ @@ -2173,29 +2109,15 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) irqreturn_t status = IRQ_NONE; unsigned long flags; - spin_lock_irqsave(&udc->lock, flags); - if (udc->stopped) - dr_clk_gate(true); - - if (try_wake_up_udc(udc) == false) { - goto irq_end; - } -#ifdef CONFIG_USB_OTG - /* if no gadget register in this driver, we need do noting */ - if (udc->transceiver->gadget == NULL) - goto irq_end; - - /* only handle device interrupt event */ - if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { - goto irq_end; - } -#endif + if (try_wake_up_udc(udc) == false) + return IRQ_NONE; + spin_lock_irqsave(&udc->lock, flags); irq_src = fsl_readl(&dr_regs->usbsts) & fsl_readl(&dr_regs->usbintr); /* Clear notification bits */ fsl_writel(irq_src, &dr_regs->usbsts); - VDBG("0x%x\n", irq_src); + /* VDBG("irq_src [0x%8x]", irq_src); */ /* Need to resume? */ if (udc->usb_state == USB_STATE_SUSPENDED) @@ -2240,24 +2162,12 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) /* Sleep Enable (Suspend) */ if (irq_src & USB_STS_SUSPEND) { - VDBG("suspend int"); suspend_irq(udc); status = IRQ_HANDLED; } if (irq_src & (USB_STS_ERR | USB_STS_SYS_ERR)) { - printk(KERN_ERR "Error IRQ %x ", irq_src); - if (irq_src & USB_STS_SYS_ERR) { - printk(KERN_ERR "This error can't be recoveried, \ - please reboot your board\n"); - printk(KERN_ERR "If this error happens frequently, \ - please check your dma buffer\n"); - } - } - -irq_end: - if (udc->stopped){ - dr_clk_gate(false); + VDBG("Error IRQ %x ", irq_src); } spin_unlock_irqrestore(&udc->lock, flags); @@ -2272,6 +2182,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) { int retval = -ENODEV; unsigned long flags = 0; + u32 portsc; if (!udc_controller) return -ENODEV; @@ -2289,18 +2200,17 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) spin_lock_irqsave(&udc_controller->lock, flags); driver->driver.bus = 0; - udc_controller->pdata->port_enables = 1; /* hook up the driver */ udc_controller->driver = driver; udc_controller->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc_controller->lock, flags); - dr_clk_gate(true); - /* It doesn't need to switch usb from low power mode to normal mode - * at otg mode - */ - if (!udc_controller->transceiver){ - dr_phy_low_power_mode(udc_controller, false); - } + + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(true); + + portsc = fsl_readl(&dr_regs->portsc1); + portsc &= ~PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(portsc, &dr_regs->portsc1); /* bind udc driver to gadget driver */ retval = driver->bind(&udc_controller->gadget); @@ -2313,30 +2223,30 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) if (udc_controller->transceiver) { /* Suspend the controller until OTG enable it */ - udc_controller->suspended = 1;/* let the otg resume it */ + udc_controller->stopped = 1; printk(KERN_INFO "Suspend udc for OTG auto detect\n"); dr_wake_up_enable(udc_controller, true); + dr_phy_low_power_mode(udc_controller, true); /* export udc suspend/resume call to OTG */ udc_controller->gadget.dev.driver->suspend = (dev_sus)fsl_udc_suspend; udc_controller->gadget.dev.driver->resume = (dev_res)fsl_udc_resume; /* connect to bus through transceiver */ - retval = otg_set_peripheral(udc_controller->transceiver, - &udc_controller->gadget); - if (retval < 0) { - ERR("can't bind to transceiver\n"); - driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = 0; - udc_controller->driver = 0; - return retval; + if (udc_controller->transceiver) { + retval = otg_set_peripheral(udc_controller->transceiver, + &udc_controller->gadget); + if (retval < 0) { + ERR("can't bind to transceiver\n"); + driver->unbind(&udc_controller->gadget); + udc_controller->gadget.dev.driver = 0; + udc_controller->driver = 0; + return retval; + } } - //dr_clk_gate(false); } else { /* Enable DR IRQ reg and Set usbcmd reg Run bit */ dr_controller_run(udc_controller); - if (udc_controller->stopped) - dr_clk_gate(false); udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; } @@ -2344,10 +2254,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) udc_controller->gadget.name, driver->driver.name); out: - if (retval){ + if (retval) printk(KERN_DEBUG "retval %d \n", retval); - udc_controller->pdata->port_enables = 0; - } return retval; } EXPORT_SYMBOL(usb_gadget_register_driver); @@ -2357,6 +2265,7 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { struct fsl_ep *loop_ep; unsigned long flags; + u32 portsc; if (!udc_controller) return -ENODEV; @@ -2364,16 +2273,15 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) if (!driver || driver != udc_controller->driver || !driver->unbind) return -EINVAL; - if(udc_controller->stopped) - dr_clk_gate(true); - if (udc_controller->transceiver) (void)otg_set_peripheral(udc_controller->transceiver, 0); + /* open phy clock for following operation */ + dr_phy_low_power_mode(udc_controller, false); + /* stop DR, disable intr */ dr_controller_stop(udc_controller); - udc_controller->pdata->port_enables = 0; /* in fact, no needed */ udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; @@ -2395,11 +2303,14 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) udc_controller->gadget.dev.driver = 0; udc_controller->driver = 0; - if (udc_controller->gadget.is_otg) { - dr_wake_up_enable(udc_controller, true); - } + dr_wake_up_enable(udc_controller, false); - dr_phy_low_power_mode(udc_controller, true); + portsc = fsl_readl(&dr_regs->portsc1); + portsc |= PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(portsc, &dr_regs->portsc1); + + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(false); printk(KERN_INFO "unregistered gadget driver '%s'\r\n", driver->driver.name); @@ -2814,7 +2725,6 @@ static int __init fsl_udc_probe(struct platform_device *pdev) ret = -ENODEV; goto err1a; } - udc_controller->gadget.is_otg = 1; #endif if ((pdev->dev.parent) && @@ -2915,6 +2825,12 @@ static int __init fsl_udc_probe(struct platform_device *pdev) if (ret < 0) goto err3; + if (udc_controller->transceiver) { + udc_controller->gadget.is_otg = 1; + /* now didn't support lpm in OTG mode*/ + device_set_wakeup_capable(&pdev->dev, 0); + } + /* setup QH and epctrl for ep0 */ ep0_setup(udc_controller); @@ -2957,29 +2873,24 @@ static int __init fsl_udc_probe(struct platform_device *pdev) #ifdef POSTPONE_FREE_LAST_DTD last_free_td = NULL; #endif - #ifndef CONFIG_USB_OTG /* disable all INTR */ fsl_writel(0, &dr_regs->usbintr); + dr_wake_up_enable(udc_controller, false); -#else - dr_wake_up_enable(udc_controller, true); -#endif + udc_controller->stopped = 1; -/* - * As mx25/mx35 does not implement clk_gate, should not let phy to low - * power mode due to IC bug - */ #if !(defined CONFIG_ARCH_MX35 || defined CONFIG_ARCH_MX25) { - dr_phy_low_power_mode(udc_controller, true); + u32 portsc; + portsc = fsl_readl(&dr_regs->portsc1); + portsc |= PORTSCX_PHY_LOW_POWER_SPD; + fsl_writel(portsc, &dr_regs->portsc1); } #endif - udc_controller->stopped = 1; - - /* let the gadget register function open the clk */ - dr_clk_gate(false); - + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(false); +#endif create_proc_file(); return 0; @@ -3006,6 +2917,9 @@ err1a: */ static int __exit fsl_udc_remove(struct platform_device *pdev) { +#ifndef CONFIG_USB_OTG + struct resource *res; +#endif struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; DECLARE_COMPLETION(done); @@ -3014,8 +2928,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) return -ENODEV; udc_controller->done = &done; /* open USB PHY clock */ - if (udc_controller->stopped) - dr_clk_gate(true); + dr_phy_low_power_mode(udc_controller, false); /* DR has been stopped in usb_gadget_unregister_driver() */ remove_proc_file(); @@ -3038,11 +2951,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) iounmap((u8 __iomem *)dr_regs); #ifndef CONFIG_USB_OTG -{ - struct resource *res; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, resource_size(res)); -} #endif device_unregister(&udc_controller->gadget.dev); @@ -3056,8 +2966,6 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) if (pdata->platform_uninit) pdata->platform_uninit(pdata); - if (udc_controller->stopped) - dr_clk_gate(false); return 0; } @@ -3065,19 +2973,10 @@ static int udc_suspend(struct fsl_udc *udc) { u32 mode, usbcmd; - /* - * When it is the PM suspend routine and the device has no - * abilities to wakeup system, it should not set wakeup enable. - * Otherwise, the system will wakeup even the user only wants to - * charge using usb - */ - if (udc_controller->gadget.dev.parent->power.status - == DPM_SUSPENDING) { - if (!device_may_wakeup(udc_controller->gadget.dev.parent)) - dr_wake_up_enable(udc, false); - else - dr_wake_up_enable(udc, true); - } + /* open clock for register access */ + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(true); + mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK; usbcmd = fsl_readl(&dr_regs->usbcmd); @@ -3088,8 +2987,9 @@ static int udc_suspend(struct fsl_udc *udc) * PM suspend. Remember this fact, so that we will leave the * controller stopped at PM resume time. */ - if (udc->suspended) { + if (udc->stopped) { pr_debug("gadget already stopped, leaving early\n"); + udc->already_stopped = 1; goto out; } @@ -3098,30 +2998,22 @@ static int udc_suspend(struct fsl_udc *udc) goto out; } - /* For some buggy hardware designs, see comment of this function for detail */ - udc_wait_b_session_low(); - udc->stopped = 1; - - /* stop the controller */ - usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; - fsl_writel(usbcmd, &dr_regs->usbcmd); - /* if the suspend is not for switch to host in otg mode */ if ((!(udc->gadget.is_otg)) || (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { - if (device_may_wakeup(udc_controller->gadget.dev.parent)) { - dr_wake_up_enable(udc, true); - } + dr_wake_up_enable(udc, true); + dr_phy_low_power_mode(udc, true); } - dr_phy_low_power_mode(udc, true); + /* stop the controller */ + usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; + fsl_writel(usbcmd, &dr_regs->usbcmd); + printk(KERN_INFO "USB Gadget suspended\n"); out: - udc->suspended++; - if (udc->suspended > 2) - printk("ERROR: suspended times > 2\n"); - + if (udc_controller->pdata->usb_clock_for_pm) + udc_controller->pdata->usb_clock_for_pm(false); return 0; } @@ -3131,24 +3023,13 @@ out: -----------------------------------------------------------------*/ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) { - int ret; -#ifdef CONFIG_USB_OTG - if (udc_controller->transceiver->gadget == NULL) - return 0; -#endif - if (udc_controller->stopped) - dr_clk_gate(true); if (((!(udc_controller->gadget.is_otg)) || (fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) && (udc_controller->usb_state > USB_STATE_POWERED) && - (udc_controller->usb_state < USB_STATE_SUSPENDED)) { - return -EBUSY;/* keep the clk on */ - } - else - ret = udc_suspend(udc_controller); - dr_clk_gate(false); + (udc_controller->usb_state < USB_STATE_SUSPENDED)) + return -EBUSY; - return ret; + return udc_suspend(udc_controller); } /*----------------------------------------------------------------- @@ -3157,54 +3038,30 @@ static int fsl_udc_suspend(struct platform_device *pdev, pm_message_t state) *-----------------------------------------------------------------*/ static int fsl_udc_resume(struct platform_device *pdev) { - pr_debug("%s(): stopped %d suspended %d\n", __func__, - udc_controller->stopped, udc_controller->suspended); - printk("udc resume\n"); -#ifdef CONFIG_USB_OTG - if (udc_controller->transceiver->gadget == NULL) - return 0; -#endif - if (udc_controller->stopped) - dr_clk_gate(true); + pr_debug("%s(): stopped %d already_stopped %d\n", __func__, + udc_controller->stopped, udc_controller->already_stopped); + /* * If the controller was stopped at suspend time, then * don't resume it now. */ - /* - * If it is PM resume routine, the udc is at low power mode, - * and the udc has no abilities to wakeup system, it should - * set the abilities to wakeup itself. Otherwise, the usb - * subsystem will not leave from low power mode. - */ - if (!device_may_wakeup(udc_controller->gadget.dev.parent) && - udc_controller->gadget.dev.parent->power.status - == DPM_RESUMING){ - dr_wake_up_enable(udc_controller, true); - } - - if (--udc_controller->suspended) { - printk("gadget was already stopped, leaving early\n"); - goto out; + if (udc_controller->already_stopped) { + udc_controller->already_stopped = 0; + pr_debug("gadget was already stopped, leaving early\n"); + return 0; } + /* Enable DR irq reg and set controller Run */ if (udc_controller->stopped) { - /* if in host mode, we need to do nothing */ - if ((fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID) == 0) { - goto out; - } dr_wake_up_enable(udc_controller, false); dr_phy_low_power_mode(udc_controller, false); - mdelay(10); + mdelay(1); + dr_controller_setup(udc_controller); dr_controller_run(udc_controller); } udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_dir = 0; -out: - /* if udc is resume by otg id change and no device - * connecting to the otg, otg will enter low power mode*/ - if (udc_controller->stopped) - dr_clk_gate(false); printk(KERN_INFO "USB Gadget resumed\n"); return 0; diff --git a/drivers/usb/gadget/arcotg_udc.h b/drivers/usb/gadget/arcotg_udc.h index 8d344acb8fef..4574954bf4f4 100644 --- a/drivers/usb/gadget/arcotg_udc.h +++ b/drivers/usb/gadget/arcotg_udc.h @@ -266,7 +266,6 @@ struct usb_sys_interface { #define PORTSCX_SPEED_BIT_POS (26) /* OTGSC Register Bit Masks */ -#define OTGSC_ID_CHANGE_IRQ_STS (1 << 16) #define OTGSC_B_SESSION_VALID_IRQ_EN (1 << 27) #define OTGSC_B_SESSION_VALID_IRQ_STS (1 << 19) #define OTGSC_B_SESSION_VALID (1 << 11) @@ -594,15 +593,9 @@ struct fsl_udc { struct otg_transceiver *transceiver; unsigned softconnect:1; unsigned vbus_active:1; - unsigned remote_wakeup:1; - /* we must distinguish the stopped and suspended state, - * stopped means the udc enter lowpower mode, suspended - * means the udc is suspended by system pm or by otg - * switching to host mode.if the udc in suspended state - * it also in the stopped state, while if the udc in - * stopped state,it may not be in the suspended state*/ unsigned stopped:1; - int suspended; + unsigned remote_wakeup:1; + unsigned already_stopped:1; struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */ struct fsl_req *status_req; /* ep0 status request */ diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 2e79b8c389a4..59e85234fa0a 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -236,7 +236,6 @@ static int config_buf(struct usb_configuration *config, int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; struct usb_function *f; int status; - int interfaceCount = 0; /* write the config descriptor */ c = buf; @@ -267,16 +266,8 @@ static int config_buf(struct usb_configuration *config, descriptors = f->hs_descriptors; else descriptors = f->descriptors; - if (f->hidden || !descriptors || descriptors[0] == NULL) { - for (; f != config->interface[interfaceCount];) { - interfaceCount++; - c->bNumInterfaces--; - } + if (!descriptors) continue; - } - for (; f != config->interface[interfaceCount];) - interfaceCount++; - status = usb_descriptor_fillbuf(next, len, (const struct usb_descriptor_header **) descriptors); if (status < 0) @@ -765,11 +756,11 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) case USB_REQ_GET_CONFIGURATION: if (ctrl->bRequestType != USB_DIR_IN) goto unknown; - if (cdev->config) { + if (cdev->config) *(u8 *)req->buf = cdev->config->bConfigurationValue; - value = min(w_length, (u16) 1); - } else + else *(u8 *)req->buf = 0; + value = min(w_length, (u16) 1); break; /* function drivers must handle get/set altsetting; if there's @@ -819,9 +810,6 @@ unknown: */ if ((ctrl->bRequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { - if (cdev->config == NULL) - return value; - f = cdev->config->interface[intf]; if (f && f->setup) value = f->setup(f, ctrl); @@ -836,25 +824,6 @@ unknown: value = c->setup(c, ctrl); } - /* If the vendor request is not processed (value < 0), - * call all device registered configure setup callbacks - * to process it. - * This is used to handle the following cases: - * - vendor request is for the device and arrives before - * setconfiguration. - * - Some devices are required to handle vendor request before - * setconfiguration such as MTP, USBNET. - */ - - if (value < 0) { - struct usb_configuration *cfg; - - list_for_each_entry(cfg, &cdev->configs, list) { - if (cfg && cfg->setup) - value = cfg->setup(cfg, ctrl); - } - } - goto done; } diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index 7dd1a8bbe382..7953948bfe4a 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c @@ -761,12 +761,3 @@ int __init acm_bind_config(struct usb_configuration *c, u8 port_num) kfree(acm); return status; } - -int __init acm_function_add(struct usb_composite_dev *cdev, - struct usb_configuration *c) -{ - int ret = acm_bind_config(c, 0); - if (ret == 0) - gserial_setup(c->cdev->gadget, 1); - return ret; -} diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 8b0a13202573..66105ce49672 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -728,7 +728,6 @@ struct fsg_dev { #include "fsl_updater.h" #endif -static int do_set_interface(struct fsg_dev *fsg, int altsetting); typedef void (*fsg_routine_t)(struct fsg_dev *); static int exception_in_progress(struct fsg_dev *fsg) @@ -1109,14 +1108,6 @@ static void fsg_disconnect(struct usb_gadget *gadget) struct fsg_dev *fsg = get_gadget_data(gadget); DBG(fsg, "disconnect or port reset\n"); - /* - * The disconnect exception will call do_set_config, and therefore will - * visit controller registers. However it is a delayed event, and will be - * handled at another process, so the controller maybe have already close the - * usb clock.*/ - if (fsg->new_config) - do_set_interface(fsg, -1);/* disable the interface */ - raise_exception(fsg, FSG_STATE_DISCONNECT); } |