From d680c76eccd9222031ee30dcee5fdedba2467610 Mon Sep 17 00:00:00 2001 From: Francesco VIRLINZI Date: Wed, 11 Mar 2009 07:40:54 +0000 Subject: sh: clkfwk: add clk_set_parent/clk_get_parent This patch adds the clk_set_parent/clk_get_parent routines to the sh clock framework. Signed-off-by: Francesco Virlinzi Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/clock.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'arch/sh/kernel/cpu/clock.c') diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 7b17137536d..332a1798547 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -239,6 +239,35 @@ void clk_recalc_rate(struct clk *clk) } EXPORT_SYMBOL_GPL(clk_recalc_rate); +int clk_set_parent(struct clk *clk, struct clk *parent) +{ + int ret = -EINVAL; + struct clk *old; + + if (!parent || !clk) + return ret; + + old = clk->parent; + if (likely(clk->ops && clk->ops->set_parent)) { + unsigned long flags; + spin_lock_irqsave(&clock_lock, flags); + ret = clk->ops->set_parent(clk, parent); + spin_unlock_irqrestore(&clock_lock, flags); + clk->parent = (ret ? old : parent); + } + + if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) + propagate_rate(clk); + return ret; +} +EXPORT_SYMBOL_GPL(clk_set_parent); + +struct clk *clk_get_parent(struct clk *clk) +{ + return clk->parent; +} +EXPORT_SYMBOL_GPL(clk_get_parent); + long clk_round_rate(struct clk *clk, unsigned long rate) { if (likely(clk->ops && clk->ops->round_rate)) { -- cgit v1.2.3-70-g09d2 From 4a55026fd7a08074676e87932578ff9e327e82a3 Mon Sep 17 00:00:00 2001 From: Francesco VIRLINZI Date: Wed, 11 Mar 2009 07:42:05 +0000 Subject: sh: clkfwk: Add resume from hibernation support. This patch adds PM support to the clock framework. With this, resume from hibernation is properly supported. Signed-off-by: Francesco Virlinzi Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/clock.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) (limited to 'arch/sh/kernel/cpu/clock.c') diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 332a1798547..3209a8740fa 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -20,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -358,6 +360,68 @@ static int show_clocks(char *buf, char **start, off_t off, return p - buf; } +#ifdef CONFIG_PM +static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) +{ + static pm_message_t prev_state; + struct clk *clkp; + + switch (state.event) { + case PM_EVENT_ON: + /* Resumeing from hibernation */ + if (prev_state.event == PM_EVENT_FREEZE) { + list_for_each_entry(clkp, &clock_list, node) + if (likely(clkp->ops)) { + if (likely(clkp->ops->set_parent)) + clkp->ops->set_parent(clkp, + clkp->parent); + if (likely(clkp->ops->set_rate)) + clkp->ops->set_rate(clkp, + clkp->rate, NO_CHANGE); + else if (likely(clkp->ops->recalc)) + clkp->ops->recalc(clkp); + } + } + break; + case PM_EVENT_FREEZE: + break; + case PM_EVENT_SUSPEND: + break; + } + + prev_state = state; + return 0; +} + +static int clks_sysdev_resume(struct sys_device *dev) +{ + return clks_sysdev_suspend(dev, PMSG_ON); +} + +static struct sysdev_class clks_sysdev_class = { + .name = "clks", +}; + +static struct sysdev_driver clks_sysdev_driver = { + .suspend = clks_sysdev_suspend, + .resume = clks_sysdev_resume, +}; + +static struct sys_device clks_sysdev_dev = { + .cls = &clks_sysdev_class, +}; + +static int __init clk_sysdev_init(void) +{ + sysdev_class_register(&clks_sysdev_class); + sysdev_driver_register(&clks_sysdev_class, &clks_sysdev_driver); + sysdev_register(&clks_sysdev_dev); + + return 0; +} +subsys_initcall(clk_sysdev_init); +#endif + int __init clk_init(void) { int i, ret = 0; -- cgit v1.2.3-70-g09d2 From 50cca715a64b66ccf173767d94d4020ea0a6129c Mon Sep 17 00:00:00 2001 From: Francesco VIRLINZI Date: Fri, 13 Mar 2009 08:08:01 +0000 Subject: sh: clkfwk: Safer resume from hibernation. This patch fixes a possible problem in the resume from hibenration. It temporaneally saves the clk->rate on the stack to avoid any possible change during the clk->set_parent(..) call. Signed-off-by: Francesco Virlinzi Signed-off-by: Paul Mundt --- arch/sh/kernel/cpu/clock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'arch/sh/kernel/cpu/clock.c') diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index 3209a8740fa..1dc896483b5 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -372,12 +372,14 @@ static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state) if (prev_state.event == PM_EVENT_FREEZE) { list_for_each_entry(clkp, &clock_list, node) if (likely(clkp->ops)) { + unsigned long rate = clkp->rate; + if (likely(clkp->ops->set_parent)) clkp->ops->set_parent(clkp, clkp->parent); if (likely(clkp->ops->set_rate)) clkp->ops->set_rate(clkp, - clkp->rate, NO_CHANGE); + rate, NO_CHANGE); else if (likely(clkp->ops->recalc)) clkp->ops->recalc(clkp); } -- cgit v1.2.3-70-g09d2