linux/arch/mips/loongson1/common/clock.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 Zhang, Keguang <keguang.zhang@gmail.com>
   3 *
   4 * This program is free software; you can redistribute  it and/or modify it
   5 * under  the terms of  the GNU General  Public License as published by the
   6 * Free Software Foundation;  either version 2 of the  License, or (at your
   7 * option) any later version.
   8 */
   9
  10#include <linux/module.h>
  11#include <linux/list.h>
  12#include <linux/mutex.h>
  13#include <linux/clk.h>
  14#include <linux/err.h>
  15#include <asm/clock.h>
  16#include <asm/time.h>
  17
  18#include <loongson1.h>
  19
  20static LIST_HEAD(clocks);
  21static DEFINE_MUTEX(clocks_mutex);
  22
  23struct clk *clk_get(struct device *dev, const char *name)
  24{
  25        struct clk *c;
  26        struct clk *ret = NULL;
  27
  28        mutex_lock(&clocks_mutex);
  29        list_for_each_entry(c, &clocks, node) {
  30                if (!strcmp(c->name, name)) {
  31                        ret = c;
  32                        break;
  33                }
  34        }
  35        mutex_unlock(&clocks_mutex);
  36
  37        return ret;
  38}
  39EXPORT_SYMBOL(clk_get);
  40
  41int clk_enable(struct clk *clk)
  42{
  43        return 0;
  44}
  45EXPORT_SYMBOL(clk_enable);
  46
  47void clk_disable(struct clk *clk)
  48{
  49}
  50EXPORT_SYMBOL(clk_disable);
  51
  52unsigned long clk_get_rate(struct clk *clk)
  53{
  54        return clk->rate;
  55}
  56EXPORT_SYMBOL(clk_get_rate);
  57
  58void clk_put(struct clk *clk)
  59{
  60}
  61EXPORT_SYMBOL(clk_put);
  62
  63static void pll_clk_init(struct clk *clk)
  64{
  65        u32 pll;
  66
  67        pll = __raw_readl(LS1X_CLK_PLL_FREQ);
  68        clk->rate = (12 + (pll & 0x3f)) * 33 / 2
  69                        + ((pll >> 8) & 0x3ff) * 33 / 1024 / 2;
  70        clk->rate *= 1000000;
  71}
  72
  73static void cpu_clk_init(struct clk *clk)
  74{
  75        u32 pll, ctrl;
  76
  77        pll = clk_get_rate(clk->parent);
  78        ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_CPU;
  79        clk->rate = pll / (ctrl >> DIV_CPU_SHIFT);
  80}
  81
  82static void ddr_clk_init(struct clk *clk)
  83{
  84        u32 pll, ctrl;
  85
  86        pll = clk_get_rate(clk->parent);
  87        ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_DDR;
  88        clk->rate = pll / (ctrl >> DIV_DDR_SHIFT);
  89}
  90
  91static void dc_clk_init(struct clk *clk)
  92{
  93        u32 pll, ctrl;
  94
  95        pll = clk_get_rate(clk->parent);
  96        ctrl = __raw_readl(LS1X_CLK_PLL_DIV) & DIV_DC;
  97        clk->rate = pll / (ctrl >> DIV_DC_SHIFT);
  98}
  99
 100static struct clk_ops pll_clk_ops = {
 101        .init   = pll_clk_init,
 102};
 103
 104static struct clk_ops cpu_clk_ops = {
 105        .init   = cpu_clk_init,
 106};
 107
 108static struct clk_ops ddr_clk_ops = {
 109        .init   = ddr_clk_init,
 110};
 111
 112static struct clk_ops dc_clk_ops = {
 113        .init   = dc_clk_init,
 114};
 115
 116static struct clk pll_clk = {
 117        .name   = "pll",
 118        .ops    = &pll_clk_ops,
 119};
 120
 121static struct clk cpu_clk = {
 122        .name   = "cpu",
 123        .parent = &pll_clk,
 124        .ops    = &cpu_clk_ops,
 125};
 126
 127static struct clk ddr_clk = {
 128        .name   = "ddr",
 129        .parent = &pll_clk,
 130        .ops    = &ddr_clk_ops,
 131};
 132
 133static struct clk dc_clk = {
 134        .name   = "dc",
 135        .parent = &pll_clk,
 136        .ops    = &dc_clk_ops,
 137};
 138
 139int clk_register(struct clk *clk)
 140{
 141        mutex_lock(&clocks_mutex);
 142        list_add(&clk->node, &clocks);
 143        if (clk->ops->init)
 144                clk->ops->init(clk);
 145        mutex_unlock(&clocks_mutex);
 146
 147        return 0;
 148}
 149EXPORT_SYMBOL(clk_register);
 150
 151static struct clk *ls1x_clks[] = {
 152        &pll_clk,
 153        &cpu_clk,
 154        &ddr_clk,
 155        &dc_clk,
 156};
 157
 158int __init ls1x_clock_init(void)
 159{
 160        int i;
 161
 162        for (i = 0; i < ARRAY_SIZE(ls1x_clks); i++)
 163                clk_register(ls1x_clks[i]);
 164
 165        return 0;
 166}
 167
 168void __init plat_time_init(void)
 169{
 170        struct clk *clk;
 171
 172        /* Initialize LS1X clocks */
 173        ls1x_clock_init();
 174
 175        /* setup mips r4k timer */
 176        clk = clk_get(NULL, "cpu");
 177        if (IS_ERR(clk))
 178                panic("unable to get dc clock, err=%ld", PTR_ERR(clk));
 179
 180        mips_hpt_frequency = clk_get_rate(clk) / 2;
 181}
 182