linux/arch/sh/kernel/cpu/sh4a/clock-sh7780.c
<<
>>
Prefs
   1/*
   2 * arch/sh/kernel/cpu/sh4a/clock-sh7780.c
   3 *
   4 * SH7780 support for the clock framework
   5 *
   6 *  Copyright (C) 2005  Paul Mundt
   7 *
   8 * This file is subject to the terms and conditions of the GNU General Public
   9 * License.  See the file "COPYING" in the main directory of this archive
  10 * for more details.
  11 */
  12#include <linux/init.h>
  13#include <linux/kernel.h>
  14#include <linux/io.h>
  15#include <linux/clkdev.h>
  16#include <asm/clock.h>
  17#include <asm/freq.h>
  18#include <asm/io.h>
  19
  20static int ifc_divisors[] = { 2, 4 };
  21static int bfc_divisors[] = { 1, 1, 1, 8, 12, 16, 24, 1 };
  22static int pfc_divisors[] = { 1, 24, 24, 1 };
  23static int cfc_divisors[] = { 1, 1, 4, 1, 6, 1, 1, 1 };
  24
  25static void master_clk_init(struct clk *clk)
  26{
  27        clk->rate *= pfc_divisors[__raw_readl(FRQCR) & 0x0003];
  28}
  29
  30static struct sh_clk_ops sh7780_master_clk_ops = {
  31        .init           = master_clk_init,
  32};
  33
  34static unsigned long module_clk_recalc(struct clk *clk)
  35{
  36        int idx = (__raw_readl(FRQCR) & 0x0003);
  37        return clk->parent->rate / pfc_divisors[idx];
  38}
  39
  40static struct sh_clk_ops sh7780_module_clk_ops = {
  41        .recalc         = module_clk_recalc,
  42};
  43
  44static unsigned long bus_clk_recalc(struct clk *clk)
  45{
  46        int idx = ((__raw_readl(FRQCR) >> 16) & 0x0007);
  47        return clk->parent->rate / bfc_divisors[idx];
  48}
  49
  50static struct sh_clk_ops sh7780_bus_clk_ops = {
  51        .recalc         = bus_clk_recalc,
  52};
  53
  54static unsigned long cpu_clk_recalc(struct clk *clk)
  55{
  56        int idx = ((__raw_readl(FRQCR) >> 24) & 0x0001);
  57        return clk->parent->rate / ifc_divisors[idx];
  58}
  59
  60static struct sh_clk_ops sh7780_cpu_clk_ops = {
  61        .recalc         = cpu_clk_recalc,
  62};
  63
  64static struct sh_clk_ops *sh7780_clk_ops[] = {
  65        &sh7780_master_clk_ops,
  66        &sh7780_module_clk_ops,
  67        &sh7780_bus_clk_ops,
  68        &sh7780_cpu_clk_ops,
  69};
  70
  71void __init arch_init_clk_ops(struct sh_clk_ops **ops, int idx)
  72{
  73        if (idx < ARRAY_SIZE(sh7780_clk_ops))
  74                *ops = sh7780_clk_ops[idx];
  75}
  76
  77static unsigned long shyway_clk_recalc(struct clk *clk)
  78{
  79        int idx = ((__raw_readl(FRQCR) >> 20) & 0x0007);
  80        return clk->parent->rate / cfc_divisors[idx];
  81}
  82
  83static struct sh_clk_ops sh7780_shyway_clk_ops = {
  84        .recalc         = shyway_clk_recalc,
  85};
  86
  87static struct clk sh7780_shyway_clk = {
  88        .flags          = CLK_ENABLE_ON_INIT,
  89        .ops            = &sh7780_shyway_clk_ops,
  90};
  91
  92/*
  93 * Additional SH7780-specific on-chip clocks that aren't already part of the
  94 * clock framework
  95 */
  96static struct clk *sh7780_onchip_clocks[] = {
  97        &sh7780_shyway_clk,
  98};
  99
 100static struct clk_lookup lookups[] = {
 101        /* main clocks */
 102        CLKDEV_CON_ID("shyway_clk", &sh7780_shyway_clk),
 103};
 104
 105int __init arch_clk_init(void)
 106{
 107        struct clk *clk;
 108        int i, ret = 0;
 109
 110        cpg_clk_init();
 111
 112        clk = clk_get(NULL, "master_clk");
 113        for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) {
 114                struct clk *clkp = sh7780_onchip_clocks[i];
 115
 116                clkp->parent = clk;
 117                ret |= clk_register(clkp);
 118        }
 119
 120        clk_put(clk);
 121
 122        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 123
 124        return ret;
 125}
 126