clock.c 18 KB

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