save and restore some clks, which might be changed in suspend. Signed-off-by: Tony Xie <xxx at rock-chips.com> Signed-off-by: Chris Zhong <zyw at rock-chips.com> Reviewed-by: Doug Anderson <dianders at chromium.org> Tested-by: Doug Anderson <dianders at chromium.org> --- Changes in v7: None Changes in v6: - modify comments Changes in v5: - modify comments Changes in v4: None Changes in v3: None Changes in v2: - __raw_readl/__raw_writel replaced by readl_relaxed/writel_relaxed drivers/clk/rockchip/clk-rk3288.c | 60 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c index 2327829..66a9cb0 100644 --- a/drivers/clk/rockchip/clk-rk3288.c +++ b/drivers/clk/rockchip/clk-rk3288.c @@ -16,6 +16,7 @@ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/syscore_ops.h> #include <dt-bindings/clock/rk3288-cru.h> #include "clk.h" @@ -762,6 +763,64 @@ static const char *rk3288_critical_clocks[] __initconst = { "hclk_peri", }; +#ifdef CONFIG_PM_SLEEP +static void __iomem *rk3288_cru_base; + +/* Some CRU registers will be reset in maskrom when the system + * wakes up from fastboot. + * So save them before suspend, restore them after resume. + */ +static const int rk3288_saved_cru_reg_ids[] = { + RK3288_MODE_CON, + RK3288_CLKSEL_CON(0), + RK3288_CLKSEL_CON(1), + RK3288_CLKSEL_CON(10), + RK3288_CLKSEL_CON(33), + RK3288_CLKSEL_CON(37), +}; + +static u32 rk3288_saved_cru_regs[ARRAY_SIZE(rk3288_saved_cru_reg_ids)]; + +static int rk3288_clk_suspend(void) +{ + int i, reg_id; + + for (i = 0; i < ARRAY_SIZE(rk3288_saved_cru_reg_ids); i++) { + reg_id = rk3288_saved_cru_reg_ids[i]; + + rk3288_saved_cru_regs[i] = + readl_relaxed(rk3288_cru_base + reg_id); + } + return 0; +} + +static void rk3288_clk_resume(void) +{ + int i, reg_id; + + for (i = ARRAY_SIZE(rk3288_saved_cru_reg_ids) - 1; i >= 0; i--) { + reg_id = rk3288_saved_cru_reg_ids[i]; + + writel_relaxed(rk3288_saved_cru_regs[i] | 0xffff0000, + rk3288_cru_base + reg_id); + } +} + +static struct syscore_ops rk3288_clk_syscore_ops = { + .suspend = rk3288_clk_suspend, + .resume = rk3288_clk_resume, +}; + +static void rk3288_clk_sleep_init(void __iomem *reg_base) +{ + rk3288_cru_base = reg_base; + register_syscore_ops(&rk3288_clk_syscore_ops); +} + +#else /* CONFIG_PM_SLEEP */ +static void rk3288_clk_sleep_init(void __iomem *reg_base) {} +#endif + static void __init rk3288_clk_init(struct device_node *np) { void __iomem *reg_base; @@ -810,5 +869,6 @@ static void __init rk3288_clk_init(struct device_node *np) ROCKCHIP_SOFTRST_HIWORD_MASK); rockchip_register_restart_notifier(RK3288_GLB_SRST_FST); + rk3288_clk_sleep_init(reg_base); } CLK_OF_DECLARE(rk3288_cru, "rockchip,rk3288-cru", rk3288_clk_init); -- 1.9.1