ENGR00219354: Fix USB host driver compiled as module fail problem
authorJingchang Lu <b35083@freescale.com>
Wed, 8 Aug 2012 01:55:46 +0000 (09:55 +0800)
committerJason Jin <Jason.jin@freescale.com>
Fri, 10 Aug 2012 10:19:13 +0000 (18:19 +0800)
Signed-off-by: Jingchang Lu <b35083@freescale.com>
drivers/usb/host/ehci-arc.c

index 93ef469c39fbb6de355c0d0e768201f45234bb2c..81ab1cffe374c9b582cee0b9b1da984586b91154 100755 (executable)
@@ -336,6 +336,7 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
        u32 tmp;
+       struct resource *res;
 
        if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
                /* Need open clock for register access */
@@ -366,6 +367,9 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
        usb_remove_hcd(hcd);
        usb_put_hcd(hcd);
 
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res)
+               free_irq(res->start, (void *)pdev);
        /*
         * do platform specific un-initialization:
         * release iomux pins, etc.
@@ -662,13 +666,35 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
        struct ehci_hcd *ehci = hcd_to_ehci(hcd);
        struct usb_device *roothub = hcd->self.root_hub;
        unsigned long flags;
-       u32 port_status;
+       u32 port_status, tmp;
        struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
 
        printk(KERN_DEBUG "USB Host suspend begins\n");
+#ifdef CONFIG_ARCH_MVF
+       if (pdata->suspended) {
+               pr_debug("%s: already suspended, leaving early\n", __func__);
+               pdata->already_suspended = 1;
+               return 0;
+       }
+
+       pr_debug("%s: suspending...\n", __func__);
+
+       hcd->state = HC_STATE_SUSPENDED;
+       pdev->dev.power.power_state = PMSG_SUSPEND;
+
+       /* ignore non-host interrupts */
+       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+       /* stop the controller */
+       tmp = ehci_readl(ehci, &ehci->regs->command);
+       tmp &= ~CMD_RUN;
+       ehci_writel(ehci, tmp, &ehci->regs->command);
+
+       pdata->suspended = 1;
+#else
        /* Only handles OTG mode switch event, system suspend event will be done in bus suspend */
        if (pdata->pmflags == 0) {
-               printk(KERN_DEBUG "%s, pm event \n", __func__);
+               printk(KERN_DEBUG "%s, pm event\n", __func__);
                /* Need open clock for register access */
                if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
                        fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
@@ -714,7 +740,7 @@ static int ehci_fsl_drv_suspend(struct platform_device *pdev,
                fsl_usb_clk_gate(hcd->self.controller->platform_data, true);
                set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        }
-
+#endif
        port_status = ehci_readl(ehci, &ehci->regs->port_status[0]);
        /* save EHCI registers */
        pdata->pm_command = ehci_readl(ehci, &ehci->regs->command);
@@ -760,6 +786,22 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
        struct fsl_usb2_wakeup_platform_data *wake_up_pdata = pdata->wakeup_pdata;
        /* Only handles OTG mode switch event */
        printk(KERN_DEBUG "ehci fsl drv resume begins: %s\n", pdata->name);
+#ifdef CONFIG_ARCH_MVF
+       if (pdata->already_suspended) {
+               pr_debug("already suspended, leaving early\n");
+               pdata->already_suspended = 0;
+               return 0;
+       }
+
+       if (!pdata->suspended) {
+               pr_debug("not suspended, leaving early\n");
+               return 0;
+       }
+
+       pdata->suspended = 0;
+
+       pr_debug("%s resuming...\n", __func__);
+#else
        if (pdata->pmflags == 0) {
                printk(KERN_DEBUG "%s,pm event, wait for wakeup irq if needed\n", __func__);
                wait_event_interruptible(wake_up_pdata->wq, !wake_up_pdata->usb_wakeup_is_pending);
@@ -773,7 +815,7 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
                fsl_usb_lowpower_mode(pdata, false);
                spin_unlock_irqrestore(&ehci->lock, flags);
        }
-
+#endif
        spin_lock_irqsave(&ehci->lock, flags);
        /* set host mode */
        fsl_platform_set_host_mode(hcd);
@@ -795,12 +837,16 @@ static int ehci_fsl_drv_resume(struct platform_device *pdev)
        ehci_writel(ehci, tmp, &ehci->regs->command);
        spin_unlock_irqrestore(&ehci->lock, flags);
 
+#ifdef CONFIG_ARCH_MVF
+       usb_hcd_resume_root_hub(hcd);
+#else
        if ((hcd->state & HC_STATE_SUSPENDED)) {
                printk(KERN_DEBUG "will resume roothub and its children\n");
                usb_lock_device(roothub);
                usb_resume(&roothub->dev, PMSG_USER_RESUME);
                usb_unlock_device(roothub);
        }
+#endif
        pdata->pmflags = 0;
        printk(KERN_DEBUG "ehci fsl drv resume ends: %s\n", pdata->name);