blob: 91db4f54bb3328be383b6c9e796ee5248585490e [file] [log] [blame]
Ben Dookse4d06e32007-02-16 12:12:31 +01001/* linux/arch/arm/mach-s3c2443/clock.c
2 *
3 * Copyright (c) 2007 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
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>
Ben Dookse4d06e32007-02-16 12:12:31 +010032#include <linux/serial_core.h>
Russell Kingfced80c2008-09-06 12:10:45 +010033#include <linux/io.h>
Ben Dookse4d06e32007-02-16 12:12:31 +010034
35#include <asm/mach/map.h>
36
Russell Kinga09e64f2008-08-05 16:14:15 +010037#include <mach/hardware.h>
Ben Dookse4d06e32007-02-16 12:12:31 +010038
Russell Kinga09e64f2008-08-05 16:14:15 +010039#include <mach/regs-s3c2443-clock.h>
Ben Dookse4d06e32007-02-16 12:12:31 +010040
Ben Dookse4253822008-10-21 14:06:38 +010041#include <plat/cpu-freq.h>
42
Ben Dooksa2b7ba92008-10-07 22:26:09 +010043#include <plat/s3c2443.h>
Ben Dooksd5120ae2008-10-07 23:09:51 +010044#include <plat/clock.h>
Ben Dooksa2b7ba92008-10-07 22:26:09 +010045#include <plat/cpu.h>
Ben Dookse4d06e32007-02-16 12:12:31 +010046
47/* We currently have to assume that the system is running
48 * from the XTPll input, and that all ***REFCLKs are being
49 * fed from it, as we cannot read the state of OM[4] from
50 * software.
51 *
52 * It would be possible for each board initialisation to
53 * set the correct muxing at initialisation
54*/
55
56static int s3c2443_clkcon_enable_h(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
Ben Dooks29a7bcf2008-07-07 18:12:38 +010085 __raw_writel(clkcon, S3C2443_PCLKCON);
Ben Dookse4d06e32007-02-16 12:12:31 +010086
87 return 0;
88}
89
90static int s3c2443_clkcon_enable_s(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{
132 return s3c2443_roundrate_clksrc(clk, rate, 4);
133}
134
135static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk,
136 unsigned long rate)
137{
138 return s3c2443_roundrate_clksrc(clk, rate, 16);
139}
140
141static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk,
142 unsigned long rate)
143{
144 return s3c2443_roundrate_clksrc(clk, rate, 256);
145}
146
147/* clock selections */
148
Ben Dookse4d06e32007-02-16 12:12:31 +0100149static struct clk clk_mpllref = {
150 .name = "mpllref",
151 .parent = &clk_xtal,
152 .id = -1,
153};
154
155#if 0
156static struct clk clk_mpll = {
157 .name = "mpll",
158 .parent = &clk_mpllref,
159 .id = -1,
160};
161#endif
162
Ben Dookse4d06e32007-02-16 12:12:31 +0100163static struct clk clk_i2s_ext = {
164 .name = "i2s-ext",
165 .id = -1,
166};
167
168static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent)
169{
170 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
171
172 clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK;
173
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
187static struct clk clk_epllref = {
188 .name = "epllref",
189 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000190 .ops = &(struct clk_ops) {
191 .set_parent = s3c2443_setparent_epllref,
192 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100193};
194
195static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
196{
197 unsigned long parent_rate = clk_get_rate(clk->parent);
198 unsigned long div = __raw_readl(S3C2443_CLKDIV0);
199
200 div &= S3C2443_CLKDIV0_EXTDIV_MASK;
201 div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */
202
203 return parent_rate / (div + 1);
204}
205
206static struct clk clk_mdivclk = {
207 .name = "mdivclk",
208 .parent = &clk_mpllref,
209 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000210 .ops = &(struct clk_ops) {
211 .get_rate = s3c2443_getrate_mdivclk,
212 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100213};
214
Ben Dookse4d06e32007-02-16 12:12:31 +0100215static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent)
216{
217 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
218
219 clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL |
220 S3C2443_CLKSRC_EXTCLK_DIV);
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
235static struct clk clk_msysclk = {
236 .name = "msysclk",
237 .parent = &clk_xtal,
238 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000239 .ops = &(struct clk_ops) {
240 .set_parent = s3c2443_setparent_msysclk,
241 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100242};
243
Ben Dooksba7622a2008-07-07 18:12:39 +0100244/* armdiv
245 *
246 * this clock is sourced from msysclk and can have a number of
247 * divider values applied to it to then be fed into armclk.
248*/
249
250static struct clk clk_armdiv = {
251 .name = "armdiv",
252 .id = -1,
253 .parent = &clk_msysclk,
254};
255
256/* armclk
257 *
258 * this is the clock fed into the ARM core itself, either from
259 * armdiv or from hclk.
260 */
261
262static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent)
263{
264 unsigned long clkdiv0;
265
266 clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
267
268 if (parent == &clk_armdiv)
269 clkdiv0 &= ~S3C2443_CLKDIV0_DVS;
270 else if (parent == &clk_h)
271 clkdiv0 |= S3C2443_CLKDIV0_DVS;
272 else
273 return -EINVAL;
274
275 __raw_writel(clkdiv0, S3C2443_CLKDIV0);
276 return 0;
277}
278
279static struct clk clk_arm = {
280 .name = "armclk",
281 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000282 .ops = &(struct clk_ops) {
283 .set_parent = s3c2443_setparent_armclk,
284 },
Ben Dooksba7622a2008-07-07 18:12:39 +0100285};
Ben Dookse4d06e32007-02-16 12:12:31 +0100286
287/* esysclk
288 *
289 * this is sourced from either the EPLL or the EPLLref clock
290*/
291
292static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent)
293{
294 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
295
296 if (parent == &clk_epll)
297 clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL;
298 else if (parent == &clk_epllref)
299 clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL;
300 else
301 return -EINVAL;
302
303 __raw_writel(clksrc, S3C2443_CLKSRC);
304 clk->parent = parent;
305
306 return 0;
307}
308
309static struct clk clk_esysclk = {
310 .name = "esysclk",
311 .parent = &clk_epll,
312 .id = -1,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000313 .ops = &(struct clk_ops) {
314 .set_parent = s3c2443_setparent_esysclk,
315 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100316};
317
318/* uartclk
319 *
320 * UART baud-rate clock sourced from esysclk via a divisor
321*/
322
323static unsigned long s3c2443_getrate_uart(struct clk *clk)
324{
325 unsigned long parent_rate = clk_get_rate(clk->parent);
326 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
327
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,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000354 .ops = &(struct clk_ops) {
355 .get_rate = s3c2443_getrate_uart,
356 .set_rate = s3c2443_setrate_uart,
357 .round_rate = s3c2443_roundrate_clksrc16,
358 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100359};
360
361/* hsspi
362 *
363 * high-speed spi clock, sourced from esysclk
364*/
365
366static unsigned long s3c2443_getrate_hsspi(struct clk *clk)
367{
368 unsigned long parent_rate = clk_get_rate(clk->parent);
369 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
370
371 div &= S3C2443_CLKDIV1_HSSPIDIV_MASK;
372 div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT;
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,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000399 .ops = &(struct clk_ops) {
400 .get_rate = s3c2443_getrate_hsspi,
401 .set_rate = s3c2443_setrate_hsspi,
402 .round_rate = s3c2443_roundrate_clksrc4,
403 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100404};
405
406/* usbhost
407 *
408 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
409*/
410
411static unsigned long s3c2443_getrate_usbhost(struct clk *clk)
412{
413 unsigned long parent_rate = clk_get_rate(clk->parent);
414 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
415
416 div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK;
417 div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT;
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
Ben Dooks0cc69da2007-05-28 18:55:43 +0100437static struct clk clk_usb_bus_host = {
Ben Dookse4d06e32007-02-16 12:12:31 +0100438 .name = "usb-bus-host-parent",
439 .id = -1,
440 .parent = &clk_esysclk,
441 .ctrlbit = S3C2443_SCLKCON_USBHOST,
442 .enable = s3c2443_clkcon_enable_s,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000443 .ops = &(struct clk_ops) {
444 .get_rate = s3c2443_getrate_usbhost,
445 .set_rate = s3c2443_setrate_usbhost,
446 .round_rate = s3c2443_roundrate_clksrc4,
447 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100448};
449
450/* clk_hsmcc_div
451 *
452 * this clock is sourced from epll, and is fed through a divider,
453 * to a mux controlled by sclkcon where either it or a extclk can
454 * be fed to the hsmmc block
455*/
456
457static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk)
458{
459 unsigned long parent_rate = clk_get_rate(clk->parent);
460 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
461
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,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000487 .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 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100492};
493
494static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
495{
496 unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
497
498 clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
499 S3C2443_SCLKCON_HSMMCCLK_EPLL);
500
501 if (parent == &clk_epll)
502 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
503 else if (parent == &clk_ext)
504 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
505 else
506 return -EINVAL;
507
508 if (clk->usage > 0) {
509 __raw_writel(clksrc, S3C2443_SCLKCON);
510 }
511
512 clk->parent = parent;
513 return 0;
514}
515
516static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
517{
518 return s3c2443_setparent_hsmmc(clk, clk->parent);
519}
520
521static struct clk clk_hsmmc = {
522 .name = "hsmmc-if",
523 .id = -1,
524 .parent = &clk_hsmmc_div,
525 .enable = s3c2443_enable_hsmmc,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000526 .ops = &(struct clk_ops) {
527 .set_parent = s3c2443_setparent_hsmmc,
528 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100529};
530
531/* i2s_eplldiv
532 *
533 * this clock is the output from the i2s divisor of esysclk
534*/
535
536static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk)
537{
538 unsigned long parent_rate = clk_get_rate(clk->parent);
539 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
540
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,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000566 .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 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100571};
572
573/* i2s-ref
574 *
575 * i2s bus reference clock, selectable from external, esysclk or epllref
576*/
577
578static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent)
579{
580 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
581
582 clksrc &= ~S3C2443_CLKSRC_I2S_MASK;
583
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
594 return 0;
595}
596
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,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000603 .ops = &(struct clk_ops) {
604 .set_parent = s3c2443_setparent_i2s,
605 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100606};
607
608/* cam-if
609 *
610 * camera interface bus-clock, divided down from esysclk
611*/
612
613static unsigned long s3c2443_getrate_cam(struct clk *clk)
614{
615 unsigned long parent_rate = clk_get_rate(clk->parent);
616 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
617
618 div &= S3C2443_CLKDIV1_CAMDIV_MASK;
619 div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT;
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,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000645 .ops = &(struct clk_ops) {
646 .get_rate = s3c2443_getrate_cam,
647 .set_rate = s3c2443_setrate_cam,
648 .round_rate = s3c2443_roundrate_clksrc16,
649 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100650};
651
652/* display-if
653 *
654 * display interface clock, divided from esysclk
655*/
656
657static unsigned long s3c2443_getrate_display(struct clk *clk)
658{
659 unsigned long parent_rate = clk_get_rate(clk->parent);
660 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
661
662 div &= S3C2443_CLKDIV1_DISPDIV_MASK;
663 div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT;
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,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000689 .ops = &(struct clk_ops) {
690 .get_rate = s3c2443_getrate_display,
691 .set_rate = s3c2443_setrate_display,
692 .round_rate = s3c2443_roundrate_clksrc256,
693 },
Ben Dookse4d06e32007-02-16 12:12:31 +0100694};
695
Ben Dooks2e16c272008-07-07 18:12:40 +0100696/* prediv
697 *
698 * this divides the msysclk down to pass to h/p/etc.
699 */
700
701static unsigned long s3c2443_prediv_getrate(struct clk *clk)
702{
703 unsigned long rate = clk_get_rate(clk->parent);
704 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
705
706 clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
707 clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
708
709 return rate / (clkdiv0 + 1);
710}
711
712static struct clk clk_prediv = {
713 .name = "prediv",
714 .id = -1,
715 .parent = &clk_msysclk,
Ben Dooksb3bf41b2009-12-01 01:24:37 +0000716 .ops = &(struct clk_ops) {
717 .get_rate = s3c2443_prediv_getrate,
718 },
Ben Dooks2e16c272008-07-07 18:12:40 +0100719};
720
Ben Dookse4d06e32007-02-16 12:12:31 +0100721/* standard clock definitions */
722
723static struct clk init_clocks_disable[] = {
724 {
725 .name = "nand",
726 .id = -1,
727 .parent = &clk_h,
728 }, {
729 .name = "sdi",
730 .id = -1,
731 .parent = &clk_p,
732 .enable = s3c2443_clkcon_enable_p,
733 .ctrlbit = S3C2443_PCLKCON_SDI,
734 }, {
735 .name = "adc",
736 .id = -1,
737 .parent = &clk_p,
738 .enable = s3c2443_clkcon_enable_p,
739 .ctrlbit = S3C2443_PCLKCON_ADC,
740 }, {
741 .name = "i2c",
742 .id = -1,
743 .parent = &clk_p,
744 .enable = s3c2443_clkcon_enable_p,
745 .ctrlbit = S3C2443_PCLKCON_IIC,
746 }, {
747 .name = "iis",
748 .id = -1,
749 .parent = &clk_p,
750 .enable = s3c2443_clkcon_enable_p,
751 .ctrlbit = S3C2443_PCLKCON_IIS,
752 }, {
753 .name = "spi",
754 .id = 0,
755 .parent = &clk_p,
756 .enable = s3c2443_clkcon_enable_p,
757 .ctrlbit = S3C2443_PCLKCON_SPI0,
758 }, {
759 .name = "spi",
760 .id = 1,
761 .parent = &clk_p,
762 .enable = s3c2443_clkcon_enable_p,
763 .ctrlbit = S3C2443_PCLKCON_SPI1,
764 }
765};
766
767static struct clk init_clocks[] = {
768 {
769 .name = "dma",
770 .id = 0,
771 .parent = &clk_h,
772 .enable = s3c2443_clkcon_enable_h,
773 .ctrlbit = S3C2443_HCLKCON_DMA0,
774 }, {
775 .name = "dma",
776 .id = 1,
777 .parent = &clk_h,
778 .enable = s3c2443_clkcon_enable_h,
779 .ctrlbit = S3C2443_HCLKCON_DMA1,
780 }, {
781 .name = "dma",
782 .id = 2,
783 .parent = &clk_h,
784 .enable = s3c2443_clkcon_enable_h,
785 .ctrlbit = S3C2443_HCLKCON_DMA2,
786 }, {
787 .name = "dma",
788 .id = 3,
789 .parent = &clk_h,
790 .enable = s3c2443_clkcon_enable_h,
791 .ctrlbit = S3C2443_HCLKCON_DMA3,
792 }, {
793 .name = "dma",
794 .id = 4,
795 .parent = &clk_h,
796 .enable = s3c2443_clkcon_enable_h,
797 .ctrlbit = S3C2443_HCLKCON_DMA4,
798 }, {
799 .name = "dma",
800 .id = 5,
801 .parent = &clk_h,
802 .enable = s3c2443_clkcon_enable_h,
803 .ctrlbit = S3C2443_HCLKCON_DMA5,
804 }, {
805 .name = "lcd",
806 .id = -1,
807 .parent = &clk_h,
808 .enable = s3c2443_clkcon_enable_h,
809 .ctrlbit = S3C2443_HCLKCON_LCDC,
810 }, {
811 .name = "gpio",
812 .id = -1,
813 .parent = &clk_p,
814 .enable = s3c2443_clkcon_enable_p,
815 .ctrlbit = S3C2443_PCLKCON_GPIO,
816 }, {
817 .name = "usb-host",
818 .id = -1,
819 .parent = &clk_h,
820 .enable = s3c2443_clkcon_enable_h,
821 .ctrlbit = S3C2443_HCLKCON_USBH,
822 }, {
823 .name = "usb-device",
824 .id = -1,
825 .parent = &clk_h,
826 .enable = s3c2443_clkcon_enable_h,
827 .ctrlbit = S3C2443_HCLKCON_USBD,
828 }, {
Ben Dooks67364332007-05-20 17:17:32 +0100829 .name = "hsmmc",
830 .id = -1,
831 .parent = &clk_h,
832 .enable = s3c2443_clkcon_enable_h,
833 .ctrlbit = S3C2443_HCLKCON_HSMMC,
834 }, {
835 .name = "cfc",
836 .id = -1,
837 .parent = &clk_h,
838 .enable = s3c2443_clkcon_enable_h,
839 .ctrlbit = S3C2443_HCLKCON_CFC,
Ben Dooks67364332007-05-20 17:17:32 +0100840 }, {
841 .name = "ssmc",
842 .id = -1,
843 .parent = &clk_h,
844 .enable = s3c2443_clkcon_enable_h,
845 .ctrlbit = S3C2443_HCLKCON_SSMC,
846 }, {
Ben Dookse4d06e32007-02-16 12:12:31 +0100847 .name = "timers",
848 .id = -1,
849 .parent = &clk_p,
850 .enable = s3c2443_clkcon_enable_p,
851 .ctrlbit = S3C2443_PCLKCON_PWMT,
852 }, {
853 .name = "uart",
854 .id = 0,
855 .parent = &clk_p,
856 .enable = s3c2443_clkcon_enable_p,
857 .ctrlbit = S3C2443_PCLKCON_UART0,
858 }, {
859 .name = "uart",
860 .id = 1,
861 .parent = &clk_p,
862 .enable = s3c2443_clkcon_enable_p,
863 .ctrlbit = S3C2443_PCLKCON_UART1,
864 }, {
865 .name = "uart",
866 .id = 2,
867 .parent = &clk_p,
868 .enable = s3c2443_clkcon_enable_p,
869 .ctrlbit = S3C2443_PCLKCON_UART2,
870 }, {
871 .name = "uart",
872 .id = 3,
873 .parent = &clk_p,
874 .enable = s3c2443_clkcon_enable_p,
875 .ctrlbit = S3C2443_PCLKCON_UART3,
876 }, {
877 .name = "rtc",
878 .id = -1,
879 .parent = &clk_p,
880 .enable = s3c2443_clkcon_enable_p,
881 .ctrlbit = S3C2443_PCLKCON_RTC,
882 }, {
883 .name = "watchdog",
884 .id = -1,
885 .parent = &clk_p,
886 .ctrlbit = S3C2443_PCLKCON_WDT,
887 }, {
888 .name = "usb-bus-host",
889 .id = -1,
890 .parent = &clk_usb_bus_host,
Ben Dooks67364332007-05-20 17:17:32 +0100891 }, {
892 .name = "ac97",
Graeme Gregoryb8b69702007-05-09 15:55:24 +0100893 .id = -1,
894 .parent = &clk_p,
895 .ctrlbit = S3C2443_PCLKCON_AC97,
Ben Dookse4d06e32007-02-16 12:12:31 +0100896 }
897};
898
899/* clocks to add where we need to check their parentage */
900
901/* s3c2443_clk_initparents
902 *
903 * Initialise the parents for the clocks that we get at start-time
904*/
905
906static int __init clk_init_set_parent(struct clk *clk, struct clk *parent)
907{
908 printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name);
909 return clk_set_parent(clk, parent);
910}
911
912static void __init s3c2443_clk_initparents(void)
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);
Ben Dooksba7622a2008-07-07 18:12:39 +0100969
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);
Ben Dookse4d06e32007-02-16 12:12:31 +0100978}
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};
992
993static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
994{
995 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
996
997 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
998}
999
Ben Dooks2e16c272008-07-07 18:12:40 +01001000static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
Ben Dookse4d06e32007-02-16 12:12:31 +01001001{
Ben Dooks2e16c272008-07-07 18:12:40 +01001002 clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
Ben Dookse4d06e32007-02-16 12:12:31 +01001003
1004 return clkcon0 + 1;
1005}
1006
1007/* clocks to add straight away */
1008
1009static struct clk *clks[] __initdata = {
1010 &clk_ext,
1011 &clk_epll,
1012 &clk_usb_bus_host,
1013 &clk_usb_bus,
1014 &clk_esysclk,
1015 &clk_epllref,
1016 &clk_mpllref,
1017 &clk_msysclk,
1018 &clk_uart,
1019 &clk_display,
1020 &clk_cam,
1021 &clk_i2s_eplldiv,
1022 &clk_i2s,
1023 &clk_hsspi,
1024 &clk_hsmmc_div,
1025 &clk_hsmmc,
Ben Dooksba7622a2008-07-07 18:12:39 +01001026 &clk_armdiv,
1027 &clk_arm,
Ben Dooks2e16c272008-07-07 18:12:40 +01001028 &clk_prediv,
Ben Dookse4d06e32007-02-16 12:12:31 +01001029};
1030
Ben Dookse4253822008-10-21 14:06:38 +01001031void __init_or_cpufreq s3c2443_setup_clocks(void)
Ben Dookse4d06e32007-02-16 12:12:31 +01001032{
Ben Dookse4d06e32007-02-16 12:12:31 +01001033 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
1034 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
Ben Dookse4253822008-10-21 14:06:38 +01001035 struct clk *xtal_clk;
1036 unsigned long xtal;
Ben Dookse4d06e32007-02-16 12:12:31 +01001037 unsigned long pll;
1038 unsigned long fclk;
1039 unsigned long hclk;
1040 unsigned long pclk;
Ben Dookse4d06e32007-02-16 12:12:31 +01001041
Ben Dookse4253822008-10-21 14:06:38 +01001042 xtal_clk = clk_get(NULL, "xtal");
1043 xtal = clk_get_rate(xtal_clk);
1044 clk_put(xtal_clk);
Ben Dooks2e16c272008-07-07 18:12:40 +01001045
Ben Dookse4d06e32007-02-16 12:12:31 +01001046 pll = s3c2443_get_mpll(mpllcon, xtal);
Ben Dooks2e16c272008-07-07 18:12:40 +01001047 clk_msysclk.rate = pll;
Ben Dookse4d06e32007-02-16 12:12:31 +01001048
1049 fclk = pll / s3c2443_fclk_div(clkdiv0);
Ben Dooks2e16c272008-07-07 18:12:40 +01001050 hclk = s3c2443_prediv_getrate(&clk_prediv);
Ben Dooks5c378662008-10-16 16:46:09 +01001051 hclk /= s3c2443_get_hdiv(clkdiv0);
Ben Dookse4d06e32007-02-16 12:12:31 +01001052 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
1053
Ben Dookse4253822008-10-21 14:06:38 +01001054 s3c24xx_setup_clocks(fclk, hclk, pclk);
Ben Dookse4d06e32007-02-16 12:12:31 +01001055
1056 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
1057 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
1058 print_mhz(pll), print_mhz(fclk),
1059 print_mhz(hclk), print_mhz(pclk));
1060
Ben Dookse4253822008-10-21 14:06:38 +01001061 s3c24xx_setup_clocks(fclk, hclk, pclk);
1062}
1063
1064void __init s3c2443_init_clocks(int xtal)
1065{
1066 struct clk *clkp;
1067 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
1068 int ret;
1069 int ptr;
1070
1071 /* s3c2443 parents h and p clocks from prediv */
1072 clk_h.parent = &clk_prediv;
1073 clk_p.parent = &clk_prediv;
1074
1075 s3c24xx_register_baseclocks(xtal);
1076 s3c2443_setup_clocks();
Ben Dookse4d06e32007-02-16 12:12:31 +01001077 s3c2443_clk_initparents();
1078
1079 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
1080 clkp = clks[ptr];
1081
1082 ret = s3c24xx_register_clock(clkp);
1083 if (ret < 0) {
1084 printk(KERN_ERR "Failed to register clock %s (%d)\n",
1085 clkp->name, ret);
1086 }
1087 }
1088
1089 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
Ben Dooks4b31d8b2008-10-21 14:07:00 +01001090 clk_epll.parent = &clk_epllref;
Ben Dookse4d06e32007-02-16 12:12:31 +01001091 clk_usb_bus.parent = &clk_usb_bus_host;
1092
1093 /* ensure usb bus clock is within correct rate of 48MHz */
1094
1095 if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) {
1096 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
1097 clk_set_rate(&clk_usb_bus_host, 48*1000*1000);
1098 }
1099
1100 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
1101 (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
1102 print_mhz(clk_get_rate(&clk_epll)),
1103 print_mhz(clk_get_rate(&clk_usb_bus)));
1104
1105 /* register clocks from clock array */
1106
1107 clkp = init_clocks;
1108 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
1109 ret = s3c24xx_register_clock(clkp);
1110 if (ret < 0) {
1111 printk(KERN_ERR "Failed to register clock %s (%d)\n",
1112 clkp->name, ret);
1113 }
1114 }
1115
1116 /* We must be careful disabling the clocks we are not intending to
Robert P. J. Day3a4fa0a2007-10-19 23:10:43 +02001117 * be using at boot time, as subsystems such as the LCD which do
Ben Dookse4d06e32007-02-16 12:12:31 +01001118 * their own DMA requests to the bus can cause the system to lockup
1119 * if they where in the middle of requesting bus access.
1120 *
1121 * Disabling the LCD clock if the LCD is active is very dangerous,
1122 * and therefore the bootloader should be careful to not enable
1123 * the LCD clock if it is not needed.
1124 */
1125
1126 /* install (and disable) the clocks we do not need immediately */
1127
1128 clkp = init_clocks_disable;
1129 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
1130
1131 ret = s3c24xx_register_clock(clkp);
1132 if (ret < 0) {
1133 printk(KERN_ERR "Failed to register clock %s (%d)\n",
1134 clkp->name, ret);
1135 }
1136
1137 (clkp->enable)(clkp, 0);
1138 }
Ben Dooks9d325f22008-11-21 10:36:05 +00001139
1140 s3c_pwmclk_init();
Ben Dookse4d06e32007-02-16 12:12:31 +01001141}