Root/target/linux/mcs814x/files-3.3/arch/arm/mach-mcs814x/clock.c

1/*
2 * Moschip MCS814x clock routines
3 *
4 * Copyright (C) 2012, Florian Fainelli <florian@openwrt.org>
5 *
6 * Licensed under GPLv2
7 */
8#include <linux/kernel.h>
9#include <linux/init.h>
10#include <linux/export.h>
11#include <linux/spinlock.h>
12#include <linux/err.h>
13#include <linux/io.h>
14#include <linux/clkdev.h>
15#include <linux/clk.h>
16
17#include <mach/mcs814x.h>
18
19#include "common.h"
20
21#define KHZ 1000
22#define MHZ (KHZ * KHZ)
23
24struct clk_ops {
25    unsigned long (*get_rate)(struct clk *clk);
26    int (*set_rate)(struct clk *clk, unsigned long rate);
27    struct clk *(*get_parent)(struct clk *clk);
28    int (*enable)(struct clk *clk, int enable);
29};
30
31struct clk {
32    struct clk *parent; /* parent clk */
33    unsigned long rate; /* clock rate in Hz */
34    unsigned long divider; /* clock divider */
35    u32 usecount; /* reference count */
36    struct clk_ops *ops; /* clock operation */
37    u32 enable_reg; /* clock enable register */
38    u32 enable_mask; /* clock enable mask */
39};
40
41static unsigned long clk_divide_parent(struct clk *clk)
42{
43    if (clk->parent && clk->divider)
44        return clk_get_rate(clk->parent) / clk->divider;
45    else
46        return 0;
47}
48
49static int clk_local_onoff_enable(struct clk *clk, int enable)
50{
51    u32 tmp;
52
53    /* no enable_reg means the clock is always enabled */
54    if (!clk->enable_reg)
55        return 0;
56
57    tmp = readl_relaxed(mcs814x_sysdbg_base + clk->enable_reg);
58    if (!enable)
59        tmp &= ~clk->enable_mask;
60    else
61        tmp |= clk->enable_mask;
62
63    writel_relaxed(tmp, mcs814x_sysdbg_base + clk->enable_reg);
64
65    return 0;
66}
67
68static struct clk_ops default_clk_ops = {
69    .get_rate = clk_divide_parent,
70    .enable = clk_local_onoff_enable,
71};
72
73static DEFINE_SPINLOCK(clocks_lock);
74
75static const unsigned long cpu_freq_table[] = {
76    175000,
77    300000,
78    125000,
79    137500,
80    212500,
81    250000,
82    162500,
83    187500,
84    162500,
85    150000,
86    225000,
87    237500,
88    200000,
89    262500,
90    275000,
91    287500
92};
93
94static struct clk clk_cpu;
95
96/* System clock is fixed at 50Mhz */
97static struct clk clk_sys = {
98    .rate = 50 * MHZ,
99};
100
101static struct clk clk_sdram;
102
103static struct clk clk_timer0 = {
104    .parent = &clk_sdram,
105    .divider = 2,
106    .ops = &default_clk_ops,
107};
108
109static struct clk clk_timer1_2 = {
110    .parent = &clk_sys,
111};
112
113/* Watchdog clock is system clock / 128 */
114static struct clk clk_wdt = {
115    .parent = &clk_sys,
116    .divider = 128,
117    .ops = &default_clk_ops,
118};
119
120static struct clk clk_emac = {
121    .ops = &default_clk_ops,
122    .enable_reg = SYSDBG_SYSCTL,
123    .enable_mask = SYSCTL_EMAC,
124};
125
126static struct clk clk_ephy = {
127    .ops = &default_clk_ops,
128    .enable_reg = SYSDBG_PLL_CTL,
129    .enable_mask = ~SYSCTL_EPHY, /* active low */
130};
131
132static struct clk clk_cipher = {
133    .ops = &default_clk_ops,
134    .enable_reg = SYSDBG_SYSCTL,
135    .enable_mask = SYSCTL_CIPHER,
136};
137
138#define CLK(_dev, _con, _clk) \
139{ .dev_id = (_dev), .con_id = (_con), .clk = (_clk) },
140
141static struct clk_lookup mcs814x_chip_clks[] = {
142    CLK("cpu", NULL, &clk_cpu)
143    CLK("sys", NULL, &clk_sys)
144    CLK("sdram", NULL, &clk_sdram)
145    /* 32-bits timer0 */
146    CLK("timer0", NULL, &clk_timer0)
147    /* 16-bits timer1 */
148    CLK("timer1", NULL, &clk_timer1_2)
149    /* 64-bits timer2, same as timer 1 */
150    CLK("timer2", NULL, &clk_timer1_2)
151    CLK(NULL, "wdt", &clk_wdt)
152    CLK(NULL, "emac", &clk_emac)
153    CLK(NULL, "ephy", &clk_ephy)
154    CLK(NULL, "cipher", &clk_cipher)
155};
156
157static void local_clk_disable(struct clk *clk)
158{
159    WARN_ON(!clk->usecount);
160
161    if (clk->usecount > 0) {
162        clk->usecount--;
163
164        if ((clk->usecount == 0) && (clk->ops->enable))
165            clk->ops->enable(clk, 0);
166
167        if (clk->parent)
168            local_clk_disable(clk->parent);
169    }
170}
171
172static int local_clk_enable(struct clk *clk)
173{
174    int ret = 0;
175
176    if (clk->parent)
177        ret = local_clk_enable(clk->parent);
178
179    if (ret)
180        return ret;
181
182    if ((clk->usecount == 0) && (clk->ops->enable))
183        ret = clk->ops->enable(clk, 1);
184
185    if (!ret)
186        clk->usecount++;
187    else if (clk->parent && clk->parent->ops->enable)
188        local_clk_disable(clk->parent);
189
190    return ret;
191}
192
193int clk_enable(struct clk *clk)
194{
195    int ret;
196    unsigned long flags;
197
198    spin_lock_irqsave(&clocks_lock, flags);
199    ret = local_clk_enable(clk);
200    spin_unlock_irqrestore(&clocks_lock, flags);
201
202    return ret;
203}
204EXPORT_SYMBOL(clk_enable);
205
206void clk_disable(struct clk *clk)
207{
208    unsigned long flags;
209
210    spin_lock_irqsave(&clocks_lock, flags);
211    local_clk_disable(clk);
212    spin_unlock_irqrestore(&clocks_lock, flags);
213}
214EXPORT_SYMBOL(clk_disable);
215
216unsigned long clk_get_rate(struct clk *clk)
217{
218    if (unlikely(IS_ERR_OR_NULL(clk)))
219        return 0;
220
221    if (clk->rate)
222        return clk->rate;
223
224    if (clk->ops && clk->ops->get_rate)
225        return clk->ops->get_rate(clk);
226
227    return clk_get_rate(clk->parent);
228}
229EXPORT_SYMBOL(clk_get_rate);
230
231struct clk *clk_get_parent(struct clk *clk)
232{
233    unsigned long flags;
234
235    if (unlikely(IS_ERR_OR_NULL(clk)))
236        return NULL;
237
238    if (!clk->ops || !clk->ops->get_parent)
239        return clk->parent;
240
241    spin_lock_irqsave(&clocks_lock, flags);
242    clk->parent = clk->ops->get_parent(clk);
243    spin_unlock_irqrestore(&clocks_lock, flags);
244
245    return clk->parent;
246}
247EXPORT_SYMBOL(clk_get_parent);
248
249void __init mcs814x_clk_init(void)
250{
251    u32 bs1;
252    u8 cpu_freq;
253
254    clkdev_add_table(mcs814x_chip_clks, ARRAY_SIZE(mcs814x_chip_clks));
255
256    /* read the bootstrap registers to know the exact clocking scheme */
257    bs1 = readl_relaxed(mcs814x_sysdbg_base + SYSDBG_BS1);
258    cpu_freq = (bs1 >> CPU_FREQ_SHIFT) & CPU_FREQ_MASK;
259
260    pr_info("CPU frequency: %lu (kHz)\n", cpu_freq_table[cpu_freq]);
261    clk_cpu.rate = cpu_freq * KHZ;
262
263    /* read SDRAM frequency */
264    if (bs1 & SDRAM_FREQ_BIT)
265        clk_sdram.rate = 100 * MHZ;
266    else
267        clk_sdram.rate = 133 * MHZ;
268
269    pr_info("SDRAM frequency: %lu (MHz)\n", clk_sdram.rate / MHZ);
270}
271
272

Archive Download this file



interactive