|
@@ -140,6 +140,7 @@ static enum exynos4_soc exynos4_soc;
|
|
#ifdef CONFIG_PM_SLEEP
|
|
#ifdef CONFIG_PM_SLEEP
|
|
static struct samsung_clk_reg_dump *exynos4_save_common;
|
|
static struct samsung_clk_reg_dump *exynos4_save_common;
|
|
static struct samsung_clk_reg_dump *exynos4_save_soc;
|
|
static struct samsung_clk_reg_dump *exynos4_save_soc;
|
|
|
|
+static struct samsung_clk_reg_dump *exynos4_save_pll;
|
|
|
|
|
|
/*
|
|
/*
|
|
* list of controller registers to be saved and restored during a
|
|
* list of controller registers to be saved and restored during a
|
|
@@ -165,6 +166,17 @@ static unsigned long exynos4x12_clk_save[] __initdata = {
|
|
E4X12_MPLL_CON0,
|
|
E4X12_MPLL_CON0,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static unsigned long exynos4_clk_pll_regs[] __initdata = {
|
|
|
|
+ EPLL_LOCK,
|
|
|
|
+ VPLL_LOCK,
|
|
|
|
+ EPLL_CON0,
|
|
|
|
+ EPLL_CON1,
|
|
|
|
+ EPLL_CON2,
|
|
|
|
+ VPLL_CON0,
|
|
|
|
+ VPLL_CON1,
|
|
|
|
+ VPLL_CON2,
|
|
|
|
+};
|
|
|
|
+
|
|
static unsigned long exynos4_clk_regs[] __initdata = {
|
|
static unsigned long exynos4_clk_regs[] __initdata = {
|
|
SRC_LEFTBUS,
|
|
SRC_LEFTBUS,
|
|
DIV_LEFTBUS,
|
|
DIV_LEFTBUS,
|
|
@@ -172,12 +184,6 @@ static unsigned long exynos4_clk_regs[] __initdata = {
|
|
SRC_RIGHTBUS,
|
|
SRC_RIGHTBUS,
|
|
DIV_RIGHTBUS,
|
|
DIV_RIGHTBUS,
|
|
GATE_IP_RIGHTBUS,
|
|
GATE_IP_RIGHTBUS,
|
|
- EPLL_CON0,
|
|
|
|
- EPLL_CON1,
|
|
|
|
- EPLL_CON2,
|
|
|
|
- VPLL_CON0,
|
|
|
|
- VPLL_CON1,
|
|
|
|
- VPLL_CON2,
|
|
|
|
SRC_TOP0,
|
|
SRC_TOP0,
|
|
SRC_TOP1,
|
|
SRC_TOP1,
|
|
SRC_CAM,
|
|
SRC_CAM,
|
|
@@ -238,23 +244,70 @@ static unsigned long exynos4_clk_regs[] __initdata = {
|
|
GATE_IP_CPU,
|
|
GATE_IP_CPU,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static const struct samsung_clk_reg_dump src_mask_suspend[] = {
|
|
|
|
+ { .offset = SRC_MASK_TOP, .value = 0x00000001, },
|
|
|
|
+ { .offset = SRC_MASK_CAM, .value = 0x11111111, },
|
|
|
|
+ { .offset = SRC_MASK_TV, .value = 0x00000111, },
|
|
|
|
+ { .offset = SRC_MASK_LCD0, .value = 0x00001111, },
|
|
|
|
+ { .offset = SRC_MASK_MAUDIO, .value = 0x00000001, },
|
|
|
|
+ { .offset = SRC_MASK_FSYS, .value = 0x01011111, },
|
|
|
|
+ { .offset = SRC_MASK_PERIL0, .value = 0x01111111, },
|
|
|
|
+ { .offset = SRC_MASK_PERIL1, .value = 0x01110111, },
|
|
|
|
+ { .offset = SRC_MASK_DMC, .value = 0x00010000, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static const struct samsung_clk_reg_dump src_mask_suspend_e4210[] = {
|
|
|
|
+ { .offset = E4210_SRC_MASK_LCD1, .value = 0x00001111, },
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define PLL_ENABLED (1 << 31)
|
|
|
|
+#define PLL_LOCKED (1 << 29)
|
|
|
|
+
|
|
|
|
+static void exynos4_clk_wait_for_pll(u32 reg)
|
|
|
|
+{
|
|
|
|
+ u32 pll_con;
|
|
|
|
+
|
|
|
|
+ pll_con = readl(reg_base + reg);
|
|
|
|
+ if (!(pll_con & PLL_ENABLED))
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ while (!(pll_con & PLL_LOCKED)) {
|
|
|
|
+ cpu_relax();
|
|
|
|
+ pll_con = readl(reg_base + reg);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
static int exynos4_clk_suspend(void)
|
|
static int exynos4_clk_suspend(void)
|
|
{
|
|
{
|
|
samsung_clk_save(reg_base, exynos4_save_common,
|
|
samsung_clk_save(reg_base, exynos4_save_common,
|
|
ARRAY_SIZE(exynos4_clk_regs));
|
|
ARRAY_SIZE(exynos4_clk_regs));
|
|
|
|
+ samsung_clk_save(reg_base, exynos4_save_pll,
|
|
|
|
+ ARRAY_SIZE(exynos4_clk_pll_regs));
|
|
|
|
|
|
- if (exynos4_soc == EXYNOS4210)
|
|
|
|
|
|
+ if (exynos4_soc == EXYNOS4210) {
|
|
samsung_clk_save(reg_base, exynos4_save_soc,
|
|
samsung_clk_save(reg_base, exynos4_save_soc,
|
|
ARRAY_SIZE(exynos4210_clk_save));
|
|
ARRAY_SIZE(exynos4210_clk_save));
|
|
- else
|
|
|
|
|
|
+ samsung_clk_restore(reg_base, src_mask_suspend_e4210,
|
|
|
|
+ ARRAY_SIZE(src_mask_suspend_e4210));
|
|
|
|
+ } else {
|
|
samsung_clk_save(reg_base, exynos4_save_soc,
|
|
samsung_clk_save(reg_base, exynos4_save_soc,
|
|
ARRAY_SIZE(exynos4x12_clk_save));
|
|
ARRAY_SIZE(exynos4x12_clk_save));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ samsung_clk_restore(reg_base, src_mask_suspend,
|
|
|
|
+ ARRAY_SIZE(src_mask_suspend));
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void exynos4_clk_resume(void)
|
|
static void exynos4_clk_resume(void)
|
|
{
|
|
{
|
|
|
|
+ samsung_clk_restore(reg_base, exynos4_save_pll,
|
|
|
|
+ ARRAY_SIZE(exynos4_clk_pll_regs));
|
|
|
|
+
|
|
|
|
+ exynos4_clk_wait_for_pll(EPLL_CON0);
|
|
|
|
+ exynos4_clk_wait_for_pll(VPLL_CON0);
|
|
|
|
+
|
|
samsung_clk_restore(reg_base, exynos4_save_common,
|
|
samsung_clk_restore(reg_base, exynos4_save_common,
|
|
ARRAY_SIZE(exynos4_clk_regs));
|
|
ARRAY_SIZE(exynos4_clk_regs));
|
|
|
|
|
|
@@ -289,9 +342,16 @@ static void exynos4_clk_sleep_init(void)
|
|
if (!exynos4_save_soc)
|
|
if (!exynos4_save_soc)
|
|
goto err_common;
|
|
goto err_common;
|
|
|
|
|
|
|
|
+ exynos4_save_pll = samsung_clk_alloc_reg_dump(exynos4_clk_pll_regs,
|
|
|
|
+ ARRAY_SIZE(exynos4_clk_pll_regs));
|
|
|
|
+ if (!exynos4_save_pll)
|
|
|
|
+ goto err_soc;
|
|
|
|
+
|
|
register_syscore_ops(&exynos4_clk_syscore_ops);
|
|
register_syscore_ops(&exynos4_clk_syscore_ops);
|
|
return;
|
|
return;
|
|
|
|
|
|
|
|
+err_soc:
|
|
|
|
+ kfree(exynos4_save_soc);
|
|
err_common:
|
|
err_common:
|
|
kfree(exynos4_save_common);
|
|
kfree(exynos4_save_common);
|
|
err_warn:
|
|
err_warn:
|