]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/clk/samsung/clk-exynos-audss.c
Merge branch 'clk-pm-runtime' into clk-next
[mirror_ubuntu-bionic-kernel.git] / drivers / clk / samsung / clk-exynos-audss.c
index b117783ed40478b03be6abe4ac1b107df8d7a424..5bfc92ee3129a5fec4df14c58f7024a64ed15058 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 
 #include <dt-bindings/clock/exynos-audss-clk.h>
 
@@ -36,14 +37,13 @@ static struct clk *epll;
 #define ASS_CLK_DIV 0x4
 #define ASS_CLK_GATE 0x8
 
-#ifdef CONFIG_PM_SLEEP
 static unsigned long reg_save[][2] = {
        { ASS_CLK_SRC,  0 },
        { ASS_CLK_DIV,  0 },
        { ASS_CLK_GATE, 0 },
 };
 
-static int exynos_audss_clk_suspend(struct device *dev)
+static int __maybe_unused exynos_audss_clk_suspend(struct device *dev)
 {
        int i;
 
@@ -53,7 +53,7 @@ static int exynos_audss_clk_suspend(struct device *dev)
        return 0;
 }
 
-static int exynos_audss_clk_resume(struct device *dev)
+static int __maybe_unused exynos_audss_clk_resume(struct device *dev)
 {
        int i;
 
@@ -62,7 +62,6 @@ static int exynos_audss_clk_resume(struct device *dev)
 
        return 0;
 }
-#endif /* CONFIG_PM_SLEEP */
 
 struct exynos_audss_clk_drvdata {
        unsigned int has_adma_clk:1;
@@ -135,6 +134,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
        const struct exynos_audss_clk_drvdata *variant;
        struct clk_hw **clk_table;
        struct resource *res;
+       struct device *dev = &pdev->dev;
        int i, ret = 0;
 
        variant = of_device_get_match_data(&pdev->dev);
@@ -142,15 +142,15 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
                return -EINVAL;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       reg_base = devm_ioremap_resource(&pdev->dev, res);
+       reg_base = devm_ioremap_resource(dev, res);
        if (IS_ERR(reg_base)) {
-               dev_err(&pdev->dev, "failed to map audss registers\n");
+               dev_err(dev, "failed to map audss registers\n");
                return PTR_ERR(reg_base);
        }
 
        epll = ERR_PTR(-ENODEV);
 
-       clk_data = devm_kzalloc(&pdev->dev,
+       clk_data = devm_kzalloc(dev,
                                sizeof(*clk_data) +
                                sizeof(*clk_data->hws) * EXYNOS_AUDSS_MAX_CLKS,
                                GFP_KERNEL);
@@ -160,8 +160,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
        clk_data->num = variant->num_clks;
        clk_table = clk_data->hws;
 
-       pll_ref = devm_clk_get(&pdev->dev, "pll_ref");
-       pll_in = devm_clk_get(&pdev->dev, "pll_in");
+       pll_ref = devm_clk_get(dev, "pll_ref");
+       pll_in = devm_clk_get(dev, "pll_in");
        if (!IS_ERR(pll_ref))
                mout_audss_p[0] = __clk_get_name(pll_ref);
        if (!IS_ERR(pll_in)) {
@@ -172,88 +172,103 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
 
                        ret = clk_prepare_enable(epll);
                        if (ret) {
-                               dev_err(&pdev->dev,
+                               dev_err(dev,
                                        "failed to prepare the epll clock\n");
                                return ret;
                        }
                }
        }
-       clk_table[EXYNOS_MOUT_AUDSS] = clk_hw_register_mux(NULL, "mout_audss",
+
+       /*
+        * Enable runtime PM here to allow the clock core using runtime PM
+        * for the registered clocks. Additionally, we increase the runtime
+        * PM usage count before registering the clocks, to prevent the
+        * clock core from runtime suspending the device.
+        */
+       pm_runtime_get_noresume(dev);
+       pm_runtime_set_active(dev);
+       pm_runtime_enable(dev);
+
+       clk_table[EXYNOS_MOUT_AUDSS] = clk_hw_register_mux(dev, "mout_audss",
                                mout_audss_p, ARRAY_SIZE(mout_audss_p),
                                CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
                                reg_base + ASS_CLK_SRC, 0, 1, 0, &lock);
 
-       cdclk = devm_clk_get(&pdev->dev, "cdclk");
-       sclk_audio = devm_clk_get(&pdev->dev, "sclk_audio");
+       cdclk = devm_clk_get(dev, "cdclk");
+       sclk_audio = devm_clk_get(dev, "sclk_audio");
        if (!IS_ERR(cdclk))
                mout_i2s_p[1] = __clk_get_name(cdclk);
        if (!IS_ERR(sclk_audio))
                mout_i2s_p[2] = __clk_get_name(sclk_audio);
-       clk_table[EXYNOS_MOUT_I2S] = clk_hw_register_mux(NULL, "mout_i2s",
+       clk_table[EXYNOS_MOUT_I2S] = clk_hw_register_mux(dev, "mout_i2s",
                                mout_i2s_p, ARRAY_SIZE(mout_i2s_p),
                                CLK_SET_RATE_NO_REPARENT,
                                reg_base + ASS_CLK_SRC, 2, 2, 0, &lock);
 
-       clk_table[EXYNOS_DOUT_SRP] = clk_hw_register_divider(NULL, "dout_srp",
+       clk_table[EXYNOS_DOUT_SRP] = clk_hw_register_divider(dev, "dout_srp",
                                "mout_audss", CLK_SET_RATE_PARENT,
                                reg_base + ASS_CLK_DIV, 0, 4, 0, &lock);
 
-       clk_table[EXYNOS_DOUT_AUD_BUS] = clk_hw_register_divider(NULL,
+       clk_table[EXYNOS_DOUT_AUD_BUS] = clk_hw_register_divider(dev,
                                "dout_aud_bus", "dout_srp", CLK_SET_RATE_PARENT,
                                reg_base + ASS_CLK_DIV, 4, 4, 0, &lock);
 
-       clk_table[EXYNOS_DOUT_I2S] = clk_hw_register_divider(NULL, "dout_i2s",
+       clk_table[EXYNOS_DOUT_I2S] = clk_hw_register_divider(dev, "dout_i2s",
                                "mout_i2s", 0, reg_base + ASS_CLK_DIV, 8, 4, 0,
                                &lock);
 
-       clk_table[EXYNOS_SRP_CLK] = clk_hw_register_gate(NULL, "srp_clk",
+       clk_table[EXYNOS_SRP_CLK] = clk_hw_register_gate(dev, "srp_clk",
                                "dout_srp", CLK_SET_RATE_PARENT,
                                reg_base + ASS_CLK_GATE, 0, 0, &lock);
 
-       clk_table[EXYNOS_I2S_BUS] = clk_hw_register_gate(NULL, "i2s_bus",
+       clk_table[EXYNOS_I2S_BUS] = clk_hw_register_gate(dev, "i2s_bus",
                                "dout_aud_bus", CLK_SET_RATE_PARENT,
                                reg_base + ASS_CLK_GATE, 2, 0, &lock);
 
-       clk_table[EXYNOS_SCLK_I2S] = clk_hw_register_gate(NULL, "sclk_i2s",
+       clk_table[EXYNOS_SCLK_I2S] = clk_hw_register_gate(dev, "sclk_i2s",
                                "dout_i2s", CLK_SET_RATE_PARENT,
                                reg_base + ASS_CLK_GATE, 3, 0, &lock);
 
-       clk_table[EXYNOS_PCM_BUS] = clk_hw_register_gate(NULL, "pcm_bus",
+       clk_table[EXYNOS_PCM_BUS] = clk_hw_register_gate(dev, "pcm_bus",
                                 "sclk_pcm", CLK_SET_RATE_PARENT,
                                reg_base + ASS_CLK_GATE, 4, 0, &lock);
 
-       sclk_pcm_in = devm_clk_get(&pdev->dev, "sclk_pcm_in");
+       sclk_pcm_in = devm_clk_get(dev, "sclk_pcm_in");
        if (!IS_ERR(sclk_pcm_in))
                sclk_pcm_p = __clk_get_name(sclk_pcm_in);
-       clk_table[EXYNOS_SCLK_PCM] = clk_hw_register_gate(NULL, "sclk_pcm",
+       clk_table[EXYNOS_SCLK_PCM] = clk_hw_register_gate(dev, "sclk_pcm",
                                sclk_pcm_p, CLK_SET_RATE_PARENT,
                                reg_base + ASS_CLK_GATE, 5, 0, &lock);
 
        if (variant->has_adma_clk) {
-               clk_table[EXYNOS_ADMA] = clk_hw_register_gate(NULL, "adma",
+               clk_table[EXYNOS_ADMA] = clk_hw_register_gate(dev, "adma",
                                "dout_srp", CLK_SET_RATE_PARENT,
                                reg_base + ASS_CLK_GATE, 9, 0, &lock);
        }
 
        for (i = 0; i < clk_data->num; i++) {
                if (IS_ERR(clk_table[i])) {
-                       dev_err(&pdev->dev, "failed to register clock %d\n", i);
+                       dev_err(dev, "failed to register clock %d\n", i);
                        ret = PTR_ERR(clk_table[i]);
                        goto unregister;
                }
        }
 
-       ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get,
+       ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get,
                                     clk_data);
        if (ret) {
-               dev_err(&pdev->dev, "failed to add clock provider\n");
+               dev_err(dev, "failed to add clock provider\n");
                goto unregister;
        }
 
+       pm_runtime_put_sync(dev);
+
        return 0;
 
 unregister:
        exynos_audss_clk_teardown();
+       pm_runtime_put_sync(dev);
+       pm_runtime_disable(dev);
 
        if (!IS_ERR(epll))
                clk_disable_unprepare(epll);
@@ -266,6 +281,7 @@ static int exynos_audss_clk_remove(struct platform_device *pdev)
        of_clk_del_provider(pdev->dev.of_node);
 
        exynos_audss_clk_teardown();
+       pm_runtime_disable(&pdev->dev);
 
        if (!IS_ERR(epll))
                clk_disable_unprepare(epll);
@@ -274,8 +290,10 @@ static int exynos_audss_clk_remove(struct platform_device *pdev)
 }
 
 static const struct dev_pm_ops exynos_audss_clk_pm_ops = {
-       SET_LATE_SYSTEM_SLEEP_PM_OPS(exynos_audss_clk_suspend,
-                                    exynos_audss_clk_resume)
+       SET_RUNTIME_PM_OPS(exynos_audss_clk_suspend, exynos_audss_clk_resume,
+                          NULL)
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+                                    pm_runtime_force_resume)
 };
 
 static struct platform_driver exynos_audss_clk_driver = {