Commit ea0c5cba authored by Dong Aisheng's avatar Dong Aisheng Committed by Shawn Guo
Browse files

clk: imx: lpcg: add suspend/resume support



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: default avatarStephen Boyd <sboyd@kernel.org>
Signed-off-by: default avatarDong Aisheng <aisheng.dong@nxp.com>
Signed-off-by: default avatarShawn Guo <shawnguo@kernel.org>
parent 18cdbad4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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,
+37 −0
Original line number Diff line number Diff line
@@ -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)
};
+1 −0
Original line number Diff line number Diff line
@@ -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,