示例#1
0
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;
}
示例#2
0
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;
}