clock.c 18 KB

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