aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2443/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c2443/clock.c')
-rw-r--r--arch/arm/mach-s3c2443/clock.c842
1 files changed, 283 insertions, 559 deletions
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index 2785d69c95b..62cd4eaee01 100644
--- a/arch/arm/mach-s3c2443/clock.c
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -1,6 +1,6 @@
1/* linux/arch/arm/mach-s3c2443/clock.c 1/* linux/arch/arm/mach-s3c2443/clock.c
2 * 2 *
3 * Copyright (c) 2007 Simtec Electronics 3 * Copyright (c) 2007, 2010 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk> 4 * Ben Dooks <ben@simtec.co.uk>
5 * 5 *
6 * S3C2443 Clock control support 6 * S3C2443 Clock control support
@@ -42,6 +42,7 @@
42 42
43#include <plat/s3c2443.h> 43#include <plat/s3c2443.h>
44#include <plat/clock.h> 44#include <plat/clock.h>
45#include <plat/clock-clksrc.h>
45#include <plat/cpu.h> 46#include <plat/cpu.h>
46 47
47/* We currently have to assume that the system is running 48/* We currently have to assume that the system is running
@@ -53,141 +54,69 @@
53 * set the correct muxing at initialisation 54 * set the correct muxing at initialisation
54*/ 55*/
55 56
56static int s3c2443_clkcon_enable_h(struct clk *clk, int enable) 57static int s3c2443_gate(void __iomem *reg, struct clk *clk, int enable)
57{
58 unsigned int clocks = clk->ctrlbit;
59 unsigned long clkcon;
60
61 clkcon = __raw_readl(S3C2443_HCLKCON);
62
63 if (enable)
64 clkcon |= clocks;
65 else
66 clkcon &= ~clocks;
67
68 __raw_writel(clkcon, S3C2443_HCLKCON);
69
70 return 0;
71}
72
73static int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
74{ 58{
75 unsigned int clocks = clk->ctrlbit; 59 u32 ctrlbit = clk->ctrlbit;
76 unsigned long clkcon; 60 u32 con = __raw_readl(reg);
77
78 clkcon = __raw_readl(S3C2443_PCLKCON);
79 61
80 if (enable) 62 if (enable)
81 clkcon |= clocks; 63 con |= ctrlbit;
82 else 64 else
83 clkcon &= ~clocks; 65 con &= ~ctrlbit;
84
85 __raw_writel(clkcon, S3C2443_PCLKCON);
86 66
67 __raw_writel(con, reg);
87 return 0; 68 return 0;
88} 69}
89 70
90static int s3c2443_clkcon_enable_s(struct clk *clk, int enable) 71static int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
91{
92 unsigned int clocks = clk->ctrlbit;
93 unsigned long clkcon;
94
95 clkcon = __raw_readl(S3C2443_SCLKCON);
96
97 if (enable)
98 clkcon |= clocks;
99 else
100 clkcon &= ~clocks;
101
102 __raw_writel(clkcon, S3C2443_SCLKCON);
103
104 return 0;
105}
106
107static unsigned long s3c2443_roundrate_clksrc(struct clk *clk,
108 unsigned long rate,
109 unsigned int max)
110{
111 unsigned long parent_rate = clk_get_rate(clk->parent);
112 int div;
113
114 if (rate > parent_rate)
115 return parent_rate;
116
117 /* note, we remove the +/- 1 calculations as they cancel out */
118
119 div = (rate / parent_rate);
120
121 if (div < 1)
122 div = 1;
123 else if (div > max)
124 div = max;
125
126 return parent_rate / div;
127}
128
129static unsigned long s3c2443_roundrate_clksrc4(struct clk *clk,
130 unsigned long rate)
131{ 72{
132 return s3c2443_roundrate_clksrc(clk, rate, 4); 73 return s3c2443_gate(S3C2443_HCLKCON, clk, enable);
133} 74}
134 75
135static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk, 76static int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
136 unsigned long rate)
137{ 77{
138 return s3c2443_roundrate_clksrc(clk, rate, 16); 78 return s3c2443_gate(S3C2443_PCLKCON, clk, enable);
139} 79}
140 80
141static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk, 81static int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
142 unsigned long rate)
143{ 82{
144 return s3c2443_roundrate_clksrc(clk, rate, 256); 83 return s3c2443_gate(S3C2443_SCLKCON, clk, enable);
145} 84}
146 85
147/* clock selections */ 86/* clock selections */
148 87
88/* mpllref is a direct descendant of clk_xtal by default, but it is not
89 * elided as the EPLL can be either sourced by the XTAL or EXTCLK and as
90 * such directly equating the two source clocks is impossible.
91 */
149static struct clk clk_mpllref = { 92static struct clk clk_mpllref = {
150 .name = "mpllref", 93 .name = "mpllref",
151 .parent = &clk_xtal, 94 .parent = &clk_xtal,
152 .id = -1, 95 .id = -1,
153}; 96};
154 97
155#if 0
156static struct clk clk_mpll = {
157 .name = "mpll",
158 .parent = &clk_mpllref,
159 .id = -1,
160};
161#endif
162
163static struct clk clk_i2s_ext = { 98static struct clk clk_i2s_ext = {
164 .name = "i2s-ext", 99 .name = "i2s-ext",
165 .id = -1, 100 .id = -1,
166}; 101};
167 102
168static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent) 103static struct clk *clk_epllref_sources[] = {
169{ 104 [0] = &clk_mpllref,
170 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); 105 [1] = &clk_mpllref,
171 106 [2] = &clk_xtal,
172 clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK; 107 [3] = &clk_ext,
173 108};
174 if (parent == &clk_xtal)
175 clksrc |= S3C2443_CLKSRC_EPLLREF_XTAL;
176 else if (parent == &clk_ext)
177 clksrc |= S3C2443_CLKSRC_EPLLREF_EXTCLK;
178 else if (parent != &clk_mpllref)
179 return -EINVAL;
180
181 __raw_writel(clksrc, S3C2443_CLKSRC);
182 clk->parent = parent;
183
184 return 0;
185}
186 109
187static struct clk clk_epllref = { 110static struct clksrc_clk clk_epllref = {
188 .name = "epllref", 111 .clk = {
189 .id = -1, 112 .name = "epllref",
190 .set_parent = s3c2443_setparent_epllref, 113 .id = -1,
114 },
115 .sources = &(struct clksrc_sources) {
116 .sources = clk_epllref_sources,
117 .nr_sources = ARRAY_SIZE(clk_epllref_sources),
118 },
119 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
191}; 120};
192 121
193static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) 122static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
@@ -205,34 +134,29 @@ static struct clk clk_mdivclk = {
205 .name = "mdivclk", 134 .name = "mdivclk",
206 .parent = &clk_mpllref, 135 .parent = &clk_mpllref,
207 .id = -1, 136 .id = -1,
208 .get_rate = s3c2443_getrate_mdivclk, 137 .ops = &(struct clk_ops) {
138 .get_rate = s3c2443_getrate_mdivclk,
139 },
209}; 140};
210 141
211static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) 142static struct clk *clk_msysclk_sources[] = {
212{ 143 [0] = &clk_mpllref,
213 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); 144 [1] = &clk_mpll,
214 145 [2] = &clk_mdivclk,
215 clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL | 146 [3] = &clk_mpllref,
216 S3C2443_CLKSRC_EXTCLK_DIV); 147};
217
218 if (parent == &clk_mpll)
219 clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL;
220 else if (parent == &clk_mdivclk)
221 clksrc |= S3C2443_CLKSRC_EXTCLK_DIV;
222 else if (parent != &clk_mpllref)
223 return -EINVAL;
224
225 __raw_writel(clksrc, S3C2443_CLKSRC);
226 clk->parent = parent;
227
228 return 0;
229}
230 148
231static struct clk clk_msysclk = { 149static struct clksrc_clk clk_msysclk = {
232 .name = "msysclk", 150 .clk = {
233 .parent = &clk_xtal, 151 .name = "msysclk",
234 .id = -1, 152 .parent = &clk_xtal,
235 .set_parent = s3c2443_setparent_msysclk, 153 .id = -1,
154 },
155 .sources = &(struct clksrc_sources) {
156 .sources = clk_msysclk_sources,
157 .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
158 },
159 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
236}; 160};
237 161
238/* armdiv 162/* armdiv
@@ -241,152 +165,159 @@ static struct clk clk_msysclk = {
241 * divider values applied to it to then be fed into armclk. 165 * divider values applied to it to then be fed into armclk.
242*/ 166*/
243 167
244static struct clk clk_armdiv = { 168/* armdiv divisor table */
245 .name = "armdiv",
246 .id = -1,
247 .parent = &clk_msysclk,
248};
249 169
250/* armclk 170static unsigned int armdiv[16] = {
251 * 171 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
252 * this is the clock fed into the ARM core itself, either from 172 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
253 * armdiv or from hclk. 173 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
254 */ 174 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
175 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
176 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
177 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
178 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
179};
255 180
256static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent) 181static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
257{ 182{
258 unsigned long clkdiv0; 183 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
259
260 clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
261
262 if (parent == &clk_armdiv)
263 clkdiv0 &= ~S3C2443_CLKDIV0_DVS;
264 else if (parent == &clk_h)
265 clkdiv0 |= S3C2443_CLKDIV0_DVS;
266 else
267 return -EINVAL;
268 184
269 __raw_writel(clkdiv0, S3C2443_CLKDIV0); 185 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
270 return 0;
271} 186}
272 187
273static struct clk clk_arm = { 188static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
274 .name = "armclk", 189 unsigned long rate)
275 .id = -1, 190{
276 .set_parent = s3c2443_setparent_armclk, 191 unsigned long parent = clk_get_rate(clk->parent);
277}; 192 unsigned long calc;
193 unsigned best = 256; /* bigger than any value */
194 unsigned div;
195 int ptr;
278 196
279/* esysclk 197 for (ptr = 0; ptr < ARRAY_SIZE(armdiv); ptr++) {
280 * 198 div = armdiv[ptr];
281 * this is sourced from either the EPLL or the EPLLref clock 199 calc = parent / div;
282*/ 200 if (calc <= rate && div < best)
201 best = div;
202 }
283 203
284static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent) 204 return parent / best;
205}
206
207static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
285{ 208{
286 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); 209 unsigned long parent = clk_get_rate(clk->parent);
210 unsigned long calc;
211 unsigned div;
212 unsigned best = 256; /* bigger than any value */
213 int ptr;
214 int val = -1;
215
216 for (ptr = 0; ptr < ARRAY_SIZE(armdiv); ptr++) {
217 div = armdiv[ptr];
218 calc = parent / div;
219 if (calc <= rate && div < best) {
220 best = div;
221 val = ptr;
222 }
223 }
287 224
288 if (parent == &clk_epll) 225 if (val >= 0) {
289 clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL; 226 unsigned long clkcon0;
290 else if (parent == &clk_epllref)
291 clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL;
292 else
293 return -EINVAL;
294 227
295 __raw_writel(clksrc, S3C2443_CLKSRC); 228 clkcon0 = __raw_readl(S3C2443_CLKDIV0);
296 clk->parent = parent; 229 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
230 clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
231 __raw_writel(clkcon0, S3C2443_CLKDIV0);
232 }
297 233
298 return 0; 234 return (val == -1) ? -EINVAL : 0;
299} 235}
300 236
301static struct clk clk_esysclk = { 237static struct clk clk_armdiv = {
302 .name = "esysclk", 238 .name = "armdiv",
303 .parent = &clk_epll,
304 .id = -1, 239 .id = -1,
305 .set_parent = s3c2443_setparent_esysclk, 240 .parent = &clk_msysclk.clk,
241 .ops = &(struct clk_ops) {
242 .round_rate = s3c2443_armclk_roundrate,
243 .set_rate = s3c2443_armclk_setrate,
244 },
306}; 245};
307 246
308/* uartclk 247/* armclk
309 * 248 *
310 * UART baud-rate clock sourced from esysclk via a divisor 249 * this is the clock fed into the ARM core itself, from armdiv or from hclk.
311*/ 250 */
312
313static unsigned long s3c2443_getrate_uart(struct clk *clk)
314{
315 unsigned long parent_rate = clk_get_rate(clk->parent);
316 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
317
318 div &= S3C2443_CLKDIV1_UARTDIV_MASK;
319 div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT;
320 251
321 return parent_rate / (div + 1); 252static struct clk *clk_arm_sources[] = {
322} 253 [0] = &clk_armdiv,
254 [1] = &clk_h,
255};
323 256
257static struct clksrc_clk clk_arm = {
258 .clk = {
259 .name = "armclk",
260 .id = -1,
261 },
262 .sources = &(struct clksrc_sources) {
263 .sources = clk_arm_sources,
264 .nr_sources = ARRAY_SIZE(clk_arm_sources),
265 },
266 .reg_src = { .reg = S3C2443_CLKDIV0, .size = 1, .shift = 13 },
267};
324 268
325static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate) 269/* esysclk
326{ 270 *
327 unsigned long parent_rate = clk_get_rate(clk->parent); 271 * this is sourced from either the EPLL or the EPLLref clock
328 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); 272*/
329 273
330 rate = s3c2443_roundrate_clksrc16(clk, rate); 274static struct clk *clk_sysclk_sources[] = {
331 rate = parent_rate / rate; 275 [0] = &clk_epllref.clk,
276 [1] = &clk_epll,
277};
332 278
333 clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; 279static struct clksrc_clk clk_esysclk = {
334 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; 280 .clk = {
281 .name = "esysclk",
282 .parent = &clk_epll,
283 .id = -1,
284 },
285 .sources = &(struct clksrc_sources) {
286 .sources = clk_sysclk_sources,
287 .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
288 },
289 .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
290};
335 291
336 __raw_writel(clkdivn, S3C2443_CLKDIV1); 292/* uartclk
337 return 0; 293 *
338} 294 * UART baud-rate clock sourced from esysclk via a divisor
295*/
339 296
340static struct clk clk_uart = { 297static struct clksrc_clk clk_uart = {
341 .name = "uartclk", 298 .clk = {
342 .id = -1, 299 .name = "uartclk",
343 .parent = &clk_esysclk, 300 .id = -1,
344 .get_rate = s3c2443_getrate_uart, 301 .parent = &clk_esysclk.clk,
345 .set_rate = s3c2443_setrate_uart, 302 },
346 .round_rate = s3c2443_roundrate_clksrc16, 303 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
347}; 304};
348 305
306
349/* hsspi 307/* hsspi
350 * 308 *
351 * high-speed spi clock, sourced from esysclk 309 * high-speed spi clock, sourced from esysclk
352*/ 310*/
353 311
354static unsigned long s3c2443_getrate_hsspi(struct clk *clk) 312static struct clksrc_clk clk_hsspi = {
355{ 313 .clk = {
356 unsigned long parent_rate = clk_get_rate(clk->parent); 314 .name = "hsspi",
357 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 315 .id = -1,
358 316 .parent = &clk_esysclk.clk,
359 div &= S3C2443_CLKDIV1_HSSPIDIV_MASK; 317 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
360 div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT; 318 .enable = s3c2443_clkcon_enable_s,
361 319 },
362 return parent_rate / (div + 1); 320 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
363}
364
365
366static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate)
367{
368 unsigned long parent_rate = clk_get_rate(clk->parent);
369 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
370
371 rate = s3c2443_roundrate_clksrc4(clk, rate);
372 rate = parent_rate / rate;
373
374 clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK;
375 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT;
376
377 __raw_writel(clkdivn, S3C2443_CLKDIV1);
378 return 0;
379}
380
381static struct clk clk_hsspi = {
382 .name = "hsspi",
383 .id = -1,
384 .parent = &clk_esysclk,
385 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
386 .enable = s3c2443_clkcon_enable_s,
387 .get_rate = s3c2443_getrate_hsspi,
388 .set_rate = s3c2443_setrate_hsspi,
389 .round_rate = s3c2443_roundrate_clksrc4,
390}; 321};
391 322
392/* usbhost 323/* usbhost
@@ -394,41 +325,15 @@ static struct clk clk_hsspi = {
394 * usb host bus-clock, usually 48MHz to provide USB bus clock timing 325 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
395*/ 326*/
396 327
397static unsigned long s3c2443_getrate_usbhost(struct clk *clk) 328static struct clksrc_clk clk_usb_bus_host = {
398{ 329 .clk = {
399 unsigned long parent_rate = clk_get_rate(clk->parent); 330 .name = "usb-bus-host-parent",
400 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 331 .id = -1,
401 332 .parent = &clk_esysclk.clk,
402 div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK; 333 .ctrlbit = S3C2443_SCLKCON_USBHOST,
403 div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; 334 .enable = s3c2443_clkcon_enable_s,
404 335 },
405 return parent_rate / (div + 1); 336 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
406}
407
408static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate)
409{
410 unsigned long parent_rate = clk_get_rate(clk->parent);
411 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
412
413 rate = s3c2443_roundrate_clksrc4(clk, rate);
414 rate = parent_rate / rate;
415
416 clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK;
417 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT;
418
419 __raw_writel(clkdivn, S3C2443_CLKDIV1);
420 return 0;
421}
422
423static struct clk clk_usb_bus_host = {
424 .name = "usb-bus-host-parent",
425 .id = -1,
426 .parent = &clk_esysclk,
427 .ctrlbit = S3C2443_SCLKCON_USBHOST,
428 .enable = s3c2443_clkcon_enable_s,
429 .get_rate = s3c2443_getrate_usbhost,
430 .set_rate = s3c2443_setrate_usbhost,
431 .round_rate = s3c2443_roundrate_clksrc4,
432}; 337};
433 338
434/* clk_hsmcc_div 339/* clk_hsmcc_div
@@ -438,39 +343,13 @@ static struct clk clk_usb_bus_host = {
438 * be fed to the hsmmc block 343 * be fed to the hsmmc block
439*/ 344*/
440 345
441static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk) 346static struct clksrc_clk clk_hsmmc_div = {
442{ 347 .clk = {
443 unsigned long parent_rate = clk_get_rate(clk->parent); 348 .name = "hsmmc-div",
444 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 349 .id = -1,
445 350 .parent = &clk_esysclk.clk,
446 div &= S3C2443_CLKDIV1_HSMMCDIV_MASK; 351 },
447 div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT; 352 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
448
449 return parent_rate / (div + 1);
450}
451
452static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate)
453{
454 unsigned long parent_rate = clk_get_rate(clk->parent);
455 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
456
457 rate = s3c2443_roundrate_clksrc4(clk, rate);
458 rate = parent_rate / rate;
459
460 clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK;
461 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT;
462
463 __raw_writel(clkdivn, S3C2443_CLKDIV1);
464 return 0;
465}
466
467static struct clk clk_hsmmc_div = {
468 .name = "hsmmc-div",
469 .id = -1,
470 .parent = &clk_esysclk,
471 .get_rate = s3c2443_getrate_hsmmc_div,
472 .set_rate = s3c2443_setrate_hsmmc_div,
473 .round_rate = s3c2443_roundrate_clksrc4,
474}; 353};
475 354
476static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) 355static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
@@ -503,82 +382,55 @@ static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
503static struct clk clk_hsmmc = { 382static struct clk clk_hsmmc = {
504 .name = "hsmmc-if", 383 .name = "hsmmc-if",
505 .id = -1, 384 .id = -1,
506 .parent = &clk_hsmmc_div, 385 .parent = &clk_hsmmc_div.clk,
507 .enable = s3c2443_enable_hsmmc, 386 .enable = s3c2443_enable_hsmmc,
508 .set_parent = s3c2443_setparent_hsmmc, 387 .ops = &(struct clk_ops) {
388 .set_parent = s3c2443_setparent_hsmmc,
389 },
509}; 390};
510 391
511/* i2s_eplldiv 392/* i2s_eplldiv
512 * 393 *
513 * this clock is the output from the i2s divisor of esysclk 394 * This clock is the output from the I2S divisor of ESYSCLK, and is seperate
395 * from the mux that comes after it (cannot merge into one single clock)
514*/ 396*/
515 397
516static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk) 398static struct clksrc_clk clk_i2s_eplldiv = {
517{ 399 .clk = {
518 unsigned long parent_rate = clk_get_rate(clk->parent); 400 .name = "i2s-eplldiv",
519 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 401 .id = -1,
520 402 .parent = &clk_esysclk.clk,
521 div &= S3C2443_CLKDIV1_I2SDIV_MASK; 403 },
522 div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT; 404 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
523
524 return parent_rate / (div + 1);
525}
526
527static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate)
528{
529 unsigned long parent_rate = clk_get_rate(clk->parent);
530 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
531
532 rate = s3c2443_roundrate_clksrc16(clk, rate);
533 rate = parent_rate / rate;
534
535 clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK;
536 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT;
537
538 __raw_writel(clkdivn, S3C2443_CLKDIV1);
539 return 0;
540}
541
542static struct clk clk_i2s_eplldiv = {
543 .name = "i2s-eplldiv",
544 .id = -1,
545 .parent = &clk_esysclk,
546 .get_rate = s3c2443_getrate_i2s_eplldiv,
547 .set_rate = s3c2443_setrate_i2s_eplldiv,
548 .round_rate = s3c2443_roundrate_clksrc16,
549}; 405};
550 406
551/* i2s-ref 407/* i2s-ref
552 * 408 *
553 * i2s bus reference clock, selectable from external, esysclk or epllref 409 * i2s bus reference clock, selectable from external, esysclk or epllref
410 *
411 * Note, this used to be two clocks, but was compressed into one.
554*/ 412*/
555 413
556static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent) 414struct clk *clk_i2s_srclist[] = {
557{ 415 [0] = &clk_i2s_eplldiv.clk,
558 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); 416 [1] = &clk_i2s_ext,
559 417 [2] = &clk_epllref.clk,
560 clksrc &= ~S3C2443_CLKSRC_I2S_MASK; 418 [3] = &clk_epllref.clk,
561 419};
562 if (parent == &clk_epllref)
563 clksrc |= S3C2443_CLKSRC_I2S_EPLLREF;
564 else if (parent == &clk_i2s_ext)
565 clksrc |= S3C2443_CLKSRC_I2S_EXT;
566 else if (parent != &clk_i2s_eplldiv)
567 return -EINVAL;
568
569 clk->parent = parent;
570 __raw_writel(clksrc, S3C2443_CLKSRC);
571
572 return 0;
573}
574 420
575static struct clk clk_i2s = { 421static struct clksrc_clk clk_i2s = {
576 .name = "i2s-if", 422 .clk = {
577 .id = -1, 423 .name = "i2s-if",
578 .parent = &clk_i2s_eplldiv, 424 .id = -1,
579 .ctrlbit = S3C2443_SCLKCON_I2SCLK, 425 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
580 .enable = s3c2443_clkcon_enable_s, 426 .enable = s3c2443_clkcon_enable_s,
581 .set_parent = s3c2443_setparent_i2s, 427
428 },
429 .sources = &(struct clksrc_sources) {
430 .sources = clk_i2s_srclist,
431 .nr_sources = ARRAY_SIZE(clk_i2s_srclist),
432 },
433 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 },
582}; 434};
583 435
584/* cam-if 436/* cam-if
@@ -586,41 +438,15 @@ static struct clk clk_i2s = {
586 * camera interface bus-clock, divided down from esysclk 438 * camera interface bus-clock, divided down from esysclk
587*/ 439*/
588 440
589static unsigned long s3c2443_getrate_cam(struct clk *clk) 441static struct clksrc_clk clk_cam = {
590{ 442 .clk = {
591 unsigned long parent_rate = clk_get_rate(clk->parent); 443 .name = "camif-upll", /* same as 2440 name */
592 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 444 .id = -1,
593 445 .parent = &clk_esysclk.clk,
594 div &= S3C2443_CLKDIV1_CAMDIV_MASK; 446 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
595 div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT; 447 .enable = s3c2443_clkcon_enable_s,
596 448 },
597 return parent_rate / (div + 1); 449 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
598}
599
600static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate)
601{
602 unsigned long parent_rate = clk_get_rate(clk->parent);
603 unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1);
604
605 rate = s3c2443_roundrate_clksrc16(clk, rate);
606 rate = parent_rate / rate;
607
608 clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK;
609 clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT;
610
611 __raw_writel(clkdiv1, S3C2443_CLKDIV1);
612 return 0;
613}
614
615static struct clk clk_cam = {
616 .name = "camif-upll", /* same as 2440 name */
617 .id = -1,
618 .parent = &clk_esysclk,
619 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
620 .enable = s3c2443_clkcon_enable_s,
621 .get_rate = s3c2443_getrate_cam,
622 .set_rate = s3c2443_setrate_cam,
623 .round_rate = s3c2443_roundrate_clksrc16,
624}; 450};
625 451
626/* display-if 452/* display-if
@@ -628,41 +454,15 @@ static struct clk clk_cam = {
628 * display interface clock, divided from esysclk 454 * display interface clock, divided from esysclk
629*/ 455*/
630 456
631static unsigned long s3c2443_getrate_display(struct clk *clk) 457static struct clksrc_clk clk_display = {
632{ 458 .clk = {
633 unsigned long parent_rate = clk_get_rate(clk->parent); 459 .name = "display-if",
634 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 460 .id = -1,
635 461 .parent = &clk_esysclk.clk,
636 div &= S3C2443_CLKDIV1_DISPDIV_MASK; 462 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
637 div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT; 463 .enable = s3c2443_clkcon_enable_s,
638 464 },
639 return parent_rate / (div + 1); 465 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
640}
641
642static int s3c2443_setrate_display(struct clk *clk, unsigned long rate)
643{
644 unsigned long parent_rate = clk_get_rate(clk->parent);
645 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
646
647 rate = s3c2443_roundrate_clksrc256(clk, rate);
648 rate = parent_rate / rate;
649
650 clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK;
651 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT;
652
653 __raw_writel(clkdivn, S3C2443_CLKDIV1);
654 return 0;
655}
656
657static struct clk clk_display = {
658 .name = "display-if",
659 .id = -1,
660 .parent = &clk_esysclk,
661 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
662 .enable = s3c2443_clkcon_enable_s,
663 .get_rate = s3c2443_getrate_display,
664 .set_rate = s3c2443_setrate_display,
665 .round_rate = s3c2443_roundrate_clksrc256,
666}; 466};
667 467
668/* prediv 468/* prediv
@@ -684,8 +484,10 @@ static unsigned long s3c2443_prediv_getrate(struct clk *clk)
684static struct clk clk_prediv = { 484static struct clk clk_prediv = {
685 .name = "prediv", 485 .name = "prediv",
686 .id = -1, 486 .id = -1,
687 .parent = &clk_msysclk, 487 .parent = &clk_msysclk.clk,
688 .get_rate = s3c2443_prediv_getrate, 488 .ops = &(struct clk_ops) {
489 .get_rate = s3c2443_prediv_getrate,
490 },
689}; 491};
690 492
691/* standard clock definitions */ 493/* standard clock definitions */
@@ -857,7 +659,7 @@ static struct clk init_clocks[] = {
857 }, { 659 }, {
858 .name = "usb-bus-host", 660 .name = "usb-bus-host",
859 .id = -1, 661 .id = -1,
860 .parent = &clk_usb_bus_host, 662 .parent = &clk_usb_bus_host.clk,
861 }, { 663 }, {
862 .name = "ac97", 664 .name = "ac97",
863 .id = -1, 665 .id = -1,
@@ -868,103 +670,26 @@ static struct clk init_clocks[] = {
868 670
869/* clocks to add where we need to check their parentage */ 671/* clocks to add where we need to check their parentage */
870 672
871/* s3c2443_clk_initparents 673static struct clksrc_clk __initdata *init_list[] = {
872 * 674 &clk_epllref, /* should be first */
873 * Initialise the parents for the clocks that we get at start-time 675 &clk_esysclk,
874*/ 676 &clk_msysclk,
875 677 &clk_arm,
876static int __init clk_init_set_parent(struct clk *clk, struct clk *parent) 678 &clk_i2s_eplldiv,
877{ 679 &clk_i2s,
878 printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name); 680 &clk_cam,
879 return clk_set_parent(clk, parent); 681 &clk_uart,
880} 682 &clk_display,
881 683 &clk_hsmmc_div,
882static void __init s3c2443_clk_initparents(void) 684 &clk_usb_bus_host,
883{
884 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
885 struct clk *parent;
886
887 switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) {
888 case S3C2443_CLKSRC_EPLLREF_EXTCLK:
889 parent = &clk_ext;
890 break;
891
892 case S3C2443_CLKSRC_EPLLREF_XTAL:
893 default:
894 parent = &clk_xtal;
895 break;
896
897 case S3C2443_CLKSRC_EPLLREF_MPLLREF:
898 case S3C2443_CLKSRC_EPLLREF_MPLLREF2:
899 parent = &clk_mpllref;
900 break;
901 }
902
903 clk_init_set_parent(&clk_epllref, parent);
904
905 switch (clksrc & S3C2443_CLKSRC_I2S_MASK) {
906 case S3C2443_CLKSRC_I2S_EXT:
907 parent = &clk_i2s_ext;
908 break;
909
910 case S3C2443_CLKSRC_I2S_EPLLDIV:
911 default:
912 parent = &clk_i2s_eplldiv;
913 break;
914
915 case S3C2443_CLKSRC_I2S_EPLLREF:
916 case S3C2443_CLKSRC_I2S_EPLLREF3:
917 parent = &clk_epllref;
918 }
919
920 clk_init_set_parent(&clk_i2s, &clk_epllref);
921
922 /* esysclk source */
923
924 parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ?
925 &clk_epll : &clk_epllref;
926
927 clk_init_set_parent(&clk_esysclk, parent);
928
929 /* msysclk source */
930
931 if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) {
932 parent = &clk_mpll;
933 } else {
934 parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ?
935 &clk_mdivclk : &clk_mpllref;
936 }
937
938 clk_init_set_parent(&clk_msysclk, parent);
939
940 /* arm */
941
942 if (__raw_readl(S3C2443_CLKDIV0) & S3C2443_CLKDIV0_DVS)
943 parent = &clk_h;
944 else
945 parent = &clk_armdiv;
946
947 clk_init_set_parent(&clk_arm, parent);
948}
949
950/* armdiv divisor table */
951
952static unsigned int armdiv[16] = {
953 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
954 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
955 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
956 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
957 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
958 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
959 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
960 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
961}; 685};
962 686
963static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0) 687static void __init s3c2443_clk_initparents(void)
964{ 688{
965 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; 689 int ptr;
966 690
967 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]; 691 for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++)
692 s3c_set_clksrc(init_list[ptr], true);
968} 693}
969 694
970static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) 695static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
@@ -976,15 +701,12 @@ static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
976 701
977/* clocks to add straight away */ 702/* clocks to add straight away */
978 703
979static struct clk *clks[] __initdata = { 704static struct clksrc_clk *clksrcs[] __initdata = {
980 &clk_ext,
981 &clk_epll,
982 &clk_usb_bus_host, 705 &clk_usb_bus_host,
983 &clk_usb_bus,
984 &clk_esysclk,
985 &clk_epllref, 706 &clk_epllref,
986 &clk_mpllref, 707 &clk_esysclk,
987 &clk_msysclk, 708 &clk_msysclk,
709 &clk_arm,
988 &clk_uart, 710 &clk_uart,
989 &clk_display, 711 &clk_display,
990 &clk_cam, 712 &clk_cam,
@@ -992,9 +714,15 @@ static struct clk *clks[] __initdata = {
992 &clk_i2s, 714 &clk_i2s,
993 &clk_hsspi, 715 &clk_hsspi,
994 &clk_hsmmc_div, 716 &clk_hsmmc_div,
717};
718
719static struct clk *clks[] __initdata = {
720 &clk_ext,
721 &clk_epll,
722 &clk_usb_bus,
723 &clk_mpllref,
995 &clk_hsmmc, 724 &clk_hsmmc,
996 &clk_armdiv, 725 &clk_armdiv,
997 &clk_arm,
998 &clk_prediv, 726 &clk_prediv,
999}; 727};
1000 728
@@ -1014,7 +742,7 @@ void __init_or_cpufreq s3c2443_setup_clocks(void)
1014 clk_put(xtal_clk); 742 clk_put(xtal_clk);
1015 743
1016 pll = s3c2443_get_mpll(mpllcon, xtal); 744 pll = s3c2443_get_mpll(mpllcon, xtal);
1017 clk_msysclk.rate = pll; 745 clk_msysclk.clk.rate = pll;
1018 746
1019 fclk = pll / s3c2443_fclk_div(clkdiv0); 747 fclk = pll / s3c2443_fclk_div(clkdiv0);
1020 hclk = s3c2443_prediv_getrate(&clk_prediv); 748 hclk = s3c2443_prediv_getrate(&clk_prediv);
@@ -1056,15 +784,18 @@ void __init s3c2443_init_clocks(int xtal)
1056 } 784 }
1057 } 785 }
1058 786
787 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
788 s3c_register_clksrc(clksrcs[ptr], 1);
789
1059 clk_epll.rate = s3c2443_get_epll(epllcon, xtal); 790 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
1060 clk_epll.parent = &clk_epllref; 791 clk_epll.parent = &clk_epllref.clk;
1061 clk_usb_bus.parent = &clk_usb_bus_host; 792 clk_usb_bus.parent = &clk_usb_bus_host.clk;
1062 793
1063 /* ensure usb bus clock is within correct rate of 48MHz */ 794 /* ensure usb bus clock is within correct rate of 48MHz */
1064 795
1065 if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) { 796 if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
1066 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); 797 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
1067 clk_set_rate(&clk_usb_bus_host, 48*1000*1000); 798 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
1068 } 799 }
1069 800
1070 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", 801 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
@@ -1074,14 +805,7 @@ void __init s3c2443_init_clocks(int xtal)
1074 805
1075 /* register clocks from clock array */ 806 /* register clocks from clock array */
1076 807
1077 clkp = init_clocks; 808 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
1078 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
1079 ret = s3c24xx_register_clock(clkp);
1080 if (ret < 0) {
1081 printk(KERN_ERR "Failed to register clock %s (%d)\n",
1082 clkp->name, ret);
1083 }
1084 }
1085 809
1086 /* We must be careful disabling the clocks we are not intending to 810 /* We must be careful disabling the clocks we are not intending to
1087 * be using at boot time, as subsystems such as the LCD which do 811 * be using at boot time, as subsystems such as the LCD which do