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 as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <linux/kernel.h>
20 #include <linux/init.h>
21 #include <linux/list.h>
22 #include <linux/math64.h>
23 #include <linux/err.h>
24 #include <linux/clk.h>
27 #include <asm/clkdev.h>
29 #include <mach/clock.h>
30 #include <mach/hardware.h>
31 #include <mach/common.h>
34 static int _clk_enable(struct clk
*clk
)
38 reg
= __raw_readl(clk
->enable_reg
);
39 reg
|= 1 << clk
->enable_shift
;
40 __raw_writel(reg
, clk
->enable_reg
);
45 static void _clk_disable(struct clk
*clk
)
49 reg
= __raw_readl(clk
->enable_reg
);
50 reg
&= ~(1 << clk
->enable_shift
);
51 __raw_writel(reg
, clk
->enable_reg
);
54 static int _clk_can_use_parent(const struct clk
*clk_arr
[], unsigned int size
,
59 for (i
= 0; i
< size
; i
++)
60 if (parent
== clk_arr
[i
])
67 _clk_simple_round_rate(struct clk
*clk
, unsigned long rate
, unsigned int limit
)
70 unsigned long parent_rate
;
72 parent_rate
= clk_get_rate(clk
->parent
);
74 div
= parent_rate
/ rate
;
75 if (parent_rate
% rate
)
81 return parent_rate
/ div
;
84 static unsigned long _clk_parent_round_rate(struct clk
*clk
, unsigned long rate
)
86 return clk
->parent
->round_rate(clk
->parent
, rate
);
89 static int _clk_parent_set_rate(struct clk
*clk
, unsigned long rate
)
91 return clk
->parent
->set_rate(clk
->parent
, rate
);
94 static unsigned long clk16m_get_rate(struct clk
*clk
)
99 static struct clk clk16m
= {
100 .get_rate
= clk16m_get_rate
,
101 .enable
= _clk_enable
,
102 .enable_reg
= CCM_CSCR
,
103 .enable_shift
= CCM_CSCR_OSC_EN_SHIFT
,
104 .disable
= _clk_disable
,
108 static unsigned long clk32_rate
;
110 static unsigned long clk32_get_rate(struct clk
*clk
)
115 static struct clk clk32
= {
116 .get_rate
= clk32_get_rate
,
119 static unsigned long clk32_premult_get_rate(struct clk
*clk
)
121 return clk_get_rate(clk
->parent
) * 512;
124 static struct clk clk32_premult
= {
126 .get_rate
= clk32_premult_get_rate
,
129 static const struct clk
*prem_clk_clocks
[] = {
134 static int prem_clk_set_parent(struct clk
*clk
, struct clk
*parent
)
137 unsigned int reg
= __raw_readl(CCM_CSCR
);
139 i
= _clk_can_use_parent(prem_clk_clocks
, ARRAY_SIZE(prem_clk_clocks
),
144 reg
&= ~CCM_CSCR_SYSTEM_SEL
;
147 reg
|= CCM_CSCR_SYSTEM_SEL
;
153 __raw_writel(reg
, CCM_CSCR
);
158 static struct clk prem_clk
= {
159 .set_parent
= prem_clk_set_parent
,
162 static unsigned long system_clk_get_rate(struct clk
*clk
)
164 return mxc_decode_pll(__raw_readl(CCM_SPCTL0
),
165 clk_get_rate(clk
->parent
));
168 static struct clk system_clk
= {
170 .get_rate
= system_clk_get_rate
,
173 static unsigned long mcu_clk_get_rate(struct clk
*clk
)
175 return mxc_decode_pll(__raw_readl(CCM_MPCTL0
),
176 clk_get_rate(clk
->parent
));
179 static struct clk mcu_clk
= {
180 .parent
= &clk32_premult
,
181 .get_rate
= mcu_clk_get_rate
,
184 static unsigned long fclk_get_rate(struct clk
*clk
)
186 unsigned long fclk
= clk_get_rate(clk
->parent
);
188 if (__raw_readl(CCM_CSCR
) & CCM_CSCR_PRESC
)
194 static struct clk fclk
= {
196 .get_rate
= fclk_get_rate
,
200 * get hclk ( SDRAM, CSI, Memory Stick, I2C, DMA )
202 static unsigned long hclk_get_rate(struct clk
*clk
)
204 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_CSCR
) &
205 CCM_CSCR_BCLK_MASK
) >> CCM_CSCR_BCLK_OFFSET
) + 1);
208 static unsigned long hclk_round_rate(struct clk
*clk
, unsigned long rate
)
210 return _clk_simple_round_rate(clk
, rate
, 16);
213 static int hclk_set_rate(struct clk
*clk
, unsigned long rate
)
217 unsigned long parent_rate
;
219 parent_rate
= clk_get_rate(clk
->parent
);
221 div
= parent_rate
/ rate
;
223 if (div
> 16 || div
< 1 || ((parent_rate
/ div
) != rate
))
228 reg
= __raw_readl(CCM_CSCR
);
229 reg
&= ~CCM_CSCR_BCLK_MASK
;
230 reg
|= div
<< CCM_CSCR_BCLK_OFFSET
;
231 __raw_writel(reg
, CCM_CSCR
);
236 static struct clk hclk
= {
237 .parent
= &system_clk
,
238 .get_rate
= hclk_get_rate
,
239 .round_rate
= hclk_round_rate
,
240 .set_rate
= hclk_set_rate
,
243 static unsigned long clk48m_get_rate(struct clk
*clk
)
245 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_CSCR
) &
246 CCM_CSCR_USB_MASK
) >> CCM_CSCR_USB_OFFSET
) + 1);
249 static unsigned long clk48m_round_rate(struct clk
*clk
, unsigned long rate
)
251 return _clk_simple_round_rate(clk
, rate
, 8);
254 static int clk48m_set_rate(struct clk
*clk
, unsigned long rate
)
258 unsigned long parent_rate
;
260 parent_rate
= clk_get_rate(clk
->parent
);
262 div
= parent_rate
/ rate
;
264 if (div
> 8 || div
< 1 || ((parent_rate
/ div
) != rate
))
269 reg
= __raw_readl(CCM_CSCR
);
270 reg
&= ~CCM_CSCR_USB_MASK
;
271 reg
|= div
<< CCM_CSCR_USB_OFFSET
;
272 __raw_writel(reg
, CCM_CSCR
);
277 static struct clk clk48m
= {
278 .parent
= &system_clk
,
279 .get_rate
= clk48m_get_rate
,
280 .round_rate
= clk48m_round_rate
,
281 .set_rate
= clk48m_set_rate
,
285 * get peripheral clock 1 ( UART[12], Timer[12], PWM )
287 static unsigned long perclk1_get_rate(struct clk
*clk
)
289 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_PCDR
) &
290 CCM_PCDR_PCLK1_MASK
) >> CCM_PCDR_PCLK1_OFFSET
) + 1);
293 static unsigned long perclk1_round_rate(struct clk
*clk
, unsigned long rate
)
295 return _clk_simple_round_rate(clk
, rate
, 16);
298 static int perclk1_set_rate(struct clk
*clk
, unsigned long rate
)
302 unsigned long parent_rate
;
304 parent_rate
= clk_get_rate(clk
->parent
);
306 div
= parent_rate
/ rate
;
308 if (div
> 16 || div
< 1 || ((parent_rate
/ div
) != rate
))
313 reg
= __raw_readl(CCM_PCDR
);
314 reg
&= ~CCM_PCDR_PCLK1_MASK
;
315 reg
|= div
<< CCM_PCDR_PCLK1_OFFSET
;
316 __raw_writel(reg
, CCM_PCDR
);
322 * get peripheral clock 2 ( LCD, SD, SPI[12] )
324 static unsigned long perclk2_get_rate(struct clk
*clk
)
326 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_PCDR
) &
327 CCM_PCDR_PCLK2_MASK
) >> CCM_PCDR_PCLK2_OFFSET
) + 1);
330 static unsigned long perclk2_round_rate(struct clk
*clk
, unsigned long rate
)
332 return _clk_simple_round_rate(clk
, rate
, 16);
335 static int perclk2_set_rate(struct clk
*clk
, unsigned long rate
)
339 unsigned long parent_rate
;
341 parent_rate
= clk_get_rate(clk
->parent
);
343 div
= parent_rate
/ rate
;
345 if (div
> 16 || div
< 1 || ((parent_rate
/ div
) != rate
))
350 reg
= __raw_readl(CCM_PCDR
);
351 reg
&= ~CCM_PCDR_PCLK2_MASK
;
352 reg
|= div
<< CCM_PCDR_PCLK2_OFFSET
;
353 __raw_writel(reg
, CCM_PCDR
);
359 * get peripheral clock 3 ( SSI )
361 static unsigned long perclk3_get_rate(struct clk
*clk
)
363 return clk_get_rate(clk
->parent
) / (((__raw_readl(CCM_PCDR
) &
364 CCM_PCDR_PCLK3_MASK
) >> CCM_PCDR_PCLK3_OFFSET
) + 1);
367 static unsigned long perclk3_round_rate(struct clk
*clk
, unsigned long rate
)
369 return _clk_simple_round_rate(clk
, rate
, 128);
372 static int perclk3_set_rate(struct clk
*clk
, unsigned long rate
)
376 unsigned long parent_rate
;
378 parent_rate
= clk_get_rate(clk
->parent
);
380 div
= parent_rate
/ rate
;
382 if (div
> 128 || div
< 1 || ((parent_rate
/ div
) != rate
))
387 reg
= __raw_readl(CCM_PCDR
);
388 reg
&= ~CCM_PCDR_PCLK3_MASK
;
389 reg
|= div
<< CCM_PCDR_PCLK3_OFFSET
;
390 __raw_writel(reg
, CCM_PCDR
);
395 static struct clk perclk
[] = {
398 .parent
= &system_clk
,
399 .get_rate
= perclk1_get_rate
,
400 .round_rate
= perclk1_round_rate
,
401 .set_rate
= perclk1_set_rate
,
404 .parent
= &system_clk
,
405 .get_rate
= perclk2_get_rate
,
406 .round_rate
= perclk2_round_rate
,
407 .set_rate
= perclk2_set_rate
,
410 .parent
= &system_clk
,
411 .get_rate
= perclk3_get_rate
,
412 .round_rate
= perclk3_round_rate
,
413 .set_rate
= perclk3_set_rate
,
417 static const struct clk
*clko_clocks
[] = {
426 static int clko_set_parent(struct clk
*clk
, struct clk
*parent
)
431 i
= _clk_can_use_parent(clko_clocks
, ARRAY_SIZE(clko_clocks
), parent
);
435 reg
= __raw_readl(CCM_CSCR
) & ~CCM_CSCR_CLKO_MASK
;
436 reg
|= i
<< CCM_CSCR_CLKO_OFFSET
;
437 __raw_writel(reg
, CCM_CSCR
);
439 if (clko_clocks
[i
]->set_rate
&& clko_clocks
[i
]->round_rate
) {
440 clk
->set_rate
= _clk_parent_set_rate
;
441 clk
->round_rate
= _clk_parent_round_rate
;
443 clk
->set_rate
= NULL
;
444 clk
->round_rate
= NULL
;
450 static struct clk clko_clk
= {
451 .set_parent
= clko_set_parent
,
454 static struct clk dma_clk
= {
456 .round_rate
= _clk_parent_round_rate
,
457 .set_rate
= _clk_parent_set_rate
,
458 .enable
= _clk_enable
,
459 .enable_reg
= SCM_GCCR
,
460 .enable_shift
= SCM_GCCR_DMA_CLK_EN_OFFSET
,
461 .disable
= _clk_disable
,
464 static struct clk csi_clk
= {
466 .round_rate
= _clk_parent_round_rate
,
467 .set_rate
= _clk_parent_set_rate
,
468 .enable
= _clk_enable
,
469 .enable_reg
= SCM_GCCR
,
470 .enable_shift
= SCM_GCCR_CSI_CLK_EN_OFFSET
,
471 .disable
= _clk_disable
,
474 static struct clk mma_clk
= {
476 .round_rate
= _clk_parent_round_rate
,
477 .set_rate
= _clk_parent_set_rate
,
478 .enable
= _clk_enable
,
479 .enable_reg
= SCM_GCCR
,
480 .enable_shift
= SCM_GCCR_MMA_CLK_EN_OFFSET
,
481 .disable
= _clk_disable
,
484 static struct clk usbd_clk
= {
486 .round_rate
= _clk_parent_round_rate
,
487 .set_rate
= _clk_parent_set_rate
,
488 .enable
= _clk_enable
,
489 .enable_reg
= SCM_GCCR
,
490 .enable_shift
= SCM_GCCR_USBD_CLK_EN_OFFSET
,
491 .disable
= _clk_disable
,
494 static struct clk gpt_clk
= {
495 .parent
= &perclk
[0],
496 .round_rate
= _clk_parent_round_rate
,
497 .set_rate
= _clk_parent_set_rate
,
500 static struct clk uart_clk
= {
501 .parent
= &perclk
[0],
502 .round_rate
= _clk_parent_round_rate
,
503 .set_rate
= _clk_parent_set_rate
,
506 static struct clk i2c_clk
= {
508 .round_rate
= _clk_parent_round_rate
,
509 .set_rate
= _clk_parent_set_rate
,
512 static struct clk spi_clk
= {
513 .parent
= &perclk
[1],
514 .round_rate
= _clk_parent_round_rate
,
515 .set_rate
= _clk_parent_set_rate
,
518 static struct clk sdhc_clk
= {
519 .parent
= &perclk
[1],
520 .round_rate
= _clk_parent_round_rate
,
521 .set_rate
= _clk_parent_set_rate
,
524 static struct clk lcdc_clk
= {
525 .parent
= &perclk
[1],
526 .round_rate
= _clk_parent_round_rate
,
527 .set_rate
= _clk_parent_set_rate
,
530 static struct clk mshc_clk
= {
532 .round_rate
= _clk_parent_round_rate
,
533 .set_rate
= _clk_parent_set_rate
,
536 static struct clk ssi_clk
= {
537 .parent
= &perclk
[2],
538 .round_rate
= _clk_parent_round_rate
,
539 .set_rate
= _clk_parent_set_rate
,
542 static struct clk rtc_clk
= {
546 #define _REGISTER_CLOCK(d, n, c) \
552 static struct clk_lookup lookups
[] __initdata
= {
553 _REGISTER_CLOCK(NULL
, "dma", dma_clk
)
554 _REGISTER_CLOCK("mx1-camera.0", NULL
, csi_clk
)
555 _REGISTER_CLOCK(NULL
, "mma", mma_clk
)
556 _REGISTER_CLOCK("imx_udc.0", NULL
, usbd_clk
)
557 _REGISTER_CLOCK(NULL
, "gpt", gpt_clk
)
558 _REGISTER_CLOCK("imx-uart.0", NULL
, uart_clk
)
559 _REGISTER_CLOCK("imx-uart.1", NULL
, uart_clk
)
560 _REGISTER_CLOCK("imx-uart.2", NULL
, uart_clk
)
561 _REGISTER_CLOCK("imx-i2c.0", NULL
, i2c_clk
)
562 _REGISTER_CLOCK("spi_imx.0", NULL
, spi_clk
)
563 _REGISTER_CLOCK("imx-mmc.0", NULL
, sdhc_clk
)
564 _REGISTER_CLOCK("imx-fb.0", NULL
, lcdc_clk
)
565 _REGISTER_CLOCK(NULL
, "mshc", mshc_clk
)
566 _REGISTER_CLOCK(NULL
, "ssi", ssi_clk
)
567 _REGISTER_CLOCK("mxc_rtc.0", NULL
, rtc_clk
)
570 int __init
mx1_clocks_init(unsigned long fref
)
575 /* disable clocks we are able to */
576 __raw_writel(0, SCM_GCCR
);
579 reg
= __raw_readl(CCM_CSCR
);
581 /* detect clock reference for system PLL */
582 if (reg
& CCM_CSCR_SYSTEM_SEL
) {
583 prem_clk
.parent
= &clk16m
;
585 /* ensure that oscillator is disabled */
586 reg
&= ~(1 << CCM_CSCR_OSC_EN_SHIFT
);
587 __raw_writel(reg
, CCM_CSCR
);
588 prem_clk
.parent
= &clk32_premult
;
591 /* detect reference for CLKO */
592 reg
= (reg
& CCM_CSCR_CLKO_MASK
) >> CCM_CSCR_CLKO_OFFSET
;
593 clko_clk
.parent
= (struct clk
*)clko_clocks
[reg
];
595 for (i
= 0; i
< ARRAY_SIZE(lookups
); i
++)
596 clkdev_add(&lookups
[i
]);
601 mxc_timer_init(&gpt_clk
, IO_ADDRESS(TIM1_BASE_ADDR
), TIM1_INT
);