linux/arch/arm/plat-omap/clock.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/plat-omap/clock.c
   3 *
   4 *  Copyright (C) 2004 - 2005 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/version.h>
  14#include <linux/kernel.h>
  15#include <linux/init.h>
  16#include <linux/module.h>
  17#include <linux/list.h>
  18#include <linux/errno.h>
  19#include <linux/err.h>
  20#include <linux/string.h>
  21#include <linux/clk.h>
  22#include <linux/mutex.h>
  23#include <linux/platform_device.h>
  24
  25#include <asm/io.h>
  26#include <asm/semaphore.h>
  27
  28#include <asm/arch/clock.h>
  29
  30static LIST_HEAD(clocks);
  31static DEFINE_MUTEX(clocks_mutex);
  32static DEFINE_SPINLOCK(clockfw_lock);
  33
  34static struct clk_functions *arch_clock;
  35
  36#ifdef CONFIG_PM_DEBUG
  37
  38static void print_parents(struct clk *clk)
  39{
  40        struct clk *p;
  41        int printed = 0;
  42
  43        list_for_each_entry(p, &clocks, node) {
  44                if (p->parent == clk && p->usecount) {
  45                        if (!clk->usecount && !printed) {
  46                                printk("MISMATCH: %s\n", clk->name);
  47                                printed = 1;
  48                        }
  49                        printk("\t%-15s\n", p->name);
  50                }
  51        }
  52}
  53
  54void clk_print_usecounts(void)
  55{
  56        unsigned long flags;
  57        struct clk *p;
  58
  59        spin_lock_irqsave(&clockfw_lock, flags);
  60        list_for_each_entry(p, &clocks, node) {
  61                if (p->usecount)
  62                        printk("%-15s: %d\n", p->name, p->usecount);
  63                print_parents(p);
  64
  65        }
  66        spin_unlock_irqrestore(&clockfw_lock, flags);
  67}
  68
  69#endif
  70
  71/*-------------------------------------------------------------------------
  72 * Standard clock functions defined in include/linux/clk.h
  73 *-------------------------------------------------------------------------*/
  74
  75/*
  76 * Returns a clock. Note that we first try to use device id on the bus
  77 * and clock name. If this fails, we try to use clock name only.
  78 */
  79struct clk * clk_get(struct device *dev, const char *id)
  80{
  81        struct clk *p, *clk = ERR_PTR(-ENOENT);
  82        int idno;
  83
  84        if (dev == NULL || dev->bus != &platform_bus_type)
  85                idno = -1;
  86        else
  87                idno = to_platform_device(dev)->id;
  88
  89        mutex_lock(&clocks_mutex);
  90
  91        list_for_each_entry(p, &clocks, node) {
  92                if (p->id == idno &&
  93                    strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
  94                        clk = p;
  95                        goto found;
  96                }
  97        }
  98
  99        list_for_each_entry(p, &clocks, node) {
 100                if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
 101                        clk = p;
 102                        break;
 103                }
 104        }
 105
 106found:
 107        mutex_unlock(&clocks_mutex);
 108
 109        return clk;
 110}
 111EXPORT_SYMBOL(clk_get);
 112
 113int clk_enable(struct clk *clk)
 114{
 115        unsigned long flags;
 116        int ret = 0;
 117
 118        if (clk == NULL || IS_ERR(clk))
 119                return -EINVAL;
 120
 121        spin_lock_irqsave(&clockfw_lock, flags);
 122        if (arch_clock->clk_enable)
 123                ret = arch_clock->clk_enable(clk);
 124        spin_unlock_irqrestore(&clockfw_lock, flags);
 125
 126        return ret;
 127}
 128EXPORT_SYMBOL(clk_enable);
 129
 130void clk_disable(struct clk *clk)
 131{
 132        unsigned long flags;
 133
 134        if (clk == NULL || IS_ERR(clk))
 135                return;
 136
 137        spin_lock_irqsave(&clockfw_lock, flags);
 138        BUG_ON(clk->usecount == 0);
 139        if (arch_clock->clk_disable)
 140                arch_clock->clk_disable(clk);
 141        spin_unlock_irqrestore(&clockfw_lock, flags);
 142}
 143EXPORT_SYMBOL(clk_disable);
 144
 145int clk_get_usecount(struct clk *clk)
 146{
 147        unsigned long flags;
 148        int ret = 0;
 149
 150        if (clk == NULL || IS_ERR(clk))
 151                return 0;
 152
 153        spin_lock_irqsave(&clockfw_lock, flags);
 154        ret = clk->usecount;
 155        spin_unlock_irqrestore(&clockfw_lock, flags);
 156
 157        return ret;
 158}
 159EXPORT_SYMBOL(clk_get_usecount);
 160
 161unsigned long clk_get_rate(struct clk *clk)
 162{
 163        unsigned long flags;
 164        unsigned long ret = 0;
 165
 166        if (clk == NULL || IS_ERR(clk))
 167                return 0;
 168
 169        spin_lock_irqsave(&clockfw_lock, flags);
 170        ret = clk->rate;
 171        spin_unlock_irqrestore(&clockfw_lock, flags);
 172
 173        return ret;
 174}
 175EXPORT_SYMBOL(clk_get_rate);
 176
 177void clk_put(struct clk *clk)
 178{
 179        if (clk && !IS_ERR(clk))
 180                module_put(clk->owner);
 181}
 182EXPORT_SYMBOL(clk_put);
 183
 184/*-------------------------------------------------------------------------
 185 * Optional clock functions defined in include/linux/clk.h
 186 *-------------------------------------------------------------------------*/
 187
 188long clk_round_rate(struct clk *clk, unsigned long rate)
 189{
 190        unsigned long flags;
 191        long ret = 0;
 192
 193        if (clk == NULL || IS_ERR(clk))
 194                return ret;
 195
 196        spin_lock_irqsave(&clockfw_lock, flags);
 197        if (arch_clock->clk_round_rate)
 198                ret = arch_clock->clk_round_rate(clk, rate);
 199        spin_unlock_irqrestore(&clockfw_lock, flags);
 200
 201        return ret;
 202}
 203EXPORT_SYMBOL(clk_round_rate);
 204
 205int clk_set_rate(struct clk *clk, unsigned long rate)
 206{
 207        unsigned long flags;
 208        int ret = -EINVAL;
 209
 210        if (clk == NULL || IS_ERR(clk))
 211                return ret;
 212
 213        spin_lock_irqsave(&clockfw_lock, flags);
 214        if (arch_clock->clk_set_rate)
 215                ret = arch_clock->clk_set_rate(clk, rate);
 216        spin_unlock_irqrestore(&clockfw_lock, flags);
 217
 218        return ret;
 219}
 220EXPORT_SYMBOL(clk_set_rate);
 221
 222int clk_set_parent(struct clk *clk, struct clk *parent)
 223{
 224        unsigned long flags;
 225        int ret = -EINVAL;
 226
 227        if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
 228                return ret;
 229
 230        spin_lock_irqsave(&clockfw_lock, flags);
 231        if (arch_clock->clk_set_parent)
 232                ret =  arch_clock->clk_set_parent(clk, parent);
 233        spin_unlock_irqrestore(&clockfw_lock, flags);
 234
 235        return ret;
 236}
 237EXPORT_SYMBOL(clk_set_parent);
 238
 239struct clk *clk_get_parent(struct clk *clk)
 240{
 241        unsigned long flags;
 242        struct clk * ret = NULL;
 243
 244        if (clk == NULL || IS_ERR(clk))
 245                return ret;
 246
 247        spin_lock_irqsave(&clockfw_lock, flags);
 248        if (arch_clock->clk_get_parent)
 249                ret = arch_clock->clk_get_parent(clk);
 250        spin_unlock_irqrestore(&clockfw_lock, flags);
 251
 252        return ret;
 253}
 254EXPORT_SYMBOL(clk_get_parent);
 255
 256/*-------------------------------------------------------------------------
 257 * OMAP specific clock functions shared between omap1 and omap2
 258 *-------------------------------------------------------------------------*/
 259
 260unsigned int __initdata mpurate;
 261
 262/*
 263 * By default we use the rate set by the bootloader.
 264 * You can override this with mpurate= cmdline option.
 265 */
 266static int __init omap_clk_setup(char *str)
 267{
 268        get_option(&str, &mpurate);
 269
 270        if (!mpurate)
 271                return 1;
 272
 273        if (mpurate < 1000)
 274                mpurate *= 1000000;
 275
 276        return 1;
 277}
 278__setup("mpurate=", omap_clk_setup);
 279
 280/* Used for clocks that always have same value as the parent clock */
 281void followparent_recalc(struct clk *clk)
 282{
 283        if (clk == NULL || IS_ERR(clk))
 284                return;
 285
 286        clk->rate = clk->parent->rate;
 287        if (unlikely(clk->flags & RATE_PROPAGATES))
 288                propagate_rate(clk);
 289}
 290
 291/* Propagate rate to children */
 292void propagate_rate(struct clk * tclk)
 293{
 294        struct clk *clkp;
 295
 296        if (tclk == NULL || IS_ERR(tclk))
 297                return;
 298
 299        list_for_each_entry(clkp, &clocks, node) {
 300                if (likely(clkp->parent != tclk))
 301                        continue;
 302                if (likely((u32)clkp->recalc))
 303                        clkp->recalc(clkp);
 304        }
 305}
 306
 307int clk_register(struct clk *clk)
 308{
 309        if (clk == NULL || IS_ERR(clk))
 310                return -EINVAL;
 311
 312        mutex_lock(&clocks_mutex);
 313        list_add(&clk->node, &clocks);
 314        if (clk->init)
 315                clk->init(clk);
 316        mutex_unlock(&clocks_mutex);
 317
 318        return 0;
 319}
 320EXPORT_SYMBOL(clk_register);
 321
 322void clk_unregister(struct clk *clk)
 323{
 324        if (clk == NULL || IS_ERR(clk))
 325                return;
 326
 327        mutex_lock(&clocks_mutex);
 328        list_del(&clk->node);
 329        mutex_unlock(&clocks_mutex);
 330}
 331EXPORT_SYMBOL(clk_unregister);
 332
 333void clk_deny_idle(struct clk *clk)
 334{
 335        unsigned long flags;
 336
 337        if (clk == NULL || IS_ERR(clk))
 338                return;
 339
 340        spin_lock_irqsave(&clockfw_lock, flags);
 341        if (arch_clock->clk_deny_idle)
 342                arch_clock->clk_deny_idle(clk);
 343        spin_unlock_irqrestore(&clockfw_lock, flags);
 344}
 345EXPORT_SYMBOL(clk_deny_idle);
 346
 347void clk_allow_idle(struct clk *clk)
 348{
 349        unsigned long flags;
 350
 351        if (clk == NULL || IS_ERR(clk))
 352                return;
 353
 354        spin_lock_irqsave(&clockfw_lock, flags);
 355        if (arch_clock->clk_allow_idle)
 356                arch_clock->clk_allow_idle(clk);
 357        spin_unlock_irqrestore(&clockfw_lock, flags);
 358}
 359EXPORT_SYMBOL(clk_allow_idle);
 360
 361/*-------------------------------------------------------------------------*/
 362
 363#ifdef CONFIG_OMAP_RESET_CLOCKS
 364/*
 365 * Disable any unused clocks left on by the bootloader
 366 */
 367static int __init clk_disable_unused(void)
 368{
 369        struct clk *ck;
 370        unsigned long flags;
 371
 372        list_for_each_entry(ck, &clocks, node) {
 373                if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
 374                        ck->enable_reg == 0)
 375                        continue;
 376
 377                spin_lock_irqsave(&clockfw_lock, flags);
 378                if (arch_clock->clk_disable_unused)
 379                        arch_clock->clk_disable_unused(ck);
 380                spin_unlock_irqrestore(&clockfw_lock, flags);
 381        }
 382
 383        return 0;
 384}
 385late_initcall(clk_disable_unused);
 386#endif
 387
 388int __init clk_init(struct clk_functions * custom_clocks)
 389{
 390        if (!custom_clocks) {
 391                printk(KERN_ERR "No custom clock functions registered\n");
 392                BUG();
 393        }
 394
 395        arch_clock = custom_clocks;
 396
 397        return 0;
 398}
 399
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.