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