Skip to content

Commit

Permalink
usb: host: ehci-platform: Add device_link between the ehci and companion
Browse files Browse the repository at this point in the history
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 <william.wu@rock-chips.com>
Change-Id: If2935c651341917251c2178a6833357a73b71079
  • Loading branch information
wuliangfeng authored and rkhuangtao committed Sep 15, 2022
1 parent 4e8841e commit 6885066
Showing 1 changed file with 26 additions and 1 deletion.
27 changes: 26 additions & 1 deletion drivers/usb/host/ehci-platform.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 6885066

Please sign in to comment.