413bfecaa131dffe3b9a47626f1751e28093e149
[openwrt/svn-archive/archive.git] / 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
24 struct 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
31 struct 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
41 static 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
49 static 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
68 static struct clk_ops default_clk_ops = {
69 .get_rate = clk_divide_parent,
70 .enable = clk_local_onoff_enable,
71 };
72
73 static DEFINE_SPINLOCK(clocks_lock);
74
75 static 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
94 static struct clk clk_cpu;
95
96 /* System clock is fixed at 50Mhz */
97 static struct clk clk_sys = {
98 .rate = 50 * MHZ,
99 };
100
101 static struct clk clk_sdram;
102
103 static struct clk clk_timer0 = {
104 .parent = &clk_sdram,
105 .divider = 2,
106 .ops = &default_clk_ops,
107 };
108
109 static struct clk clk_timer1_2 = {
110 .parent = &clk_sys,
111 };
112
113 /* Watchdog clock is system clock / 128 */
114 static struct clk clk_wdt = {
115 .parent = &clk_sys,
116 .divider = 128,
117 .ops = &default_clk_ops,
118 };
119
120 static struct clk clk_emac = {
121 .ops = &default_clk_ops,
122 .enable_reg = SYSDBG_SYSCTL,
123 .enable_mask = SYSCTL_EMAC,
124 };
125
126 static struct clk clk_ephy = {
127 .ops = &default_clk_ops,
128 .enable_reg = SYSDBG_PLL_CTL,
129 .enable_mask = ~SYSCTL_EPHY, /* active low */
130 };
131
132 static 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
141 static 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
157 static 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
172 static 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
193 int 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 }
204 EXPORT_SYMBOL(clk_enable);
205
206 void 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 }
214 EXPORT_SYMBOL(clk_disable);
215
216 unsigned 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 }
229 EXPORT_SYMBOL(clk_get_rate);
230
231 struct 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 }
247 EXPORT_SYMBOL(clk_get_parent);
248
249 void __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