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