diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c index b7fcb469c87a..0d4d1216f2dd 100644 --- a/drivers/clk/mvebu/common.c +++ b/drivers/clk/mvebu/common.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "common.h" @@ -177,14 +178,17 @@ struct clk_gating_ctrl { spinlock_t *lock; struct clk **gates; int num_gates; + void __iomem *base; + u32 saved_reg; }; #define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) +static struct clk_gating_ctrl *ctrl; + static struct clk *clk_gating_get_src( struct of_phandle_args *clkspec, void *data) { - struct clk_gating_ctrl *ctrl = (struct clk_gating_ctrl *)data; int n; if (clkspec->args_count < 1) @@ -199,15 +203,35 @@ static struct clk *clk_gating_get_src( return ERR_PTR(-ENODEV); } +static int mvebu_clk_gating_suspend(void) +{ + ctrl->saved_reg = readl(ctrl->base); + return 0; +} + +static void mvebu_clk_gating_resume(void) +{ + writel(ctrl->saved_reg, ctrl->base); +} + +static struct syscore_ops clk_gate_syscore_ops = { + .suspend = mvebu_clk_gating_suspend, + .resume = mvebu_clk_gating_resume, +}; + void __init mvebu_clk_gating_setup(struct device_node *np, const struct clk_gating_soc_desc *desc) { - struct clk_gating_ctrl *ctrl; struct clk *clk; void __iomem *base; const char *default_parent = NULL; int n; + if (ctrl) { + pr_err("mvebu-clk-gating: cannot instantiate more than one gatable clock device\n"); + return; + } + base = of_iomap(np, 0); if (WARN_ON(!base)) return; @@ -225,6 +249,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, /* lock must already be initialized */ ctrl->lock = &ctrl_gating_lock; + ctrl->base = base; + /* Count, allocate, and register clock gates */ for (n = 0; desc[n].name;) n++; @@ -246,6 +272,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np, of_clk_add_provider(np, clk_gating_get_src, ctrl); + register_syscore_ops(&clk_gate_syscore_ops); + return; gates_out: kfree(ctrl);