1 /* linux/arch/arm/plat-samsung/clock-clksrc.c
3 * Copyright 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.
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/list.h>
16 #include <linux/errno.h>
17 #include <linux/err.h>
18 #include <linux/clk.h>
19 #include <linux/device.h>
22 #include <plat/clock.h>
23 #include <plat/clock-clksrc.h>
24 #include <plat/cpu-freq.h>
26 static inline struct clksrc_clk
*to_clksrc(struct clk
*clk
)
28 return container_of(clk
, struct clksrc_clk
, clk
);
31 static inline u32
bit_mask(u32 shift
, u32 nr_bits
)
33 u32 mask
= 0xffffffff >> (32 - nr_bits
);
38 static unsigned long s3c_getrate_clksrc(struct clk
*clk
)
40 struct clksrc_clk
*sclk
= to_clksrc(clk
);
41 unsigned long rate
= clk_get_rate(clk
->parent
);
42 u32 clkdiv
= __raw_readl(sclk
->reg_div
.reg
);
43 u32 mask
= bit_mask(sclk
->reg_div
.shift
, sclk
->reg_div
.size
);
46 clkdiv
>>= sclk
->reg_div
.shift
;
53 static int s3c_setrate_clksrc(struct clk
*clk
, unsigned long rate
)
55 struct clksrc_clk
*sclk
= to_clksrc(clk
);
56 void __iomem
*reg
= sclk
->reg_div
.reg
;
58 u32 mask
= bit_mask(sclk
->reg_div
.shift
, sclk
->reg_div
.size
);
61 rate
= clk_round_rate(clk
, rate
);
62 div
= clk_get_rate(clk
->parent
) / rate
;
63 if (div
> (1 << sclk
->reg_div
.size
))
66 val
= __raw_readl(reg
);
68 val
|= (div
- 1) << sclk
->reg_div
.shift
;
69 __raw_writel(val
, reg
);
74 static int s3c_setparent_clksrc(struct clk
*clk
, struct clk
*parent
)
76 struct clksrc_clk
*sclk
= to_clksrc(clk
);
77 struct clksrc_sources
*srcs
= sclk
->sources
;
78 u32 clksrc
= __raw_readl(sclk
->reg_src
.reg
);
79 u32 mask
= bit_mask(sclk
->reg_src
.shift
, sclk
->reg_src
.size
);
83 for (ptr
= 0; ptr
< srcs
->nr_sources
; ptr
++)
84 if (srcs
->sources
[ptr
] == parent
) {
93 clksrc
|= src_nr
<< sclk
->reg_src
.shift
;
95 __raw_writel(clksrc
, sclk
->reg_src
.reg
);
102 static unsigned long s3c_roundrate_clksrc(struct clk
*clk
,
105 struct clksrc_clk
*sclk
= to_clksrc(clk
);
106 unsigned long parent_rate
= clk_get_rate(clk
->parent
);
107 int max_div
= 1 << sclk
->reg_div
.size
;
110 if (rate
>= parent_rate
)
113 div
= parent_rate
/ rate
;
114 if (parent_rate
% rate
)
122 rate
= parent_rate
/ div
;
128 /* Clock initialisation code */
130 void __init_or_cpufreq
s3c_set_clksrc(struct clksrc_clk
*clk
, bool announce
)
132 struct clksrc_sources
*srcs
= clk
->sources
;
133 u32 mask
= bit_mask(clk
->reg_src
.shift
, clk
->reg_src
.size
);
136 if (!clk
->reg_src
.reg
) {
137 if (!clk
->clk
.parent
)
138 printk(KERN_ERR
"%s: no parent clock specified\n",
143 clksrc
= __raw_readl(clk
->reg_src
.reg
);
145 clksrc
>>= clk
->reg_src
.shift
;
147 if (clksrc
> srcs
->nr_sources
|| !srcs
->sources
[clksrc
]) {
148 printk(KERN_ERR
"%s: bad source %d\n",
149 clk
->clk
.name
, clksrc
);
153 clk
->clk
.parent
= srcs
->sources
[clksrc
];
156 printk(KERN_INFO
"%s: source is %s (%d), rate is %ld\n",
157 clk
->clk
.name
, clk
->clk
.parent
->name
, clksrc
,
158 clk_get_rate(&clk
->clk
));
161 static struct clk_ops clksrc_ops
= {
162 .set_parent
= s3c_setparent_clksrc
,
163 .get_rate
= s3c_getrate_clksrc
,
164 .set_rate
= s3c_setrate_clksrc
,
165 .round_rate
= s3c_roundrate_clksrc
,
168 static struct clk_ops clksrc_ops_nodiv
= {
169 .set_parent
= s3c_setparent_clksrc
,
172 static struct clk_ops clksrc_ops_nosrc
= {
173 .get_rate
= s3c_getrate_clksrc
,
174 .set_rate
= s3c_setrate_clksrc
,
175 .round_rate
= s3c_roundrate_clksrc
,
178 void __init
s3c_register_clksrc(struct clksrc_clk
*clksrc
, int size
)
182 for (; size
> 0; size
--, clksrc
++) {
183 if (!clksrc
->reg_div
.reg
&& !clksrc
->reg_src
.reg
)
184 printk(KERN_ERR
"%s: clock %s has no registers set\n",
185 __func__
, clksrc
->clk
.name
);
187 /* fill in the default functions */
189 if (!clksrc
->clk
.ops
) {
190 if (!clksrc
->reg_div
.reg
)
191 clksrc
->clk
.ops
= &clksrc_ops_nodiv
;
192 else if (!clksrc
->reg_src
.reg
)
193 clksrc
->clk
.ops
= &clksrc_ops_nosrc
;
195 clksrc
->clk
.ops
= &clksrc_ops
;
198 /* setup the clocksource, but do not announce it
199 * as it may be re-set by the setup routines
200 * called after the rest of the clocks have been
203 s3c_set_clksrc(clksrc
, false);
205 ret
= s3c24xx_register_clock(&clksrc
->clk
);
208 printk(KERN_ERR
"%s: failed to register %s (%d)\n",
209 __func__
, clksrc
->clk
.name
, ret
);