linux/arch/arm/plat-omap/clock.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/plat-omap/clock.c
   3 *
   4 *  Copyright (C) 2004 - 2008 Nokia corporation
   5 *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
   6 *
   7 *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 */
  13#include <linux/kernel.h>
  14#include <linux/init.h>
  15#include <linux/module.h>
  16#include <linux/list.h>
  17#include <linux/errno.h>
  18#include <linux/err.h>
  19#include <linux/string.h>
  20#include <linux/clk.h>
  21#include <linux/mutex.h>
  22#include <linux/platform_device.h>
  23#include <linux/cpufreq.h>
  24#include <linux/debugfs.h>
  25#include <linux/io.h>
  26
  27#include <mach/clock.h>
  28
  29static LIST_HEAD(clocks);
  30static DEFINE_MUTEX(clocks_mutex);
  31static DEFINE_SPINLOCK(clockfw_lock);
  32
  33static struct clk_functions *arch_clock;
  34
  35/*-------------------------------------------------------------------------
  36 * Standard clock functions defined in include/linux/clk.h
  37 *-------------------------------------------------------------------------*/
  38
  39int clk_enable(struct clk *clk)
  40{
  41        unsigned long flags;
  42        int ret = 0;
  43
  44        if (clk == NULL || IS_ERR(clk))
  45                return -EINVAL;
  46
  47        spin_lock_irqsave(&clockfw_lock, flags);
  48        if (arch_clock->clk_enable)
  49                ret = arch_clock->clk_enable(clk);
  50        spin_unlock_irqrestore(&clockfw_lock, flags);
  51
  52        return ret;
  53}
  54EXPORT_SYMBOL(clk_enable);
  55
  56void clk_disable(struct clk *clk)
  57{
  58        unsigned long flags;
  59
  60        if (clk == NULL || IS_ERR(clk))
  61                return;
  62
  63        spin_lock_irqsave(&clockfw_lock, flags);
  64        if (clk->usecount == 0) {
  65                printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
  66                       clk->name);
  67                WARN_ON(1);
  68                goto out;
  69        }
  70
  71        if (arch_clock->clk_disable)
  72                arch_clock->clk_disable(clk);
  73
  74out:
  75        spin_unlock_irqrestore(&clockfw_lock, flags);
  76}
  77EXPORT_SYMBOL(clk_disable);
  78
  79unsigned long clk_get_rate(struct clk *clk)
  80{
  81        unsigned long flags;
  82        unsigned long ret = 0;
  83
  84        if (clk == NULL || IS_ERR(clk))
  85                return 0;
  86
  87        spin_lock_irqsave(&clockfw_lock, flags);
  88        ret = clk->rate;
  89        spin_unlock_irqrestore(&clockfw_lock, flags);
  90
  91        return ret;
  92}
  93EXPORT_SYMBOL(clk_get_rate);
  94
  95/*-------------------------------------------------------------------------
  96 * Optional clock functions defined in include/linux/clk.h
  97 *-------------------------------------------------------------------------*/
  98
  99long clk_round_rate(struct clk *clk, unsigned long rate)
 100{
 101        unsigned long flags;
 102        long ret = 0;
 103
 104        if (clk == NULL || IS_ERR(clk))
 105                return ret;
 106
 107        spin_lock_irqsave(&clockfw_lock, flags);
 108        if (arch_clock->clk_round_rate)
 109                ret = arch_clock->clk_round_rate(clk, rate);
 110        spin_unlock_irqrestore(&clockfw_lock, flags);
 111
 112        return ret;
 113}
 114EXPORT_SYMBOL(clk_round_rate);
 115
 116int clk_set_rate(struct clk *clk, unsigned long rate)
 117{
 118        unsigned long flags;
 119        int ret = -EINVAL;
 120
 121        if (clk == NULL || IS_ERR(clk))
 122                return ret;
 123
 124        spin_lock_irqsave(&clockfw_lock, flags);
 125        if (arch_clock->clk_set_rate)
 126                ret = arch_clock->clk_set_rate(clk, rate);
 127        if (ret == 0) {
 128                if (clk->recalc)
 129                        clk->rate = clk->recalc(clk);
 130                propagate_rate(clk);
 131        }
 132        spin_unlock_irqrestore(&clockfw_lock, flags);
 133
 134        return ret;
 135}
 136EXPORT_SYMBOL(clk_set_rate);
 137
 138int clk_set_parent(struct clk *clk, struct clk *parent)
 139{
 140        unsigned long flags;
 141        int ret = -EINVAL;
 142
 143        if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
 144                return ret;
 145
 146        spin_lock_irqsave(&clockfw_lock, flags);
 147        if (clk->usecount == 0) {
 148                if (arch_clock->clk_set_parent)
 149                        ret = arch_clock->clk_set_parent(clk, parent);
 150                if (ret == 0) {
 151                        if (clk->recalc)
 152                                clk->rate = clk->recalc(clk);
 153                        propagate_rate(clk);
 154                }
 155        } else
 156                ret = -EBUSY;
 157        spin_unlock_irqrestore(&clockfw_lock, flags);
 158
 159        return ret;
 160}
 161EXPORT_SYMBOL(clk_set_parent);
 162
 163struct clk *clk_get_parent(struct clk *clk)
 164{
 165        return clk->parent;
 166}
 167EXPORT_SYMBOL(clk_get_parent);
 168
 169/*-------------------------------------------------------------------------
 170 * OMAP specific clock functions shared between omap1 and omap2
 171 *-------------------------------------------------------------------------*/
 172
 173unsigned int __initdata mpurate;
 174
 175/*
 176 * By default we use the rate set by the bootloader.
 177 * You can override this with mpurate= cmdline option.
 178 */
 179static int __init omap_clk_setup(char *str)
 180{
 181        get_option(&str, &mpurate);
 182
 183        if (!mpurate)
 184                return 1;
 185
 186        if (mpurate < 1000)
 187                mpurate *= 1000000;
 188
 189        return 1;
 190}
 191__setup("mpurate=", omap_clk_setup);
 192
 193/* Used for clocks that always have same value as the parent clock */
 194unsigned long followparent_recalc(struct clk *clk)
 195{
 196        return clk->parent->rate;
 197}
 198
 199void clk_reparent(struct clk *child, struct clk *parent)
 200{
 201        list_del_init(&child->sibling);
 202        if (parent)
 203                list_add(&child->sibling, &parent->children);
 204        child->parent = parent;
 205
 206        /* now do the debugfs renaming to reattach the child
 207           to the proper parent */
 208}
 209
 210/* Propagate rate to children */
 211void propagate_rate(struct clk * tclk)
 212{
 213        struct clk *clkp;
 214
 215        list_for_each_entry(clkp, &tclk->children, sibling) {
 216                if (clkp->recalc)
 217                        clkp->rate = clkp->recalc(clkp);
 218                propagate_rate(clkp);
 219        }
 220}
 221
 222static LIST_HEAD(root_clks);
 223
 224/**
 225 * recalculate_root_clocks - recalculate and propagate all root clocks
 226 *
 227 * Recalculates all root clocks (clocks with no parent), which if the
 228 * clock's .recalc is set correctly, should also propagate their rates.
 229 * Called at init.
 230 */
 231void recalculate_root_clocks(void)
 232{
 233        struct clk *clkp;
 234
 235        list_for_each_entry(clkp, &root_clks, sibling) {
 236                if (clkp->recalc)
 237                        clkp->rate = clkp->recalc(clkp);
 238                propagate_rate(clkp);
 239        }
 240}
 241
 242/**
 243 * clk_init_one - initialize any fields in the struct clk before clk init
 244 * @clk: struct clk * to initialize
 245 *
 246 * Initialize any struct clk fields needed before normal clk initialization
 247 * can run.  No return value.
 248 */
 249void clk_init_one(struct clk *clk)
 250{
 251        INIT_LIST_HEAD(&clk->children);
 252}
 253
 254int clk_register(struct clk *clk)
 255{
 256        if (clk == NULL || IS_ERR(clk))
 257                return -EINVAL;
 258
 259        /*
 260         * trap out already registered clocks
 261         */
 262        if (clk->node.next || clk->node.prev)
 263                return 0;
 264
 265        mutex_lock(&clocks_mutex);
 266        if (clk->parent)
 267                list_add(&clk->sibling, &clk->parent->children);
 268        else
 269                list_add(&clk->sibling, &root_clks);
 270
 271        list_add(&clk->node, &clocks);
 272        if (clk->init)
 273                clk->init(clk);
 274        mutex_unlock(&clocks_mutex);
 275
 276        return 0;
 277}
 278EXPORT_SYMBOL(clk_register);
 279
 280void clk_unregister(struct clk *clk)
 281{
 282        if (clk == NULL || IS_ERR(clk))
 283                return;
 284
 285        mutex_lock(&clocks_mutex);
 286        list_del(&clk->sibling);
 287        list_del(&clk->node);
 288        mutex_unlock(&clocks_mutex);
 289}
 290EXPORT_SYMBOL(clk_unregister);
 291
 292void clk_enable_init_clocks(void)
 293{
 294        struct clk *clkp;
 295
 296        list_for_each_entry(clkp, &clocks, node) {
 297                if (clkp->flags & ENABLE_ON_INIT)
 298                        clk_enable(clkp);
 299        }
 300}
 301EXPORT_SYMBOL(clk_enable_init_clocks);
 302
 303/*
 304 * Low level helpers
 305 */
 306static int clkll_enable_null(struct clk *clk)
 307{
 308        return 0;
 309}
 310
 311static void clkll_disable_null(struct clk *clk)
 312{
 313}
 314
 315const struct clkops clkops_null = {
 316        .enable         = clkll_enable_null,
 317        .disable        = clkll_disable_null,
 318};
 319
 320#ifdef CONFIG_CPU_FREQ
 321void clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
 322{
 323        unsigned long flags;
 324
 325        spin_lock_irqsave(&clockfw_lock, flags);
 326        if (arch_clock->clk_init_cpufreq_table)
 327                arch_clock->clk_init_cpufreq_table(table);
 328        spin_unlock_irqrestore(&clockfw_lock, flags);
 329}
 330EXPORT_SYMBOL(clk_init_cpufreq_table);
 331#endif
 332
 333/*-------------------------------------------------------------------------*/
 334
 335#ifdef CONFIG_OMAP_RESET_CLOCKS
 336/*
 337 * Disable any unused clocks left on by the bootloader
 338 */
 339static int __init clk_disable_unused(void)
 340{
 341        struct clk *ck;
 342        unsigned long flags;
 343
 344        list_for_each_entry(ck, &clocks, node) {
 345                if (ck->ops == &clkops_null)
 346                        continue;
 347
 348                if (ck->usecount > 0 || ck->enable_reg == 0)
 349                        continue;
 350
 351                spin_lock_irqsave(&clockfw_lock, flags);
 352                if (arch_clock->clk_disable_unused)
 353                        arch_clock->clk_disable_unused(ck);
 354                spin_unlock_irqrestore(&clockfw_lock, flags);
 355        }
 356
 357        return 0;
 358}
 359late_initcall(clk_disable_unused);
 360#endif
 361
 362int __init clk_init(struct clk_functions * custom_clocks)
 363{
 364        if (!custom_clocks) {
 365                printk(KERN_ERR "No custom clock functions registered\n");
 366                BUG();
 367        }
 368
 369        arch_clock = custom_clocks;
 370
 371        return 0;
 372}
 373
 374#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
 375/*
 376 *      debugfs support to trace clock tree hierarchy and attributes
 377 */
 378static struct dentry *clk_debugfs_root;
 379
 380static int clk_debugfs_register_one(struct clk *c)
 381{
 382        int err;
 383        struct dentry *d, *child;
 384        struct clk *pa = c->parent;
 385        char s[255];
 386        char *p = s;
 387
 388        p += sprintf(p, "%s", c->name);
 389        if (c->id != 0)
 390                sprintf(p, ":%d", c->id);
 391        d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
 392        if (!d)
 393                return -ENOMEM;
 394        c->dent = d;
 395
 396        d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
 397        if (!d) {
 398                err = -ENOMEM;
 399                goto err_out;
 400        }
 401        d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
 402        if (!d) {
 403                err = -ENOMEM;
 404                goto err_out;
 405        }
 406        d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
 407        if (!d) {
 408                err = -ENOMEM;
 409                goto err_out;
 410        }
 411        return 0;
 412
 413err_out:
 414        d = c->dent;
 415        list_for_each_entry(child, &d->d_subdirs, d_u.d_child)
 416                debugfs_remove(child);
 417        debugfs_remove(c->dent);
 418        return err;
 419}
 420
 421static int clk_debugfs_register(struct clk *c)
 422{
 423        int err;
 424        struct clk *pa = c->parent;
 425
 426        if (pa && !pa->dent) {
 427                err = clk_debugfs_register(pa);
 428                if (err)
 429                        return err;
 430        }
 431
 432        if (!c->dent) {
 433                err = clk_debugfs_register_one(c);
 434                if (err)
 435                        return err;
 436        }
 437        return 0;
 438}
 439
 440static int __init clk_debugfs_init(void)
 441{
 442        struct clk *c;
 443        struct dentry *d;
 444        int err;
 445
 446        d = debugfs_create_dir("clock", NULL);
 447        if (!d)
 448                return -ENOMEM;
 449        clk_debugfs_root = d;
 450
 451        list_for_each_entry(c, &clocks, node) {
 452                err = clk_debugfs_register(c);
 453                if (err)
 454                        goto err_out;
 455        }
 456        return 0;
 457err_out:
 458        debugfs_remove(clk_debugfs_root); /* REVISIT: Cleanup correctly */
 459        return err;
 460}
 461late_initcall(clk_debugfs_init);
 462
 463#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
 464
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.