diff options
Diffstat (limited to 'arch/sh/kernel/cpu/clock.c')
-rw-r--r-- | arch/sh/kernel/cpu/clock.c | 102 |
1 files changed, 68 insertions, 34 deletions
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c index abb586b12565..014f318f5a05 100644 --- a/arch/sh/kernel/cpu/clock.c +++ b/arch/sh/kernel/cpu/clock.c @@ -1,7 +1,7 @@ /* * arch/sh/kernel/cpu/clock.c - SuperH clock framework * - * Copyright (C) 2005, 2006 Paul Mundt + * Copyright (C) 2005, 2006, 2007 Paul Mundt * * This clock framework is derived from the OMAP version by: * @@ -23,6 +23,7 @@ #include <linux/seq_file.h> #include <linux/err.h> #include <linux/platform_device.h> +#include <linux/proc_fs.h> #include <asm/clock.h> #include <asm/timer.h> @@ -98,15 +99,17 @@ int __clk_enable(struct clk *clk) if (clk->ops && clk->ops->init) clk->ops->init(clk); + kref_get(&clk->kref); + if (clk->flags & CLK_ALWAYS_ENABLED) return 0; if (likely(clk->ops && clk->ops->enable)) clk->ops->enable(clk); - kref_get(&clk->kref); return 0; } +EXPORT_SYMBOL_GPL(__clk_enable); int clk_enable(struct clk *clk) { @@ -119,6 +122,7 @@ int clk_enable(struct clk *clk) return ret; } +EXPORT_SYMBOL_GPL(clk_enable); static void clk_kref_release(struct kref *kref) { @@ -127,11 +131,17 @@ static void clk_kref_release(struct kref *kref) void __clk_disable(struct clk *clk) { + int count = kref_put(&clk->kref, clk_kref_release); + if (clk->flags & CLK_ALWAYS_ENABLED) return; - kref_put(&clk->kref, clk_kref_release); + if (!count) { /* count reaches zero, disable the clock */ + if (likely(clk->ops && clk->ops->disable)) + clk->ops->disable(clk); + } } +EXPORT_SYMBOL_GPL(__clk_disable); void clk_disable(struct clk *clk) { @@ -141,6 +151,7 @@ void clk_disable(struct clk *clk) __clk_disable(clk); spin_unlock_irqrestore(&clock_lock, flags); } +EXPORT_SYMBOL_GPL(clk_disable); int clk_register(struct clk *clk) { @@ -151,8 +162,18 @@ int clk_register(struct clk *clk) mutex_unlock(&clock_list_sem); + if (clk->flags & CLK_ALWAYS_ENABLED) { + pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name); + if (clk->ops && clk->ops->init) + clk->ops->init(clk); + if (clk->ops && clk->ops->enable) + clk->ops->enable(clk); + pr_debug( "Enabled."); + } + return 0; } +EXPORT_SYMBOL_GPL(clk_register); void clk_unregister(struct clk *clk) { @@ -160,21 +181,29 @@ void clk_unregister(struct clk *clk) list_del(&clk->node); mutex_unlock(&clock_list_sem); } +EXPORT_SYMBOL_GPL(clk_unregister); -inline unsigned long clk_get_rate(struct clk *clk) +unsigned long clk_get_rate(struct clk *clk) { return clk->rate; } +EXPORT_SYMBOL_GPL(clk_get_rate); int clk_set_rate(struct clk *clk, unsigned long rate) { + return clk_set_rate_ex(clk, rate, 0); +} +EXPORT_SYMBOL_GPL(clk_set_rate); + +int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id) +{ int ret = -EOPNOTSUPP; if (likely(clk->ops && clk->ops->set_rate)) { unsigned long flags; spin_lock_irqsave(&clock_lock, flags); - ret = clk->ops->set_rate(clk, rate); + ret = clk->ops->set_rate(clk, rate, algo_id); spin_unlock_irqrestore(&clock_lock, flags); } @@ -183,6 +212,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate) return ret; } +EXPORT_SYMBOL_GPL(clk_set_rate_ex); void clk_recalc_rate(struct clk *clk) { @@ -197,6 +227,7 @@ void clk_recalc_rate(struct clk *clk) if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) propagate_rate(clk); } +EXPORT_SYMBOL_GPL(clk_recalc_rate); /* * Returns a clock. Note that we first try to use device id on the bus @@ -233,18 +264,43 @@ found: return clk; } +EXPORT_SYMBOL_GPL(clk_get); void clk_put(struct clk *clk) { if (clk && !IS_ERR(clk)) module_put(clk->owner); } +EXPORT_SYMBOL_GPL(clk_put); void __init __attribute__ ((weak)) arch_init_clk_ops(struct clk_ops **ops, int type) { } +static int show_clocks(char *buf, char **start, off_t off, + int len, int *eof, void *data) +{ + struct clk *clk; + char *p = buf; + + list_for_each_entry_reverse(clk, &clock_list, node) { + unsigned long rate = clk_get_rate(clk); + + /* + * Don't bother listing dummy clocks with no ancestry + * that only support enable and disable ops. + */ + if (unlikely(!rate && !clk->parent)) + continue; + + p += sprintf(p, "%-12s\t: %ld.%02ldMHz\n", clk->name, + rate / 1000000, (rate % 1000000) / 10000); + } + + return p - buf; +} + int __init clk_init(void) { int i, ret = 0; @@ -256,7 +312,6 @@ int __init clk_init(void) arch_init_clk_ops(&clk->ops, i); ret |= clk_register(clk); - clk_enable(clk); } /* Kick the child clocks.. */ @@ -266,35 +321,14 @@ int __init clk_init(void) return ret; } -int show_clocks(struct seq_file *m) +static int __init clk_proc_init(void) { - struct clk *clk; - - list_for_each_entry_reverse(clk, &clock_list, node) { - unsigned long rate = clk_get_rate(clk); - - /* - * Don't bother listing dummy clocks with no ancestry - * that only support enable and disable ops. - */ - if (unlikely(!rate && !clk->parent)) - continue; - - seq_printf(m, "%-12s\t: %ld.%02ldMHz\n", clk->name, - rate / 1000000, (rate % 1000000) / 10000); - } + struct proc_dir_entry *p; + p = create_proc_read_entry("clocks", S_IRUSR, NULL, + show_clocks, NULL); + if (unlikely(!p)) + return -EINVAL; return 0; } - -EXPORT_SYMBOL_GPL(clk_register); -EXPORT_SYMBOL_GPL(clk_unregister); -EXPORT_SYMBOL_GPL(clk_get); -EXPORT_SYMBOL_GPL(clk_put); -EXPORT_SYMBOL_GPL(clk_enable); -EXPORT_SYMBOL_GPL(clk_disable); -EXPORT_SYMBOL_GPL(__clk_enable); -EXPORT_SYMBOL_GPL(__clk_disable); -EXPORT_SYMBOL_GPL(clk_get_rate); -EXPORT_SYMBOL_GPL(clk_set_rate); -EXPORT_SYMBOL_GPL(clk_recalc_rate); +subsys_initcall(clk_proc_init); |