Commit 16b7e0cc authored by Johan Hovold's avatar Johan Hovold Committed by Greg Kroah-Hartman
Browse files

USB: xhci-plat: fix legacy PHY double init



Commits 7b8ef22e ("usb: xhci: plat: Add USB phy support") and
9134c1fd ("usb: xhci: plat: Add USB 3.0 phy support") added support
for looking up legacy PHYs from the sysdev devicetree node and
initialising them.

This broke drivers such as dwc3 which manages PHYs themself as the PHYs
would now be initialised twice, something which specifically can lead to
resources being left enabled during suspend (e.g. with the
usb_phy_generic PHY driver).

As the dwc3 driver uses driver-name matching for the xhci platform
device, fix this by only looking up and initialising PHYs for devices
that have been matched using OF.

Note that checking that the platform device has a devicetree node would
currently be sufficient, but that could lead to subtle breakages in case
anyone ever tries to reuse an ancestor's node.

Fixes: 7b8ef22e ("usb: xhci: plat: Add USB phy support")
Fixes: 9134c1fd ("usb: xhci: plat: Add USB 3.0 phy support")
Cc: stable@vger.kernel.org      # 4.1
Cc: Maxime Ripard <mripard@kernel.org>
Cc: Stanley Chang <stanley_chang@realtek.com>
Signed-off-by: default avatarJohan Hovold <johan+linaro@kernel.org>
Tested-by: default avatarStefan Eichenberger <stefan.eichenberger@toradex.com>
Tested-by: default avatarStanley Chang <stanley_chang@realtek.com>
Link: https://lore.kernel.org/r/20231103164323.14294-1-johan+linaro@kernel.org


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 4b435764
Loading
Loading
Loading
Loading
+30 −20
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/usb/phy.h>
#include <linux/slab.h>
@@ -148,7 +149,7 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
	int			ret;
	int			irq;
	struct xhci_plat_priv	*priv = NULL;

	bool			of_match;

	if (usb_disabled())
		return -ENODEV;
@@ -253,6 +254,12 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
					 &xhci->imod_interval);
	}

	/*
	 * Drivers such as dwc3 manages PHYs themself (and rely on driver name
	 * matching for the xhci platform device).
	 */
	of_match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
	if (of_match) {
		hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev, "usb-phy", 0);
		if (IS_ERR(hcd->usb_phy)) {
			ret = PTR_ERR(hcd->usb_phy);
@@ -264,6 +271,7 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
			if (ret)
				goto disable_clk;
		}
	}

	hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);

@@ -285,6 +293,7 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
			goto dealloc_usb2_hcd;
		}

		if (of_match) {
			xhci->shared_hcd->usb_phy = devm_usb_get_phy_by_phandle(sysdev,
										"usb-phy", 1);
			if (IS_ERR(xhci->shared_hcd->usb_phy)) {
@@ -295,6 +304,7 @@ int xhci_plat_probe(struct platform_device *pdev, struct device *sysdev, const s
					dev_err(sysdev, "%s init usb3phy fail (ret=%d)\n",
						__func__, ret);
			}
		}

		xhci->shared_hcd->tpl_support = hcd->tpl_support;
	}