Skip to content

Commit

Permalink
usb: xhci: tegra: Add support for managing powergates
Browse files Browse the repository at this point in the history
The Tegra XHCI controller requires that the XUSBA (for superspeed) and
XUSBC (for host) power-domains are enabled. Commit 8df1274
("soc/tegra: pmc: Enable XUSB partitions on boot") was added to force
on these power-domains if the XHCI driver is enabled while proper
power-domain support is added, to ensure the device did not hang on
boot. However, rather than forcing on these power-domains in the PMC
driver we can use the legacy Tegra powergate APIs to turn on these
power-domains during the probe of the Tegra XHCI driver.

In the near future we plan to move the Tegra XHCI driver to use the
generic PM domain framework for power-domains and so to prepare for
this only use the legacy Tegra powergate API if there is not PM
domain associated with device (ie. dev.pm_domain is NULL). Please
note that in the future the superspeed and host resets will be handled
by the generic PM domain provider and so these are only these are only
needed in the case where there is no generic PM domain.

Signed-off-by: Jon Hunter <[email protected]>
Acked-by: Thierry Reding <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
jonhunter authored and gregkh committed May 24, 2018
1 parent ee9e5f4 commit 58c3811
Showing 1 changed file with 49 additions and 19 deletions.
68 changes: 49 additions & 19 deletions drivers/usb/host/xhci-tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/slab.h>
#include <soc/tegra/pmc.h>

#include "xhci.h"

Expand Down Expand Up @@ -974,20 +975,6 @@ static int tegra_xusb_probe(struct platform_device *pdev)
if (IS_ERR(tegra->padctl))
return PTR_ERR(tegra->padctl);

tegra->host_rst = devm_reset_control_get(&pdev->dev, "xusb_host");
if (IS_ERR(tegra->host_rst)) {
err = PTR_ERR(tegra->host_rst);
dev_err(&pdev->dev, "failed to get xusb_host reset: %d\n", err);
goto put_padctl;
}

tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss");
if (IS_ERR(tegra->ss_rst)) {
err = PTR_ERR(tegra->ss_rst);
dev_err(&pdev->dev, "failed to get xusb_ss reset: %d\n", err);
goto put_padctl;
}

tegra->host_clk = devm_clk_get(&pdev->dev, "xusb_host");
if (IS_ERR(tegra->host_clk)) {
err = PTR_ERR(tegra->host_clk);
Expand Down Expand Up @@ -1051,11 +1038,48 @@ static int tegra_xusb_probe(struct platform_device *pdev)
goto put_padctl;
}

if (!pdev->dev.pm_domain) {
tegra->host_rst = devm_reset_control_get(&pdev->dev,
"xusb_host");
if (IS_ERR(tegra->host_rst)) {
err = PTR_ERR(tegra->host_rst);
dev_err(&pdev->dev,
"failed to get xusb_host reset: %d\n", err);
goto put_padctl;
}

tegra->ss_rst = devm_reset_control_get(&pdev->dev, "xusb_ss");
if (IS_ERR(tegra->ss_rst)) {
err = PTR_ERR(tegra->ss_rst);
dev_err(&pdev->dev, "failed to get xusb_ss reset: %d\n",
err);
goto put_padctl;
}

err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBA,
tegra->ss_clk,
tegra->ss_rst);
if (err) {
dev_err(&pdev->dev,
"failed to enable XUSBA domain: %d\n", err);
goto put_padctl;
}

err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_XUSBC,
tegra->host_clk,
tegra->host_rst);
if (err) {
dev_err(&pdev->dev,
"failed to enable XUSBC domain: %d\n", err);
goto disable_xusba;
}
}

tegra->supplies = devm_kcalloc(&pdev->dev, tegra->soc->num_supplies,
sizeof(*tegra->supplies), GFP_KERNEL);
if (!tegra->supplies) {
err = -ENOMEM;
goto put_padctl;
goto disable_xusbc;
}

for (i = 0; i < tegra->soc->num_supplies; i++)
Expand All @@ -1065,7 +1089,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
tegra->supplies);
if (err) {
dev_err(&pdev->dev, "failed to get regulators: %d\n", err);
goto put_padctl;
goto disable_xusbc;
}

for (i = 0; i < tegra->soc->num_types; i++)
Expand All @@ -1075,7 +1099,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
sizeof(*tegra->phys), GFP_KERNEL);
if (!tegra->phys) {
err = -ENOMEM;
goto put_padctl;
goto disable_xusbc;
}

for (i = 0, k = 0; i < tegra->soc->num_types; i++) {
Expand All @@ -1091,7 +1115,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
"failed to get PHY %s: %ld\n", prop,
PTR_ERR(phy));
err = PTR_ERR(phy);
goto put_padctl;
goto disable_xusbc;
}

tegra->phys[k++] = phy;
Expand All @@ -1102,7 +1126,7 @@ static int tegra_xusb_probe(struct platform_device *pdev)
dev_name(&pdev->dev));
if (!tegra->hcd) {
err = -ENOMEM;
goto put_padctl;
goto disable_xusbc;
}

/*
Expand Down Expand Up @@ -1198,6 +1222,12 @@ static int tegra_xusb_probe(struct platform_device *pdev)
disable_rpm:
pm_runtime_disable(&pdev->dev);
usb_put_hcd(tegra->hcd);
disable_xusbc:
if (!&pdev->dev.pm_domain)
tegra_powergate_power_off(TEGRA_POWERGATE_XUSBC);
disable_xusba:
if (!&pdev->dev.pm_domain)
tegra_powergate_power_off(TEGRA_POWERGATE_XUSBA);
put_padctl:
tegra_xusb_padctl_put(tegra->padctl);
return err;
Expand Down

0 comments on commit 58c3811

Please sign in to comment.