blob: 8486ea46d6c19808a0e2b6c4cbab8512f5504f3e [file] [log] [blame]
Sascha Hauerdf1bf4b2008-07-05 10:02:48 +02001/*
2 * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
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., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301, USA.
18 */
19
20#include <linux/module.h>
21#include <linux/spinlock.h>
22#include <linux/delay.h>
23#include <linux/clk.h>
24#include <linux/err.h>
25#include <linux/io.h>
Russell Kinga09e64f2008-08-05 16:14:15 +010026#include <mach/clock.h>
Sascha Hauera2449092008-12-18 11:51:57 +010027#include <mach/hardware.h>
Sascha Hauerdf1bf4b2008-07-05 10:02:48 +020028#include <asm/div64.h>
29
30#include "crm_regs.h"
31
32#define PRE_DIV_MIN_FREQ 10000000 /* Minimum Frequency after Predivider */
33
34static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post)
35{
36 u32 min_pre, temp_pre, old_err, err;
37
38 if (div >= 512) {
39 *pre = 8;
40 *post = 64;
41 } else if (div >= 64) {
42 min_pre = (div - 1) / 64 + 1;
43 old_err = 8;
44 for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) {
45 err = div % temp_pre;
46 if (err == 0) {
47 *pre = temp_pre;
48 break;
49 }
50 err = temp_pre - err;
51 if (err < old_err) {
52 old_err = err;
53 *pre = temp_pre;
54 }
55 }
56 *post = (div + *pre - 1) / *pre;
57 } else if (div <= 8) {
58 *pre = div;
59 *post = 1;
60 } else {
61 *pre = 1;
62 *post = div;
63 }
64}
65
66static struct clk mcu_pll_clk;
67static struct clk mcu_main_clk;
68static struct clk usb_pll_clk;
69static struct clk serial_pll_clk;
70static struct clk ipg_clk;
71static struct clk ckih_clk;
72static struct clk ahb_clk;
73
74static int _clk_enable(struct clk *clk)
75{
76 u32 reg;
77
78 reg = __raw_readl(clk->enable_reg);
79 reg |= 3 << clk->enable_shift;
80 __raw_writel(reg, clk->enable_reg);
81
82 return 0;
83}
84
85static void _clk_disable(struct clk *clk)
86{
87 u32 reg;
88
89 reg = __raw_readl(clk->enable_reg);
90 reg &= ~(3 << clk->enable_shift);
91 __raw_writel(reg, clk->enable_reg);
92}
93
94static void _clk_emi_disable(struct clk *clk)
95{
96 u32 reg;
97
98 reg = __raw_readl(clk->enable_reg);
99 reg &= ~(3 << clk->enable_shift);
100 reg |= (1 << clk->enable_shift);
101 __raw_writel(reg, clk->enable_reg);
102}
103
104static int _clk_pll_set_rate(struct clk *clk, unsigned long rate)
105{
106 u32 reg;
107 signed long pd = 1; /* Pre-divider */
108 signed long mfi; /* Multiplication Factor (Integer part) */
109 signed long mfn; /* Multiplication Factor (Integer part) */
110 signed long mfd; /* Multiplication Factor (Denominator Part) */
111 signed long tmp;
112 u32 ref_freq = clk_get_rate(clk->parent);
113
114 while (((ref_freq / pd) * 10) > rate)
115 pd++;
116
117 if ((ref_freq / pd) < PRE_DIV_MIN_FREQ)
118 return -EINVAL;
119
120 /* the ref_freq/2 in the following is to round up */
121 mfi = (((rate / 2) * pd) + (ref_freq / 2)) / ref_freq;
122 if (mfi < 5 || mfi > 15)
123 return -EINVAL;
124
125 /* pick a mfd value that will work
126 * then solve for mfn */
127 mfd = ref_freq / 50000;
128
129 /*
130 * pll_freq * pd * mfd
131 * mfn = -------------------- - (mfi * mfd)
132 * 2 * ref_freq
133 */
134 /* the tmp/2 is for rounding */
135 tmp = ref_freq / 10000;
136 mfn =
137 ((((((rate / 2) + (tmp / 2)) / tmp) * pd) * mfd) / 10000) -
138 (mfi * mfd);
139
140 mfn = mfn & 0x3ff;
141 pd--;
142 mfd--;
143
144 /* Change the Pll value */
145 reg = (mfi << MXC_CCM_PCTL_MFI_OFFSET) |
146 (mfn << MXC_CCM_PCTL_MFN_OFFSET) |
147 (mfd << MXC_CCM_PCTL_MFD_OFFSET) | (pd << MXC_CCM_PCTL_PD_OFFSET);
148
149 if (clk == &mcu_pll_clk)
150 __raw_writel(reg, MXC_CCM_MPCTL);
151 else if (clk == &usb_pll_clk)
152 __raw_writel(reg, MXC_CCM_UPCTL);
153 else if (clk == &serial_pll_clk)
154 __raw_writel(reg, MXC_CCM_SRPCTL);
155
156 return 0;
157}
158
159static unsigned long _clk_pll_get_rate(struct clk *clk)
160{
Sascha Hauerdf1bf4b2008-07-05 10:02:48 +0200161 unsigned long reg, ccmr;
Sascha Hauera2865192009-01-26 15:41:16 +0100162 unsigned int prcs, ref_clk;
Sascha Hauerdf1bf4b2008-07-05 10:02:48 +0200163
164 ccmr = __raw_readl(MXC_CCM_CCMR);
165 prcs = (ccmr & MXC_CCM_CCMR_PRCS_MASK) >> MXC_CCM_CCMR_PRCS_OFFSET;
166 if (prcs == 0x1)
167 ref_clk = CKIL_CLK_FREQ * 1024;
168 else
169 ref_clk = clk_get_rate(&ckih_clk);
170
171 if (clk == &mcu_pll_clk) {
172 if ((ccmr & MXC_CCM_CCMR_MPE) == 0)
173 return ref_clk;
174 if ((ccmr & MXC_CCM_CCMR_MDS) != 0)
175 return ref_clk;
176 reg = __raw_readl(MXC_CCM_MPCTL);
177 } else if (clk == &usb_pll_clk)
178 reg = __raw_readl(MXC_CCM_UPCTL);
179 else if (clk == &serial_pll_clk)
180 reg = __raw_readl(MXC_CCM_SRPCTL);
181 else {
182 BUG();
183 return 0;
184 }
185
Sascha Hauera2865192009-01-26 15:41:16 +0100186 return mxc_decode_pll(reg, ref_clk);
Sascha Hauerdf1bf4b2008-07-05 10:02:48 +0200187}
188
189static int _clk_usb_pll_enable(struct clk *clk)
190{
191 u32 reg;
192
193 reg = __raw_readl(MXC_CCM_CCMR);
194 reg |= MXC_CCM_CCMR_UPE;
195 __raw_writel(reg, MXC_CCM_CCMR);
196
197 /* No lock bit on MX31, so using max time from spec */
198 udelay(80);
199
200 return 0;
201}
202
203static void _clk_usb_pll_disable(struct clk *clk)
204{
205 u32 reg;
206
207 reg = __raw_readl(MXC_CCM_CCMR);
208 reg &= ~MXC_CCM_CCMR_UPE;
209 __raw_writel(reg, MXC_CCM_CCMR);
210}
211
212static int _clk_serial_pll_enable(struct clk *clk)
213{
214 u32 reg;
215
216 reg = __raw_readl(MXC_CCM_CCMR);
217 reg |= MXC_CCM_CCMR_SPE;
218 __raw_writel(reg, MXC_CCM_CCMR);
219
220 /* No lock bit on MX31, so using max time from spec */
221 udelay(80);
222
223 return 0;
224}
225
226static void _clk_serial_pll_disable(struct clk *clk)
227{
228 u32 reg;
229
230 reg = __raw_readl(MXC_CCM_CCMR);
231 reg &= ~MXC_CCM_CCMR_SPE;
232 __raw_writel(reg, MXC_CCM_CCMR);
233}
234
235#define PDR0(mask, off) ((__raw_readl(MXC_CCM_PDR0) & mask) >> off)
236#define PDR1(mask, off) ((__raw_readl(MXC_CCM_PDR1) & mask) >> off)
237#define PDR2(mask, off) ((__raw_readl(MXC_CCM_PDR2) & mask) >> off)
238
239static unsigned long _clk_mcu_main_get_rate(struct clk *clk)
240{
241 u32 pmcr0 = __raw_readl(MXC_CCM_PMCR0);
242
243 if ((pmcr0 & MXC_CCM_PMCR0_DFSUP1) == MXC_CCM_PMCR0_DFSUP1_SPLL)
244 return clk_get_rate(&serial_pll_clk);
245 else
246 return clk_get_rate(&mcu_pll_clk);
247}
248
249static unsigned long _clk_hclk_get_rate(struct clk *clk)
250{
251 unsigned long max_pdf;
252
253 max_pdf = PDR0(MXC_CCM_PDR0_MAX_PODF_MASK,
254 MXC_CCM_PDR0_MAX_PODF_OFFSET);
255 return clk_get_rate(clk->parent) / (max_pdf + 1);
256}
257
258static unsigned long _clk_ipg_get_rate(struct clk *clk)
259{
260 unsigned long ipg_pdf;
261
262 ipg_pdf = PDR0(MXC_CCM_PDR0_IPG_PODF_MASK,
263 MXC_CCM_PDR0_IPG_PODF_OFFSET);
264 return clk_get_rate(clk->parent) / (ipg_pdf + 1);
265}
266
267static unsigned long _clk_nfc_get_rate(struct clk *clk)
268{
269 unsigned long nfc_pdf;
270
271 nfc_pdf = PDR0(MXC_CCM_PDR0_NFC_PODF_MASK,
272 MXC_CCM_PDR0_NFC_PODF_OFFSET);
273 return clk_get_rate(clk->parent) / (nfc_pdf + 1);
274}
275
276static unsigned long _clk_hsp_get_rate(struct clk *clk)
277{
278 unsigned long hsp_pdf;
279
280 hsp_pdf = PDR0(MXC_CCM_PDR0_HSP_PODF_MASK,
281 MXC_CCM_PDR0_HSP_PODF_OFFSET);
282 return clk_get_rate(clk->parent) / (hsp_pdf + 1);
283}
284
285static unsigned long _clk_usb_get_rate(struct clk *clk)
286{
287 unsigned long usb_pdf, usb_prepdf;
288
289 usb_pdf = PDR1(MXC_CCM_PDR1_USB_PODF_MASK,
290 MXC_CCM_PDR1_USB_PODF_OFFSET);
291 usb_prepdf = PDR1(MXC_CCM_PDR1_USB_PRDF_MASK,
292 MXC_CCM_PDR1_USB_PRDF_OFFSET);
293 return clk_get_rate(clk->parent) / (usb_prepdf + 1) / (usb_pdf + 1);
294}
295
296static unsigned long _clk_csi_get_rate(struct clk *clk)
297{
298 u32 reg, pre, post;
299
300 reg = __raw_readl(MXC_CCM_PDR0);
301 pre = (reg & MXC_CCM_PDR0_CSI_PRDF_MASK) >>
302 MXC_CCM_PDR0_CSI_PRDF_OFFSET;
303 pre++;
304 post = (reg & MXC_CCM_PDR0_CSI_PODF_MASK) >>
305 MXC_CCM_PDR0_CSI_PODF_OFFSET;
306 post++;
307 return clk_get_rate(clk->parent) / (pre * post);
308}
309
310static unsigned long _clk_csi_round_rate(struct clk *clk, unsigned long rate)
311{
312 u32 pre, post, parent = clk_get_rate(clk->parent);
313 u32 div = parent / rate;
314
315 if (parent % rate)
316 div++;
317
318 __calc_pre_post_dividers(div, &pre, &post);
319
320 return parent / (pre * post);
321}
322
323static int _clk_csi_set_rate(struct clk *clk, unsigned long rate)
324{
325 u32 reg, div, pre, post, parent = clk_get_rate(clk->parent);
326
327 div = parent / rate;
328
329 if ((parent / div) != rate)
330 return -EINVAL;
331
332 __calc_pre_post_dividers(div, &pre, &post);
333
334 /* Set CSI clock divider */
335 reg = __raw_readl(MXC_CCM_PDR0) &
336 ~(MXC_CCM_PDR0_CSI_PODF_MASK | MXC_CCM_PDR0_CSI_PRDF_MASK);
337 reg |= (post - 1) << MXC_CCM_PDR0_CSI_PODF_OFFSET;
338 reg |= (pre - 1) << MXC_CCM_PDR0_CSI_PRDF_OFFSET;
339 __raw_writel(reg, MXC_CCM_PDR0);
340
341 return 0;
342}
343
344static unsigned long _clk_per_get_rate(struct clk *clk)
345{
346 unsigned long per_pdf;
347
348 per_pdf = PDR0(MXC_CCM_PDR0_PER_PODF_MASK,
349 MXC_CCM_PDR0_PER_PODF_OFFSET);
350 return clk_get_rate(clk->parent) / (per_pdf + 1);
351}
352
353static unsigned long _clk_ssi1_get_rate(struct clk *clk)
354{
355 unsigned long ssi1_pdf, ssi1_prepdf;
356
357 ssi1_pdf = PDR1(MXC_CCM_PDR1_SSI1_PODF_MASK,
358 MXC_CCM_PDR1_SSI1_PODF_OFFSET);
359 ssi1_prepdf = PDR1(MXC_CCM_PDR1_SSI1_PRE_PODF_MASK,
360 MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET);
361 return clk_get_rate(clk->parent) / (ssi1_prepdf + 1) / (ssi1_pdf + 1);
362}
363
364static unsigned long _clk_ssi2_get_rate(struct clk *clk)
365{
366 unsigned long ssi2_pdf, ssi2_prepdf;
367
368 ssi2_pdf = PDR1(MXC_CCM_PDR1_SSI2_PODF_MASK,
369 MXC_CCM_PDR1_SSI2_PODF_OFFSET);
370 ssi2_prepdf = PDR1(MXC_CCM_PDR1_SSI2_PRE_PODF_MASK,
371 MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET);
372 return clk_get_rate(clk->parent) / (ssi2_prepdf + 1) / (ssi2_pdf + 1);
373}
374
375static unsigned long _clk_firi_get_rate(struct clk *clk)
376{
377 unsigned long firi_pdf, firi_prepdf;
378
379 firi_pdf = PDR1(MXC_CCM_PDR1_FIRI_PODF_MASK,
380 MXC_CCM_PDR1_FIRI_PODF_OFFSET);
381 firi_prepdf = PDR1(MXC_CCM_PDR1_FIRI_PRE_PODF_MASK,
382 MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET);
383 return clk_get_rate(clk->parent) / (firi_prepdf + 1) / (firi_pdf + 1);
384}
385
386static unsigned long _clk_firi_round_rate(struct clk *clk, unsigned long rate)
387{
388 u32 pre, post;
389 u32 parent = clk_get_rate(clk->parent);
390 u32 div = parent / rate;
391
392 if (parent % rate)
393 div++;
394
395 __calc_pre_post_dividers(div, &pre, &post);
396
397 return parent / (pre * post);
398
399}
400
401static int _clk_firi_set_rate(struct clk *clk, unsigned long rate)
402{
403 u32 reg, div, pre, post, parent = clk_get_rate(clk->parent);
404
405 div = parent / rate;
406
407 if ((parent / div) != rate)
408 return -EINVAL;
409
410 __calc_pre_post_dividers(div, &pre, &post);
411
412 /* Set FIRI clock divider */
413 reg = __raw_readl(MXC_CCM_PDR1) &
414 ~(MXC_CCM_PDR1_FIRI_PODF_MASK | MXC_CCM_PDR1_FIRI_PRE_PODF_MASK);
415 reg |= (pre - 1) << MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET;
416 reg |= (post - 1) << MXC_CCM_PDR1_FIRI_PODF_OFFSET;
417 __raw_writel(reg, MXC_CCM_PDR1);
418
419 return 0;
420}
421
422static unsigned long _clk_mbx_get_rate(struct clk *clk)
423{
424 return clk_get_rate(clk->parent) / 2;
425}
426
427static unsigned long _clk_mstick1_get_rate(struct clk *clk)
428{
429 unsigned long msti_pdf;
430
431 msti_pdf = PDR2(MXC_CCM_PDR2_MST1_PDF_MASK,
432 MXC_CCM_PDR2_MST1_PDF_OFFSET);
433 return clk_get_rate(clk->parent) / (msti_pdf + 1);
434}
435
436static unsigned long _clk_mstick2_get_rate(struct clk *clk)
437{
438 unsigned long msti_pdf;
439
440 msti_pdf = PDR2(MXC_CCM_PDR2_MST2_PDF_MASK,
441 MXC_CCM_PDR2_MST2_PDF_OFFSET);
442 return clk_get_rate(clk->parent) / (msti_pdf + 1);
443}
444
445static unsigned long ckih_rate;
446
447static unsigned long clk_ckih_get_rate(struct clk *clk)
448{
449 return ckih_rate;
450}
451
452static struct clk ckih_clk = {
453 .name = "ckih",
454 .get_rate = clk_ckih_get_rate,
455};
456
457static unsigned long clk_ckil_get_rate(struct clk *clk)
458{
459 return CKIL_CLK_FREQ;
460}
461
462static struct clk ckil_clk = {
463 .name = "ckil",
464 .get_rate = clk_ckil_get_rate,
465};
466
467static struct clk mcu_pll_clk = {
468 .name = "mcu_pll",
469 .parent = &ckih_clk,
470 .set_rate = _clk_pll_set_rate,
471 .get_rate = _clk_pll_get_rate,
472};
473
474static struct clk mcu_main_clk = {
475 .name = "mcu_main_clk",
476 .parent = &mcu_pll_clk,
477 .get_rate = _clk_mcu_main_get_rate,
478};
479
480static struct clk serial_pll_clk = {
481 .name = "serial_pll",
482 .parent = &ckih_clk,
483 .set_rate = _clk_pll_set_rate,
484 .get_rate = _clk_pll_get_rate,
485 .enable = _clk_serial_pll_enable,
486 .disable = _clk_serial_pll_disable,
487};
488
489static struct clk usb_pll_clk = {
490 .name = "usb_pll",
491 .parent = &ckih_clk,
492 .set_rate = _clk_pll_set_rate,
493 .get_rate = _clk_pll_get_rate,
494 .enable = _clk_usb_pll_enable,
495 .disable = _clk_usb_pll_disable,
496};
497
498static struct clk ahb_clk = {
499 .name = "ahb_clk",
500 .parent = &mcu_main_clk,
501 .get_rate = _clk_hclk_get_rate,
502};
503
504static struct clk per_clk = {
505 .name = "per_clk",
506 .parent = &usb_pll_clk,
507 .get_rate = _clk_per_get_rate,
508};
509
510static struct clk perclk_clk = {
511 .name = "perclk_clk",
512 .parent = &ipg_clk,
513};
514
515static struct clk cspi_clk[] = {
516 {
517 .name = "cspi_clk",
518 .id = 0,
519 .parent = &ipg_clk,
520 .enable = _clk_enable,
521 .enable_reg = MXC_CCM_CGR2,
522 .enable_shift = MXC_CCM_CGR2_CSPI1_OFFSET,
523 .disable = _clk_disable,},
524 {
525 .name = "cspi_clk",
526 .id = 1,
527 .parent = &ipg_clk,
528 .enable = _clk_enable,
529 .enable_reg = MXC_CCM_CGR2,
530 .enable_shift = MXC_CCM_CGR2_CSPI2_OFFSET,
531 .disable = _clk_disable,},
532 {
533 .name = "cspi_clk",
534 .id = 2,
535 .parent = &ipg_clk,
536 .enable = _clk_enable,
537 .enable_reg = MXC_CCM_CGR0,
538 .enable_shift = MXC_CCM_CGR0_CSPI3_OFFSET,
539 .disable = _clk_disable,},
540};
541
542static struct clk ipg_clk = {
543 .name = "ipg_clk",
544 .parent = &ahb_clk,
545 .get_rate = _clk_ipg_get_rate,
546};
547
548static struct clk emi_clk = {
549 .name = "emi_clk",
550 .parent = &ahb_clk,
551 .enable = _clk_enable,
552 .enable_reg = MXC_CCM_CGR2,
553 .enable_shift = MXC_CCM_CGR2_EMI_OFFSET,
554 .disable = _clk_emi_disable,
555};
556
557static struct clk gpt_clk = {
558 .name = "gpt_clk",
559 .parent = &perclk_clk,
560 .enable = _clk_enable,
561 .enable_reg = MXC_CCM_CGR0,
562 .enable_shift = MXC_CCM_CGR0_GPT_OFFSET,
563 .disable = _clk_disable,
564};
565
566static struct clk pwm_clk = {
567 .name = "pwm_clk",
568 .parent = &perclk_clk,
569 .enable = _clk_enable,
570 .enable_reg = MXC_CCM_CGR0,
571 .enable_shift = MXC_CCM_CGR1_PWM_OFFSET,
572 .disable = _clk_disable,
573};
574
575static struct clk epit_clk[] = {
576 {
577 .name = "epit_clk",
578 .id = 0,
579 .parent = &perclk_clk,
580 .enable = _clk_enable,
581 .enable_reg = MXC_CCM_CGR0,
582 .enable_shift = MXC_CCM_CGR0_EPIT1_OFFSET,
583 .disable = _clk_disable,},
584 {
585 .name = "epit_clk",
586 .id = 1,
587 .parent = &perclk_clk,
588 .enable = _clk_enable,
589 .enable_reg = MXC_CCM_CGR0,
590 .enable_shift = MXC_CCM_CGR0_EPIT2_OFFSET,
591 .disable = _clk_disable,},
592};
593
594static struct clk nfc_clk = {
595 .name = "nfc_clk",
596 .parent = &ahb_clk,
597 .get_rate = _clk_nfc_get_rate,
598};
599
600static struct clk scc_clk = {
601 .name = "scc_clk",
602 .parent = &ipg_clk,
603};
604
605static struct clk ipu_clk = {
606 .name = "ipu_clk",
607 .parent = &mcu_main_clk,
608 .get_rate = _clk_hsp_get_rate,
609 .enable = _clk_enable,
610 .enable_reg = MXC_CCM_CGR1,
611 .enable_shift = MXC_CCM_CGR1_IPU_OFFSET,
612 .disable = _clk_disable,
613};
614
615static struct clk kpp_clk = {
616 .name = "kpp_clk",
617 .parent = &ipg_clk,
618 .enable = _clk_enable,
619 .enable_reg = MXC_CCM_CGR1,
620 .enable_shift = MXC_CCM_CGR1_KPP_OFFSET,
621 .disable = _clk_disable,
622};
623
624static struct clk wdog_clk = {
625 .name = "wdog_clk",
626 .parent = &ipg_clk,
627 .enable = _clk_enable,
628 .enable_reg = MXC_CCM_CGR1,
629 .enable_shift = MXC_CCM_CGR1_WDOG_OFFSET,
630 .disable = _clk_disable,
631};
632static struct clk rtc_clk = {
633 .name = "rtc_clk",
634 .parent = &ipg_clk,
635 .enable = _clk_enable,
636 .enable_reg = MXC_CCM_CGR1,
637 .enable_shift = MXC_CCM_CGR1_RTC_OFFSET,
638 .disable = _clk_disable,
639};
640
641static struct clk usb_clk[] = {
642 {
643 .name = "usb_clk",
644 .parent = &usb_pll_clk,
645 .get_rate = _clk_usb_get_rate,},
646 {
647 .name = "usb_ahb_clk",
648 .parent = &ahb_clk,
649 .enable = _clk_enable,
650 .enable_reg = MXC_CCM_CGR1,
651 .enable_shift = MXC_CCM_CGR1_USBOTG_OFFSET,
652 .disable = _clk_disable,},
653};
654
655static struct clk csi_clk = {
656 .name = "csi_clk",
657 .parent = &serial_pll_clk,
658 .get_rate = _clk_csi_get_rate,
659 .round_rate = _clk_csi_round_rate,
660 .set_rate = _clk_csi_set_rate,
661 .enable = _clk_enable,
662 .enable_reg = MXC_CCM_CGR1,
663 .enable_shift = MXC_CCM_CGR1_CSI_OFFSET,
664 .disable = _clk_disable,
665};
666
667static struct clk uart_clk[] = {
668 {
669 .name = "uart_clk",
670 .id = 0,
671 .parent = &perclk_clk,
672 .enable = _clk_enable,
673 .enable_reg = MXC_CCM_CGR0,
674 .enable_shift = MXC_CCM_CGR0_UART1_OFFSET,
675 .disable = _clk_disable,},
676 {
677 .name = "uart_clk",
678 .id = 1,
679 .parent = &perclk_clk,
680 .enable = _clk_enable,
681 .enable_reg = MXC_CCM_CGR0,
682 .enable_shift = MXC_CCM_CGR0_UART2_OFFSET,
683 .disable = _clk_disable,},
684 {
685 .name = "uart_clk",
686 .id = 2,
687 .parent = &perclk_clk,
688 .enable = _clk_enable,
689 .enable_reg = MXC_CCM_CGR1,
690 .enable_shift = MXC_CCM_CGR1_UART3_OFFSET,
691 .disable = _clk_disable,},
692 {
693 .name = "uart_clk",
694 .id = 3,
695 .parent = &perclk_clk,
696 .enable = _clk_enable,
697 .enable_reg = MXC_CCM_CGR1,
698 .enable_shift = MXC_CCM_CGR1_UART4_OFFSET,
699 .disable = _clk_disable,},
700 {
701 .name = "uart_clk",
702 .id = 4,
703 .parent = &perclk_clk,
704 .enable = _clk_enable,
705 .enable_reg = MXC_CCM_CGR1,
706 .enable_shift = MXC_CCM_CGR1_UART5_OFFSET,
707 .disable = _clk_disable,},
708};
709
710static struct clk i2c_clk[] = {
711 {
712 .name = "i2c_clk",
713 .id = 0,
714 .parent = &perclk_clk,
715 .enable = _clk_enable,
716 .enable_reg = MXC_CCM_CGR0,
717 .enable_shift = MXC_CCM_CGR0_I2C1_OFFSET,
718 .disable = _clk_disable,},
719 {
720 .name = "i2c_clk",
721 .id = 1,
722 .parent = &perclk_clk,
723 .enable = _clk_enable,
724 .enable_reg = MXC_CCM_CGR0,
725 .enable_shift = MXC_CCM_CGR0_I2C2_OFFSET,
726 .disable = _clk_disable,},
727 {
728 .name = "i2c_clk",
729 .id = 2,
730 .parent = &perclk_clk,
731 .enable = _clk_enable,
732 .enable_reg = MXC_CCM_CGR0,
733 .enable_shift = MXC_CCM_CGR0_I2C3_OFFSET,
734 .disable = _clk_disable,},
735};
736
737static struct clk owire_clk = {
738 .name = "owire_clk",
739 .parent = &perclk_clk,
740 .enable_reg = MXC_CCM_CGR1,
741 .enable_shift = MXC_CCM_CGR1_OWIRE_OFFSET,
742 .enable = _clk_enable,
743 .disable = _clk_disable,
744};
745
746static struct clk sdhc_clk[] = {
747 {
748 .name = "sdhc_clk",
749 .id = 0,
750 .parent = &perclk_clk,
751 .enable = _clk_enable,
752 .enable_reg = MXC_CCM_CGR0,
753 .enable_shift = MXC_CCM_CGR0_SD_MMC1_OFFSET,
754 .disable = _clk_disable,},
755 {
756 .name = "sdhc_clk",
757 .id = 1,
758 .parent = &perclk_clk,
759 .enable = _clk_enable,
760 .enable_reg = MXC_CCM_CGR0,
761 .enable_shift = MXC_CCM_CGR0_SD_MMC2_OFFSET,
762 .disable = _clk_disable,},
763};
764
765static struct clk ssi_clk[] = {
766 {
767 .name = "ssi_clk",
768 .parent = &serial_pll_clk,
769 .get_rate = _clk_ssi1_get_rate,
770 .enable = _clk_enable,
771 .enable_reg = MXC_CCM_CGR0,
772 .enable_shift = MXC_CCM_CGR0_SSI1_OFFSET,
773 .disable = _clk_disable,},
774 {
775 .name = "ssi_clk",
776 .id = 1,
777 .parent = &serial_pll_clk,
778 .get_rate = _clk_ssi2_get_rate,
779 .enable = _clk_enable,
780 .enable_reg = MXC_CCM_CGR2,
781 .enable_shift = MXC_CCM_CGR2_SSI2_OFFSET,
782 .disable = _clk_disable,},
783};
784
785static struct clk firi_clk = {
786 .name = "firi_clk",
787 .parent = &usb_pll_clk,
788 .round_rate = _clk_firi_round_rate,
789 .set_rate = _clk_firi_set_rate,
790 .get_rate = _clk_firi_get_rate,
791 .enable = _clk_enable,
792 .enable_reg = MXC_CCM_CGR2,
793 .enable_shift = MXC_CCM_CGR2_FIRI_OFFSET,
794 .disable = _clk_disable,
795};
796
797static struct clk ata_clk = {
798 .name = "ata_clk",
799 .parent = &ipg_clk,
800 .enable = _clk_enable,
801 .enable_reg = MXC_CCM_CGR0,
802 .enable_shift = MXC_CCM_CGR0_ATA_OFFSET,
803 .disable = _clk_disable,
804};
805
806static struct clk mbx_clk = {
807 .name = "mbx_clk",
808 .parent = &ahb_clk,
809 .enable = _clk_enable,
810 .enable_reg = MXC_CCM_CGR2,
811 .enable_shift = MXC_CCM_CGR2_GACC_OFFSET,
812 .get_rate = _clk_mbx_get_rate,
813};
814
815static struct clk vpu_clk = {
816 .name = "vpu_clk",
817 .parent = &ahb_clk,
818 .enable = _clk_enable,
819 .enable_reg = MXC_CCM_CGR2,
820 .enable_shift = MXC_CCM_CGR2_GACC_OFFSET,
821 .get_rate = _clk_mbx_get_rate,
822};
823
824static struct clk rtic_clk = {
825 .name = "rtic_clk",
826 .parent = &ahb_clk,
827 .enable = _clk_enable,
828 .enable_reg = MXC_CCM_CGR2,
829 .enable_shift = MXC_CCM_CGR2_RTIC_OFFSET,
830 .disable = _clk_disable,
831};
832
833static struct clk rng_clk = {
834 .name = "rng_clk",
835 .parent = &ipg_clk,
836 .enable = _clk_enable,
837 .enable_reg = MXC_CCM_CGR0,
838 .enable_shift = MXC_CCM_CGR0_RNG_OFFSET,
839 .disable = _clk_disable,
840};
841
842static struct clk sdma_clk[] = {
843 {
844 .name = "sdma_ahb_clk",
845 .parent = &ahb_clk,
846 .enable = _clk_enable,
847 .enable_reg = MXC_CCM_CGR0,
848 .enable_shift = MXC_CCM_CGR0_SDMA_OFFSET,
849 .disable = _clk_disable,},
850 {
851 .name = "sdma_ipg_clk",
852 .parent = &ipg_clk,}
853};
854
855static struct clk mpeg4_clk = {
856 .name = "mpeg4_clk",
857 .parent = &ahb_clk,
858 .enable = _clk_enable,
859 .enable_reg = MXC_CCM_CGR1,
860 .enable_shift = MXC_CCM_CGR1_HANTRO_OFFSET,
861 .disable = _clk_disable,
862};
863
864static struct clk vl2cc_clk = {
865 .name = "vl2cc_clk",
866 .parent = &ahb_clk,
867 .enable = _clk_enable,
868 .enable_reg = MXC_CCM_CGR1,
869 .enable_shift = MXC_CCM_CGR1_HANTRO_OFFSET,
870 .disable = _clk_disable,
871};
872
873static struct clk mstick_clk[] = {
874 {
875 .name = "mstick_clk",
876 .id = 0,
877 .parent = &usb_pll_clk,
878 .get_rate = _clk_mstick1_get_rate,
879 .enable = _clk_enable,
880 .enable_reg = MXC_CCM_CGR1,
881 .enable_shift = MXC_CCM_CGR1_MEMSTICK1_OFFSET,
882 .disable = _clk_disable,},
883 {
884 .name = "mstick_clk",
885 .id = 1,
886 .parent = &usb_pll_clk,
887 .get_rate = _clk_mstick2_get_rate,
888 .enable = _clk_enable,
889 .enable_reg = MXC_CCM_CGR1,
890 .enable_shift = MXC_CCM_CGR1_MEMSTICK2_OFFSET,
891 .disable = _clk_disable,},
892};
893
894static struct clk iim_clk = {
895 .name = "iim_clk",
896 .parent = &ipg_clk,
897 .enable = _clk_enable,
898 .enable_reg = MXC_CCM_CGR0,
899 .enable_shift = MXC_CCM_CGR0_IIM_OFFSET,
900 .disable = _clk_disable,
901};
902
903static unsigned long _clk_cko1_round_rate(struct clk *clk, unsigned long rate)
904{
905 u32 div, parent = clk_get_rate(clk->parent);
906
907 div = parent / rate;
908 if (parent % rate)
909 div++;
910
911 if (div > 8)
912 div = 16;
913 else if (div > 4)
914 div = 8;
915 else if (div > 2)
916 div = 4;
917
918 return parent / div;
919}
920
921static int _clk_cko1_set_rate(struct clk *clk, unsigned long rate)
922{
923 u32 reg, div, parent = clk_get_rate(clk->parent);
924
925 div = parent / rate;
926
927 if (div == 16)
928 div = 4;
929 else if (div == 8)
930 div = 3;
931 else if (div == 4)
932 div = 2;
933 else if (div == 2)
934 div = 1;
935 else if (div == 1)
936 div = 0;
937 else
938 return -EINVAL;
939
940 reg = __raw_readl(MXC_CCM_COSR) & ~MXC_CCM_COSR_CLKOUTDIV_MASK;
941 reg |= div << MXC_CCM_COSR_CLKOUTDIV_OFFSET;
942 __raw_writel(reg, MXC_CCM_COSR);
943
944 return 0;
945}
946
947static unsigned long _clk_cko1_get_rate(struct clk *clk)
948{
949 u32 div;
950
951 div = __raw_readl(MXC_CCM_COSR) & MXC_CCM_COSR_CLKOUTDIV_MASK >>
952 MXC_CCM_COSR_CLKOUTDIV_OFFSET;
953
954 return clk_get_rate(clk->parent) / (1 << div);
955}
956
957static int _clk_cko1_set_parent(struct clk *clk, struct clk *parent)
958{
959 u32 reg;
960
961 reg = __raw_readl(MXC_CCM_COSR) & ~MXC_CCM_COSR_CLKOSEL_MASK;
962
963 if (parent == &mcu_main_clk)
964 reg |= 0 << MXC_CCM_COSR_CLKOSEL_OFFSET;
965 else if (parent == &ipg_clk)
966 reg |= 1 << MXC_CCM_COSR_CLKOSEL_OFFSET;
967 else if (parent == &usb_pll_clk)
968 reg |= 2 << MXC_CCM_COSR_CLKOSEL_OFFSET;
969 else if (parent == mcu_main_clk.parent)
970 reg |= 3 << MXC_CCM_COSR_CLKOSEL_OFFSET;
971 else if (parent == &ahb_clk)
972 reg |= 5 << MXC_CCM_COSR_CLKOSEL_OFFSET;
973 else if (parent == &serial_pll_clk)
974 reg |= 7 << MXC_CCM_COSR_CLKOSEL_OFFSET;
975 else if (parent == &ckih_clk)
976 reg |= 8 << MXC_CCM_COSR_CLKOSEL_OFFSET;
977 else if (parent == &emi_clk)
978 reg |= 9 << MXC_CCM_COSR_CLKOSEL_OFFSET;
979 else if (parent == &ipu_clk)
980 reg |= 0xA << MXC_CCM_COSR_CLKOSEL_OFFSET;
981 else if (parent == &nfc_clk)
982 reg |= 0xB << MXC_CCM_COSR_CLKOSEL_OFFSET;
983 else if (parent == &uart_clk[0])
984 reg |= 0xC << MXC_CCM_COSR_CLKOSEL_OFFSET;
985 else
986 return -EINVAL;
987
988 __raw_writel(reg, MXC_CCM_COSR);
989
990 return 0;
991}
992
993static int _clk_cko1_enable(struct clk *clk)
994{
995 u32 reg;
996
997 reg = __raw_readl(MXC_CCM_COSR) | MXC_CCM_COSR_CLKOEN;
998 __raw_writel(reg, MXC_CCM_COSR);
999
1000 return 0;
1001}
1002
1003static void _clk_cko1_disable(struct clk *clk)
1004{
1005 u32 reg;
1006
1007 reg = __raw_readl(MXC_CCM_COSR) & ~MXC_CCM_COSR_CLKOEN;
1008 __raw_writel(reg, MXC_CCM_COSR);
1009}
1010
1011static struct clk cko1_clk = {
1012 .name = "cko1_clk",
1013 .get_rate = _clk_cko1_get_rate,
1014 .set_rate = _clk_cko1_set_rate,
1015 .round_rate = _clk_cko1_round_rate,
1016 .set_parent = _clk_cko1_set_parent,
1017 .enable = _clk_cko1_enable,
1018 .disable = _clk_cko1_disable,
1019};
1020
1021static struct clk *mxc_clks[] = {
1022 &ckih_clk,
1023 &ckil_clk,
1024 &mcu_pll_clk,
1025 &usb_pll_clk,
1026 &serial_pll_clk,
1027 &mcu_main_clk,
1028 &ahb_clk,
1029 &per_clk,
1030 &perclk_clk,
1031 &cko1_clk,
1032 &emi_clk,
1033 &cspi_clk[0],
1034 &cspi_clk[1],
1035 &cspi_clk[2],
1036 &ipg_clk,
1037 &gpt_clk,
1038 &pwm_clk,
1039 &wdog_clk,
1040 &rtc_clk,
1041 &epit_clk[0],
1042 &epit_clk[1],
1043 &nfc_clk,
1044 &ipu_clk,
1045 &kpp_clk,
1046 &usb_clk[0],
1047 &usb_clk[1],
1048 &csi_clk,
1049 &uart_clk[0],
1050 &uart_clk[1],
1051 &uart_clk[2],
1052 &uart_clk[3],
1053 &uart_clk[4],
1054 &i2c_clk[0],
1055 &i2c_clk[1],
1056 &i2c_clk[2],
1057 &owire_clk,
1058 &sdhc_clk[0],
1059 &sdhc_clk[1],
1060 &ssi_clk[0],
1061 &ssi_clk[1],
1062 &firi_clk,
1063 &ata_clk,
1064 &rtic_clk,
1065 &rng_clk,
1066 &sdma_clk[0],
1067 &sdma_clk[1],
1068 &mstick_clk[0],
1069 &mstick_clk[1],
1070 &scc_clk,
1071 &iim_clk,
1072};
1073
1074int __init mxc_clocks_init(unsigned long fref)
1075{
1076 u32 reg;
1077 struct clk **clkp;
1078
1079 ckih_rate = fref;
1080
1081 for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++)
1082 clk_register(*clkp);
1083
1084 if (cpu_is_mx31()) {
1085 clk_register(&mpeg4_clk);
1086 clk_register(&mbx_clk);
1087 } else {
1088 clk_register(&vpu_clk);
1089 clk_register(&vl2cc_clk);
1090 }
1091
1092 /* Turn off all possible clocks */
1093 __raw_writel(MXC_CCM_CGR0_GPT_MASK, MXC_CCM_CGR0);
1094 __raw_writel(0, MXC_CCM_CGR1);
1095
1096 __raw_writel(MXC_CCM_CGR2_EMI_MASK |
1097 MXC_CCM_CGR2_IPMUX1_MASK |
1098 MXC_CCM_CGR2_IPMUX2_MASK |
1099 MXC_CCM_CGR2_MXCCLKENSEL_MASK | /* for MX32 */
1100 MXC_CCM_CGR2_CHIKCAMPEN_MASK | /* for MX32 */
1101 MXC_CCM_CGR2_OVRVPUBUSY_MASK | /* for MX32 */
1102 1 << 27 | 1 << 28, /* Bit 27 and 28 are not defined for
1103 MX32, but still required to be set */
1104 MXC_CCM_CGR2);
1105
1106 clk_disable(&cko1_clk);
1107 clk_disable(&usb_pll_clk);
1108
1109 pr_info("Clock input source is %ld\n", clk_get_rate(&ckih_clk));
1110
1111 clk_enable(&gpt_clk);
1112 clk_enable(&emi_clk);
1113 clk_enable(&iim_clk);
1114
1115 clk_enable(&serial_pll_clk);
1116
1117 if (mx31_revision() >= CHIP_REV_2_0) {
1118 reg = __raw_readl(MXC_CCM_PMCR1);
1119 /* No PLL restart on DVFS switch; enable auto EMI handshake */
1120 reg |= MXC_CCM_PMCR1_PLLRDIS | MXC_CCM_PMCR1_EMIRQ_EN;
1121 __raw_writel(reg, MXC_CCM_PMCR1);
1122 }
1123
1124 return 0;
1125}
1126