1 /* linux/arch/arm/plat-s3c24xx/clock-dclk.c
3 * Copyright (c) 2004-2008 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 * http://armlinux.simtec.co.uk/
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * S3C24XX - definitions for DCLK and CLKOUT registers
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
16 #include <linux/clk.h>
19 #include <mach/regs-clock.h>
20 #include <mach/regs-gpio.h>
22 #include <plat/clock.h>
25 /* clocks that could be registered by external code */
27 static int s3c24xx_dclk_enable(struct clk
*clk
, int enable
)
29 unsigned long dclkcon
= __raw_readl(S3C24XX_DCLKCON
);
32 dclkcon
|= clk
->ctrlbit
;
34 dclkcon
&= ~clk
->ctrlbit
;
36 __raw_writel(dclkcon
, S3C24XX_DCLKCON
);
41 static int s3c24xx_dclk_setparent(struct clk
*clk
, struct clk
*parent
)
43 unsigned long dclkcon
;
46 if (parent
== &clk_upll
)
48 else if (parent
== &clk_p
)
55 dclkcon
= __raw_readl(S3C24XX_DCLKCON
);
57 if (clk
->ctrlbit
== S3C2410_DCLKCON_DCLK0EN
) {
59 dclkcon
|= S3C2410_DCLKCON_DCLK0_UCLK
;
61 dclkcon
&= ~S3C2410_DCLKCON_DCLK0_UCLK
;
64 dclkcon
|= S3C2410_DCLKCON_DCLK1_UCLK
;
66 dclkcon
&= ~S3C2410_DCLKCON_DCLK1_UCLK
;
69 __raw_writel(dclkcon
, S3C24XX_DCLKCON
);
73 static unsigned long s3c24xx_calc_div(struct clk
*clk
, unsigned long rate
)
77 if ((rate
== 0) || !clk
->parent
)
80 div
= clk_get_rate(clk
->parent
) / rate
;
89 static unsigned long s3c24xx_round_dclk_rate(struct clk
*clk
,
92 unsigned long div
= s3c24xx_calc_div(clk
, rate
);
97 return clk_get_rate(clk
->parent
) / div
;
100 static int s3c24xx_set_dclk_rate(struct clk
*clk
, unsigned long rate
)
102 unsigned long mask
, data
, div
= s3c24xx_calc_div(clk
, rate
);
107 if (clk
== &s3c24xx_dclk0
) {
108 mask
= S3C2410_DCLKCON_DCLK0_DIV_MASK
|
109 S3C2410_DCLKCON_DCLK0_CMP_MASK
;
110 data
= S3C2410_DCLKCON_DCLK0_DIV(div
) |
111 S3C2410_DCLKCON_DCLK0_CMP((div
+ 1) / 2);
112 } else if (clk
== &s3c24xx_dclk1
) {
113 mask
= S3C2410_DCLKCON_DCLK1_DIV_MASK
|
114 S3C2410_DCLKCON_DCLK1_CMP_MASK
;
115 data
= S3C2410_DCLKCON_DCLK1_DIV(div
) |
116 S3C2410_DCLKCON_DCLK1_CMP((div
+ 1) / 2);
120 clk
->rate
= clk_get_rate(clk
->parent
) / div
;
121 __raw_writel(((__raw_readl(S3C24XX_DCLKCON
) & ~mask
) | data
),
125 static int s3c24xx_clkout_setparent(struct clk
*clk
, struct clk
*parent
)
128 unsigned long source
;
130 /* calculate the MISCCR setting for the clock */
132 if (parent
== &clk_mpll
)
133 source
= S3C2410_MISCCR_CLK0_MPLL
;
134 else if (parent
== &clk_upll
)
135 source
= S3C2410_MISCCR_CLK0_UPLL
;
136 else if (parent
== &clk_f
)
137 source
= S3C2410_MISCCR_CLK0_FCLK
;
138 else if (parent
== &clk_h
)
139 source
= S3C2410_MISCCR_CLK0_HCLK
;
140 else if (parent
== &clk_p
)
141 source
= S3C2410_MISCCR_CLK0_PCLK
;
142 else if (clk
== &s3c24xx_clkout0
&& parent
== &s3c24xx_dclk0
)
143 source
= S3C2410_MISCCR_CLK0_DCLK0
;
144 else if (clk
== &s3c24xx_clkout1
&& parent
== &s3c24xx_dclk1
)
145 source
= S3C2410_MISCCR_CLK0_DCLK0
;
149 clk
->parent
= parent
;
151 if (clk
== &s3c24xx_clkout0
)
152 mask
= S3C2410_MISCCR_CLK0_MASK
;
155 mask
= S3C2410_MISCCR_CLK1_MASK
;
158 s3c2410_modify_misccr(mask
, source
);
162 /* external clock definitions */
164 static struct clk_ops dclk_ops
= {
165 .set_parent
= s3c24xx_dclk_setparent
,
166 .set_rate
= s3c24xx_set_dclk_rate
,
167 .round_rate
= s3c24xx_round_dclk_rate
,
170 struct clk s3c24xx_dclk0
= {
173 .ctrlbit
= S3C2410_DCLKCON_DCLK0EN
,
174 .enable
= s3c24xx_dclk_enable
,
178 struct clk s3c24xx_dclk1
= {
181 .ctrlbit
= S3C2410_DCLKCON_DCLK1EN
,
182 .enable
= s3c24xx_dclk_enable
,
186 static struct clk_ops clkout_ops
= {
187 .set_parent
= s3c24xx_clkout_setparent
,
190 struct clk s3c24xx_clkout0
= {
196 struct clk s3c24xx_clkout1
= {