diff options
author | Thierry Reding <treding@nvidia.com> | 2019-02-18 17:36:43 +0100 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2019-03-22 14:05:07 +0100 |
commit | 7fe5719b4364fe9b673c3763007915877f3922c0 (patch) | |
tree | 38281f003cf3cc46809c4b415ecf1009d92c6ac4 | |
parent | Merge branch 'reset/acquire' of git://git.pengutronix.de/git/pza/linux into f... (diff) | |
download | linux-7fe5719b4364fe9b673c3763007915877f3922c0.tar.xz linux-7fe5719b4364fe9b673c3763007915877f3922c0.zip |
soc/tegra: pmc: Implement acquire/release for resets
By implementing the acquire/release protocol, the resets can be shared
with other drivers that also adhere to this protocol. This will be used
for example by the SOR driver to put hardware into a known good state,
irrespective of whether or not the power domain can be reset.
Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r-- | drivers/soc/tegra/pmc.c | 39 |
1 files changed, 33 insertions, 6 deletions
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 0df258518693..0c5f79528e5f 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -656,10 +656,15 @@ static int tegra_genpd_power_on(struct generic_pm_domain *domain) int err; err = tegra_powergate_power_up(pg, true); - if (err) + if (err) { dev_err(dev, "failed to turn on PM domain %s: %d\n", pg->genpd.name, err); + goto out; + } + reset_control_release(pg->reset); + +out: return err; } @@ -669,10 +674,18 @@ static int tegra_genpd_power_off(struct generic_pm_domain *domain) struct device *dev = pg->pmc->dev; int err; + err = reset_control_acquire(pg->reset); + if (err < 0) { + pr_err("failed to acquire resets: %d\n", err); + return err; + } + err = tegra_powergate_power_down(pg); - if (err) + if (err) { dev_err(dev, "failed to turn off PM domain %s: %d\n", pg->genpd.name, err); + reset_control_release(pg->reset); + } return err; } @@ -937,20 +950,34 @@ static int tegra_powergate_of_get_resets(struct tegra_powergate *pg, struct device *dev = pg->pmc->dev; int err; - pg->reset = of_reset_control_array_get_exclusive(np); + pg->reset = of_reset_control_array_get_exclusive_released(np); if (IS_ERR(pg->reset)) { err = PTR_ERR(pg->reset); dev_err(dev, "failed to get device resets: %d\n", err); return err; } - if (off) + err = reset_control_acquire(pg->reset); + if (err < 0) { + pr_err("failed to acquire resets: %d\n", err); + goto out; + } + + if (off) { err = reset_control_assert(pg->reset); - else + } else { err = reset_control_deassert(pg->reset); + if (err < 0) + goto out; - if (err) + reset_control_release(pg->reset); + } + +out: + if (err) { + reset_control_release(pg->reset); reset_control_put(pg->reset); + } return err; } |