]> www.infradead.org Git - linux.git/commitdiff
clk: samsung: exynos5433: Extract PM support to common ARM64 layer
authorSam Protsenko <semen.protsenko@linaro.org>
Tue, 7 Mar 2023 00:24:23 +0000 (18:24 -0600)
committerKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Tue, 7 Mar 2023 07:38:54 +0000 (08:38 +0100)
Exynos5433 clock driver implements PM support internally, which might be
also useful for other Exynos clock drivers. Extract all PM related code
from clk-exynos5433 to common ARM64 functions.

Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
Link: https://lore.kernel.org/r/20230307002423.24454-4-semen.protsenko@linaro.org
Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
drivers/clk/samsung/clk-exynos-arm64.c
drivers/clk/samsung/clk-exynos-arm64.h
drivers/clk/samsung/clk-exynos5433.c

index 60fd820c14aa925434d00713c953822cbb08014a..7d8937caf22acc08966e363a086c04f12353785c 100644 (file)
@@ -10,6 +10,9 @@
  */
 #include <linux/clk.h>
 #include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
 
 #include "clk-exynos-arm64.h"
 
 #define GATE_OFF_START         0x2000
 #define GATE_OFF_END           0x2fff
 
+struct exynos_arm64_cmu_data {
+       struct samsung_clk_reg_dump *clk_save;
+       unsigned int nr_clk_save;
+       const struct samsung_clk_reg_dump *clk_suspend;
+       unsigned int nr_clk_suspend;
+
+       struct clk *clk;
+       struct clk **pclks;
+       int nr_pclks;
+
+       struct samsung_clk_provider *ctx;
+};
+
 /**
  * exynos_arm64_init_clocks - Set clocks initial configuration
  * @np:                        CMU device tree node with "reg" property (CMU addr)
@@ -76,10 +92,16 @@ static int __init exynos_arm64_enable_bus_clk(struct device *dev,
        if (!cmu->clk_name)
                return 0;
 
-       if (dev)
+       if (dev) {
+               struct exynos_arm64_cmu_data *data;
+
                parent_clk = clk_get(dev, cmu->clk_name);
-       else
+               data = dev_get_drvdata(dev);
+               if (data)
+                       data->clk = parent_clk;
+       } else {
                parent_clk = of_clk_get_by_name(np, cmu->clk_name);
+       }
 
        if (IS_ERR(parent_clk))
                return PTR_ERR(parent_clk);
@@ -87,6 +109,46 @@ static int __init exynos_arm64_enable_bus_clk(struct device *dev,
        return clk_prepare_enable(parent_clk);
 }
 
+static int __init exynos_arm64_cmu_prepare_pm(struct device *dev,
+               const struct samsung_cmu_info *cmu)
+{
+       struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
+       int i;
+
+       data->clk_save = samsung_clk_alloc_reg_dump(cmu->clk_regs,
+                                                   cmu->nr_clk_regs);
+       if (!data->clk_save)
+               return -ENOMEM;
+
+       data->nr_clk_save = cmu->nr_clk_regs;
+       data->clk_suspend = cmu->suspend_regs;
+       data->nr_clk_suspend = cmu->nr_suspend_regs;
+       data->nr_pclks = of_clk_get_parent_count(dev->of_node);
+       if (!data->nr_pclks)
+               return 0;
+
+       data->pclks = devm_kcalloc(dev, sizeof(struct clk *), data->nr_pclks,
+                                  GFP_KERNEL);
+       if (!data->pclks) {
+               kfree(data->clk_save);
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < data->nr_pclks; i++) {
+               struct clk *clk = of_clk_get(dev->of_node, i);
+
+               if (IS_ERR(clk)) {
+                       kfree(data->clk_save);
+                       while (--i >= 0)
+                               clk_put(data->pclks[i]);
+                       return PTR_ERR(clk);
+               }
+               data->pclks[i] = clk;
+       }
+
+       return 0;
+}
+
 /**
  * exynos_arm64_register_cmu - Register specified Exynos CMU domain
  * @dev:       Device object; may be NULL if this function is not being
@@ -117,3 +179,113 @@ void __init exynos_arm64_register_cmu(struct device *dev,
        exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs);
        samsung_cmu_register_one(np, cmu);
 }
+
+/**
+ * exynos_arm64_register_cmu_pm - Register Exynos CMU domain with PM support
+ *
+ * @pdev:      Platform device object
+ * @set_manual:        If true, set gate clocks to manual mode
+ *
+ * It's a version of exynos_arm64_register_cmu() with PM support. Should be
+ * called from probe function of platform driver.
+ *
+ * Return: 0 on success, or negative error code on error.
+ */
+int __init exynos_arm64_register_cmu_pm(struct platform_device *pdev,
+                                       bool set_manual)
+{
+       const struct samsung_cmu_info *cmu;
+       struct device *dev = &pdev->dev;
+       struct device_node *np = dev->of_node;
+       struct exynos_arm64_cmu_data *data;
+       void __iomem *reg_base;
+       int ret;
+
+       cmu = of_device_get_match_data(dev);
+
+       data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, data);
+
+       ret = exynos_arm64_cmu_prepare_pm(dev, cmu);
+       if (ret)
+               return ret;
+
+       /*
+        * Try to boot even if the parent clock enablement fails, as it might be
+        * already enabled by bootloader.
+        */
+       ret = exynos_arm64_enable_bus_clk(dev, NULL, cmu);
+       if (ret)
+               dev_err(dev, "%s: could not enable bus clock %s; err = %d\n",
+                      __func__, cmu->clk_name, ret);
+
+       if (set_manual)
+               exynos_arm64_init_clocks(np, cmu->clk_regs, cmu->nr_clk_regs);
+
+       reg_base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(reg_base))
+               return PTR_ERR(reg_base);
+
+       data->ctx = samsung_clk_init(dev, reg_base, cmu->nr_clk_ids);
+
+       /*
+        * 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);
+
+       samsung_cmu_register_clocks(data->ctx, cmu);
+       samsung_clk_of_add_provider(dev->of_node, data->ctx);
+       pm_runtime_put_sync(dev);
+
+       return 0;
+}
+
+int exynos_arm64_cmu_suspend(struct device *dev)
+{
+       struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
+       int i;
+
+       samsung_clk_save(data->ctx->reg_base, data->clk_save,
+                        data->nr_clk_save);
+
+       for (i = 0; i < data->nr_pclks; i++)
+               clk_prepare_enable(data->pclks[i]);
+
+       /* For suspend some registers have to be set to certain values */
+       samsung_clk_restore(data->ctx->reg_base, data->clk_suspend,
+                           data->nr_clk_suspend);
+
+       for (i = 0; i < data->nr_pclks; i++)
+               clk_disable_unprepare(data->pclks[i]);
+
+       clk_disable_unprepare(data->clk);
+
+       return 0;
+}
+
+int exynos_arm64_cmu_resume(struct device *dev)
+{
+       struct exynos_arm64_cmu_data *data = dev_get_drvdata(dev);
+       int i;
+
+       clk_prepare_enable(data->clk);
+
+       for (i = 0; i < data->nr_pclks; i++)
+               clk_prepare_enable(data->pclks[i]);
+
+       samsung_clk_restore(data->ctx->reg_base, data->clk_save,
+                           data->nr_clk_save);
+
+       for (i = 0; i < data->nr_pclks; i++)
+               clk_disable_unprepare(data->pclks[i]);
+
+       return 0;
+}
index 0dd174693935dc095f8589c333180e0dccaa12c1..969979e714bc63a5e5e85181d04e52659f3274af 100644 (file)
@@ -16,5 +16,8 @@
 
 void exynos_arm64_register_cmu(struct device *dev,
                struct device_node *np, const struct samsung_cmu_info *cmu);
+int exynos_arm64_register_cmu_pm(struct platform_device *pdev, bool set_manual);
+int exynos_arm64_cmu_suspend(struct device *dev);
+int exynos_arm64_cmu_resume(struct device *dev);
 
 #endif /* __CLK_EXYNOS_ARM64_H */
index eb72bf2aaee8fd66965d97a9daa45b5e9163eeac..ed43233649aeb5e83b6f087de68d656f23882b76 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/clk-provider.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
-#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
@@ -19,6 +18,7 @@
 
 #include "clk.h"
 #include "clk-cpu.h"
+#include "clk-exynos-arm64.h"
 #include "clk-pll.h"
 
 /*
@@ -5478,160 +5478,9 @@ static const struct samsung_cmu_info imem_cmu_info __initconst = {
        .clk_name               = "aclk_imem_200",
 };
 
-struct exynos5433_cmu_data {
-       struct samsung_clk_reg_dump *clk_save;
-       unsigned int nr_clk_save;
-       const struct samsung_clk_reg_dump *clk_suspend;
-       unsigned int nr_clk_suspend;
-
-       struct clk *clk;
-       struct clk **pclks;
-       int nr_pclks;
-
-       /* must be the last entry */
-       struct samsung_clk_provider ctx;
-};
-
-static int __maybe_unused exynos5433_cmu_suspend(struct device *dev)
-{
-       struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
-       int i;
-
-       samsung_clk_save(data->ctx.reg_base, data->clk_save,
-                        data->nr_clk_save);
-
-       for (i = 0; i < data->nr_pclks; i++)
-               clk_prepare_enable(data->pclks[i]);
-
-       /* for suspend some registers have to be set to certain values */
-       samsung_clk_restore(data->ctx.reg_base, data->clk_suspend,
-                           data->nr_clk_suspend);
-
-       for (i = 0; i < data->nr_pclks; i++)
-               clk_disable_unprepare(data->pclks[i]);
-
-       clk_disable_unprepare(data->clk);
-
-       return 0;
-}
-
-static int __maybe_unused exynos5433_cmu_resume(struct device *dev)
-{
-       struct exynos5433_cmu_data *data = dev_get_drvdata(dev);
-       int i;
-
-       clk_prepare_enable(data->clk);
-
-       for (i = 0; i < data->nr_pclks; i++)
-               clk_prepare_enable(data->pclks[i]);
-
-       samsung_clk_restore(data->ctx.reg_base, data->clk_save,
-                           data->nr_clk_save);
-
-       for (i = 0; i < data->nr_pclks; i++)
-               clk_disable_unprepare(data->pclks[i]);
-
-       return 0;
-}
-
 static int __init exynos5433_cmu_probe(struct platform_device *pdev)
 {
-       const struct samsung_cmu_info *info;
-       struct exynos5433_cmu_data *data;
-       struct samsung_clk_provider *ctx;
-       struct device *dev = &pdev->dev;
-       void __iomem *reg_base;
-       int i;
-
-       info = of_device_get_match_data(dev);
-
-       data = devm_kzalloc(dev,
-                           struct_size(data, ctx.clk_data.hws, info->nr_clk_ids),
-                           GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-       ctx = &data->ctx;
-
-       reg_base = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(reg_base))
-               return PTR_ERR(reg_base);
-
-       for (i = 0; i < info->nr_clk_ids; ++i)
-               ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
-
-       ctx->clk_data.num = info->nr_clk_ids;
-       ctx->reg_base = reg_base;
-       ctx->dev = dev;
-       spin_lock_init(&ctx->lock);
-
-       data->clk_save = samsung_clk_alloc_reg_dump(info->clk_regs,
-                                                   info->nr_clk_regs);
-       if (!data->clk_save)
-               return -ENOMEM;
-       data->nr_clk_save = info->nr_clk_regs;
-       data->clk_suspend = info->suspend_regs;
-       data->nr_clk_suspend = info->nr_suspend_regs;
-       data->nr_pclks = of_clk_get_parent_count(dev->of_node);
-
-       if (data->nr_pclks > 0) {
-               data->pclks = devm_kcalloc(dev, sizeof(struct clk *),
-                                          data->nr_pclks, GFP_KERNEL);
-               if (!data->pclks) {
-                       kfree(data->clk_save);
-                       return -ENOMEM;
-               }
-               for (i = 0; i < data->nr_pclks; i++) {
-                       struct clk *clk = of_clk_get(dev->of_node, i);
-
-                       if (IS_ERR(clk)) {
-                               kfree(data->clk_save);
-                               while (--i >= 0)
-                                       clk_put(data->pclks[i]);
-                               return PTR_ERR(clk);
-                       }
-                       data->pclks[i] = clk;
-               }
-       }
-
-       if (info->clk_name)
-               data->clk = clk_get(dev, info->clk_name);
-       clk_prepare_enable(data->clk);
-
-       platform_set_drvdata(pdev, data);
-
-       /*
-        * 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);
-
-       if (info->pll_clks)
-               samsung_clk_register_pll(ctx, info->pll_clks,
-                                        info->nr_pll_clks);
-       if (info->mux_clks)
-               samsung_clk_register_mux(ctx, info->mux_clks,
-                                        info->nr_mux_clks);
-       if (info->div_clks)
-               samsung_clk_register_div(ctx, info->div_clks,
-                                        info->nr_div_clks);
-       if (info->gate_clks)
-               samsung_clk_register_gate(ctx, info->gate_clks,
-                                         info->nr_gate_clks);
-       if (info->fixed_clks)
-               samsung_clk_register_fixed_rate(ctx, info->fixed_clks,
-                                               info->nr_fixed_clks);
-       if (info->fixed_factor_clks)
-               samsung_clk_register_fixed_factor(ctx, info->fixed_factor_clks,
-                                                 info->nr_fixed_factor_clks);
-
-       samsung_clk_of_add_provider(dev->of_node, ctx);
-       pm_runtime_put_sync(dev);
-
-       return 0;
+       return exynos_arm64_register_cmu_pm(pdev, false);
 }
 
 static const struct of_device_id exynos5433_cmu_of_match[] = {
@@ -5679,7 +5528,7 @@ static const struct of_device_id exynos5433_cmu_of_match[] = {
 };
 
 static const struct dev_pm_ops exynos5433_cmu_pm_ops = {
-       SET_RUNTIME_PM_OPS(exynos5433_cmu_suspend, exynos5433_cmu_resume,
+       SET_RUNTIME_PM_OPS(exynos_arm64_cmu_suspend, exynos_arm64_cmu_resume,
                           NULL)
        SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
                                     pm_runtime_force_resume)