blob: eede79855f4af0565217f94c7b2e8ce6412f9e56 [file] [log] [blame]
Holger Schurigaa3b0a62009-01-26 16:34:54 +01001/*
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
21#include <linux/clk.h>
22#include <linux/io.h>
23#include <linux/module.h>
24
25#include <mach/clock.h>
26#include <mach/common.h>
27#include <asm/clkdev.h>
28#include <asm/div64.h>
29
30#include "crm_regs.h"
31
32static int _clk_enable(struct clk *clk)
33{
34 u32 reg;
35
36 reg = __raw_readl(clk->enable_reg);
37 reg |= 1 << clk->enable_shift;
38 __raw_writel(reg, clk->enable_reg);
39 return 0;
40}
41
42static void _clk_disable(struct clk *clk)
43{
44 u32 reg;
45
46 reg = __raw_readl(clk->enable_reg);
47 reg &= ~(1 << clk->enable_shift);
48 __raw_writel(reg, clk->enable_reg);
49}
50
Martin Fuzzeya0895162009-06-06 16:36:44 +020051static unsigned long _clk_generic_round_rate(struct clk *clk,
52 unsigned long rate,
53 u32 max_divisor)
54{
55 u32 div;
56 unsigned long parent_rate;
57
58 parent_rate = clk_get_rate(clk->parent);
59
60 div = parent_rate / rate;
61 if (parent_rate % rate)
62 div++;
63
64 if (div > max_divisor)
65 div = max_divisor;
66
67 return parent_rate / div;
68}
69
Holger Schurigaa3b0a62009-01-26 16:34:54 +010070static int _clk_spll_enable(struct clk *clk)
71{
72 u32 reg;
73
74 reg = __raw_readl(CCM_CSCR);
75 reg |= CCM_CSCR_SPEN;
76 __raw_writel(reg, CCM_CSCR);
77
78 while ((__raw_readl(CCM_SPCTL1) & CCM_SPCTL1_LF) == 0)
79 ;
80 return 0;
81}
82
83static void _clk_spll_disable(struct clk *clk)
84{
85 u32 reg;
86
87 reg = __raw_readl(CCM_CSCR);
88 reg &= ~CCM_CSCR_SPEN;
89 __raw_writel(reg, CCM_CSCR);
90}
91
92
93#define CSCR() (__raw_readl(CCM_CSCR))
94#define PCDR0() (__raw_readl(CCM_PCDR0))
95#define PCDR1() (__raw_readl(CCM_PCDR1))
96
97static unsigned long _clk_perclkx_round_rate(struct clk *clk,
98 unsigned long rate)
99{
Martin Fuzzeya0895162009-06-06 16:36:44 +0200100 return _clk_generic_round_rate(clk, rate, 64);
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100101}
102
103static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate)
104{
105 u32 reg;
106 u32 div;
107 unsigned long parent_rate;
108
109 parent_rate = clk_get_rate(clk->parent);
110
111 if (clk->id < 0 || clk->id > 3)
112 return -EINVAL;
113
114 div = parent_rate / rate;
115 if (div > 64 || div < 1 || ((parent_rate / div) != rate))
116 return -EINVAL;
117 div--;
118
119 reg =
120 __raw_readl(CCM_PCDR1) & ~(CCM_PCDR1_PERDIV1_MASK <<
121 (clk->id << 3));
122 reg |= div << (clk->id << 3);
123 __raw_writel(reg, CCM_PCDR1);
124
125 return 0;
126}
127
128static unsigned long _clk_usb_recalc(struct clk *clk)
129{
130 unsigned long usb_pdf;
131 unsigned long parent_rate;
132
133 parent_rate = clk_get_rate(clk->parent);
134
135 usb_pdf = (CSCR() & CCM_CSCR_USB_MASK) >> CCM_CSCR_USB_OFFSET;
136
137 return parent_rate / (usb_pdf + 1U);
138}
139
Martin Fuzzeya0895162009-06-06 16:36:44 +0200140static unsigned long _clk_usb_round_rate(struct clk *clk,
141 unsigned long rate)
142{
143 return _clk_generic_round_rate(clk, rate, 8);
144}
145
146static int _clk_usb_set_rate(struct clk *clk, unsigned long rate)
147{
148 u32 reg;
149 u32 div;
150 unsigned long parent_rate;
151
152 parent_rate = clk_get_rate(clk->parent);
153
154 div = parent_rate / rate;
155 if (div > 8 || div < 1 || ((parent_rate / div) != rate))
156 return -EINVAL;
157 div--;
158
159 reg = CSCR() & ~CCM_CSCR_USB_MASK;
160 reg |= div << CCM_CSCR_USB_OFFSET;
161 __raw_writel(reg, CCM_CSCR);
162
163 return 0;
164}
165
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100166static unsigned long _clk_ssix_recalc(struct clk *clk, unsigned long pdf)
167{
168 unsigned long parent_rate;
169
170 parent_rate = clk_get_rate(clk->parent);
171
172 pdf = (pdf < 2) ? 124UL : pdf; /* MX21 & MX27 TO1 */
173
174 return 2UL * parent_rate / pdf;
175}
176
177static unsigned long _clk_ssi1_recalc(struct clk *clk)
178{
179 return _clk_ssix_recalc(clk,
180 (PCDR0() & CCM_PCDR0_SSI1BAUDDIV_MASK)
181 >> CCM_PCDR0_SSI1BAUDDIV_OFFSET);
182}
183
184static unsigned long _clk_ssi2_recalc(struct clk *clk)
185{
186 return _clk_ssix_recalc(clk,
187 (PCDR0() & CCM_PCDR0_SSI2BAUDDIV_MASK) >>
188 CCM_PCDR0_SSI2BAUDDIV_OFFSET);
189}
190
191static unsigned long _clk_nfc_recalc(struct clk *clk)
192{
193 unsigned long nfc_pdf;
194 unsigned long parent_rate;
195
196 parent_rate = clk_get_rate(clk->parent);
197
198 nfc_pdf = (PCDR0() & CCM_PCDR0_NFCDIV_MASK)
199 >> CCM_PCDR0_NFCDIV_OFFSET;
200
201 return parent_rate / (nfc_pdf + 1);
202}
203
204static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate)
205{
206 return clk->parent->round_rate(clk->parent, rate);
207}
208
209static int _clk_parent_set_rate(struct clk *clk, unsigned long rate)
210{
211 return clk->parent->set_rate(clk->parent, rate);
212}
213
214static unsigned long external_high_reference; /* in Hz */
215
216static unsigned long get_high_reference_clock_rate(struct clk *clk)
217{
218 return external_high_reference;
219}
220
221/*
222 * the high frequency external clock reference
223 * Default case is 26MHz.
224 */
225static struct clk ckih_clk = {
226 .get_rate = get_high_reference_clock_rate,
227};
228
229static unsigned long external_low_reference; /* in Hz */
230
231static unsigned long get_low_reference_clock_rate(struct clk *clk)
232{
233 return external_low_reference;
234}
235
236/*
237 * the low frequency external clock reference
238 * Default case is 32.768kHz.
239 */
240static struct clk ckil_clk = {
241 .get_rate = get_low_reference_clock_rate,
242};
243
244
245static unsigned long _clk_fpm_recalc(struct clk *clk)
246{
247 return clk_get_rate(clk->parent) * 512;
248}
249
250/* Output of frequency pre multiplier */
251static struct clk fpm_clk = {
252 .parent = &ckil_clk,
253 .get_rate = _clk_fpm_recalc,
254};
255
256static unsigned long get_mpll_clk(struct clk *clk)
257{
258 uint32_t reg;
259 unsigned long ref_clk;
260 unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
261 unsigned long long temp;
262
263 ref_clk = clk_get_rate(clk->parent);
264
265 reg = __raw_readl(CCM_MPCTL0);
266 pdf = (reg & CCM_MPCTL0_PD_MASK) >> CCM_MPCTL0_PD_OFFSET;
267 mfd = (reg & CCM_MPCTL0_MFD_MASK) >> CCM_MPCTL0_MFD_OFFSET;
268 mfi = (reg & CCM_MPCTL0_MFI_MASK) >> CCM_MPCTL0_MFI_OFFSET;
269 mfn = (reg & CCM_MPCTL0_MFN_MASK) >> CCM_MPCTL0_MFN_OFFSET;
270
271 mfi = (mfi <= 5) ? 5 : mfi;
272 temp = 2LL * ref_clk * mfn;
273 do_div(temp, mfd + 1);
274 temp = 2LL * ref_clk * mfi + temp;
275 do_div(temp, pdf + 1);
276
277 return (unsigned long)temp;
278}
279
280static struct clk mpll_clk = {
281 .parent = &ckih_clk,
282 .get_rate = get_mpll_clk,
283};
284
285static unsigned long _clk_fclk_get_rate(struct clk *clk)
286{
287 unsigned long parent_rate;
288 u32 div;
289
290 div = (CSCR() & CCM_CSCR_PRESC_MASK) >> CCM_CSCR_PRESC_OFFSET;
291 parent_rate = clk_get_rate(clk->parent);
292
293 return parent_rate / (div+1);
294}
295
296static struct clk fclk_clk = {
297 .parent = &mpll_clk,
298 .get_rate = _clk_fclk_get_rate
299};
300
301static unsigned long get_spll_clk(struct clk *clk)
302{
303 uint32_t reg;
304 unsigned long ref_clk;
305 unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
306 unsigned long long temp;
307
308 ref_clk = clk_get_rate(clk->parent);
309
310 reg = __raw_readl(CCM_SPCTL0);
311 pdf = (reg & CCM_SPCTL0_PD_MASK) >> CCM_SPCTL0_PD_OFFSET;
312 mfd = (reg & CCM_SPCTL0_MFD_MASK) >> CCM_SPCTL0_MFD_OFFSET;
313 mfi = (reg & CCM_SPCTL0_MFI_MASK) >> CCM_SPCTL0_MFI_OFFSET;
314 mfn = (reg & CCM_SPCTL0_MFN_MASK) >> CCM_SPCTL0_MFN_OFFSET;
315
316 mfi = (mfi <= 5) ? 5 : mfi;
317 temp = 2LL * ref_clk * mfn;
318 do_div(temp, mfd + 1);
319 temp = 2LL * ref_clk * mfi + temp;
320 do_div(temp, pdf + 1);
321
322 return (unsigned long)temp;
323}
324
325static struct clk spll_clk = {
326 .parent = &ckih_clk,
327 .get_rate = get_spll_clk,
328 .enable = _clk_spll_enable,
329 .disable = _clk_spll_disable,
330};
331
332static unsigned long get_hclk_clk(struct clk *clk)
333{
334 unsigned long rate;
335 unsigned long bclk_pdf;
336
337 bclk_pdf = (CSCR() & CCM_CSCR_BCLK_MASK)
338 >> CCM_CSCR_BCLK_OFFSET;
339
340 rate = clk_get_rate(clk->parent);
341 return rate / (bclk_pdf + 1);
342}
343
344static struct clk hclk_clk = {
345 .parent = &fclk_clk,
346 .get_rate = get_hclk_clk,
347};
348
349static unsigned long get_ipg_clk(struct clk *clk)
350{
351 unsigned long rate;
352 unsigned long ipg_pdf;
353
354 ipg_pdf = (CSCR() & CCM_CSCR_IPDIV) >> CCM_CSCR_IPDIV_OFFSET;
355
356 rate = clk_get_rate(clk->parent);
357 return rate / (ipg_pdf + 1);
358}
359
360static struct clk ipg_clk = {
361 .parent = &hclk_clk,
362 .get_rate = get_ipg_clk,
363};
364
365static unsigned long _clk_perclkx_recalc(struct clk *clk)
366{
367 unsigned long perclk_pdf;
368 unsigned long parent_rate;
369
370 parent_rate = clk_get_rate(clk->parent);
371
372 if (clk->id < 0 || clk->id > 3)
373 return 0;
374
375 perclk_pdf = (PCDR1() >> (clk->id << 3)) & CCM_PCDR1_PERDIV1_MASK;
376
377 return parent_rate / (perclk_pdf + 1);
378}
379
380static struct clk per_clk[] = {
381 {
382 .id = 0,
383 .parent = &mpll_clk,
384 .get_rate = _clk_perclkx_recalc,
385 }, {
386 .id = 1,
387 .parent = &mpll_clk,
388 .get_rate = _clk_perclkx_recalc,
389 }, {
390 .id = 2,
391 .parent = &mpll_clk,
392 .round_rate = _clk_perclkx_round_rate,
393 .set_rate = _clk_perclkx_set_rate,
394 .get_rate = _clk_perclkx_recalc,
395 /* Enable/Disable done via lcd_clkc[1] */
396 }, {
397 .id = 3,
398 .parent = &mpll_clk,
399 .round_rate = _clk_perclkx_round_rate,
400 .set_rate = _clk_perclkx_set_rate,
401 .get_rate = _clk_perclkx_recalc,
402 /* Enable/Disable done via csi_clk[1] */
403 },
404};
405
406static struct clk uart_ipg_clk[];
407
408static struct clk uart_clk[] = {
409 {
410 .id = 0,
411 .parent = &per_clk[0],
412 .secondary = &uart_ipg_clk[0],
413 }, {
414 .id = 1,
415 .parent = &per_clk[0],
416 .secondary = &uart_ipg_clk[1],
417 }, {
418 .id = 2,
419 .parent = &per_clk[0],
420 .secondary = &uart_ipg_clk[2],
421 }, {
422 .id = 3,
423 .parent = &per_clk[0],
424 .secondary = &uart_ipg_clk[3],
425 },
426};
427
428static struct clk uart_ipg_clk[] = {
429 {
430 .id = 0,
431 .parent = &ipg_clk,
432 .enable = _clk_enable,
433 .enable_reg = CCM_PCCR_UART1_REG,
434 .enable_shift = CCM_PCCR_UART1_OFFSET,
435 .disable = _clk_disable,
436 }, {
437 .id = 1,
438 .parent = &ipg_clk,
439 .enable = _clk_enable,
440 .enable_reg = CCM_PCCR_UART2_REG,
441 .enable_shift = CCM_PCCR_UART2_OFFSET,
442 .disable = _clk_disable,
443 }, {
444 .id = 2,
445 .parent = &ipg_clk,
446 .enable = _clk_enable,
447 .enable_reg = CCM_PCCR_UART3_REG,
448 .enable_shift = CCM_PCCR_UART3_OFFSET,
449 .disable = _clk_disable,
450 }, {
451 .id = 3,
452 .parent = &ipg_clk,
453 .enable = _clk_enable,
454 .enable_reg = CCM_PCCR_UART4_REG,
455 .enable_shift = CCM_PCCR_UART4_OFFSET,
456 .disable = _clk_disable,
457 },
458};
459
460static struct clk gpt_ipg_clk[];
461
462static struct clk gpt_clk[] = {
463 {
464 .id = 0,
465 .parent = &per_clk[0],
466 .secondary = &gpt_ipg_clk[0],
467 }, {
468 .id = 1,
469 .parent = &per_clk[0],
470 .secondary = &gpt_ipg_clk[1],
471 }, {
472 .id = 2,
473 .parent = &per_clk[0],
474 .secondary = &gpt_ipg_clk[2],
475 },
476};
477
478static struct clk gpt_ipg_clk[] = {
479 {
480 .id = 0,
481 .parent = &ipg_clk,
482 .enable = _clk_enable,
483 .enable_reg = CCM_PCCR_GPT1_REG,
484 .enable_shift = CCM_PCCR_GPT1_OFFSET,
485 .disable = _clk_disable,
486 }, {
487 .id = 1,
488 .parent = &ipg_clk,
489 .enable = _clk_enable,
490 .enable_reg = CCM_PCCR_GPT2_REG,
491 .enable_shift = CCM_PCCR_GPT2_OFFSET,
492 .disable = _clk_disable,
493 }, {
494 .id = 2,
495 .parent = &ipg_clk,
496 .enable = _clk_enable,
497 .enable_reg = CCM_PCCR_GPT3_REG,
498 .enable_shift = CCM_PCCR_GPT3_OFFSET,
499 .disable = _clk_disable,
500 },
501};
502
503static struct clk pwm_clk[] = {
504 {
505 .parent = &per_clk[0],
506 .secondary = &pwm_clk[1],
507 }, {
508 .parent = &ipg_clk,
509 .enable = _clk_enable,
510 .enable_reg = CCM_PCCR_PWM_REG,
511 .enable_shift = CCM_PCCR_PWM_OFFSET,
512 .disable = _clk_disable,
513 },
514};
515
516static struct clk sdhc_ipg_clk[];
517
518static struct clk sdhc_clk[] = {
519 {
520 .id = 0,
521 .parent = &per_clk[1],
522 .secondary = &sdhc_ipg_clk[0],
523 }, {
524 .id = 1,
525 .parent = &per_clk[1],
526 .secondary = &sdhc_ipg_clk[1],
527 },
528};
529
530static struct clk sdhc_ipg_clk[] = {
531 {
532 .id = 0,
533 .parent = &ipg_clk,
534 .enable = _clk_enable,
535 .enable_reg = CCM_PCCR_SDHC1_REG,
536 .enable_shift = CCM_PCCR_SDHC1_OFFSET,
537 .disable = _clk_disable,
538 }, {
539 .id = 1,
540 .parent = &ipg_clk,
541 .enable = _clk_enable,
542 .enable_reg = CCM_PCCR_SDHC2_REG,
543 .enable_shift = CCM_PCCR_SDHC2_OFFSET,
544 .disable = _clk_disable,
545 },
546};
547
548static struct clk cspi_ipg_clk[];
549
550static struct clk cspi_clk[] = {
551 {
552 .id = 0,
553 .parent = &per_clk[1],
554 .secondary = &cspi_ipg_clk[0],
555 }, {
556 .id = 1,
557 .parent = &per_clk[1],
558 .secondary = &cspi_ipg_clk[1],
559 }, {
560 .id = 2,
561 .parent = &per_clk[1],
562 .secondary = &cspi_ipg_clk[2],
563 },
564};
565
566static struct clk cspi_ipg_clk[] = {
567 {
568 .id = 0,
569 .parent = &ipg_clk,
570 .enable = _clk_enable,
571 .enable_reg = CCM_PCCR_CSPI1_REG,
572 .enable_shift = CCM_PCCR_CSPI1_OFFSET,
573 .disable = _clk_disable,
574 }, {
575 .id = 1,
576 .parent = &ipg_clk,
577 .enable = _clk_enable,
578 .enable_reg = CCM_PCCR_CSPI2_REG,
579 .enable_shift = CCM_PCCR_CSPI2_OFFSET,
580 .disable = _clk_disable,
581 }, {
582 .id = 3,
583 .parent = &ipg_clk,
584 .enable = _clk_enable,
585 .enable_reg = CCM_PCCR_CSPI3_REG,
586 .enable_shift = CCM_PCCR_CSPI3_OFFSET,
587 .disable = _clk_disable,
588 },
589};
590
591static struct clk lcdc_clk[] = {
592 {
593 .parent = &per_clk[2],
594 .secondary = &lcdc_clk[1],
595 .round_rate = _clk_parent_round_rate,
596 .set_rate = _clk_parent_set_rate,
597 }, {
598 .parent = &ipg_clk,
599 .secondary = &lcdc_clk[2],
600 .enable = _clk_enable,
601 .enable_reg = CCM_PCCR_LCDC_REG,
602 .enable_shift = CCM_PCCR_LCDC_OFFSET,
603 .disable = _clk_disable,
604 }, {
605 .parent = &hclk_clk,
606 .enable = _clk_enable,
607 .enable_reg = CCM_PCCR_HCLK_LCDC_REG,
608 .enable_shift = CCM_PCCR_HCLK_LCDC_OFFSET,
609 .disable = _clk_disable,
610 },
611};
612
613static struct clk csi_clk[] = {
614 {
615 .parent = &per_clk[3],
616 .secondary = &csi_clk[1],
617 .round_rate = _clk_parent_round_rate,
618 .set_rate = _clk_parent_set_rate,
619 }, {
620 .parent = &hclk_clk,
621 .enable = _clk_enable,
622 .enable_reg = CCM_PCCR_HCLK_CSI_REG,
623 .enable_shift = CCM_PCCR_HCLK_CSI_OFFSET,
624 .disable = _clk_disable,
625 },
626};
627
628static struct clk usb_clk[] = {
629 {
630 .parent = &spll_clk,
Martin Fuzzeya0895162009-06-06 16:36:44 +0200631 .secondary = &usb_clk[1],
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100632 .get_rate = _clk_usb_recalc,
633 .enable = _clk_enable,
634 .enable_reg = CCM_PCCR_USBOTG_REG,
635 .enable_shift = CCM_PCCR_USBOTG_OFFSET,
636 .disable = _clk_disable,
Martin Fuzzeya0895162009-06-06 16:36:44 +0200637 .round_rate = _clk_usb_round_rate,
638 .set_rate = _clk_usb_set_rate,
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100639 }, {
640 .parent = &hclk_clk,
641 .enable = _clk_enable,
642 .enable_reg = CCM_PCCR_HCLK_USBOTG_REG,
643 .enable_shift = CCM_PCCR_HCLK_USBOTG_OFFSET,
644 .disable = _clk_disable,
645 }
646};
647
648static struct clk ssi_ipg_clk[];
649
650static struct clk ssi_clk[] = {
651 {
652 .id = 0,
653 .parent = &mpll_clk,
654 .secondary = &ssi_ipg_clk[0],
655 .get_rate = _clk_ssi1_recalc,
656 .enable = _clk_enable,
657 .enable_reg = CCM_PCCR_SSI1_BAUD_REG,
658 .enable_shift = CCM_PCCR_SSI1_BAUD_OFFSET,
659 .disable = _clk_disable,
660 }, {
661 .id = 1,
662 .parent = &mpll_clk,
663 .secondary = &ssi_ipg_clk[1],
664 .get_rate = _clk_ssi2_recalc,
665 .enable = _clk_enable,
666 .enable_reg = CCM_PCCR_SSI2_BAUD_REG,
667 .enable_shift = CCM_PCCR_SSI2_BAUD_OFFSET,
668 .disable = _clk_disable,
669 },
670};
671
672static struct clk ssi_ipg_clk[] = {
673 {
674 .id = 0,
675 .parent = &ipg_clk,
676 .enable = _clk_enable,
677 .enable_reg = CCM_PCCR_SSI1_REG,
678 .enable_shift = CCM_PCCR_SSI1_IPG_OFFSET,
679 .disable = _clk_disable,
680 }, {
681 .id = 1,
682 .parent = &ipg_clk,
683 .enable = _clk_enable,
684 .enable_reg = CCM_PCCR_SSI2_REG,
685 .enable_shift = CCM_PCCR_SSI2_IPG_OFFSET,
686 .disable = _clk_disable,
687 },
688};
689
690
691static struct clk nfc_clk = {
692 .parent = &fclk_clk,
693 .get_rate = _clk_nfc_recalc,
694 .enable = _clk_enable,
695 .enable_reg = CCM_PCCR_NFC_REG,
696 .enable_shift = CCM_PCCR_NFC_OFFSET,
697 .disable = _clk_disable,
698};
699
700static struct clk dma_clk[] = {
701 {
702 .parent = &hclk_clk,
703 .enable = _clk_enable,
704 .enable_reg = CCM_PCCR_DMA_REG,
705 .enable_shift = CCM_PCCR_DMA_OFFSET,
706 .disable = _clk_disable,
707 .secondary = &dma_clk[1],
708 }, {
709 .enable = _clk_enable,
710 .enable_reg = CCM_PCCR_HCLK_DMA_REG,
711 .enable_shift = CCM_PCCR_HCLK_DMA_OFFSET,
712 .disable = _clk_disable,
713 },
714};
715
716static struct clk brom_clk = {
717 .parent = &hclk_clk,
718 .enable = _clk_enable,
719 .enable_reg = CCM_PCCR_HCLK_BROM_REG,
720 .enable_shift = CCM_PCCR_HCLK_BROM_OFFSET,
721 .disable = _clk_disable,
722};
723
724static struct clk emma_clk[] = {
725 {
726 .parent = &hclk_clk,
727 .enable = _clk_enable,
728 .enable_reg = CCM_PCCR_EMMA_REG,
729 .enable_shift = CCM_PCCR_EMMA_OFFSET,
730 .disable = _clk_disable,
731 .secondary = &emma_clk[1],
732 }, {
733 .enable = _clk_enable,
734 .enable_reg = CCM_PCCR_HCLK_EMMA_REG,
735 .enable_shift = CCM_PCCR_HCLK_EMMA_OFFSET,
736 .disable = _clk_disable,
737 }
738};
739
740static struct clk slcdc_clk[] = {
741 {
742 .parent = &hclk_clk,
743 .enable = _clk_enable,
744 .enable_reg = CCM_PCCR_SLCDC_REG,
745 .enable_shift = CCM_PCCR_SLCDC_OFFSET,
746 .disable = _clk_disable,
747 .secondary = &slcdc_clk[1],
748 }, {
749 .enable = _clk_enable,
750 .enable_reg = CCM_PCCR_HCLK_SLCDC_REG,
751 .enable_shift = CCM_PCCR_HCLK_SLCDC_OFFSET,
752 .disable = _clk_disable,
753 }
754};
755
756static struct clk wdog_clk = {
757 .parent = &ipg_clk,
758 .enable = _clk_enable,
759 .enable_reg = CCM_PCCR_WDT_REG,
760 .enable_shift = CCM_PCCR_WDT_OFFSET,
761 .disable = _clk_disable,
762};
763
764static struct clk gpio_clk = {
765 .parent = &ipg_clk,
766 .enable = _clk_enable,
767 .enable_reg = CCM_PCCR_GPIO_REG,
768 .enable_shift = CCM_PCCR_GPIO_OFFSET,
769 .disable = _clk_disable,
770};
771
772static struct clk i2c_clk = {
773 .id = 0,
774 .parent = &ipg_clk,
775 .enable = _clk_enable,
776 .enable_reg = CCM_PCCR_I2C1_REG,
777 .enable_shift = CCM_PCCR_I2C1_OFFSET,
778 .disable = _clk_disable,
779};
780
781static struct clk kpp_clk = {
782 .parent = &ipg_clk,
783 .enable = _clk_enable,
784 .enable_reg = CCM_PCCR_KPP_REG,
785 .enable_shift = CCM_PCCR_KPP_OFFSET,
786 .disable = _clk_disable,
787};
788
789static struct clk owire_clk = {
790 .parent = &ipg_clk,
791 .enable = _clk_enable,
792 .enable_reg = CCM_PCCR_OWIRE_REG,
793 .enable_shift = CCM_PCCR_OWIRE_OFFSET,
794 .disable = _clk_disable,
795};
796
797static struct clk rtc_clk = {
798 .parent = &ipg_clk,
799 .enable = _clk_enable,
800 .enable_reg = CCM_PCCR_RTC_REG,
801 .enable_shift = CCM_PCCR_RTC_OFFSET,
802 .disable = _clk_disable,
803};
804
805static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate)
806{
Martin Fuzzeya0895162009-06-06 16:36:44 +0200807 return _clk_generic_round_rate(clk, rate, 8);
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100808}
809
810static int _clk_clko_set_rate(struct clk *clk, unsigned long rate)
811{
812 u32 reg;
813 u32 div;
814 unsigned long parent_rate;
815
816 parent_rate = clk_get_rate(clk->parent);
817
818 div = parent_rate / rate;
819
820 if (div > 8 || div < 1 || ((parent_rate / div) != rate))
821 return -EINVAL;
822 div--;
823
824 reg = __raw_readl(CCM_PCDR0);
825
826 if (clk->parent == &usb_clk[0]) {
827 reg &= ~CCM_PCDR0_48MDIV_MASK;
828 reg |= div << CCM_PCDR0_48MDIV_OFFSET;
829 }
830 __raw_writel(reg, CCM_PCDR0);
831
832 return 0;
833}
834
835static unsigned long _clk_clko_recalc(struct clk *clk)
836{
837 u32 div = 0;
838 unsigned long parent_rate;
839
840 parent_rate = clk_get_rate(clk->parent);
841
842 if (clk->parent == &usb_clk[0]) /* 48M */
843 div = __raw_readl(CCM_PCDR0) & CCM_PCDR0_48MDIV_MASK
844 >> CCM_PCDR0_48MDIV_OFFSET;
845 div++;
846
847 return parent_rate / div;
848}
849
850static struct clk clko_clk;
851
852static int _clk_clko_set_parent(struct clk *clk, struct clk *parent)
853{
854 u32 reg;
855
856 reg = __raw_readl(CCM_CCSR) & ~CCM_CCSR_CLKOSEL_MASK;
857
858 if (parent == &ckil_clk)
859 reg |= 0 << CCM_CCSR_CLKOSEL_OFFSET;
860 else if (parent == &fpm_clk)
861 reg |= 1 << CCM_CCSR_CLKOSEL_OFFSET;
862 else if (parent == &ckih_clk)
863 reg |= 2 << CCM_CCSR_CLKOSEL_OFFSET;
864 else if (parent == mpll_clk.parent)
865 reg |= 3 << CCM_CCSR_CLKOSEL_OFFSET;
866 else if (parent == spll_clk.parent)
867 reg |= 4 << CCM_CCSR_CLKOSEL_OFFSET;
868 else if (parent == &mpll_clk)
869 reg |= 5 << CCM_CCSR_CLKOSEL_OFFSET;
870 else if (parent == &spll_clk)
871 reg |= 6 << CCM_CCSR_CLKOSEL_OFFSET;
872 else if (parent == &fclk_clk)
873 reg |= 7 << CCM_CCSR_CLKOSEL_OFFSET;
874 else if (parent == &hclk_clk)
875 reg |= 8 << CCM_CCSR_CLKOSEL_OFFSET;
876 else if (parent == &ipg_clk)
877 reg |= 9 << CCM_CCSR_CLKOSEL_OFFSET;
878 else if (parent == &per_clk[0])
879 reg |= 0xA << CCM_CCSR_CLKOSEL_OFFSET;
880 else if (parent == &per_clk[1])
881 reg |= 0xB << CCM_CCSR_CLKOSEL_OFFSET;
882 else if (parent == &per_clk[2])
883 reg |= 0xC << CCM_CCSR_CLKOSEL_OFFSET;
884 else if (parent == &per_clk[3])
885 reg |= 0xD << CCM_CCSR_CLKOSEL_OFFSET;
886 else if (parent == &ssi_clk[0])
887 reg |= 0xE << CCM_CCSR_CLKOSEL_OFFSET;
888 else if (parent == &ssi_clk[1])
889 reg |= 0xF << CCM_CCSR_CLKOSEL_OFFSET;
890 else if (parent == &nfc_clk)
891 reg |= 0x10 << CCM_CCSR_CLKOSEL_OFFSET;
892 else if (parent == &usb_clk[0])
893 reg |= 0x14 << CCM_CCSR_CLKOSEL_OFFSET;
894 else if (parent == &clko_clk)
895 reg |= 0x15 << CCM_CCSR_CLKOSEL_OFFSET;
896 else
897 return -EINVAL;
898
899 __raw_writel(reg, CCM_CCSR);
900
901 return 0;
902}
903
904static struct clk clko_clk = {
905 .get_rate = _clk_clko_recalc,
906 .set_rate = _clk_clko_set_rate,
907 .round_rate = _clk_clko_round_rate,
908 .set_parent = _clk_clko_set_parent,
909};
910
911
912#define _REGISTER_CLOCK(d, n, c) \
913 { \
914 .dev_id = d, \
915 .con_id = n, \
916 .clk = &c, \
917 },
Rabin Vincent6b4bfb82009-05-26 22:31:46 +0530918static struct clk_lookup lookups[] = {
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100919/* It's unlikely that any driver wants one of them directly:
920 _REGISTER_CLOCK(NULL, "ckih", ckih_clk)
921 _REGISTER_CLOCK(NULL, "ckil", ckil_clk)
922 _REGISTER_CLOCK(NULL, "fpm", fpm_clk)
923 _REGISTER_CLOCK(NULL, "mpll", mpll_clk)
924 _REGISTER_CLOCK(NULL, "spll", spll_clk)
925 _REGISTER_CLOCK(NULL, "fclk", fclk_clk)
926 _REGISTER_CLOCK(NULL, "hclk", hclk_clk)
927 _REGISTER_CLOCK(NULL, "ipg", ipg_clk)
928*/
929 _REGISTER_CLOCK(NULL, "perclk1", per_clk[0])
930 _REGISTER_CLOCK(NULL, "perclk2", per_clk[1])
931 _REGISTER_CLOCK(NULL, "perclk3", per_clk[2])
932 _REGISTER_CLOCK(NULL, "perclk4", per_clk[3])
933 _REGISTER_CLOCK(NULL, "clko", clko_clk)
934 _REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0])
935 _REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[1])
936 _REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[2])
937 _REGISTER_CLOCK("imx-uart.3", NULL, uart_clk[3])
938 _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[0])
939 _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[1])
940 _REGISTER_CLOCK(NULL, "gpt1", gpt_clk[2])
941 _REGISTER_CLOCK(NULL, "pwm", pwm_clk[0])
942 _REGISTER_CLOCK(NULL, "sdhc1", sdhc_clk[0])
943 _REGISTER_CLOCK(NULL, "sdhc2", sdhc_clk[1])
944 _REGISTER_CLOCK(NULL, "cspi1", cspi_clk[0])
945 _REGISTER_CLOCK(NULL, "cspi2", cspi_clk[1])
946 _REGISTER_CLOCK(NULL, "cspi3", cspi_clk[2])
Holger Schurig289a6892009-03-31 12:16:59 +0200947 _REGISTER_CLOCK("imx-fb.0", NULL, lcdc_clk[0])
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100948 _REGISTER_CLOCK(NULL, "csi", csi_clk[0])
Martin Fuzzeya0895162009-06-06 16:36:44 +0200949 _REGISTER_CLOCK("imx21-hcd.0", NULL, usb_clk[0])
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100950 _REGISTER_CLOCK(NULL, "ssi1", ssi_clk[0])
951 _REGISTER_CLOCK(NULL, "ssi2", ssi_clk[1])
Holger Schurig289a6892009-03-31 12:16:59 +0200952 _REGISTER_CLOCK("mxc_nand.0", NULL, nfc_clk)
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100953 _REGISTER_CLOCK(NULL, "dma", dma_clk[0])
954 _REGISTER_CLOCK(NULL, "brom", brom_clk)
955 _REGISTER_CLOCK(NULL, "emma", emma_clk[0])
956 _REGISTER_CLOCK(NULL, "slcdc", slcdc_clk[0])
Holger Schurig289a6892009-03-31 12:16:59 +0200957 _REGISTER_CLOCK("imx-wdt.0", NULL, wdog_clk)
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100958 _REGISTER_CLOCK(NULL, "gpio", gpio_clk)
Holger Schurig1b3c9bf2009-04-01 13:58:21 +0200959 _REGISTER_CLOCK("imx-i2c.0", NULL, i2c_clk)
Holger Schurigaa3b0a62009-01-26 16:34:54 +0100960 _REGISTER_CLOCK("mxc-keypad", NULL, kpp_clk)
961 _REGISTER_CLOCK(NULL, "owire", owire_clk)
962 _REGISTER_CLOCK(NULL, "rtc", rtc_clk)
963};
964
965/*
966 * must be called very early to get information about the
967 * available clock rate when the timer framework starts
968 */
969int __init mx21_clocks_init(unsigned long lref, unsigned long href)
970{
971 int i;
972 u32 cscr;
973
974 external_low_reference = lref;
975 external_high_reference = href;
976
977 /* detect clock reference for both system PLL */
978 cscr = CSCR();
979 if (cscr & CCM_CSCR_MCU)
980 mpll_clk.parent = &ckih_clk;
981 else
982 mpll_clk.parent = &fpm_clk;
983
984 if (cscr & CCM_CSCR_SP)
985 spll_clk.parent = &ckih_clk;
986 else
987 spll_clk.parent = &fpm_clk;
988
989 for (i = 0; i < ARRAY_SIZE(lookups); i++)
990 clkdev_add(&lookups[i]);
991
992 /* Turn off all clock gates */
993 __raw_writel(0, CCM_PCCR0);
994 __raw_writel(CCM_PCCR_GPT1_MASK, CCM_PCCR1);
995
996 /* This turns of the serial PLL as well */
997 spll_clk.disable(&spll_clk);
998
999 /* This will propagate to all children and init all the clock rates. */
1000 clk_enable(&per_clk[0]);
1001 clk_enable(&gpio_clk);
1002
1003#ifdef CONFIG_DEBUG_LL_CONSOLE
1004 clk_enable(&uart_clk[0]);
1005#endif
1006
Sascha Hauer8db5d1a2009-05-25 12:21:38 +02001007 mxc_timer_init(&gpt_clk[0], IO_ADDRESS(GPT1_BASE_ADDR), MXC_INT_GPT1);
Holger Schurigaa3b0a62009-01-26 16:34:54 +01001008 return 0;
1009}