linux/arch/arm/plat-samsung/clock.c
<<
>>
Prefs
   1/* linux/arch/arm/plat-s3c24xx/clock.c
   2 *
   3 * Copyright 2004-2005 Simtec Electronics
   4 *      Ben Dooks <ben@simtec.co.uk>
   5 *
   6 * S3C24XX Core clock control support
   7 *
   8 * Based on, and code from linux/arch/arm/mach-versatile/clock.c
   9 **
  10 **  Copyright (C) 2004 ARM Limited.
  11 **  Written by Deep Blue Solutions Limited.
  12 *
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License as published by
  16 * the Free Software Foundation; either version 2 of the License, or
  17 * (at your option) any later version.
  18 *
  19 * This program is distributed in the hope that it will be useful,
  20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22 * GNU General Public License for more details.
  23 *
  24 * You should have received a copy of the GNU General Public License
  25 * along with this program; if not, write to the Free Software
  26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  27*/
  28
  29#include <linux/init.h>
  30#include <linux/module.h>
  31#include <linux/kernel.h>
  32#include <linux/list.h>
  33#include <linux/errno.h>
  34#include <linux/err.h>
  35#include <linux/platform_device.h>
  36#include <linux/device.h>
  37#include <linux/interrupt.h>
  38#include <linux/ioport.h>
  39#include <linux/clk.h>
  40#include <linux/spinlock.h>
  41#include <linux/io.h>
  42#if defined(CONFIG_DEBUG_FS)
  43#include <linux/debugfs.h>
  44#endif
  45
  46#include <mach/hardware.h>
  47#include <asm/irq.h>
  48
  49#include <plat/cpu-freq.h>
  50
  51#include <plat/clock.h>
  52#include <plat/cpu.h>
  53
  54#include <linux/serial_core.h>
  55#include <plat/regs-serial.h> /* for s3c24xx_uart_devs */
  56
  57/* clock information */
  58
  59static LIST_HEAD(clocks);
  60
  61/* We originally used an mutex here, but some contexts (see resume)
  62 * are calling functions such as clk_set_parent() with IRQs disabled
  63 * causing an BUG to be triggered.
  64 */
  65DEFINE_SPINLOCK(clocks_lock);
  66
  67/* Global watchdog clock used by arch_wtd_reset() callback */
  68struct clk *s3c2410_wdtclk;
  69static int __init s3c_wdt_reset_init(void)
  70{
  71        s3c2410_wdtclk = clk_get(NULL, "watchdog");
  72        if (IS_ERR(s3c2410_wdtclk))
  73                printk(KERN_WARNING "%s: warning: cannot get watchdog clock\n", __func__);
  74        return 0;
  75}
  76arch_initcall(s3c_wdt_reset_init);
  77
  78/* enable and disable calls for use with the clk struct */
  79
  80static int clk_null_enable(struct clk *clk, int enable)
  81{
  82        return 0;
  83}
  84
  85int clk_enable(struct clk *clk)
  86{
  87        unsigned long flags;
  88
  89        if (IS_ERR(clk) || clk == NULL)
  90                return -EINVAL;
  91
  92        clk_enable(clk->parent);
  93
  94        spin_lock_irqsave(&clocks_lock, flags);
  95
  96        if ((clk->usage++) == 0)
  97                (clk->enable)(clk, 1);
  98
  99        spin_unlock_irqrestore(&clocks_lock, flags);
 100        return 0;
 101}
 102
 103void clk_disable(struct clk *clk)
 104{
 105        unsigned long flags;
 106
 107        if (IS_ERR(clk) || clk == NULL)
 108                return;
 109
 110        spin_lock_irqsave(&clocks_lock, flags);
 111
 112        if ((--clk->usage) == 0)
 113                (clk->enable)(clk, 0);
 114
 115        spin_unlock_irqrestore(&clocks_lock, flags);
 116        clk_disable(clk->parent);
 117}
 118
 119
 120unsigned long clk_get_rate(struct clk *clk)
 121{
 122        if (IS_ERR_OR_NULL(clk))
 123                return 0;
 124
 125        if (clk->rate != 0)
 126                return clk->rate;
 127
 128        if (clk->ops != NULL && clk->ops->get_rate != NULL)
 129                return (clk->ops->get_rate)(clk);
 130
 131        if (clk->parent != NULL)
 132                return clk_get_rate(clk->parent);
 133
 134        return clk->rate;
 135}
 136
 137long clk_round_rate(struct clk *clk, unsigned long rate)
 138{
 139        if (!IS_ERR_OR_NULL(clk) && clk->ops && clk->ops->round_rate)
 140                return (clk->ops->round_rate)(clk, rate);
 141
 142        return rate;
 143}
 144
 145int clk_set_rate(struct clk *clk, unsigned long rate)
 146{
 147        unsigned long flags;
 148        int ret;
 149
 150        if (IS_ERR_OR_NULL(clk))
 151                return -EINVAL;
 152
 153        /* We do not default just do a clk->rate = rate as
 154         * the clock may have been made this way by choice.
 155         */
 156
 157        WARN_ON(clk->ops == NULL);
 158        WARN_ON(clk->ops && clk->ops->set_rate == NULL);
 159
 160        if (clk->ops == NULL || clk->ops->set_rate == NULL)
 161                return -EINVAL;
 162
 163        spin_lock_irqsave(&clocks_lock, flags);
 164        ret = (clk->ops->set_rate)(clk, rate);
 165        spin_unlock_irqrestore(&clocks_lock, flags);
 166
 167        return ret;
 168}
 169
 170struct clk *clk_get_parent(struct clk *clk)
 171{
 172        return clk->parent;
 173}
 174
 175int clk_set_parent(struct clk *clk, struct clk *parent)
 176{
 177        unsigned long flags;
 178        int ret = 0;
 179
 180        if (IS_ERR_OR_NULL(clk) || IS_ERR_OR_NULL(parent))
 181                return -EINVAL;
 182
 183        spin_lock_irqsave(&clocks_lock, flags);
 184
 185        if (clk->ops && clk->ops->set_parent)
 186                ret = (clk->ops->set_parent)(clk, parent);
 187
 188        spin_unlock_irqrestore(&clocks_lock, flags);
 189
 190        return ret;
 191}
 192
 193EXPORT_SYMBOL(clk_enable);
 194EXPORT_SYMBOL(clk_disable);
 195EXPORT_SYMBOL(clk_get_rate);
 196EXPORT_SYMBOL(clk_round_rate);
 197EXPORT_SYMBOL(clk_set_rate);
 198EXPORT_SYMBOL(clk_get_parent);
 199EXPORT_SYMBOL(clk_set_parent);
 200
 201/* base clocks */
 202
 203int clk_default_setrate(struct clk *clk, unsigned long rate)
 204{
 205        clk->rate = rate;
 206        return 0;
 207}
 208
 209struct clk_ops clk_ops_def_setrate = {
 210        .set_rate       = clk_default_setrate,
 211};
 212
 213struct clk clk_xtal = {
 214        .name           = "xtal",
 215        .rate           = 0,
 216        .parent         = NULL,
 217        .ctrlbit        = 0,
 218};
 219
 220struct clk clk_ext = {
 221        .name           = "ext",
 222};
 223
 224struct clk clk_epll = {
 225        .name           = "epll",
 226};
 227
 228struct clk clk_mpll = {
 229        .name           = "mpll",
 230        .ops            = &clk_ops_def_setrate,
 231};
 232
 233struct clk clk_upll = {
 234        .name           = "upll",
 235        .parent         = NULL,
 236        .ctrlbit        = 0,
 237};
 238
 239struct clk clk_f = {
 240        .name           = "fclk",
 241        .rate           = 0,
 242        .parent         = &clk_mpll,
 243        .ctrlbit        = 0,
 244};
 245
 246struct clk clk_h = {
 247        .name           = "hclk",
 248        .rate           = 0,
 249        .parent         = NULL,
 250        .ctrlbit        = 0,
 251        .ops            = &clk_ops_def_setrate,
 252};
 253
 254struct clk clk_p = {
 255        .name           = "pclk",
 256        .rate           = 0,
 257        .parent         = NULL,
 258        .ctrlbit        = 0,
 259        .ops            = &clk_ops_def_setrate,
 260};
 261
 262struct clk clk_usb_bus = {
 263        .name           = "usb-bus",
 264        .rate           = 0,
 265        .parent         = &clk_upll,
 266};
 267
 268
 269struct clk s3c24xx_uclk = {
 270        .name           = "uclk",
 271};
 272
 273/* initialise the clock system */
 274
 275/**
 276 * s3c24xx_register_clock() - register a clock
 277 * @clk: The clock to register
 278 *
 279 * Add the specified clock to the list of clocks known by the system.
 280 */
 281int s3c24xx_register_clock(struct clk *clk)
 282{
 283        if (clk->enable == NULL)
 284                clk->enable = clk_null_enable;
 285
 286        /* fill up the clk_lookup structure and register it*/
 287        clk->lookup.dev_id = clk->devname;
 288        clk->lookup.con_id = clk->name;
 289        clk->lookup.clk = clk;
 290        clkdev_add(&clk->lookup);
 291
 292        return 0;
 293}
 294
 295/**
 296 * s3c24xx_register_clocks() - register an array of clock pointers
 297 * @clks: Pointer to an array of struct clk pointers
 298 * @nr_clks: The number of clocks in the @clks array.
 299 *
 300 * Call s3c24xx_register_clock() for all the clock pointers contained
 301 * in the @clks list. Returns the number of failures.
 302 */
 303int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
 304{
 305        int fails = 0;
 306
 307        for (; nr_clks > 0; nr_clks--, clks++) {
 308                if (s3c24xx_register_clock(*clks) < 0) {
 309                        struct clk *clk = *clks;
 310                        printk(KERN_ERR "%s: failed to register %p: %s\n",
 311                               __func__, clk, clk->name);
 312                        fails++;
 313                }
 314        }
 315
 316        return fails;
 317}
 318
 319/**
 320 * s3c_register_clocks() - register an array of clocks
 321 * @clkp: Pointer to the first clock in the array.
 322 * @nr_clks: Number of clocks to register.
 323 *
 324 * Call s3c24xx_register_clock() on the @clkp array given, printing an
 325 * error if it fails to register the clock (unlikely).
 326 */
 327void __init s3c_register_clocks(struct clk *clkp, int nr_clks)
 328{
 329        int ret;
 330
 331        for (; nr_clks > 0; nr_clks--, clkp++) {
 332                ret = s3c24xx_register_clock(clkp);
 333
 334                if (ret < 0) {
 335                        printk(KERN_ERR "Failed to register clock %s (%d)\n",
 336                               clkp->name, ret);
 337                }
 338        }
 339}
 340
 341/**
 342 * s3c_disable_clocks() - disable an array of clocks
 343 * @clkp: Pointer to the first clock in the array.
 344 * @nr_clks: Number of clocks to register.
 345 *
 346 * for internal use only at initialisation time. disable the clocks in the
 347 * @clkp array.
 348 */
 349
 350void __init s3c_disable_clocks(struct clk *clkp, int nr_clks)
 351{
 352        for (; nr_clks > 0; nr_clks--, clkp++)
 353                (clkp->enable)(clkp, 0);
 354}
 355
 356/* initialise all the clocks */
 357
 358int __init s3c24xx_register_baseclocks(unsigned long xtal)
 359{
 360        printk(KERN_INFO "S3C24XX Clocks, Copyright 2004 Simtec Electronics\n");
 361
 362        clk_xtal.rate = xtal;
 363
 364        /* register our clocks */
 365
 366        if (s3c24xx_register_clock(&clk_xtal) < 0)
 367                printk(KERN_ERR "failed to register master xtal\n");
 368
 369        if (s3c24xx_register_clock(&clk_mpll) < 0)
 370                printk(KERN_ERR "failed to register mpll clock\n");
 371
 372        if (s3c24xx_register_clock(&clk_upll) < 0)
 373                printk(KERN_ERR "failed to register upll clock\n");
 374
 375        if (s3c24xx_register_clock(&clk_f) < 0)
 376                printk(KERN_ERR "failed to register cpu fclk\n");
 377
 378        if (s3c24xx_register_clock(&clk_h) < 0)
 379                printk(KERN_ERR "failed to register cpu hclk\n");
 380
 381        if (s3c24xx_register_clock(&clk_p) < 0)
 382                printk(KERN_ERR "failed to register cpu pclk\n");
 383
 384        return 0;
 385}
 386
 387#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
 388/* debugfs support to trace clock tree hierarchy and attributes */
 389
 390static struct dentry *clk_debugfs_root;
 391
 392static void clock_tree_show_one(struct seq_file *s, struct clk *c, int level)
 393{
 394        struct clk *child;
 395        const char *state;
 396        char buf[255] = { 0 };
 397        int n = 0;
 398
 399        if (c->name)
 400                n = snprintf(buf, sizeof(buf) - 1, "%s", c->name);
 401
 402        if (c->devname)
 403                n += snprintf(buf + n, sizeof(buf) - 1 - n, ":%s", c->devname);
 404
 405        state = (c->usage > 0) ? "on" : "off";
 406
 407        seq_printf(s, "%*s%-*s %-6s %-3d %-10lu\n",
 408                   level * 3 + 1, "",
 409                   50 - level * 3, buf,
 410                   state, c->usage, clk_get_rate(c));
 411
 412        list_for_each_entry(child, &clocks, list) {
 413                if (child->parent != c)
 414                        continue;
 415
 416                clock_tree_show_one(s, child, level + 1);
 417        }
 418}
 419
 420static int clock_tree_show(struct seq_file *s, void *data)
 421{
 422        struct clk *c;
 423        unsigned long flags;
 424
 425        seq_printf(s, " clock state ref rate\n");
 426        seq_printf(s, "----------------------------------------------------\n");
 427
 428        spin_lock_irqsave(&clocks_lock, flags);
 429
 430        list_for_each_entry(c, &clocks, list)
 431                if (c->parent == NULL)
 432                        clock_tree_show_one(s, c, 0);
 433
 434        spin_unlock_irqrestore(&clocks_lock, flags);
 435        return 0;
 436}
 437
 438static int clock_tree_open(struct inode *inode, struct file *file)
 439{
 440        return single_open(file, clock_tree_show, inode->i_private);
 441}
 442
 443static const struct file_operations clock_tree_fops = {
 444        .open           = clock_tree_open,
 445        .read           = seq_read,
 446        .llseek         = seq_lseek,
 447        .release        = single_release,
 448};
 449
 450static int clock_rate_show(void *data, u64 *val)
 451{
 452        struct clk *c = data;
 453        *val = clk_get_rate(c);
 454        return 0;
 455}
 456DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_rate_show, NULL, "%llu\n");
 457
 458static int clk_debugfs_register_one(struct clk *c)
 459{
 460        int err;
 461        struct dentry *d;
 462        struct clk *pa = c->parent;
 463        char s[255];
 464        char *p = s;
 465
 466        p += sprintf(p, "%s", c->devname);
 467
 468        d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
 469        if (!d)
 470                return -ENOMEM;
 471
 472        c->dent = d;
 473
 474        d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usage);
 475        if (!d) {
 476                err = -ENOMEM;
 477                goto err_out;
 478        }
 479
 480        d = debugfs_create_file("rate", S_IRUGO, c->dent, c, &clock_rate_fops);
 481        if (!d) {
 482                err = -ENOMEM;
 483                goto err_out;
 484        }
 485        return 0;
 486
 487err_out:
 488        debugfs_remove_recursive(c->dent);
 489        return err;
 490}
 491
 492static int clk_debugfs_register(struct clk *c)
 493{
 494        int err;
 495        struct clk *pa = c->parent;
 496
 497        if (pa && !pa->dent) {
 498                err = clk_debugfs_register(pa);
 499                if (err)
 500                        return err;
 501        }
 502
 503        if (!c->dent) {
 504                err = clk_debugfs_register_one(c);
 505                if (err)
 506                        return err;
 507        }
 508        return 0;
 509}
 510
 511static int __init clk_debugfs_init(void)
 512{
 513        struct clk *c;
 514        struct dentry *d;
 515        int err = -ENOMEM;
 516
 517        d = debugfs_create_dir("clock", NULL);
 518        if (!d)
 519                return -ENOMEM;
 520        clk_debugfs_root = d;
 521
 522        d = debugfs_create_file("clock_tree", S_IRUGO, clk_debugfs_root, NULL,
 523                                 &clock_tree_fops);
 524        if (!d)
 525                goto err_out;
 526
 527        list_for_each_entry(c, &clocks, list) {
 528                err = clk_debugfs_register(c);
 529                if (err)
 530                        goto err_out;
 531        }
 532        return 0;
 533
 534err_out:
 535        debugfs_remove_recursive(clk_debugfs_root);
 536        return err;
 537}
 538late_initcall(clk_debugfs_init);
 539
 540#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
 541