2 * Copyright (c) 2004-2008 Simtec Electronics
3 * Ben Dooks <ben@simtec.co.uk>
4 * http://armlinux.simtec.co.uk/
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 * S3C24XX - definitions for DCLK and CLKOUT registers
13 #include <linux/kernel.h>
14 #include <linux/errno.h>
15 #include <linux/clk.h>
18 #include <mach/regs-clock.h>
19 #include <mach/regs-gpio.h>
21 #include <plat/clock.h>
24 /* clocks that could be registered by external code */
26 static int s3c24xx_dclk_enable(struct clk
*clk
, int enable
)
28 unsigned long dclkcon
= __raw_readl(S3C24XX_DCLKCON
);
31 dclkcon
|= clk
->ctrlbit
;
33 dclkcon
&= ~clk
->ctrlbit
;
35 __raw_writel(dclkcon
, S3C24XX_DCLKCON
);
40 static int s3c24xx_dclk_setparent(struct clk
*clk
, struct clk
*parent
)
42 unsigned long dclkcon
;
45 if (parent
== &clk_upll
)
47 else if (parent
== &clk_p
)
54 dclkcon
= __raw_readl(S3C24XX_DCLKCON
);
56 if (clk
->ctrlbit
== S3C2410_DCLKCON_DCLK0EN
) {
58 dclkcon
|= S3C2410_DCLKCON_DCLK0_UCLK
;
60 dclkcon
&= ~S3C2410_DCLKCON_DCLK0_UCLK
;
63 dclkcon
|= S3C2410_DCLKCON_DCLK1_UCLK
;
65 dclkcon
&= ~S3C2410_DCLKCON_DCLK1_UCLK
;
68 __raw_writel(dclkcon
, S3C24XX_DCLKCON
);
72 static unsigned long s3c24xx_calc_div(struct clk
*clk
, unsigned long rate
)
76 if ((rate
== 0) || !clk
->parent
)
79 div
= clk_get_rate(clk
->parent
) / rate
;
88 static unsigned long s3c24xx_round_dclk_rate(struct clk
*clk
,
91 unsigned long div
= s3c24xx_calc_div(clk
, rate
);
96 return clk_get_rate(clk
->parent
) / div
;
99 static int s3c24xx_set_dclk_rate(struct clk
*clk
, unsigned long rate
)
101 unsigned long mask
, data
, div
= s3c24xx_calc_div(clk
, rate
);
106 if (clk
== &s3c24xx_dclk0
) {
107 mask
= S3C2410_DCLKCON_DCLK0_DIV_MASK
|
108 S3C2410_DCLKCON_DCLK0_CMP_MASK
;
109 data
= S3C2410_DCLKCON_DCLK0_DIV(div
) |
110 S3C2410_DCLKCON_DCLK0_CMP((div
+ 1) / 2);
111 } else if (clk
== &s3c24xx_dclk1
) {
112 mask
= S3C2410_DCLKCON_DCLK1_DIV_MASK
|
113 S3C2410_DCLKCON_DCLK1_CMP_MASK
;
114 data
= S3C2410_DCLKCON_DCLK1_DIV(div
) |
115 S3C2410_DCLKCON_DCLK1_CMP((div
+ 1) / 2);
119 clk
->rate
= clk_get_rate(clk
->parent
) / div
;
120 __raw_writel(((__raw_readl(S3C24XX_DCLKCON
) & ~mask
) | data
),
124 static int s3c24xx_clkout_setparent(struct clk
*clk
, struct clk
*parent
)
127 unsigned long source
;
129 /* calculate the MISCCR setting for the clock */
131 if (parent
== &clk_mpll
)
132 source
= S3C2410_MISCCR_CLK0_MPLL
;
133 else if (parent
== &clk_upll
)
134 source
= S3C2410_MISCCR_CLK0_UPLL
;
135 else if (parent
== &clk_f
)
136 source
= S3C2410_MISCCR_CLK0_FCLK
;
137 else if (parent
== &clk_h
)
138 source
= S3C2410_MISCCR_CLK0_HCLK
;
139 else if (parent
== &clk_p
)
140 source
= S3C2410_MISCCR_CLK0_PCLK
;
141 else if (clk
== &s3c24xx_clkout0
&& parent
== &s3c24xx_dclk0
)
142 source
= S3C2410_MISCCR_CLK0_DCLK0
;
143 else if (clk
== &s3c24xx_clkout1
&& parent
== &s3c24xx_dclk1
)
144 source
= S3C2410_MISCCR_CLK0_DCLK0
;
148 clk
->parent
= parent
;
150 if (clk
== &s3c24xx_clkout0
)
151 mask
= S3C2410_MISCCR_CLK0_MASK
;
154 mask
= S3C2410_MISCCR_CLK1_MASK
;
157 s3c2410_modify_misccr(mask
, source
);
161 /* external clock definitions */
163 static struct clk_ops dclk_ops
= {
164 .set_parent
= s3c24xx_dclk_setparent
,
165 .set_rate
= s3c24xx_set_dclk_rate
,
166 .round_rate
= s3c24xx_round_dclk_rate
,
169 struct clk s3c24xx_dclk0
= {
171 .ctrlbit
= S3C2410_DCLKCON_DCLK0EN
,
172 .enable
= s3c24xx_dclk_enable
,
176 struct clk s3c24xx_dclk1
= {
178 .ctrlbit
= S3C2410_DCLKCON_DCLK1EN
,
179 .enable
= s3c24xx_dclk_enable
,
183 static struct clk_ops clkout_ops
= {
184 .set_parent
= s3c24xx_clkout_setparent
,
187 struct clk s3c24xx_clkout0
= {
192 struct clk s3c24xx_clkout1
= {