Loading drivers/usb/gadget/fsl_udc_core.c +132 −15 Original line number Diff line number Diff line Loading @@ -353,6 +353,19 @@ static void dr_controller_stop(struct fsl_udc *udc) { unsigned int tmp; pr_debug("%s\n", __func__); /* if we're in OTG mode, and the Host is currently using the port, * stop now and don't rip the controller out from under the * ehci driver */ if (udc->gadget.is_otg) { if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { pr_debug("udc: Leaving early\n"); return; } } /* disable all INTR */ fsl_writel(0, &dr_regs->usbintr); Loading Loading @@ -1668,6 +1681,9 @@ static void port_change_irq(struct fsl_udc *udc) { u32 speed; if (udc->bus_reset) udc->bus_reset = 0; /* Bus resetting is finished */ if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) { /* Get the speed */ Loading Loading @@ -1775,6 +1791,8 @@ static void reset_irq(struct fsl_udc *udc) if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) { VDBG("Bus reset"); /* Bus is reseting */ udc->bus_reset = 1; /* Reset all the queues, include XD, dTD, EP queue * head and TR Queue */ reset_queues(udc); Loading Loading @@ -1852,6 +1870,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) /* Reset Received */ if (irq_src & USB_STS_RESET) { VDBG("reset int"); reset_irq(udc); status = IRQ_HANDLED; } Loading Loading @@ -1909,11 +1928,30 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, goto out; } /* Enable DR IRQ reg and Set usbcmd reg Run bit */ if (udc_controller->transceiver) { /* Suspend the controller until OTG enable it */ udc_controller->stopped = 1; printk(KERN_INFO "Suspend udc for OTG auto detect\n"); /* connect to bus through transceiver */ 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; } } } else { /* Enable DR IRQ reg and set USBCMD reg Run bit */ dr_controller_run(udc_controller); udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_state = WAIT_FOR_SETUP; udc_controller->ep0_dir = 0; } printk(KERN_INFO "%s: bind to driver %s\n", udc_controller->gadget.name, driver->driver.name); Loading Loading @@ -2374,18 +2412,31 @@ static int __init fsl_udc_probe(struct platform_device *pdev) spin_lock_init(&udc_controller->lock); udc_controller->stopped = 1; #ifdef CONFIG_USB_OTG if (pdata->operating_mode == FSL_USB2_DR_OTG) { udc_controller->transceiver = otg_get_transceiver(); if (!udc_controller->transceiver) { ERR("Can't find OTG driver!\n"); ret = -ENODEV; goto err_kfree; } } #endif res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENXIO; goto err_kfree; } if (pdata->operating_mode == FSL_USB2_DR_DEVICE) { if (!request_mem_region(res->start, res->end - res->start + 1, driver_name)) { ERR("request mem region for %s failed\n", pdev->name); ret = -EBUSY; goto err_kfree; } } dr_regs = ioremap(res->start, resource_size(res)); if (!dr_regs) { Loading Loading @@ -2455,9 +2506,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev) goto err_free_irq; } if (!udc_controller->transceiver) { /* initialize usb hw reg except for regs for EP, * leave usbintr reg untouched */ dr_controller_setup(udc_controller); } fsl_udc_clk_finalize(pdev); Loading @@ -2477,6 +2530,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev) if (ret < 0) goto err_free_irq; if (udc_controller->transceiver) udc_controller->gadget.is_otg = 1; /* setup QH and epctrl for ep0 */ ep0_setup(udc_controller); Loading Loading @@ -2521,6 +2577,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) err_iounmap_noclk: iounmap(dr_regs); err_release_mem_region: if (pdata->operating_mode == FSL_USB2_DR_DEVICE) release_mem_region(res->start, res->end - res->start + 1); err_kfree: kfree(udc_controller); Loading Loading @@ -2555,6 +2612,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) dma_pool_destroy(udc_controller->td_pool); free_irq(udc_controller->irq, udc_controller); iounmap(dr_regs); if (pdata->operating_mode == FSL_USB2_DR_DEVICE) release_mem_region(res->start, res->end - res->start + 1); device_unregister(&udc_controller->gadget.dev); Loading Loading @@ -2598,6 +2656,62 @@ static int fsl_udc_resume(struct platform_device *pdev) return 0; } static int fsl_udc_otg_suspend(struct device *dev, pm_message_t state) { struct fsl_udc *udc = udc_controller; u32 mode, usbcmd; mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK; pr_debug("%s(): mode 0x%x stopped %d\n", __func__, mode, udc->stopped); /* * If the controller is already stopped, then this must be a * PM suspend. Remember this fact, so that we will leave the * controller stopped at PM resume time. */ if (udc->stopped) { pr_debug("gadget already stopped, leaving early\n"); udc->already_stopped = 1; return 0; } if (mode != USB_MODE_CTRL_MODE_DEVICE) { pr_debug("gadget not in device mode, leaving early\n"); return 0; } /* stop the controller */ usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; fsl_writel(usbcmd, &dr_regs->usbcmd); udc->stopped = 1; pr_info("USB Gadget suspended\n"); return 0; } static int fsl_udc_otg_resume(struct device *dev) { 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 (udc_controller->already_stopped) { udc_controller->already_stopped = 0; pr_debug("gadget was already stopped, leaving early\n"); return 0; } pr_info("USB Gadget resume\n"); return fsl_udc_resume(NULL); } /*------------------------------------------------------------------------- Register entry point for the peripheral controller driver --------------------------------------------------------------------------*/ Loading @@ -2610,6 +2724,9 @@ static struct platform_driver udc_driver = { .driver = { .name = (char *)driver_name, .owner = THIS_MODULE, /* udc suspend/resume called from OTG driver */ .suspend = fsl_udc_otg_suspend, .resume = fsl_udc_otg_resume, }, }; Loading drivers/usb/gadget/fsl_usb2_udc.h +2 −0 Original line number Diff line number Diff line Loading @@ -476,6 +476,7 @@ struct fsl_udc { unsigned vbus_active:1; unsigned stopped:1; unsigned remote_wakeup:1; unsigned already_stopped:1; unsigned big_endian_desc:1; struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */ Loading @@ -487,6 +488,7 @@ struct fsl_udc { dma_addr_t ep_qh_dma; /* dma address of QH */ u32 max_pipes; /* Device max pipes */ u32 bus_reset; /* Device is bus resetting */ u32 resume_state; /* USB state to resume */ u32 usb_state; /* USB current state */ u32 ep0_state; /* Endpoint zero state */ Loading drivers/usb/host/ehci-fsl.c +66 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,9 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, pdata->regs = hcd->regs; if (pdata->power_budget) hcd->power_budget = pdata->power_budget; /* * do platform specific init: check the clock, grab/config pins, etc. */ Loading @@ -134,6 +137,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) goto err4; #ifdef CONFIG_USB_OTG if (pdata->operating_mode == FSL_USB2_DR_OTG) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); ehci->transceiver = otg_get_transceiver(); dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n", hcd, ehci, ehci->transceiver); if (ehci->transceiver) { retval = otg_set_host(ehci->transceiver, &ehci_to_hcd(ehci)->self); if (retval) { if (ehci->transceiver) put_device(ehci->transceiver->dev); goto err4; } } else { dev_err(&pdev->dev, "can't find transceiver\n"); retval = -ENODEV; goto err4; } } #endif return retval; err4: Loading Loading @@ -164,6 +191,12 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; struct ehci_hcd *ehci = hcd_to_ehci(hcd); if (ehci->transceiver) { otg_set_host(ehci->transceiver, NULL); put_device(ehci->transceiver->dev); } usb_remove_hcd(hcd); Loading Loading @@ -544,6 +577,38 @@ static struct dev_pm_ops ehci_fsl_pm_ops = { #define EHCI_FSL_PM_OPS NULL #endif /* CONFIG_PM */ #ifdef CONFIG_USB_OTG static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); u32 status; if (!port) return -EINVAL; port--; /* start port reset before HNP protocol time out */ status = readl(&ehci->regs->port_status[port]); if (!(status & PORT_CONNECT)) return -ENODEV; /* khubd will finish the reset later */ if (ehci_is_TDI(ehci)) { writel(PORT_RESET | (status & ~(PORT_CSC | PORT_PEC | PORT_OCC)), &ehci->regs->port_status[port]); } else { writel(PORT_RESET, &ehci->regs->port_status[port]); } return 0; } #else #define ehci_start_port_reset NULL #endif /* CONFIG_USB_OTG */ static const struct hc_driver ehci_fsl_hc_driver = { .description = hcd_name, .product_desc = "Freescale On-Chip EHCI Host Controller", Loading Loading @@ -583,6 +648,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, .start_port_reset = ehci_start_port_reset, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, Loading drivers/usb/host/ehci-hub.c +8 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ */ /*-------------------------------------------------------------------------*/ #include <linux/usb/otg.h> #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) Loading Loading @@ -801,6 +802,13 @@ static int ehci_hub_control ( goto error; if (ehci->no_selective_suspend) break; #ifdef CONFIG_USB_OTG if ((hcd->self.otg_port == (wIndex + 1)) && hcd->self.b_hnp_enable) { otg_start_hnp(ehci->transceiver); break; } #endif if (!(temp & PORT_SUSPEND)) break; if ((temp & PORT_PE) == 0) Loading drivers/usb/host/ehci.h +4 −0 Original line number Diff line number Diff line Loading @@ -161,6 +161,10 @@ struct ehci_hcd { /* one per controller */ #ifdef DEBUG struct dentry *debug_dir; #endif /* * OTG controllers and transceivers need software interaction */ struct otg_transceiver *transceiver; }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ Loading Loading
drivers/usb/gadget/fsl_udc_core.c +132 −15 Original line number Diff line number Diff line Loading @@ -353,6 +353,19 @@ static void dr_controller_stop(struct fsl_udc *udc) { unsigned int tmp; pr_debug("%s\n", __func__); /* if we're in OTG mode, and the Host is currently using the port, * stop now and don't rip the controller out from under the * ehci driver */ if (udc->gadget.is_otg) { if (!(fsl_readl(&dr_regs->otgsc) & OTGSC_STS_USB_ID)) { pr_debug("udc: Leaving early\n"); return; } } /* disable all INTR */ fsl_writel(0, &dr_regs->usbintr); Loading Loading @@ -1668,6 +1681,9 @@ static void port_change_irq(struct fsl_udc *udc) { u32 speed; if (udc->bus_reset) udc->bus_reset = 0; /* Bus resetting is finished */ if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) { /* Get the speed */ Loading Loading @@ -1775,6 +1791,8 @@ static void reset_irq(struct fsl_udc *udc) if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) { VDBG("Bus reset"); /* Bus is reseting */ udc->bus_reset = 1; /* Reset all the queues, include XD, dTD, EP queue * head and TR Queue */ reset_queues(udc); Loading Loading @@ -1852,6 +1870,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc) /* Reset Received */ if (irq_src & USB_STS_RESET) { VDBG("reset int"); reset_irq(udc); status = IRQ_HANDLED; } Loading Loading @@ -1909,11 +1928,30 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver, goto out; } /* Enable DR IRQ reg and Set usbcmd reg Run bit */ if (udc_controller->transceiver) { /* Suspend the controller until OTG enable it */ udc_controller->stopped = 1; printk(KERN_INFO "Suspend udc for OTG auto detect\n"); /* connect to bus through transceiver */ 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; } } } else { /* Enable DR IRQ reg and set USBCMD reg Run bit */ dr_controller_run(udc_controller); udc_controller->usb_state = USB_STATE_ATTACHED; udc_controller->ep0_state = WAIT_FOR_SETUP; udc_controller->ep0_dir = 0; } printk(KERN_INFO "%s: bind to driver %s\n", udc_controller->gadget.name, driver->driver.name); Loading Loading @@ -2374,18 +2412,31 @@ static int __init fsl_udc_probe(struct platform_device *pdev) spin_lock_init(&udc_controller->lock); udc_controller->stopped = 1; #ifdef CONFIG_USB_OTG if (pdata->operating_mode == FSL_USB2_DR_OTG) { udc_controller->transceiver = otg_get_transceiver(); if (!udc_controller->transceiver) { ERR("Can't find OTG driver!\n"); ret = -ENODEV; goto err_kfree; } } #endif res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENXIO; goto err_kfree; } if (pdata->operating_mode == FSL_USB2_DR_DEVICE) { if (!request_mem_region(res->start, res->end - res->start + 1, driver_name)) { ERR("request mem region for %s failed\n", pdev->name); ret = -EBUSY; goto err_kfree; } } dr_regs = ioremap(res->start, resource_size(res)); if (!dr_regs) { Loading Loading @@ -2455,9 +2506,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev) goto err_free_irq; } if (!udc_controller->transceiver) { /* initialize usb hw reg except for regs for EP, * leave usbintr reg untouched */ dr_controller_setup(udc_controller); } fsl_udc_clk_finalize(pdev); Loading @@ -2477,6 +2530,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev) if (ret < 0) goto err_free_irq; if (udc_controller->transceiver) udc_controller->gadget.is_otg = 1; /* setup QH and epctrl for ep0 */ ep0_setup(udc_controller); Loading Loading @@ -2521,6 +2577,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev) err_iounmap_noclk: iounmap(dr_regs); err_release_mem_region: if (pdata->operating_mode == FSL_USB2_DR_DEVICE) release_mem_region(res->start, res->end - res->start + 1); err_kfree: kfree(udc_controller); Loading Loading @@ -2555,6 +2612,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev) dma_pool_destroy(udc_controller->td_pool); free_irq(udc_controller->irq, udc_controller); iounmap(dr_regs); if (pdata->operating_mode == FSL_USB2_DR_DEVICE) release_mem_region(res->start, res->end - res->start + 1); device_unregister(&udc_controller->gadget.dev); Loading Loading @@ -2598,6 +2656,62 @@ static int fsl_udc_resume(struct platform_device *pdev) return 0; } static int fsl_udc_otg_suspend(struct device *dev, pm_message_t state) { struct fsl_udc *udc = udc_controller; u32 mode, usbcmd; mode = fsl_readl(&dr_regs->usbmode) & USB_MODE_CTRL_MODE_MASK; pr_debug("%s(): mode 0x%x stopped %d\n", __func__, mode, udc->stopped); /* * If the controller is already stopped, then this must be a * PM suspend. Remember this fact, so that we will leave the * controller stopped at PM resume time. */ if (udc->stopped) { pr_debug("gadget already stopped, leaving early\n"); udc->already_stopped = 1; return 0; } if (mode != USB_MODE_CTRL_MODE_DEVICE) { pr_debug("gadget not in device mode, leaving early\n"); return 0; } /* stop the controller */ usbcmd = fsl_readl(&dr_regs->usbcmd) & ~USB_CMD_RUN_STOP; fsl_writel(usbcmd, &dr_regs->usbcmd); udc->stopped = 1; pr_info("USB Gadget suspended\n"); return 0; } static int fsl_udc_otg_resume(struct device *dev) { 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 (udc_controller->already_stopped) { udc_controller->already_stopped = 0; pr_debug("gadget was already stopped, leaving early\n"); return 0; } pr_info("USB Gadget resume\n"); return fsl_udc_resume(NULL); } /*------------------------------------------------------------------------- Register entry point for the peripheral controller driver --------------------------------------------------------------------------*/ Loading @@ -2610,6 +2724,9 @@ static struct platform_driver udc_driver = { .driver = { .name = (char *)driver_name, .owner = THIS_MODULE, /* udc suspend/resume called from OTG driver */ .suspend = fsl_udc_otg_suspend, .resume = fsl_udc_otg_resume, }, }; Loading
drivers/usb/gadget/fsl_usb2_udc.h +2 −0 Original line number Diff line number Diff line Loading @@ -476,6 +476,7 @@ struct fsl_udc { unsigned vbus_active:1; unsigned stopped:1; unsigned remote_wakeup:1; unsigned already_stopped:1; unsigned big_endian_desc:1; struct ep_queue_head *ep_qh; /* Endpoints Queue-Head */ Loading @@ -487,6 +488,7 @@ struct fsl_udc { dma_addr_t ep_qh_dma; /* dma address of QH */ u32 max_pipes; /* Device max pipes */ u32 bus_reset; /* Device is bus resetting */ u32 resume_state; /* USB state to resume */ u32 usb_state; /* USB current state */ u32 ep0_state; /* Endpoint zero state */ Loading
drivers/usb/host/ehci-fsl.c +66 −0 Original line number Diff line number Diff line Loading @@ -117,6 +117,9 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, pdata->regs = hcd->regs; if (pdata->power_budget) hcd->power_budget = pdata->power_budget; /* * do platform specific init: check the clock, grab/config pins, etc. */ Loading @@ -134,6 +137,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED); if (retval != 0) goto err4; #ifdef CONFIG_USB_OTG if (pdata->operating_mode == FSL_USB2_DR_OTG) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); ehci->transceiver = otg_get_transceiver(); dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n", hcd, ehci, ehci->transceiver); if (ehci->transceiver) { retval = otg_set_host(ehci->transceiver, &ehci_to_hcd(ehci)->self); if (retval) { if (ehci->transceiver) put_device(ehci->transceiver->dev); goto err4; } } else { dev_err(&pdev->dev, "can't find transceiver\n"); retval = -ENODEV; goto err4; } } #endif return retval; err4: Loading Loading @@ -164,6 +191,12 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; struct ehci_hcd *ehci = hcd_to_ehci(hcd); if (ehci->transceiver) { otg_set_host(ehci->transceiver, NULL); put_device(ehci->transceiver->dev); } usb_remove_hcd(hcd); Loading Loading @@ -544,6 +577,38 @@ static struct dev_pm_ops ehci_fsl_pm_ops = { #define EHCI_FSL_PM_OPS NULL #endif /* CONFIG_PM */ #ifdef CONFIG_USB_OTG static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); u32 status; if (!port) return -EINVAL; port--; /* start port reset before HNP protocol time out */ status = readl(&ehci->regs->port_status[port]); if (!(status & PORT_CONNECT)) return -ENODEV; /* khubd will finish the reset later */ if (ehci_is_TDI(ehci)) { writel(PORT_RESET | (status & ~(PORT_CSC | PORT_PEC | PORT_OCC)), &ehci->regs->port_status[port]); } else { writel(PORT_RESET, &ehci->regs->port_status[port]); } return 0; } #else #define ehci_start_port_reset NULL #endif /* CONFIG_USB_OTG */ static const struct hc_driver ehci_fsl_hc_driver = { .description = hcd_name, .product_desc = "Freescale On-Chip EHCI Host Controller", Loading Loading @@ -583,6 +648,7 @@ static const struct hc_driver ehci_fsl_hc_driver = { .hub_control = ehci_hub_control, .bus_suspend = ehci_bus_suspend, .bus_resume = ehci_bus_resume, .start_port_reset = ehci_start_port_reset, .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, Loading
drivers/usb/host/ehci-hub.c +8 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ */ /*-------------------------------------------------------------------------*/ #include <linux/usb/otg.h> #define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) Loading Loading @@ -801,6 +802,13 @@ static int ehci_hub_control ( goto error; if (ehci->no_selective_suspend) break; #ifdef CONFIG_USB_OTG if ((hcd->self.otg_port == (wIndex + 1)) && hcd->self.b_hnp_enable) { otg_start_hnp(ehci->transceiver); break; } #endif if (!(temp & PORT_SUSPEND)) break; if ((temp & PORT_PE) == 0) Loading
drivers/usb/host/ehci.h +4 −0 Original line number Diff line number Diff line Loading @@ -161,6 +161,10 @@ struct ehci_hcd { /* one per controller */ #ifdef DEBUG struct dentry *debug_dir; #endif /* * OTG controllers and transceivers need software interaction */ struct otg_transceiver *transceiver; }; /* convert between an HCD pointer and the corresponding EHCI_HCD */ Loading