]>
Commit | Line | Data |
---|---|---|
e4d06e39 BD |
1 | /* linux/arch/arm/mach-s3c2443/clock.c |
2 | * | |
3 | * Copyright (c) 2007 Simtec Electronics | |
4 | * Ben Dooks <[email protected]> | |
5 | * | |
6 | * S3C2443 Clock control support | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; either version 2 of the License, or | |
11 | * (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 | */ | |
22 | ||
23 | #include <linux/init.h> | |
24 | #include <linux/module.h> | |
25 | #include <linux/kernel.h> | |
26 | #include <linux/list.h> | |
27 | #include <linux/errno.h> | |
28 | #include <linux/err.h> | |
29 | #include <linux/sysdev.h> | |
30 | #include <linux/clk.h> | |
31 | #include <linux/mutex.h> | |
32 | #include <linux/delay.h> | |
33 | #include <linux/serial_core.h> | |
34 | ||
35 | #include <asm/mach/map.h> | |
36 | ||
37 | #include <asm/hardware.h> | |
38 | #include <asm/io.h> | |
39 | ||
40 | #include <asm/arch/regs-s3c2443-clock.h> | |
41 | ||
42 | #include <asm/plat-s3c24xx/s3c2443.h> | |
43 | #include <asm/plat-s3c24xx/clock.h> | |
44 | #include <asm/plat-s3c24xx/cpu.h> | |
45 | ||
46 | /* We currently have to assume that the system is running | |
47 | * from the XTPll input, and that all ***REFCLKs are being | |
48 | * fed from it, as we cannot read the state of OM[4] from | |
49 | * software. | |
50 | * | |
51 | * It would be possible for each board initialisation to | |
52 | * set the correct muxing at initialisation | |
53 | */ | |
54 | ||
55 | static int s3c2443_clkcon_enable_h(struct clk *clk, int enable) | |
56 | { | |
57 | unsigned int clocks = clk->ctrlbit; | |
58 | unsigned long clkcon; | |
59 | ||
60 | clkcon = __raw_readl(S3C2443_HCLKCON); | |
61 | ||
62 | if (enable) | |
63 | clkcon |= clocks; | |
64 | else | |
65 | clkcon &= ~clocks; | |
66 | ||
67 | __raw_writel(clkcon, S3C2443_HCLKCON); | |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
72 | static int s3c2443_clkcon_enable_p(struct clk *clk, int enable) | |
73 | { | |
74 | unsigned int clocks = clk->ctrlbit; | |
75 | unsigned long clkcon; | |
76 | ||
77 | clkcon = __raw_readl(S3C2443_PCLKCON); | |
78 | ||
79 | if (enable) | |
80 | clkcon |= clocks; | |
81 | else | |
82 | clkcon &= ~clocks; | |
83 | ||
29a7bcfd | 84 | __raw_writel(clkcon, S3C2443_PCLKCON); |
e4d06e39 BD |
85 | |
86 | return 0; | |
87 | } | |
88 | ||
89 | static int s3c2443_clkcon_enable_s(struct clk *clk, int enable) | |
90 | { | |
91 | unsigned int clocks = clk->ctrlbit; | |
92 | unsigned long clkcon; | |
93 | ||
94 | clkcon = __raw_readl(S3C2443_SCLKCON); | |
95 | ||
96 | if (enable) | |
97 | clkcon |= clocks; | |
98 | else | |
99 | clkcon &= ~clocks; | |
100 | ||
101 | __raw_writel(clkcon, S3C2443_SCLKCON); | |
102 | ||
103 | return 0; | |
104 | } | |
105 | ||
106 | static unsigned long s3c2443_roundrate_clksrc(struct clk *clk, | |
107 | unsigned long rate, | |
108 | unsigned int max) | |
109 | { | |
110 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
111 | int div; | |
112 | ||
113 | if (rate > parent_rate) | |
114 | return parent_rate; | |
115 | ||
116 | /* note, we remove the +/- 1 calculations as they cancel out */ | |
117 | ||
118 | div = (rate / parent_rate); | |
119 | ||
120 | if (div < 1) | |
121 | div = 1; | |
122 | else if (div > max) | |
123 | div = max; | |
124 | ||
125 | return parent_rate / div; | |
126 | } | |
127 | ||
128 | static unsigned long s3c2443_roundrate_clksrc4(struct clk *clk, | |
129 | unsigned long rate) | |
130 | { | |
131 | return s3c2443_roundrate_clksrc(clk, rate, 4); | |
132 | } | |
133 | ||
134 | static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk, | |
135 | unsigned long rate) | |
136 | { | |
137 | return s3c2443_roundrate_clksrc(clk, rate, 16); | |
138 | } | |
139 | ||
140 | static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk, | |
141 | unsigned long rate) | |
142 | { | |
143 | return s3c2443_roundrate_clksrc(clk, rate, 256); | |
144 | } | |
145 | ||
146 | /* clock selections */ | |
147 | ||
148 | /* CPU EXTCLK input */ | |
149 | static struct clk clk_ext = { | |
150 | .name = "ext", | |
151 | .id = -1, | |
152 | }; | |
153 | ||
154 | static struct clk clk_mpllref = { | |
155 | .name = "mpllref", | |
156 | .parent = &clk_xtal, | |
157 | .id = -1, | |
158 | }; | |
159 | ||
160 | #if 0 | |
161 | static struct clk clk_mpll = { | |
162 | .name = "mpll", | |
163 | .parent = &clk_mpllref, | |
164 | .id = -1, | |
165 | }; | |
166 | #endif | |
167 | ||
168 | static struct clk clk_epllref; | |
169 | ||
170 | static struct clk clk_epll = { | |
171 | .name = "epll", | |
172 | .parent = &clk_epllref, | |
173 | .id = -1, | |
174 | }; | |
175 | ||
176 | static struct clk clk_i2s_ext = { | |
177 | .name = "i2s-ext", | |
178 | .id = -1, | |
179 | }; | |
180 | ||
181 | static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent) | |
182 | { | |
183 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | |
184 | ||
185 | clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK; | |
186 | ||
187 | if (parent == &clk_xtal) | |
188 | clksrc |= S3C2443_CLKSRC_EPLLREF_XTAL; | |
189 | else if (parent == &clk_ext) | |
190 | clksrc |= S3C2443_CLKSRC_EPLLREF_EXTCLK; | |
191 | else if (parent != &clk_mpllref) | |
192 | return -EINVAL; | |
193 | ||
194 | __raw_writel(clksrc, S3C2443_CLKSRC); | |
195 | clk->parent = parent; | |
196 | ||
197 | return 0; | |
198 | } | |
199 | ||
200 | static struct clk clk_epllref = { | |
201 | .name = "epllref", | |
202 | .id = -1, | |
203 | .set_parent = s3c2443_setparent_epllref, | |
204 | }; | |
205 | ||
206 | static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) | |
207 | { | |
208 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
209 | unsigned long div = __raw_readl(S3C2443_CLKDIV0); | |
210 | ||
211 | div &= S3C2443_CLKDIV0_EXTDIV_MASK; | |
212 | div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */ | |
213 | ||
214 | return parent_rate / (div + 1); | |
215 | } | |
216 | ||
217 | static struct clk clk_mdivclk = { | |
218 | .name = "mdivclk", | |
219 | .parent = &clk_mpllref, | |
220 | .id = -1, | |
221 | .get_rate = s3c2443_getrate_mdivclk, | |
222 | }; | |
223 | ||
e4d06e39 BD |
224 | static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent) |
225 | { | |
226 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | |
227 | ||
228 | clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL | | |
229 | S3C2443_CLKSRC_EXTCLK_DIV); | |
230 | ||
231 | if (parent == &clk_mpll) | |
232 | clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL; | |
233 | else if (parent == &clk_mdivclk) | |
234 | clksrc |= S3C2443_CLKSRC_EXTCLK_DIV; | |
235 | else if (parent != &clk_mpllref) | |
236 | return -EINVAL; | |
237 | ||
238 | __raw_writel(clksrc, S3C2443_CLKSRC); | |
239 | clk->parent = parent; | |
240 | ||
241 | return 0; | |
242 | } | |
243 | ||
244 | static struct clk clk_msysclk = { | |
245 | .name = "msysclk", | |
246 | .parent = &clk_xtal, | |
247 | .id = -1, | |
248 | .set_parent = s3c2443_setparent_msysclk, | |
249 | }; | |
250 | ||
ba7622a1 BD |
251 | /* armdiv |
252 | * | |
253 | * this clock is sourced from msysclk and can have a number of | |
254 | * divider values applied to it to then be fed into armclk. | |
255 | */ | |
256 | ||
257 | static struct clk clk_armdiv = { | |
258 | .name = "armdiv", | |
259 | .id = -1, | |
260 | .parent = &clk_msysclk, | |
261 | }; | |
262 | ||
263 | /* armclk | |
264 | * | |
265 | * this is the clock fed into the ARM core itself, either from | |
266 | * armdiv or from hclk. | |
267 | */ | |
268 | ||
269 | static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent) | |
270 | { | |
271 | unsigned long clkdiv0; | |
272 | ||
273 | clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | |
274 | ||
275 | if (parent == &clk_armdiv) | |
276 | clkdiv0 &= ~S3C2443_CLKDIV0_DVS; | |
277 | else if (parent == &clk_h) | |
278 | clkdiv0 |= S3C2443_CLKDIV0_DVS; | |
279 | else | |
280 | return -EINVAL; | |
281 | ||
282 | __raw_writel(clkdiv0, S3C2443_CLKDIV0); | |
283 | return 0; | |
284 | } | |
285 | ||
286 | static struct clk clk_arm = { | |
287 | .name = "armclk", | |
288 | .id = -1, | |
289 | .set_parent = s3c2443_setparent_armclk, | |
290 | }; | |
e4d06e39 BD |
291 | |
292 | /* esysclk | |
293 | * | |
294 | * this is sourced from either the EPLL or the EPLLref clock | |
295 | */ | |
296 | ||
297 | static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent) | |
298 | { | |
299 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | |
300 | ||
301 | if (parent == &clk_epll) | |
302 | clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL; | |
303 | else if (parent == &clk_epllref) | |
304 | clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL; | |
305 | else | |
306 | return -EINVAL; | |
307 | ||
308 | __raw_writel(clksrc, S3C2443_CLKSRC); | |
309 | clk->parent = parent; | |
310 | ||
311 | return 0; | |
312 | } | |
313 | ||
314 | static struct clk clk_esysclk = { | |
315 | .name = "esysclk", | |
316 | .parent = &clk_epll, | |
317 | .id = -1, | |
318 | .set_parent = s3c2443_setparent_esysclk, | |
319 | }; | |
320 | ||
321 | /* uartclk | |
322 | * | |
323 | * UART baud-rate clock sourced from esysclk via a divisor | |
324 | */ | |
325 | ||
326 | static unsigned long s3c2443_getrate_uart(struct clk *clk) | |
327 | { | |
328 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
329 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | |
330 | ||
331 | div &= S3C2443_CLKDIV1_UARTDIV_MASK; | |
332 | div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT; | |
333 | ||
334 | return parent_rate / (div + 1); | |
335 | } | |
336 | ||
337 | ||
338 | static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate) | |
339 | { | |
340 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
341 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | |
342 | ||
343 | rate = s3c2443_roundrate_clksrc16(clk, rate); | |
344 | rate = parent_rate / rate; | |
345 | ||
346 | clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; | |
347 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; | |
348 | ||
349 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | |
350 | return 0; | |
351 | } | |
352 | ||
353 | static struct clk clk_uart = { | |
354 | .name = "uartclk", | |
355 | .id = -1, | |
356 | .parent = &clk_esysclk, | |
357 | .get_rate = s3c2443_getrate_uart, | |
358 | .set_rate = s3c2443_setrate_uart, | |
359 | .round_rate = s3c2443_roundrate_clksrc16, | |
360 | }; | |
361 | ||
362 | /* hsspi | |
363 | * | |
364 | * high-speed spi clock, sourced from esysclk | |
365 | */ | |
366 | ||
367 | static unsigned long s3c2443_getrate_hsspi(struct clk *clk) | |
368 | { | |
369 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
370 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | |
371 | ||
372 | div &= S3C2443_CLKDIV1_HSSPIDIV_MASK; | |
373 | div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT; | |
374 | ||
375 | return parent_rate / (div + 1); | |
376 | } | |
377 | ||
378 | ||
379 | static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate) | |
380 | { | |
381 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
382 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | |
383 | ||
384 | rate = s3c2443_roundrate_clksrc4(clk, rate); | |
385 | rate = parent_rate / rate; | |
386 | ||
387 | clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK; | |
388 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT; | |
389 | ||
390 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | |
391 | return 0; | |
392 | } | |
393 | ||
394 | static struct clk clk_hsspi = { | |
395 | .name = "hsspi", | |
396 | .id = -1, | |
397 | .parent = &clk_esysclk, | |
398 | .ctrlbit = S3C2443_SCLKCON_HSSPICLK, | |
399 | .enable = s3c2443_clkcon_enable_s, | |
400 | .get_rate = s3c2443_getrate_hsspi, | |
401 | .set_rate = s3c2443_setrate_hsspi, | |
402 | .round_rate = s3c2443_roundrate_clksrc4, | |
403 | }; | |
404 | ||
405 | /* usbhost | |
406 | * | |
407 | * usb host bus-clock, usually 48MHz to provide USB bus clock timing | |
408 | */ | |
409 | ||
410 | static unsigned long s3c2443_getrate_usbhost(struct clk *clk) | |
411 | { | |
412 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
413 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | |
414 | ||
415 | div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK; | |
416 | div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; | |
417 | ||
418 | return parent_rate / (div + 1); | |
419 | } | |
420 | ||
421 | static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate) | |
422 | { | |
423 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
424 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | |
425 | ||
426 | rate = s3c2443_roundrate_clksrc4(clk, rate); | |
427 | rate = parent_rate / rate; | |
428 | ||
429 | clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK; | |
430 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; | |
431 | ||
432 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | |
433 | return 0; | |
434 | } | |
435 | ||
0cc69daa | 436 | static struct clk clk_usb_bus_host = { |
e4d06e39 BD |
437 | .name = "usb-bus-host-parent", |
438 | .id = -1, | |
439 | .parent = &clk_esysclk, | |
440 | .ctrlbit = S3C2443_SCLKCON_USBHOST, | |
441 | .enable = s3c2443_clkcon_enable_s, | |
442 | .get_rate = s3c2443_getrate_usbhost, | |
443 | .set_rate = s3c2443_setrate_usbhost, | |
444 | .round_rate = s3c2443_roundrate_clksrc4, | |
445 | }; | |
446 | ||
447 | /* clk_hsmcc_div | |
448 | * | |
449 | * this clock is sourced from epll, and is fed through a divider, | |
450 | * to a mux controlled by sclkcon where either it or a extclk can | |
451 | * be fed to the hsmmc block | |
452 | */ | |
453 | ||
454 | static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk) | |
455 | { | |
456 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
457 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | |
458 | ||
459 | div &= S3C2443_CLKDIV1_HSMMCDIV_MASK; | |
460 | div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT; | |
461 | ||
462 | return parent_rate / (div + 1); | |
463 | } | |
464 | ||
465 | static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate) | |
466 | { | |
467 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
468 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | |
469 | ||
470 | rate = s3c2443_roundrate_clksrc4(clk, rate); | |
471 | rate = parent_rate / rate; | |
472 | ||
473 | clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK; | |
474 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT; | |
475 | ||
476 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | |
477 | return 0; | |
478 | } | |
479 | ||
480 | static struct clk clk_hsmmc_div = { | |
481 | .name = "hsmmc-div", | |
482 | .id = -1, | |
483 | .parent = &clk_esysclk, | |
484 | .get_rate = s3c2443_getrate_hsmmc_div, | |
485 | .set_rate = s3c2443_setrate_hsmmc_div, | |
486 | .round_rate = s3c2443_roundrate_clksrc4, | |
487 | }; | |
488 | ||
489 | static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) | |
490 | { | |
491 | unsigned long clksrc = __raw_readl(S3C2443_SCLKCON); | |
492 | ||
493 | clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT | | |
494 | S3C2443_SCLKCON_HSMMCCLK_EPLL); | |
495 | ||
496 | if (parent == &clk_epll) | |
497 | clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL; | |
498 | else if (parent == &clk_ext) | |
499 | clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT; | |
500 | else | |
501 | return -EINVAL; | |
502 | ||
503 | if (clk->usage > 0) { | |
504 | __raw_writel(clksrc, S3C2443_SCLKCON); | |
505 | } | |
506 | ||
507 | clk->parent = parent; | |
508 | return 0; | |
509 | } | |
510 | ||
511 | static int s3c2443_enable_hsmmc(struct clk *clk, int enable) | |
512 | { | |
513 | return s3c2443_setparent_hsmmc(clk, clk->parent); | |
514 | } | |
515 | ||
516 | static struct clk clk_hsmmc = { | |
517 | .name = "hsmmc-if", | |
518 | .id = -1, | |
519 | .parent = &clk_hsmmc_div, | |
520 | .enable = s3c2443_enable_hsmmc, | |
521 | .set_parent = s3c2443_setparent_hsmmc, | |
522 | }; | |
523 | ||
524 | /* i2s_eplldiv | |
525 | * | |
526 | * this clock is the output from the i2s divisor of esysclk | |
527 | */ | |
528 | ||
529 | static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk) | |
530 | { | |
531 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
532 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | |
533 | ||
534 | div &= S3C2443_CLKDIV1_I2SDIV_MASK; | |
535 | div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT; | |
536 | ||
537 | return parent_rate / (div + 1); | |
538 | } | |
539 | ||
540 | static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate) | |
541 | { | |
542 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
543 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | |
544 | ||
545 | rate = s3c2443_roundrate_clksrc16(clk, rate); | |
546 | rate = parent_rate / rate; | |
547 | ||
548 | clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK; | |
549 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT; | |
550 | ||
551 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | |
552 | return 0; | |
553 | } | |
554 | ||
555 | static struct clk clk_i2s_eplldiv = { | |
556 | .name = "i2s-eplldiv", | |
557 | .id = -1, | |
558 | .parent = &clk_esysclk, | |
559 | .get_rate = s3c2443_getrate_i2s_eplldiv, | |
560 | .set_rate = s3c2443_setrate_i2s_eplldiv, | |
561 | .round_rate = s3c2443_roundrate_clksrc16, | |
562 | }; | |
563 | ||
564 | /* i2s-ref | |
565 | * | |
566 | * i2s bus reference clock, selectable from external, esysclk or epllref | |
567 | */ | |
568 | ||
569 | static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent) | |
570 | { | |
571 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | |
572 | ||
573 | clksrc &= ~S3C2443_CLKSRC_I2S_MASK; | |
574 | ||
575 | if (parent == &clk_epllref) | |
576 | clksrc |= S3C2443_CLKSRC_I2S_EPLLREF; | |
577 | else if (parent == &clk_i2s_ext) | |
578 | clksrc |= S3C2443_CLKSRC_I2S_EXT; | |
579 | else if (parent != &clk_i2s_eplldiv) | |
580 | return -EINVAL; | |
581 | ||
582 | clk->parent = parent; | |
583 | __raw_writel(clksrc, S3C2443_CLKSRC); | |
584 | ||
585 | return 0; | |
586 | } | |
587 | ||
588 | static struct clk clk_i2s = { | |
589 | .name = "i2s-if", | |
590 | .id = -1, | |
591 | .parent = &clk_i2s_eplldiv, | |
592 | .ctrlbit = S3C2443_SCLKCON_I2SCLK, | |
593 | .enable = s3c2443_clkcon_enable_s, | |
594 | .set_parent = s3c2443_setparent_i2s, | |
595 | }; | |
596 | ||
597 | /* cam-if | |
598 | * | |
599 | * camera interface bus-clock, divided down from esysclk | |
600 | */ | |
601 | ||
602 | static unsigned long s3c2443_getrate_cam(struct clk *clk) | |
603 | { | |
604 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
605 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | |
606 | ||
607 | div &= S3C2443_CLKDIV1_CAMDIV_MASK; | |
608 | div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT; | |
609 | ||
610 | return parent_rate / (div + 1); | |
611 | } | |
612 | ||
613 | static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate) | |
614 | { | |
615 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
616 | unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1); | |
617 | ||
618 | rate = s3c2443_roundrate_clksrc16(clk, rate); | |
619 | rate = parent_rate / rate; | |
620 | ||
621 | clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK; | |
622 | clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT; | |
623 | ||
624 | __raw_writel(clkdiv1, S3C2443_CLKDIV1); | |
625 | return 0; | |
626 | } | |
627 | ||
628 | static struct clk clk_cam = { | |
629 | .name = "camif-upll", /* same as 2440 name */ | |
630 | .id = -1, | |
631 | .parent = &clk_esysclk, | |
632 | .ctrlbit = S3C2443_SCLKCON_CAMCLK, | |
633 | .enable = s3c2443_clkcon_enable_s, | |
634 | .get_rate = s3c2443_getrate_cam, | |
635 | .set_rate = s3c2443_setrate_cam, | |
636 | .round_rate = s3c2443_roundrate_clksrc16, | |
637 | }; | |
638 | ||
639 | /* display-if | |
640 | * | |
641 | * display interface clock, divided from esysclk | |
642 | */ | |
643 | ||
644 | static unsigned long s3c2443_getrate_display(struct clk *clk) | |
645 | { | |
646 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
647 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | |
648 | ||
649 | div &= S3C2443_CLKDIV1_DISPDIV_MASK; | |
650 | div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT; | |
651 | ||
652 | return parent_rate / (div + 1); | |
653 | } | |
654 | ||
655 | static int s3c2443_setrate_display(struct clk *clk, unsigned long rate) | |
656 | { | |
657 | unsigned long parent_rate = clk_get_rate(clk->parent); | |
658 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | |
659 | ||
660 | rate = s3c2443_roundrate_clksrc256(clk, rate); | |
661 | rate = parent_rate / rate; | |
662 | ||
663 | clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; | |
664 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; | |
665 | ||
666 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | |
667 | return 0; | |
668 | } | |
669 | ||
670 | static struct clk clk_display = { | |
671 | .name = "display-if", | |
672 | .id = -1, | |
673 | .parent = &clk_esysclk, | |
674 | .ctrlbit = S3C2443_SCLKCON_DISPCLK, | |
675 | .enable = s3c2443_clkcon_enable_s, | |
676 | .get_rate = s3c2443_getrate_display, | |
677 | .set_rate = s3c2443_setrate_display, | |
678 | .round_rate = s3c2443_roundrate_clksrc256, | |
679 | }; | |
680 | ||
2e16c27a BD |
681 | /* prediv |
682 | * | |
683 | * this divides the msysclk down to pass to h/p/etc. | |
684 | */ | |
685 | ||
686 | static unsigned long s3c2443_prediv_getrate(struct clk *clk) | |
687 | { | |
688 | unsigned long rate = clk_get_rate(clk->parent); | |
689 | unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | |
690 | ||
691 | clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK; | |
692 | clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT; | |
693 | ||
694 | return rate / (clkdiv0 + 1); | |
695 | } | |
696 | ||
697 | static struct clk clk_prediv = { | |
698 | .name = "prediv", | |
699 | .id = -1, | |
700 | .parent = &clk_msysclk, | |
701 | .get_rate = s3c2443_prediv_getrate, | |
702 | }; | |
703 | ||
e4d06e39 BD |
704 | /* standard clock definitions */ |
705 | ||
706 | static struct clk init_clocks_disable[] = { | |
707 | { | |
708 | .name = "nand", | |
709 | .id = -1, | |
710 | .parent = &clk_h, | |
711 | }, { | |
712 | .name = "sdi", | |
713 | .id = -1, | |
714 | .parent = &clk_p, | |
715 | .enable = s3c2443_clkcon_enable_p, | |
716 | .ctrlbit = S3C2443_PCLKCON_SDI, | |
717 | }, { | |
718 | .name = "adc", | |
719 | .id = -1, | |
720 | .parent = &clk_p, | |
721 | .enable = s3c2443_clkcon_enable_p, | |
722 | .ctrlbit = S3C2443_PCLKCON_ADC, | |
723 | }, { | |
724 | .name = "i2c", | |
725 | .id = -1, | |
726 | .parent = &clk_p, | |
727 | .enable = s3c2443_clkcon_enable_p, | |
728 | .ctrlbit = S3C2443_PCLKCON_IIC, | |
729 | }, { | |
730 | .name = "iis", | |
731 | .id = -1, | |
732 | .parent = &clk_p, | |
733 | .enable = s3c2443_clkcon_enable_p, | |
734 | .ctrlbit = S3C2443_PCLKCON_IIS, | |
735 | }, { | |
736 | .name = "spi", | |
737 | .id = 0, | |
738 | .parent = &clk_p, | |
739 | .enable = s3c2443_clkcon_enable_p, | |
740 | .ctrlbit = S3C2443_PCLKCON_SPI0, | |
741 | }, { | |
742 | .name = "spi", | |
743 | .id = 1, | |
744 | .parent = &clk_p, | |
745 | .enable = s3c2443_clkcon_enable_p, | |
746 | .ctrlbit = S3C2443_PCLKCON_SPI1, | |
747 | } | |
748 | }; | |
749 | ||
750 | static struct clk init_clocks[] = { | |
751 | { | |
752 | .name = "dma", | |
753 | .id = 0, | |
754 | .parent = &clk_h, | |
755 | .enable = s3c2443_clkcon_enable_h, | |
756 | .ctrlbit = S3C2443_HCLKCON_DMA0, | |
757 | }, { | |
758 | .name = "dma", | |
759 | .id = 1, | |
760 | .parent = &clk_h, | |
761 | .enable = s3c2443_clkcon_enable_h, | |
762 | .ctrlbit = S3C2443_HCLKCON_DMA1, | |
763 | }, { | |
764 | .name = "dma", | |
765 | .id = 2, | |
766 | .parent = &clk_h, | |
767 | .enable = s3c2443_clkcon_enable_h, | |
768 | .ctrlbit = S3C2443_HCLKCON_DMA2, | |
769 | }, { | |
770 | .name = "dma", | |
771 | .id = 3, | |
772 | .parent = &clk_h, | |
773 | .enable = s3c2443_clkcon_enable_h, | |
774 | .ctrlbit = S3C2443_HCLKCON_DMA3, | |
775 | }, { | |
776 | .name = "dma", | |
777 | .id = 4, | |
778 | .parent = &clk_h, | |
779 | .enable = s3c2443_clkcon_enable_h, | |
780 | .ctrlbit = S3C2443_HCLKCON_DMA4, | |
781 | }, { | |
782 | .name = "dma", | |
783 | .id = 5, | |
784 | .parent = &clk_h, | |
785 | .enable = s3c2443_clkcon_enable_h, | |
786 | .ctrlbit = S3C2443_HCLKCON_DMA5, | |
787 | }, { | |
788 | .name = "lcd", | |
789 | .id = -1, | |
790 | .parent = &clk_h, | |
791 | .enable = s3c2443_clkcon_enable_h, | |
792 | .ctrlbit = S3C2443_HCLKCON_LCDC, | |
793 | }, { | |
794 | .name = "gpio", | |
795 | .id = -1, | |
796 | .parent = &clk_p, | |
797 | .enable = s3c2443_clkcon_enable_p, | |
798 | .ctrlbit = S3C2443_PCLKCON_GPIO, | |
799 | }, { | |
800 | .name = "usb-host", | |
801 | .id = -1, | |
802 | .parent = &clk_h, | |
803 | .enable = s3c2443_clkcon_enable_h, | |
804 | .ctrlbit = S3C2443_HCLKCON_USBH, | |
805 | }, { | |
806 | .name = "usb-device", | |
807 | .id = -1, | |
808 | .parent = &clk_h, | |
809 | .enable = s3c2443_clkcon_enable_h, | |
810 | .ctrlbit = S3C2443_HCLKCON_USBD, | |
67364334 BD |
811 | }, { |
812 | .name = "hsmmc", | |
813 | .id = -1, | |
814 | .parent = &clk_h, | |
815 | .enable = s3c2443_clkcon_enable_h, | |
816 | .ctrlbit = S3C2443_HCLKCON_HSMMC, | |
817 | }, { | |
818 | .name = "cfc", | |
819 | .id = -1, | |
820 | .parent = &clk_h, | |
821 | .enable = s3c2443_clkcon_enable_h, | |
822 | .ctrlbit = S3C2443_HCLKCON_CFC, | |
67364334 BD |
823 | }, { |
824 | .name = "ssmc", | |
825 | .id = -1, | |
826 | .parent = &clk_h, | |
827 | .enable = s3c2443_clkcon_enable_h, | |
828 | .ctrlbit = S3C2443_HCLKCON_SSMC, | |
e4d06e39 BD |
829 | }, { |
830 | .name = "timers", | |
831 | .id = -1, | |
832 | .parent = &clk_p, | |
833 | .enable = s3c2443_clkcon_enable_p, | |
834 | .ctrlbit = S3C2443_PCLKCON_PWMT, | |
835 | }, { | |
836 | .name = "uart", | |
837 | .id = 0, | |
838 | .parent = &clk_p, | |
839 | .enable = s3c2443_clkcon_enable_p, | |
840 | .ctrlbit = S3C2443_PCLKCON_UART0, | |
841 | }, { | |
842 | .name = "uart", | |
843 | .id = 1, | |
844 | .parent = &clk_p, | |
845 | .enable = s3c2443_clkcon_enable_p, | |
846 | .ctrlbit = S3C2443_PCLKCON_UART1, | |
847 | }, { | |
848 | .name = "uart", | |
849 | .id = 2, | |
850 | .parent = &clk_p, | |
851 | .enable = s3c2443_clkcon_enable_p, | |
852 | .ctrlbit = S3C2443_PCLKCON_UART2, | |
853 | }, { | |
854 | .name = "uart", | |
855 | .id = 3, | |
856 | .parent = &clk_p, | |
857 | .enable = s3c2443_clkcon_enable_p, | |
858 | .ctrlbit = S3C2443_PCLKCON_UART3, | |
859 | }, { | |
860 | .name = "rtc", | |
861 | .id = -1, | |
862 | .parent = &clk_p, | |
863 | .enable = s3c2443_clkcon_enable_p, | |
864 | .ctrlbit = S3C2443_PCLKCON_RTC, | |
865 | }, { | |
866 | .name = "watchdog", | |
867 | .id = -1, | |
868 | .parent = &clk_p, | |
869 | .ctrlbit = S3C2443_PCLKCON_WDT, | |
870 | }, { | |
871 | .name = "usb-bus-host", | |
872 | .id = -1, | |
873 | .parent = &clk_usb_bus_host, | |
67364334 BD |
874 | }, { |
875 | .name = "ac97", | |
b8b6970b GG |
876 | .id = -1, |
877 | .parent = &clk_p, | |
878 | .ctrlbit = S3C2443_PCLKCON_AC97, | |
e4d06e39 BD |
879 | } |
880 | }; | |
881 | ||
882 | /* clocks to add where we need to check their parentage */ | |
883 | ||
884 | /* s3c2443_clk_initparents | |
885 | * | |
886 | * Initialise the parents for the clocks that we get at start-time | |
887 | */ | |
888 | ||
889 | static int __init clk_init_set_parent(struct clk *clk, struct clk *parent) | |
890 | { | |
891 | printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name); | |
892 | return clk_set_parent(clk, parent); | |
893 | } | |
894 | ||
895 | static void __init s3c2443_clk_initparents(void) | |
896 | { | |
897 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | |
898 | struct clk *parent; | |
899 | ||
900 | switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) { | |
901 | case S3C2443_CLKSRC_EPLLREF_EXTCLK: | |
902 | parent = &clk_ext; | |
903 | break; | |
904 | ||
905 | case S3C2443_CLKSRC_EPLLREF_XTAL: | |
906 | default: | |
907 | parent = &clk_xtal; | |
908 | break; | |
909 | ||
910 | case S3C2443_CLKSRC_EPLLREF_MPLLREF: | |
911 | case S3C2443_CLKSRC_EPLLREF_MPLLREF2: | |
912 | parent = &clk_mpllref; | |
913 | break; | |
914 | } | |
915 | ||
916 | clk_init_set_parent(&clk_epllref, parent); | |
917 | ||
918 | switch (clksrc & S3C2443_CLKSRC_I2S_MASK) { | |
919 | case S3C2443_CLKSRC_I2S_EXT: | |
920 | parent = &clk_i2s_ext; | |
921 | break; | |
922 | ||
923 | case S3C2443_CLKSRC_I2S_EPLLDIV: | |
924 | default: | |
925 | parent = &clk_i2s_eplldiv; | |
926 | break; | |
927 | ||
928 | case S3C2443_CLKSRC_I2S_EPLLREF: | |
929 | case S3C2443_CLKSRC_I2S_EPLLREF3: | |
930 | parent = &clk_epllref; | |
931 | } | |
932 | ||
933 | clk_init_set_parent(&clk_i2s, &clk_epllref); | |
934 | ||
935 | /* esysclk source */ | |
936 | ||
937 | parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ? | |
938 | &clk_epll : &clk_epllref; | |
939 | ||
940 | clk_init_set_parent(&clk_esysclk, parent); | |
941 | ||
942 | /* msysclk source */ | |
943 | ||
944 | if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) { | |
945 | parent = &clk_mpll; | |
946 | } else { | |
947 | parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ? | |
948 | &clk_mdivclk : &clk_mpllref; | |
949 | } | |
950 | ||
951 | clk_init_set_parent(&clk_msysclk, parent); | |
ba7622a1 BD |
952 | |
953 | /* arm */ | |
954 | ||
955 | if (__raw_readl(S3C2443_CLKDIV0) & S3C2443_CLKDIV0_DVS) | |
956 | parent = &clk_h; | |
957 | else | |
958 | parent = &clk_armdiv; | |
959 | ||
960 | clk_init_set_parent(&clk_arm, parent); | |
e4d06e39 BD |
961 | } |
962 | ||
963 | /* armdiv divisor table */ | |
964 | ||
965 | static unsigned int armdiv[16] = { | |
966 | [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1, | |
967 | [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2, | |
968 | [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3, | |
969 | [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4, | |
970 | [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6, | |
971 | [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8, | |
972 | [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12, | |
973 | [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16, | |
974 | }; | |
975 | ||
976 | static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0) | |
977 | { | |
978 | clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK; | |
979 | ||
980 | return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]; | |
981 | } | |
982 | ||
2e16c27a | 983 | static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) |
e4d06e39 | 984 | { |
2e16c27a | 985 | clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK; |
e4d06e39 BD |
986 | |
987 | return clkcon0 + 1; | |
988 | } | |
989 | ||
990 | /* clocks to add straight away */ | |
991 | ||
992 | static struct clk *clks[] __initdata = { | |
993 | &clk_ext, | |
994 | &clk_epll, | |
995 | &clk_usb_bus_host, | |
996 | &clk_usb_bus, | |
997 | &clk_esysclk, | |
998 | &clk_epllref, | |
999 | &clk_mpllref, | |
1000 | &clk_msysclk, | |
1001 | &clk_uart, | |
1002 | &clk_display, | |
1003 | &clk_cam, | |
1004 | &clk_i2s_eplldiv, | |
1005 | &clk_i2s, | |
1006 | &clk_hsspi, | |
1007 | &clk_hsmmc_div, | |
1008 | &clk_hsmmc, | |
ba7622a1 BD |
1009 | &clk_armdiv, |
1010 | &clk_arm, | |
2e16c27a | 1011 | &clk_prediv, |
e4d06e39 BD |
1012 | }; |
1013 | ||
1014 | void __init s3c2443_init_clocks(int xtal) | |
1015 | { | |
1016 | unsigned long epllcon = __raw_readl(S3C2443_EPLLCON); | |
1017 | unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON); | |
1018 | unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0); | |
1019 | unsigned long pll; | |
1020 | unsigned long fclk; | |
1021 | unsigned long hclk; | |
1022 | unsigned long pclk; | |
1023 | struct clk *clkp; | |
1024 | int ret; | |
1025 | int ptr; | |
1026 | ||
2e16c27a BD |
1027 | /* s3c2443 parents h and p clocks from prediv */ |
1028 | clk_h.parent = &clk_prediv; | |
1029 | clk_p.parent = &clk_prediv; | |
1030 | ||
e4d06e39 | 1031 | pll = s3c2443_get_mpll(mpllcon, xtal); |
2e16c27a | 1032 | clk_msysclk.rate = pll; |
e4d06e39 BD |
1033 | |
1034 | fclk = pll / s3c2443_fclk_div(clkdiv0); | |
2e16c27a BD |
1035 | hclk = s3c2443_prediv_getrate(&clk_prediv); |
1036 | hclk = hclk / s3c2443_get_hdiv(clkdiv0); | |
e4d06e39 BD |
1037 | hclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_HCLK) ? 2 : 1); |
1038 | pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1); | |
1039 | ||
1040 | s3c24xx_setup_clocks(xtal, fclk, hclk, pclk); | |
1041 | ||
1042 | printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n", | |
1043 | (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on", | |
1044 | print_mhz(pll), print_mhz(fclk), | |
1045 | print_mhz(hclk), print_mhz(pclk)); | |
1046 | ||
1047 | s3c2443_clk_initparents(); | |
1048 | ||
1049 | for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { | |
1050 | clkp = clks[ptr]; | |
1051 | ||
1052 | ret = s3c24xx_register_clock(clkp); | |
1053 | if (ret < 0) { | |
1054 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | |
1055 | clkp->name, ret); | |
1056 | } | |
1057 | } | |
1058 | ||
1059 | clk_epll.rate = s3c2443_get_epll(epllcon, xtal); | |
1060 | ||
1061 | clk_usb_bus.parent = &clk_usb_bus_host; | |
1062 | ||
1063 | /* ensure usb bus clock is within correct rate of 48MHz */ | |
1064 | ||
1065 | if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) { | |
1066 | printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); | |
1067 | clk_set_rate(&clk_usb_bus_host, 48*1000*1000); | |
1068 | } | |
1069 | ||
1070 | printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", | |
1071 | (epllcon & S3C2443_PLLCON_OFF) ? "off":"on", | |
1072 | print_mhz(clk_get_rate(&clk_epll)), | |
1073 | print_mhz(clk_get_rate(&clk_usb_bus))); | |
1074 | ||
1075 | /* register clocks from clock array */ | |
1076 | ||
1077 | clkp = 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 | ||
1086 | /* We must be careful disabling the clocks we are not intending to | |
3a4fa0a2 | 1087 | * be using at boot time, as subsystems such as the LCD which do |
e4d06e39 BD |
1088 | * their own DMA requests to the bus can cause the system to lockup |
1089 | * if they where in the middle of requesting bus access. | |
1090 | * | |
1091 | * Disabling the LCD clock if the LCD is active is very dangerous, | |
1092 | * and therefore the bootloader should be careful to not enable | |
1093 | * the LCD clock if it is not needed. | |
1094 | */ | |
1095 | ||
1096 | /* install (and disable) the clocks we do not need immediately */ | |
1097 | ||
1098 | clkp = init_clocks_disable; | |
1099 | for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { | |
1100 | ||
1101 | ret = s3c24xx_register_clock(clkp); | |
1102 | if (ret < 0) { | |
1103 | printk(KERN_ERR "Failed to register clock %s (%d)\n", | |
1104 | clkp->name, ret); | |
1105 | } | |
1106 | ||
1107 | (clkp->enable)(clkp, 0); | |
1108 | } | |
1109 | } |