clk: rockchip: rk3288: add suspend and resume
authorChris Zhong <zyw@rock-chips.com>
Fri, 7 Nov 2014 13:49:33 +0000 (21:49 +0800)
committerHeiko Stuebner <heiko@sntech.de>
Mon, 10 Nov 2014 19:56:42 +0000 (20:56 +0100)
save and restore some clks, which might be changed in suspend.

Signed-off-by: Tony Xie <xxx@rock-chips.com>
Signed-off-by: Chris Zhong <zyw@rock-chips.com>
Reviewed-by: Doug Anderson <dianders@chromium.org>
Tested-by: Doug Anderson <dianders@chromium.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
drivers/clk/rockchip/clk-rk3288.c

index bd9534a00737c1d62c30869d427e1f2134560c3a..1a9d03cf2b00489deaced0b3f31ed920c414aca7 100644 (file)
@@ -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"
 
@@ -764,6 +765,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;
@@ -812,5 +871,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);