Message ID | 1566299605-15641-12-git-send-email-aisheng.dong@nxp.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
Series | clk: imx8: add new clock binding for better pm support | expand |
Quoting Dong Aisheng (2019-08-20 04:13:25) > diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c > index 3c092a0..4df0818 100644 > --- a/drivers/clk/imx/clk-lpcg-scu.c > +++ b/drivers/clk/imx/clk-lpcg-scu.c > @@ -33,6 +33,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) > @@ -112,5 +115,35 @@ 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; > } > + > +int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev) static? > +{ > + 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; > +} > + > +int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) static? > +{ > + struct clk_lpcg_scu *clk = dev_get_drvdata(dev); > + > + /* FIXME: double write in case a failure */ What does this mean? 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) > +};
On Sat, Sep 7, 2019 at 9:22 PM Stephen Boyd <sboyd@kernel.org> wrote: > > Quoting Dong Aisheng (2019-08-20 04:13:25) > > diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c > > index 3c092a0..4df0818 100644 > > --- a/drivers/clk/imx/clk-lpcg-scu.c > > +++ b/drivers/clk/imx/clk-lpcg-scu.c > > @@ -33,6 +33,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) > > @@ -112,5 +115,35 @@ 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; > > } > > + > > +int __maybe_unused imx_clk_lpcg_scu_suspend(struct device *dev) > > static? > > > +{ > > + 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; > > +} > > + > > +int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) > > static? > Will fix. > > +{ > > + struct clk_lpcg_scu *clk = dev_get_drvdata(dev); > > + > > + /* FIXME: double write in case a failure */ > > What does this mean? Sometimes writes don't work unless the CPU issues > them twice? > Yes, it's a hardware timing issues. Regards Aisheng > > + 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) > > +};
diff --git a/drivers/clk/imx/clk-imx8qxp-lpcg.c b/drivers/clk/imx/clk-imx8qxp-lpcg.c index ca9bd58..885498f 100644 --- a/drivers/clk/imx/clk-imx8qxp-lpcg.c +++ b/drivers/clk/imx/clk-imx8qxp-lpcg.c @@ -338,6 +338,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, diff --git a/drivers/clk/imx/clk-lpcg-scu.c b/drivers/clk/imx/clk-lpcg-scu.c index 3c092a0..4df0818 100644 --- a/drivers/clk/imx/clk-lpcg-scu.c +++ b/drivers/clk/imx/clk-lpcg-scu.c @@ -33,6 +33,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) @@ -112,5 +115,35 @@ 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; } + +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; +} + +int __maybe_unused imx_clk_lpcg_scu_resume(struct device *dev) +{ + struct clk_lpcg_scu *clk = dev_get_drvdata(dev); + + /* FIXME: double write in case a failure */ + 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) +}; diff --git a/drivers/clk/imx/clk-scu.h b/drivers/clk/imx/clk-scu.h index 84efda3..6d4b6e2 100644 --- a/drivers/clk/imx/clk-scu.h +++ b/drivers/clk/imx/clk-scu.h @@ -12,6 +12,7 @@ extern u32 clock_cells; 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,
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. Signed-off-by: Dong Aisheng <aisheng.dong@nxp.com> --- ChangeLog: v3: new patch --- drivers/clk/imx/clk-imx8qxp-lpcg.c | 1 + drivers/clk/imx/clk-lpcg-scu.c | 33 +++++++++++++++++++++++++++++++++ drivers/clk/imx/clk-scu.h | 1 + 3 files changed, 35 insertions(+)