s3c6400-clock.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /* linux/arch/arm/plat-s3c64xx/s3c6400-clock.c
  2. *
  3. * Copyright 2008 Openmoko, Inc.
  4. * Copyright 2008 Simtec Electronics
  5. * Ben Dooks <ben@simtec.co.uk>
  6. * http://armlinux.simtec.co.uk/
  7. *
  8. * S3C6400 based common clock support
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License version 2 as
  12. * published by the Free Software Foundation.
  13. */
  14. #include <linux/init.h>
  15. #include <linux/module.h>
  16. #include <linux/kernel.h>
  17. #include <linux/list.h>
  18. #include <linux/errno.h>
  19. #include <linux/err.h>
  20. #include <linux/clk.h>
  21. #include <linux/sysdev.h>
  22. #include <linux/io.h>
  23. #include <mach/hardware.h>
  24. #include <mach/map.h>
  25. #include <plat/cpu-freq.h>
  26. #include <plat/regs-clock.h>
  27. #include <plat/clock.h>
  28. #include <plat/cpu.h>
  29. #include <plat/pll.h>
  30. /* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
  31. * ext_xtal_mux for want of an actual name from the manual.
  32. */
  33. static struct clk clk_ext_xtal_mux = {
  34. .name = "ext_xtal",
  35. .id = -1,
  36. };
  37. #define clk_fin_apll clk_ext_xtal_mux
  38. #define clk_fin_mpll clk_ext_xtal_mux
  39. #define clk_fin_epll clk_ext_xtal_mux
  40. #define clk_fout_mpll clk_mpll
  41. struct clk_sources {
  42. unsigned int nr_sources;
  43. struct clk **sources;
  44. };
  45. struct clksrc_clk {
  46. struct clk clk;
  47. unsigned int mask;
  48. unsigned int shift;
  49. struct clk_sources *sources;
  50. unsigned int divider_shift;
  51. void __iomem *reg_divider;
  52. };
  53. static struct clk clk_fout_apll = {
  54. .name = "fout_apll",
  55. .id = -1,
  56. };
  57. static struct clk *clk_src_apll_list[] = {
  58. [0] = &clk_fin_apll,
  59. [1] = &clk_fout_apll,
  60. };
  61. static struct clk_sources clk_src_apll = {
  62. .sources = clk_src_apll_list,
  63. .nr_sources = ARRAY_SIZE(clk_src_apll_list),
  64. };
  65. static struct clksrc_clk clk_mout_apll = {
  66. .clk = {
  67. .name = "mout_apll",
  68. .id = -1,
  69. },
  70. .shift = S3C6400_CLKSRC_APLL_MOUT_SHIFT,
  71. .mask = S3C6400_CLKSRC_APLL_MOUT,
  72. .sources = &clk_src_apll,
  73. };
  74. static struct clk clk_fout_epll = {
  75. .name = "fout_epll",
  76. .id = -1,
  77. };
  78. static struct clk *clk_src_epll_list[] = {
  79. [0] = &clk_fin_epll,
  80. [1] = &clk_fout_epll,
  81. };
  82. static struct clk_sources clk_src_epll = {
  83. .sources = clk_src_epll_list,
  84. .nr_sources = ARRAY_SIZE(clk_src_epll_list),
  85. };
  86. static struct clksrc_clk clk_mout_epll = {
  87. .clk = {
  88. .name = "mout_epll",
  89. .id = -1,
  90. },
  91. .shift = S3C6400_CLKSRC_EPLL_MOUT_SHIFT,
  92. .mask = S3C6400_CLKSRC_EPLL_MOUT,
  93. .sources = &clk_src_epll,
  94. };
  95. static struct clk *clk_src_mpll_list[] = {
  96. [0] = &clk_fin_mpll,
  97. [1] = &clk_fout_mpll,
  98. };
  99. static struct clk_sources clk_src_mpll = {
  100. .sources = clk_src_mpll_list,
  101. .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
  102. };
  103. static struct clksrc_clk clk_mout_mpll = {
  104. .clk = {
  105. .name = "mout_mpll",
  106. .id = -1,
  107. },
  108. .shift = S3C6400_CLKSRC_MPLL_MOUT_SHIFT,
  109. .mask = S3C6400_CLKSRC_MPLL_MOUT,
  110. .sources = &clk_src_mpll,
  111. };
  112. static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk)
  113. {
  114. unsigned long rate = clk_get_rate(clk->parent);
  115. printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
  116. if (__raw_readl(S3C_CLK_DIV0) & S3C6400_CLKDIV0_MPLL_MASK)
  117. rate /= 2;
  118. return rate;
  119. }
  120. static struct clk clk_dout_mpll = {
  121. .name = "dout_mpll",
  122. .id = -1,
  123. .parent = &clk_mout_mpll.clk,
  124. .get_rate = s3c64xx_clk_doutmpll_get_rate,
  125. };
  126. static struct clk *clkset_spi_mmc_list[] = {
  127. &clk_mout_epll.clk,
  128. &clk_dout_mpll,
  129. &clk_fin_epll,
  130. &clk_27m,
  131. };
  132. static struct clk_sources clkset_spi_mmc = {
  133. .sources = clkset_spi_mmc_list,
  134. .nr_sources = ARRAY_SIZE(clkset_spi_mmc_list),
  135. };
  136. static struct clk *clkset_irda_list[] = {
  137. &clk_mout_epll.clk,
  138. &clk_dout_mpll,
  139. NULL,
  140. &clk_27m,
  141. };
  142. static struct clk_sources clkset_irda = {
  143. .sources = clkset_irda_list,
  144. .nr_sources = ARRAY_SIZE(clkset_irda_list),
  145. };
  146. static struct clk *clkset_uart_list[] = {
  147. &clk_mout_epll.clk,
  148. &clk_dout_mpll,
  149. NULL,
  150. NULL
  151. };
  152. static struct clk_sources clkset_uart = {
  153. .sources = clkset_uart_list,
  154. .nr_sources = ARRAY_SIZE(clkset_uart_list),
  155. };
  156. static struct clk *clkset_uhost_list[] = {
  157. &clk_48m,
  158. &clk_mout_epll.clk,
  159. &clk_dout_mpll,
  160. &clk_fin_epll,
  161. };
  162. static struct clk_sources clkset_uhost = {
  163. .sources = clkset_uhost_list,
  164. .nr_sources = ARRAY_SIZE(clkset_uhost_list),
  165. };
  166. /* The peripheral clocks are all controlled via clocksource followed
  167. * by an optional divider and gate stage. We currently roll this into
  168. * one clock which hides the intermediate clock from the mux.
  169. *
  170. * Note, the JPEG clock can only be an even divider...
  171. *
  172. * The scaler and LCD clocks depend on the S3C64XX version, and also
  173. * have a common parent divisor so are not included here.
  174. */
  175. static inline struct clksrc_clk *to_clksrc(struct clk *clk)
  176. {
  177. return container_of(clk, struct clksrc_clk, clk);
  178. }
  179. static unsigned long s3c64xx_getrate_clksrc(struct clk *clk)
  180. {
  181. struct clksrc_clk *sclk = to_clksrc(clk);
  182. unsigned long rate = clk_get_rate(clk->parent);
  183. u32 clkdiv = __raw_readl(sclk->reg_divider);
  184. clkdiv >>= sclk->divider_shift;
  185. clkdiv &= 0xf;
  186. clkdiv++;
  187. rate /= clkdiv;
  188. return rate;
  189. }
  190. static int s3c64xx_setrate_clksrc(struct clk *clk, unsigned long rate)
  191. {
  192. struct clksrc_clk *sclk = to_clksrc(clk);
  193. void __iomem *reg = sclk->reg_divider;
  194. unsigned int div;
  195. u32 val;
  196. rate = clk_round_rate(clk, rate);
  197. div = clk_get_rate(clk->parent) / rate;
  198. if (div > 16)
  199. return -EINVAL;
  200. val = __raw_readl(reg);
  201. val &= ~(0xf << sclk->shift);
  202. val |= (div - 1) << sclk->shift;
  203. __raw_writel(val, reg);
  204. return 0;
  205. }
  206. static int s3c64xx_setparent_clksrc(struct clk *clk, struct clk *parent)
  207. {
  208. struct clksrc_clk *sclk = to_clksrc(clk);
  209. struct clk_sources *srcs = sclk->sources;
  210. u32 clksrc = __raw_readl(S3C_CLK_SRC);
  211. int src_nr = -1;
  212. int ptr;
  213. for (ptr = 0; ptr < srcs->nr_sources; ptr++)
  214. if (srcs->sources[ptr] == parent) {
  215. src_nr = ptr;
  216. break;
  217. }
  218. if (src_nr >= 0) {
  219. clksrc &= ~sclk->mask;
  220. clksrc |= src_nr << sclk->shift;
  221. __raw_writel(clksrc, S3C_CLK_SRC);
  222. return 0;
  223. }
  224. return -EINVAL;
  225. }
  226. static unsigned long s3c64xx_roundrate_clksrc(struct clk *clk,
  227. unsigned long rate)
  228. {
  229. unsigned long parent_rate = clk_get_rate(clk->parent);
  230. int div;
  231. if (rate > parent_rate)
  232. rate = parent_rate;
  233. else {
  234. div = rate / parent_rate;
  235. if (div == 0)
  236. div = 1;
  237. if (div > 16)
  238. div = 16;
  239. rate = parent_rate / div;
  240. }
  241. return rate;
  242. }
  243. static struct clksrc_clk clk_mmc0 = {
  244. .clk = {
  245. .name = "mmc_bus",
  246. .id = 0,
  247. .ctrlbit = S3C_CLKCON_SCLK_MMC0,
  248. .enable = s3c64xx_sclk_ctrl,
  249. .set_parent = s3c64xx_setparent_clksrc,
  250. .get_rate = s3c64xx_getrate_clksrc,
  251. .set_rate = s3c64xx_setrate_clksrc,
  252. .round_rate = s3c64xx_roundrate_clksrc,
  253. },
  254. .shift = S3C6400_CLKSRC_MMC0_SHIFT,
  255. .mask = S3C6400_CLKSRC_MMC0_MASK,
  256. .sources = &clkset_spi_mmc,
  257. .divider_shift = S3C6400_CLKDIV1_MMC0_SHIFT,
  258. .reg_divider = S3C_CLK_DIV1,
  259. };
  260. static struct clksrc_clk clk_mmc1 = {
  261. .clk = {
  262. .name = "mmc_bus",
  263. .id = 1,
  264. .ctrlbit = S3C_CLKCON_SCLK_MMC1,
  265. .enable = s3c64xx_sclk_ctrl,
  266. .get_rate = s3c64xx_getrate_clksrc,
  267. .set_rate = s3c64xx_setrate_clksrc,
  268. .set_parent = s3c64xx_setparent_clksrc,
  269. .round_rate = s3c64xx_roundrate_clksrc,
  270. },
  271. .shift = S3C6400_CLKSRC_MMC1_SHIFT,
  272. .mask = S3C6400_CLKSRC_MMC1_MASK,
  273. .sources = &clkset_spi_mmc,
  274. .divider_shift = S3C6400_CLKDIV1_MMC1_SHIFT,
  275. .reg_divider = S3C_CLK_DIV1,
  276. };
  277. static struct clksrc_clk clk_mmc2 = {
  278. .clk = {
  279. .name = "mmc_bus",
  280. .id = 2,
  281. .ctrlbit = S3C_CLKCON_SCLK_MMC2,
  282. .enable = s3c64xx_sclk_ctrl,
  283. .get_rate = s3c64xx_getrate_clksrc,
  284. .set_rate = s3c64xx_setrate_clksrc,
  285. .set_parent = s3c64xx_setparent_clksrc,
  286. .round_rate = s3c64xx_roundrate_clksrc,
  287. },
  288. .shift = S3C6400_CLKSRC_MMC2_SHIFT,
  289. .mask = S3C6400_CLKSRC_MMC2_MASK,
  290. .sources = &clkset_spi_mmc,
  291. .divider_shift = S3C6400_CLKDIV1_MMC2_SHIFT,
  292. .reg_divider = S3C_CLK_DIV1,
  293. };
  294. static struct clksrc_clk clk_usbhost = {
  295. .clk = {
  296. .name = "usb-bus-host",
  297. .id = -1,
  298. .ctrlbit = S3C_CLKCON_SCLK_UHOST,
  299. .enable = s3c64xx_sclk_ctrl,
  300. .set_parent = s3c64xx_setparent_clksrc,
  301. .get_rate = s3c64xx_getrate_clksrc,
  302. .set_rate = s3c64xx_setrate_clksrc,
  303. .round_rate = s3c64xx_roundrate_clksrc,
  304. },
  305. .shift = S3C6400_CLKSRC_UHOST_SHIFT,
  306. .mask = S3C6400_CLKSRC_UHOST_MASK,
  307. .sources = &clkset_uhost,
  308. .divider_shift = S3C6400_CLKDIV1_UHOST_SHIFT,
  309. .reg_divider = S3C_CLK_DIV1,
  310. };
  311. static struct clksrc_clk clk_uart_uclk1 = {
  312. .clk = {
  313. .name = "uclk1",
  314. .id = -1,
  315. .ctrlbit = S3C_CLKCON_SCLK_UART,
  316. .enable = s3c64xx_sclk_ctrl,
  317. .set_parent = s3c64xx_setparent_clksrc,
  318. .get_rate = s3c64xx_getrate_clksrc,
  319. .set_rate = s3c64xx_setrate_clksrc,
  320. .round_rate = s3c64xx_roundrate_clksrc,
  321. },
  322. .shift = S3C6400_CLKSRC_UART_SHIFT,
  323. .mask = S3C6400_CLKSRC_UART_MASK,
  324. .sources = &clkset_uart,
  325. .divider_shift = S3C6400_CLKDIV2_UART_SHIFT,
  326. .reg_divider = S3C_CLK_DIV2,
  327. };
  328. /* Where does UCLK0 come from? */
  329. static struct clksrc_clk clk_spi0 = {
  330. .clk = {
  331. .name = "spi-bus",
  332. .id = 0,
  333. .ctrlbit = S3C_CLKCON_SCLK_SPI0,
  334. .enable = s3c64xx_sclk_ctrl,
  335. .set_parent = s3c64xx_setparent_clksrc,
  336. .get_rate = s3c64xx_getrate_clksrc,
  337. .set_rate = s3c64xx_setrate_clksrc,
  338. .round_rate = s3c64xx_roundrate_clksrc,
  339. },
  340. .shift = S3C6400_CLKSRC_SPI0_SHIFT,
  341. .mask = S3C6400_CLKSRC_SPI0_MASK,
  342. .sources = &clkset_spi_mmc,
  343. .divider_shift = S3C6400_CLKDIV2_SPI0_SHIFT,
  344. .reg_divider = S3C_CLK_DIV2,
  345. };
  346. static struct clksrc_clk clk_spi1 = {
  347. .clk = {
  348. .name = "spi-bus",
  349. .id = 1,
  350. .ctrlbit = S3C_CLKCON_SCLK_SPI1,
  351. .enable = s3c64xx_sclk_ctrl,
  352. .set_parent = s3c64xx_setparent_clksrc,
  353. .get_rate = s3c64xx_getrate_clksrc,
  354. .set_rate = s3c64xx_setrate_clksrc,
  355. .round_rate = s3c64xx_roundrate_clksrc,
  356. },
  357. .shift = S3C6400_CLKSRC_SPI1_SHIFT,
  358. .mask = S3C6400_CLKSRC_SPI1_MASK,
  359. .sources = &clkset_spi_mmc,
  360. .divider_shift = S3C6400_CLKDIV2_SPI1_SHIFT,
  361. .reg_divider = S3C_CLK_DIV2,
  362. };
  363. static struct clk clk_iis_cd0 = {
  364. .name = "iis_cdclk0",
  365. .id = -1,
  366. };
  367. static struct clk clk_iis_cd1 = {
  368. .name = "iis_cdclk1",
  369. .id = -1,
  370. };
  371. static struct clk clk_pcm_cd = {
  372. .name = "pcm_cdclk",
  373. .id = -1,
  374. };
  375. static struct clk *clkset_audio0_list[] = {
  376. [0] = &clk_mout_epll.clk,
  377. [1] = &clk_dout_mpll,
  378. [2] = &clk_fin_epll,
  379. [3] = &clk_iis_cd0,
  380. [4] = &clk_pcm_cd,
  381. };
  382. static struct clk_sources clkset_audio0 = {
  383. .sources = clkset_audio0_list,
  384. .nr_sources = ARRAY_SIZE(clkset_audio0_list),
  385. };
  386. static struct clksrc_clk clk_audio0 = {
  387. .clk = {
  388. .name = "audio-bus",
  389. .id = 0,
  390. .ctrlbit = S3C_CLKCON_SCLK_AUDIO0,
  391. .enable = s3c64xx_sclk_ctrl,
  392. .set_parent = s3c64xx_setparent_clksrc,
  393. .get_rate = s3c64xx_getrate_clksrc,
  394. .set_rate = s3c64xx_setrate_clksrc,
  395. .round_rate = s3c64xx_roundrate_clksrc,
  396. },
  397. .shift = S3C6400_CLKSRC_AUDIO0_SHIFT,
  398. .mask = S3C6400_CLKSRC_AUDIO0_MASK,
  399. .sources = &clkset_audio0,
  400. .divider_shift = S3C6400_CLKDIV2_AUDIO0_SHIFT,
  401. .reg_divider = S3C_CLK_DIV2,
  402. };
  403. static struct clk *clkset_audio1_list[] = {
  404. [0] = &clk_mout_epll.clk,
  405. [1] = &clk_dout_mpll,
  406. [2] = &clk_fin_epll,
  407. [3] = &clk_iis_cd1,
  408. [4] = &clk_pcm_cd,
  409. };
  410. static struct clk_sources clkset_audio1 = {
  411. .sources = clkset_audio1_list,
  412. .nr_sources = ARRAY_SIZE(clkset_audio1_list),
  413. };
  414. static struct clksrc_clk clk_audio1 = {
  415. .clk = {
  416. .name = "audio-bus",
  417. .id = 1,
  418. .ctrlbit = S3C_CLKCON_SCLK_AUDIO1,
  419. .enable = s3c64xx_sclk_ctrl,
  420. .set_parent = s3c64xx_setparent_clksrc,
  421. .get_rate = s3c64xx_getrate_clksrc,
  422. .set_rate = s3c64xx_setrate_clksrc,
  423. .round_rate = s3c64xx_roundrate_clksrc,
  424. },
  425. .shift = S3C6400_CLKSRC_AUDIO1_SHIFT,
  426. .mask = S3C6400_CLKSRC_AUDIO1_MASK,
  427. .sources = &clkset_audio1,
  428. .divider_shift = S3C6400_CLKDIV2_AUDIO1_SHIFT,
  429. .reg_divider = S3C_CLK_DIV2,
  430. };
  431. static struct clksrc_clk clk_irda = {
  432. .clk = {
  433. .name = "irda-bus",
  434. .id = 0,
  435. .ctrlbit = S3C_CLKCON_SCLK_IRDA,
  436. .enable = s3c64xx_sclk_ctrl,
  437. .set_parent = s3c64xx_setparent_clksrc,
  438. .get_rate = s3c64xx_getrate_clksrc,
  439. .set_rate = s3c64xx_setrate_clksrc,
  440. .round_rate = s3c64xx_roundrate_clksrc,
  441. },
  442. .shift = S3C6400_CLKSRC_IRDA_SHIFT,
  443. .mask = S3C6400_CLKSRC_IRDA_MASK,
  444. .sources = &clkset_irda,
  445. .divider_shift = S3C6400_CLKDIV2_IRDA_SHIFT,
  446. .reg_divider = S3C_CLK_DIV2,
  447. };
  448. /* Clock initialisation code */
  449. static struct clksrc_clk *init_parents[] = {
  450. &clk_mout_apll,
  451. &clk_mout_epll,
  452. &clk_mout_mpll,
  453. &clk_mmc0,
  454. &clk_mmc1,
  455. &clk_mmc2,
  456. &clk_usbhost,
  457. &clk_uart_uclk1,
  458. &clk_spi0,
  459. &clk_spi1,
  460. &clk_audio0,
  461. &clk_audio1,
  462. &clk_irda,
  463. };
  464. static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk)
  465. {
  466. struct clk_sources *srcs = clk->sources;
  467. u32 clksrc = __raw_readl(S3C_CLK_SRC);
  468. clksrc &= clk->mask;
  469. clksrc >>= clk->shift;
  470. if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
  471. printk(KERN_ERR "%s: bad source %d\n",
  472. clk->clk.name, clksrc);
  473. return;
  474. }
  475. clk->clk.parent = srcs->sources[clksrc];
  476. printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
  477. clk->clk.name, clk->clk.parent->name, clksrc,
  478. clk_get_rate(&clk->clk));
  479. }
  480. #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
  481. void __init_or_cpufreq s3c6400_setup_clocks(void)
  482. {
  483. struct clk *xtal_clk;
  484. unsigned long xtal;
  485. unsigned long fclk;
  486. unsigned long hclk;
  487. unsigned long hclk2;
  488. unsigned long pclk;
  489. unsigned long epll;
  490. unsigned long apll;
  491. unsigned long mpll;
  492. unsigned int ptr;
  493. u32 clkdiv0;
  494. printk(KERN_DEBUG "%s: registering clocks\n", __func__);
  495. clkdiv0 = __raw_readl(S3C_CLK_DIV0);
  496. printk(KERN_DEBUG "%s: clkdiv0 = %08x\n", __func__, clkdiv0);
  497. xtal_clk = clk_get(NULL, "xtal");
  498. BUG_ON(IS_ERR(xtal_clk));
  499. xtal = clk_get_rate(xtal_clk);
  500. clk_put(xtal_clk);
  501. printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
  502. epll = s3c6400_get_epll(xtal);
  503. mpll = s3c6400_get_pll(xtal, __raw_readl(S3C_MPLL_CON));
  504. apll = s3c6400_get_pll(xtal, __raw_readl(S3C_APLL_CON));
  505. fclk = mpll;
  506. printk(KERN_INFO "S3C64XX: PLL settings, A=%ld, M=%ld, E=%ld\n",
  507. apll, mpll, epll);
  508. hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2);
  509. hclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK);
  510. pclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_PCLK);
  511. printk(KERN_INFO "S3C64XX: HCLK2=%ld, HCLK=%ld, PCLK=%ld\n",
  512. hclk2, hclk, pclk);
  513. clk_fout_mpll.rate = mpll;
  514. clk_fout_epll.rate = epll;
  515. clk_fout_apll.rate = apll;
  516. clk_h.rate = hclk;
  517. clk_p.rate = pclk;
  518. clk_f.rate = fclk;
  519. for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
  520. s3c6400_set_clksrc(init_parents[ptr]);
  521. }
  522. static struct clk *clks[] __initdata = {
  523. &clk_ext_xtal_mux,
  524. &clk_iis_cd0,
  525. &clk_iis_cd1,
  526. &clk_pcm_cd,
  527. &clk_mout_epll.clk,
  528. &clk_fout_epll,
  529. &clk_mout_mpll.clk,
  530. &clk_dout_mpll,
  531. &clk_mmc0.clk,
  532. &clk_mmc1.clk,
  533. &clk_mmc2.clk,
  534. &clk_usbhost.clk,
  535. &clk_uart_uclk1.clk,
  536. &clk_spi0.clk,
  537. &clk_spi1.clk,
  538. &clk_audio0.clk,
  539. &clk_audio1.clk,
  540. &clk_irda.clk,
  541. };
  542. void __init s3c6400_register_clocks(void)
  543. {
  544. struct clk *clkp;
  545. int ret;
  546. int ptr;
  547. for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
  548. clkp = clks[ptr];
  549. ret = s3c24xx_register_clock(clkp);
  550. if (ret < 0) {
  551. printk(KERN_ERR "Failed to register clock %s (%d)\n",
  552. clkp->name, ret);
  553. }
  554. }
  555. clk_mpll.parent = &clk_mout_mpll.clk;
  556. clk_epll.parent = &clk_mout_epll.clk;
  557. }