USB: extend ehci-fsl and fsl_udc_core driver for OTG operation
Signed-off-by: Anatolij Gustschin <agust@denx.de> Cc: Li Yang <leoli@freescale.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
		
					parent
					
						
							
								0807c500a1
							
						
					
				
			
			
				commit
				
					
						83722bc943
					
				
			
		
					 6 changed files with 213 additions and 15 deletions
				
			
		| 
						 | 
					@ -353,6 +353,19 @@ static void dr_controller_stop(struct fsl_udc *udc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int tmp;
 | 
						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 */
 | 
						/* disable all INTR */
 | 
				
			||||||
	fsl_writel(0, &dr_regs->usbintr);
 | 
						fsl_writel(0, &dr_regs->usbintr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1668,6 +1681,9 @@ static void port_change_irq(struct fsl_udc *udc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 speed;
 | 
						u32 speed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (udc->bus_reset)
 | 
				
			||||||
 | 
							udc->bus_reset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Bus resetting is finished */
 | 
						/* Bus resetting is finished */
 | 
				
			||||||
	if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
 | 
						if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
 | 
				
			||||||
		/* Get the speed */
 | 
							/* Get the speed */
 | 
				
			||||||
| 
						 | 
					@ -1775,6 +1791,8 @@ static void reset_irq(struct fsl_udc *udc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
 | 
						if (fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET) {
 | 
				
			||||||
		VDBG("Bus reset");
 | 
							VDBG("Bus reset");
 | 
				
			||||||
 | 
							/* Bus is reseting */
 | 
				
			||||||
 | 
							udc->bus_reset = 1;
 | 
				
			||||||
		/* Reset all the queues, include XD, dTD, EP queue
 | 
							/* Reset all the queues, include XD, dTD, EP queue
 | 
				
			||||||
		 * head and TR Queue */
 | 
							 * head and TR Queue */
 | 
				
			||||||
		reset_queues(udc);
 | 
							reset_queues(udc);
 | 
				
			||||||
| 
						 | 
					@ -1852,6 +1870,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Reset Received */
 | 
						/* Reset Received */
 | 
				
			||||||
	if (irq_src & USB_STS_RESET) {
 | 
						if (irq_src & USB_STS_RESET) {
 | 
				
			||||||
 | 
							VDBG("reset int");
 | 
				
			||||||
		reset_irq(udc);
 | 
							reset_irq(udc);
 | 
				
			||||||
		status = IRQ_HANDLED;
 | 
							status = IRQ_HANDLED;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1909,11 +1928,30 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 | 
				
			||||||
		goto out;
 | 
							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);
 | 
							dr_controller_run(udc_controller);
 | 
				
			||||||
		udc_controller->usb_state = USB_STATE_ATTACHED;
 | 
							udc_controller->usb_state = USB_STATE_ATTACHED;
 | 
				
			||||||
		udc_controller->ep0_state = WAIT_FOR_SETUP;
 | 
							udc_controller->ep0_state = WAIT_FOR_SETUP;
 | 
				
			||||||
		udc_controller->ep0_dir = 0;
 | 
							udc_controller->ep0_dir = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	printk(KERN_INFO "%s: bind to driver %s\n",
 | 
						printk(KERN_INFO "%s: bind to driver %s\n",
 | 
				
			||||||
			udc_controller->gadget.name, driver->driver.name);
 | 
								udc_controller->gadget.name, driver->driver.name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2374,18 +2412,31 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 | 
				
			||||||
	spin_lock_init(&udc_controller->lock);
 | 
						spin_lock_init(&udc_controller->lock);
 | 
				
			||||||
	udc_controller->stopped = 1;
 | 
						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);
 | 
						res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
				
			||||||
	if (!res) {
 | 
						if (!res) {
 | 
				
			||||||
		ret = -ENXIO;
 | 
							ret = -ENXIO;
 | 
				
			||||||
		goto err_kfree;
 | 
							goto err_kfree;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pdata->operating_mode == FSL_USB2_DR_DEVICE) {
 | 
				
			||||||
		if (!request_mem_region(res->start, res->end - res->start + 1,
 | 
							if (!request_mem_region(res->start, res->end - res->start + 1,
 | 
				
			||||||
					driver_name)) {
 | 
										driver_name)) {
 | 
				
			||||||
			ERR("request mem region for %s failed\n", pdev->name);
 | 
								ERR("request mem region for %s failed\n", pdev->name);
 | 
				
			||||||
			ret = -EBUSY;
 | 
								ret = -EBUSY;
 | 
				
			||||||
			goto err_kfree;
 | 
								goto err_kfree;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dr_regs = ioremap(res->start, resource_size(res));
 | 
						dr_regs = ioremap(res->start, resource_size(res));
 | 
				
			||||||
	if (!dr_regs) {
 | 
						if (!dr_regs) {
 | 
				
			||||||
| 
						 | 
					@ -2455,9 +2506,11 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 | 
				
			||||||
		goto err_free_irq;
 | 
							goto err_free_irq;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!udc_controller->transceiver) {
 | 
				
			||||||
		/* initialize usb hw reg except for regs for EP,
 | 
							/* initialize usb hw reg except for regs for EP,
 | 
				
			||||||
		 * leave usbintr reg untouched */
 | 
							 * leave usbintr reg untouched */
 | 
				
			||||||
		dr_controller_setup(udc_controller);
 | 
							dr_controller_setup(udc_controller);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fsl_udc_clk_finalize(pdev);
 | 
						fsl_udc_clk_finalize(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2477,6 +2530,9 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		goto err_free_irq;
 | 
							goto err_free_irq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (udc_controller->transceiver)
 | 
				
			||||||
 | 
							udc_controller->gadget.is_otg = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* setup QH and epctrl for ep0 */
 | 
						/* setup QH and epctrl for ep0 */
 | 
				
			||||||
	ep0_setup(udc_controller);
 | 
						ep0_setup(udc_controller);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2521,6 +2577,7 @@ err_iounmap:
 | 
				
			||||||
err_iounmap_noclk:
 | 
					err_iounmap_noclk:
 | 
				
			||||||
	iounmap(dr_regs);
 | 
						iounmap(dr_regs);
 | 
				
			||||||
err_release_mem_region:
 | 
					err_release_mem_region:
 | 
				
			||||||
 | 
						if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
 | 
				
			||||||
		release_mem_region(res->start, res->end - res->start + 1);
 | 
							release_mem_region(res->start, res->end - res->start + 1);
 | 
				
			||||||
err_kfree:
 | 
					err_kfree:
 | 
				
			||||||
	kfree(udc_controller);
 | 
						kfree(udc_controller);
 | 
				
			||||||
| 
						 | 
					@ -2555,6 +2612,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
 | 
				
			||||||
	dma_pool_destroy(udc_controller->td_pool);
 | 
						dma_pool_destroy(udc_controller->td_pool);
 | 
				
			||||||
	free_irq(udc_controller->irq, udc_controller);
 | 
						free_irq(udc_controller->irq, udc_controller);
 | 
				
			||||||
	iounmap(dr_regs);
 | 
						iounmap(dr_regs);
 | 
				
			||||||
 | 
						if (pdata->operating_mode == FSL_USB2_DR_DEVICE)
 | 
				
			||||||
		release_mem_region(res->start, res->end - res->start + 1);
 | 
							release_mem_region(res->start, res->end - res->start + 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	device_unregister(&udc_controller->gadget.dev);
 | 
						device_unregister(&udc_controller->gadget.dev);
 | 
				
			||||||
| 
						 | 
					@ -2598,6 +2656,62 @@ static int fsl_udc_resume(struct platform_device *pdev)
 | 
				
			||||||
	return 0;
 | 
						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
 | 
						Register entry point for the peripheral controller driver
 | 
				
			||||||
--------------------------------------------------------------------------*/
 | 
					--------------------------------------------------------------------------*/
 | 
				
			||||||
| 
						 | 
					@ -2610,6 +2724,9 @@ static struct platform_driver udc_driver = {
 | 
				
			||||||
	.driver  = {
 | 
						.driver  = {
 | 
				
			||||||
		.name = (char *)driver_name,
 | 
							.name = (char *)driver_name,
 | 
				
			||||||
		.owner = THIS_MODULE,
 | 
							.owner = THIS_MODULE,
 | 
				
			||||||
 | 
							/* udc suspend/resume called from OTG driver */
 | 
				
			||||||
 | 
							.suspend = fsl_udc_otg_suspend,
 | 
				
			||||||
 | 
							.resume  = fsl_udc_otg_resume,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -476,6 +476,7 @@ struct fsl_udc {
 | 
				
			||||||
	unsigned vbus_active:1;
 | 
						unsigned vbus_active:1;
 | 
				
			||||||
	unsigned stopped:1;
 | 
						unsigned stopped:1;
 | 
				
			||||||
	unsigned remote_wakeup:1;
 | 
						unsigned remote_wakeup:1;
 | 
				
			||||||
 | 
						unsigned already_stopped:1;
 | 
				
			||||||
	unsigned big_endian_desc:1;
 | 
						unsigned big_endian_desc:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct ep_queue_head *ep_qh;	/* Endpoints Queue-Head */
 | 
						struct ep_queue_head *ep_qh;	/* Endpoints Queue-Head */
 | 
				
			||||||
| 
						 | 
					@ -487,6 +488,7 @@ struct fsl_udc {
 | 
				
			||||||
	dma_addr_t ep_qh_dma;		/* dma address of QH */
 | 
						dma_addr_t ep_qh_dma;		/* dma address of QH */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u32 max_pipes;          /* Device max pipes */
 | 
						u32 max_pipes;          /* Device max pipes */
 | 
				
			||||||
 | 
						u32 bus_reset;		/* Device is bus resetting */
 | 
				
			||||||
	u32 resume_state;	/* USB state to resume */
 | 
						u32 resume_state;	/* USB state to resume */
 | 
				
			||||||
	u32 usb_state;		/* USB current state */
 | 
						u32 usb_state;		/* USB current state */
 | 
				
			||||||
	u32 ep0_state;		/* Endpoint zero state */
 | 
						u32 ep0_state;		/* Endpoint zero state */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -117,6 +117,9 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pdata->regs = hcd->regs;
 | 
						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.
 | 
						 * do platform specific init: check the clock, grab/config pins, etc.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
						retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
 | 
				
			||||||
	if (retval != 0)
 | 
						if (retval != 0)
 | 
				
			||||||
		goto err4;
 | 
							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;
 | 
						return retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      err4:
 | 
					      err4:
 | 
				
			||||||
| 
						 | 
					@ -164,6 +191,12 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
 | 
				
			||||||
			       struct platform_device *pdev)
 | 
								       struct platform_device *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 | 
						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);
 | 
						usb_remove_hcd(hcd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -544,6 +577,38 @@ static struct dev_pm_ops ehci_fsl_pm_ops = {
 | 
				
			||||||
#define EHCI_FSL_PM_OPS		NULL
 | 
					#define EHCI_FSL_PM_OPS		NULL
 | 
				
			||||||
#endif /* CONFIG_PM */
 | 
					#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 = {
 | 
					static const struct hc_driver ehci_fsl_hc_driver = {
 | 
				
			||||||
	.description = hcd_name,
 | 
						.description = hcd_name,
 | 
				
			||||||
	.product_desc = "Freescale On-Chip EHCI Host Controller",
 | 
						.product_desc = "Freescale On-Chip EHCI Host Controller",
 | 
				
			||||||
| 
						 | 
					@ -583,6 +648,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
 | 
				
			||||||
	.hub_control = ehci_hub_control,
 | 
						.hub_control = ehci_hub_control,
 | 
				
			||||||
	.bus_suspend = ehci_bus_suspend,
 | 
						.bus_suspend = ehci_bus_suspend,
 | 
				
			||||||
	.bus_resume = ehci_bus_resume,
 | 
						.bus_resume = ehci_bus_resume,
 | 
				
			||||||
 | 
						.start_port_reset = ehci_start_port_reset,
 | 
				
			||||||
	.relinquish_port = ehci_relinquish_port,
 | 
						.relinquish_port = ehci_relinquish_port,
 | 
				
			||||||
	.port_handed_over = ehci_port_handed_over,
 | 
						.port_handed_over = ehci_port_handed_over,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*-------------------------------------------------------------------------*/
 | 
					/*-------------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					#include <linux/usb/otg.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
 | 
					#define	PORT_WAKE_BITS	(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -801,6 +802,13 @@ static int ehci_hub_control (
 | 
				
			||||||
				goto error;
 | 
									goto error;
 | 
				
			||||||
			if (ehci->no_selective_suspend)
 | 
								if (ehci->no_selective_suspend)
 | 
				
			||||||
				break;
 | 
									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))
 | 
								if (!(temp & PORT_SUSPEND))
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			if ((temp & PORT_PE) == 0)
 | 
								if ((temp & PORT_PE) == 0)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -161,6 +161,10 @@ struct ehci_hcd {			/* one per controller */
 | 
				
			||||||
#ifdef DEBUG
 | 
					#ifdef DEBUG
 | 
				
			||||||
	struct dentry		*debug_dir;
 | 
						struct dentry		*debug_dir;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * OTG controllers and transceivers need software interaction
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct otg_transceiver	*transceiver;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
 | 
					/* convert between an HCD pointer and the corresponding EHCI_HCD */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,6 +72,7 @@ struct fsl_usb2_platform_data {
 | 
				
			||||||
	void		(*exit)(struct platform_device *);
 | 
						void		(*exit)(struct platform_device *);
 | 
				
			||||||
	void __iomem	*regs;		/* ioremap'd register base */
 | 
						void __iomem	*regs;		/* ioremap'd register base */
 | 
				
			||||||
	struct clk	*clk;
 | 
						struct clk	*clk;
 | 
				
			||||||
 | 
						unsigned	power_budget;	/* hcd->power_budget */
 | 
				
			||||||
	unsigned	big_endian_mmio:1;
 | 
						unsigned	big_endian_mmio:1;
 | 
				
			||||||
	unsigned	big_endian_desc:1;
 | 
						unsigned	big_endian_desc:1;
 | 
				
			||||||
	unsigned	es:1;		/* need USBMODE:ES */
 | 
						unsigned	es:1;		/* need USBMODE:ES */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue