From 68850661b51e40faf9f5f21e4b7a083476da3f99 Mon Sep 17 00:00:00 2001 From: William Wu Date: Wed, 14 Sep 2022 10:42:50 +0800 Subject: [PATCH] usb: host: ehci-platform: Add device_link between the ehci and companion Rockchip ehci controller has companion ohci controller, and the ohci depends on the ehci, if the ehci controller has been suspend or shutdown, it shouldn't access the ohci controller, otherwise, the system may hang in ohci_readl or ohci_writel on Rockchip platforms. In order to enforce suspend/resume and shutdown ordering, this commit creates link between the ehci and ohci. This link avoids to suspend or shutdown ehci before its companion ohci. Corresponding, DL_FLAG_AUTOREMOVE_CONSUMER can't be added, then device_link_removed should be added explicitly. Meanwhile, the ehci must not be resumed after its companion if the companion is the consumer device of ehci. Signed-off-by: William Wu Change-Id: If2935c651341917251c2178a6833357a73b71079 --- drivers/usb/host/ehci-platform.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 3e48737f893f..e6f0871375b9 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -276,6 +276,8 @@ static int ehci_platform_probe(struct platform_device *dev) struct ehci_platform_priv *priv; struct ehci_hcd *ehci; int err, irq, clk = 0; + struct device *companion_dev; + struct device_link *link; if (usb_disabled()) return -ENODEV; @@ -414,6 +416,21 @@ static int ehci_platform_probe(struct platform_device *dev) if (of_usb_get_phy_mode(dev->dev.of_node) == USBPHY_INTERFACE_MODE_HSIC) ehci_usic_init(hcd); + if (of_device_is_compatible(dev->dev.of_node, + "rockchip,rk3588-ehci")) { + companion_dev = usb_of_get_companion_dev(hcd->self.controller); + if (companion_dev) { + link = device_link_add(companion_dev, hcd->self.controller, + DL_FLAG_STATELESS); + if (!link) { + dev_err(&dev->dev, "Unable to link %s\n", + dev_name(companion_dev)); + err = -EINVAL; + goto err_power; + } + } + } + device_wakeup_enable(hcd->self.controller); device_enable_async_suspend(hcd->self.controller); platform_set_drvdata(dev, hcd); @@ -447,11 +464,19 @@ static int ehci_platform_remove(struct platform_device *dev) struct usb_hcd *hcd = platform_get_drvdata(dev); struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); + struct device *companion_dev; int clk; if (priv->quirk_poll) quirk_poll_end(priv); + if (of_device_is_compatible(dev->dev.of_node, + "rockchip,rk3588-ehci")) { + companion_dev = usb_of_get_companion_dev(hcd->self.controller); + if (companion_dev) + device_link_remove(companion_dev, hcd->self.controller); + } + usb_remove_hcd(hcd); if (pdata->power_off) @@ -510,7 +535,7 @@ static int __maybe_unused ehci_platform_resume(struct device *dev) } companion_dev = usb_of_get_companion_dev(hcd->self.controller); - if (companion_dev) { + if (companion_dev && !device_is_dependent(hcd->self.controller, companion_dev)) { device_pm_wait_for_dev(hcd->self.controller, companion_dev); put_device(companion_dev); }