static void ehci_fsl_shutdown(struct usb_hcd *hcd) { if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); fsl_usb_clk_gate(hcd->self.controller->platform_data, true); } /* Disable wakeup event first */ usb_host_set_wakeup(hcd->self.controller, false); ehci_shutdown(hcd); if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); fsl_usb_clk_gate(hcd->self.controller->platform_data, false); } }
static int ehci_fsl_bus_resume(struct usb_hcd *hcd) { int ret = 0; struct fsl_usb2_platform_data *pdata; pdata = hcd->self.controller->platform_data; printk(KERN_DEBUG "%s, %s\n", __func__, pdata->name); /* * At otg mode, it should not call host resume for usb gadget device * Otherwise, this usb device can't be recognized as a gadget */ if (hcd->self.is_b_host) { return -ESHUTDOWN; } if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); fsl_usb_clk_gate(hcd->self.controller->platform_data, true); usb_host_set_wakeup(hcd->self.controller, false); fsl_usb_lowpower_mode(pdata, false); } if (pdata->platform_resume) pdata->platform_resume(pdata); ret = ehci_bus_resume(hcd); if (ret) return ret; return ret; }
static int ehci_fsl_bus_suspend(struct usb_hcd *hcd) { int ret = 0; struct fsl_usb2_platform_data *pdata; pdata = hcd->self.controller->platform_data; printk(KERN_DEBUG "%s, %s\n", __func__, pdata->name); /* the host is already at low power mode */ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { return 0; } ret = ehci_bus_suspend(hcd); if (ret != 0) return ret; if (pdata->platform_suspend) pdata->platform_suspend(pdata); usb_host_set_wakeup(hcd->self.controller, true); fsl_usb_lowpower_mode(pdata, true); fsl_usb_clk_gate(hcd->self.controller->platform_data, false); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); return ret; }
static int ehci_fsl_bus_suspend(struct usb_hcd *hcd) { int ret = 0; struct fsl_usb2_platform_data *pdata; u32 tmp, portsc; struct ehci_hcd *ehci = hcd_to_ehci(hcd); pdata = hcd->self.controller->platform_data; printk(KERN_DEBUG "%s, %s\n", __func__, pdata->name); /* the host is already at low power mode */ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { return 0; } portsc = ehci_readl(ehci, &ehci->regs->port_status[0]); ret = ehci_bus_suspend(hcd); if (ret != 0) return ret; if (portsc & PORT_CCS) { printk(KERN_DEBUG "there is a device on the port\n"); tmp = ehci_readl(ehci, &ehci->regs->command); tmp |= CMD_RUN; ehci_writel(ehci, tmp, &ehci->regs->command); } if (pdata->platform_suspend) pdata->platform_suspend(pdata); usb_host_set_wakeup(hcd->self.controller, true); fsl_usb_lowpower_mode(pdata, true); fsl_usb_clk_gate(hcd->self.controller->platform_data, false); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); return ret; }
static int ehci_fsl_drv_resume(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct usb_device *roothub = hcd->self.root_hub; u32 tmp; struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; 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); 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); if (!host_can_wakeup_system(pdev)) { if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { fsl_usb_clk_gate(hcd->self.controller->platform_data, true); } usb_host_set_wakeup(hcd->self.controller, true); if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { fsl_usb_clk_gate(hcd->self.controller->platform_data, false); } } return 0; } if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); fsl_usb_clk_gate(hcd->self.controller->platform_data, true); usb_host_set_wakeup(hcd->self.controller, false); fsl_usb_lowpower_mode(pdata, false); } /* set host mode */ fsl_platform_set_host_mode(hcd); /* restore EHCI registers */ ehci_writel(ehci, pdata->pm_portsc, &ehci->regs->port_status[0]); ehci_writel(ehci, pdata->pm_command, &ehci->regs->command); ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable); ehci_writel(ehci, pdata->pm_frame_index, &ehci->regs->frame_index); ehci_writel(ehci, pdata->pm_segment, &ehci->regs->segment); ehci_writel(ehci, pdata->pm_frame_list, &ehci->regs->frame_list); ehci_writel(ehci, pdata->pm_async_next, &ehci->regs->async_next); ehci_writel(ehci, pdata->pm_configured_flag, &ehci->regs->configured_flag); tmp = ehci_readl(ehci, &ehci->regs->command); tmp |= CMD_RUN; ehci_writel(ehci, tmp, &ehci->regs->command); 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); } pdata->pmflags = 0; printk(KERN_DEBUG "ehci fsl drv resume ends: %s\n", pdata->name); return 0; }
/* These routines rely on the bus (pci, platform, etc) * to handle powerdown and wakeup, and currently also on * transceivers that don't need any software attention to set up * the right sort of wakeup. * * They're also used for turning on/off the port when doing OTG. */ static int ehci_fsl_drv_suspend(struct platform_device *pdev, pm_message_t message) { struct usb_hcd *hcd = platform_get_drvdata(pdev); struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct usb_device *roothub = hcd->self.root_hub; u32 port_status; struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data; printk(KERN_DEBUG "USB Host suspend begins\n"); /* 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__); if (!host_can_wakeup_system(pdev)) { int mask; /* 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); mask = ehci_readl(ehci, &ehci->regs->intr_enable); mask &= ~STS_PCD; ehci_writel(ehci, mask, &ehci->regs->intr_enable); usb_host_set_wakeup(hcd->self.controller, false); fsl_usb_clk_gate(hcd->self.controller->platform_data, false); } return 0; } /* only the otg host can go here */ /* wait for all usb device on the hcd dettached */ usb_lock_device(roothub); if (roothub->children[0] != NULL) { int old = hcd->self.is_b_host; printk(KERN_DEBUG "will resume roothub and its children\n"); hcd->self.is_b_host = 0; /* resume the roothub, so that it can test the children is disconnected */ if (roothub->state == USB_STATE_SUSPENDED) usb_resume(&roothub->dev, PMSG_USER_SUSPEND); /* we must do unlock here, the hubd thread will hold the same lock * here release the lock, so that the hubd thread can process the usb * disconnect event and set the children[0] be NULL, or there will be * a deadlock */ usb_unlock_device(roothub); while (roothub->children[0] != NULL) msleep(1); usb_lock_device(roothub); hcd->self.is_b_host = old; } usb_unlock_device(roothub); if (!(hcd->state & HC_STATE_SUSPENDED)) { printk(KERN_DEBUG "will suspend roothub and its children\n"); usb_lock_device(roothub); usb_suspend(&roothub->dev, PMSG_USER_SUSPEND); usb_unlock_device(roothub); } if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { fsl_usb_clk_gate(hcd->self.controller->platform_data, true); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); } port_status = ehci_readl(ehci, &ehci->regs->port_status[0]); /* save EHCI registers */ pdata->pm_command = ehci_readl(ehci, &ehci->regs->command); pdata->pm_command &= ~CMD_RUN; pdata->pm_status = ehci_readl(ehci, &ehci->regs->status); pdata->pm_intr_enable = ehci_readl(ehci, &ehci->regs->intr_enable); pdata->pm_frame_index = ehci_readl(ehci, &ehci->regs->frame_index); pdata->pm_segment = ehci_readl(ehci, &ehci->regs->segment); pdata->pm_frame_list = ehci_readl(ehci, &ehci->regs->frame_list); pdata->pm_async_next = ehci_readl(ehci, &ehci->regs->async_next); pdata->pm_configured_flag = ehci_readl(ehci, &ehci->regs->configured_flag); pdata->pm_portsc = ehci_readl(ehci, &ehci->regs->port_status[0]); /* clear the W1C bits */ pdata->pm_portsc &= cpu_to_hc32(ehci, ~PORT_RWC_BITS); /* clear PHCD bit */ pdata->pm_portsc &= ~PORT_PTS_PHCD; usb_host_set_wakeup(hcd->self.controller, true); fsl_usb_lowpower_mode(pdata, true); if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); fsl_usb_clk_gate(hcd->self.controller->platform_data, false); } pdata->pmflags = 0; printk(KERN_DEBUG "host suspend ends\n"); return 0; }