2 * Copyright (C) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
18 #include <linux/kernel.h>
19 #include <linux/init.h>
20 #include <linux/list.h>
21 #include <linux/math64.h>
22 #include <linux/err.h>
23 #include <linux/clk.h>
25 #include <linux/clkdev.h>
27 #include <mach/clock.h>
28 #include <mach/hardware.h>
29 #include <mach/common.h>
31 #define IO_ADDR_CCM(off) (MX1_IO_ADDRESS(MX1_CCM_BASE_ADDR + (off)))
33 /* CCM register addresses */
34 #define CCM_CSCR IO_ADDR_CCM(0x0)
35 #define CCM_MPCTL0 IO_ADDR_CCM(0x4)
36 #define CCM_SPCTL0 IO_ADDR_CCM(0xc)
37 #define CCM_PCDR IO_ADDR_CCM(0x20)
39 #define CCM_CSCR_CLKO_OFFSET 29
40 #define CCM_CSCR_CLKO_MASK (0x7 << 29)
41 #define CCM_CSCR_USB_OFFSET 26
42 #define CCM_CSCR_USB_MASK (0x7 << 26)
43 #define CCM_CSCR_OSC_EN_SHIFT 17
44 #define CCM_CSCR_SYSTEM_SEL (1 << 16)
45 #define CCM_CSCR_BCLK_OFFSET 10
46 #define CCM_CSCR_BCLK_MASK (0xf << 10)
47 #define CCM_CSCR_PRESC (1 << 15)
49 #define CCM_PCDR_PCLK3_OFFSET 16
50 #define CCM_PCDR_PCLK3_MASK (0x7f << 16)
51 #define CCM_PCDR_PCLK2_OFFSET 4
52 #define CCM_PCDR_PCLK2_MASK (0xf << 4)
53 #define CCM_PCDR_PCLK1_OFFSET 0
54 #define CCM_PCDR_PCLK1_MASK 0xf
56 #define IO_ADDR_SCM(off) (MX1_IO_ADDRESS(MX1_SCM_BASE_ADDR + (off)))
58 /* SCM register addresses */
59 #define SCM_GCCR IO_ADDR_SCM(0xc)
61 #define SCM_GCCR_DMA_CLK_EN_OFFSET 3
62 #define SCM_GCCR_CSI_CLK_EN_OFFSET 2
63 #define SCM_GCCR_MMA_CLK_EN_OFFSET 1
64 #define SCM_GCCR_USBD_CLK_EN_OFFSET 0
66 static int _clk_enable(struct clk
*clk
)
70 reg
= __raw_readl(clk
->enable_reg
);
71 reg
|= 1 << clk
->enable_shift
;
72 __raw_writel(reg
, clk
->enable_reg
);
77 static void _clk_disable(struct clk
*clk
)
81 reg
= __raw_readl(clk
->enable_reg
);
82 reg
&= ~(1 << clk
->enable_shift
);
83 __raw_writel(reg
, clk
->enable_reg
);
86 static int _clk_can_use_parent(const struct clk
*clk_arr
[], unsigned int size
,
91 for (i
= 0; i
< size
; i
++)
92 if (parent
== clk_arr
[i
])
99 _clk_simple_round_rate(struct clk
*clk
, unsigned long rate
, unsigned int limit
)
102 unsigned long parent_rate
;
104 parent_rate
= clk_get_rate(clk
->parent
);
106 div
= parent_rate
/ rate
;
107 if (parent_rate
% rate
)
113 return parent_rate
/ div
;
116 static unsigned long _clk_parent_round_rate(struct clk
*clk
, unsigned long rate
)
118 return clk
->parent
->round_rate(clk
->parent
, rate
);
121 static int _clk_parent_set_rate(struct clk
*clk
, unsigned long rate
)
123 return clk
->parent
->set_rate(clk
->parent
, rate
);
126 static unsigned long clk16m_get_rate(struct clk
*clk
)
131 static struct clk clk16m
= {
132 .get_rate
= clk16m_get_rate
,
133 .enable
= _clk_enable
,
134 .enable_reg
= CCM_CSCR
,
135 .enable_shift
= CCM_CSCR_OSC_EN_SHIFT
,
136 .disable
= _clk_disable
,
140 static unsigned long clk32_rate
;
142 static unsigned long clk32_get_rate(struct clk
*clk
)
147 static struct clk clk32
= {
148 .get_rate
= clk32_get_rate
,
151 static unsigned long clk32_premult_get_rate(struct clk
*clk
)
153 return clk_get_rate(clk
->parent
) * 512;
156 static struct clk clk32_premult
= {
158 .get_rate
= clk32_premult_get_rate
,
161 static const struct clk
*prem_clk_clocks
[] = {
166 static int prem_clk_set_parent(struct clk
*clk
, struct clk
*parent
)
169 unsigned int reg
= __raw_readl(CCM_CSCR
);
171 i
= _clk_can_use_parent(prem_clk_clocks
, ARRAY_SIZE(prem_clk_clocks
),
176 reg
&= ~CCM_CSCR_SYSTEM_SEL
;
179 reg
|= CCM_CSCR_SYSTEM_SEL
;
185 __raw_writel(reg
, CCM_CSCR
);
190 static struct clk prem_clk
= {
191 .set_parent
= prem_clk_set_parent
,
194 static unsigned long system_clk_get_rate(struct clk
*clk
)
196 return mxc_decode_pll(__raw_readl(CCM_SPCTL0
),
197 clk_get_rate(clk
->parent
));
200 static struct clk system_clk
= {
202 .get_rate
= system_clk_get_rate
,
205 static unsigned long mcu_clk_get_rate(struct clk
*clk
)
207 return mxc_decode_pll(__raw_readl(CCM_MPCTL0
),
208 clk_get_rate(clk
->parent
));
211 static struct clk mcu_clk
= {
212 .parent
= &clk32_premult
,
213 .get_rate
= mcu_clk_get_rate
,
216 static unsigned long fclk_get_rate(struct clk
*clk
)
218 unsigned long fclk
= clk_get_rate(clk
->parent
);
220 if (__raw_readl(CCM_CSCR
) & CCM_CSCR_PRESC
)
226 static struct clk fclk
= {
228 .get_rate
= fclk_get_rate
,
232 * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
234 static unsigned long hclk_get_rate(struct clk
*clk
)
236 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_CSCR
) &
237 CCM_CSCR_BCLK_MASK
) >> CCM_CSCR_BCLK_OFFSET
) + 1);
240 static unsigned long hclk_round_rate(struct clk
*clk
, unsigned long rate
)
242 return _clk_simple_round_rate(clk
, rate
, 16);
245 static int hclk_set_rate(struct clk
*clk
, unsigned long rate
)
249 unsigned long parent_rate
;
251 parent_rate
= clk_get_rate(clk
->parent
);
253 div
= parent_rate
/ rate
;
255 if (div
> 16 || div
< 1 || ((parent_rate
/ div
) != rate
))
260 reg
= __raw_readl(CCM_CSCR
);
261 reg
&= ~CCM_CSCR_BCLK_MASK
;
262 reg
|= div
<< CCM_CSCR_BCLK_OFFSET
;
263 __raw_writel(reg
, CCM_CSCR
);
268 static struct clk hclk
= {
269 .parent
= &system_clk
,
270 .get_rate
= hclk_get_rate
,
271 .round_rate
= hclk_round_rate
,
272 .set_rate
= hclk_set_rate
,
275 static unsigned long clk48m_get_rate(struct clk
*clk
)
277 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_CSCR
) &
278 CCM_CSCR_USB_MASK
) >> CCM_CSCR_USB_OFFSET
) + 1);
281 static unsigned long clk48m_round_rate(struct clk
*clk
, unsigned long rate
)
283 return _clk_simple_round_rate(clk
, rate
, 8);
286 static int clk48m_set_rate(struct clk
*clk
, unsigned long rate
)
290 unsigned long parent_rate
;
292 parent_rate
= clk_get_rate(clk
->parent
);
294 div
= parent_rate
/ rate
;
296 if (div
> 8 || div
< 1 || ((parent_rate
/ div
) != rate
))
301 reg
= __raw_readl(CCM_CSCR
);
302 reg
&= ~CCM_CSCR_USB_MASK
;
303 reg
|= div
<< CCM_CSCR_USB_OFFSET
;
304 __raw_writel(reg
, CCM_CSCR
);
309 static struct clk clk48m
= {
310 .parent
= &system_clk
,
311 .get_rate
= clk48m_get_rate
,
312 .round_rate
= clk48m_round_rate
,
313 .set_rate
= clk48m_set_rate
,
317 * get peripheral clock 1 ( UART[12], Timer[12], PWM )
319 static unsigned long perclk1_get_rate(struct clk
*clk
)
321 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_PCDR
) &
322 CCM_PCDR_PCLK1_MASK
) >> CCM_PCDR_PCLK1_OFFSET
) + 1);
325 static unsigned long perclk1_round_rate(struct clk
*clk
, unsigned long rate
)
327 return _clk_simple_round_rate(clk
, rate
, 16);
330 static int perclk1_set_rate(struct clk
*clk
, unsigned long rate
)
334 unsigned long parent_rate
;
336 parent_rate
= clk_get_rate(clk
->parent
);
338 div
= parent_rate
/ rate
;
340 if (div
> 16 || div
< 1 || ((parent_rate
/ div
) != rate
))
345 reg
= __raw_readl(CCM_PCDR
);
346 reg
&= ~CCM_PCDR_PCLK1_MASK
;
347 reg
|= div
<< CCM_PCDR_PCLK1_OFFSET
;
348 __raw_writel(reg
, CCM_PCDR
);
354 * get peripheral clock 2 ( LCD, SD, SPI[12] )
356 static unsigned long perclk2_get_rate(struct clk
*clk
)
358 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_PCDR
) &
359 CCM_PCDR_PCLK2_MASK
) >> CCM_PCDR_PCLK2_OFFSET
) + 1);
362 static unsigned long perclk2_round_rate(struct clk
*clk
, unsigned long rate
)
364 return _clk_simple_round_rate(clk
, rate
, 16);
367 static int perclk2_set_rate(struct clk
*clk
, unsigned long rate
)
371 unsigned long parent_rate
;
373 parent_rate
= clk_get_rate(clk
->parent
);
375 div
= parent_rate
/ rate
;
377 if (div
> 16 || div
< 1 || ((parent_rate
/ div
) != rate
))
382 reg
= __raw_readl(CCM_PCDR
);
383 reg
&= ~CCM_PCDR_PCLK2_MASK
;
384 reg
|= div
<< CCM_PCDR_PCLK2_OFFSET
;
385 __raw_writel(reg
, CCM_PCDR
);
391 * get peripheral clock 3 ( SSI )
393 static unsigned long perclk3_get_rate(struct clk
*clk
)
395 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_PCDR
) &
396 CCM_PCDR_PCLK3_MASK
) >> CCM_PCDR_PCLK3_OFFSET
) + 1);
399 static unsigned long perclk3_round_rate(struct clk
*clk
, unsigned long rate
)
401 return _clk_simple_round_rate(clk
, rate
, 128);
404 static int perclk3_set_rate(struct clk
*clk
, unsigned long rate
)
408 unsigned long parent_rate
;
410 parent_rate
= clk_get_rate(clk
->parent
);
412 div
= parent_rate
/ rate
;
414 if (div
> 128 || div
< 1 || ((parent_rate
/ div
) != rate
))
419 reg
= __raw_readl(CCM_PCDR
);
420 reg
&= ~CCM_PCDR_PCLK3_MASK
;
421 reg
|= div
<< CCM_PCDR_PCLK3_OFFSET
;
422 __raw_writel(reg
, CCM_PCDR
);
427 static struct clk perclk
[] = {
430 .parent
= &system_clk
,
431 .get_rate
= perclk1_get_rate
,
432 .round_rate
= perclk1_round_rate
,
433 .set_rate
= perclk1_set_rate
,
436 .parent
= &system_clk
,
437 .get_rate
= perclk2_get_rate
,
438 .round_rate
= perclk2_round_rate
,
439 .set_rate
= perclk2_set_rate
,
442 .parent
= &system_clk
,
443 .get_rate
= perclk3_get_rate
,
444 .round_rate
= perclk3_round_rate
,
445 .set_rate
= perclk3_set_rate
,
449 static const struct clk
*clko_clocks
[] = {
458 static int clko_set_parent(struct clk
*clk
, struct clk
*parent
)
463 i
= _clk_can_use_parent(clko_clocks
, ARRAY_SIZE(clko_clocks
), parent
);
467 reg
= __raw_readl(CCM_CSCR
) & ~CCM_CSCR_CLKO_MASK
;
468 reg
|= i
<< CCM_CSCR_CLKO_OFFSET
;
469 __raw_writel(reg
, CCM_CSCR
);
471 if (clko_clocks
[i
]->set_rate
&& clko_clocks
[i
]->round_rate
) {
472 clk
->set_rate
= _clk_parent_set_rate
;
473 clk
->round_rate
= _clk_parent_round_rate
;
475 clk
->set_rate
= NULL
;
476 clk
->round_rate
= NULL
;
482 static struct clk clko_clk
= {
483 .set_parent
= clko_set_parent
,
486 static struct clk dma_clk
= {
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_DMA_CLK_EN_OFFSET
,
493 .disable
= _clk_disable
,
496 static struct clk csi_clk
= {
498 .round_rate
= _clk_parent_round_rate
,
499 .set_rate
= _clk_parent_set_rate
,
500 .enable
= _clk_enable
,
501 .enable_reg
= SCM_GCCR
,
502 .enable_shift
= SCM_GCCR_CSI_CLK_EN_OFFSET
,
503 .disable
= _clk_disable
,
506 static struct clk mma_clk
= {
508 .round_rate
= _clk_parent_round_rate
,
509 .set_rate
= _clk_parent_set_rate
,
510 .enable
= _clk_enable
,
511 .enable_reg
= SCM_GCCR
,
512 .enable_shift
= SCM_GCCR_MMA_CLK_EN_OFFSET
,
513 .disable
= _clk_disable
,
516 static struct clk usbd_clk
= {
518 .round_rate
= _clk_parent_round_rate
,
519 .set_rate
= _clk_parent_set_rate
,
520 .enable
= _clk_enable
,
521 .enable_reg
= SCM_GCCR
,
522 .enable_shift
= SCM_GCCR_USBD_CLK_EN_OFFSET
,
523 .disable
= _clk_disable
,
526 static struct clk gpt_clk
= {
527 .parent
= &perclk
[0],
528 .round_rate
= _clk_parent_round_rate
,
529 .set_rate
= _clk_parent_set_rate
,
532 static struct clk uart_clk
= {
533 .parent
= &perclk
[0],
534 .round_rate
= _clk_parent_round_rate
,
535 .set_rate
= _clk_parent_set_rate
,
538 static struct clk i2c_clk
= {
540 .round_rate
= _clk_parent_round_rate
,
541 .set_rate
= _clk_parent_set_rate
,
544 static struct clk spi_clk
= {
545 .parent
= &perclk
[1],
546 .round_rate
= _clk_parent_round_rate
,
547 .set_rate
= _clk_parent_set_rate
,
550 static struct clk sdhc_clk
= {
551 .parent
= &perclk
[1],
552 .round_rate
= _clk_parent_round_rate
,
553 .set_rate
= _clk_parent_set_rate
,
556 static struct clk lcdc_clk
= {
557 .parent
= &perclk
[1],
558 .round_rate
= _clk_parent_round_rate
,
559 .set_rate
= _clk_parent_set_rate
,
562 static struct clk mshc_clk
= {
564 .round_rate
= _clk_parent_round_rate
,
565 .set_rate
= _clk_parent_set_rate
,
568 static struct clk ssi_clk
= {
569 .parent
= &perclk
[2],
570 .round_rate
= _clk_parent_round_rate
,
571 .set_rate
= _clk_parent_set_rate
,
574 static struct clk rtc_clk
= {
578 #define _REGISTER_CLOCK(d, n, c) \
584 static struct clk_lookup lookups
[] __initdata
= {
585 _REGISTER_CLOCK(NULL
, "dma", dma_clk
)
586 _REGISTER_CLOCK("mx1-camera.0", NULL
, csi_clk
)
587 _REGISTER_CLOCK(NULL
, "mma", mma_clk
)
588 _REGISTER_CLOCK("imx_udc.0", NULL
, usbd_clk
)
589 _REGISTER_CLOCK(NULL
, "gpt", gpt_clk
)
590 _REGISTER_CLOCK("imx-uart.0", NULL
, uart_clk
)
591 _REGISTER_CLOCK("imx-uart.1", NULL
, uart_clk
)
592 _REGISTER_CLOCK("imx-uart.2", NULL
, uart_clk
)
593 _REGISTER_CLOCK("imx-i2c.0", NULL
, i2c_clk
)
594 _REGISTER_CLOCK("imx1-cspi.0", NULL
, spi_clk
)
595 _REGISTER_CLOCK("imx1-cspi.1", NULL
, spi_clk
)
596 _REGISTER_CLOCK("imx-mmc.0", NULL
, sdhc_clk
)
597 _REGISTER_CLOCK("imx-fb.0", NULL
, lcdc_clk
)
598 _REGISTER_CLOCK(NULL
, "mshc", mshc_clk
)
599 _REGISTER_CLOCK(NULL
, "ssi", ssi_clk
)
600 _REGISTER_CLOCK("mxc_rtc.0", NULL
, rtc_clk
)
603 int __init
mx1_clocks_init(unsigned long fref
)
607 /* disable clocks we are able to */
608 __raw_writel(0, SCM_GCCR
);
611 reg
= __raw_readl(CCM_CSCR
);
613 /* detect clock reference for system PLL */
614 if (reg
& CCM_CSCR_SYSTEM_SEL
) {
615 prem_clk
.parent
= &clk16m
;
617 /* ensure that oscillator is disabled */
618 reg
&= ~(1 << CCM_CSCR_OSC_EN_SHIFT
);
619 __raw_writel(reg
, CCM_CSCR
);
620 prem_clk
.parent
= &clk32_premult
;
623 /* detect reference for CLKO */
624 reg
= (reg
& CCM_CSCR_CLKO_MASK
) >> CCM_CSCR_CLKO_OFFSET
;
625 clko_clk
.parent
= (struct clk
*)clko_clocks
[reg
];
627 clkdev_add_table(lookups
, ARRAY_SIZE(lookups
));
632 mxc_timer_init(&gpt_clk
, MX1_IO_ADDRESS(MX1_TIM1_BASE_ADDR
),