clock.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. /*
  2. * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. */
  18. #include <linux/kernel.h>
  19. #include <linux/init.h>
  20. #include <linux/list.h>
  21. #include <linux/math64.h>
  22. #include <linux/err.h>
  23. #include <linux/clk.h>
  24. #include <linux/io.h>
  25. #include <asm/clkdev.h>
  26. #include <mach/clock.h>
  27. #include <mach/hardware.h>
  28. #include <mach/common.h>
  29. #include "crm_regs.h"
  30. static int _clk_enable(struct clk *clk)
  31. {
  32. unsigned int reg;
  33. reg = __raw_readl(clk->enable_reg);
  34. reg |= 1 << clk->enable_shift;
  35. __raw_writel(reg, clk->enable_reg);
  36. return 0;
  37. }
  38. static void _clk_disable(struct clk *clk)
  39. {
  40. unsigned int reg;
  41. reg = __raw_readl(clk->enable_reg);
  42. reg &= ~(1 << clk->enable_shift);
  43. __raw_writel(reg, clk->enable_reg);
  44. }
  45. static int _clk_can_use_parent(const struct clk *clk_arr[], unsigned int size,
  46. struct clk *parent)
  47. {
  48. int i;
  49. for (i = 0; i < size; i++)
  50. if (parent == clk_arr[i])
  51. return i;
  52. return -EINVAL;
  53. }
  54. static unsigned long
  55. _clk_simple_round_rate(struct clk *clk, unsigned long rate, unsigned int limit)
  56. {
  57. int div;
  58. unsigned long parent_rate;
  59. parent_rate = clk_get_rate(clk->parent);
  60. div = parent_rate / rate;
  61. if (parent_rate % rate)
  62. div++;
  63. if (div > limit)
  64. div = limit;
  65. return parent_rate / div;
  66. }
  67. static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate)
  68. {
  69. return clk->parent->round_rate(clk->parent, rate);
  70. }
  71. static int _clk_parent_set_rate(struct clk *clk, unsigned long rate)
  72. {
  73. return clk->parent->set_rate(clk->parent, rate);
  74. }
  75. static unsigned long clk16m_get_rate(struct clk *clk)
  76. {
  77. return 16000000;
  78. }
  79. static struct clk clk16m = {
  80. .get_rate = clk16m_get_rate,
  81. .enable = _clk_enable,
  82. .enable_reg = CCM_CSCR,
  83. .enable_shift = CCM_CSCR_OSC_EN_SHIFT,
  84. .disable = _clk_disable,
  85. };
  86. /* in Hz */
  87. static unsigned long clk32_rate;
  88. static unsigned long clk32_get_rate(struct clk *clk)
  89. {
  90. return clk32_rate;
  91. }
  92. static struct clk clk32 = {
  93. .get_rate = clk32_get_rate,
  94. };
  95. static unsigned long clk32_premult_get_rate(struct clk *clk)
  96. {
  97. return clk_get_rate(clk->parent) * 512;
  98. }
  99. static struct clk clk32_premult = {
  100. .parent = &clk32,
  101. .get_rate = clk32_premult_get_rate,
  102. };
  103. static const struct clk *prem_clk_clocks[] = {
  104. &clk32_premult,
  105. &clk16m,
  106. };
  107. static int prem_clk_set_parent(struct clk *clk, struct clk *parent)
  108. {
  109. int i;
  110. unsigned int reg = __raw_readl(CCM_CSCR);
  111. i = _clk_can_use_parent(prem_clk_clocks, ARRAY_SIZE(prem_clk_clocks),
  112. parent);
  113. switch (i) {
  114. case 0:
  115. reg &= ~CCM_CSCR_SYSTEM_SEL;
  116. break;
  117. case 1:
  118. reg |= CCM_CSCR_SYSTEM_SEL;
  119. break;
  120. default:
  121. return i;
  122. }
  123. __raw_writel(reg, CCM_CSCR);
  124. return 0;
  125. }
  126. static struct clk prem_clk = {
  127. .set_parent = prem_clk_set_parent,
  128. };
  129. static unsigned long system_clk_get_rate(struct clk *clk)
  130. {
  131. return mxc_decode_pll(__raw_readl(CCM_SPCTL0),
  132. clk_get_rate(clk->parent));
  133. }
  134. static struct clk system_clk = {
  135. .parent = &prem_clk,
  136. .get_rate = system_clk_get_rate,
  137. };
  138. static unsigned long mcu_clk_get_rate(struct clk *clk)
  139. {
  140. return mxc_decode_pll(__raw_readl(CCM_MPCTL0),
  141. clk_get_rate(clk->parent));
  142. }
  143. static struct clk mcu_clk = {
  144. .parent = &clk32_premult,
  145. .get_rate = mcu_clk_get_rate,
  146. };
  147. static unsigned long fclk_get_rate(struct clk *clk)
  148. {
  149. unsigned long fclk = clk_get_rate(clk->parent);
  150. if (__raw_readl(CCM_CSCR) & CCM_CSCR_PRESC)
  151. fclk /= 2;
  152. return fclk;
  153. }
  154. static struct clk fclk = {
  155. .parent = &mcu_clk,
  156. .get_rate = fclk_get_rate,
  157. };
  158. /*
  159. * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
  160. */
  161. static unsigned long hclk_get_rate(struct clk *clk)
  162. {
  163. return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) &
  164. CCM_CSCR_BCLK_MASK) >> CCM_CSCR_BCLK_OFFSET) + 1);
  165. }
  166. static unsigned long hclk_round_rate(struct clk *clk, unsigned long rate)
  167. {
  168. return _clk_simple_round_rate(clk, rate, 16);
  169. }
  170. static int hclk_set_rate(struct clk *clk, unsigned long rate)
  171. {
  172. unsigned int div;
  173. unsigned int reg;
  174. unsigned long parent_rate;
  175. parent_rate = clk_get_rate(clk->parent);
  176. div = parent_rate / rate;
  177. if (div > 16 || div < 1 || ((parent_rate / div) != rate))
  178. return -EINVAL;
  179. div--;
  180. reg = __raw_readl(CCM_CSCR);
  181. reg &= ~CCM_CSCR_BCLK_MASK;
  182. reg |= div << CCM_CSCR_BCLK_OFFSET;
  183. __raw_writel(reg, CCM_CSCR);
  184. return 0;
  185. }
  186. static struct clk hclk = {
  187. .parent = &system_clk,
  188. .get_rate = hclk_get_rate,
  189. .round_rate = hclk_round_rate,
  190. .set_rate = hclk_set_rate,
  191. };
  192. static unsigned long clk48m_get_rate(struct clk *clk)
  193. {
  194. return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) &
  195. CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET) + 1);
  196. }
  197. static unsigned long clk48m_round_rate(struct clk *clk, unsigned long rate)
  198. {
  199. return _clk_simple_round_rate(clk, rate, 8);
  200. }
  201. static int clk48m_set_rate(struct clk *clk, unsigned long rate)
  202. {
  203. unsigned int div;
  204. unsigned int reg;
  205. unsigned long parent_rate;
  206. parent_rate = clk_get_rate(clk->parent);
  207. div = parent_rate / rate;
  208. if (div > 8 || div < 1 || ((parent_rate / div) != rate))
  209. return -EINVAL;
  210. div--;
  211. reg = __raw_readl(CCM_CSCR);
  212. reg &= ~CCM_CSCR_USB_MASK;
  213. reg |= div << CCM_CSCR_USB_OFFSET;
  214. __raw_writel(reg, CCM_CSCR);
  215. return 0;
  216. }
  217. static struct clk clk48m = {
  218. .parent = &system_clk,
  219. .get_rate = clk48m_get_rate,
  220. .round_rate = clk48m_round_rate,
  221. .set_rate = clk48m_set_rate,
  222. };
  223. /*
  224. * get peripheral clock 1 ( UART[12], Timer[12], PWM )
  225. */
  226. static unsigned long perclk1_get_rate(struct clk *clk)
  227. {
  228. return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
  229. CCM_PCDR_PCLK1_MASK) >> CCM_PCDR_PCLK1_OFFSET) + 1);
  230. }
  231. static unsigned long perclk1_round_rate(struct clk *clk, unsigned long rate)
  232. {
  233. return _clk_simple_round_rate(clk, rate, 16);
  234. }
  235. static int perclk1_set_rate(struct clk *clk, unsigned long rate)
  236. {
  237. unsigned int div;
  238. unsigned int reg;
  239. unsigned long parent_rate;
  240. parent_rate = clk_get_rate(clk->parent);
  241. div = parent_rate / rate;
  242. if (div > 16 || div < 1 || ((parent_rate / div) != rate))
  243. return -EINVAL;
  244. div--;
  245. reg = __raw_readl(CCM_PCDR);
  246. reg &= ~CCM_PCDR_PCLK1_MASK;
  247. reg |= div << CCM_PCDR_PCLK1_OFFSET;
  248. __raw_writel(reg, CCM_PCDR);
  249. return 0;
  250. }
  251. /*
  252. * get peripheral clock 2 ( LCD, SD, SPI[12] )
  253. */
  254. static unsigned long perclk2_get_rate(struct clk *clk)
  255. {
  256. return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
  257. CCM_PCDR_PCLK2_MASK) >> CCM_PCDR_PCLK2_OFFSET) + 1);
  258. }
  259. static unsigned long perclk2_round_rate(struct clk *clk, unsigned long rate)
  260. {
  261. return _clk_simple_round_rate(clk, rate, 16);
  262. }
  263. static int perclk2_set_rate(struct clk *clk, unsigned long rate)
  264. {
  265. unsigned int div;
  266. unsigned int reg;
  267. unsigned long parent_rate;
  268. parent_rate = clk_get_rate(clk->parent);
  269. div = parent_rate / rate;
  270. if (div > 16 || div < 1 || ((parent_rate / div) != rate))
  271. return -EINVAL;
  272. div--;
  273. reg = __raw_readl(CCM_PCDR);
  274. reg &= ~CCM_PCDR_PCLK2_MASK;
  275. reg |= div << CCM_PCDR_PCLK2_OFFSET;
  276. __raw_writel(reg, CCM_PCDR);
  277. return 0;
  278. }
  279. /*
  280. * get peripheral clock 3 ( SSI )
  281. */
  282. static unsigned long perclk3_get_rate(struct clk *clk)
  283. {
  284. return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
  285. CCM_PCDR_PCLK3_MASK) >> CCM_PCDR_PCLK3_OFFSET) + 1);
  286. }
  287. static unsigned long perclk3_round_rate(struct clk *clk, unsigned long rate)
  288. {
  289. return _clk_simple_round_rate(clk, rate, 128);
  290. }
  291. static int perclk3_set_rate(struct clk *clk, unsigned long rate)
  292. {
  293. unsigned int div;
  294. unsigned int reg;
  295. unsigned long parent_rate;
  296. parent_rate = clk_get_rate(clk->parent);
  297. div = parent_rate / rate;
  298. if (div > 128 || div < 1 || ((parent_rate / div) != rate))
  299. return -EINVAL;
  300. div--;
  301. reg = __raw_readl(CCM_PCDR);
  302. reg &= ~CCM_PCDR_PCLK3_MASK;
  303. reg |= div << CCM_PCDR_PCLK3_OFFSET;
  304. __raw_writel(reg, CCM_PCDR);
  305. return 0;
  306. }
  307. static struct clk perclk[] = {
  308. {
  309. .id = 0,
  310. .parent = &system_clk,
  311. .get_rate = perclk1_get_rate,
  312. .round_rate = perclk1_round_rate,
  313. .set_rate = perclk1_set_rate,
  314. }, {
  315. .id = 1,
  316. .parent = &system_clk,
  317. .get_rate = perclk2_get_rate,
  318. .round_rate = perclk2_round_rate,
  319. .set_rate = perclk2_set_rate,
  320. }, {
  321. .id = 2,
  322. .parent = &system_clk,
  323. .get_rate = perclk3_get_rate,
  324. .round_rate = perclk3_round_rate,
  325. .set_rate = perclk3_set_rate,
  326. }
  327. };
  328. static const struct clk *clko_clocks[] = {
  329. &perclk[0],
  330. &hclk,
  331. &clk48m,
  332. &clk16m,
  333. &prem_clk,
  334. &fclk,
  335. };
  336. static int clko_set_parent(struct clk *clk, struct clk *parent)
  337. {
  338. int i;
  339. unsigned int reg;
  340. i = _clk_can_use_parent(clko_clocks, ARRAY_SIZE(clko_clocks), parent);
  341. if (i < 0)
  342. return i;
  343. reg = __raw_readl(CCM_CSCR) & ~CCM_CSCR_CLKO_MASK;
  344. reg |= i << CCM_CSCR_CLKO_OFFSET;
  345. __raw_writel(reg, CCM_CSCR);
  346. if (clko_clocks[i]->set_rate && clko_clocks[i]->round_rate) {
  347. clk->set_rate = _clk_parent_set_rate;
  348. clk->round_rate = _clk_parent_round_rate;
  349. } else {
  350. clk->set_rate = NULL;
  351. clk->round_rate = NULL;
  352. }
  353. return 0;
  354. }
  355. static struct clk clko_clk = {
  356. .set_parent = clko_set_parent,
  357. };
  358. static struct clk dma_clk = {
  359. .parent = &hclk,
  360. .round_rate = _clk_parent_round_rate,
  361. .set_rate = _clk_parent_set_rate,
  362. .enable = _clk_enable,
  363. .enable_reg = SCM_GCCR,
  364. .enable_shift = SCM_GCCR_DMA_CLK_EN_OFFSET,
  365. .disable = _clk_disable,
  366. };
  367. static struct clk csi_clk = {
  368. .parent = &hclk,
  369. .round_rate = _clk_parent_round_rate,
  370. .set_rate = _clk_parent_set_rate,
  371. .enable = _clk_enable,
  372. .enable_reg = SCM_GCCR,
  373. .enable_shift = SCM_GCCR_CSI_CLK_EN_OFFSET,
  374. .disable = _clk_disable,
  375. };
  376. static struct clk mma_clk = {
  377. .parent = &hclk,
  378. .round_rate = _clk_parent_round_rate,
  379. .set_rate = _clk_parent_set_rate,
  380. .enable = _clk_enable,
  381. .enable_reg = SCM_GCCR,
  382. .enable_shift = SCM_GCCR_MMA_CLK_EN_OFFSET,
  383. .disable = _clk_disable,
  384. };
  385. static struct clk usbd_clk = {
  386. .parent = &clk48m,
  387. .round_rate = _clk_parent_round_rate,
  388. .set_rate = _clk_parent_set_rate,
  389. .enable = _clk_enable,
  390. .enable_reg = SCM_GCCR,
  391. .enable_shift = SCM_GCCR_USBD_CLK_EN_OFFSET,
  392. .disable = _clk_disable,
  393. };
  394. static struct clk gpt_clk = {
  395. .parent = &perclk[0],
  396. .round_rate = _clk_parent_round_rate,
  397. .set_rate = _clk_parent_set_rate,
  398. };
  399. static struct clk uart_clk = {
  400. .parent = &perclk[0],
  401. .round_rate = _clk_parent_round_rate,
  402. .set_rate = _clk_parent_set_rate,
  403. };
  404. static struct clk i2c_clk = {
  405. .parent = &hclk,
  406. .round_rate = _clk_parent_round_rate,
  407. .set_rate = _clk_parent_set_rate,
  408. };
  409. static struct clk spi_clk = {
  410. .parent = &perclk[1],
  411. .round_rate = _clk_parent_round_rate,
  412. .set_rate = _clk_parent_set_rate,
  413. };
  414. static struct clk sdhc_clk = {
  415. .parent = &perclk[1],
  416. .round_rate = _clk_parent_round_rate,
  417. .set_rate = _clk_parent_set_rate,
  418. };
  419. static struct clk lcdc_clk = {
  420. .parent = &perclk[1],
  421. .round_rate = _clk_parent_round_rate,
  422. .set_rate = _clk_parent_set_rate,
  423. };
  424. static struct clk mshc_clk = {
  425. .parent = &hclk,
  426. .round_rate = _clk_parent_round_rate,
  427. .set_rate = _clk_parent_set_rate,
  428. };
  429. static struct clk ssi_clk = {
  430. .parent = &perclk[2],
  431. .round_rate = _clk_parent_round_rate,
  432. .set_rate = _clk_parent_set_rate,
  433. };
  434. static struct clk rtc_clk = {
  435. .parent = &clk32,
  436. };
  437. #define _REGISTER_CLOCK(d, n, c) \
  438. { \
  439. .dev_id = d, \
  440. .con_id = n, \
  441. .clk = &c, \
  442. },
  443. static struct clk_lookup lookups[] __initdata = {
  444. _REGISTER_CLOCK(NULL, "dma", dma_clk)
  445. _REGISTER_CLOCK("mx1-camera.0", NULL, csi_clk)
  446. _REGISTER_CLOCK(NULL, "mma", mma_clk)
  447. _REGISTER_CLOCK("imx_udc.0", NULL, usbd_clk)
  448. _REGISTER_CLOCK(NULL, "gpt", gpt_clk)
  449. _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk)
  450. _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk)
  451. _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk)
  452. _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
  453. _REGISTER_CLOCK("spi_imx.0", NULL, spi_clk)
  454. _REGISTER_CLOCK("imx-mmc.0", NULL, sdhc_clk)
  455. _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk)
  456. _REGISTER_CLOCK(NULL, "mshc", mshc_clk)
  457. _REGISTER_CLOCK(NULL, "ssi", ssi_clk)
  458. _REGISTER_CLOCK("mxc_rtc.0", NULL, rtc_clk)
  459. };
  460. int __init mx1_clocks_init(unsigned long fref)
  461. {
  462. unsigned int reg;
  463. int i;
  464. /* disable clocks we are able to */
  465. __raw_writel(0, SCM_GCCR);
  466. clk32_rate = fref;
  467. reg = __raw_readl(CCM_CSCR);
  468. /* detect clock reference for system PLL */
  469. if (reg & CCM_CSCR_SYSTEM_SEL) {
  470. prem_clk.parent = &clk16m;
  471. } else {
  472. /* ensure that oscillator is disabled */
  473. reg &= ~(1 << CCM_CSCR_OSC_EN_SHIFT);
  474. __raw_writel(reg, CCM_CSCR);
  475. prem_clk.parent = &clk32_premult;
  476. }
  477. /* detect reference for CLKO */
  478. reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET;
  479. clko_clk.parent = (struct clk *)clko_clocks[reg];
  480. for (i = 0; i < ARRAY_SIZE(lookups); i++)
  481. clkdev_add(&lookups[i]);
  482. clk_enable(&hclk);
  483. clk_enable(&fclk);
  484. mxc_timer_init(&gpt_clk, IO_ADDRESS(TIM1_BASE_ADDR), TIM1_INT);
  485. return 0;
  486. }