dwc3: Add QTI MSM platform specific feature and other changes
This change adds QTI MSM platform specific USB related features
and fixes.
Change-Id: I0f733d05f3f88a4a734d8489b5eb548391ab3af3
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
index ed56bf9..c86abfc 100644
--- a/drivers/usb/host/xhci-plat.c
+++ b/drivers/usb/host/xhci-plat.c
@@ -198,6 +198,15 @@
goto put_hcd;
}
+ if (pdev->dev.parent)
+ pm_runtime_resume(pdev->dev.parent);
+
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
+
xhci = hcd_to_xhci(hcd);
match = of_match_node(usb_xhci_of_match, pdev->dev.of_node);
if (match) {
@@ -238,14 +247,17 @@
goto put_usb3_hcd;
}
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
if (ret)
goto disable_usb_phy;
- ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED | IRQF_ONESHOT);
if (ret)
goto dealloc_usb2_hcd;
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
return 0;
@@ -274,6 +286,8 @@
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct clk *clk = xhci->clk;
+ pm_runtime_disable(&dev->dev);
+
usb_remove_hcd(xhci->shared_hcd);
usb_phy_shutdown(hcd->usb_phy);
@@ -287,33 +301,57 @@
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int xhci_plat_suspend(struct device *dev)
+#ifdef CONFIG_PM
+static int xhci_plat_runtime_idle(struct device *dev)
{
- struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
-
/*
- * xhci_suspend() needs `do_wakeup` to know whether host is allowed
- * to do wakeup during suspend. Since xhci_plat_suspend is currently
- * only designed for system suspend, device_may_wakeup() is enough
- * to dertermine whether host is allowed to do wakeup. Need to
- * reconsider this when xhci_plat_suspend enlarges its scope, e.g.,
- * also applies to runtime suspend.
+ * When pm_runtime_put_autosuspend() is called on this device,
+ * after this idle callback returns the PM core will schedule the
+ * autosuspend if there is any remaining time until expiry. However,
+ * when reaching this point because the child_count becomes 0, the
+ * core does not honor autosuspend in that case and results in
+ * idle/suspend happening immediately. In order to have a delay
+ * before suspend we have to call pm_runtime_autosuspend() manually.
*/
- return xhci_suspend(xhci, device_may_wakeup(dev));
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_autosuspend(dev);
+ return -EBUSY;
}
-static int xhci_plat_resume(struct device *dev)
+static int xhci_plat_runtime_suspend(struct device *dev)
{
- struct usb_hcd *hcd = dev_get_drvdata(dev);
- struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
- return xhci_resume(xhci, 0);
+ if (!xhci)
+ return 0;
+
+ dev_dbg(dev, "xhci-plat runtime suspend\n");
+
+ return xhci_suspend(xhci, true);
+}
+
+static int xhci_plat_runtime_resume(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 runtime resume\n");
+
+ ret = xhci_resume(xhci, false);
+ pm_runtime_mark_last_busy(dev);
+
+ return ret;
}
static const struct dev_pm_ops xhci_plat_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(xhci_plat_suspend, xhci_plat_resume)
+ SET_SYSTEM_SLEEP_PM_OPS(NULL, NULL)
+ SET_RUNTIME_PM_OPS(xhci_plat_runtime_suspend, xhci_plat_runtime_resume,
+ xhci_plat_runtime_idle)
};
#define DEV_PM_OPS (&xhci_plat_pm_ops)
#else