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