Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clock-s3c2412.c
Go to the documentation of this file.
1 /* linux/arch/arm/mach-s3c2412/clock.c
2  *
3  * Copyright (c) 2006 Simtec Electronics
4  * Ben Dooks <[email protected]>
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 
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 
70 
71  return 0;
72 }
73 
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 
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 
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 
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 
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 
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 
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 
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 */
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 
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 
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 
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 
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 
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 
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 
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 }
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 
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 
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 
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",
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 }