linux/arch/sh/kernel/cpu/clock.c
<<
>>
Prefs
   1/*
   2 * arch/sh/kernel/cpu/clock.c - SuperH clock framework
   3 *
   4 *  Copyright (C) 2005, 2006, 2007  Paul Mundt
   5 *
   6 * This clock framework is derived from the OMAP version by:
   7 *
   8 *      Copyright (C) 2004 - 2005 Nokia Corporation
   9 *      Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
  10 *
  11 *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
  12 *
  13 * This file is subject to the terms and conditions of the GNU General Public
  14 * License.  See the file "COPYING" in the main directory of this archive
  15 * for more details.
  16 */
  17#include <linux/kernel.h>
  18#include <linux/init.h>
  19#include <linux/module.h>
  20#include <linux/mutex.h>
  21#include <linux/list.h>
  22#include <linux/kref.h>
  23#include <linux/seq_file.h>
  24#include <linux/err.h>
  25#include <linux/platform_device.h>
  26#include <linux/proc_fs.h>
  27#include <asm/clock.h>
  28#include <asm/timer.h>
  29
  30static LIST_HEAD(clock_list);
  31static DEFINE_SPINLOCK(clock_lock);
  32static DEFINE_MUTEX(clock_list_sem);
  33
  34/*
  35 * Each subtype is expected to define the init routines for these clocks,
  36 * as each subtype (or processor family) will have these clocks at the
  37 * very least. These are all provided through the CPG, which even some of
  38 * the more quirky parts (such as ST40, SH4-202, etc.) still have.
  39 *
  40 * The processor-specific code is expected to register any additional
  41 * clock sources that are of interest.
  42 */
  43static struct clk master_clk = {
  44        .name           = "master_clk",
  45        .flags          = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
  46        .rate           = CONFIG_SH_PCLK_FREQ,
  47};
  48
  49static struct clk module_clk = {
  50        .name           = "module_clk",
  51        .parent         = &master_clk,
  52        .flags          = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
  53};
  54
  55static struct clk bus_clk = {
  56        .name           = "bus_clk",
  57        .parent         = &master_clk,
  58        .flags          = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES,
  59};
  60
  61static struct clk cpu_clk = {
  62        .name           = "cpu_clk",
  63        .parent         = &master_clk,
  64        .flags          = CLK_ALWAYS_ENABLED,
  65};
  66
  67/*
  68 * The ordering of these clocks matters, do not change it.
  69 */
  70static struct clk *onchip_clocks[] = {
  71        &master_clk,
  72        &module_clk,
  73        &bus_clk,
  74        &cpu_clk,
  75};
  76
  77static void propagate_rate(struct clk *clk)
  78{
  79        struct clk *clkp;
  80
  81        list_for_each_entry(clkp, &clock_list, node) {
  82                if (likely(clkp->parent != clk))
  83                        continue;
  84                if (likely(clkp->ops && clkp->ops->recalc))
  85                        clkp->ops->recalc(clkp);
  86                if (unlikely(clkp->flags & CLK_RATE_PROPAGATES))
  87                        propagate_rate(clkp);
  88        }
  89}
  90
  91static int __clk_enable(struct clk *clk)
  92{
  93        /*
  94         * See if this is the first time we're enabling the clock, some
  95         * clocks that are always enabled still require "special"
  96         * initialization. This is especially true if the clock mode
  97         * changes and the clock needs to hunt for the proper set of
  98         * divisors to use before it can effectively recalc.
  99         */
 100        if (unlikely(atomic_read(&clk->kref.refcount) == 1))
 101                if (clk->ops && clk->ops->init)
 102                        clk->ops->init(clk);
 103
 104        kref_get(&clk->kref);
 105
 106        if (clk->flags & CLK_ALWAYS_ENABLED)
 107                return 0;
 108
 109        if (likely(clk->ops && clk->ops->enable))
 110                clk->ops->enable(clk);
 111
 112        return 0;
 113}
 114
 115int clk_enable(struct clk *clk)
 116{
 117        unsigned long flags;
 118        int ret;
 119
 120        spin_lock_irqsave(&clock_lock, flags);
 121        ret = __clk_enable(clk);
 122        spin_unlock_irqrestore(&clock_lock, flags);
 123
 124        return ret;
 125}
 126EXPORT_SYMBOL_GPL(clk_enable);
 127
 128static void clk_kref_release(struct kref *kref)
 129{
 130        /* Nothing to do */
 131}
 132
 133static void __clk_disable(struct clk *clk)
 134{
 135        int count = kref_put(&clk->kref, clk_kref_release);
 136
 137        if (clk->flags & CLK_ALWAYS_ENABLED)
 138                return;
 139
 140        if (!count) {   /* count reaches zero, disable the clock */
 141                if (likely(clk->ops && clk->ops->disable))
 142                        clk->ops->disable(clk);
 143        }
 144}
 145
 146void clk_disable(struct clk *clk)
 147{
 148        unsigned long flags;
 149
 150        spin_lock_irqsave(&clock_lock, flags);
 151        __clk_disable(clk);
 152        spin_unlock_irqrestore(&clock_lock, flags);
 153}
 154EXPORT_SYMBOL_GPL(clk_disable);
 155
 156int clk_register(struct clk *clk)
 157{
 158        mutex_lock(&clock_list_sem);
 159
 160        list_add(&clk->node, &clock_list);
 161        kref_init(&clk->kref);
 162
 163        mutex_unlock(&clock_list_sem);
 164
 165        if (clk->flags & CLK_ALWAYS_ENABLED) {
 166                pr_debug( "Clock '%s' is ALWAYS_ENABLED\n", clk->name);
 167                if (clk->ops && clk->ops->init)
 168                        clk->ops->init(clk);
 169                if (clk->ops && clk->ops->enable)
 170                        clk->ops->enable(clk);
 171                pr_debug( "Enabled.");
 172        }
 173
 174        return 0;
 175}
 176EXPORT_SYMBOL_GPL(clk_register);
 177
 178void clk_unregister(struct clk *clk)
 179{
 180        mutex_lock(&clock_list_sem);
 181        list_del(&clk->node);
 182        mutex_unlock(&clock_list_sem);
 183}
 184EXPORT_SYMBOL_GPL(clk_unregister);
 185
 186unsigned long clk_get_rate(struct clk *clk)
 187{
 188        return clk->rate;
 189}
 190EXPORT_SYMBOL_GPL(clk_get_rate);
 191
 192int clk_set_rate(struct clk *clk, unsigned long rate)
 193{
 194        return clk_set_rate_ex(clk, rate, 0);
 195}
 196EXPORT_SYMBOL_GPL(clk_set_rate);
 197
 198int clk_set_rate_ex(struct clk *clk, unsigned long rate, int algo_id)
 199{
 200        int ret = -EOPNOTSUPP;
 201
 202        if (likely(clk->ops && clk->ops->set_rate)) {
 203                unsigned long flags;
 204
 205                spin_lock_irqsave(&clock_lock, flags);
 206                ret = clk->ops->set_rate(clk, rate, algo_id);
 207                spin_unlock_irqrestore(&clock_lock, flags);
 208        }
 209
 210        if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
 211                propagate_rate(clk);
 212
 213        return ret;
 214}
 215EXPORT_SYMBOL_GPL(clk_set_rate_ex);
 216
 217void clk_recalc_rate(struct clk *clk)
 218{
 219        if (likely(clk->ops && clk->ops->recalc)) {
 220                unsigned long flags;
 221
 222                spin_lock_irqsave(&clock_lock, flags);
 223                clk->ops->recalc(clk);
 224                spin_unlock_irqrestore(&clock_lock, flags);
 225        }
 226
 227        if (unlikely(clk->flags & CLK_RATE_PROPAGATES))
 228                propagate_rate(clk);
 229}
 230EXPORT_SYMBOL_GPL(clk_recalc_rate);
 231
 232long clk_round_rate(struct clk *clk, unsigned long rate)
 233{
 234        if (likely(clk->ops && clk->ops->round_rate)) {
 235                unsigned long flags, rounded;
 236
 237                spin_lock_irqsave(&clock_lock, flags);
 238                rounded = clk->ops->round_rate(clk, rate);
 239                spin_unlock_irqrestore(&clock_lock, flags);
 240
 241                return rounded;
 242        }
 243
 244        return clk_get_rate(clk);
 245}
 246EXPORT_SYMBOL_GPL(clk_round_rate);
 247
 248/*
 249 * Returns a clock. Note that we first try to use device id on the bus
 250 * and clock name. If this fails, we try to use clock name only.
 251 */
 252struct clk *clk_get(struct device *dev, const char *id)
 253{
 254        struct clk *p, *clk = ERR_PTR(-ENOENT);
 255        int idno;
 256
 257        if (dev == NULL || dev->bus != &platform_bus_type)
 258                idno = -1;
 259        else
 260                idno = to_platform_device(dev)->id;
 261
 262        mutex_lock(&clock_list_sem);
 263        list_for_each_entry(p, &clock_list, node) {
 264                if (p->id == idno &&
 265                    strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
 266                        clk = p;
 267                        goto found;
 268                }
 269        }
 270
 271        list_for_each_entry(p, &clock_list, node) {
 272                if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
 273                        clk = p;
 274                        break;
 275                }
 276        }
 277
 278found:
 279        mutex_unlock(&clock_list_sem);
 280
 281        return clk;
 282}
 283EXPORT_SYMBOL_GPL(clk_get);
 284
 285void clk_put(struct clk *clk)
 286{
 287        if (clk && !IS_ERR(clk))
 288                module_put(clk->owner);
 289}
 290EXPORT_SYMBOL_GPL(clk_put);
 291
 292void __init __attribute__ ((weak))
 293arch_init_clk_ops(struct clk_ops **ops, int type)
 294{
 295}
 296
 297int __init __attribute__ ((weak))
 298arch_clk_init(void)
 299{
 300        return 0;
 301}
 302
 303static int show_clocks(char *buf, char **start, off_t off,
 304                       int len, int *eof, void *data)
 305{
 306        struct clk *clk;
 307        char *p = buf;
 308
 309        list_for_each_entry_reverse(clk, &clock_list, node) {
 310                unsigned long rate = clk_get_rate(clk);
 311
 312                p += sprintf(p, "%-12s\t: %ld.%02ldMHz\t%s\n", clk->name,
 313                             rate / 1000000, (rate % 1000000) / 10000,
 314                             ((clk->flags & CLK_ALWAYS_ENABLED) ||
 315                              (atomic_read(&clk->kref.refcount) != 1)) ?
 316                             "enabled" : "disabled");
 317        }
 318
 319        return p - buf;
 320}
 321
 322int __init clk_init(void)
 323{
 324        int i, ret = 0;
 325
 326        BUG_ON(!master_clk.rate);
 327
 328        for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) {
 329                struct clk *clk = onchip_clocks[i];
 330
 331                arch_init_clk_ops(&clk->ops, i);
 332                ret |= clk_register(clk);
 333        }
 334
 335        ret |= arch_clk_init();
 336
 337        /* Kick the child clocks.. */
 338        propagate_rate(&master_clk);
 339        propagate_rate(&bus_clk);
 340
 341        return ret;
 342}
 343
 344static int __init clk_proc_init(void)
 345{
 346        struct proc_dir_entry *p;
 347        p = create_proc_read_entry("clocks", S_IRUSR, NULL,
 348                                   show_clocks, NULL);
 349        if (unlikely(!p))
 350                return -EINVAL;
 351
 352        return 0;
 353}
 354subsys_initcall(clk_proc_init);
 355
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.