MXC PLL decoding: calculate mfn value with less magic
[deliverable/linux.git] / arch / arm / mach-mx1 / clock.c
CommitLineData
cfca8b53
PZ
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
19#include <linux/kernel.h>
20#include <linux/init.h>
21#include <linux/math64.h>
22#include <linux/err.h>
23#include <linux/clk.h>
24#include <linux/io.h>
25
26#include <mach/clock.h>
27#include <mach/hardware.h>
30c730f8 28#include <mach/common.h>
cfca8b53
PZ
29#include "crm_regs.h"
30
31static int _clk_enable(struct clk *clk)
32{
33 unsigned int reg;
34
35 reg = __raw_readl(clk->enable_reg);
36 reg |= 1 << clk->enable_shift;
37 __raw_writel(reg, clk->enable_reg);
38
39 return 0;
40}
41
42static void _clk_disable(struct clk *clk)
43{
44 unsigned int reg;
45
46 reg = __raw_readl(clk->enable_reg);
47 reg &= ~(1 << clk->enable_shift);
48 __raw_writel(reg, clk->enable_reg);
49}
50
51static int _clk_can_use_parent(const struct clk *clk_arr[], unsigned int size,
52 struct clk *parent)
53{
54 int i;
55
56 for (i = 0; i < size; i++)
57 if (parent == clk_arr[i])
58 return i;
59
60 return -EINVAL;
61}
62
63static unsigned long
64_clk_simple_round_rate(struct clk *clk, unsigned long rate, unsigned int limit)
65{
66 int div;
67 unsigned long parent_rate;
68
69 parent_rate = clk_get_rate(clk->parent);
70
71 div = parent_rate / rate;
72 if (parent_rate % rate)
73 div++;
74
75 if (div > limit)
76 div = limit;
77
78 return parent_rate / div;
79}
80
81static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate)
82{
83 return clk->parent->round_rate(clk->parent, rate);
84}
85
86static int _clk_parent_set_rate(struct clk *clk, unsigned long rate)
87{
88 return clk->parent->set_rate(clk->parent, rate);
89}
90
cfca8b53
PZ
91static unsigned long clk16m_get_rate(struct clk *clk)
92{
93 return 16000000;
94}
95
96static struct clk clk16m = {
97 .name = "CLK16M",
98 .get_rate = clk16m_get_rate,
99 .enable = _clk_enable,
100 .enable_reg = CCM_CSCR,
101 .enable_shift = CCM_CSCR_OSC_EN_SHIFT,
102 .disable = _clk_disable,
103};
104
105/* in Hz */
106static unsigned long clk32_rate;
107
108static unsigned long clk32_get_rate(struct clk *clk)
109{
110 return clk32_rate;
111}
112
113static struct clk clk32 = {
114 .name = "CLK32",
115 .get_rate = clk32_get_rate,
116};
117
118static unsigned long clk32_premult_get_rate(struct clk *clk)
119{
120 return clk_get_rate(clk->parent) * 512;
121}
122
123static struct clk clk32_premult = {
124 .name = "CLK32_premultiplier",
125 .parent = &clk32,
126 .get_rate = clk32_premult_get_rate,
127};
128
129static const struct clk *prem_clk_clocks[] = {
130 &clk32_premult,
131 &clk16m,
132};
133
134static int prem_clk_set_parent(struct clk *clk, struct clk *parent)
135{
136 int i;
137 unsigned int reg = __raw_readl(CCM_CSCR);
138
139 i = _clk_can_use_parent(prem_clk_clocks, ARRAY_SIZE(prem_clk_clocks),
140 parent);
141
142 switch (i) {
143 case 0:
144 reg &= ~CCM_CSCR_SYSTEM_SEL;
145 break;
146 case 1:
147 reg |= CCM_CSCR_SYSTEM_SEL;
148 break;
149 default:
150 return i;
151 }
152
153 __raw_writel(reg, CCM_CSCR);
154
155 return 0;
156}
157
158static struct clk prem_clk = {
159 .name = "prem_clk",
160 .set_parent = prem_clk_set_parent,
161};
162
163static unsigned long system_clk_get_rate(struct clk *clk)
164{
a2865197 165 return mxc_decode_pll(__raw_readl(CCM_SPCTL0),
cfca8b53
PZ
166 clk_get_rate(clk->parent));
167}
168
169static struct clk system_clk = {
170 .name = "system_clk",
171 .parent = &prem_clk,
172 .get_rate = system_clk_get_rate,
173};
174
175static unsigned long mcu_clk_get_rate(struct clk *clk)
176{
a2865197 177 return mxc_decode_pll(__raw_readl(CCM_MPCTL0),
cfca8b53
PZ
178 clk_get_rate(clk->parent));
179}
180
181static struct clk mcu_clk = {
182 .name = "mcu_clk",
183 .parent = &clk32_premult,
184 .get_rate = mcu_clk_get_rate,
185};
186
187static unsigned long fclk_get_rate(struct clk *clk)
188{
189 unsigned long fclk = clk_get_rate(clk->parent);
190
191 if (__raw_readl(CCM_CSCR) & CCM_CSCR_PRESC)
192 fclk /= 2;
193
194 return fclk;
195}
196
197static struct clk fclk = {
198 .name = "fclk",
199 .parent = &mcu_clk,
200 .get_rate = fclk_get_rate,
201};
202
203/*
204 * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
205 */
206static unsigned long hclk_get_rate(struct clk *clk)
207{
208 return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) &
209 CCM_CSCR_BCLK_MASK) >> CCM_CSCR_BCLK_OFFSET) + 1);
210}
211
212static unsigned long hclk_round_rate(struct clk *clk, unsigned long rate)
213{
214 return _clk_simple_round_rate(clk, rate, 16);
215}
216
217static int hclk_set_rate(struct clk *clk, unsigned long rate)
218{
219 unsigned int div;
220 unsigned int reg;
221 unsigned long parent_rate;
222
223 parent_rate = clk_get_rate(clk->parent);
224
225 div = parent_rate / rate;
226
227 if (div > 16 || div < 1 || ((parent_rate / div) != rate))
228 return -EINVAL;
229
230 div--;
231
232 reg = __raw_readl(CCM_CSCR);
233 reg &= ~CCM_CSCR_BCLK_MASK;
234 reg |= div << CCM_CSCR_BCLK_OFFSET;
235 __raw_writel(reg, CCM_CSCR);
236
237 return 0;
238}
239
240static struct clk hclk = {
241 .name = "hclk",
242 .parent = &system_clk,
243 .get_rate = hclk_get_rate,
244 .round_rate = hclk_round_rate,
245 .set_rate = hclk_set_rate,
246};
247
248static unsigned long clk48m_get_rate(struct clk *clk)
249{
250 return clk_get_rate(clk->parent) / (((__raw_readl(CCM_CSCR) &
251 CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET) + 1);
252}
253
254static unsigned long clk48m_round_rate(struct clk *clk, unsigned long rate)
255{
256 return _clk_simple_round_rate(clk, rate, 8);
257}
258
259static int clk48m_set_rate(struct clk *clk, unsigned long rate)
260{
261 unsigned int div;
262 unsigned int reg;
263 unsigned long parent_rate;
264
265 parent_rate = clk_get_rate(clk->parent);
266
267 div = parent_rate / rate;
268
269 if (div > 8 || div < 1 || ((parent_rate / div) != rate))
270 return -EINVAL;
271
272 div--;
273
274 reg = __raw_readl(CCM_CSCR);
275 reg &= ~CCM_CSCR_USB_MASK;
276 reg |= div << CCM_CSCR_USB_OFFSET;
277 __raw_writel(reg, CCM_CSCR);
278
279 return 0;
280}
281
282static struct clk clk48m = {
283 .name = "CLK48M",
284 .parent = &system_clk,
285 .get_rate = clk48m_get_rate,
286 .round_rate = clk48m_round_rate,
287 .set_rate = clk48m_set_rate,
288};
289
290/*
291 * get peripheral clock 1 ( UART[12], Timer[12], PWM )
292 */
293static unsigned long perclk1_get_rate(struct clk *clk)
294{
295 return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
296 CCM_PCDR_PCLK1_MASK) >> CCM_PCDR_PCLK1_OFFSET) + 1);
297}
298
299static unsigned long perclk1_round_rate(struct clk *clk, unsigned long rate)
300{
301 return _clk_simple_round_rate(clk, rate, 16);
302}
303
304static int perclk1_set_rate(struct clk *clk, unsigned long rate)
305{
306 unsigned int div;
307 unsigned int reg;
308 unsigned long parent_rate;
309
310 parent_rate = clk_get_rate(clk->parent);
311
312 div = parent_rate / rate;
313
314 if (div > 16 || div < 1 || ((parent_rate / div) != rate))
315 return -EINVAL;
316
317 div--;
318
319 reg = __raw_readl(CCM_PCDR);
320 reg &= ~CCM_PCDR_PCLK1_MASK;
321 reg |= div << CCM_PCDR_PCLK1_OFFSET;
322 __raw_writel(reg, CCM_PCDR);
323
324 return 0;
325}
326
327/*
328 * get peripheral clock 2 ( LCD, SD, SPI[12] )
329 */
330static unsigned long perclk2_get_rate(struct clk *clk)
331{
332 return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
333 CCM_PCDR_PCLK2_MASK) >> CCM_PCDR_PCLK2_OFFSET) + 1);
334}
335
336static unsigned long perclk2_round_rate(struct clk *clk, unsigned long rate)
337{
338 return _clk_simple_round_rate(clk, rate, 16);
339}
340
341static int perclk2_set_rate(struct clk *clk, unsigned long rate)
342{
343 unsigned int div;
344 unsigned int reg;
345 unsigned long parent_rate;
346
347 parent_rate = clk_get_rate(clk->parent);
348
349 div = parent_rate / rate;
350
351 if (div > 16 || div < 1 || ((parent_rate / div) != rate))
352 return -EINVAL;
353
354 div--;
355
356 reg = __raw_readl(CCM_PCDR);
357 reg &= ~CCM_PCDR_PCLK2_MASK;
358 reg |= div << CCM_PCDR_PCLK2_OFFSET;
359 __raw_writel(reg, CCM_PCDR);
360
361 return 0;
362}
363
364/*
365 * get peripheral clock 3 ( SSI )
366 */
367static unsigned long perclk3_get_rate(struct clk *clk)
368{
369 return clk_get_rate(clk->parent) / (((__raw_readl(CCM_PCDR) &
370 CCM_PCDR_PCLK3_MASK) >> CCM_PCDR_PCLK3_OFFSET) + 1);
371}
372
373static unsigned long perclk3_round_rate(struct clk *clk, unsigned long rate)
374{
375 return _clk_simple_round_rate(clk, rate, 128);
376}
377
378static int perclk3_set_rate(struct clk *clk, unsigned long rate)
379{
380 unsigned int div;
381 unsigned int reg;
382 unsigned long parent_rate;
383
384 parent_rate = clk_get_rate(clk->parent);
385
386 div = parent_rate / rate;
387
388 if (div > 128 || div < 1 || ((parent_rate / div) != rate))
389 return -EINVAL;
390
391 div--;
392
393 reg = __raw_readl(CCM_PCDR);
394 reg &= ~CCM_PCDR_PCLK3_MASK;
395 reg |= div << CCM_PCDR_PCLK3_OFFSET;
396 __raw_writel(reg, CCM_PCDR);
397
398 return 0;
399}
400
401static struct clk perclk[] = {
402 {
403 .name = "perclk",
404 .id = 0,
405 .parent = &system_clk,
406 .get_rate = perclk1_get_rate,
407 .round_rate = perclk1_round_rate,
408 .set_rate = perclk1_set_rate,
409 }, {
410 .name = "perclk",
411 .id = 1,
412 .parent = &system_clk,
413 .get_rate = perclk2_get_rate,
414 .round_rate = perclk2_round_rate,
415 .set_rate = perclk2_set_rate,
416 }, {
417 .name = "perclk",
418 .id = 2,
419 .parent = &system_clk,
420 .get_rate = perclk3_get_rate,
421 .round_rate = perclk3_round_rate,
422 .set_rate = perclk3_set_rate,
423 }
424};
425
426static const struct clk *clko_clocks[] = {
427 &perclk[0],
428 &hclk,
429 &clk48m,
430 &clk16m,
431 &prem_clk,
432 &fclk,
433};
434
435static int clko_set_parent(struct clk *clk, struct clk *parent)
436{
437 int i;
438 unsigned int reg;
439
440 i = _clk_can_use_parent(clko_clocks, ARRAY_SIZE(clko_clocks), parent);
441 if (i < 0)
442 return i;
443
444 reg = __raw_readl(CCM_CSCR) & ~CCM_CSCR_CLKO_MASK;
445 reg |= i << CCM_CSCR_CLKO_OFFSET;
446 __raw_writel(reg, CCM_CSCR);
447
448 if (clko_clocks[i]->set_rate && clko_clocks[i]->round_rate) {
449 clk->set_rate = _clk_parent_set_rate;
450 clk->round_rate = _clk_parent_round_rate;
451 } else {
452 clk->set_rate = NULL;
453 clk->round_rate = NULL;
454 }
455
456 return 0;
457}
458
459static struct clk clko_clk = {
460 .name = "clko_clk",
461 .set_parent = clko_set_parent,
462};
463
464static struct clk dma_clk = {
e65fb009 465 .name = "dma",
cfca8b53
PZ
466 .parent = &hclk,
467 .round_rate = _clk_parent_round_rate,
468 .set_rate = _clk_parent_set_rate,
469 .enable = _clk_enable,
470 .enable_reg = SCM_GCCR,
471 .enable_shift = SCM_GCCR_DMA_CLK_EN_OFFSET,
472 .disable = _clk_disable,
473};
474
475static struct clk csi_clk = {
476 .name = "csi_clk",
477 .parent = &hclk,
478 .round_rate = _clk_parent_round_rate,
479 .set_rate = _clk_parent_set_rate,
480 .enable = _clk_enable,
481 .enable_reg = SCM_GCCR,
482 .enable_shift = SCM_GCCR_CSI_CLK_EN_OFFSET,
483 .disable = _clk_disable,
484};
485
486static struct clk mma_clk = {
487 .name = "mma_clk",
488 .parent = &hclk,
489 .round_rate = _clk_parent_round_rate,
490 .set_rate = _clk_parent_set_rate,
491 .enable = _clk_enable,
492 .enable_reg = SCM_GCCR,
493 .enable_shift = SCM_GCCR_MMA_CLK_EN_OFFSET,
494 .disable = _clk_disable,
495};
496
497static struct clk usbd_clk = {
498 .name = "usbd_clk",
499 .parent = &clk48m,
500 .round_rate = _clk_parent_round_rate,
501 .set_rate = _clk_parent_set_rate,
502 .enable = _clk_enable,
503 .enable_reg = SCM_GCCR,
504 .enable_shift = SCM_GCCR_USBD_CLK_EN_OFFSET,
505 .disable = _clk_disable,
506};
507
508static struct clk gpt_clk = {
509 .name = "gpt_clk",
510 .parent = &perclk[0],
511 .round_rate = _clk_parent_round_rate,
512 .set_rate = _clk_parent_set_rate,
513};
514
515static struct clk uart_clk = {
e65fb009 516 .name = "uart",
cfca8b53
PZ
517 .parent = &perclk[0],
518 .round_rate = _clk_parent_round_rate,
519 .set_rate = _clk_parent_set_rate,
520};
521
522static struct clk i2c_clk = {
523 .name = "i2c_clk",
524 .parent = &hclk,
525 .round_rate = _clk_parent_round_rate,
526 .set_rate = _clk_parent_set_rate,
527};
528
529static struct clk spi_clk = {
530 .name = "spi_clk",
531 .parent = &perclk[1],
532 .round_rate = _clk_parent_round_rate,
533 .set_rate = _clk_parent_set_rate,
534};
535
536static struct clk sdhc_clk = {
537 .name = "sdhc_clk",
538 .parent = &perclk[1],
539 .round_rate = _clk_parent_round_rate,
540 .set_rate = _clk_parent_set_rate,
541};
542
543static struct clk lcdc_clk = {
544 .name = "lcdc_clk",
545 .parent = &perclk[1],
546 .round_rate = _clk_parent_round_rate,
547 .set_rate = _clk_parent_set_rate,
548};
549
550static struct clk mshc_clk = {
551 .name = "mshc_clk",
552 .parent = &hclk,
553 .round_rate = _clk_parent_round_rate,
554 .set_rate = _clk_parent_set_rate,
555};
556
557static struct clk ssi_clk = {
558 .name = "ssi_clk",
559 .parent = &perclk[2],
560 .round_rate = _clk_parent_round_rate,
561 .set_rate = _clk_parent_set_rate,
562};
563
564static struct clk rtc_clk = {
565 .name = "rtc_clk",
566 .parent = &clk32,
567};
568
569static struct clk *mxc_clks[] = {
570 &clk16m,
571 &clk32,
572 &clk32_premult,
573 &prem_clk,
574 &system_clk,
575 &mcu_clk,
576 &fclk,
577 &hclk,
578 &clk48m,
579 &perclk[0],
580 &perclk[1],
581 &perclk[2],
582 &clko_clk,
583 &dma_clk,
584 &csi_clk,
585 &mma_clk,
586 &usbd_clk,
587 &gpt_clk,
588 &uart_clk,
589 &i2c_clk,
590 &spi_clk,
591 &sdhc_clk,
592 &lcdc_clk,
593 &mshc_clk,
594 &ssi_clk,
595 &rtc_clk,
596};
597
30c730f8 598int __init mx1_clocks_init(unsigned long fref)
cfca8b53
PZ
599{
600 struct clk **clkp;
601 unsigned int reg;
602
603 /* disable clocks we are able to */
604 __raw_writel(0, SCM_GCCR);
605
606 clk32_rate = fref;
607 reg = __raw_readl(CCM_CSCR);
608
609 /* detect clock reference for system PLL */
610 if (reg & CCM_CSCR_SYSTEM_SEL) {
611 prem_clk.parent = &clk16m;
612 } else {
613 /* ensure that oscillator is disabled */
614 reg &= ~(1 << CCM_CSCR_OSC_EN_SHIFT);
615 __raw_writel(reg, CCM_CSCR);
616 prem_clk.parent = &clk32_premult;
617 }
618
619 /* detect reference for CLKO */
620 reg = (reg & CCM_CSCR_CLKO_MASK) >> CCM_CSCR_CLKO_OFFSET;
621 clko_clk.parent = (struct clk *)clko_clocks[reg];
622
623 for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++)
624 clk_register(*clkp);
625
626 clk_enable(&hclk);
627 clk_enable(&fclk);
628
8db5d1a6 629 mxc_timer_init(&gpt_clk, IO_ADDRESS(TIM1_BASE_ADDR), TIM1_INT);
30c730f8 630
cfca8b53
PZ
631 return 0;
632}
This page took 0.088875 seconds and 5 git commands to generate.