s3c6400-clock.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  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. 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. 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. 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. 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. 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. 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. 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_mout_epll.clk,
  158. &clk_dout_mpll,
  159. &clk_fin_epll,
  160. &clk_48m,
  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. val = __raw_readl(reg);
  199. val &= ~sclk->mask;
  200. val |= (rate - 1) << sclk->shift;
  201. __raw_writel(val, reg);
  202. return 0;
  203. }
  204. static int s3c64xx_setparent_clksrc(struct clk *clk, struct clk *parent)
  205. {
  206. struct clksrc_clk *sclk = to_clksrc(clk);
  207. struct clk_sources *srcs = sclk->sources;
  208. u32 clksrc = __raw_readl(S3C_CLK_SRC);
  209. int src_nr = -1;
  210. int ptr;
  211. for (ptr = 0; ptr < srcs->nr_sources; ptr++)
  212. if (srcs->sources[ptr] == parent) {
  213. src_nr = ptr;
  214. break;
  215. }
  216. if (src_nr >= 0) {
  217. clksrc &= ~sclk->mask;
  218. clksrc |= src_nr << sclk->shift;
  219. __raw_writel(clksrc, S3C_CLK_SRC);
  220. return 0;
  221. }
  222. return -EINVAL;
  223. }
  224. static unsigned long s3c64xx_roundrate_clksrc(struct clk *clk,
  225. unsigned long rate)
  226. {
  227. unsigned long parent_rate = clk_get_rate(clk->parent);
  228. int div;
  229. if (rate > parent_rate)
  230. rate = parent_rate;
  231. else {
  232. div = rate / parent_rate;
  233. if (div == 0)
  234. div = 1;
  235. if (div > 16)
  236. div = 16;
  237. rate = parent_rate / div;
  238. }
  239. return rate;
  240. }
  241. static struct clksrc_clk clk_mmc0 = {
  242. .clk = {
  243. .name = "mmc_bus",
  244. .id = 0,
  245. .ctrlbit = S3C_CLKCON_SCLK_MMC0,
  246. .enable = s3c64xx_sclk_ctrl,
  247. .set_parent = s3c64xx_setparent_clksrc,
  248. .get_rate = s3c64xx_getrate_clksrc,
  249. .set_rate = s3c64xx_setrate_clksrc,
  250. .round_rate = s3c64xx_roundrate_clksrc,
  251. },
  252. .shift = S3C6400_CLKSRC_MMC0_SHIFT,
  253. .mask = S3C6400_CLKSRC_MMC0_MASK,
  254. .sources = &clkset_spi_mmc,
  255. .divider_shift = S3C6400_CLKDIV1_MMC0_SHIFT,
  256. .reg_divider = S3C_CLK_DIV1,
  257. };
  258. static struct clksrc_clk clk_mmc1 = {
  259. .clk = {
  260. .name = "mmc_bus",
  261. .id = 1,
  262. .ctrlbit = S3C_CLKCON_SCLK_MMC1,
  263. .enable = s3c64xx_sclk_ctrl,
  264. .get_rate = s3c64xx_getrate_clksrc,
  265. .set_rate = s3c64xx_setrate_clksrc,
  266. .set_parent = s3c64xx_setparent_clksrc,
  267. .round_rate = s3c64xx_roundrate_clksrc,
  268. },
  269. .shift = S3C6400_CLKSRC_MMC1_SHIFT,
  270. .mask = S3C6400_CLKSRC_MMC1_MASK,
  271. .sources = &clkset_spi_mmc,
  272. .divider_shift = S3C6400_CLKDIV1_MMC1_SHIFT,
  273. .reg_divider = S3C_CLK_DIV1,
  274. };
  275. static struct clksrc_clk clk_mmc2 = {
  276. .clk = {
  277. .name = "mmc_bus",
  278. .id = 2,
  279. .ctrlbit = S3C_CLKCON_SCLK_MMC2,
  280. .enable = s3c64xx_sclk_ctrl,
  281. .get_rate = s3c64xx_getrate_clksrc,
  282. .set_rate = s3c64xx_setrate_clksrc,
  283. .set_parent = s3c64xx_setparent_clksrc,
  284. .round_rate = s3c64xx_roundrate_clksrc,
  285. },
  286. .shift = S3C6400_CLKSRC_MMC2_SHIFT,
  287. .mask = S3C6400_CLKSRC_MMC2_MASK,
  288. .sources = &clkset_spi_mmc,
  289. .divider_shift = S3C6400_CLKDIV1_MMC2_SHIFT,
  290. .reg_divider = S3C_CLK_DIV1,
  291. };
  292. static struct clksrc_clk clk_usbhost = {
  293. .clk = {
  294. .name = "usb-host-bus",
  295. .id = -1,
  296. .ctrlbit = S3C_CLKCON_SCLK_UHOST,
  297. .enable = s3c64xx_sclk_ctrl,
  298. .set_parent = s3c64xx_setparent_clksrc,
  299. .get_rate = s3c64xx_getrate_clksrc,
  300. .set_rate = s3c64xx_setrate_clksrc,
  301. .round_rate = s3c64xx_roundrate_clksrc,
  302. },
  303. .shift = S3C6400_CLKSRC_UHOST_SHIFT,
  304. .mask = S3C6400_CLKSRC_UHOST_MASK,
  305. .sources = &clkset_uhost,
  306. .divider_shift = S3C6400_CLKDIV1_UHOST_SHIFT,
  307. .reg_divider = S3C_CLK_DIV1,
  308. };
  309. static struct clksrc_clk clk_uart_uclk1 = {
  310. .clk = {
  311. .name = "uclk1",
  312. .id = -1,
  313. .ctrlbit = S3C_CLKCON_SCLK_UART,
  314. .enable = s3c64xx_sclk_ctrl,
  315. .set_parent = s3c64xx_setparent_clksrc,
  316. .get_rate = s3c64xx_getrate_clksrc,
  317. .set_rate = s3c64xx_setrate_clksrc,
  318. .round_rate = s3c64xx_roundrate_clksrc,
  319. },
  320. .shift = S3C6400_CLKSRC_UART_SHIFT,
  321. .mask = S3C6400_CLKSRC_UART_MASK,
  322. .sources = &clkset_uart,
  323. .divider_shift = S3C6400_CLKDIV2_UART_SHIFT,
  324. .reg_divider = S3C_CLK_DIV2,
  325. };
  326. /* Where does UCLK0 come from? */
  327. static struct clksrc_clk clk_spi0 = {
  328. .clk = {
  329. .name = "spi-bus",
  330. .id = 0,
  331. .ctrlbit = S3C_CLKCON_SCLK_SPI0,
  332. .enable = s3c64xx_sclk_ctrl,
  333. .set_parent = s3c64xx_setparent_clksrc,
  334. .get_rate = s3c64xx_getrate_clksrc,
  335. .set_rate = s3c64xx_setrate_clksrc,
  336. .round_rate = s3c64xx_roundrate_clksrc,
  337. },
  338. .shift = S3C6400_CLKSRC_SPI0_SHIFT,
  339. .mask = S3C6400_CLKSRC_SPI0_MASK,
  340. .sources = &clkset_spi_mmc,
  341. .divider_shift = S3C6400_CLKDIV2_SPI0_SHIFT,
  342. .reg_divider = S3C_CLK_DIV2,
  343. };
  344. static struct clksrc_clk clk_spi1 = {
  345. .clk = {
  346. .name = "spi-bus",
  347. .id = 1,
  348. .ctrlbit = S3C_CLKCON_SCLK_SPI1,
  349. .enable = s3c64xx_sclk_ctrl,
  350. .set_parent = s3c64xx_setparent_clksrc,
  351. .get_rate = s3c64xx_getrate_clksrc,
  352. .set_rate = s3c64xx_setrate_clksrc,
  353. .round_rate = s3c64xx_roundrate_clksrc,
  354. },
  355. .shift = S3C6400_CLKSRC_SPI1_SHIFT,
  356. .mask = S3C6400_CLKSRC_SPI1_MASK,
  357. .sources = &clkset_spi_mmc,
  358. .divider_shift = S3C6400_CLKDIV2_SPI1_SHIFT,
  359. .reg_divider = S3C_CLK_DIV2,
  360. };
  361. static struct clk clk_iis_cd0 = {
  362. .name = "iis_cdclk0",
  363. .id = -1,
  364. };
  365. static struct clk clk_iis_cd1 = {
  366. .name = "iis_cdclk1",
  367. .id = -1,
  368. };
  369. static struct clk clk_pcm_cd = {
  370. .name = "pcm_cdclk",
  371. .id = -1,
  372. };
  373. static struct clk *clkset_audio0_list[] = {
  374. [0] = &clk_mout_epll.clk,
  375. [1] = &clk_dout_mpll,
  376. [2] = &clk_fin_epll,
  377. [3] = &clk_iis_cd0,
  378. [4] = &clk_pcm_cd,
  379. };
  380. static struct clk_sources clkset_audio0 = {
  381. .sources = clkset_audio0_list,
  382. .nr_sources = ARRAY_SIZE(clkset_audio0_list),
  383. };
  384. static struct clksrc_clk clk_audio0 = {
  385. .clk = {
  386. .name = "audio-bus",
  387. .id = 0,
  388. .ctrlbit = S3C_CLKCON_SCLK_AUDIO0,
  389. .enable = s3c64xx_sclk_ctrl,
  390. .set_parent = s3c64xx_setparent_clksrc,
  391. .get_rate = s3c64xx_getrate_clksrc,
  392. .set_rate = s3c64xx_setrate_clksrc,
  393. .round_rate = s3c64xx_roundrate_clksrc,
  394. },
  395. .shift = S3C6400_CLKSRC_AUDIO0_SHIFT,
  396. .mask = S3C6400_CLKSRC_AUDIO0_MASK,
  397. .sources = &clkset_audio0,
  398. .divider_shift = S3C6400_CLKDIV2_AUDIO0_SHIFT,
  399. .reg_divider = S3C_CLK_DIV2,
  400. };
  401. static struct clk *clkset_audio1_list[] = {
  402. [0] = &clk_mout_epll.clk,
  403. [1] = &clk_dout_mpll,
  404. [2] = &clk_fin_epll,
  405. [3] = &clk_iis_cd1,
  406. [4] = &clk_pcm_cd,
  407. };
  408. static struct clk_sources clkset_audio1 = {
  409. .sources = clkset_audio1_list,
  410. .nr_sources = ARRAY_SIZE(clkset_audio1_list),
  411. };
  412. static struct clksrc_clk clk_audio1 = {
  413. .clk = {
  414. .name = "audio-bus",
  415. .id = 1,
  416. .ctrlbit = S3C_CLKCON_SCLK_AUDIO1,
  417. .enable = s3c64xx_sclk_ctrl,
  418. .set_parent = s3c64xx_setparent_clksrc,
  419. .get_rate = s3c64xx_getrate_clksrc,
  420. .set_rate = s3c64xx_setrate_clksrc,
  421. .round_rate = s3c64xx_roundrate_clksrc,
  422. },
  423. .shift = S3C6400_CLKSRC_AUDIO1_SHIFT,
  424. .mask = S3C6400_CLKSRC_AUDIO1_MASK,
  425. .sources = &clkset_audio1,
  426. .divider_shift = S3C6400_CLKDIV2_AUDIO1_SHIFT,
  427. .reg_divider = S3C_CLK_DIV2,
  428. };
  429. static struct clksrc_clk clk_irda = {
  430. .clk = {
  431. .name = "irda-bus",
  432. .id = 0,
  433. .ctrlbit = S3C_CLKCON_SCLK_IRDA,
  434. .enable = s3c64xx_sclk_ctrl,
  435. .set_parent = s3c64xx_setparent_clksrc,
  436. .get_rate = s3c64xx_getrate_clksrc,
  437. .set_rate = s3c64xx_setrate_clksrc,
  438. .round_rate = s3c64xx_roundrate_clksrc,
  439. },
  440. .shift = S3C6400_CLKSRC_IRDA_SHIFT,
  441. .mask = S3C6400_CLKSRC_IRDA_MASK,
  442. .sources = &clkset_irda,
  443. .divider_shift = S3C6400_CLKDIV2_IRDA_SHIFT,
  444. .reg_divider = S3C_CLK_DIV2,
  445. };
  446. /* Clock initialisation code */
  447. static struct clksrc_clk *init_parents[] = {
  448. &clk_mout_apll,
  449. &clk_mout_epll,
  450. &clk_mout_mpll,
  451. &clk_mmc0,
  452. &clk_mmc1,
  453. &clk_mmc2,
  454. &clk_usbhost,
  455. &clk_uart_uclk1,
  456. &clk_spi0,
  457. &clk_spi1,
  458. &clk_audio0,
  459. &clk_audio1,
  460. &clk_irda,
  461. };
  462. static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk)
  463. {
  464. struct clk_sources *srcs = clk->sources;
  465. u32 clksrc = __raw_readl(S3C_CLK_SRC);
  466. clksrc &= clk->mask;
  467. clksrc >>= clk->shift;
  468. if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
  469. printk(KERN_ERR "%s: bad source %d\n",
  470. clk->clk.name, clksrc);
  471. return;
  472. }
  473. clk->clk.parent = srcs->sources[clksrc];
  474. printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
  475. clk->clk.name, clk->clk.parent->name, clksrc,
  476. clk_get_rate(&clk->clk));
  477. }
  478. #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
  479. void __init_or_cpufreq s3c6400_setup_clocks(void)
  480. {
  481. struct clk *xtal_clk;
  482. unsigned long xtal;
  483. unsigned long fclk;
  484. unsigned long hclk;
  485. unsigned long hclk2;
  486. unsigned long pclk;
  487. unsigned long epll;
  488. unsigned long apll;
  489. unsigned long mpll;
  490. unsigned int ptr;
  491. u32 clkdiv0;
  492. printk(KERN_DEBUG "%s: registering clocks\n", __func__);
  493. clkdiv0 = __raw_readl(S3C_CLK_DIV0);
  494. printk(KERN_DEBUG "%s: clkdiv0 = %08x\n", __func__, clkdiv0);
  495. xtal_clk = clk_get(NULL, "xtal");
  496. BUG_ON(IS_ERR(xtal_clk));
  497. xtal = clk_get_rate(xtal_clk);
  498. clk_put(xtal_clk);
  499. printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
  500. epll = s3c6400_get_epll(xtal);
  501. mpll = s3c6400_get_pll(xtal, __raw_readl(S3C_MPLL_CON));
  502. apll = s3c6400_get_pll(xtal, __raw_readl(S3C_APLL_CON));
  503. fclk = mpll;
  504. printk(KERN_INFO "S3C64XX: PLL settings, A=%ld, M=%ld, E=%ld\n",
  505. apll, mpll, epll);
  506. hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2);
  507. hclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK);
  508. pclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_PCLK);
  509. printk(KERN_INFO "S3C64XX: HCLK2=%ld, HCLK=%ld, PCLK=%ld\n",
  510. hclk2, hclk, pclk);
  511. clk_fout_mpll.rate = mpll;
  512. clk_fout_epll.rate = epll;
  513. clk_fout_apll.rate = apll;
  514. clk_h.rate = hclk;
  515. clk_p.rate = pclk;
  516. clk_f.rate = fclk;
  517. for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
  518. s3c6400_set_clksrc(init_parents[ptr]);
  519. }
  520. static struct clk *clks[] __initdata = {
  521. &clk_ext_xtal_mux,
  522. &clk_iis_cd0,
  523. &clk_iis_cd1,
  524. &clk_pcm_cd,
  525. &clk_mout_epll.clk,
  526. &clk_fout_epll,
  527. &clk_mout_mpll.clk,
  528. &clk_dout_mpll,
  529. &clk_mmc0.clk,
  530. &clk_mmc1.clk,
  531. &clk_mmc2.clk,
  532. &clk_usbhost.clk,
  533. &clk_uart_uclk1.clk,
  534. &clk_spi0.clk,
  535. &clk_spi1.clk,
  536. &clk_audio0.clk,
  537. &clk_audio1.clk,
  538. &clk_irda.clk,
  539. };
  540. void __init s3c6400_register_clocks(void)
  541. {
  542. struct clk *clkp;
  543. int ret;
  544. int ptr;
  545. for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
  546. clkp = clks[ptr];
  547. ret = s3c24xx_register_clock(clkp);
  548. if (ret < 0) {
  549. printk(KERN_ERR "Failed to register clock %s (%d)\n",
  550. clkp->name, ret);
  551. }
  552. }
  553. clk_mpll.parent = &clk_mout_mpll.clk;
  554. clk_epll.parent = &clk_mout_epll.clk;
  555. }