linux/arch/arm/plat-samsung/clock-clksrc.c
<<
>>
Prefs
   1/* linux/arch/arm/plat-samsung/clock-clksrc.c
   2 *
   3 * Copyright 2008 Simtec Electronics
   4 *      Ben Dooks <ben@simtec.co.uk>
   5 *      http://armlinux.simtec.co.uk/
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10*/
  11
  12#include <linux/init.h>
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/list.h>
  16#include <linux/errno.h>
  17#include <linux/err.h>
  18#include <linux/clk.h>
  19#include <linux/device.h>
  20#include <linux/io.h>
  21
  22#include <plat/clock.h>
  23#include <plat/clock-clksrc.h>
  24#include <plat/cpu-freq.h>
  25
  26static inline struct clksrc_clk *to_clksrc(struct clk *clk)
  27{
  28        return container_of(clk, struct clksrc_clk, clk);
  29}
  30
  31static inline u32 bit_mask(u32 shift, u32 nr_bits)
  32{
  33        u32 mask = 0xffffffff >> (32 - nr_bits);
  34
  35        return mask << shift;
  36}
  37
  38static unsigned long s3c_getrate_clksrc(struct clk *clk)
  39{
  40        struct clksrc_clk *sclk = to_clksrc(clk);
  41        unsigned long rate = clk_get_rate(clk->parent);
  42        u32 clkdiv = __raw_readl(sclk->reg_div.reg);
  43        u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
  44
  45        clkdiv &= mask;
  46        clkdiv >>= sclk->reg_div.shift;
  47        clkdiv++;
  48
  49        rate /= clkdiv;
  50        return rate;
  51}
  52
  53static int s3c_setrate_clksrc(struct clk *clk, unsigned long rate)
  54{
  55        struct clksrc_clk *sclk = to_clksrc(clk);
  56        void __iomem *reg = sclk->reg_div.reg;
  57        unsigned int div;
  58        u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
  59        u32 val;
  60
  61        rate = clk_round_rate(clk, rate);
  62        div = clk_get_rate(clk->parent) / rate;
  63        if (div > (1 << sclk->reg_div.size))
  64                return -EINVAL;
  65
  66        val = __raw_readl(reg);
  67        val &= ~mask;
  68        val |= (div - 1) << sclk->reg_div.shift;
  69        __raw_writel(val, reg);
  70
  71        return 0;
  72}
  73
  74static int s3c_setparent_clksrc(struct clk *clk, struct clk *parent)
  75{
  76        struct clksrc_clk *sclk = to_clksrc(clk);
  77        struct clksrc_sources *srcs = sclk->sources;
  78        u32 clksrc = __raw_readl(sclk->reg_src.reg);
  79        u32 mask = bit_mask(sclk->reg_src.shift, sclk->reg_src.size);
  80        int src_nr = -1;
  81        int ptr;
  82
  83        for (ptr = 0; ptr < srcs->nr_sources; ptr++)
  84                if (srcs->sources[ptr] == parent) {
  85                        src_nr = ptr;
  86                        break;
  87                }
  88
  89        if (src_nr >= 0) {
  90                clk->parent = parent;
  91
  92                clksrc &= ~mask;
  93                clksrc |= src_nr << sclk->reg_src.shift;
  94
  95                __raw_writel(clksrc, sclk->reg_src.reg);
  96                return 0;
  97        }
  98
  99        return -EINVAL;
 100}
 101
 102static unsigned long s3c_roundrate_clksrc(struct clk *clk,
 103                                              unsigned long rate)
 104{
 105        struct clksrc_clk *sclk = to_clksrc(clk);
 106        unsigned long parent_rate = clk_get_rate(clk->parent);
 107        int max_div = 1 << sclk->reg_div.size;
 108        int div;
 109
 110        if (rate >= parent_rate)
 111                rate = parent_rate;
 112        else {
 113                div = parent_rate / rate;
 114                if (parent_rate % rate)
 115                        div++;
 116
 117                if (div == 0)
 118                        div = 1;
 119                if (div > max_div)
 120                        div = max_div;
 121
 122                rate = parent_rate / div;
 123        }
 124
 125        return rate;
 126}
 127
 128/* Clock initialisation code */
 129
 130void __init_or_cpufreq s3c_set_clksrc(struct clksrc_clk *clk, bool announce)
 131{
 132        struct clksrc_sources *srcs = clk->sources;
 133        u32 mask = bit_mask(clk->reg_src.shift, clk->reg_src.size);
 134        u32 clksrc;
 135
 136        if (!clk->reg_src.reg) {
 137                if (!clk->clk.parent)
 138                        printk(KERN_ERR "%s: no parent clock specified\n",
 139                                clk->clk.name);
 140                return;
 141        }
 142
 143        clksrc = __raw_readl(clk->reg_src.reg);
 144        clksrc &= mask;
 145        clksrc >>= clk->reg_src.shift;
 146
 147        if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
 148                printk(KERN_ERR "%s: bad source %d\n",
 149                       clk->clk.name, clksrc);
 150                return;
 151        }
 152
 153        clk->clk.parent = srcs->sources[clksrc];
 154
 155        if (announce)
 156                printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
 157                       clk->clk.name, clk->clk.parent->name, clksrc,
 158                       clk_get_rate(&clk->clk));
 159}
 160
 161static struct clk_ops clksrc_ops = {
 162        .set_parent     = s3c_setparent_clksrc,
 163        .get_rate       = s3c_getrate_clksrc,
 164        .set_rate       = s3c_setrate_clksrc,
 165        .round_rate     = s3c_roundrate_clksrc,
 166};
 167
 168static struct clk_ops clksrc_ops_nodiv = {
 169        .set_parent     = s3c_setparent_clksrc,
 170};
 171
 172static struct clk_ops clksrc_ops_nosrc = {
 173        .get_rate       = s3c_getrate_clksrc,
 174        .set_rate       = s3c_setrate_clksrc,
 175        .round_rate     = s3c_roundrate_clksrc,
 176};
 177
 178void __init s3c_register_clksrc(struct clksrc_clk *clksrc, int size)
 179{
 180        int ret;
 181
 182        for (; size > 0; size--, clksrc++) {
 183                if (!clksrc->reg_div.reg && !clksrc->reg_src.reg)
 184                        printk(KERN_ERR "%s: clock %s has no registers set\n",
 185                               __func__, clksrc->clk.name);
 186
 187                /* fill in the default functions */
 188
 189                if (!clksrc->clk.ops) {
 190                        if (!clksrc->reg_div.reg)
 191                                clksrc->clk.ops = &clksrc_ops_nodiv;
 192                        else if (!clksrc->reg_src.reg)
 193                                clksrc->clk.ops = &clksrc_ops_nosrc;
 194                        else
 195                                clksrc->clk.ops = &clksrc_ops;
 196                }
 197
 198                /* setup the clocksource, but do not announce it
 199                 * as it may be re-set by the setup routines
 200                 * called after the rest of the clocks have been
 201                 * registered
 202                 */
 203                s3c_set_clksrc(clksrc, false);
 204
 205                ret = s3c24xx_register_clock(&clksrc->clk);
 206
 207                if (ret < 0) {
 208                        printk(KERN_ERR "%s: failed to register %s (%d)\n",
 209                               __func__, clksrc->clk.name, ret);
 210                }
 211        }
 212}
 213