s5pc100-clock.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144
  1. /* linux/arch/arm/plat-s5pc1xx/s5pc100-clock.c
  2. *
  3. * Copyright 2009 Samsung Electronics, Co.
  4. * Byungho Min <bhmin@samsung.com>
  5. *
  6. * S5PC100 based common clock support
  7. *
  8. * Based on plat-s3c64xx/s3c6400-clock.c
  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. #include <plat/devs.h>
  31. #include <plat/s5pc100.h>
  32. /* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
  33. * ext_xtal_mux for want of an actual name from the manual.
  34. */
  35. static struct clk clk_ext_xtal_mux = {
  36. .name = "ext_xtal",
  37. .id = -1,
  38. };
  39. #define clk_fin_apll clk_ext_xtal_mux
  40. #define clk_fin_mpll clk_ext_xtal_mux
  41. #define clk_fin_epll clk_ext_xtal_mux
  42. #define clk_fin_hpll clk_ext_xtal_mux
  43. #define clk_fout_mpll clk_mpll
  44. #define clk_vclk_54m clk_54m
  45. struct clk_sources {
  46. unsigned int nr_sources;
  47. struct clk **sources;
  48. };
  49. struct clksrc_clk {
  50. struct clk clk;
  51. unsigned int mask;
  52. unsigned int shift;
  53. struct clk_sources *sources;
  54. unsigned int divider_shift;
  55. void __iomem *reg_divider;
  56. void __iomem *reg_source;
  57. };
  58. /* APLL */
  59. static struct clk clk_fout_apll = {
  60. .name = "fout_apll",
  61. .id = -1,
  62. .rate = 27000000,
  63. };
  64. static struct clk *clk_src_apll_list[] = {
  65. [0] = &clk_fin_apll,
  66. [1] = &clk_fout_apll,
  67. };
  68. static struct clk_sources clk_src_apll = {
  69. .sources = clk_src_apll_list,
  70. .nr_sources = ARRAY_SIZE(clk_src_apll_list),
  71. };
  72. static struct clksrc_clk clk_mout_apll = {
  73. .clk = {
  74. .name = "mout_apll",
  75. .id = -1,
  76. },
  77. .shift = S5PC100_CLKSRC0_APLL_SHIFT,
  78. .mask = S5PC100_CLKSRC0_APLL_MASK,
  79. .sources = &clk_src_apll,
  80. .reg_source = S5PC100_CLKSRC0,
  81. };
  82. static unsigned long s5pc100_clk_dout_apll_get_rate(struct clk *clk)
  83. {
  84. unsigned long rate = clk_get_rate(clk->parent);
  85. unsigned int ratio;
  86. ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_APLL_MASK;
  87. ratio >>= S5PC100_CLKDIV0_APLL_SHIFT;
  88. return rate / (ratio + 1);
  89. }
  90. static struct clk clk_dout_apll = {
  91. .name = "dout_apll",
  92. .id = -1,
  93. .parent = &clk_mout_apll.clk,
  94. .get_rate = s5pc100_clk_dout_apll_get_rate,
  95. };
  96. static unsigned long s5pc100_clk_arm_get_rate(struct clk *clk)
  97. {
  98. unsigned long rate = clk_get_rate(clk->parent);
  99. unsigned int ratio;
  100. ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_ARM_MASK;
  101. ratio >>= S5PC100_CLKDIV0_ARM_SHIFT;
  102. return rate / (ratio + 1);
  103. }
  104. static unsigned long s5pc100_clk_arm_round_rate(struct clk *clk,
  105. unsigned long rate)
  106. {
  107. unsigned long parent = clk_get_rate(clk->parent);
  108. u32 div;
  109. if (parent < rate)
  110. return rate;
  111. div = (parent / rate) - 1;
  112. if (div > S5PC100_CLKDIV0_ARM_MASK)
  113. div = S5PC100_CLKDIV0_ARM_MASK;
  114. return parent / (div + 1);
  115. }
  116. static int s5pc100_clk_arm_set_rate(struct clk *clk, unsigned long rate)
  117. {
  118. unsigned long parent = clk_get_rate(clk->parent);
  119. u32 div;
  120. u32 val;
  121. if (rate < parent / (S5PC100_CLKDIV0_ARM_MASK + 1))
  122. return -EINVAL;
  123. rate = clk_round_rate(clk, rate);
  124. div = clk_get_rate(clk->parent) / rate;
  125. val = __raw_readl(S5PC100_CLKDIV0);
  126. val &= S5PC100_CLKDIV0_ARM_MASK;
  127. val |= (div - 1);
  128. __raw_writel(val, S5PC100_CLKDIV0);
  129. return 0;
  130. }
  131. static struct clk clk_arm = {
  132. .name = "armclk",
  133. .id = -1,
  134. .parent = &clk_dout_apll,
  135. .get_rate = s5pc100_clk_arm_get_rate,
  136. .set_rate = s5pc100_clk_arm_set_rate,
  137. .round_rate = s5pc100_clk_arm_round_rate,
  138. };
  139. static unsigned long s5pc100_clk_dout_d0_bus_get_rate(struct clk *clk)
  140. {
  141. unsigned long rate = clk_get_rate(clk->parent);
  142. unsigned int ratio;
  143. ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_D0_MASK;
  144. ratio >>= S5PC100_CLKDIV0_D0_SHIFT;
  145. return rate / (ratio + 1);
  146. }
  147. static struct clk clk_dout_d0_bus = {
  148. .name = "dout_d0_bus",
  149. .id = -1,
  150. .parent = &clk_arm,
  151. .get_rate = s5pc100_clk_dout_d0_bus_get_rate,
  152. };
  153. static unsigned long s5pc100_clk_dout_pclkd0_get_rate(struct clk *clk)
  154. {
  155. unsigned long rate = clk_get_rate(clk->parent);
  156. unsigned int ratio;
  157. ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_PCLKD0_MASK;
  158. ratio >>= S5PC100_CLKDIV0_PCLKD0_SHIFT;
  159. return rate / (ratio + 1);
  160. }
  161. static struct clk clk_dout_pclkd0 = {
  162. .name = "dout_pclkd0",
  163. .id = -1,
  164. .parent = &clk_dout_d0_bus,
  165. .get_rate = s5pc100_clk_dout_pclkd0_get_rate,
  166. };
  167. static unsigned long s5pc100_clk_dout_apll2_get_rate(struct clk *clk)
  168. {
  169. unsigned long rate = clk_get_rate(clk->parent);
  170. unsigned int ratio;
  171. ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_APLL2_MASK;
  172. ratio >>= S5PC100_CLKDIV1_APLL2_SHIFT;
  173. return rate / (ratio + 1);
  174. }
  175. static struct clk clk_dout_apll2 = {
  176. .name = "dout_apll2",
  177. .id = -1,
  178. .parent = &clk_mout_apll.clk,
  179. .get_rate = s5pc100_clk_dout_apll2_get_rate,
  180. };
  181. /* MPLL */
  182. static struct clk *clk_src_mpll_list[] = {
  183. [0] = &clk_fin_mpll,
  184. [1] = &clk_fout_mpll,
  185. };
  186. static struct clk_sources clk_src_mpll = {
  187. .sources = clk_src_mpll_list,
  188. .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
  189. };
  190. static struct clksrc_clk clk_mout_mpll = {
  191. .clk = {
  192. .name = "mout_mpll",
  193. .id = -1,
  194. },
  195. .shift = S5PC100_CLKSRC0_MPLL_SHIFT,
  196. .mask = S5PC100_CLKSRC0_MPLL_MASK,
  197. .sources = &clk_src_mpll,
  198. .reg_source = S5PC100_CLKSRC0,
  199. };
  200. static struct clk *clkset_am_list[] = {
  201. [0] = &clk_mout_mpll.clk,
  202. [1] = &clk_dout_apll2,
  203. };
  204. static struct clk_sources clk_src_am = {
  205. .sources = clkset_am_list,
  206. .nr_sources = ARRAY_SIZE(clkset_am_list),
  207. };
  208. static struct clksrc_clk clk_mout_am = {
  209. .clk = {
  210. .name = "mout_am",
  211. .id = -1,
  212. },
  213. .shift = S5PC100_CLKSRC0_AMMUX_SHIFT,
  214. .mask = S5PC100_CLKSRC0_AMMUX_MASK,
  215. .sources = &clk_src_am,
  216. .reg_source = S5PC100_CLKSRC0,
  217. };
  218. static unsigned long s5pc100_clk_dout_d1_bus_get_rate(struct clk *clk)
  219. {
  220. unsigned long rate = clk_get_rate(clk->parent);
  221. unsigned int ratio;
  222. printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
  223. ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_D1_MASK;
  224. ratio >>= S5PC100_CLKDIV1_D1_SHIFT;
  225. return rate / (ratio + 1);
  226. }
  227. static struct clk clk_dout_d1_bus = {
  228. .name = "dout_d1_bus",
  229. .id = -1,
  230. .parent = &clk_mout_am.clk,
  231. .get_rate = s5pc100_clk_dout_d1_bus_get_rate,
  232. };
  233. static struct clk *clkset_onenand_list[] = {
  234. [0] = &clk_dout_d0_bus,
  235. [1] = &clk_dout_d1_bus,
  236. };
  237. static struct clk_sources clk_src_onenand = {
  238. .sources = clkset_onenand_list,
  239. .nr_sources = ARRAY_SIZE(clkset_onenand_list),
  240. };
  241. static struct clksrc_clk clk_mout_onenand = {
  242. .clk = {
  243. .name = "mout_onenand",
  244. .id = -1,
  245. },
  246. .shift = S5PC100_CLKSRC0_ONENAND_SHIFT,
  247. .mask = S5PC100_CLKSRC0_ONENAND_MASK,
  248. .sources = &clk_src_onenand,
  249. .reg_source = S5PC100_CLKSRC0,
  250. };
  251. static unsigned long s5pc100_clk_dout_pclkd1_get_rate(struct clk *clk)
  252. {
  253. unsigned long rate = clk_get_rate(clk->parent);
  254. unsigned int ratio;
  255. printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
  256. ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_PCLKD1_MASK;
  257. ratio >>= S5PC100_CLKDIV1_PCLKD1_SHIFT;
  258. return rate / (ratio + 1);
  259. }
  260. static struct clk clk_dout_pclkd1 = {
  261. .name = "dout_pclkd1",
  262. .id = -1,
  263. .parent = &clk_dout_d1_bus,
  264. .get_rate = s5pc100_clk_dout_pclkd1_get_rate,
  265. };
  266. static unsigned long s5pc100_clk_dout_mpll2_get_rate(struct clk *clk)
  267. {
  268. unsigned long rate = clk_get_rate(clk->parent);
  269. unsigned int ratio;
  270. printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
  271. ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL2_MASK;
  272. ratio >>= S5PC100_CLKDIV1_MPLL2_SHIFT;
  273. return rate / (ratio + 1);
  274. }
  275. static struct clk clk_dout_mpll2 = {
  276. .name = "dout_mpll2",
  277. .id = -1,
  278. .parent = &clk_mout_am.clk,
  279. .get_rate = s5pc100_clk_dout_mpll2_get_rate,
  280. };
  281. static unsigned long s5pc100_clk_dout_cam_get_rate(struct clk *clk)
  282. {
  283. unsigned long rate = clk_get_rate(clk->parent);
  284. unsigned int ratio;
  285. printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
  286. ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_CAM_MASK;
  287. ratio >>= S5PC100_CLKDIV1_CAM_SHIFT;
  288. return rate / (ratio + 1);
  289. }
  290. static struct clk clk_dout_cam = {
  291. .name = "dout_cam",
  292. .id = -1,
  293. .parent = &clk_dout_mpll2,
  294. .get_rate = s5pc100_clk_dout_cam_get_rate,
  295. };
  296. static unsigned long s5pc100_clk_dout_mpll_get_rate(struct clk *clk)
  297. {
  298. unsigned long rate = clk_get_rate(clk->parent);
  299. unsigned int ratio;
  300. printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
  301. ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL_MASK;
  302. ratio >>= S5PC100_CLKDIV1_MPLL_SHIFT;
  303. return rate / (ratio + 1);
  304. }
  305. static struct clk clk_dout_mpll = {
  306. .name = "dout_mpll",
  307. .id = -1,
  308. .parent = &clk_mout_am.clk,
  309. .get_rate = s5pc100_clk_dout_mpll_get_rate,
  310. };
  311. /* EPLL */
  312. static struct clk clk_fout_epll = {
  313. .name = "fout_epll",
  314. .id = -1,
  315. };
  316. static struct clk *clk_src_epll_list[] = {
  317. [0] = &clk_fin_epll,
  318. [1] = &clk_fout_epll,
  319. };
  320. static struct clk_sources clk_src_epll = {
  321. .sources = clk_src_epll_list,
  322. .nr_sources = ARRAY_SIZE(clk_src_epll_list),
  323. };
  324. static struct clksrc_clk clk_mout_epll = {
  325. .clk = {
  326. .name = "mout_epll",
  327. .id = -1,
  328. },
  329. .shift = S5PC100_CLKSRC0_EPLL_SHIFT,
  330. .mask = S5PC100_CLKSRC0_EPLL_MASK,
  331. .sources = &clk_src_epll,
  332. .reg_source = S5PC100_CLKSRC0,
  333. };
  334. /* HPLL */
  335. static struct clk clk_fout_hpll = {
  336. .name = "fout_hpll",
  337. .id = -1,
  338. };
  339. static struct clk *clk_src_hpll_list[] = {
  340. [0] = &clk_27m,
  341. [1] = &clk_fout_hpll,
  342. };
  343. static struct clk_sources clk_src_hpll = {
  344. .sources = clk_src_hpll_list,
  345. .nr_sources = ARRAY_SIZE(clk_src_hpll_list),
  346. };
  347. static struct clksrc_clk clk_mout_hpll = {
  348. .clk = {
  349. .name = "mout_hpll",
  350. .id = -1,
  351. },
  352. .shift = S5PC100_CLKSRC0_HPLL_SHIFT,
  353. .mask = S5PC100_CLKSRC0_HPLL_MASK,
  354. .sources = &clk_src_hpll,
  355. .reg_source = S5PC100_CLKSRC0,
  356. };
  357. /* Peripherals */
  358. /*
  359. * The peripheral clocks are all controlled via clocksource followed
  360. * by an optional divider and gate stage. We currently roll this into
  361. * one clock which hides the intermediate clock from the mux.
  362. *
  363. * Note, the JPEG clock can only be an even divider...
  364. *
  365. * The scaler and LCD clocks depend on the S5PC100 version, and also
  366. * have a common parent divisor so are not included here.
  367. */
  368. static inline struct clksrc_clk *to_clksrc(struct clk *clk)
  369. {
  370. return container_of(clk, struct clksrc_clk, clk);
  371. }
  372. static unsigned long s5pc100_getrate_clksrc(struct clk *clk)
  373. {
  374. struct clksrc_clk *sclk = to_clksrc(clk);
  375. unsigned long rate = clk_get_rate(clk->parent);
  376. u32 clkdiv = __raw_readl(sclk->reg_divider);
  377. clkdiv >>= sclk->divider_shift;
  378. clkdiv &= 0xf;
  379. clkdiv++;
  380. rate /= clkdiv;
  381. return rate;
  382. }
  383. static int s5pc100_setrate_clksrc(struct clk *clk, unsigned long rate)
  384. {
  385. struct clksrc_clk *sclk = to_clksrc(clk);
  386. void __iomem *reg = sclk->reg_divider;
  387. unsigned int div;
  388. u32 val;
  389. rate = clk_round_rate(clk, rate);
  390. div = clk_get_rate(clk->parent) / rate;
  391. if (div > 16)
  392. return -EINVAL;
  393. val = __raw_readl(reg);
  394. val &= ~(0xf << sclk->divider_shift);
  395. val |= (div - 1) << sclk->divider_shift;
  396. __raw_writel(val, reg);
  397. return 0;
  398. }
  399. static int s5pc100_setparent_clksrc(struct clk *clk, struct clk *parent)
  400. {
  401. struct clksrc_clk *sclk = to_clksrc(clk);
  402. struct clk_sources *srcs = sclk->sources;
  403. u32 clksrc = __raw_readl(sclk->reg_source);
  404. int src_nr = -1;
  405. int ptr;
  406. for (ptr = 0; ptr < srcs->nr_sources; ptr++)
  407. if (srcs->sources[ptr] == parent) {
  408. src_nr = ptr;
  409. break;
  410. }
  411. if (src_nr >= 0) {
  412. clksrc &= ~sclk->mask;
  413. clksrc |= src_nr << sclk->shift;
  414. __raw_writel(clksrc, sclk->reg_source);
  415. return 0;
  416. }
  417. return -EINVAL;
  418. }
  419. static unsigned long s5pc100_roundrate_clksrc(struct clk *clk,
  420. unsigned long rate)
  421. {
  422. unsigned long parent_rate = clk_get_rate(clk->parent);
  423. int div;
  424. if (rate > parent_rate)
  425. rate = parent_rate;
  426. else {
  427. div = rate / parent_rate;
  428. if (div == 0)
  429. div = 1;
  430. if (div > 16)
  431. div = 16;
  432. rate = parent_rate / div;
  433. }
  434. return rate;
  435. }
  436. static struct clk *clkset_spi_list[] = {
  437. &clk_mout_epll.clk,
  438. &clk_dout_mpll2,
  439. &clk_fin_epll,
  440. &clk_mout_hpll.clk,
  441. };
  442. static struct clk_sources clkset_spi = {
  443. .sources = clkset_spi_list,
  444. .nr_sources = ARRAY_SIZE(clkset_spi_list),
  445. };
  446. static struct clksrc_clk clk_spi0 = {
  447. .clk = {
  448. .name = "spi_bus",
  449. .id = 0,
  450. .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0,
  451. .enable = s5pc100_sclk0_ctrl,
  452. .set_parent = s5pc100_setparent_clksrc,
  453. .get_rate = s5pc100_getrate_clksrc,
  454. .set_rate = s5pc100_setrate_clksrc,
  455. .round_rate = s5pc100_roundrate_clksrc,
  456. },
  457. .shift = S5PC100_CLKSRC1_SPI0_SHIFT,
  458. .mask = S5PC100_CLKSRC1_SPI0_MASK,
  459. .sources = &clkset_spi,
  460. .divider_shift = S5PC100_CLKDIV2_SPI0_SHIFT,
  461. .reg_divider = S5PC100_CLKDIV2,
  462. .reg_source = S5PC100_CLKSRC1,
  463. };
  464. static struct clksrc_clk clk_spi1 = {
  465. .clk = {
  466. .name = "spi_bus",
  467. .id = 1,
  468. .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1,
  469. .enable = s5pc100_sclk0_ctrl,
  470. .set_parent = s5pc100_setparent_clksrc,
  471. .get_rate = s5pc100_getrate_clksrc,
  472. .set_rate = s5pc100_setrate_clksrc,
  473. .round_rate = s5pc100_roundrate_clksrc,
  474. },
  475. .shift = S5PC100_CLKSRC1_SPI1_SHIFT,
  476. .mask = S5PC100_CLKSRC1_SPI1_MASK,
  477. .sources = &clkset_spi,
  478. .divider_shift = S5PC100_CLKDIV2_SPI1_SHIFT,
  479. .reg_divider = S5PC100_CLKDIV2,
  480. .reg_source = S5PC100_CLKSRC1,
  481. };
  482. static struct clksrc_clk clk_spi2 = {
  483. .clk = {
  484. .name = "spi_bus",
  485. .id = 2,
  486. .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2,
  487. .enable = s5pc100_sclk0_ctrl,
  488. .set_parent = s5pc100_setparent_clksrc,
  489. .get_rate = s5pc100_getrate_clksrc,
  490. .set_rate = s5pc100_setrate_clksrc,
  491. .round_rate = s5pc100_roundrate_clksrc,
  492. },
  493. .shift = S5PC100_CLKSRC1_SPI2_SHIFT,
  494. .mask = S5PC100_CLKSRC1_SPI2_MASK,
  495. .sources = &clkset_spi,
  496. .divider_shift = S5PC100_CLKDIV2_SPI2_SHIFT,
  497. .reg_divider = S5PC100_CLKDIV2,
  498. .reg_source = S5PC100_CLKSRC1,
  499. };
  500. static struct clk *clkset_uart_list[] = {
  501. &clk_mout_epll.clk,
  502. &clk_dout_mpll,
  503. };
  504. static struct clk_sources clkset_uart = {
  505. .sources = clkset_uart_list,
  506. .nr_sources = ARRAY_SIZE(clkset_uart_list),
  507. };
  508. static struct clksrc_clk clk_uart_uclk1 = {
  509. .clk = {
  510. .name = "uclk1",
  511. .id = -1,
  512. .ctrlbit = S5PC100_CLKGATE_SCLK0_UART,
  513. .enable = s5pc100_sclk0_ctrl,
  514. .set_parent = s5pc100_setparent_clksrc,
  515. .get_rate = s5pc100_getrate_clksrc,
  516. .set_rate = s5pc100_setrate_clksrc,
  517. .round_rate = s5pc100_roundrate_clksrc,
  518. },
  519. .shift = S5PC100_CLKSRC1_UART_SHIFT,
  520. .mask = S5PC100_CLKSRC1_UART_MASK,
  521. .sources = &clkset_uart,
  522. .divider_shift = S5PC100_CLKDIV2_UART_SHIFT,
  523. .reg_divider = S5PC100_CLKDIV2,
  524. .reg_source = S5PC100_CLKSRC1,
  525. };
  526. static struct clk clk_iis_cd0 = {
  527. .name = "iis_cdclk0",
  528. .id = -1,
  529. };
  530. static struct clk clk_iis_cd1 = {
  531. .name = "iis_cdclk1",
  532. .id = -1,
  533. };
  534. static struct clk clk_iis_cd2 = {
  535. .name = "iis_cdclk2",
  536. .id = -1,
  537. };
  538. static struct clk clk_pcm_cd0 = {
  539. .name = "pcm_cdclk0",
  540. .id = -1,
  541. };
  542. static struct clk clk_pcm_cd1 = {
  543. .name = "pcm_cdclk1",
  544. .id = -1,
  545. };
  546. static struct clk *clkset_audio0_list[] = {
  547. &clk_mout_epll.clk,
  548. &clk_dout_mpll,
  549. &clk_fin_epll,
  550. &clk_iis_cd0,
  551. &clk_pcm_cd0,
  552. &clk_mout_hpll.clk,
  553. };
  554. static struct clk_sources clkset_audio0 = {
  555. .sources = clkset_audio0_list,
  556. .nr_sources = ARRAY_SIZE(clkset_audio0_list),
  557. };
  558. static struct clksrc_clk clk_audio0 = {
  559. .clk = {
  560. .name = "audio-bus",
  561. .id = 0,
  562. .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO0,
  563. .enable = s5pc100_sclk1_ctrl,
  564. .set_parent = s5pc100_setparent_clksrc,
  565. .get_rate = s5pc100_getrate_clksrc,
  566. .set_rate = s5pc100_setrate_clksrc,
  567. .round_rate = s5pc100_roundrate_clksrc,
  568. },
  569. .shift = S5PC100_CLKSRC3_AUDIO0_SHIFT,
  570. .mask = S5PC100_CLKSRC3_AUDIO0_MASK,
  571. .sources = &clkset_audio0,
  572. .divider_shift = S5PC100_CLKDIV4_AUDIO0_SHIFT,
  573. .reg_divider = S5PC100_CLKDIV4,
  574. .reg_source = S5PC100_CLKSRC3,
  575. };
  576. static struct clk *clkset_audio1_list[] = {
  577. &clk_mout_epll.clk,
  578. &clk_dout_mpll,
  579. &clk_fin_epll,
  580. &clk_iis_cd1,
  581. &clk_pcm_cd1,
  582. &clk_mout_hpll.clk,
  583. };
  584. static struct clk_sources clkset_audio1 = {
  585. .sources = clkset_audio1_list,
  586. .nr_sources = ARRAY_SIZE(clkset_audio1_list),
  587. };
  588. static struct clksrc_clk clk_audio1 = {
  589. .clk = {
  590. .name = "audio-bus",
  591. .id = 1,
  592. .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO1,
  593. .enable = s5pc100_sclk1_ctrl,
  594. .set_parent = s5pc100_setparent_clksrc,
  595. .get_rate = s5pc100_getrate_clksrc,
  596. .set_rate = s5pc100_setrate_clksrc,
  597. .round_rate = s5pc100_roundrate_clksrc,
  598. },
  599. .shift = S5PC100_CLKSRC3_AUDIO1_SHIFT,
  600. .mask = S5PC100_CLKSRC3_AUDIO1_MASK,
  601. .sources = &clkset_audio1,
  602. .divider_shift = S5PC100_CLKDIV4_AUDIO1_SHIFT,
  603. .reg_divider = S5PC100_CLKDIV4,
  604. .reg_source = S5PC100_CLKSRC3,
  605. };
  606. static struct clk *clkset_audio2_list[] = {
  607. &clk_mout_epll.clk,
  608. &clk_dout_mpll,
  609. &clk_fin_epll,
  610. &clk_iis_cd2,
  611. &clk_mout_hpll.clk,
  612. };
  613. static struct clk_sources clkset_audio2 = {
  614. .sources = clkset_audio2_list,
  615. .nr_sources = ARRAY_SIZE(clkset_audio2_list),
  616. };
  617. static struct clksrc_clk clk_audio2 = {
  618. .clk = {
  619. .name = "audio-bus",
  620. .id = 2,
  621. .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO2,
  622. .enable = s5pc100_sclk1_ctrl,
  623. .set_parent = s5pc100_setparent_clksrc,
  624. .get_rate = s5pc100_getrate_clksrc,
  625. .set_rate = s5pc100_setrate_clksrc,
  626. .round_rate = s5pc100_roundrate_clksrc,
  627. },
  628. .shift = S5PC100_CLKSRC3_AUDIO2_SHIFT,
  629. .mask = S5PC100_CLKSRC3_AUDIO2_MASK,
  630. .sources = &clkset_audio2,
  631. .divider_shift = S5PC100_CLKDIV4_AUDIO2_SHIFT,
  632. .reg_divider = S5PC100_CLKDIV4,
  633. .reg_source = S5PC100_CLKSRC3,
  634. };
  635. static struct clk *clkset_spdif_list[] = {
  636. &clk_audio0.clk,
  637. &clk_audio1.clk,
  638. &clk_audio2.clk,
  639. };
  640. static struct clk_sources clkset_spdif = {
  641. .sources = clkset_spdif_list,
  642. .nr_sources = ARRAY_SIZE(clkset_spdif_list),
  643. };
  644. static struct clksrc_clk clk_spdif = {
  645. .clk = {
  646. .name = "spdif",
  647. .id = -1,
  648. },
  649. .shift = S5PC100_CLKSRC3_SPDIF_SHIFT,
  650. .mask = S5PC100_CLKSRC3_SPDIF_MASK,
  651. .sources = &clkset_spdif,
  652. .reg_source = S5PC100_CLKSRC3,
  653. };
  654. static struct clk *clkset_lcd_fimc_list[] = {
  655. &clk_mout_epll.clk,
  656. &clk_dout_mpll,
  657. &clk_mout_hpll.clk,
  658. &clk_vclk_54m,
  659. };
  660. static struct clk_sources clkset_lcd_fimc = {
  661. .sources = clkset_lcd_fimc_list,
  662. .nr_sources = ARRAY_SIZE(clkset_lcd_fimc_list),
  663. };
  664. static struct clksrc_clk clk_lcd = {
  665. .clk = {
  666. .name = "lcd",
  667. .id = -1,
  668. .ctrlbit = S5PC100_CLKGATE_SCLK1_LCD,
  669. .enable = s5pc100_sclk1_ctrl,
  670. .set_parent = s5pc100_setparent_clksrc,
  671. .get_rate = s5pc100_getrate_clksrc,
  672. .set_rate = s5pc100_setrate_clksrc,
  673. .round_rate = s5pc100_roundrate_clksrc,
  674. },
  675. .shift = S5PC100_CLKSRC2_LCD_SHIFT,
  676. .mask = S5PC100_CLKSRC2_LCD_MASK,
  677. .sources = &clkset_lcd_fimc,
  678. .divider_shift = S5PC100_CLKDIV3_LCD_SHIFT,
  679. .reg_divider = S5PC100_CLKDIV3,
  680. .reg_source = S5PC100_CLKSRC2,
  681. };
  682. static struct clksrc_clk clk_fimc0 = {
  683. .clk = {
  684. .name = "fimc",
  685. .id = 0,
  686. .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC0,
  687. .enable = s5pc100_sclk1_ctrl,
  688. .set_parent = s5pc100_setparent_clksrc,
  689. .get_rate = s5pc100_getrate_clksrc,
  690. .set_rate = s5pc100_setrate_clksrc,
  691. .round_rate = s5pc100_roundrate_clksrc,
  692. },
  693. .shift = S5PC100_CLKSRC2_FIMC0_SHIFT,
  694. .mask = S5PC100_CLKSRC2_FIMC0_MASK,
  695. .sources = &clkset_lcd_fimc,
  696. .divider_shift = S5PC100_CLKDIV3_FIMC0_SHIFT,
  697. .reg_divider = S5PC100_CLKDIV3,
  698. .reg_source = S5PC100_CLKSRC2,
  699. };
  700. static struct clksrc_clk clk_fimc1 = {
  701. .clk = {
  702. .name = "fimc",
  703. .id = 1,
  704. .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC1,
  705. .enable = s5pc100_sclk1_ctrl,
  706. .set_parent = s5pc100_setparent_clksrc,
  707. .get_rate = s5pc100_getrate_clksrc,
  708. .set_rate = s5pc100_setrate_clksrc,
  709. .round_rate = s5pc100_roundrate_clksrc,
  710. },
  711. .shift = S5PC100_CLKSRC2_FIMC1_SHIFT,
  712. .mask = S5PC100_CLKSRC2_FIMC1_MASK,
  713. .sources = &clkset_lcd_fimc,
  714. .divider_shift = S5PC100_CLKDIV3_FIMC1_SHIFT,
  715. .reg_divider = S5PC100_CLKDIV3,
  716. .reg_source = S5PC100_CLKSRC2,
  717. };
  718. static struct clksrc_clk clk_fimc2 = {
  719. .clk = {
  720. .name = "fimc",
  721. .id = 2,
  722. .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC2,
  723. .enable = s5pc100_sclk1_ctrl,
  724. .set_parent = s5pc100_setparent_clksrc,
  725. .get_rate = s5pc100_getrate_clksrc,
  726. .set_rate = s5pc100_setrate_clksrc,
  727. .round_rate = s5pc100_roundrate_clksrc,
  728. },
  729. .shift = S5PC100_CLKSRC2_FIMC2_SHIFT,
  730. .mask = S5PC100_CLKSRC2_FIMC2_MASK,
  731. .sources = &clkset_lcd_fimc,
  732. .divider_shift = S5PC100_CLKDIV3_FIMC2_SHIFT,
  733. .reg_divider = S5PC100_CLKDIV3,
  734. .reg_source = S5PC100_CLKSRC2,
  735. };
  736. static struct clk *clkset_mmc_list[] = {
  737. &clk_mout_epll.clk,
  738. &clk_dout_mpll,
  739. &clk_fin_epll,
  740. &clk_mout_hpll.clk ,
  741. };
  742. static struct clk_sources clkset_mmc = {
  743. .sources = clkset_mmc_list,
  744. .nr_sources = ARRAY_SIZE(clkset_mmc_list),
  745. };
  746. static struct clksrc_clk clk_mmc0 = {
  747. .clk = {
  748. .name = "mmc_bus",
  749. .id = 0,
  750. .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0,
  751. .enable = s5pc100_sclk0_ctrl,
  752. .set_parent = s5pc100_setparent_clksrc,
  753. .get_rate = s5pc100_getrate_clksrc,
  754. .set_rate = s5pc100_setrate_clksrc,
  755. .round_rate = s5pc100_roundrate_clksrc,
  756. },
  757. .shift = S5PC100_CLKSRC2_MMC0_SHIFT,
  758. .mask = S5PC100_CLKSRC2_MMC0_MASK,
  759. .sources = &clkset_mmc,
  760. .divider_shift = S5PC100_CLKDIV3_MMC0_SHIFT,
  761. .reg_divider = S5PC100_CLKDIV3,
  762. .reg_source = S5PC100_CLKSRC2,
  763. };
  764. static struct clksrc_clk clk_mmc1 = {
  765. .clk = {
  766. .name = "mmc_bus",
  767. .id = 1,
  768. .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1,
  769. .enable = s5pc100_sclk0_ctrl,
  770. .set_parent = s5pc100_setparent_clksrc,
  771. .get_rate = s5pc100_getrate_clksrc,
  772. .set_rate = s5pc100_setrate_clksrc,
  773. .round_rate = s5pc100_roundrate_clksrc,
  774. },
  775. .shift = S5PC100_CLKSRC2_MMC1_SHIFT,
  776. .mask = S5PC100_CLKSRC2_MMC1_MASK,
  777. .sources = &clkset_mmc,
  778. .divider_shift = S5PC100_CLKDIV3_MMC1_SHIFT,
  779. .reg_divider = S5PC100_CLKDIV3,
  780. .reg_source = S5PC100_CLKSRC2,
  781. };
  782. static struct clksrc_clk clk_mmc2 = {
  783. .clk = {
  784. .name = "mmc_bus",
  785. .id = 2,
  786. .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2,
  787. .enable = s5pc100_sclk0_ctrl,
  788. .set_parent = s5pc100_setparent_clksrc,
  789. .get_rate = s5pc100_getrate_clksrc,
  790. .set_rate = s5pc100_setrate_clksrc,
  791. .round_rate = s5pc100_roundrate_clksrc,
  792. },
  793. .shift = S5PC100_CLKSRC2_MMC2_SHIFT,
  794. .mask = S5PC100_CLKSRC2_MMC2_MASK,
  795. .sources = &clkset_mmc,
  796. .divider_shift = S5PC100_CLKDIV3_MMC2_SHIFT,
  797. .reg_divider = S5PC100_CLKDIV3,
  798. .reg_source = S5PC100_CLKSRC2,
  799. };
  800. static struct clk *clkset_usbhost_list[] = {
  801. &clk_mout_epll.clk,
  802. &clk_dout_mpll,
  803. &clk_mout_hpll.clk,
  804. &clk_48m,
  805. };
  806. static struct clk_sources clkset_usbhost = {
  807. .sources = clkset_usbhost_list,
  808. .nr_sources = ARRAY_SIZE(clkset_usbhost_list),
  809. };
  810. static struct clksrc_clk clk_usbhost = {
  811. .clk = {
  812. .name = "usbhost",
  813. .id = -1,
  814. .ctrlbit = S5PC100_CLKGATE_SCLK0_USBHOST,
  815. .enable = s5pc100_sclk0_ctrl,
  816. .set_parent = s5pc100_setparent_clksrc,
  817. .get_rate = s5pc100_getrate_clksrc,
  818. .set_rate = s5pc100_setrate_clksrc,
  819. .round_rate = s5pc100_roundrate_clksrc,
  820. },
  821. .shift = S5PC100_CLKSRC1_UHOST_SHIFT,
  822. .mask = S5PC100_CLKSRC1_UHOST_MASK,
  823. .sources = &clkset_usbhost,
  824. .divider_shift = S5PC100_CLKDIV2_UHOST_SHIFT,
  825. .reg_divider = S5PC100_CLKDIV2,
  826. .reg_source = S5PC100_CLKSRC1,
  827. };
  828. /* Clock initialisation code */
  829. static struct clksrc_clk *init_parents[] = {
  830. &clk_mout_apll,
  831. &clk_mout_mpll,
  832. &clk_mout_am,
  833. &clk_mout_onenand,
  834. &clk_mout_epll,
  835. &clk_mout_hpll,
  836. &clk_spi0,
  837. &clk_spi1,
  838. &clk_spi2,
  839. &clk_uart_uclk1,
  840. &clk_audio0,
  841. &clk_audio1,
  842. &clk_audio2,
  843. &clk_spdif,
  844. &clk_lcd,
  845. &clk_fimc0,
  846. &clk_fimc1,
  847. &clk_fimc2,
  848. &clk_mmc0,
  849. &clk_mmc1,
  850. &clk_mmc2,
  851. &clk_usbhost,
  852. };
  853. static void __init_or_cpufreq s5pc100_set_clksrc(struct clksrc_clk *clk)
  854. {
  855. struct clk_sources *srcs = clk->sources;
  856. u32 clksrc = __raw_readl(clk->reg_source);
  857. clksrc &= clk->mask;
  858. clksrc >>= clk->shift;
  859. if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
  860. printk(KERN_ERR "%s: bad source %d\n",
  861. clk->clk.name, clksrc);
  862. return;
  863. }
  864. clk->clk.parent = srcs->sources[clksrc];
  865. printk(KERN_INFO "%s: source is %s (%d), rate is %ld.%03ld MHz\n",
  866. clk->clk.name, clk->clk.parent->name, clksrc,
  867. print_mhz(clk_get_rate(&clk->clk)));
  868. }
  869. #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
  870. void __init_or_cpufreq s5pc100_setup_clocks(void)
  871. {
  872. struct clk *xtal_clk;
  873. unsigned long xtal;
  874. unsigned long armclk;
  875. unsigned long hclkd0;
  876. unsigned long hclk;
  877. unsigned long pclkd0;
  878. unsigned long pclk;
  879. unsigned long apll, mpll, epll, hpll;
  880. unsigned int ptr;
  881. u32 clkdiv0, clkdiv1;
  882. printk(KERN_DEBUG "%s: registering clocks\n", __func__);
  883. clkdiv0 = __raw_readl(S5PC100_CLKDIV0);
  884. clkdiv1 = __raw_readl(S5PC100_CLKDIV1);
  885. printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n", __func__, clkdiv0, clkdiv1);
  886. xtal_clk = clk_get(NULL, "xtal");
  887. BUG_ON(IS_ERR(xtal_clk));
  888. xtal = clk_get_rate(xtal_clk);
  889. clk_put(xtal_clk);
  890. printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
  891. apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_APLL_CON));
  892. mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_MPLL_CON));
  893. epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_EPLL_CON));
  894. hpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_HPLL_CON));
  895. printk(KERN_INFO "S5PC100: Apll=%ld.%03ld Mhz, Mpll=%ld.%03ld Mhz"
  896. ", Epll=%ld.%03ld Mhz, Hpll=%ld.%03ld Mhz\n",
  897. print_mhz(apll), print_mhz(mpll),
  898. print_mhz(epll), print_mhz(hpll));
  899. armclk = apll / GET_DIV(clkdiv0, S5PC100_CLKDIV0_APLL);
  900. armclk = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_ARM);
  901. hclkd0 = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_D0);
  902. pclkd0 = hclkd0 / GET_DIV(clkdiv0, S5PC100_CLKDIV0_PCLKD0);
  903. hclk = mpll / GET_DIV(clkdiv1, S5PC100_CLKDIV1_D1);
  904. pclk = hclk / GET_DIV(clkdiv1, S5PC100_CLKDIV1_PCLKD1);
  905. printk(KERN_INFO "S5PC100: ARMCLK=%ld.%03ld MHz, HCLKD0=%ld.%03ld MHz,"
  906. " PCLKD0=%ld.%03ld MHz\n, HCLK=%ld.%03ld MHz,"
  907. " PCLK=%ld.%03ld MHz\n",
  908. print_mhz(armclk), print_mhz(hclkd0),
  909. print_mhz(pclkd0), print_mhz(hclk), print_mhz(pclk));
  910. clk_fout_apll.rate = apll;
  911. clk_fout_mpll.rate = mpll;
  912. clk_fout_epll.rate = epll;
  913. clk_fout_hpll.rate = hpll;
  914. clk_h.rate = hclk;
  915. clk_p.rate = pclk;
  916. clk_f.rate = armclk;
  917. for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
  918. s5pc100_set_clksrc(init_parents[ptr]);
  919. }
  920. static struct clk *clks[] __initdata = {
  921. &clk_ext_xtal_mux,
  922. &clk_mout_apll.clk,
  923. &clk_dout_apll,
  924. &clk_dout_d0_bus,
  925. &clk_dout_pclkd0,
  926. &clk_dout_apll2,
  927. &clk_mout_mpll.clk,
  928. &clk_mout_am.clk,
  929. &clk_dout_d1_bus,
  930. &clk_mout_onenand.clk,
  931. &clk_dout_pclkd1,
  932. &clk_dout_mpll2,
  933. &clk_dout_cam,
  934. &clk_dout_mpll,
  935. &clk_mout_epll.clk,
  936. &clk_fout_epll,
  937. &clk_iis_cd0,
  938. &clk_iis_cd1,
  939. &clk_iis_cd2,
  940. &clk_pcm_cd0,
  941. &clk_pcm_cd1,
  942. &clk_spi0.clk,
  943. &clk_spi1.clk,
  944. &clk_spi2.clk,
  945. &clk_uart_uclk1.clk,
  946. &clk_audio0.clk,
  947. &clk_audio1.clk,
  948. &clk_audio2.clk,
  949. &clk_spdif.clk,
  950. &clk_lcd.clk,
  951. &clk_fimc0.clk,
  952. &clk_fimc1.clk,
  953. &clk_fimc2.clk,
  954. &clk_mmc0.clk,
  955. &clk_mmc1.clk,
  956. &clk_mmc2.clk,
  957. &clk_usbhost.clk,
  958. &clk_arm,
  959. };
  960. void __init s5pc100_register_clocks(void)
  961. {
  962. struct clk *clkp;
  963. int ret;
  964. int ptr;
  965. for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
  966. clkp = clks[ptr];
  967. ret = s3c24xx_register_clock(clkp);
  968. if (ret < 0) {
  969. printk(KERN_ERR "Failed to register clock %s (%d)\n",
  970. clkp->name, ret);
  971. }
  972. }
  973. }