clk:starfive:isp:Add runtime and system pm control
authorXingyu Wu <xingyu.wu@starfivetech.com>
Fri, 30 Sep 2022 07:26:59 +0000 (15:26 +0800)
committermason.huo <mason.huo@starfivetech.com>
Thu, 27 Oct 2022 05:57:03 +0000 (13:57 +0800)
Add runtime and system pm in isp clock tree driver.

Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
drivers/clk/starfive/clk-starfive-jh7110-gen.c [changed mode: 0755->0644]
drivers/clk/starfive/clk-starfive-jh7110-isp.c [changed mode: 0755->0644]
drivers/clk/starfive/clk-starfive-jh7110-sys.c [changed mode: 0755->0644]

old mode 100755 (executable)
new mode 100644 (file)
index 42e6176..9aac50d
@@ -16,6 +16,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/of_device.h>
+#include <linux/pm_runtime.h>
 
 #include <dt-bindings/clock/starfive-jh7110-clkgen.h>
 #include "clk-starfive-jh7110.h"
@@ -53,6 +54,19 @@ void __iomem *jh7110_clk_reg_addr_get(struct jh7110_clk *clk)
 static u32 jh7110_clk_reg_get(struct jh7110_clk *clk)
 {
        void __iomem *reg = jh7110_clk_reg_addr_get(clk);
+       if (clk->reg_flags == JH7110_CLK_ISP_FLAG) {
+               int ret;
+               struct jh7110_clk_priv *priv = jh7110_priv_from(clk);
+
+               if (pm_runtime_suspended(priv->dev)) {
+                       ret = pm_runtime_get_sync(priv->dev);
+                       if (ret < 0) {
+                               dev_err(priv->dev, "cannot resume device :%d.\n", ret);
+                               return 0;
+                       }
+                       pm_runtime_put(priv->dev);
+               }
+       }
 
        return readl_relaxed(reg);
 }
@@ -69,7 +83,7 @@ static void jh7110_clk_reg_rmw(struct jh7110_clk *clk, u32 mask, u32 value)
                || clk->idx == JH7110_UART5_CLK_CORE)
                && (value != JH7110_CLK_ENABLE))
                value  <<= 8;
-       value |= readl_relaxed(reg) & ~mask;
+       value |= jh7110_clk_reg_get(clk) & ~mask;
        writel_relaxed(value, reg);
        spin_unlock_irqrestore(&priv->rmw_lock, flags);
 }
old mode 100755 (executable)
new mode 100644 (file)
index a8fc3c5..b30cc76
 #define JH7110_ISP_TOP_CLK_BIST_APB_CLKGEN     (JH7110_CLK_ISP_END + 2)
 #define JH7110_ISP_TOP_CLK_DVP_CLKGEN          (JH7110_CLK_ISP_END + 3)
 
+struct isp_init_crg {
+       int num_clks;
+       struct clk_bulk_data *clks;
+       struct reset_control *rsts;
+};
+
 static const struct jh7110_clk_data jh7110_clk_isp_data[] __initconst = {
        //syscon
        JH7110__DIV(JH7110_DOM4_APB_FUNC, "dom4_apb_func",
@@ -72,7 +78,92 @@ static const struct jh7110_clk_data jh7110_clk_isp_data[] __initconst = {
 static struct clk_bulk_data isp_top_clks[] = {
        { .id = "u0_dom_isp_top_clk_dom_isp_top_clk_ispcore_2x" },
        { .id = "u0_dom_isp_top_clk_dom_isp_top_clk_isp_axi" },
-       { .id = "u0_sft7110_noc_bus_clk_isp_axi" },
+};
+
+static int jh7110_isp_crg_get(struct device *dev, struct isp_init_crg *crg)
+{
+       int ret;
+
+       crg->rsts = devm_reset_control_array_get_shared(dev);
+       if (IS_ERR(crg->rsts)) {
+               dev_err(dev, "rst get failed\n");
+               return PTR_ERR(crg->rsts);
+       }
+
+       crg->clks = isp_top_clks;
+       crg->num_clks = ARRAY_SIZE(isp_top_clks);
+       ret = clk_bulk_get(dev, crg->num_clks, crg->clks);
+       if (ret) {
+               dev_err(dev, "clks get failed: %d\n", ret);
+               goto clks_get_failed;
+       }
+
+       return 0;
+
+clks_get_failed:
+       reset_control_assert(crg->rsts);
+       reset_control_put(crg->rsts);
+
+       return ret;
+}
+
+static int jh7110_isp_crg_enable(struct device *dev, struct isp_init_crg *crg, bool enable)
+{
+       int ret;
+
+       dev_dbg(dev, "starfive jh7110 isp clk&rst %sable\n", enable ? "en":"dis");
+       if (enable) {
+               ret = reset_control_deassert(crg->rsts);
+               if (ret) {
+                       dev_err(dev, "rst deassert failed: %d\n", ret);
+                       goto crg_failed;
+               }
+
+               ret = clk_bulk_prepare_enable(crg->num_clks, crg->clks);
+               if (ret) {
+                       dev_err(dev, "clks enable failed: %d\n", ret);
+                       goto crg_failed;
+               }
+       } else {
+               clk_bulk_disable_unprepare(crg->num_clks, crg->clks);
+       }
+
+       return 0;
+crg_failed:
+       return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int clk_isp_system_suspend(struct device *dev)
+{
+       return pm_runtime_force_suspend(dev);
+}
+
+static int clk_isp_system_resume(struct device *dev)
+{
+       return pm_runtime_force_resume(dev);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int clk_isp_runtime_suspend(struct device *dev)
+{
+       struct isp_init_crg *crg = dev_get_drvdata(dev);
+
+       return jh7110_isp_crg_enable(dev, crg, false);
+}
+
+static int clk_isp_runtime_resume(struct device *dev)
+{
+       struct isp_init_crg *crg = dev_get_drvdata(dev);
+
+       return jh7110_isp_crg_enable(dev, crg, true);
+}
+#endif
+
+static const struct dev_pm_ops clk_isp_pm_ops = {
+       SET_RUNTIME_PM_OPS(clk_isp_runtime_suspend, clk_isp_runtime_resume, NULL)
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(clk_isp_system_suspend, clk_isp_system_resume)
 };
 
 static struct clk_hw *jh7110_isp_clk_get(struct of_phandle_args *clkspec,
@@ -93,9 +184,8 @@ static struct clk_hw *jh7110_isp_clk_get(struct of_phandle_args *clkspec,
 static int __init clk_starfive_jh7110_isp_probe(struct platform_device *pdev)
 {
        struct jh7110_clk_priv *priv;
+       struct isp_init_crg *crg;
        unsigned int idx;
-       struct reset_control *rsts;
-       int num_clks;
        int ret = 0;
 
        priv = devm_kzalloc(&pdev->dev, struct_size(priv, reg,
@@ -109,36 +199,22 @@ static int __init clk_starfive_jh7110_isp_probe(struct platform_device *pdev)
        if (IS_ERR(priv->isp_base))
                return PTR_ERR(priv->isp_base);
 
+       crg = devm_kzalloc(&pdev->dev, sizeof(*crg), GFP_KERNEL);
+       if (!crg)
+               return -ENOMEM;
+       dev_set_drvdata(&pdev->dev, crg);
+
+       ret = jh7110_isp_crg_get(&pdev->dev, crg);
+       if (ret)
+               goto init_failed;
+
+       pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
        pm_runtime_enable(&pdev->dev);
        ret = pm_runtime_get_sync(&pdev->dev);
        if (ret < 0) {
                dev_err(&pdev->dev, "failed to get pm runtime: %d\n", ret);
-               return ret;
-       }
-
-       rsts = devm_reset_control_array_get_shared(priv->dev);
-       if (!IS_ERR(rsts)) {
-               ret = reset_control_deassert(rsts);
-               if (ret) {
-                       dev_err(priv->dev, "rst deassert failed: %d\n", ret);
-                       goto rsts_deassert_failed;
-               }
-       } else {
-               dev_err(priv->dev, "rst get failed\n");
-               return PTR_ERR(rsts);
-       }
-
-       num_clks = ARRAY_SIZE(isp_top_clks);
-       ret = clk_bulk_get(priv->dev, num_clks, isp_top_clks);
-       if (!ret) {
-               ret = clk_bulk_prepare_enable(num_clks, isp_top_clks);
-               if (ret) {
-                       dev_err(priv->dev, "clks enable failed: %d\n", ret);
-                       goto clks_enable_failed;
-               }
-       } else {
-               dev_err(priv->dev, "clks get failed: %d\n", ret);
-               goto clks_get_failed;
+               goto init_failed;
        }
 
        priv->pll[PLL_OFI(JH7110_U3_PCLK_MUX_FUNC_PCLK)] =
@@ -247,28 +323,20 @@ static int __init clk_starfive_jh7110_isp_probe(struct platform_device *pdev)
 
                ret = devm_clk_hw_register(priv->dev, &clk->hw);
                if (ret)
-                       return ret;
+                       goto init_failed;
        }
 
        ret = devm_of_clk_add_hw_provider(priv->dev, jh7110_isp_clk_get, priv);
        if (ret)
-               return ret;
+               goto init_failed;
 
-       clk_bulk_put(num_clks, isp_top_clks);
-       reset_control_put(rsts);
+       pm_runtime_put_sync(&pdev->dev);
 
        dev_info(&pdev->dev, "starfive JH7110 clk_isp init successfully.");
        return 0;
 
-clks_enable_failed:
-       clk_bulk_put(num_clks, isp_top_clks);
-clks_get_failed:
-       reset_control_assert(rsts);
-rsts_deassert_failed:
-       reset_control_put(rsts);
-
+init_failed:
        return ret;
-
 }
 
 static const struct of_device_id clk_starfive_jh7110_isp_match[] = {
@@ -281,6 +349,7 @@ static struct platform_driver clk_starfive_jh7110_isp_driver = {
                .driver = {
                .name = "clk-starfive-jh7110-isp",
                .of_match_table = clk_starfive_jh7110_isp_match,
+               .pm     = &clk_isp_pm_ops,
        },
 };
 module_platform_driver(clk_starfive_jh7110_isp_driver);
old mode 100755 (executable)
new mode 100644 (file)
index 73051bb..cc19ec6
@@ -138,7 +138,7 @@ static const struct jh7110_clk_data jh7110_clk_sys_data[] __initconst = {
                        GATE_FLAG_NORMAL, JH7110_ISP_AXI),
        JH7110_GATE(JH7110_NOC_BUS_CLK_ISP_AXI,
                        "u0_sft7110_noc_bus_clk_isp_axi",
-                       CLK_IGNORE_UNUSED, JH7110_ISP_AXI),
+                       CLK_IS_CRITICAL, JH7110_ISP_AXI),
        //HIFI4
        JH7110__DIV(JH7110_HIFI4_CORE, "hifi4_core", 15, JH7110_BUS_ROOT),
        JH7110__DIV(JH7110_HIFI4_AXI, "hifi4_axi", 2, JH7110_HIFI4_CORE),