aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/cpu/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/cpu/clock.c')
-rw-r--r--arch/sh/kernel/cpu/clock.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 7b17137536d6..1dc896483b59 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -20,6 +20,8 @@
20#include <linux/mutex.h> 20#include <linux/mutex.h>
21#include <linux/list.h> 21#include <linux/list.h>
22#include <linux/kref.h> 22#include <linux/kref.h>
23#include <linux/kobject.h>
24#include <linux/sysdev.h>
23#include <linux/seq_file.h> 25#include <linux/seq_file.h>
24#include <linux/err.h> 26#include <linux/err.h>
25#include <linux/platform_device.h> 27#include <linux/platform_device.h>
@@ -239,6 +241,35 @@ void clk_recalc_rate(struct clk *clk)
239} 241}
240EXPORT_SYMBOL_GPL(clk_recalc_rate); 242EXPORT_SYMBOL_GPL(clk_recalc_rate);
241 243
244int clk_set_parent(struct clk *clk, struct clk *parent)
245{
246 int ret = -EINVAL;
247 struct clk *old;
248
249 if (!parent || !clk)
250 return ret;
251
252 old = clk->parent;
253 if (likely(clk->ops && clk->ops->set_parent)) {
254 unsigned long flags;
255 spin_lock_irqsave(&clock_lock, flags);
256 ret = clk->ops->set_parent(clk, parent);
257 spin_unlock_irqrestore(&clock_lock, flags);
258 clk->parent = (ret ? old : parent);
259 }
260
261 if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
262 propagate_rate(clk);
263 return ret;
264}
265EXPORT_SYMBOL_GPL(clk_set_parent);
266
267struct clk *clk_get_parent(struct clk *clk)
268{
269 return clk->parent;
270}
271EXPORT_SYMBOL_GPL(clk_get_parent);
272
242long clk_round_rate(struct clk *clk, unsigned long rate) 273long clk_round_rate(struct clk *clk, unsigned long rate)
243{ 274{
244 if (likely(clk->ops && clk->ops->round_rate)) { 275 if (likely(clk->ops && clk->ops->round_rate)) {
@@ -329,6 +360,70 @@ static int show_clocks(char *buf, char **start, off_t off,
329 return p - buf; 360 return p - buf;
330} 361}
331 362
363#ifdef CONFIG_PM
364static int clks_sysdev_suspend(struct sys_device *dev, pm_message_t state)
365{
366 static pm_message_t prev_state;
367 struct clk *clkp;
368
369 switch (state.event) {
370 case PM_EVENT_ON:
371 /* Resumeing from hibernation */
372 if (prev_state.event == PM_EVENT_FREEZE) {
373 list_for_each_entry(clkp, &clock_list, node)
374 if (likely(clkp->ops)) {
375 unsigned long rate = clkp->rate;
376
377 if (likely(clkp->ops->set_parent))
378 clkp->ops->set_parent(clkp,
379 clkp->parent);
380 if (likely(clkp->ops->set_rate))
381 clkp->ops->set_rate(clkp,
382 rate, NO_CHANGE);
383 else if (likely(clkp->ops->recalc))
384 clkp->ops->recalc(clkp);
385 }
386 }
387 break;
388 case PM_EVENT_FREEZE:
389 break;
390 case PM_EVENT_SUSPEND:
391 break;
392 }
393
394 prev_state = state;
395 return 0;
396}
397
398static int clks_sysdev_resume(struct sys_device *dev)
399{
400 return clks_sysdev_suspend(dev, PMSG_ON);
401}
402
403static struct sysdev_class clks_sysdev_class = {
404 .name = "clks",
405};
406
407static struct sysdev_driver clks_sysdev_driver = {
408 .suspend = clks_sysdev_suspend,
409 .resume = clks_sysdev_resume,
410};
411
412static struct sys_device clks_sysdev_dev = {
413 .cls = &clks_sysdev_class,
414};
415
416static int __init clk_sysdev_init(void)
417{
418 sysdev_class_register(&clks_sysdev_class);
419 sysdev_driver_register(&clks_sysdev_class, &clks_sysdev_driver);
420 sysdev_register(&clks_sysdev_dev);
421
422 return 0;
423}
424subsys_initcall(clk_sysdev_init);
425#endif
426
332int __init clk_init(void) 427int __init clk_init(void)
333{ 428{
334 int i, ret = 0; 429 int i, ret = 0;