aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2443
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2010-03-07 17:56:19 -0500
committerBen Dooks <ben-linux@fluff.org>2010-03-07 17:56:19 -0500
commit3b05007e43ea629394e89ea0b023d7b15375a2bb (patch)
treef96ba06dc0f8934786d40351eeeadb40675e04ee /arch/arm/mach-s3c2443
parentf9fed7cd7efaa0d050f21f6f9ed532d3143b7369 (diff)
parent41f23a09f32124322dc41bea7f65baff6e9b0ac5 (diff)
ARM: Merge next-samsung-s3c2443-clock
Merge branch 'next-samsung-s3c2443-clock' into next-samsung
Diffstat (limited to 'arch/arm/mach-s3c2443')
-rw-r--r--arch/arm/mach-s3c2443/Kconfig1
-rw-r--r--arch/arm/mach-s3c2443/clock.c817
2 files changed, 260 insertions, 558 deletions
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig
index 4314c4424909..698140af247c 100644
--- a/arch/arm/mach-s3c2443/Kconfig
+++ b/arch/arm/mach-s3c2443/Kconfig
@@ -7,6 +7,7 @@ config CPU_S3C2443
7 depends on ARCH_S3C2410 7 depends on ARCH_S3C2410
8 select S3C2443_DMA if S3C2410_DMA 8 select S3C2443_DMA if S3C2410_DMA
9 select CPU_LLSERIAL_S3C2440 9 select CPU_LLSERIAL_S3C2440
10 select SAMSUNG_CLKSRC
10 help 11 help
11 Support for the S3C2443 SoC from the S3C24XX line 12 Support for the S3C2443 SoC from the S3C24XX line
12 13
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
index 3eb8b935d64c..62cd4eaee01b 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,143 +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{
75 unsigned int clocks = clk->ctrlbit;
76 unsigned long clkcon;
77
78 clkcon = __raw_readl(S3C2443_PCLKCON);
79
80 if (enable)
81 clkcon |= clocks;
82 else
83 clkcon &= ~clocks;
84
85 __raw_writel(clkcon, S3C2443_PCLKCON);
86
87 return 0;
88}
89
90static int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
91{ 58{
92 unsigned int clocks = clk->ctrlbit; 59 u32 ctrlbit = clk->ctrlbit;
93 unsigned long clkcon; 60 u32 con = __raw_readl(reg);
94
95 clkcon = __raw_readl(S3C2443_SCLKCON);
96 61
97 if (enable) 62 if (enable)
98 clkcon |= clocks; 63 con |= ctrlbit;
99 else 64 else
100 clkcon &= ~clocks; 65 con &= ~ctrlbit;
101
102 __raw_writel(clkcon, S3C2443_SCLKCON);
103 66
67 __raw_writel(con, reg);
104 return 0; 68 return 0;
105} 69}
106 70
107static unsigned long s3c2443_roundrate_clksrc(struct clk *clk, 71static int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
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 .ops = &(struct clk_ops) { 113 .id = -1,
191 .set_parent = s3c2443_setparent_epllref, 114 },
115 .sources = &(struct clksrc_sources) {
116 .sources = clk_epllref_sources,
117 .nr_sources = ARRAY_SIZE(clk_epllref_sources),
192 }, 118 },
119 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 },
193}; 120};
194 121
195static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) 122static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
@@ -212,33 +139,24 @@ static struct clk clk_mdivclk = {
212 }, 139 },
213}; 140};
214 141
215static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) 142static struct clk *clk_msysclk_sources[] = {
216{ 143 [0] = &clk_mpllref,
217 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); 144 [1] = &clk_mpll,
218 145 [2] = &clk_mdivclk,
219 clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL | 146 [3] = &clk_mpllref,
220 S3C2443_CLKSRC_EXTCLK_DIV); 147};
221
222 if (parent == &clk_mpll)
223 clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL;
224 else if (parent == &clk_mdivclk)
225 clksrc |= S3C2443_CLKSRC_EXTCLK_DIV;
226 else if (parent != &clk_mpllref)
227 return -EINVAL;
228
229 __raw_writel(clksrc, S3C2443_CLKSRC);
230 clk->parent = parent;
231
232 return 0;
233}
234 148
235static struct clk clk_msysclk = { 149static struct clksrc_clk clk_msysclk = {
236 .name = "msysclk", 150 .clk = {
237 .parent = &clk_xtal, 151 .name = "msysclk",
238 .id = -1, 152 .parent = &clk_xtal,
239 .ops = &(struct clk_ops) { 153 .id = -1,
240 .set_parent = s3c2443_setparent_msysclk, 154 },
155 .sources = &(struct clksrc_sources) {
156 .sources = clk_msysclk_sources,
157 .nr_sources = ARRAY_SIZE(clk_msysclk_sources),
241 }, 158 },
159 .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 3 },
242}; 160};
243 161
244/* armdiv 162/* armdiv
@@ -247,72 +165,128 @@ static struct clk clk_msysclk = {
247 * divider values applied to it to then be fed into armclk. 165 * divider values applied to it to then be fed into armclk.
248*/ 166*/
249 167
250static struct clk clk_armdiv = { 168/* armdiv divisor table */
251 .name = "armdiv", 169
252 .id = -1, 170static unsigned int armdiv[16] = {
253 .parent = &clk_msysclk, 171 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
172 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
173 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
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,
254}; 179};
255 180
256/* armclk 181static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
257 * 182{
258 * this is the clock fed into the ARM core itself, either from 183 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
259 * armdiv or from hclk.
260 */
261 184
262static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent) 185 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
186}
187
188static unsigned long s3c2443_armclk_roundrate(struct clk *clk,
189 unsigned long rate)
263{ 190{
264 unsigned long clkdiv0; 191 unsigned long parent = clk_get_rate(clk->parent);
192 unsigned long calc;
193 unsigned best = 256; /* bigger than any value */
194 unsigned div;
195 int ptr;
265 196
266 clkdiv0 = __raw_readl(S3C2443_CLKDIV0); 197 for (ptr = 0; ptr < ARRAY_SIZE(armdiv); ptr++) {
198 div = armdiv[ptr];
199 calc = parent / div;
200 if (calc <= rate && div < best)
201 best = div;
202 }
267 203
268 if (parent == &clk_armdiv) 204 return parent / best;
269 clkdiv0 &= ~S3C2443_CLKDIV0_DVS; 205}
270 else if (parent == &clk_h)
271 clkdiv0 |= S3C2443_CLKDIV0_DVS;
272 else
273 return -EINVAL;
274 206
275 __raw_writel(clkdiv0, S3C2443_CLKDIV0); 207static int s3c2443_armclk_setrate(struct clk *clk, unsigned long rate)
276 return 0; 208{
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 }
224
225 if (val >= 0) {
226 unsigned long clkcon0;
227
228 clkcon0 = __raw_readl(S3C2443_CLKDIV0);
229 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
230 clkcon0 |= val << S3C2443_CLKDIV0_ARMDIV_SHIFT;
231 __raw_writel(clkcon0, S3C2443_CLKDIV0);
232 }
233
234 return (val == -1) ? -EINVAL : 0;
277} 235}
278 236
279static struct clk clk_arm = { 237static struct clk clk_armdiv = {
280 .name = "armclk", 238 .name = "armdiv",
281 .id = -1, 239 .id = -1,
240 .parent = &clk_msysclk.clk,
282 .ops = &(struct clk_ops) { 241 .ops = &(struct clk_ops) {
283 .set_parent = s3c2443_setparent_armclk, 242 .round_rate = s3c2443_armclk_roundrate,
243 .set_rate = s3c2443_armclk_setrate,
284 }, 244 },
285}; 245};
286 246
287/* esysclk 247/* armclk
288 * 248 *
289 * this is sourced from either the EPLL or the EPLLref clock 249 * this is the clock fed into the ARM core itself, from armdiv or from hclk.
290*/ 250 */
291 251
292static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent) 252static struct clk *clk_arm_sources[] = {
293{ 253 [0] = &clk_armdiv,
294 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); 254 [1] = &clk_h,
255};
295 256
296 if (parent == &clk_epll) 257static struct clksrc_clk clk_arm = {
297 clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL; 258 .clk = {
298 else if (parent == &clk_epllref) 259 .name = "armclk",
299 clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL; 260 .id = -1,
300 else 261 },
301 return -EINVAL; 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};
302 268
303 __raw_writel(clksrc, S3C2443_CLKSRC); 269/* esysclk
304 clk->parent = parent; 270 *
271 * this is sourced from either the EPLL or the EPLLref clock
272*/
305 273
306 return 0; 274static struct clk *clk_sysclk_sources[] = {
307} 275 [0] = &clk_epllref.clk,
276 [1] = &clk_epll,
277};
308 278
309static struct clk clk_esysclk = { 279static struct clksrc_clk clk_esysclk = {
310 .name = "esysclk", 280 .clk = {
311 .parent = &clk_epll, 281 .name = "esysclk",
312 .id = -1, 282 .parent = &clk_epll,
313 .ops = &(struct clk_ops) { 283 .id = -1,
314 .set_parent = s3c2443_setparent_esysclk, 284 },
285 .sources = &(struct clksrc_sources) {
286 .sources = clk_sysclk_sources,
287 .nr_sources = ARRAY_SIZE(clk_sysclk_sources),
315 }, 288 },
289 .reg_src = { .reg = S3C2443_CLKSRC, .size = 1, .shift = 6 },
316}; 290};
317 291
318/* uartclk 292/* uartclk
@@ -320,87 +294,30 @@ static struct clk clk_esysclk = {
320 * UART baud-rate clock sourced from esysclk via a divisor 294 * UART baud-rate clock sourced from esysclk via a divisor
321*/ 295*/
322 296
323static unsigned long s3c2443_getrate_uart(struct clk *clk) 297static struct clksrc_clk clk_uart = {
324{ 298 .clk = {
325 unsigned long parent_rate = clk_get_rate(clk->parent); 299 .name = "uartclk",
326 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 300 .id = -1,
327 301 .parent = &clk_esysclk.clk,
328 div &= S3C2443_CLKDIV1_UARTDIV_MASK;
329 div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT;
330
331 return parent_rate / (div + 1);
332}
333
334
335static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate)
336{
337 unsigned long parent_rate = clk_get_rate(clk->parent);
338 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
339
340 rate = s3c2443_roundrate_clksrc16(clk, rate);
341 rate = parent_rate / rate;
342
343 clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK;
344 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT;
345
346 __raw_writel(clkdivn, S3C2443_CLKDIV1);
347 return 0;
348}
349
350static struct clk clk_uart = {
351 .name = "uartclk",
352 .id = -1,
353 .parent = &clk_esysclk,
354 .ops = &(struct clk_ops) {
355 .get_rate = s3c2443_getrate_uart,
356 .set_rate = s3c2443_setrate_uart,
357 .round_rate = s3c2443_roundrate_clksrc16,
358 }, 302 },
303 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 },
359}; 304};
360 305
306
361/* hsspi 307/* hsspi
362 * 308 *
363 * high-speed spi clock, sourced from esysclk 309 * high-speed spi clock, sourced from esysclk
364*/ 310*/
365 311
366static unsigned long s3c2443_getrate_hsspi(struct clk *clk) 312static struct clksrc_clk clk_hsspi = {
367{ 313 .clk = {
368 unsigned long parent_rate = clk_get_rate(clk->parent); 314 .name = "hsspi",
369 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 315 .id = -1,
370 316 .parent = &clk_esysclk.clk,
371 div &= S3C2443_CLKDIV1_HSSPIDIV_MASK; 317 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
372 div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT; 318 .enable = s3c2443_clkcon_enable_s,
373
374 return parent_rate / (div + 1);
375}
376
377
378static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate)
379{
380 unsigned long parent_rate = clk_get_rate(clk->parent);
381 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
382
383 rate = s3c2443_roundrate_clksrc4(clk, rate);
384 rate = parent_rate / rate;
385
386 clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK;
387 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT;
388
389 __raw_writel(clkdivn, S3C2443_CLKDIV1);
390 return 0;
391}
392
393static struct clk clk_hsspi = {
394 .name = "hsspi",
395 .id = -1,
396 .parent = &clk_esysclk,
397 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
398 .enable = s3c2443_clkcon_enable_s,
399 .ops = &(struct clk_ops) {
400 .get_rate = s3c2443_getrate_hsspi,
401 .set_rate = s3c2443_setrate_hsspi,
402 .round_rate = s3c2443_roundrate_clksrc4,
403 }, 319 },
320 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
404}; 321};
405 322
406/* usbhost 323/* usbhost
@@ -408,43 +325,15 @@ static struct clk clk_hsspi = {
408 * 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
409*/ 326*/
410 327
411static unsigned long s3c2443_getrate_usbhost(struct clk *clk) 328static struct clksrc_clk clk_usb_bus_host = {
412{ 329 .clk = {
413 unsigned long parent_rate = clk_get_rate(clk->parent); 330 .name = "usb-bus-host-parent",
414 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 331 .id = -1,
415 332 .parent = &clk_esysclk.clk,
416 div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK; 333 .ctrlbit = S3C2443_SCLKCON_USBHOST,
417 div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; 334 .enable = s3c2443_clkcon_enable_s,
418
419 return parent_rate / (div + 1);
420}
421
422static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate)
423{
424 unsigned long parent_rate = clk_get_rate(clk->parent);
425 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
426
427 rate = s3c2443_roundrate_clksrc4(clk, rate);
428 rate = parent_rate / rate;
429
430 clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK;
431 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT;
432
433 __raw_writel(clkdivn, S3C2443_CLKDIV1);
434 return 0;
435}
436
437static struct clk clk_usb_bus_host = {
438 .name = "usb-bus-host-parent",
439 .id = -1,
440 .parent = &clk_esysclk,
441 .ctrlbit = S3C2443_SCLKCON_USBHOST,
442 .enable = s3c2443_clkcon_enable_s,
443 .ops = &(struct clk_ops) {
444 .get_rate = s3c2443_getrate_usbhost,
445 .set_rate = s3c2443_setrate_usbhost,
446 .round_rate = s3c2443_roundrate_clksrc4,
447 }, 335 },
336 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 },
448}; 337};
449 338
450/* clk_hsmcc_div 339/* clk_hsmcc_div
@@ -454,41 +343,13 @@ static struct clk clk_usb_bus_host = {
454 * be fed to the hsmmc block 343 * be fed to the hsmmc block
455*/ 344*/
456 345
457static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk) 346static struct clksrc_clk clk_hsmmc_div = {
458{ 347 .clk = {
459 unsigned long parent_rate = clk_get_rate(clk->parent); 348 .name = "hsmmc-div",
460 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 349 .id = -1,
461 350 .parent = &clk_esysclk.clk,
462 div &= S3C2443_CLKDIV1_HSMMCDIV_MASK;
463 div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT;
464
465 return parent_rate / (div + 1);
466}
467
468static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate)
469{
470 unsigned long parent_rate = clk_get_rate(clk->parent);
471 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
472
473 rate = s3c2443_roundrate_clksrc4(clk, rate);
474 rate = parent_rate / rate;
475
476 clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK;
477 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT;
478
479 __raw_writel(clkdivn, S3C2443_CLKDIV1);
480 return 0;
481}
482
483static struct clk clk_hsmmc_div = {
484 .name = "hsmmc-div",
485 .id = -1,
486 .parent = &clk_esysclk,
487 .ops = &(struct clk_ops) {
488 .get_rate = s3c2443_getrate_hsmmc_div,
489 .set_rate = s3c2443_setrate_hsmmc_div,
490 .round_rate = s3c2443_roundrate_clksrc4,
491 }, 351 },
352 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 },
492}; 353};
493 354
494static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) 355static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
@@ -521,7 +382,7 @@ static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
521static struct clk clk_hsmmc = { 382static struct clk clk_hsmmc = {
522 .name = "hsmmc-if", 383 .name = "hsmmc-if",
523 .id = -1, 384 .id = -1,
524 .parent = &clk_hsmmc_div, 385 .parent = &clk_hsmmc_div.clk,
525 .enable = s3c2443_enable_hsmmc, 386 .enable = s3c2443_enable_hsmmc,
526 .ops = &(struct clk_ops) { 387 .ops = &(struct clk_ops) {
527 .set_parent = s3c2443_setparent_hsmmc, 388 .set_parent = s3c2443_setparent_hsmmc,
@@ -530,79 +391,46 @@ static struct clk clk_hsmmc = {
530 391
531/* i2s_eplldiv 392/* i2s_eplldiv
532 * 393 *
533 * 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)
534*/ 396*/
535 397
536static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk) 398static struct clksrc_clk clk_i2s_eplldiv = {
537{ 399 .clk = {
538 unsigned long parent_rate = clk_get_rate(clk->parent); 400 .name = "i2s-eplldiv",
539 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 401 .id = -1,
540 402 .parent = &clk_esysclk.clk,
541 div &= S3C2443_CLKDIV1_I2SDIV_MASK;
542 div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT;
543
544 return parent_rate / (div + 1);
545}
546
547static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate)
548{
549 unsigned long parent_rate = clk_get_rate(clk->parent);
550 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
551
552 rate = s3c2443_roundrate_clksrc16(clk, rate);
553 rate = parent_rate / rate;
554
555 clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK;
556 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT;
557
558 __raw_writel(clkdivn, S3C2443_CLKDIV1);
559 return 0;
560}
561
562static struct clk clk_i2s_eplldiv = {
563 .name = "i2s-eplldiv",
564 .id = -1,
565 .parent = &clk_esysclk,
566 .ops = &(struct clk_ops) {
567 .get_rate = s3c2443_getrate_i2s_eplldiv,
568 .set_rate = s3c2443_setrate_i2s_eplldiv,
569 .round_rate = s3c2443_roundrate_clksrc16,
570 }, 403 },
404 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, },
571}; 405};
572 406
573/* i2s-ref 407/* i2s-ref
574 * 408 *
575 * 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.
576*/ 412*/
577 413
578static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent) 414struct clk *clk_i2s_srclist[] = {
579{ 415 [0] = &clk_i2s_eplldiv.clk,
580 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); 416 [1] = &clk_i2s_ext,
581 417 [2] = &clk_epllref.clk,
582 clksrc &= ~S3C2443_CLKSRC_I2S_MASK; 418 [3] = &clk_epllref.clk,
583 419};
584 if (parent == &clk_epllref)
585 clksrc |= S3C2443_CLKSRC_I2S_EPLLREF;
586 else if (parent == &clk_i2s_ext)
587 clksrc |= S3C2443_CLKSRC_I2S_EXT;
588 else if (parent != &clk_i2s_eplldiv)
589 return -EINVAL;
590
591 clk->parent = parent;
592 __raw_writel(clksrc, S3C2443_CLKSRC);
593 420
594 return 0; 421static struct clksrc_clk clk_i2s = {
595} 422 .clk = {
423 .name = "i2s-if",
424 .id = -1,
425 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
426 .enable = s3c2443_clkcon_enable_s,
596 427
597static struct clk clk_i2s = {
598 .name = "i2s-if",
599 .id = -1,
600 .parent = &clk_i2s_eplldiv,
601 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
602 .enable = s3c2443_clkcon_enable_s,
603 .ops = &(struct clk_ops) {
604 .set_parent = s3c2443_setparent_i2s,
605 }, 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 },
606}; 434};
607 435
608/* cam-if 436/* cam-if
@@ -610,43 +438,15 @@ static struct clk clk_i2s = {
610 * camera interface bus-clock, divided down from esysclk 438 * camera interface bus-clock, divided down from esysclk
611*/ 439*/
612 440
613static unsigned long s3c2443_getrate_cam(struct clk *clk) 441static struct clksrc_clk clk_cam = {
614{ 442 .clk = {
615 unsigned long parent_rate = clk_get_rate(clk->parent); 443 .name = "camif-upll", /* same as 2440 name */
616 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 444 .id = -1,
617 445 .parent = &clk_esysclk.clk,
618 div &= S3C2443_CLKDIV1_CAMDIV_MASK; 446 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
619 div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT; 447 .enable = s3c2443_clkcon_enable_s,
620
621 return parent_rate / (div + 1);
622}
623
624static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate)
625{
626 unsigned long parent_rate = clk_get_rate(clk->parent);
627 unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1);
628
629 rate = s3c2443_roundrate_clksrc16(clk, rate);
630 rate = parent_rate / rate;
631
632 clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK;
633 clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT;
634
635 __raw_writel(clkdiv1, S3C2443_CLKDIV1);
636 return 0;
637}
638
639static struct clk clk_cam = {
640 .name = "camif-upll", /* same as 2440 name */
641 .id = -1,
642 .parent = &clk_esysclk,
643 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
644 .enable = s3c2443_clkcon_enable_s,
645 .ops = &(struct clk_ops) {
646 .get_rate = s3c2443_getrate_cam,
647 .set_rate = s3c2443_setrate_cam,
648 .round_rate = s3c2443_roundrate_clksrc16,
649 }, 448 },
449 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 },
650}; 450};
651 451
652/* display-if 452/* display-if
@@ -654,43 +454,15 @@ static struct clk clk_cam = {
654 * display interface clock, divided from esysclk 454 * display interface clock, divided from esysclk
655*/ 455*/
656 456
657static unsigned long s3c2443_getrate_display(struct clk *clk) 457static struct clksrc_clk clk_display = {
658{ 458 .clk = {
659 unsigned long parent_rate = clk_get_rate(clk->parent); 459 .name = "display-if",
660 unsigned long div = __raw_readl(S3C2443_CLKDIV1); 460 .id = -1,
661 461 .parent = &clk_esysclk.clk,
662 div &= S3C2443_CLKDIV1_DISPDIV_MASK; 462 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
663 div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT; 463 .enable = s3c2443_clkcon_enable_s,
664
665 return parent_rate / (div + 1);
666}
667
668static int s3c2443_setrate_display(struct clk *clk, unsigned long rate)
669{
670 unsigned long parent_rate = clk_get_rate(clk->parent);
671 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
672
673 rate = s3c2443_roundrate_clksrc256(clk, rate);
674 rate = parent_rate / rate;
675
676 clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK;
677 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT;
678
679 __raw_writel(clkdivn, S3C2443_CLKDIV1);
680 return 0;
681}
682
683static struct clk clk_display = {
684 .name = "display-if",
685 .id = -1,
686 .parent = &clk_esysclk,
687 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
688 .enable = s3c2443_clkcon_enable_s,
689 .ops = &(struct clk_ops) {
690 .get_rate = s3c2443_getrate_display,
691 .set_rate = s3c2443_setrate_display,
692 .round_rate = s3c2443_roundrate_clksrc256,
693 }, 464 },
465 .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 },
694}; 466};
695 467
696/* prediv 468/* prediv
@@ -712,7 +484,7 @@ static unsigned long s3c2443_prediv_getrate(struct clk *clk)
712static struct clk clk_prediv = { 484static struct clk clk_prediv = {
713 .name = "prediv", 485 .name = "prediv",
714 .id = -1, 486 .id = -1,
715 .parent = &clk_msysclk, 487 .parent = &clk_msysclk.clk,
716 .ops = &(struct clk_ops) { 488 .ops = &(struct clk_ops) {
717 .get_rate = s3c2443_prediv_getrate, 489 .get_rate = s3c2443_prediv_getrate,
718 }, 490 },
@@ -887,7 +659,7 @@ static struct clk init_clocks[] = {
887 }, { 659 }, {
888 .name = "usb-bus-host", 660 .name = "usb-bus-host",
889 .id = -1, 661 .id = -1,
890 .parent = &clk_usb_bus_host, 662 .parent = &clk_usb_bus_host.clk,
891 }, { 663 }, {
892 .name = "ac97", 664 .name = "ac97",
893 .id = -1, 665 .id = -1,
@@ -898,103 +670,26 @@ static struct clk init_clocks[] = {
898 670
899/* clocks to add where we need to check their parentage */ 671/* clocks to add where we need to check their parentage */
900 672
901/* s3c2443_clk_initparents 673static struct clksrc_clk __initdata *init_list[] = {
902 * 674 &clk_epllref, /* should be first */
903 * Initialise the parents for the clocks that we get at start-time 675 &clk_esysclk,
904*/ 676 &clk_msysclk,
905 677 &clk_arm,
906static int __init clk_init_set_parent(struct clk *clk, struct clk *parent) 678 &clk_i2s_eplldiv,
907{ 679 &clk_i2s,
908 printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name); 680 &clk_cam,
909 return clk_set_parent(clk, parent); 681 &clk_uart,
910} 682 &clk_display,
911 683 &clk_hsmmc_div,
912static void __init s3c2443_clk_initparents(void) 684 &clk_usb_bus_host,
913{
914 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
915 struct clk *parent;
916
917 switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) {
918 case S3C2443_CLKSRC_EPLLREF_EXTCLK:
919 parent = &clk_ext;
920 break;
921
922 case S3C2443_CLKSRC_EPLLREF_XTAL:
923 default:
924 parent = &clk_xtal;
925 break;
926
927 case S3C2443_CLKSRC_EPLLREF_MPLLREF:
928 case S3C2443_CLKSRC_EPLLREF_MPLLREF2:
929 parent = &clk_mpllref;
930 break;
931 }
932
933 clk_init_set_parent(&clk_epllref, parent);
934
935 switch (clksrc & S3C2443_CLKSRC_I2S_MASK) {
936 case S3C2443_CLKSRC_I2S_EXT:
937 parent = &clk_i2s_ext;
938 break;
939
940 case S3C2443_CLKSRC_I2S_EPLLDIV:
941 default:
942 parent = &clk_i2s_eplldiv;
943 break;
944
945 case S3C2443_CLKSRC_I2S_EPLLREF:
946 case S3C2443_CLKSRC_I2S_EPLLREF3:
947 parent = &clk_epllref;
948 }
949
950 clk_init_set_parent(&clk_i2s, &clk_epllref);
951
952 /* esysclk source */
953
954 parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ?
955 &clk_epll : &clk_epllref;
956
957 clk_init_set_parent(&clk_esysclk, parent);
958
959 /* msysclk source */
960
961 if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) {
962 parent = &clk_mpll;
963 } else {
964 parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ?
965 &clk_mdivclk : &clk_mpllref;
966 }
967
968 clk_init_set_parent(&clk_msysclk, parent);
969
970 /* arm */
971
972 if (__raw_readl(S3C2443_CLKDIV0) & S3C2443_CLKDIV0_DVS)
973 parent = &clk_h;
974 else
975 parent = &clk_armdiv;
976
977 clk_init_set_parent(&clk_arm, parent);
978}
979
980/* armdiv divisor table */
981
982static unsigned int armdiv[16] = {
983 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
984 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
985 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
986 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
987 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
988 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
989 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
990 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
991}; 685};
992 686
993static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0) 687static void __init s3c2443_clk_initparents(void)
994{ 688{
995 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; 689 int ptr;
996 690
997 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);
998} 693}
999 694
1000static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) 695static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
@@ -1006,15 +701,12 @@ static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
1006 701
1007/* clocks to add straight away */ 702/* clocks to add straight away */
1008 703
1009static struct clk *clks[] __initdata = { 704static struct clksrc_clk *clksrcs[] __initdata = {
1010 &clk_ext,
1011 &clk_epll,
1012 &clk_usb_bus_host, 705 &clk_usb_bus_host,
1013 &clk_usb_bus,
1014 &clk_esysclk,
1015 &clk_epllref, 706 &clk_epllref,
1016 &clk_mpllref, 707 &clk_esysclk,
1017 &clk_msysclk, 708 &clk_msysclk,
709 &clk_arm,
1018 &clk_uart, 710 &clk_uart,
1019 &clk_display, 711 &clk_display,
1020 &clk_cam, 712 &clk_cam,
@@ -1022,9 +714,15 @@ static struct clk *clks[] __initdata = {
1022 &clk_i2s, 714 &clk_i2s,
1023 &clk_hsspi, 715 &clk_hsspi,
1024 &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,
1025 &clk_hsmmc, 724 &clk_hsmmc,
1026 &clk_armdiv, 725 &clk_armdiv,
1027 &clk_arm,
1028 &clk_prediv, 726 &clk_prediv,
1029}; 727};
1030 728
@@ -1044,7 +742,7 @@ void __init_or_cpufreq s3c2443_setup_clocks(void)
1044 clk_put(xtal_clk); 742 clk_put(xtal_clk);
1045 743
1046 pll = s3c2443_get_mpll(mpllcon, xtal); 744 pll = s3c2443_get_mpll(mpllcon, xtal);
1047 clk_msysclk.rate = pll; 745 clk_msysclk.clk.rate = pll;
1048 746
1049 fclk = pll / s3c2443_fclk_div(clkdiv0); 747 fclk = pll / s3c2443_fclk_div(clkdiv0);
1050 hclk = s3c2443_prediv_getrate(&clk_prediv); 748 hclk = s3c2443_prediv_getrate(&clk_prediv);
@@ -1086,15 +784,18 @@ void __init s3c2443_init_clocks(int xtal)
1086 } 784 }
1087 } 785 }
1088 786
787 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
788 s3c_register_clksrc(clksrcs[ptr], 1);
789
1089 clk_epll.rate = s3c2443_get_epll(epllcon, xtal); 790 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
1090 clk_epll.parent = &clk_epllref; 791 clk_epll.parent = &clk_epllref.clk;
1091 clk_usb_bus.parent = &clk_usb_bus_host; 792 clk_usb_bus.parent = &clk_usb_bus_host.clk;
1092 793
1093 /* ensure usb bus clock is within correct rate of 48MHz */ 794 /* ensure usb bus clock is within correct rate of 48MHz */
1094 795
1095 if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) { 796 if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) {
1096 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); 797 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
1097 clk_set_rate(&clk_usb_bus_host, 48*1000*1000); 798 clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000);
1098 } 799 }
1099 800
1100 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",