17 #include <linux/kernel.h>
18 #include <linux/slab.h>
26 #define HB_PLL_LOCK_500 0x20000000
27 #define HB_PLL_LOCK 0x10000000
28 #define HB_PLL_DIVF_SHIFT 20
29 #define HB_PLL_DIVF_MASK 0x0ff00000
30 #define HB_PLL_DIVQ_SHIFT 16
31 #define HB_PLL_DIVQ_MASK 0x00070000
32 #define HB_PLL_DIVR_SHIFT 8
33 #define HB_PLL_DIVR_MASK 0x00001f00
34 #define HB_PLL_RANGE_SHIFT 4
35 #define HB_PLL_RANGE_MASK 0x00000070
36 #define HB_PLL_BYPASS 0x00000008
37 #define HB_PLL_RESET 0x00000004
38 #define HB_PLL_EXT_BYPASS 0x00000002
39 #define HB_PLL_EXT_ENA 0x00000001
41 #define HB_PLL_VCO_MIN_FREQ 2133000000
42 #define HB_PLL_MAX_FREQ HB_PLL_VCO_MIN_FREQ
43 #define HB_PLL_MIN_FREQ (HB_PLL_VCO_MIN_FREQ / 64)
45 #define HB_A9_BCLK_DIV_MASK 0x00000006
46 #define HB_A9_BCLK_DIV_SHIFT 1
47 #define HB_A9_PCLK_DIV 0x00000001
54 #define to_hb_clk(p) container_of(p, struct hb_clk, hw)
56 static int clk_pll_prepare(
struct clk_hw *hwclk)
73 static void clk_pll_unprepare(
struct clk_hw *hwclk)
83 static int clk_pll_enable(
struct clk_hw *hwclk)
95 static void clk_pll_disable(
struct clk_hw *hwclk)
105 static unsigned long clk_pll_recalc_rate(
struct clk_hw *hwclk,
106 unsigned long parent_rate)
109 unsigned long divf, divq, vco_freq,
reg;
117 vco_freq = parent_rate * (divf + 1);
119 return vco_freq / (1 << divq);
122 static void clk_pll_calc(
unsigned long rate,
unsigned long ref_freq,
126 unsigned long vco_freq;
133 for (divq = 1; divq <= 6; divq++) {
138 vco_freq = rate * (1 << divq);
139 divf = (vco_freq + (ref_freq / 2)) / ref_freq;
146 static long clk_pll_round_rate(
struct clk_hw *hwclk,
unsigned long rate,
147 unsigned long *parent_rate)
150 unsigned long ref_freq = *parent_rate;
152 clk_pll_calc(rate, ref_freq, &divq, &divf);
154 return (ref_freq * (divf + 1)) / (1 << divq);
157 static int clk_pll_set_rate(
struct clk_hw *hwclk,
unsigned long rate,
158 unsigned long parent_rate)
164 clk_pll_calc(rate, parent_rate, &divq, &divf);
193 static const struct clk_ops clk_pll_ops = {
194 .prepare = clk_pll_prepare,
195 .unprepare = clk_pll_unprepare,
196 .enable = clk_pll_enable,
197 .disable = clk_pll_disable,
198 .recalc_rate = clk_pll_recalc_rate,
199 .round_rate = clk_pll_round_rate,
200 .set_rate = clk_pll_set_rate,
203 static unsigned long clk_cpu_periphclk_recalc_rate(
struct clk_hw *hwclk,
204 unsigned long parent_rate)
208 return parent_rate /
div;
211 static const struct clk_ops a9periphclk_ops = {
212 .recalc_rate = clk_cpu_periphclk_recalc_rate,
215 static unsigned long clk_cpu_a9bclk_recalc_rate(
struct clk_hw *hwclk,
216 unsigned long parent_rate)
221 return parent_rate / (div + 2);
224 static const struct clk_ops a9bclk_ops = {
225 .recalc_rate = clk_cpu_a9bclk_recalc_rate,
228 static unsigned long clk_periclk_recalc_rate(
struct clk_hw *hwclk,
229 unsigned long parent_rate)
238 return parent_rate /
div;
241 static long clk_periclk_round_rate(
struct clk_hw *hwclk,
unsigned long rate,
242 unsigned long *parent_rate)
246 div = *parent_rate /
rate;
250 return *parent_rate /
div;
253 static int clk_periclk_set_rate(
struct clk_hw *hwclk,
unsigned long rate,
254 unsigned long parent_rate)
259 div = parent_rate /
rate;
267 static const struct clk_ops periclk_ops = {
268 .recalc_rate = clk_periclk_recalc_rate,
269 .round_rate = clk_periclk_round_rate,
270 .set_rate = clk_periclk_set_rate,
278 const char *clk_name = node->
name;
280 struct clk_init_data
init;
283 rc = of_property_read_u32(node,
"reg", ®);
287 hb_clk = kzalloc(
sizeof(*hb_clk),
GFP_KERNEL);
295 init.name = clk_name;
298 parent_name = of_clk_get_parent_name(node, 0);
299 init.parent_names = &parent_name;
300 init.num_parents = 1;
309 rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
315 hb_clk_init(node, &clk_pll_ops);
320 hb_clk_init(node, &a9periphclk_ops);
325 struct clk *clk = hb_clk_init(node, &a9bclk_ops);
326 clk_prepare_enable(clk);
331 hb_clk_init(node, &periclk_ops);
335 { .compatible =
"fixed-clock", .data = of_fixed_clk_setup, },
336 { .compatible =
"calxeda,hb-pll-clock", .data = hb_pll_init, },
337 { .compatible =
"calxeda,hb-a9periph-clock", .data = hb_a9periph_init, },
338 { .compatible =
"calxeda,hb-a9bus-clock", .data = hb_a9bus_init, },
339 { .compatible =
"calxeda,hb-emmc-clock", .data = hb_emmc_init, },
345 of_clk_init(clk_match);