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
  39/* This functions is moved to arch/arm/common/clkdev.c. For OMAP4 since
  40 * clock framework is not up , it is defined here to avoid rework in
  41 * every driver. Also dummy prcm reset function is added */
  42
  43/* Dummy hooks only for OMAP4.For rest OMAPs, common clkdev is used */
  44#if defined(CONFIG_ARCH_OMAP4)
  45struct clk *clk_get(struct device *dev, const char *id)
  46{
  47        return NULL;
  48}
  49EXPORT_SYMBOL(clk_get);
  50
  51void clk_put(struct clk *clk)
  52{
  53}
  54EXPORT_SYMBOL(clk_put);
  55
  56void omap2_clk_prepare_for_reboot(void)
  57{
  58}
  59EXPORT_SYMBOL(omap2_clk_prepare_for_reboot);
  60
  61void omap_prcm_arch_reset(char mode)
  62{
  63}
  64EXPORT_SYMBOL(omap_prcm_arch_reset);
  65#endif
  66int clk_enable(struct clk *clk)
  67{
  68        unsigned long flags;
  69        int ret = 0;
  70        if (cpu_is_omap44xx())
  71                /* OMAP4 clk framework not supported yet */
  72                return 0;
  73
  74        if (clk == NULL || IS_ERR(clk))
  75                return -EINVAL;
  76
  77        spin_lock_irqsave(&clockfw_lock, flags);
  78        if (arch_clock->clk_enable)
  79                ret = arch_clock->clk_enable(clk);
  80        spin_unlock_irqrestore(&clockfw_lock, flags);
  81
  82        return ret;
  83}
  84EXPORT_SYMBOL(clk_enable);
  85
  86void clk_disable(struct clk *clk)
  87{
  88        unsigned long flags;
  89
  90        if (clk == NULL || IS_ERR(clk))
  91                return;
  92
  93        spin_lock_irqsave(&clockfw_lock, flags);
  94        if (clk->usecount == 0) {
  95                printk(KERN_ERR "Trying disable clock %s with 0 usecount\n",
  96                       clk->name);
  97                WARN_ON(1);
  98                goto out;
  99        }
 100
 101        if (arch_clock->clk_disable)
 102                arch_clock->clk_disable(clk);
 103
 104out:
 105        spin_unlock_irqrestore(&clockfw_lock, flags);
 106}
 107EXPORT_SYMBOL(clk_disable);
 108
 109unsigned long clk_get_rate(struct clk *clk)
 110{
 111        unsigned long flags;
 112        unsigned long ret = 0;
 113
 114        if (clk == NULL || IS_ERR(clk))
 115                return 0;
 116
 117        spin_lock_irqsave(&clockfw_lock, flags);
 118        ret = clk->rate;
 119        spin_unlock_irqrestore(&clockfw_lock, flags);
 120
 121        return ret;
 122}
 123EXPORT_SYMBOL(clk_get_rate);
 124
 125/*-------------------------------------------------------------------------
 126 * Optional clock functions defined in include/linux/clk.h
 127 *-------------------------------------------------------------------------*/
 128
 129long clk_round_rate(struct clk *clk, unsigned long rate)
 130{
 131        unsigned long flags;
 132        long ret = 0;
 133
 134        if (clk == NULL || IS_ERR(clk))
 135                return ret;
 136
 137        spin_lock_irqsave(&clockfw_lock, flags);
 138        if (arch_clock->clk_round_rate)
 139                ret = arch_clock->clk_round_rate(clk, rate);
 140        spin_unlock_irqrestore(&clockfw_lock, flags);
 141
 142        return ret;
 143}
 144EXPORT_SYMBOL(clk_round_rate);
 145
 146int clk_set_rate(struct clk *clk, unsigned long rate)
 147{
 148        unsigned long flags;
 149        int ret = -EINVAL;
 150
 151        if (clk == NULL || IS_ERR(clk))
 152                return ret;
 153
 154        spin_lock_irqsave(&clockfw_lock, flags);
 155        if (arch_clock->clk_set_rate)
 156                ret = arch_clock->clk_set_rate(clk, rate);
 157        if (ret == 0) {
 158                if (clk->recalc)
 159                        clk->rate = clk->recalc(clk);
 160                propagate_rate(clk);
 161        }
 162        spin_unlock_irqrestore(&clockfw_lock, flags);
 163
 164        return ret;
 165}
 166EXPORT_SYMBOL(clk_set_rate);
 167
 168int clk_set_parent(struct clk *clk, struct clk *parent)
 169{
 170        unsigned long flags;
 171        int ret = -EINVAL;
 172
 173        if (cpu_is_omap44xx())
 174        /* OMAP4 clk framework not supported yet */
 175                return 0;
 176        if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
 177                return ret;
 178
 179        spin_lock_irqsave(&clockfw_lock, flags);
 180        if (clk->usecount == 0) {
 181                if (arch_clock->clk_set_parent)
 182                        ret = arch_clock->clk_set_parent(clk, parent);
 183                if (ret == 0) {
 184                        if (clk->recalc)
 185                                clk->rate = clk->recalc(clk);
 186                        propagate_rate(clk);
 187                }
 188        } else
 189                ret = -EBUSY;
 190        spin_unlock_irqrestore(&clockfw_lock, flags);
 191
 192        return ret;
 193}
 194EXPORT_SYMBOL(clk_set_parent);
 195
 196struct clk *clk_get_parent(struct clk *clk)
 197{
 198        return clk->parent;
 199}
 200EXPORT_SYMBOL(clk_get_parent);
 201
 202/*-------------------------------------------------------------------------
 203 * OMAP specific clock functions shared between omap1 and omap2
 204 *-------------------------------------------------------------------------*/
 205
 206unsigned int __initdata mpurate;
 207
 208/*
 209 * By default we use the rate set by the bootloader.
 210 * You can override this with mpurate= cmdline option.
 211 */
 212static int __init omap_clk_setup(char *str)
 213{
 214        get_option(&str, &mpurate);
 215
 216        if (!mpurate)
 217                return 1;
 218
 219        if (mpurate < 1000)
 220                mpurate *= 1000000;
 221
 222        return 1;
 223}
 224__setup("mpurate=", omap_clk_setup);
 225
 226/* Used for clocks that always have same value as the parent clock */
 227unsigned long followparent_recalc(struct clk *clk)
 228{
 229        return clk->parent->rate;
 230}
 231
 232void clk_reparent(struct clk *child, struct clk *parent)
 233{
 234        list_del_init(&child->sibling);
 235        if (parent)
 236                list_add(&child->sibling, &parent->children);
 237        child->parent = parent;
 238
 239        /* now do the debugfs renaming to reattach the child
 240           to the proper parent */
 241}
 242
 243/* Propagate rate to children */
 244void propagate_rate(struct clk * tclk)
 245{
 246        struct clk *clkp;
 247
 248        list_for_each_entry(clkp, &tclk->children, sibling) {
 249                if (clkp->recalc)
 250                        clkp->rate = clkp->recalc(clkp);
 251                propagate_rate(clkp);
 252        }
 253}
 254
 255static LIST_HEAD(root_clks);
 256
 257/**
 258 * recalculate_root_clocks - recalculate and propagate all root clocks
 259 *
 260 * Recalculates all root clocks (clocks with no parent), which if the
 261 * clock's .recalc is set correctly, should also propagate their rates.
 262 * Called at init.
 263 */
 264void recalculate_root_clocks(void)
 265{
 266        struct clk *clkp;
 267
 268        list_for_each_entry(clkp, &root_clks, sibling) {
 269                if (clkp->recalc)
 270                        clkp->rate = clkp->recalc(clkp);
 271                propagate_rate(clkp);
 272        }
 273}
 274
 275/**
 276 * clk_preinit - initialize any fields in the struct clk before clk init
 277 * @clk: struct clk * to initialize
 278 *
 279 * Initialize any struct clk fields needed before normal clk initialization
 280 * can run.  No return value.
 281 */
 282void clk_preinit(struct clk *clk)
 283{
 284        INIT_LIST_HEAD(&clk->children);
 285}
 286
 287int clk_register(struct clk *clk)
 288{
 289        if (clk == NULL || IS_ERR(clk))
 290                return -EINVAL;
 291
 292        /*
 293         * trap out already registered clocks
 294         */
 295        if (clk->node.next || clk->node.prev)
 296                return 0;
 297
 298        mutex_lock(&clocks_mutex);
 299        if (clk->parent)
 300                list_add(&clk->sibling, &clk->parent->children);
 301        else
 302                list_add(&clk->sibling, &root_clks);
 303
 304        list_add(&clk->node, &clocks);
 305        if (clk->init)
 306                clk->init(clk);
 307        mutex_unlock(&clocks_mutex);
 308
 309        return 0;
 310}
 311EXPORT_SYMBOL(clk_register);
 312
 313void clk_unregister(struct clk *clk)
 314{
 315        if (clk == NULL || IS_ERR(clk))
 316                return;
 317
 318        mutex_lock(&clocks_mutex);
 319        list_del(&clk->sibling);
 320        list_del(&clk->node);
 321        mutex_unlock(&clocks_mutex);
 322}
 323EXPORT_SYMBOL(clk_unregister);
 324
 325void clk_enable_init_clocks(void)
 326{
 327        struct clk *clkp;
 328
 329        list_for_each_entry(clkp, &clocks, node) {
 330                if (clkp->flags & ENABLE_ON_INIT)
 331                        clk_enable(clkp);
 332        }
 333}
 334EXPORT_SYMBOL(clk_enable_init_clocks);
 335
 336/*
 337 * Low level helpers
 338 */
 339static int clkll_enable_null(struct clk *clk)
 340{
 341        return 0;
 342}
 343
 344static void clkll_disable_null(struct clk *clk)
 345{
 346}
 347
 348const struct clkops clkops_null = {
 349        .enable         = clkll_enable_null,
 350        .disable        = clkll_disable_null,
 351};
 352
 353#ifdef CONFIG_CPU_FREQ
 354void clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
 355{
 356        unsigned long flags;
 357
 358        spin_lock_irqsave(&clockfw_lock, flags);
 359        if (arch_clock->clk_init_cpufreq_table)
 360                arch_clock->clk_init_cpufreq_table(table);
 361        spin_unlock_irqrestore(&clockfw_lock, flags);
 362}
 363EXPORT_SYMBOL(clk_init_cpufreq_table);
 364#endif
 365
 366/*-------------------------------------------------------------------------*/
 367
 368#ifdef CONFIG_OMAP_RESET_CLOCKS
 369/*
 370 * Disable any unused clocks left on by the bootloader
 371 */
 372static int __init clk_disable_unused(void)
 373{
 374        struct clk *ck;
 375        unsigned long flags;
 376
 377        list_for_each_entry(ck, &clocks, node) {
 378                if (ck->ops == &clkops_null)
 379                        continue;
 380
 381                if (ck->usecount > 0 || ck->enable_reg == 0)
 382                        continue;
 383
 384                spin_lock_irqsave(&clockfw_lock, flags);
 385                if (arch_clock->clk_disable_unused)
 386                        arch_clock->clk_disable_unused(ck);
 387                spin_unlock_irqrestore(&clockfw_lock, flags);
 388        }
 389
 390        return 0;
 391}
 392late_initcall(clk_disable_unused);
 393#endif
 394
 395int __init clk_init(struct clk_functions * custom_clocks)
 396{
 397        if (!custom_clocks) {
 398                printk(KERN_ERR "No custom clock functions registered\n");
 399                BUG();
 400        }
 401
 402        arch_clock = custom_clocks;
 403
 404        return 0;
 405}
 406
 407#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
 408/*
 409 *      debugfs support to trace clock tree hierarchy and attributes
 410 */
 411static struct dentry *clk_debugfs_root;
 412
 413static int clk_debugfs_register_one(struct clk *c)
 414{
 415        int err;
 416        struct dentry *d, *child;
 417        struct clk *pa = c->parent;
 418        char s[255];
 419        char *p = s;
 420
 421        p += sprintf(p, "%s", c->name);
 422        if (c->id != 0)
 423                sprintf(p, ":%d", c->id);
 424        d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
 425        if (!d)
 426                return -ENOMEM;
 427        c->dent = d;
 428
 429        d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
 430        if (!d) {
 431                err = -ENOMEM;
 432                goto err_out;
 433        }
 434        d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
 435        if (!d) {
 436                err = -ENOMEM;
 437                goto err_out;
 438        }
 439        d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
 440        if (!d) {
 441                err = -ENOMEM;
 442                goto err_out;
 443        }
 444        return 0;
 445
 446err_out:
 447        d = c->dent;
 448        list_for_each_entry(child, &d->d_subdirs, d_u.d_child)
 449                debugfs_remove(child);
 450        debugfs_remove(c->dent);
 451        return err;
 452}
 453
 454static int clk_debugfs_register(struct clk *c)
 455{
 456        int err;
 457        struct clk *pa = c->parent;
 458
 459        if (pa && !pa->dent) {
 460                err = clk_debugfs_register(pa);
 461                if (err)
 462                        return err;
 463        }
 464
 465        if (!c->dent) {
 466                err = clk_debugfs_register_one(c);
 467                if (err)
 468                        return err;
 469        }
 470        return 0;
 471}
 472
 473static int __init clk_debugfs_init(void)
 474{
 475        struct clk *c;
 476        struct dentry *d;
 477        int err;
 478
 479        d = debugfs_create_dir("clock", NULL);
 480        if (!d)
 481                return -ENOMEM;
 482        clk_debugfs_root = d;
 483
 484        list_for_each_entry(c, &clocks, node) {
 485                err = clk_debugfs_register(c);
 486                if (err)
 487                        goto err_out;
 488        }
 489        return 0;
 490err_out:
 491        debugfs_remove_recursive(clk_debugfs_root);
 492        return err;
 493}
 494late_initcall(clk_debugfs_init);
 495
 496#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
 497