soc/tegra: fuse: Add runtime PM support
authorDmitry Osipenko <digetx@gmail.com>
Mon, 2 Aug 2021 22:13:34 +0000 (01:13 +0300)
committerThierry Reding <treding@nvidia.com>
Wed, 11 Aug 2021 09:55:04 +0000 (11:55 +0200)
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: Dmitry Osipenko <digetx@gmail.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
drivers/soc/tegra/fuse/fuse-tegra.c
drivers/soc/tegra/fuse/fuse-tegra20.c
drivers/soc/tegra/fuse/fuse-tegra30.c

index 2434c570b53c99d973a3a8d488720849246ecc84..747237865aff6fff175b05f335e800ad56f38ad5 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 
@@ -210,6 +211,8 @@ static int tegra_fuse_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, fuse);
        fuse->dev = &pdev->dev;
 
+       pm_runtime_enable(&pdev->dev);
+
        if (fuse->soc->probe) {
                err = fuse->soc->probe(fuse);
                if (err < 0)
@@ -248,13 +251,40 @@ static int tegra_fuse_probe(struct platform_device *pdev)
 restore:
        fuse->clk = NULL;
        fuse->base = base;
+       pm_runtime_disable(&pdev->dev);
        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 = {
        .driver = {
                .name = "tegra-fuse",
                .of_match_table = tegra_fuse_match,
+               .pm = &tegra_fuse_pm,
                .suppress_bind_attrs = true,
        },
        .probe = tegra_fuse_probe,
index 16aaa28573ac0ab5eecfae767579519902f6f49b..cd6a273707fe0891fe721b7d8f451830ae23b764 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kobject.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/random.h>
 
 #include <soc/tegra/fuse.h>
@@ -46,6 +47,10 @@ static u32 tegra20_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
        u32 value = 0;
        int err;
 
+       err = pm_runtime_resume_and_get(fuse->dev);
+       if (err)
+               return err;
+
        mutex_lock(&fuse->apbdma.lock);
 
        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)
 
        reinit_completion(&fuse->apbdma.wait);
 
-       clk_prepare_enable(fuse->clk);
-
        dmaengine_submit(dma_desc);
        dma_async_issue_pending(fuse->apbdma.chan);
        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)
        else
                value = *fuse->apbdma.virt;
 
-       clk_disable_unprepare(fuse->clk);
-
 out:
        mutex_unlock(&fuse->apbdma.lock);
+       pm_runtime_put(fuse->dev);
        return value;
 }
 
index c1aa7815bd6ecfa8b6f20ac83848af266698fca4..dd03565a39a4c9b4531853d0741cfc3604727b8a 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/of_device.h>
 #include <linux/of_address.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/random.h>
 
 #include <soc/tegra/fuse.h>
@@ -52,15 +53,13 @@ static u32 tegra30_fuse_read(struct tegra_fuse *fuse, unsigned int offset)
        u32 value;
        int err;
 
-       err = clk_prepare_enable(fuse->clk);
-       if (err < 0) {
-               dev_err(fuse->dev, "failed to enable FUSE clock: %d\n", err);
+       err = pm_runtime_resume_and_get(fuse->dev);
+       if (err)
                return 0;
-       }
 
        value = readl_relaxed(fuse->base + FUSE_BEGIN + offset);
 
-       clk_disable_unprepare(fuse->clk);
+       pm_runtime_put(fuse->dev);
 
        return value;
 }