| From 5caf43318aa2f14f82d496ca2debff200fead56a Mon Sep 17 00:00:00 2001 |
| From: Martin Blumenstingl <martin.blumenstingl@googlemail.com> |
| Date: Sat, 3 Mar 2018 22:43:03 +0100 |
| Subject: [PATCH 0894/1795] usb: add a flag to skip PHY initialization to |
| struct usb_hcd |
| |
| The USB HCD core driver parses the device-tree node for "phys" and |
| "usb-phys" properties. It also manages the power state of these PHYs |
| automatically. |
| However, drivers may opt-out of this behavior by setting "phy" or |
| "usb_phy" in struct usb_hcd to a non-null value. An example where this |
| is required is the "Qualcomm USB2 controller", implemented by the |
| chipidea driver. The hardware requires that the PHY is only powered on |
| after the "reset completed" event from the controller is received. |
| |
| A follow-up patch will allow the USB HCD core driver to manage more than |
| one PHY. Add a new "skip_phy_initialization" bitflag to struct usb_hcd |
| so drivers can opt-out of any PHY management provided by the USB HCD |
| core driver. |
| |
| This also updates the existing drivers so they use the new flag if they |
| want to opt out of the PHY management provided by the USB HCD core |
| driver. This means that for these drivers the new "multiple PHY" |
| handling (which will be added in a follow-up patch) will be disabled as |
| well. |
| |
| Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> |
| Acked-by: Peter Chen <peter.chen@nxp.com> |
| Tested-by: Neil Armstrong <narmstrong@baylibre.con> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| (cherry picked from commit 4e88d4c083016454f179686529ae65d70b933b58) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> |
| --- |
| drivers/usb/chipidea/host.c | 6 ++---- |
| drivers/usb/core/hcd.c | 4 ++-- |
| drivers/usb/host/ehci-fsl.c | 2 ++ |
| drivers/usb/host/ehci-platform.c | 4 ++-- |
| drivers/usb/host/ehci-tegra.c | 1 + |
| drivers/usb/host/ohci-omap.c | 1 + |
| drivers/usb/host/ohci-platform.c | 4 ++-- |
| drivers/usb/host/xhci-plat.c | 1 + |
| include/linux/usb/hcd.h | 6 ++++++ |
| 9 files changed, 19 insertions(+), 10 deletions(-) |
| |
| diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c |
| index a49e8567ac7d..9e26951f696c 100644 |
| --- a/drivers/usb/chipidea/host.c |
| +++ b/drivers/usb/chipidea/host.c |
| @@ -137,10 +137,8 @@ static int host_start(struct ci_hdrc *ci) |
| |
| hcd->power_budget = ci->platdata->power_budget; |
| hcd->tpl_support = ci->platdata->tpl_support; |
| - if (ci->phy) |
| - hcd->phy = ci->phy; |
| - else |
| - hcd->usb_phy = ci->usb_phy; |
| + if (ci->phy || ci->usb_phy) |
| + hcd->skip_phy_initialization = 1; |
| |
| ehci = hcd_to_ehci(hcd); |
| ehci->caps = ci->hw_bank.cap; |
| diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c |
| index 9fa30a6ada6e..d92c366d58b3 100644 |
| --- a/drivers/usb/core/hcd.c |
| +++ b/drivers/usb/core/hcd.c |
| @@ -2742,7 +2742,7 @@ int usb_add_hcd(struct usb_hcd *hcd, |
| int retval; |
| struct usb_device *rhdev; |
| |
| - if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->usb_phy) { |
| + if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->skip_phy_initialization) { |
| struct usb_phy *phy = usb_get_phy_dev(hcd->self.sysdev, 0); |
| |
| if (IS_ERR(phy)) { |
| @@ -2760,7 +2760,7 @@ int usb_add_hcd(struct usb_hcd *hcd, |
| } |
| } |
| |
| - if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) { |
| + if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->skip_phy_initialization) { |
| struct phy *phy = phy_get(hcd->self.sysdev, "usb"); |
| |
| if (IS_ERR(phy)) { |
| diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c |
| index 7c4bb32230d2..0831917321fe 100644 |
| --- a/drivers/usb/host/ehci-fsl.c |
| +++ b/drivers/usb/host/ehci-fsl.c |
| @@ -169,6 +169,8 @@ static int fsl_ehci_drv_probe(struct platform_device *pdev) |
| retval = -ENODEV; |
| goto err2; |
| } |
| + |
| + hcd->skip_phy_initialization = 1; |
| } |
| #endif |
| return retval; |
| diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c |
| index cb77af3a71c1..86d535fe5b44 100644 |
| --- a/drivers/usb/host/ehci-platform.c |
| +++ b/drivers/usb/host/ehci-platform.c |
| @@ -222,9 +222,9 @@ static int ehci_platform_probe(struct platform_device *dev) |
| if (IS_ERR(priv->phys[phy_num])) { |
| err = PTR_ERR(priv->phys[phy_num]); |
| goto err_put_hcd; |
| - } else if (!hcd->phy) { |
| + } else { |
| /* Avoiding phy_get() in usb_add_hcd() */ |
| - hcd->phy = priv->phys[phy_num]; |
| + hcd->skip_phy_initialization = 1; |
| } |
| } |
| |
| diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c |
| index fe8423e17877..ae5439f96530 100644 |
| --- a/drivers/usb/host/ehci-tegra.c |
| +++ b/drivers/usb/host/ehci-tegra.c |
| @@ -472,6 +472,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) |
| goto cleanup_clk_en; |
| } |
| hcd->usb_phy = u_phy; |
| + hcd->skip_phy_initialization = 1; |
| |
| tegra->needs_double_reset = of_property_read_bool(pdev->dev.of_node, |
| "nvidia,needs-double-reset"); |
| diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c |
| index 0201c49bc4fc..d8d35d456456 100644 |
| --- a/drivers/usb/host/ohci-omap.c |
| +++ b/drivers/usb/host/ohci-omap.c |
| @@ -230,6 +230,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) |
| } else { |
| return -EPROBE_DEFER; |
| } |
| + hcd->skip_phy_initialization = 1; |
| ohci->start_hnp = start_hnp; |
| } |
| #endif |
| diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c |
| index 908ebcfbc350..488b811b565f 100644 |
| --- a/drivers/usb/host/ohci-platform.c |
| +++ b/drivers/usb/host/ohci-platform.c |
| @@ -189,9 +189,9 @@ static int ohci_platform_probe(struct platform_device *dev) |
| if (IS_ERR(priv->phys[phy_num])) { |
| err = PTR_ERR(priv->phys[phy_num]); |
| goto err_put_hcd; |
| - } else if (!hcd->phy) { |
| + } else { |
| /* Avoiding phy_get() in usb_add_hcd() */ |
| - hcd->phy = priv->phys[phy_num]; |
| + hcd->skip_phy_initialization = 1; |
| } |
| } |
| |
| diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c |
| index c435df29cdb8..ea089fdda611 100644 |
| --- a/drivers/usb/host/xhci-plat.c |
| +++ b/drivers/usb/host/xhci-plat.c |
| @@ -284,6 +284,7 @@ static int xhci_plat_probe(struct platform_device *pdev) |
| ret = usb_phy_init(hcd->usb_phy); |
| if (ret) |
| goto put_usb3_hcd; |
| + hcd->skip_phy_initialization = 1; |
| } |
| |
| ret = usb_add_hcd(hcd, irq, IRQF_SHARED); |
| diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h |
| index 176900528822..693502c84c04 100644 |
| --- a/include/linux/usb/hcd.h |
| +++ b/include/linux/usb/hcd.h |
| @@ -151,6 +151,12 @@ struct usb_hcd { |
| unsigned msix_enabled:1; /* driver has MSI-X enabled? */ |
| unsigned msi_enabled:1; /* driver has MSI enabled? */ |
| unsigned remove_phy:1; /* auto-remove USB phy */ |
| + /* |
| + * do not manage the PHY state in the HCD core, instead let the driver |
| + * handle this (for example if the PHY can only be turned on after a |
| + * specific event) |
| + */ |
| + unsigned skip_phy_initialization:1; |
| |
| /* The next flag is a stopgap, to be removed when all the HCDs |
| * support the new root-hub polling mechanism. */ |
| -- |
| 2.19.0 |
| |