static int s5p_ehci_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); struct usb_hcd *hcd = s5p_ehci->hcd; struct ehci_hcd *ehci = hcd_to_ehci(hcd); unsigned long flags; int rc = 0; #ifdef CONFIG_MDM_HSIC_PM if (check_udev_suspend_allowed(hsic_pm_dev) > 0) { set_host_stat(hsic_pm_dev, POWER_OFF); if (wait_dev_pwr_stat(hsic_pm_dev, POWER_OFF) < 0) { set_host_stat(hsic_pm_dev, POWER_ON); pm_runtime_resume(&pdev->dev); return -EBUSY; } } else { pm_runtime_resume(&pdev->dev); return -EBUSY; } #endif if (time_before(jiffies, ehci->next_statechange)) msleep(10); /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. * * This is still racy as hcd->state is manipulated outside of * any locks =P But that will be a different fix. */ spin_lock_irqsave(&ehci->lock, flags); if (hcd->state != HC_STATE_SUSPENDED && hcd->state != HC_STATE_HALT) { spin_unlock_irqrestore(&ehci->lock, flags); return -EINVAL; } ehci_writel(ehci, 0, &ehci->regs->intr_enable); (void)ehci_readl(ehci, &ehci->regs->intr_enable); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irqrestore(&ehci->lock, flags); if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); #if defined(CONFIG_LINK_DEVICE_HSIC) || defined(CONFIG_LINK_DEVICE_USB) if (pdata && pdata->noti_host_states) pdata->noti_host_states(pdev, S5P_HOST_OFF); #endif clk_disable(s5p_ehci->clk); return rc; }
static int s5p_ehci_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); struct usb_hcd *hcd = s5p_ehci->hcd; struct ehci_hcd *ehci = hcd_to_ehci(hcd); unsigned long flags; int rc = 0; #ifdef CONFIG_MDM_HSIC_PM /* * check suspend returns 1 if it is possible to suspend * otherwise, it returns 0 impossible or returns some error */ rc = check_udev_suspend_allowed(hsic_pm_dev); if (rc > 0) { set_host_stat(hsic_pm_dev, POWER_OFF); if (wait_dev_pwr_stat(hsic_pm_dev, POWER_OFF) < 0) { set_host_stat(hsic_pm_dev, POWER_ON); pm_runtime_resume(&pdev->dev); return -EBUSY; } } else if (rc == -ENODEV) { /* no hsic pm driver loaded, proceed suspend */ pr_debug("%s: suspend without hsic pm\n", __func__); } else { pm_runtime_resume(&pdev->dev); return -EBUSY; } rc = 0; #endif #if defined(CONFIG_LINK_DEVICE_HSIC) || defined(CONFIG_LINK_DEVICE_USB) rc = get_hostwake_state(); if (rc) { pr_info("%s: suspend fail by host wakeup irq\n", __func__); pm_runtime_resume(&pdev->dev); return -EBUSY; } #endif if (time_before(jiffies, ehci->next_statechange)) usleep_range(10000, 11000); /* Root hub was already suspended. Disable irq emission and * mark HW unaccessible, bail out if RH has been resumed. Use * the spinlock to properly synchronize with possible pending * RH suspend or resume activity. * * This is still racy as hcd->state is manipulated outside of * any locks =P But that will be a different fix. */ spin_lock_irqsave(&ehci->lock, flags); if (hcd->state != HC_STATE_SUSPENDED && hcd->state != HC_STATE_HALT) { spin_unlock_irqrestore(&ehci->lock, flags); return -EINVAL; } ehci_writel(ehci, 0, &ehci->regs->intr_enable); (void)ehci_readl(ehci, &ehci->regs->intr_enable); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irqrestore(&ehci->lock, flags); if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); #if defined(CONFIG_LINK_DEVICE_HSIC) || defined(CONFIG_LINK_DEVICE_USB) set_host_states(0); #endif clk_disable(s5p_ehci->clk); return rc; }