linux/arch/sh/kernel/cpu/clock-cpg.c
<<
>>
Prefs
   1#include <linux/clk.h>
   2#include <linux/compiler.h>
   3#include <linux/slab.h>
   4#include <linux/io.h>
   5#include <asm/clock.h>
   6
   7static int sh_clk_mstp32_enable(struct clk *clk)
   8{
   9        __raw_writel(__raw_readl(clk->enable_reg) & ~(1 << clk->enable_bit),
  10                     clk->enable_reg);
  11        return 0;
  12}
  13
  14static void sh_clk_mstp32_disable(struct clk *clk)
  15{
  16        __raw_writel(__raw_readl(clk->enable_reg) | (1 << clk->enable_bit),
  17                     clk->enable_reg);
  18}
  19
  20static struct clk_ops sh_clk_mstp32_clk_ops = {
  21        .enable         = sh_clk_mstp32_enable,
  22        .disable        = sh_clk_mstp32_disable,
  23        .recalc         = followparent_recalc,
  24};
  25
  26int __init sh_clk_mstp32_register(struct clk *clks, int nr)
  27{
  28        struct clk *clkp;
  29        int ret = 0;
  30        int k;
  31
  32        for (k = 0; !ret && (k < nr); k++) {
  33                clkp = clks + k;
  34                clkp->ops = &sh_clk_mstp32_clk_ops;
  35                ret |= clk_register(clkp);
  36        }
  37
  38        return ret;
  39}
  40
  41static long sh_clk_div_round_rate(struct clk *clk, unsigned long rate)
  42{
  43        return clk_rate_table_round(clk, clk->freq_table, rate);
  44}
  45
  46static int sh_clk_div6_divisors[64] = {
  47        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
  48        17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
  49        33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
  50        49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64
  51};
  52
  53static struct clk_div_mult_table sh_clk_div6_table = {
  54        .divisors = sh_clk_div6_divisors,
  55        .nr_divisors = ARRAY_SIZE(sh_clk_div6_divisors),
  56};
  57
  58static unsigned long sh_clk_div6_recalc(struct clk *clk)
  59{
  60        struct clk_div_mult_table *table = &sh_clk_div6_table;
  61        unsigned int idx;
  62
  63        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
  64                             table, NULL);
  65
  66        idx = __raw_readl(clk->enable_reg) & 0x003f;
  67
  68        return clk->freq_table[idx].frequency;
  69}
  70
  71static int sh_clk_div6_set_rate(struct clk *clk,
  72                                unsigned long rate, int algo_id)
  73{
  74        unsigned long value;
  75        int idx;
  76
  77        idx = clk_rate_table_find(clk, clk->freq_table, rate);
  78        if (idx < 0)
  79                return idx;
  80
  81        value = __raw_readl(clk->enable_reg);
  82        value &= ~0x3f;
  83        value |= idx;
  84        __raw_writel(value, clk->enable_reg);
  85        return 0;
  86}
  87
  88static int sh_clk_div6_enable(struct clk *clk)
  89{
  90        unsigned long value;
  91        int ret;
  92
  93        ret = sh_clk_div6_set_rate(clk, clk->rate, 0);
  94        if (ret == 0) {
  95                value = __raw_readl(clk->enable_reg);
  96                value &= ~0x100; /* clear stop bit to enable clock */
  97                __raw_writel(value, clk->enable_reg);
  98        }
  99        return ret;
 100}
 101
 102static void sh_clk_div6_disable(struct clk *clk)
 103{
 104        unsigned long value;
 105
 106        value = __raw_readl(clk->enable_reg);
 107        value |= 0x100; /* stop clock */
 108        value |= 0x3f; /* VDIV bits must be non-zero, overwrite divider */
 109        __raw_writel(value, clk->enable_reg);
 110}
 111
 112static struct clk_ops sh_clk_div6_clk_ops = {
 113        .recalc         = sh_clk_div6_recalc,
 114        .round_rate     = sh_clk_div_round_rate,
 115        .set_rate       = sh_clk_div6_set_rate,
 116        .enable         = sh_clk_div6_enable,
 117        .disable        = sh_clk_div6_disable,
 118};
 119
 120int __init sh_clk_div6_register(struct clk *clks, int nr)
 121{
 122        struct clk *clkp;
 123        void *freq_table;
 124        int nr_divs = sh_clk_div6_table.nr_divisors;
 125        int freq_table_size = sizeof(struct cpufreq_frequency_table);
 126        int ret = 0;
 127        int k;
 128
 129        freq_table_size *= (nr_divs + 1);
 130        freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
 131        if (!freq_table) {
 132                pr_err("sh_clk_div6_register: unable to alloc memory\n");
 133                return -ENOMEM;
 134        }
 135
 136        for (k = 0; !ret && (k < nr); k++) {
 137                clkp = clks + k;
 138
 139                clkp->ops = &sh_clk_div6_clk_ops;
 140                clkp->id = -1;
 141                clkp->freq_table = freq_table + (k * freq_table_size);
 142                clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
 143
 144                ret = clk_register(clkp);
 145        }
 146
 147        return ret;
 148}
 149
 150static unsigned long sh_clk_div4_recalc(struct clk *clk)
 151{
 152        struct clk_div_mult_table *table = clk->priv;
 153        unsigned int idx;
 154
 155        clk_rate_table_build(clk, clk->freq_table, table->nr_divisors,
 156                             table, &clk->arch_flags);
 157
 158        idx = (__raw_readl(clk->enable_reg) >> clk->enable_bit) & 0x000f;
 159
 160        return clk->freq_table[idx].frequency;
 161}
 162
 163static struct clk_ops sh_clk_div4_clk_ops = {
 164        .recalc         = sh_clk_div4_recalc,
 165        .round_rate     = sh_clk_div_round_rate,
 166};
 167
 168int __init sh_clk_div4_register(struct clk *clks, int nr,
 169                                struct clk_div_mult_table *table)
 170{
 171        struct clk *clkp;
 172        void *freq_table;
 173        int nr_divs = table->nr_divisors;
 174        int freq_table_size = sizeof(struct cpufreq_frequency_table);
 175        int ret = 0;
 176        int k;
 177
 178        freq_table_size *= (nr_divs + 1);
 179        freq_table = kzalloc(freq_table_size * nr, GFP_KERNEL);
 180        if (!freq_table) {
 181                pr_err("sh_clk_div4_register: unable to alloc memory\n");
 182                return -ENOMEM;
 183        }
 184
 185        for (k = 0; !ret && (k < nr); k++) {
 186                clkp = clks + k;
 187
 188                clkp->ops = &sh_clk_div4_clk_ops;
 189                clkp->id = -1;
 190                clkp->priv = table;
 191
 192                clkp->freq_table = freq_table + (k * freq_table_size);
 193                clkp->freq_table[nr_divs].frequency = CPUFREQ_TABLE_END;
 194
 195                ret = clk_register(clkp);
 196        }
 197
 198        return ret;
 199}
 200
 201#ifdef CONFIG_SH_CLK_CPG_LEGACY
 202static struct clk master_clk = {
 203        .name           = "master_clk",
 204        .flags          = CLK_ENABLE_ON_INIT,
 205        .rate           = CONFIG_SH_PCLK_FREQ,
 206};
 207
 208static struct clk peripheral_clk = {
 209        .name           = "peripheral_clk",
 210        .parent         = &master_clk,
 211        .flags          = CLK_ENABLE_ON_INIT,
 212};
 213
 214static struct clk bus_clk = {
 215        .name           = "bus_clk",
 216        .parent         = &master_clk,
 217        .flags          = CLK_ENABLE_ON_INIT,
 218};
 219
 220static struct clk cpu_clk = {
 221        .name           = "cpu_clk",
 222        .parent         = &master_clk,
 223        .flags          = CLK_ENABLE_ON_INIT,
 224};
 225
 226/*
 227 * The ordering of these clocks matters, do not change it.
 228 */
 229static struct clk *onchip_clocks[] = {
 230        &master_clk,
 231        &peripheral_clk,
 232        &bus_clk,
 233        &cpu_clk,
 234};
 235
 236int __init __deprecated cpg_clk_init(void)
 237{
 238        int i, ret = 0;
 239
 240        for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) {
 241                struct clk *clk = onchip_clocks[i];
 242                arch_init_clk_ops(&clk->ops, i);
 243                if (clk->ops)
 244                        ret |= clk_register(clk);
 245        }
 246
 247        return ret;
 248}
 249
 250/*
 251 * Placeholder for compatability, until the lazy CPUs do this
 252 * on their own.
 253 */
 254int __init __weak arch_clk_init(void)
 255{
 256        return cpg_clk_init();
 257}
 258#endif /* CONFIG_SH_CPG_CLK_LEGACY */
 259