linux/arch/arm/plat-s3c/clock.c
<<
>>
Prefs
   1/* linux/arch/arm/plat-s3c24xx/clock.c
   2 *
   3 * Copyright (c) 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/sysdev.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
  43#include <mach/hardware.h>
  44#include <asm/irq.h>
  45
  46#include <plat/cpu-freq.h>
  47
  48#include <plat/clock.h>
  49#include <plat/cpu.h>
  50
  51/* clock information */
  52
  53static LIST_HEAD(clocks);
  54
  55/* We originally used an mutex here, but some contexts (see resume)
  56 * are calling functions such as clk_set_parent() with IRQs disabled
  57 * causing an BUG to be triggered.
  58 */
  59DEFINE_SPINLOCK(clocks_lock);
  60
  61/* enable and disable calls for use with the clk struct */
  62
  63static int clk_null_enable(struct clk *clk, int enable)
  64{
  65        return 0;
  66}
  67
  68/* Clock API calls */
  69
  70struct clk *clk_get(struct device *dev, const char *id)
  71{
  72        struct clk *p;
  73        struct clk *clk = ERR_PTR(-ENOENT);
  74        int idno;
  75
  76        if (dev == NULL || dev->bus != &platform_bus_type)
  77                idno = -1;
  78        else
  79                idno = to_platform_device(dev)->id;
  80
  81        spin_lock(&clocks_lock);
  82
  83        list_for_each_entry(p, &clocks, list) {
  84                if (p->id == idno &&
  85                    strcmp(id, p->name) == 0 &&
  86                    try_module_get(p->owner)) {
  87                        clk = p;
  88                        break;
  89                }
  90        }
  91
  92        /* check for the case where a device was supplied, but the
  93         * clock that was being searched for is not device specific */
  94
  95        if (IS_ERR(clk)) {
  96                list_for_each_entry(p, &clocks, list) {
  97                        if (p->id == -1 && strcmp(id, p->name) == 0 &&
  98                            try_module_get(p->owner)) {
  99                                clk = p;
 100                                break;
 101                        }
 102                }
 103        }
 104
 105        spin_unlock(&clocks_lock);
 106        return clk;
 107}
 108
 109void clk_put(struct clk *clk)
 110{
 111        module_put(clk->owner);
 112}
 113
 114int clk_enable(struct clk *clk)
 115{
 116        if (IS_ERR(clk) || clk == NULL)
 117                return -EINVAL;
 118
 119        clk_enable(clk->parent);
 120
 121        spin_lock(&clocks_lock);
 122
 123        if ((clk->usage++) == 0)
 124                (clk->enable)(clk, 1);
 125
 126        spin_unlock(&clocks_lock);
 127        return 0;
 128}
 129
 130void clk_disable(struct clk *clk)
 131{
 132        if (IS_ERR(clk) || clk == NULL)
 133                return;
 134
 135        spin_lock(&clocks_lock);
 136
 137        if ((--clk->usage) == 0)
 138                (clk->enable)(clk, 0);
 139
 140        spin_unlock(&clocks_lock);
 141        clk_disable(clk->parent);
 142}
 143
 144
 145unsigned long clk_get_rate(struct clk *clk)
 146{
 147        if (IS_ERR(clk))
 148                return 0;
 149
 150        if (clk->rate != 0)
 151                return clk->rate;
 152
 153        if (clk->get_rate != NULL)
 154                return (clk->get_rate)(clk);
 155
 156        if (clk->parent != NULL)
 157                return clk_get_rate(clk->parent);
 158
 159        return clk->rate;
 160}
 161
 162long clk_round_rate(struct clk *clk, unsigned long rate)
 163{
 164        if (!IS_ERR(clk) && clk->round_rate)
 165                return (clk->round_rate)(clk, rate);
 166
 167        return rate;
 168}
 169
 170int clk_set_rate(struct clk *clk, unsigned long rate)
 171{
 172        int ret;
 173
 174        if (IS_ERR(clk))
 175                return -EINVAL;
 176
 177        /* We do not default just do a clk->rate = rate as
 178         * the clock may have been made this way by choice.
 179         */
 180
 181        WARN_ON(clk->set_rate == NULL);
 182
 183        if (clk->set_rate == NULL)
 184                return -EINVAL;
 185
 186        spin_lock(&clocks_lock);
 187        ret = (clk->set_rate)(clk, rate);
 188        spin_unlock(&clocks_lock);
 189
 190        return ret;
 191}
 192
 193struct clk *clk_get_parent(struct clk *clk)
 194{
 195        return clk->parent;
 196}
 197
 198int clk_set_parent(struct clk *clk, struct clk *parent)
 199{
 200        int ret = 0;
 201
 202        if (IS_ERR(clk))
 203                return -EINVAL;
 204
 205        spin_lock(&clocks_lock);
 206
 207        if (clk->set_parent)
 208                ret = (clk->set_parent)(clk, parent);
 209
 210        spin_unlock(&clocks_lock);
 211
 212        return ret;
 213}
 214
 215EXPORT_SYMBOL(clk_get);
 216EXPORT_SYMBOL(clk_put);
 217EXPORT_SYMBOL(clk_enable);
 218EXPORT_SYMBOL(clk_disable);
 219EXPORT_SYMBOL(clk_get_rate);
 220EXPORT_SYMBOL(clk_round_rate);
 221EXPORT_SYMBOL(clk_set_rate);
 222EXPORT_SYMBOL(clk_get_parent);
 223EXPORT_SYMBOL(clk_set_parent);
 224
 225/* base clocks */
 226
 227static int clk_default_setrate(struct clk *clk, unsigned long rate)
 228{
 229        clk->rate = rate;
 230        return 0;
 231}
 232
 233struct clk clk_xtal = {
 234        .name           = "xtal",
 235        .id             = -1,
 236        .rate           = 0,
 237        .parent         = NULL,
 238        .ctrlbit        = 0,
 239};
 240
 241struct clk clk_ext = {
 242        .name           = "ext",
 243        .id             = -1,
 244};
 245
 246struct clk clk_epll = {
 247        .name           = "epll",
 248        .id             = -1,
 249};
 250
 251struct clk clk_mpll = {
 252        .name           = "mpll",
 253        .id             = -1,
 254        .set_rate       = clk_default_setrate,
 255};
 256
 257struct clk clk_upll = {
 258        .name           = "upll",
 259        .id             = -1,
 260        .parent         = NULL,
 261        .ctrlbit        = 0,
 262};
 263
 264struct clk clk_f = {
 265        .name           = "fclk",
 266        .id             = -1,
 267        .rate           = 0,
 268        .parent         = &clk_mpll,
 269        .ctrlbit        = 0,
 270        .set_rate       = clk_default_setrate,
 271};
 272
 273struct clk clk_h = {
 274        .name           = "hclk",
 275        .id             = -1,
 276        .rate           = 0,
 277        .parent         = NULL,
 278        .ctrlbit        = 0,
 279        .set_rate       = clk_default_setrate,
 280};
 281
 282struct clk clk_p = {
 283        .name           = "pclk",
 284        .id             = -1,
 285        .rate           = 0,
 286        .parent         = NULL,
 287        .ctrlbit        = 0,
 288        .set_rate       = clk_default_setrate,
 289};
 290
 291struct clk clk_usb_bus = {
 292        .name           = "usb-bus",
 293        .id             = -1,
 294        .rate           = 0,
 295        .parent         = &clk_upll,
 296};
 297
 298
 299
 300struct clk s3c24xx_uclk = {
 301        .name           = "uclk",
 302        .id             = -1,
 303};
 304
 305/* initialise the clock system */
 306
 307int s3c24xx_register_clock(struct clk *clk)
 308{
 309        if (clk->enable == NULL)
 310                clk->enable = clk_null_enable;
 311
 312        /* add to the list of available clocks */
 313
 314        /* Quick check to see if this clock has already been registered. */
 315        BUG_ON(clk->list.prev != clk->list.next);
 316
 317        spin_lock(&clocks_lock);
 318        list_add(&clk->list, &clocks);
 319        spin_unlock(&clocks_lock);
 320
 321        return 0;
 322}
 323
 324int s3c24xx_register_clocks(struct clk **clks, int nr_clks)
 325{
 326        int fails = 0;
 327
 328        for (; nr_clks > 0; nr_clks--, clks++) {
 329                if (s3c24xx_register_clock(*clks) < 0)
 330                        fails++;
 331        }
 332
 333        return fails;
 334}
 335
 336/* initalise all the clocks */
 337
 338int __init s3c24xx_register_baseclocks(unsigned long xtal)
 339{
 340        printk(KERN_INFO "S3C24XX Clocks, (c) 2004 Simtec Electronics\n");
 341
 342        clk_xtal.rate = xtal;
 343
 344        /* register our clocks */
 345
 346        if (s3c24xx_register_clock(&clk_xtal) < 0)
 347                printk(KERN_ERR "failed to register master xtal\n");
 348
 349        if (s3c24xx_register_clock(&clk_mpll) < 0)
 350                printk(KERN_ERR "failed to register mpll clock\n");
 351
 352        if (s3c24xx_register_clock(&clk_upll) < 0)
 353                printk(KERN_ERR "failed to register upll clock\n");
 354
 355        if (s3c24xx_register_clock(&clk_f) < 0)
 356                printk(KERN_ERR "failed to register cpu fclk\n");
 357
 358        if (s3c24xx_register_clock(&clk_h) < 0)
 359                printk(KERN_ERR "failed to register cpu hclk\n");
 360
 361        if (s3c24xx_register_clock(&clk_p) < 0)
 362                printk(KERN_ERR "failed to register cpu pclk\n");
 363
 364        return 0;
 365}
 366
 367