Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0faf881d authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "xhci-plat: Add hibernation support to xhci platform"

parents f7d145e4 c79ef74a
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -1495,9 +1495,10 @@ int usb_resume(struct device *dev, pm_message_t msg)
	 * Some buses would like to keep their devices in suspend
	 * state after system resume.  Their resume happen when
	 * a remote wakeup is detected or interface driver start
	 * I/O.
	 * I/O. And in the case when the system is restoring from
	 * hibernation, make sure all the devices are resumed.
	 */
	if (udev->bus->skip_resume)
	if (udev->bus->skip_resume && msg.event != PM_EVENT_RESTORE)
		return 0;

	/* For all calls, take the device back to full power and
+19 −1
Original line number Diff line number Diff line
@@ -1567,6 +1567,19 @@ static int dwc3_suspend(struct device *dev)
	return 0;
}

static int dwc3_pm_restore(struct device *dev)
{
	/*
	 * Set the core as runtime active to prevent the runtime
	 * PM ops being called before the PM restore is completed.
	 */
	pm_runtime_disable(dev);
	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);

	return 0;
}

static int dwc3_resume(struct device *dev)
{
	struct dwc3	*dwc = dev_get_drvdata(dev);
@@ -1591,7 +1604,12 @@ static int dwc3_resume(struct device *dev)
#endif /* CONFIG_PM_SLEEP */

static const struct dev_pm_ops dwc3_dev_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(dwc3_suspend, dwc3_resume)
	.suspend	= dwc3_suspend,
	.resume		= dwc3_resume,
	.freeze		= dwc3_suspend,
	.thaw		= dwc3_pm_restore,
	.poweroff	= dwc3_suspend,
	.restore	= dwc3_pm_restore,
	SET_RUNTIME_PM_OPS(dwc3_runtime_suspend, dwc3_runtime_resume,
			dwc3_runtime_idle)
};
+85 −15
Original line number Diff line number Diff line
@@ -2093,6 +2093,19 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc)
	dwc3_core_init(dwc);
	/* Re-configure event buffers */
	dwc3_event_buffers_setup(dwc);

	/* Get initial P3 status and enable IN_P3 event */
	val = dwc3_msm_read_reg_field(mdwc->base,
		DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK);
	atomic_set(&mdwc->in_p3, val == DWC3_LINK_STATE_U3);
	dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG,
				PWR_EVNT_POWERDOWN_IN_P3_MASK, 1);

	if (mdwc->otg_state == OTG_STATE_A_HOST) {
		dev_dbg(mdwc->dev, "%s: set the core in host mode\n",
							__func__);
		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
	}
}

static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc)
@@ -2246,7 +2259,7 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc,
	}
}

static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation)
{
	int ret;
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
@@ -2363,8 +2376,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
	clk_disable_unprepare(mdwc->xo_clk);

	/* Perform controller power collapse */
	if (!mdwc->in_host_mode && (!mdwc->in_device_mode ||
					mdwc->in_restart)) {
	if ((!mdwc->in_host_mode && (!mdwc->in_device_mode ||
					mdwc->in_restart)) || hibernation) {
		mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE;
		dev_dbg(mdwc->dev, "%s: power collapse\n", __func__);
		dwc3_msm_config_gdsc(mdwc, 0);
@@ -2520,8 +2533,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)

	/* Recover from controller power collapse */
	if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) {
		u32 tmp;

		if (mdwc->iommu_map) {
			ret = arm_iommu_attach_device(mdwc->dev,
					mdwc->iommu_map);
@@ -2536,13 +2547,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)

		dwc3_msm_power_collapse_por(mdwc);

		/* Get initial P3 status and enable IN_P3 event */
		tmp = dwc3_msm_read_reg_field(mdwc->base,
			DWC3_GDBGLTSSM, DWC3_GDBGLTSSM_LINKSTATE_MASK);
		atomic_set(&mdwc->in_p3, tmp == DWC3_LINK_STATE_U3);
		dwc3_msm_write_reg_field(mdwc->base, PWR_EVNT_IRQ_MASK_REG,
					PWR_EVNT_POWERDOWN_IN_P3_MASK, 1);

		mdwc->lpm_flags &= ~MDWC3_POWER_COLLAPSE;
	}

@@ -4404,7 +4408,39 @@ static int dwc3_msm_pm_suspend(struct device *dev)
		return -EBUSY;
	}

	ret = dwc3_msm_suspend(mdwc);
	ret = dwc3_msm_suspend(mdwc, false);
	if (!ret)
		atomic_set(&mdwc->pm_suspended, 1);

	return ret;
}

static int dwc3_msm_pm_freeze(struct device *dev)
{
	int ret = 0;
	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);

	dev_dbg(dev, "dwc3-msm PM freeze\n");
	dbg_event(0xFF, "PM Freeze", 0);

	flush_workqueue(mdwc->dwc3_wq);

	/* Resume the core to make sure we can power collapse it */
	ret = dwc3_msm_resume(mdwc);

	/*
	 * PHYs also needed to be power collapsed, so call the notify_disconnect
	 * before suspend to ensure it.
	 */
	usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH);
	mdwc->hs_phy->flags &= ~PHY_HOST_MODE;
	if (mdwc->ss_phy) {
		usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER);
		mdwc->ss_phy->flags &= ~PHY_HOST_MODE;
	}

	ret = dwc3_msm_suspend(mdwc, true);
	if (!ret)
		atomic_set(&mdwc->pm_suspended, 1);

@@ -4426,6 +4462,35 @@ static int dwc3_msm_pm_resume(struct device *dev)
	/* kick in otg state machine */
	queue_work(mdwc->dwc3_wq, &mdwc->resume_work);

	return 0;
}

static int dwc3_msm_pm_restore(struct device *dev)
{
	struct dwc3_msm *mdwc = dev_get_drvdata(dev);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);

	dev_dbg(dev, "dwc3-msm PM restore\n");
	dbg_event(0xFF, "PM Restore", 0);

	atomic_set(&mdwc->pm_suspended, 0);

	dwc3_msm_resume(mdwc);
	pm_runtime_disable(dev);
	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);

	/* Restore PHY flags if hibernated in host mode */
	if (mdwc->otg_state == OTG_STATE_A_HOST) {
		usb_phy_notify_connect(mdwc->hs_phy, USB_SPEED_HIGH);
		mdwc->hs_phy->flags |= PHY_HOST_MODE;
		if (mdwc->ss_phy) {
			usb_phy_notify_connect(mdwc->ss_phy, USB_SPEED_SUPER);
			mdwc->ss_phy->flags |= PHY_HOST_MODE;
		}
	}


	return 0;
}
#endif
@@ -4450,7 +4515,7 @@ static int dwc3_msm_runtime_suspend(struct device *dev)
	dev_dbg(dev, "DWC3-msm runtime suspend\n");
	dbg_event(0xFF, "RT Sus", 0);

	return dwc3_msm_suspend(mdwc);
	return dwc3_msm_suspend(mdwc, false);
}

static int dwc3_msm_runtime_resume(struct device *dev)
@@ -4466,7 +4531,12 @@ static int dwc3_msm_runtime_resume(struct device *dev)
#endif

static const struct dev_pm_ops dwc3_msm_dev_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(dwc3_msm_pm_suspend, dwc3_msm_pm_resume)
	.suspend	= dwc3_msm_pm_suspend,
	.resume		= dwc3_msm_pm_resume,
	.freeze		= dwc3_msm_pm_freeze,
	.restore	= dwc3_msm_pm_restore,
	.thaw		= dwc3_msm_pm_restore,
	.poweroff	= dwc3_msm_pm_suspend,
	SET_RUNTIME_PM_OPS(dwc3_msm_runtime_suspend, dwc3_msm_runtime_resume,
				dwc3_msm_runtime_idle)
};
+36 −1
Original line number Diff line number Diff line
@@ -439,6 +439,39 @@ static int xhci_plat_runtime_idle(struct device *dev)
	return -EBUSY;
}

static int xhci_plat_pm_freeze(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	struct xhci_hcd *xhci = hcd_to_xhci(hcd);

	if (!xhci)
		return 0;

	dev_dbg(dev, "xhci-plat freeze\n");

	return xhci_suspend(xhci, false);
}

static int xhci_plat_pm_restore(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
	int ret;

	if (!xhci)
		return 0;

	dev_dbg(dev, "xhci-plat restore\n");

	ret = xhci_resume(xhci, true);
	pm_runtime_disable(dev);
	pm_runtime_set_active(dev);
	pm_runtime_enable(dev);
	pm_runtime_mark_last_busy(dev);

	return ret;
}

static int xhci_plat_runtime_suspend(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -470,7 +503,9 @@ static int xhci_plat_runtime_resume(struct device *dev)
}

static const struct dev_pm_ops xhci_plat_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(NULL, NULL)
	.freeze		= xhci_plat_pm_freeze,
	.restore	= xhci_plat_pm_restore,
	.thaw		= xhci_plat_pm_restore,
	SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend, xhci_plat_runtime_resume,
			   xhci_plat_runtime_idle)
};
+4 −2
Original line number Diff line number Diff line
@@ -947,7 +947,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
	struct usb_hcd		*hcd = xhci_to_hcd(xhci);
	u32			command;

	if (!hcd->state)
	if (!hcd->state || xhci->suspended)
		return 0;

	if (hcd->state != HC_STATE_SUSPENDED ||
@@ -1017,6 +1017,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
	/* step 5: remove core well power */
	/* synchronize irq when using MSI-X */
	xhci_msix_sync_irqs(xhci);
	xhci->suspended = true;

	return rc;
}
@@ -1036,7 +1037,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
	int			retval = 0;
	bool			comp_timer_running = false;

	if (!hcd->state)
	if (!hcd->state || !xhci->suspended)
		return 0;

	/* Wait a bit if either of the roothubs need to settle from the
@@ -1173,6 +1174,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)

	/* Re-enable port polling. */
	xhci_dbg(xhci, "%s: starting port polling.\n", __func__);
	xhci->suspended = false;
	set_bit(HCD_FLAG_POLL_RH, &xhci->shared_hcd->flags);
	usb_hcd_poll_rh_status(xhci->shared_hcd);
	set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
Loading