clock_imx21.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. /*
  2. * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
  3. * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
  4. * Copyright 2008 Martin Fuzzey, mfuzzey@gmail.com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  18. * MA 02110-1301, USA.
  19. */
  20. #include <linux/clk.h>
  21. #include <linux/io.h>
  22. #include <linux/module.h>
  23. #include <mach/clock.h>
  24. #include <mach/common.h>
  25. #include <asm/clkdev.h>
  26. #include <asm/div64.h>
  27. #include "crm_regs.h"
  28. static int _clk_enable(struct clk *clk)
  29. {
  30. u32 reg;
  31. reg = __raw_readl(clk->enable_reg);
  32. reg |= 1 << clk->enable_shift;
  33. __raw_writel(reg, clk->enable_reg);
  34. return 0;
  35. }
  36. static void _clk_disable(struct clk *clk)
  37. {
  38. u32 reg;
  39. reg = __raw_readl(clk->enable_reg);
  40. reg &= ~(1 << clk->enable_shift);
  41. __raw_writel(reg, clk->enable_reg);
  42. }
  43. static int _clk_spll_enable(struct clk *clk)
  44. {
  45. u32 reg;
  46. reg = __raw_readl(CCM_CSCR);
  47. reg |= CCM_CSCR_SPEN;
  48. __raw_writel(reg, CCM_CSCR);
  49. while ((__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF) == 0)
  50. ;
  51. return 0;
  52. }
  53. static void _clk_spll_disable(struct clk *clk)
  54. {
  55. u32 reg;
  56. reg = __raw_readl(CCM_CSCR);
  57. reg &= ~CCM_CSCR_SPEN;
  58. __raw_writel(reg, CCM_CSCR);
  59. }
  60. #define CSCR() (__raw_readl(CCM_CSCR))
  61. #define PCDR0() (__raw_readl(CCM_PCDR0))
  62. #define PCDR1() (__raw_readl(CCM_PCDR1))
  63. static unsigned long _clk_perclkx_round_rate(struct clk *clk,
  64. unsigned long rate)
  65. {
  66. u32 div;
  67. unsigned long parent_rate;
  68. parent_rate = clk_get_rate(clk->parent);
  69. div = parent_rate / rate;
  70. if (parent_rate % rate)
  71. div++;
  72. if (div > 64)
  73. div = 64;
  74. return parent_rate / div;
  75. }
  76. static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate)
  77. {
  78. u32 reg;
  79. u32 div;
  80. unsigned long parent_rate;
  81. parent_rate = clk_get_rate(clk->parent);
  82. if (clk->id < 0 || clk->id > 3)
  83. return -EINVAL;
  84. div = parent_rate / rate;
  85. if (div > 64 || div < 1 || ((parent_rate / div) != rate))
  86. return -EINVAL;
  87. div--;
  88. reg =
  89. __raw_readl(CCM_PCDR1) & ~(CCM_PCDR1_PERDIV1_MASK <<
  90. (clk->id << 3));
  91. reg |= div << (clk->id << 3);
  92. __raw_writel(reg, CCM_PCDR1);
  93. return 0;
  94. }
  95. static unsigned long _clk_usb_recalc(struct clk *clk)
  96. {
  97. unsigned long usb_pdf;
  98. unsigned long parent_rate;
  99. parent_rate = clk_get_rate(clk->parent);
  100. usb_pdf = (CSCR() & CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET;
  101. return parent_rate / (usb_pdf + 1U);
  102. }
  103. static unsigned long _clk_ssix_recalc(struct clk *clk, unsigned long pdf)
  104. {
  105. unsigned long parent_rate;
  106. parent_rate = clk_get_rate(clk->parent);
  107. pdf = (pdf < 2) ? 124UL : pdf; /* MX21 & MX27 TO1 */
  108. return 2UL * parent_rate / pdf;
  109. }
  110. static unsigned long _clk_ssi1_recalc(struct clk *clk)
  111. {
  112. return _clk_ssix_recalc(clk,
  113. (PCDR0() & CCM_PCDR0_SSI1BAUDDIV_MASK)
  114. >> CCM_PCDR0_SSI1BAUDDIV_OFFSET);
  115. }
  116. static unsigned long _clk_ssi2_recalc(struct clk *clk)
  117. {
  118. return _clk_ssix_recalc(clk,
  119. (PCDR0() & CCM_PCDR0_SSI2BAUDDIV_MASK) >>
  120. CCM_PCDR0_SSI2BAUDDIV_OFFSET);
  121. }
  122. static unsigned long _clk_nfc_recalc(struct clk *clk)
  123. {
  124. unsigned long nfc_pdf;
  125. unsigned long parent_rate;
  126. parent_rate = clk_get_rate(clk->parent);
  127. nfc_pdf = (PCDR0() & CCM_PCDR0_NFCDIV_MASK)
  128. >> CCM_PCDR0_NFCDIV_OFFSET;
  129. return parent_rate / (nfc_pdf + 1);
  130. }
  131. static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate)
  132. {
  133. return clk->parent->round_rate(clk->parent, rate);
  134. }
  135. static int _clk_parent_set_rate(struct clk *clk, unsigned long rate)
  136. {
  137. return clk->parent->set_rate(clk->parent, rate);
  138. }
  139. static unsigned long external_high_reference; /* in Hz */
  140. static unsigned long get_high_reference_clock_rate(struct clk *clk)
  141. {
  142. return external_high_reference;
  143. }
  144. /*
  145. * the high frequency external clock reference
  146. * Default case is 26MHz.
  147. */
  148. static struct clk ckih_clk = {
  149. .get_rate = get_high_reference_clock_rate,
  150. };
  151. static unsigned long external_low_reference; /* in Hz */
  152. static unsigned long get_low_reference_clock_rate(struct clk *clk)
  153. {
  154. return external_low_reference;
  155. }
  156. /*
  157. * the low frequency external clock reference
  158. * Default case is 32.768kHz.
  159. */
  160. static struct clk ckil_clk = {
  161. .get_rate = get_low_reference_clock_rate,
  162. };
  163. static unsigned long _clk_fpm_recalc(struct clk *clk)
  164. {
  165. return clk_get_rate(clk->parent) * 512;
  166. }
  167. /* Output of frequency pre multiplier */
  168. static struct clk fpm_clk = {
  169. .parent = &ckil_clk,
  170. .get_rate = _clk_fpm_recalc,
  171. };
  172. static unsigned long get_mpll_clk(struct clk *clk)
  173. {
  174. uint32_t reg;
  175. unsigned long ref_clk;
  176. unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
  177. unsigned long long temp;
  178. ref_clk = clk_get_rate(clk->parent);
  179. reg = __raw_readl(CCM_MPCTL0);
  180. pdf = (reg & CCM_MPCTL0_PD_MASK) >> CCM_MPCTL0_PD_OFFSET;
  181. mfd = (reg & CCM_MPCTL0_MFD_MASK) >> CCM_MPCTL0_MFD_OFFSET;
  182. mfi = (reg & CCM_MPCTL0_MFI_MASK) >> CCM_MPCTL0_MFI_OFFSET;
  183. mfn = (reg & CCM_MPCTL0_MFN_MASK) >> CCM_MPCTL0_MFN_OFFSET;
  184. mfi = (mfi <= 5) ? 5 : mfi;
  185. temp = 2LL * ref_clk * mfn;
  186. do_div(temp, mfd + 1);
  187. temp = 2LL * ref_clk * mfi + temp;
  188. do_div(temp, pdf + 1);
  189. return (unsigned long)temp;
  190. }
  191. static struct clk mpll_clk = {
  192. .parent = &ckih_clk,
  193. .get_rate = get_mpll_clk,
  194. };
  195. static unsigned long _clk_fclk_get_rate(struct clk *clk)
  196. {
  197. unsigned long parent_rate;
  198. u32 div;
  199. div = (CSCR() & CCM_CSCR_PRESC_MASK) >> CCM_CSCR_PRESC_OFFSET;
  200. parent_rate = clk_get_rate(clk->parent);
  201. return parent_rate / (div+1);
  202. }
  203. static struct clk fclk_clk = {
  204. .parent = &mpll_clk,
  205. .get_rate = _clk_fclk_get_rate
  206. };
  207. static unsigned long get_spll_clk(struct clk *clk)
  208. {
  209. uint32_t reg;
  210. unsigned long ref_clk;
  211. unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
  212. unsigned long long temp;
  213. ref_clk = clk_get_rate(clk->parent);
  214. reg = __raw_readl(CCM_SPCTL0);
  215. pdf = (reg & CCM_SPCTL0_PD_MASK) >> CCM_SPCTL0_PD_OFFSET;
  216. mfd = (reg & CCM_SPCTL0_MFD_MASK) >> CCM_SPCTL0_MFD_OFFSET;
  217. mfi = (reg & CCM_SPCTL0_MFI_MASK) >> CCM_SPCTL0_MFI_OFFSET;
  218. mfn = (reg & CCM_SPCTL0_MFN_MASK) >> CCM_SPCTL0_MFN_OFFSET;
  219. mfi = (mfi <= 5) ? 5 : mfi;
  220. temp = 2LL * ref_clk * mfn;
  221. do_div(temp, mfd + 1);
  222. temp = 2LL * ref_clk * mfi + temp;
  223. do_div(temp, pdf + 1);
  224. return (unsigned long)temp;
  225. }
  226. static struct clk spll_clk = {
  227. .parent = &ckih_clk,
  228. .get_rate = get_spll_clk,
  229. .enable = _clk_spll_enable,
  230. .disable = _clk_spll_disable,
  231. };
  232. static unsigned long get_hclk_clk(struct clk *clk)
  233. {
  234. unsigned long rate;
  235. unsigned long bclk_pdf;
  236. bclk_pdf = (CSCR() & CCM_CSCR_BCLK_MASK)
  237. >> CCM_CSCR_BCLK_OFFSET;
  238. rate = clk_get_rate(clk->parent);
  239. return rate / (bclk_pdf + 1);
  240. }
  241. static struct clk hclk_clk = {
  242. .parent = &fclk_clk,
  243. .get_rate = get_hclk_clk,
  244. };
  245. static unsigned long get_ipg_clk(struct clk *clk)
  246. {
  247. unsigned long rate;
  248. unsigned long ipg_pdf;
  249. ipg_pdf = (CSCR() & CCM_CSCR_IPDIV) >> CCM_CSCR_IPDIV_OFFSET;
  250. rate = clk_get_rate(clk->parent);
  251. return rate / (ipg_pdf + 1);
  252. }
  253. static struct clk ipg_clk = {
  254. .parent = &hclk_clk,
  255. .get_rate = get_ipg_clk,
  256. };
  257. static unsigned long _clk_perclkx_recalc(struct clk *clk)
  258. {
  259. unsigned long perclk_pdf;
  260. unsigned long parent_rate;
  261. parent_rate = clk_get_rate(clk->parent);
  262. if (clk->id < 0 || clk->id > 3)
  263. return 0;
  264. perclk_pdf = (PCDR1() >> (clk->id << 3)) & CCM_PCDR1_PERDIV1_MASK;
  265. return parent_rate / (perclk_pdf + 1);
  266. }
  267. static struct clk per_clk[] = {
  268. {
  269. .id = 0,
  270. .parent = &mpll_clk,
  271. .get_rate = _clk_perclkx_recalc,
  272. }, {
  273. .id = 1,
  274. .parent = &mpll_clk,
  275. .get_rate = _clk_perclkx_recalc,
  276. }, {
  277. .id = 2,
  278. .parent = &mpll_clk,
  279. .round_rate = _clk_perclkx_round_rate,
  280. .set_rate = _clk_perclkx_set_rate,
  281. .get_rate = _clk_perclkx_recalc,
  282. /* Enable/Disable done via lcd_clkc[1] */
  283. }, {
  284. .id = 3,
  285. .parent = &mpll_clk,
  286. .round_rate = _clk_perclkx_round_rate,
  287. .set_rate = _clk_perclkx_set_rate,
  288. .get_rate = _clk_perclkx_recalc,
  289. /* Enable/Disable done via csi_clk[1] */
  290. },
  291. };
  292. static struct clk uart_ipg_clk[];
  293. static struct clk uart_clk[] = {
  294. {
  295. .id = 0,
  296. .parent = &per_clk[0],
  297. .secondary = &uart_ipg_clk[0],
  298. }, {
  299. .id = 1,
  300. .parent = &per_clk[0],
  301. .secondary = &uart_ipg_clk[1],
  302. }, {
  303. .id = 2,
  304. .parent = &per_clk[0],
  305. .secondary = &uart_ipg_clk[2],
  306. }, {
  307. .id = 3,
  308. .parent = &per_clk[0],
  309. .secondary = &uart_ipg_clk[3],
  310. },
  311. };
  312. static struct clk uart_ipg_clk[] = {
  313. {
  314. .id = 0,
  315. .parent = &ipg_clk,
  316. .enable = _clk_enable,
  317. .enable_reg = CCM_PCCR_UART1_REG,
  318. .enable_shift = CCM_PCCR_UART1_OFFSET,
  319. .disable = _clk_disable,
  320. }, {
  321. .id = 1,
  322. .parent = &ipg_clk,
  323. .enable = _clk_enable,
  324. .enable_reg = CCM_PCCR_UART2_REG,
  325. .enable_shift = CCM_PCCR_UART2_OFFSET,
  326. .disable = _clk_disable,
  327. }, {
  328. .id = 2,
  329. .parent = &ipg_clk,
  330. .enable = _clk_enable,
  331. .enable_reg = CCM_PCCR_UART3_REG,
  332. .enable_shift = CCM_PCCR_UART3_OFFSET,
  333. .disable = _clk_disable,
  334. }, {
  335. .id = 3,
  336. .parent = &ipg_clk,
  337. .enable = _clk_enable,
  338. .enable_reg = CCM_PCCR_UART4_REG,
  339. .enable_shift = CCM_PCCR_UART4_OFFSET,
  340. .disable = _clk_disable,
  341. },
  342. };
  343. static struct clk gpt_ipg_clk[];
  344. static struct clk gpt_clk[] = {
  345. {
  346. .id = 0,
  347. .parent = &per_clk[0],
  348. .secondary = &gpt_ipg_clk[0],
  349. }, {
  350. .id = 1,
  351. .parent = &per_clk[0],
  352. .secondary = &gpt_ipg_clk[1],
  353. }, {
  354. .id = 2,
  355. .parent = &per_clk[0],
  356. .secondary = &gpt_ipg_clk[2],
  357. },
  358. };
  359. static struct clk gpt_ipg_clk[] = {
  360. {
  361. .id = 0,
  362. .parent = &ipg_clk,
  363. .enable = _clk_enable,
  364. .enable_reg = CCM_PCCR_GPT1_REG,
  365. .enable_shift = CCM_PCCR_GPT1_OFFSET,
  366. .disable = _clk_disable,
  367. }, {
  368. .id = 1,
  369. .parent = &ipg_clk,
  370. .enable = _clk_enable,
  371. .enable_reg = CCM_PCCR_GPT2_REG,
  372. .enable_shift = CCM_PCCR_GPT2_OFFSET,
  373. .disable = _clk_disable,
  374. }, {
  375. .id = 2,
  376. .parent = &ipg_clk,
  377. .enable = _clk_enable,
  378. .enable_reg = CCM_PCCR_GPT3_REG,
  379. .enable_shift = CCM_PCCR_GPT3_OFFSET,
  380. .disable = _clk_disable,
  381. },
  382. };
  383. static struct clk pwm_clk[] = {
  384. {
  385. .parent = &per_clk[0],
  386. .secondary = &pwm_clk[1],
  387. }, {
  388. .parent = &ipg_clk,
  389. .enable = _clk_enable,
  390. .enable_reg = CCM_PCCR_PWM_REG,
  391. .enable_shift = CCM_PCCR_PWM_OFFSET,
  392. .disable = _clk_disable,
  393. },
  394. };
  395. static struct clk sdhc_ipg_clk[];
  396. static struct clk sdhc_clk[] = {
  397. {
  398. .id = 0,
  399. .parent = &per_clk[1],
  400. .secondary = &sdhc_ipg_clk[0],
  401. }, {
  402. .id = 1,
  403. .parent = &per_clk[1],
  404. .secondary = &sdhc_ipg_clk[1],
  405. },
  406. };
  407. static struct clk sdhc_ipg_clk[] = {
  408. {
  409. .id = 0,
  410. .parent = &ipg_clk,
  411. .enable = _clk_enable,
  412. .enable_reg = CCM_PCCR_SDHC1_REG,
  413. .enable_shift = CCM_PCCR_SDHC1_OFFSET,
  414. .disable = _clk_disable,
  415. }, {
  416. .id = 1,
  417. .parent = &ipg_clk,
  418. .enable = _clk_enable,
  419. .enable_reg = CCM_PCCR_SDHC2_REG,
  420. .enable_shift = CCM_PCCR_SDHC2_OFFSET,
  421. .disable = _clk_disable,
  422. },
  423. };
  424. static struct clk cspi_ipg_clk[];
  425. static struct clk cspi_clk[] = {
  426. {
  427. .id = 0,
  428. .parent = &per_clk[1],
  429. .secondary = &cspi_ipg_clk[0],
  430. }, {
  431. .id = 1,
  432. .parent = &per_clk[1],
  433. .secondary = &cspi_ipg_clk[1],
  434. }, {
  435. .id = 2,
  436. .parent = &per_clk[1],
  437. .secondary = &cspi_ipg_clk[2],
  438. },
  439. };
  440. static struct clk cspi_ipg_clk[] = {
  441. {
  442. .id = 0,
  443. .parent = &ipg_clk,
  444. .enable = _clk_enable,
  445. .enable_reg = CCM_PCCR_CSPI1_REG,
  446. .enable_shift = CCM_PCCR_CSPI1_OFFSET,
  447. .disable = _clk_disable,
  448. }, {
  449. .id = 1,
  450. .parent = &ipg_clk,
  451. .enable = _clk_enable,
  452. .enable_reg = CCM_PCCR_CSPI2_REG,
  453. .enable_shift = CCM_PCCR_CSPI2_OFFSET,
  454. .disable = _clk_disable,
  455. }, {
  456. .id = 3,
  457. .parent = &ipg_clk,
  458. .enable = _clk_enable,
  459. .enable_reg = CCM_PCCR_CSPI3_REG,
  460. .enable_shift = CCM_PCCR_CSPI3_OFFSET,
  461. .disable = _clk_disable,
  462. },
  463. };
  464. static struct clk lcdc_clk[] = {
  465. {
  466. .parent = &per_clk[2],
  467. .secondary = &lcdc_clk[1],
  468. .round_rate = _clk_parent_round_rate,
  469. .set_rate = _clk_parent_set_rate,
  470. }, {
  471. .parent = &ipg_clk,
  472. .secondary = &lcdc_clk[2],
  473. .enable = _clk_enable,
  474. .enable_reg = CCM_PCCR_LCDC_REG,
  475. .enable_shift = CCM_PCCR_LCDC_OFFSET,
  476. .disable = _clk_disable,
  477. }, {
  478. .parent = &hclk_clk,
  479. .enable = _clk_enable,
  480. .enable_reg = CCM_PCCR_HCLK_LCDC_REG,
  481. .enable_shift = CCM_PCCR_HCLK_LCDC_OFFSET,
  482. .disable = _clk_disable,
  483. },
  484. };
  485. static struct clk csi_clk[] = {
  486. {
  487. .parent = &per_clk[3],
  488. .secondary = &csi_clk[1],
  489. .round_rate = _clk_parent_round_rate,
  490. .set_rate = _clk_parent_set_rate,
  491. }, {
  492. .parent = &hclk_clk,
  493. .enable = _clk_enable,
  494. .enable_reg = CCM_PCCR_HCLK_CSI_REG,
  495. .enable_shift = CCM_PCCR_HCLK_CSI_OFFSET,
  496. .disable = _clk_disable,
  497. },
  498. };
  499. static struct clk usb_clk[] = {
  500. {
  501. .parent = &spll_clk,
  502. .get_rate = _clk_usb_recalc,
  503. .enable = _clk_enable,
  504. .enable_reg = CCM_PCCR_USBOTG_REG,
  505. .enable_shift = CCM_PCCR_USBOTG_OFFSET,
  506. .disable = _clk_disable,
  507. }, {
  508. .parent = &hclk_clk,
  509. .enable = _clk_enable,
  510. .enable_reg = CCM_PCCR_HCLK_USBOTG_REG,
  511. .enable_shift = CCM_PCCR_HCLK_USBOTG_OFFSET,
  512. .disable = _clk_disable,
  513. }
  514. };
  515. static struct clk ssi_ipg_clk[];
  516. static struct clk ssi_clk[] = {
  517. {
  518. .id = 0,
  519. .parent = &mpll_clk,
  520. .secondary = &ssi_ipg_clk[0],
  521. .get_rate = _clk_ssi1_recalc,
  522. .enable = _clk_enable,
  523. .enable_reg = CCM_PCCR_SSI1_BAUD_REG,
  524. .enable_shift = CCM_PCCR_SSI1_BAUD_OFFSET,
  525. .disable = _clk_disable,
  526. }, {
  527. .id = 1,
  528. .parent = &mpll_clk,
  529. .secondary = &ssi_ipg_clk[1],
  530. .get_rate = _clk_ssi2_recalc,
  531. .enable = _clk_enable,
  532. .enable_reg = CCM_PCCR_SSI2_BAUD_REG,
  533. .enable_shift = CCM_PCCR_SSI2_BAUD_OFFSET,
  534. .disable = _clk_disable,
  535. },
  536. };
  537. static struct clk ssi_ipg_clk[] = {
  538. {
  539. .id = 0,
  540. .parent = &ipg_clk,
  541. .enable = _clk_enable,
  542. .enable_reg = CCM_PCCR_SSI1_REG,
  543. .enable_shift = CCM_PCCR_SSI1_IPG_OFFSET,
  544. .disable = _clk_disable,
  545. }, {
  546. .id = 1,
  547. .parent = &ipg_clk,
  548. .enable = _clk_enable,
  549. .enable_reg = CCM_PCCR_SSI2_REG,
  550. .enable_shift = CCM_PCCR_SSI2_IPG_OFFSET,
  551. .disable = _clk_disable,
  552. },
  553. };
  554. static struct clk nfc_clk = {
  555. .parent = &fclk_clk,
  556. .get_rate = _clk_nfc_recalc,
  557. .enable = _clk_enable,
  558. .enable_reg = CCM_PCCR_NFC_REG,
  559. .enable_shift = CCM_PCCR_NFC_OFFSET,
  560. .disable = _clk_disable,
  561. };
  562. static struct clk dma_clk[] = {
  563. {
  564. .parent = &hclk_clk,
  565. .enable = _clk_enable,
  566. .enable_reg = CCM_PCCR_DMA_REG,
  567. .enable_shift = CCM_PCCR_DMA_OFFSET,
  568. .disable = _clk_disable,
  569. .secondary = &dma_clk[1],
  570. }, {
  571. .enable = _clk_enable,
  572. .enable_reg = CCM_PCCR_HCLK_DMA_REG,
  573. .enable_shift = CCM_PCCR_HCLK_DMA_OFFSET,
  574. .disable = _clk_disable,
  575. },
  576. };
  577. static struct clk brom_clk = {
  578. .parent = &hclk_clk,
  579. .enable = _clk_enable,
  580. .enable_reg = CCM_PCCR_HCLK_BROM_REG,
  581. .enable_shift = CCM_PCCR_HCLK_BROM_OFFSET,
  582. .disable = _clk_disable,
  583. };
  584. static struct clk emma_clk[] = {
  585. {
  586. .parent = &hclk_clk,
  587. .enable = _clk_enable,
  588. .enable_reg = CCM_PCCR_EMMA_REG,
  589. .enable_shift = CCM_PCCR_EMMA_OFFSET,
  590. .disable = _clk_disable,
  591. .secondary = &emma_clk[1],
  592. }, {
  593. .enable = _clk_enable,
  594. .enable_reg = CCM_PCCR_HCLK_EMMA_REG,
  595. .enable_shift = CCM_PCCR_HCLK_EMMA_OFFSET,
  596. .disable = _clk_disable,
  597. }
  598. };
  599. static struct clk slcdc_clk[] = {
  600. {
  601. .parent = &hclk_clk,
  602. .enable = _clk_enable,
  603. .enable_reg = CCM_PCCR_SLCDC_REG,
  604. .enable_shift = CCM_PCCR_SLCDC_OFFSET,
  605. .disable = _clk_disable,
  606. .secondary = &slcdc_clk[1],
  607. }, {
  608. .enable = _clk_enable,
  609. .enable_reg = CCM_PCCR_HCLK_SLCDC_REG,
  610. .enable_shift = CCM_PCCR_HCLK_SLCDC_OFFSET,
  611. .disable = _clk_disable,
  612. }
  613. };
  614. static struct clk wdog_clk = {
  615. .parent = &ipg_clk,
  616. .enable = _clk_enable,
  617. .enable_reg = CCM_PCCR_WDT_REG,
  618. .enable_shift = CCM_PCCR_WDT_OFFSET,
  619. .disable = _clk_disable,
  620. };
  621. static struct clk gpio_clk = {
  622. .parent = &ipg_clk,
  623. .enable = _clk_enable,
  624. .enable_reg = CCM_PCCR_GPIO_REG,
  625. .enable_shift = CCM_PCCR_GPIO_OFFSET,
  626. .disable = _clk_disable,
  627. };
  628. static struct clk i2c_clk = {
  629. .id = 0,
  630. .parent = &ipg_clk,
  631. .enable = _clk_enable,
  632. .enable_reg = CCM_PCCR_I2C1_REG,
  633. .enable_shift = CCM_PCCR_I2C1_OFFSET,
  634. .disable = _clk_disable,
  635. };
  636. static struct clk kpp_clk = {
  637. .parent = &ipg_clk,
  638. .enable = _clk_enable,
  639. .enable_reg = CCM_PCCR_KPP_REG,
  640. .enable_shift = CCM_PCCR_KPP_OFFSET,
  641. .disable = _clk_disable,
  642. };
  643. static struct clk owire_clk = {
  644. .parent = &ipg_clk,
  645. .enable = _clk_enable,
  646. .enable_reg = CCM_PCCR_OWIRE_REG,
  647. .enable_shift = CCM_PCCR_OWIRE_OFFSET,
  648. .disable = _clk_disable,
  649. };
  650. static struct clk rtc_clk = {
  651. .parent = &ipg_clk,
  652. .enable = _clk_enable,
  653. .enable_reg = CCM_PCCR_RTC_REG,
  654. .enable_shift = CCM_PCCR_RTC_OFFSET,
  655. .disable = _clk_disable,
  656. };
  657. static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate)
  658. {
  659. u32 div;
  660. unsigned long parent_rate;
  661. parent_rate = clk_get_rate(clk->parent);
  662. div = parent_rate / rate;
  663. if (parent_rate % rate)
  664. div++;
  665. if (div > 8)
  666. div = 8;
  667. return parent_rate / div;
  668. }
  669. static int _clk_clko_set_rate(struct clk *clk, unsigned long rate)
  670. {
  671. u32 reg;
  672. u32 div;
  673. unsigned long parent_rate;
  674. parent_rate = clk_get_rate(clk->parent);
  675. div = parent_rate / rate;
  676. if (div > 8 || div < 1 || ((parent_rate / div) != rate))
  677. return -EINVAL;
  678. div--;
  679. reg = __raw_readl(CCM_PCDR0);
  680. if (clk->parent == &usb_clk[0]) {
  681. reg &= ~CCM_PCDR0_48MDIV_MASK;
  682. reg |= div << CCM_PCDR0_48MDIV_OFFSET;
  683. }
  684. __raw_writel(reg, CCM_PCDR0);
  685. return 0;
  686. }
  687. static unsigned long _clk_clko_recalc(struct clk *clk)
  688. {
  689. u32 div = 0;
  690. unsigned long parent_rate;
  691. parent_rate = clk_get_rate(clk->parent);
  692. if (clk->parent == &usb_clk[0]) /* 48M */
  693. div = __raw_readl(CCM_PCDR0) & CCM_PCDR0_48MDIV_MASK
  694. >> CCM_PCDR0_48MDIV_OFFSET;
  695. div++;
  696. return parent_rate / div;
  697. }
  698. static struct clk clko_clk;
  699. static int _clk_clko_set_parent(struct clk *clk, struct clk *parent)
  700. {
  701. u32 reg;
  702. reg = __raw_readl(CCM_CCSR) & ~CCM_CCSR_CLKOSEL_MASK;
  703. if (parent == &ckil_clk)
  704. reg |= 0 << CCM_CCSR_CLKOSEL_OFFSET;
  705. else if (parent == &fpm_clk)
  706. reg |= 1 << CCM_CCSR_CLKOSEL_OFFSET;
  707. else if (parent == &ckih_clk)
  708. reg |= 2 << CCM_CCSR_CLKOSEL_OFFSET;
  709. else if (parent == mpll_clk.parent)
  710. reg |= 3 << CCM_CCSR_CLKOSEL_OFFSET;
  711. else if (parent == spll_clk.parent)
  712. reg |= 4 << CCM_CCSR_CLKOSEL_OFFSET;
  713. else if (parent == &mpll_clk)
  714. reg |= 5 << CCM_CCSR_CLKOSEL_OFFSET;
  715. else if (parent == &spll_clk)
  716. reg |= 6 << CCM_CCSR_CLKOSEL_OFFSET;
  717. else if (parent == &fclk_clk)
  718. reg |= 7 << CCM_CCSR_CLKOSEL_OFFSET;
  719. else if (parent == &hclk_clk)
  720. reg |= 8 << CCM_CCSR_CLKOSEL_OFFSET;
  721. else if (parent == &ipg_clk)
  722. reg |= 9 << CCM_CCSR_CLKOSEL_OFFSET;
  723. else if (parent == &per_clk[0])
  724. reg |= 0xA << CCM_CCSR_CLKOSEL_OFFSET;
  725. else if (parent == &per_clk[1])
  726. reg |= 0xB << CCM_CCSR_CLKOSEL_OFFSET;
  727. else if (parent == &per_clk[2])
  728. reg |= 0xC << CCM_CCSR_CLKOSEL_OFFSET;
  729. else if (parent == &per_clk[3])
  730. reg |= 0xD << CCM_CCSR_CLKOSEL_OFFSET;
  731. else if (parent == &ssi_clk[0])
  732. reg |= 0xE << CCM_CCSR_CLKOSEL_OFFSET;
  733. else if (parent == &ssi_clk[1])
  734. reg |= 0xF << CCM_CCSR_CLKOSEL_OFFSET;
  735. else if (parent == &nfc_clk)
  736. reg |= 0x10 << CCM_CCSR_CLKOSEL_OFFSET;
  737. else if (parent == &usb_clk[0])
  738. reg |= 0x14 << CCM_CCSR_CLKOSEL_OFFSET;
  739. else if (parent == &clko_clk)
  740. reg |= 0x15 << CCM_CCSR_CLKOSEL_OFFSET;
  741. else
  742. return -EINVAL;
  743. __raw_writel(reg, CCM_CCSR);
  744. return 0;
  745. }
  746. static struct clk clko_clk = {
  747. .get_rate = _clk_clko_recalc,
  748. .set_rate = _clk_clko_set_rate,
  749. .round_rate = _clk_clko_round_rate,
  750. .set_parent = _clk_clko_set_parent,
  751. };
  752. #define _REGISTER_CLOCK(d, n, c) \
  753. { \
  754. .dev_id = d, \
  755. .con_id = n, \
  756. .clk = &c, \
  757. },
  758. static struct clk_lookup lookups[] __initdata = {
  759. /* It's unlikely that any driver wants one of them directly:
  760. _REGISTER_CLOCK(NULL, "ckih", ckih_clk)
  761. _REGISTER_CLOCK(NULL, "ckil", ckil_clk)
  762. _REGISTER_CLOCK(NULL, "fpm", fpm_clk)
  763. _REGISTER_CLOCK(NULL, "mpll", mpll_clk)
  764. _REGISTER_CLOCK(NULL, "spll", spll_clk)
  765. _REGISTER_CLOCK(NULL, "fclk", fclk_clk)
  766. _REGISTER_CLOCK(NULL, "hclk", hclk_clk)
  767. _REGISTER_CLOCK(NULL, "ipg", ipg_clk)
  768. */
  769. _REGISTER_CLOCK(NULL, "perclk1", per_clk[0])
  770. _REGISTER_CLOCK(NULL, "perclk2", per_clk[1])
  771. _REGISTER_CLOCK(NULL, "perclk3", per_clk[2])
  772. _REGISTER_CLOCK(NULL, "perclk4", per_clk[3])
  773. _REGISTER_CLOCK(NULL, "clko", clko_clk)
  774. _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0])
  775. _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[1])
  776. _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[2])
  777. _REGISTER_CLOCK("imx-uart.3", NULL, uart_clk[3])
  778. _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[0])
  779. _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[1])
  780. _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[2])
  781. _REGISTER_CLOCK(NULL, "pwm", pwm_clk[0])
  782. _REGISTER_CLOCK(NULL, "sdhc1", sdhc_clk[0])
  783. _REGISTER_CLOCK(NULL, "sdhc2", sdhc_clk[1])
  784. _REGISTER_CLOCK(NULL, "cspi1", cspi_clk[0])
  785. _REGISTER_CLOCK(NULL, "cspi2", cspi_clk[1])
  786. _REGISTER_CLOCK(NULL, "cspi3", cspi_clk[2])
  787. _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0])
  788. _REGISTER_CLOCK(NULL, "csi", csi_clk[0])
  789. _REGISTER_CLOCK(NULL, "usb", usb_clk[0])
  790. _REGISTER_CLOCK(NULL, "ssi1", ssi_clk[0])
  791. _REGISTER_CLOCK(NULL, "ssi2", ssi_clk[1])
  792. _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
  793. _REGISTER_CLOCK(NULL, "dma", dma_clk[0])
  794. _REGISTER_CLOCK(NULL, "brom", brom_clk)
  795. _REGISTER_CLOCK(NULL, "emma", emma_clk[0])
  796. _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk[0])
  797. _REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
  798. _REGISTER_CLOCK(NULL, "gpio", gpio_clk)
  799. _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
  800. _REGISTER_CLOCK("mxc-keypad", NULL, kpp_clk)
  801. _REGISTER_CLOCK(NULL, "owire", owire_clk)
  802. _REGISTER_CLOCK(NULL, "rtc", rtc_clk)
  803. };
  804. /*
  805. * must be called very early to get information about the
  806. * available clock rate when the timer framework starts
  807. */
  808. int __init mx21_clocks_init(unsigned long lref, unsigned long href)
  809. {
  810. int i;
  811. u32 cscr;
  812. external_low_reference = lref;
  813. external_high_reference = href;
  814. /* detect clock reference for both system PLL */
  815. cscr = CSCR();
  816. if (cscr & CCM_CSCR_MCU)
  817. mpll_clk.parent = &ckih_clk;
  818. else
  819. mpll_clk.parent = &fpm_clk;
  820. if (cscr & CCM_CSCR_SP)
  821. spll_clk.parent = &ckih_clk;
  822. else
  823. spll_clk.parent = &fpm_clk;
  824. for (i = 0; i < ARRAY_SIZE(lookups); i++)
  825. clkdev_add(&lookups[i]);
  826. /* Turn off all clock gates */
  827. __raw_writel(0, CCM_PCCR0);
  828. __raw_writel(CCM_PCCR_GPT1_MASK, CCM_PCCR1);
  829. /* This turns of the serial PLL as well */
  830. spll_clk.disable(&spll_clk);
  831. /* This will propagate to all children and init all the clock rates. */
  832. clk_enable(&per_clk[0]);
  833. clk_enable(&gpio_clk);
  834. #ifdef CONFIG_DEBUG_LL_CONSOLE
  835. clk_enable(&uart_clk[0]);
  836. #endif
  837. mxc_timer_init(&gpt_clk[0]);
  838. return 0;
  839. }