linux/arch/sh/kernel/cpu/sh2a/clock-sh7264.c
<<
>>
Prefs
   1/*
   2 * arch/sh/kernel/cpu/sh2a/clock-sh7264.c
   3 *
   4 * SH7264 clock framework support
   5 *
   6 * Copyright (C) 2012  Phil Edworthy
   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
  18/* SH7264 registers */
  19#define FRQCR           0xfffe0010
  20#define STBCR3          0xfffe0408
  21#define STBCR4          0xfffe040c
  22#define STBCR5          0xfffe0410
  23#define STBCR6          0xfffe0414
  24#define STBCR7          0xfffe0418
  25#define STBCR8          0xfffe041c
  26
  27static const unsigned int pll1rate[] = {8, 12};
  28
  29static unsigned int pll1_div;
  30
  31/* Fixed 32 KHz root clock for RTC */
  32static struct clk r_clk = {
  33        .rate           = 32768,
  34};
  35
  36/*
  37 * Default rate for the root input clock, reset this with clk_set_rate()
  38 * from the platform code.
  39 */
  40static struct clk extal_clk = {
  41        .rate           = 18000000,
  42};
  43
  44static unsigned long pll_recalc(struct clk *clk)
  45{
  46        unsigned long rate = clk->parent->rate / pll1_div;
  47        return rate * pll1rate[(__raw_readw(FRQCR) >> 8) & 1];
  48}
  49
  50static struct sh_clk_ops pll_clk_ops = {
  51        .recalc         = pll_recalc,
  52};
  53
  54static struct clk pll_clk = {
  55        .ops            = &pll_clk_ops,
  56        .parent         = &extal_clk,
  57        .flags          = CLK_ENABLE_ON_INIT,
  58};
  59
  60struct clk *main_clks[] = {
  61        &r_clk,
  62        &extal_clk,
  63        &pll_clk,
  64};
  65
  66static int div2[] = { 1, 2, 3, 4, 6, 8, 12 };
  67
  68static struct clk_div_mult_table div4_div_mult_table = {
  69        .divisors = div2,
  70        .nr_divisors = ARRAY_SIZE(div2),
  71};
  72
  73static struct clk_div4_table div4_table = {
  74        .div_mult_table = &div4_div_mult_table,
  75};
  76
  77enum { DIV4_I, DIV4_P,
  78       DIV4_NR };
  79
  80#define DIV4(_reg, _bit, _mask, _flags) \
  81  SH_CLK_DIV4(&pll_clk, _reg, _bit, _mask, _flags)
  82
  83/* The mask field specifies the div2 entries that are valid */
  84struct clk div4_clks[DIV4_NR] = {
  85        [DIV4_I] = DIV4(FRQCR, 4, 0x7,  CLK_ENABLE_REG_16BIT
  86                                        | CLK_ENABLE_ON_INIT),
  87        [DIV4_P] = DIV4(FRQCR, 0, 0x78, CLK_ENABLE_REG_16BIT),
  88};
  89
  90enum {  MSTP77, MSTP74, MSTP72,
  91        MSTP60,
  92        MSTP35, MSTP34, MSTP33, MSTP32, MSTP30,
  93        MSTP_NR };
  94
  95static struct clk mstp_clks[MSTP_NR] = {
  96        [MSTP77] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 7, 0), /* SCIF */
  97        [MSTP74] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 4, 0), /* VDC */
  98        [MSTP72] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR7, 2, 0), /* CMT */
  99        [MSTP60] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR6, 0, 0), /* USB */
 100        [MSTP35] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 6, 0), /* MTU2 */
 101        [MSTP34] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 4, 0), /* SDHI0 */
 102        [MSTP33] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 3, 0), /* SDHI1 */
 103        [MSTP32] = SH_CLK_MSTP8(&div4_clks[DIV4_P], STBCR3, 2, 0), /* ADC */
 104        [MSTP30] = SH_CLK_MSTP8(&r_clk, STBCR3, 0, 0),  /* RTC */
 105};
 106
 107static struct clk_lookup lookups[] = {
 108        /* main clocks */
 109        CLKDEV_CON_ID("rclk", &r_clk),
 110        CLKDEV_CON_ID("extal", &extal_clk),
 111        CLKDEV_CON_ID("pll_clk", &pll_clk),
 112
 113        /* DIV4 clocks */
 114        CLKDEV_CON_ID("cpu_clk", &div4_clks[DIV4_I]),
 115        CLKDEV_CON_ID("peripheral_clk", &div4_clks[DIV4_P]),
 116
 117        /* MSTP clocks */
 118        CLKDEV_ICK_ID("fck", "sh-sci.0", &mstp_clks[MSTP77]),
 119        CLKDEV_ICK_ID("fck", "sh-sci.1", &mstp_clks[MSTP77]),
 120        CLKDEV_ICK_ID("fck", "sh-sci.2", &mstp_clks[MSTP77]),
 121        CLKDEV_ICK_ID("fck", "sh-sci.3", &mstp_clks[MSTP77]),
 122        CLKDEV_ICK_ID("fck", "sh-sci.4", &mstp_clks[MSTP77]),
 123        CLKDEV_ICK_ID("fck", "sh-sci.5", &mstp_clks[MSTP77]),
 124        CLKDEV_ICK_ID("fck", "sh-sci.6", &mstp_clks[MSTP77]),
 125        CLKDEV_ICK_ID("fck", "sh-sci.7", &mstp_clks[MSTP77]),
 126        CLKDEV_CON_ID("vdc3", &mstp_clks[MSTP74]),
 127        CLKDEV_ICK_ID("fck", "sh-cmt-16.0", &mstp_clks[MSTP72]),
 128        CLKDEV_CON_ID("usb0", &mstp_clks[MSTP60]),
 129        CLKDEV_ICK_ID("fck", "sh-mtu2", &mstp_clks[MSTP35]),
 130        CLKDEV_CON_ID("sdhi0", &mstp_clks[MSTP34]),
 131        CLKDEV_CON_ID("sdhi1", &mstp_clks[MSTP33]),
 132        CLKDEV_CON_ID("adc0", &mstp_clks[MSTP32]),
 133        CLKDEV_CON_ID("rtc0", &mstp_clks[MSTP30]),
 134};
 135
 136int __init arch_clk_init(void)
 137{
 138        int k, ret = 0;
 139
 140        if (test_mode_pin(MODE_PIN0)) {
 141                if (test_mode_pin(MODE_PIN1))
 142                        pll1_div = 3;
 143                else
 144                        pll1_div = 4;
 145        } else
 146                pll1_div = 1;
 147
 148        for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
 149                ret = clk_register(main_clks[k]);
 150
 151        clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 152
 153        if (!ret)
 154                ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
 155
 156        if (!ret)
 157                ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
 158
 159        return ret;
 160}
 161