Commit 24a15252 authored by Dmitry Osipenko's avatar Dmitry Osipenko Committed by Thierry Reding

soc/tegra: fuse: Add runtime PM support

The Tegra FUSE belongs to the core power domain and we're going to enable
GENPD support for the core domain. Now FUSE device must be resumed using
runtime PM API in order to initialize the FUSE power state. Add runtime PM
support to the FUSE driver.
Signed-off-by: default avatarDmitry Osipenko <digetx@gmail.com>
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent a65a4ea1
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/sys_soc.h> #include <linux/sys_soc.h>
...@@ -210,6 +211,8 @@ static int tegra_fuse_probe(struct platform_device *pdev) ...@@ -210,6 +211,8 @@ static int tegra_fuse_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, fuse); platform_set_drvdata(pdev, fuse);
fuse->dev = &pdev->dev; fuse->dev = &pdev->dev;
pm_runtime_enable(&pdev->dev);
if (fuse->soc->probe) { if (fuse->soc->probe) {
err = fuse->soc->probe(fuse); err = fuse->soc->probe(fuse);
if (err < 0) if (err < 0)
...@@ -248,13 +251,40 @@ static int tegra_fuse_probe(struct platform_device *pdev) ...@@ -248,13 +251,40 @@ static int tegra_fuse_probe(struct platform_device *pdev)
restore: restore:
fuse->clk = NULL; fuse->clk = NULL;
fuse->base = base; fuse->base = base;
pm_runtime_disable(&pdev->dev);
return err; return err;
} }
static int __maybe_unused tegra_fuse_runtime_resume(struct device *dev)
{
int err;
err = clk_prepare_enable(fuse->clk);
if (err < 0) {
dev_err(dev, "failed to enable FUSE clock: %d\n", err);
return err;
}
return 0;
}
static int __maybe_unused tegra_fuse_runtime_suspend(struct device *dev)
{
clk_disable_unprepare(fuse->clk);
return 0;
}
static const struct dev_pm_ops tegra_fuse_pm = {
SET_RUNTIME_PM_OPS(tegra_fuse_runtime_suspend, tegra_fuse_runtime_resume,
NULL)
};
static struct platform_driver tegra_fuse_driver = { static struct platform_driver tegra_fuse_driver = {
.driver = { .driver = {
.name = "tegra-fuse", .name = "tegra-fuse",
.of_match_table = tegra_fuse_match, .of_match_table = tegra_fuse_match,
.pm = &tegra_fuse_pm,
.suppress_bind_attrs = true, .suppress_bind_attrs = true,
}, },
.probe = tegra_fuse_probe, .probe = tegra_fuse_probe,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/random.h> #include <linux/random.h>
#include <soc/tegra/fuse.h> #include <soc/tegra/fuse.h>
...@@ -46,6 +47,10 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) ...@@ -46,6 +47,10 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
u32 value = 0; u32 value = 0;
int err; int err;
err = pm_runtime_resume_and_get(fuse->dev);
if (err)
return err;
mutex_lock(&fuse->apbdma.lock); mutex_lock(&fuse->apbdma.lock);
fuse->apbdma.config.src_addr = fuse->phys + FUSE_BEGIN + offset; fuse->apbdma.config.src_addr = fuse->phys + FUSE_BEGIN + offset;
...@@ -66,8 +71,6 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) ...@@ -66,8 +71,6 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
reinit_completion(&fuse->apbdma.wait); reinit_completion(&fuse->apbdma.wait);
clk_prepare_enable(fuse->clk);
dmaengine_submit(dma_desc); dmaengine_submit(dma_desc);
dma_async_issue_pending(fuse->apbdma.chan); dma_async_issue_pending(fuse->apbdma.chan);
time_left = wait_for_completion_timeout(&fuse->apbdma.wait, time_left = wait_for_completion_timeout(&fuse->apbdma.wait,
...@@ -78,10 +81,9 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset) ...@@ -78,10 +81,9 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
else else
value = *fuse->apbdma.virt; value = *fuse->apbdma.virt;
clk_disable_unprepare(fuse->clk);
out: out:
mutex_unlock(&fuse->apbdma.lock); mutex_unlock(&fuse->apbdma.lock);
pm_runtime_put(fuse->dev);
return value; return value;
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/random.h> #include <linux/random.h>
#include <soc/tegra/fuse.h> #include <soc/tegra/fuse.h>
...@@ -52,15 +53,13 @@ static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset) ...@@ -52,15 +53,13 @@ static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
u32 value; u32 value;
int err; int err;
err = clk_prepare_enable(fuse->clk); err = pm_runtime_resume_and_get(fuse->dev);
if (err < 0) { if (err)
dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err);
return 0; return 0;
}
value = readl_relaxed(fuse->base + FUSE_BEGIN + offset); value = readl_relaxed(fuse->base + FUSE_BEGIN + offset);
clk_disable_unprepare(fuse->clk); pm_runtime_put(fuse->dev);
return value; return value;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment