1 /* linux/arch/arm/mach-s3c2412/clock.c
2  *
3  * Copyright (c) 2006 Simtec Electronics
4  *	Ben Dooks <ben@simtec.co.uk>
5  *
6  * S3C2412,S3C2413 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/device.h>
30 #include <linux/clk.h>
31 #include <linux/mutex.h>
32 #include <linux/delay.h>
33 #include <linux/serial_core.h>
34 #include <linux/io.h>
35 
36 #include <asm/mach/map.h>
37 
38 #include <mach/hardware.h>
39 
40 #include <plat/regs-serial.h>
41 #include <mach/regs-clock.h>
42 #include <mach/regs-gpio.h>
43 
44 #include <plat/s3c2412.h>
45 #include <plat/clock.h>
46 #include <plat/cpu.h>
47 
48 /* We currently have to assume that the system is running
49  * from the XTPll input, and that all ***REFCLKs are being
50  * fed from it, as we cannot read the state of OM[4] from
51  * software.
52  *
53  * It would be possible for each board initialisation to
54  * set the correct muxing at initialisation
55 */
56 
s3c2412_clkcon_enable(struct clk * clk,int enable)57 static int s3c2412_clkcon_enable(struct clk *clk, int enable)
58 {
59 	unsigned int clocks = clk->ctrlbit;
60 	unsigned long clkcon;
61 
62 	clkcon = __raw_readl(S3C2410_CLKCON);
63 
64 	if (enable)
65 		clkcon |= clocks;
66 	else
67 		clkcon &= ~clocks;
68 
69 	__raw_writel(clkcon, S3C2410_CLKCON);
70 
71 	return 0;
72 }
73 
s3c2412_upll_enable(struct clk * clk,int enable)74 static int s3c2412_upll_enable(struct clk *clk, int enable)
75 {
76 	unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
77 	unsigned long orig = upllcon;
78 
79 	if (!enable)
80 		upllcon |= S3C2412_PLLCON_OFF;
81 	else
82 		upllcon &= ~S3C2412_PLLCON_OFF;
83 
84 	__raw_writel(upllcon, S3C2410_UPLLCON);
85 
86 	/* allow ~150uS for the PLL to settle and lock */
87 
88 	if (enable && (orig & S3C2412_PLLCON_OFF))
89 		udelay(150);
90 
91 	return 0;
92 }
93 
94 /* clock selections */
95 
96 static struct clk clk_erefclk = {
97 	.name		= "erefclk",
98 };
99 
100 static struct clk clk_urefclk = {
101 	.name		= "urefclk",
102 };
103 
s3c2412_setparent_usysclk(struct clk * clk,struct clk * parent)104 static int s3c2412_setparent_usysclk(struct clk *clk, struct clk *parent)
105 {
106 	unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
107 
108 	if (parent == &clk_urefclk)
109 		clksrc &= ~S3C2412_CLKSRC_USYSCLK_UPLL;
110 	else if (parent == &clk_upll)
111 		clksrc |= S3C2412_CLKSRC_USYSCLK_UPLL;
112 	else
113 		return -EINVAL;
114 
115 	clk->parent = parent;
116 
117 	__raw_writel(clksrc, S3C2412_CLKSRC);
118 	return 0;
119 }
120 
121 static struct clk clk_usysclk = {
122 	.name		= "usysclk",
123 	.parent		= &clk_xtal,
124 	.ops		= &(struct clk_ops) {
125 		.set_parent	= s3c2412_setparent_usysclk,
126 	},
127 };
128 
129 static struct clk clk_mrefclk = {
130 	.name		= "mrefclk",
131 	.parent		= &clk_xtal,
132 };
133 
134 static struct clk clk_mdivclk = {
135 	.name		= "mdivclk",
136 	.parent		= &clk_xtal,
137 };
138 
s3c2412_setparent_usbsrc(struct clk * clk,struct clk * parent)139 static int s3c2412_setparent_usbsrc(struct clk *clk, struct clk *parent)
140 {
141 	unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
142 
143 	if (parent == &clk_usysclk)
144 		clksrc &= ~S3C2412_CLKSRC_USBCLK_HCLK;
145 	else if (parent == &clk_h)
146 		clksrc |= S3C2412_CLKSRC_USBCLK_HCLK;
147 	else
148 		return -EINVAL;
149 
150 	clk->parent = parent;
151 
152 	__raw_writel(clksrc, S3C2412_CLKSRC);
153 	return 0;
154 }
155 
s3c2412_roundrate_usbsrc(struct clk * clk,unsigned long rate)156 static unsigned long s3c2412_roundrate_usbsrc(struct clk *clk,
157 					      unsigned long rate)
158 {
159 	unsigned long parent_rate = clk_get_rate(clk->parent);
160 	int div;
161 
162 	if (rate > parent_rate)
163 		return parent_rate;
164 
165 	div = parent_rate / rate;
166 	if (div > 2)
167 		div = 2;
168 
169 	return parent_rate / div;
170 }
171 
s3c2412_getrate_usbsrc(struct clk * clk)172 static unsigned long s3c2412_getrate_usbsrc(struct clk *clk)
173 {
174 	unsigned long parent_rate = clk_get_rate(clk->parent);
175 	unsigned long div = __raw_readl(S3C2410_CLKDIVN);
176 
177 	return parent_rate / ((div & S3C2412_CLKDIVN_USB48DIV) ? 2 : 1);
178 }
179 
s3c2412_setrate_usbsrc(struct clk * clk,unsigned long rate)180 static int s3c2412_setrate_usbsrc(struct clk *clk, unsigned long rate)
181 {
182 	unsigned long parent_rate = clk_get_rate(clk->parent);
183 	unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
184 
185 	rate = s3c2412_roundrate_usbsrc(clk, rate);
186 
187 	if ((parent_rate / rate) == 2)
188 		clkdivn |= S3C2412_CLKDIVN_USB48DIV;
189 	else
190 		clkdivn &= ~S3C2412_CLKDIVN_USB48DIV;
191 
192 	__raw_writel(clkdivn, S3C2410_CLKDIVN);
193 	return 0;
194 }
195 
196 static struct clk clk_usbsrc = {
197 	.name		= "usbsrc",
198 	.ops		= &(struct clk_ops) {
199 		.get_rate	= s3c2412_getrate_usbsrc,
200 		.set_rate	= s3c2412_setrate_usbsrc,
201 		.round_rate	= s3c2412_roundrate_usbsrc,
202 		.set_parent	= s3c2412_setparent_usbsrc,
203 	},
204 };
205 
s3c2412_setparent_msysclk(struct clk * clk,struct clk * parent)206 static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
207 {
208 	unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
209 
210 	if (parent == &clk_mdivclk)
211 		clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
212 	else if (parent == &clk_mpll)
213 		clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
214 	else
215 		return -EINVAL;
216 
217 	clk->parent = parent;
218 
219 	__raw_writel(clksrc, S3C2412_CLKSRC);
220 	return 0;
221 }
222 
223 static struct clk clk_msysclk = {
224 	.name		= "msysclk",
225 	.ops		= &(struct clk_ops) {
226 		.set_parent	= s3c2412_setparent_msysclk,
227 	},
228 };
229 
s3c2412_setparent_armclk(struct clk * clk,struct clk * parent)230 static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent)
231 {
232 	unsigned long flags;
233 	unsigned long clkdiv;
234 	unsigned long dvs;
235 
236 	/* Note, we current equate fclk andf msysclk for S3C2412 */
237 
238 	if (parent == &clk_msysclk || parent == &clk_f)
239 		dvs = 0;
240 	else if (parent == &clk_h)
241 		dvs = S3C2412_CLKDIVN_DVSEN;
242 	else
243 		return -EINVAL;
244 
245 	clk->parent = parent;
246 
247 	/* update this under irq lockdown, clkdivn is not protected
248 	 * by the clock system. */
249 
250 	local_irq_save(flags);
251 
252 	clkdiv  = __raw_readl(S3C2410_CLKDIVN);
253 	clkdiv &= ~S3C2412_CLKDIVN_DVSEN;
254 	clkdiv |= dvs;
255 	__raw_writel(clkdiv, S3C2410_CLKDIVN);
256 
257 	local_irq_restore(flags);
258 
259 	return 0;
260 }
261 
262 static struct clk clk_armclk = {
263 	.name		= "armclk",
264 	.parent		= &clk_msysclk,
265 	.ops		= &(struct clk_ops) {
266 		.set_parent	= s3c2412_setparent_armclk,
267 	},
268 };
269 
270 /* these next clocks have an divider immediately after them,
271  * so we can register them with their divider and leave out the
272  * intermediate clock stage
273 */
s3c2412_roundrate_clksrc(struct clk * clk,unsigned long rate)274 static unsigned long s3c2412_roundrate_clksrc(struct clk *clk,
275 					      unsigned long rate)
276 {
277 	unsigned long parent_rate = clk_get_rate(clk->parent);
278 	int div;
279 
280 	if (rate > parent_rate)
281 		return parent_rate;
282 
283 	/* note, we remove the +/- 1 calculations as they cancel out */
284 
285 	div = (rate / parent_rate);
286 
287 	if (div < 1)
288 		div = 1;
289 	else if (div > 16)
290 		div = 16;
291 
292 	return parent_rate / div;
293 }
294 
s3c2412_setparent_uart(struct clk * clk,struct clk * parent)295 static int s3c2412_setparent_uart(struct clk *clk, struct clk *parent)
296 {
297 	unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
298 
299 	if (parent == &clk_erefclk)
300 		clksrc &= ~S3C2412_CLKSRC_UARTCLK_MPLL;
301 	else if (parent == &clk_mpll)
302 		clksrc |= S3C2412_CLKSRC_UARTCLK_MPLL;
303 	else
304 		return -EINVAL;
305 
306 	clk->parent = parent;
307 
308 	__raw_writel(clksrc, S3C2412_CLKSRC);
309 	return 0;
310 }
311 
s3c2412_getrate_uart(struct clk * clk)312 static unsigned long s3c2412_getrate_uart(struct clk *clk)
313 {
314 	unsigned long parent_rate = clk_get_rate(clk->parent);
315 	unsigned long div = __raw_readl(S3C2410_CLKDIVN);
316 
317 	div &= S3C2412_CLKDIVN_UARTDIV_MASK;
318 	div >>= S3C2412_CLKDIVN_UARTDIV_SHIFT;
319 
320 	return parent_rate / (div + 1);
321 }
322 
s3c2412_setrate_uart(struct clk * clk,unsigned long rate)323 static int s3c2412_setrate_uart(struct clk *clk, unsigned long rate)
324 {
325 	unsigned long parent_rate = clk_get_rate(clk->parent);
326 	unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
327 
328 	rate = s3c2412_roundrate_clksrc(clk, rate);
329 
330 	clkdivn &= ~S3C2412_CLKDIVN_UARTDIV_MASK;
331 	clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_UARTDIV_SHIFT;
332 
333 	__raw_writel(clkdivn, S3C2410_CLKDIVN);
334 	return 0;
335 }
336 
337 static struct clk clk_uart = {
338 	.name		= "uartclk",
339 	.ops		= &(struct clk_ops) {
340 		.get_rate	= s3c2412_getrate_uart,
341 		.set_rate	= s3c2412_setrate_uart,
342 		.set_parent	= s3c2412_setparent_uart,
343 		.round_rate	= s3c2412_roundrate_clksrc,
344 	},
345 };
346 
s3c2412_setparent_i2s(struct clk * clk,struct clk * parent)347 static int s3c2412_setparent_i2s(struct clk *clk, struct clk *parent)
348 {
349 	unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
350 
351 	if (parent == &clk_erefclk)
352 		clksrc &= ~S3C2412_CLKSRC_I2SCLK_MPLL;
353 	else if (parent == &clk_mpll)
354 		clksrc |= S3C2412_CLKSRC_I2SCLK_MPLL;
355 	else
356 		return -EINVAL;
357 
358 	clk->parent = parent;
359 
360 	__raw_writel(clksrc, S3C2412_CLKSRC);
361 	return 0;
362 }
363 
s3c2412_getrate_i2s(struct clk * clk)364 static unsigned long s3c2412_getrate_i2s(struct clk *clk)
365 {
366 	unsigned long parent_rate = clk_get_rate(clk->parent);
367 	unsigned long div = __raw_readl(S3C2410_CLKDIVN);
368 
369 	div &= S3C2412_CLKDIVN_I2SDIV_MASK;
370 	div >>= S3C2412_CLKDIVN_I2SDIV_SHIFT;
371 
372 	return parent_rate / (div + 1);
373 }
374 
s3c2412_setrate_i2s(struct clk * clk,unsigned long rate)375 static int s3c2412_setrate_i2s(struct clk *clk, unsigned long rate)
376 {
377 	unsigned long parent_rate = clk_get_rate(clk->parent);
378 	unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
379 
380 	rate = s3c2412_roundrate_clksrc(clk, rate);
381 
382 	clkdivn &= ~S3C2412_CLKDIVN_I2SDIV_MASK;
383 	clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_I2SDIV_SHIFT;
384 
385 	__raw_writel(clkdivn, S3C2410_CLKDIVN);
386 	return 0;
387 }
388 
389 static struct clk clk_i2s = {
390 	.name		= "i2sclk",
391 	.ops		= &(struct clk_ops) {
392 		.get_rate	= s3c2412_getrate_i2s,
393 		.set_rate	= s3c2412_setrate_i2s,
394 		.set_parent	= s3c2412_setparent_i2s,
395 		.round_rate	= s3c2412_roundrate_clksrc,
396 	},
397 };
398 
s3c2412_setparent_cam(struct clk * clk,struct clk * parent)399 static int s3c2412_setparent_cam(struct clk *clk, struct clk *parent)
400 {
401 	unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
402 
403 	if (parent == &clk_usysclk)
404 		clksrc &= ~S3C2412_CLKSRC_CAMCLK_HCLK;
405 	else if (parent == &clk_h)
406 		clksrc |= S3C2412_CLKSRC_CAMCLK_HCLK;
407 	else
408 		return -EINVAL;
409 
410 	clk->parent = parent;
411 
412 	__raw_writel(clksrc, S3C2412_CLKSRC);
413 	return 0;
414 }
s3c2412_getrate_cam(struct clk * clk)415 static unsigned long s3c2412_getrate_cam(struct clk *clk)
416 {
417 	unsigned long parent_rate = clk_get_rate(clk->parent);
418 	unsigned long div = __raw_readl(S3C2410_CLKDIVN);
419 
420 	div &= S3C2412_CLKDIVN_CAMDIV_MASK;
421 	div >>= S3C2412_CLKDIVN_CAMDIV_SHIFT;
422 
423 	return parent_rate / (div + 1);
424 }
425 
s3c2412_setrate_cam(struct clk * clk,unsigned long rate)426 static int s3c2412_setrate_cam(struct clk *clk, unsigned long rate)
427 {
428 	unsigned long parent_rate = clk_get_rate(clk->parent);
429 	unsigned long clkdivn = __raw_readl(S3C2410_CLKDIVN);
430 
431 	rate = s3c2412_roundrate_clksrc(clk, rate);
432 
433 	clkdivn &= ~S3C2412_CLKDIVN_CAMDIV_MASK;
434 	clkdivn |= ((parent_rate / rate) - 1) << S3C2412_CLKDIVN_CAMDIV_SHIFT;
435 
436 	__raw_writel(clkdivn, S3C2410_CLKDIVN);
437 	return 0;
438 }
439 
440 static struct clk clk_cam = {
441 	.name		= "camif-upll",	/* same as 2440 name */
442 	.ops		= &(struct clk_ops) {
443 		.get_rate	= s3c2412_getrate_cam,
444 		.set_rate	= s3c2412_setrate_cam,
445 		.set_parent	= s3c2412_setparent_cam,
446 		.round_rate	= s3c2412_roundrate_clksrc,
447 	},
448 };
449 
450 /* standard clock definitions */
451 
452 static struct clk init_clocks_disable[] = {
453 	{
454 		.name		= "nand",
455 		.parent		= &clk_h,
456 		.enable		= s3c2412_clkcon_enable,
457 		.ctrlbit	= S3C2412_CLKCON_NAND,
458 	}, {
459 		.name		= "sdi",
460 		.parent		= &clk_p,
461 		.enable		= s3c2412_clkcon_enable,
462 		.ctrlbit	= S3C2412_CLKCON_SDI,
463 	}, {
464 		.name		= "adc",
465 		.parent		= &clk_p,
466 		.enable		= s3c2412_clkcon_enable,
467 		.ctrlbit	= S3C2412_CLKCON_ADC,
468 	}, {
469 		.name		= "i2c",
470 		.parent		= &clk_p,
471 		.enable		= s3c2412_clkcon_enable,
472 		.ctrlbit	= S3C2412_CLKCON_IIC,
473 	}, {
474 		.name		= "iis",
475 		.parent		= &clk_p,
476 		.enable		= s3c2412_clkcon_enable,
477 		.ctrlbit	= S3C2412_CLKCON_IIS,
478 	}, {
479 		.name		= "spi",
480 		.parent		= &clk_p,
481 		.enable		= s3c2412_clkcon_enable,
482 		.ctrlbit	= S3C2412_CLKCON_SPI,
483 	}
484 };
485 
486 static struct clk init_clocks[] = {
487 	{
488 		.name		= "dma",
489 		.parent		= &clk_h,
490 		.enable		= s3c2412_clkcon_enable,
491 		.ctrlbit	= S3C2412_CLKCON_DMA0,
492 	}, {
493 		.name		= "dma",
494 		.parent		= &clk_h,
495 		.enable		= s3c2412_clkcon_enable,
496 		.ctrlbit	= S3C2412_CLKCON_DMA1,
497 	}, {
498 		.name		= "dma",
499 		.parent		= &clk_h,
500 		.enable		= s3c2412_clkcon_enable,
501 		.ctrlbit	= S3C2412_CLKCON_DMA2,
502 	}, {
503 		.name		= "dma",
504 		.parent		= &clk_h,
505 		.enable		= s3c2412_clkcon_enable,
506 		.ctrlbit	= S3C2412_CLKCON_DMA3,
507 	}, {
508 		.name		= "lcd",
509 		.parent		= &clk_h,
510 		.enable		= s3c2412_clkcon_enable,
511 		.ctrlbit	= S3C2412_CLKCON_LCDC,
512 	}, {
513 		.name		= "gpio",
514 		.parent		= &clk_p,
515 		.enable		= s3c2412_clkcon_enable,
516 		.ctrlbit	= S3C2412_CLKCON_GPIO,
517 	}, {
518 		.name		= "usb-host",
519 		.parent		= &clk_h,
520 		.enable		= s3c2412_clkcon_enable,
521 		.ctrlbit	= S3C2412_CLKCON_USBH,
522 	}, {
523 		.name		= "usb-device",
524 		.parent		= &clk_h,
525 		.enable		= s3c2412_clkcon_enable,
526 		.ctrlbit	= S3C2412_CLKCON_USBD,
527 	}, {
528 		.name		= "timers",
529 		.parent		= &clk_p,
530 		.enable		= s3c2412_clkcon_enable,
531 		.ctrlbit	= S3C2412_CLKCON_PWMT,
532 	}, {
533 		.name		= "uart",
534 		.devname	= "s3c2412-uart.0",
535 		.parent		= &clk_p,
536 		.enable		= s3c2412_clkcon_enable,
537 		.ctrlbit	= S3C2412_CLKCON_UART0,
538 	}, {
539 		.name		= "uart",
540 		.devname	= "s3c2412-uart.1",
541 		.parent		= &clk_p,
542 		.enable		= s3c2412_clkcon_enable,
543 		.ctrlbit	= S3C2412_CLKCON_UART1,
544 	}, {
545 		.name		= "uart",
546 		.devname	= "s3c2412-uart.2",
547 		.parent		= &clk_p,
548 		.enable		= s3c2412_clkcon_enable,
549 		.ctrlbit	= S3C2412_CLKCON_UART2,
550 	}, {
551 		.name		= "rtc",
552 		.parent		= &clk_p,
553 		.enable		= s3c2412_clkcon_enable,
554 		.ctrlbit	= S3C2412_CLKCON_RTC,
555 	}, {
556 		.name		= "watchdog",
557 		.parent		= &clk_p,
558 		.ctrlbit	= 0,
559 	}, {
560 		.name		= "usb-bus-gadget",
561 		.parent		= &clk_usb_bus,
562 		.enable		= s3c2412_clkcon_enable,
563 		.ctrlbit	= S3C2412_CLKCON_USB_DEV48,
564 	}, {
565 		.name		= "usb-bus-host",
566 		.parent		= &clk_usb_bus,
567 		.enable		= s3c2412_clkcon_enable,
568 		.ctrlbit	= S3C2412_CLKCON_USB_HOST48,
569 	}
570 };
571 
572 /* clocks to add where we need to check their parentage */
573 
574 struct clk_init {
575 	struct clk	*clk;
576 	unsigned int	 bit;
577 	struct clk	*src_0;
578 	struct clk	*src_1;
579 };
580 
581 static struct clk_init clks_src[] __initdata = {
582 	{
583 		.clk	= &clk_usysclk,
584 		.bit	= S3C2412_CLKSRC_USBCLK_HCLK,
585 		.src_0	= &clk_urefclk,
586 		.src_1	= &clk_upll,
587 	}, {
588 		.clk	= &clk_i2s,
589 		.bit	= S3C2412_CLKSRC_I2SCLK_MPLL,
590 		.src_0	= &clk_erefclk,
591 		.src_1	= &clk_mpll,
592 	}, {
593 		.clk	= &clk_cam,
594 		.bit	= S3C2412_CLKSRC_CAMCLK_HCLK,
595 		.src_0	= &clk_usysclk,
596 		.src_1	= &clk_h,
597 	}, {
598 		.clk	= &clk_msysclk,
599 		.bit	= S3C2412_CLKSRC_MSYSCLK_MPLL,
600 		.src_0	= &clk_mdivclk,
601 		.src_1	= &clk_mpll,
602 	}, {
603 		.clk	= &clk_uart,
604 		.bit	= S3C2412_CLKSRC_UARTCLK_MPLL,
605 		.src_0	= &clk_erefclk,
606 		.src_1	= &clk_mpll,
607 	}, {
608 		.clk	= &clk_usbsrc,
609 		.bit	= S3C2412_CLKSRC_USBCLK_HCLK,
610 		.src_0	= &clk_usysclk,
611 		.src_1	= &clk_h,
612 	/* here we assume  OM[4] select xtal */
613 	}, {
614 		.clk	= &clk_erefclk,
615 		.bit	= S3C2412_CLKSRC_EREFCLK_EXTCLK,
616 		.src_0	= &clk_xtal,
617 		.src_1	= &clk_ext,
618 	}, {
619 		.clk	= &clk_urefclk,
620 		.bit	= S3C2412_CLKSRC_UREFCLK_EXTCLK,
621 		.src_0	= &clk_xtal,
622 		.src_1	= &clk_ext,
623 	},
624 };
625 
626 /* s3c2412_clk_initparents
627  *
628  * Initialise the parents for the clocks that we get at start-time
629 */
630 
s3c2412_clk_initparents(void)631 static void __init s3c2412_clk_initparents(void)
632 {
633 	unsigned long clksrc = __raw_readl(S3C2412_CLKSRC);
634 	struct clk_init *cip = clks_src;
635 	struct clk *src;
636 	int ptr;
637 	int ret;
638 
639 	for (ptr = 0; ptr < ARRAY_SIZE(clks_src); ptr++, cip++) {
640 		ret = s3c24xx_register_clock(cip->clk);
641 		if (ret < 0) {
642 			printk(KERN_ERR "Failed to register clock %s (%d)\n",
643 			       cip->clk->name, ret);
644 		}
645 
646 		src = (clksrc & cip->bit) ? cip->src_1 : cip->src_0;
647 
648 		printk(KERN_INFO "%s: parent %s\n", cip->clk->name, src->name);
649 		clk_set_parent(cip->clk, src);
650 	}
651 }
652 
653 /* clocks to add straight away */
654 
655 static struct clk *clks[] __initdata = {
656 	&clk_ext,
657 	&clk_usb_bus,
658 	&clk_mrefclk,
659 	&clk_armclk,
660 };
661 
662 static struct clk_lookup s3c2412_clk_lookup[] = {
663 	CLKDEV_INIT(NULL, "clk_uart_baud1", &s3c24xx_uclk),
664 	CLKDEV_INIT(NULL, "clk_uart_baud2", &clk_p),
665 	CLKDEV_INIT(NULL, "clk_uart_baud3", &clk_usysclk),
666 };
667 
s3c2412_baseclk_add(void)668 int __init s3c2412_baseclk_add(void)
669 {
670 	unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
671 	unsigned int dvs;
672 	struct clk *clkp;
673 	int ret;
674 	int ptr;
675 
676 	clk_upll.enable = s3c2412_upll_enable;
677 	clk_usb_bus.parent = &clk_usbsrc;
678 	clk_usb_bus.rate = 0x0;
679 
680 	clk_f.parent = &clk_msysclk;
681 
682 	s3c2412_clk_initparents();
683 
684 	for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
685 		clkp = clks[ptr];
686 
687 		ret = s3c24xx_register_clock(clkp);
688 		if (ret < 0) {
689 			printk(KERN_ERR "Failed to register clock %s (%d)\n",
690 			       clkp->name, ret);
691 		}
692 	}
693 
694 	/* set the dvs state according to what we got at boot time */
695 
696 	dvs = __raw_readl(S3C2410_CLKDIVN) & S3C2412_CLKDIVN_DVSEN;
697 
698 	if (dvs)
699 		clk_armclk.parent = &clk_h;
700 
701 	printk(KERN_INFO "S3C2412: DVS is %s\n", dvs ? "on" : "off");
702 
703 	/* ensure usb bus clock is within correct rate of 48MHz */
704 
705 	if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {
706 		printk(KERN_INFO "Warning: USB bus clock not at 48MHz\n");
707 
708 		/* for the moment, let's use the UPLL, and see if we can
709 		 * get 48MHz */
710 
711 		clk_set_parent(&clk_usysclk, &clk_upll);
712 		clk_set_parent(&clk_usbsrc, &clk_usysclk);
713 		clk_set_rate(&clk_usbsrc, 48*1000*1000);
714 	}
715 
716 	printk("S3C2412: upll %s, %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
717 	       (__raw_readl(S3C2410_UPLLCON) & S3C2412_PLLCON_OFF) ? "off":"on",
718 	       print_mhz(clk_get_rate(&clk_upll)),
719 	       print_mhz(clk_get_rate(&clk_usb_bus)));
720 
721 	/* register clocks from clock array */
722 
723 	clkp = init_clocks;
724 	for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
725 		/* ensure that we note the clock state */
726 
727 		clkp->usage = clkcon & clkp->ctrlbit ? 1 : 0;
728 
729 		ret = s3c24xx_register_clock(clkp);
730 		if (ret < 0) {
731 			printk(KERN_ERR "Failed to register clock %s (%d)\n",
732 			       clkp->name, ret);
733 		}
734 	}
735 
736 	/* We must be careful disabling the clocks we are not intending to
737 	 * be using at boot time, as subsystems such as the LCD which do
738 	 * their own DMA requests to the bus can cause the system to lockup
739 	 * if they where in the middle of requesting bus access.
740 	 *
741 	 * Disabling the LCD clock if the LCD is active is very dangerous,
742 	 * and therefore the bootloader should be careful to not enable
743 	 * the LCD clock if it is not needed.
744 	*/
745 
746 	/* install (and disable) the clocks we do not need immediately */
747 
748 	clkp = init_clocks_disable;
749 	for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
750 
751 		ret = s3c24xx_register_clock(clkp);
752 		if (ret < 0) {
753 			printk(KERN_ERR "Failed to register clock %s (%d)\n",
754 			       clkp->name, ret);
755 		}
756 
757 		s3c2412_clkcon_enable(clkp, 0);
758 	}
759 
760 	clkdev_add_table(s3c2412_clk_lookup, ARRAY_SIZE(s3c2412_clk_lookup));
761 	s3c_pwmclk_init();
762 	return 0;
763 }
764