clk: imx: lpcg: add suspend/resume support
authorDong Aisheng <aisheng.dong@nxp.com>
Wed, 29 Jul 2020 08:00:18 +0000 (16:00 +0800)
committerShawn Guo <shawnguo@kernel.org>
Mon, 26 Oct 2020 02:54:08 +0000 (10:54 +0800)
LPCG clock state may be lost when it's power domain is completely
off during system suspend/resume and we need save and restore the
state properly.

Reviewed-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com>
Signed-off-by: Shawn Guo <shawnguo@kernel.org>
drivers/clk/imx/clk-imx8qxp-lpcg.c
drivers/clk/imx/clk-lpcg-scu.c
drivers/clk/imx/clk-scu.h

index 50ab660..d3e905c 100644 (file)
@@ -364,6 +364,7 @@ static struct platform_driver imx8qxp_lpcg_clk_driver = {
        .driver = {
                .name = "imx8qxp-lpcg-clk",
                .of_match_table = imx8qxp_lpcg_match,
+               .pm = &imx_clk_lpcg_scu_pm_ops,
                .suppress_bind_attrs = true,
        },
        .probe = imx8qxp_lpcg_clk_probe,
index 4363ab6..77be763 100644 (file)
@@ -34,6 +34,9 @@ struct clk_lpcg_scu {
        void __iomem *reg;
        u8 bit_idx;
        bool hw_gate;
+
+       /* for state save&restore */
+       u32 state;
 };
 
 #define to_clk_lpcg_scu(_hw) container_of(_hw, struct clk_lpcg_scu, hw)
@@ -113,6 +116,9 @@ struct clk_hw *__imx_clk_lpcg_scu(struct device *dev, const char *name,
                hw = ERR_PTR(ret);
        }
 
+       if (dev)
+               dev_set_drvdata(dev, clk);
+
        return hw;
 }
 
@@ -123,3 +129,34 @@ void imx_clk_lpcg_scu_unregister(struct clk_hw *hw)
        clk_hw_unregister(&clk->hw);
        kfree(clk);
 }
+
+static int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev)
+{
+       struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+
+       clk->state = readl_relaxed(clk->reg);
+       dev_dbg(dev, "save lpcg state 0x%x\n", clk->state);
+
+       return 0;
+}
+
+static int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev)
+{
+       struct clk_lpcg_scu *clk = dev_get_drvdata(dev);
+
+       /*
+        * FIXME: Sometimes writes don't work unless the CPU issues
+        * them twice
+        */
+
+       writel(clk->state, clk->reg);
+       writel(clk->state, clk->reg);
+       dev_dbg(dev, "restore lpcg state 0x%x\n", clk->state);
+
+       return 0;
+}
+
+const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(imx_clk_lpcg_scu_suspend,
+                                     imx_clk_lpcg_scu_resume)
+};
index faee1ba..e835216 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/of.h>
 
 extern struct list_head imx_scu_clks[];
+extern const struct dev_pm_ops imx_clk_lpcg_scu_pm_ops;
 
 int imx_clk_scu_init(struct device_node *np);
 struct clk_hw *imx_scu_of_clk_src_get(struct of_phandle_args *clkspec,