2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3 * Copyright (c) 2013 Linaro Ltd.
4 * Author: Thomas Abraham <thomas.ab@samsung.com>
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 * This file includes utility functions to register clocks to common
11 * clock framework for Samsung platforms.
14 #include <linux/of_address.h>
15 #include <linux/syscore_ops.h>
19 static LIST_HEAD(clock_reg_cache_list
);
21 void samsung_clk_save(void __iomem
*base
,
22 struct samsung_clk_reg_dump
*rd
,
23 unsigned int num_regs
)
25 for (; num_regs
> 0; --num_regs
, ++rd
)
26 rd
->value
= readl(base
+ rd
->offset
);
29 void samsung_clk_restore(void __iomem
*base
,
30 const struct samsung_clk_reg_dump
*rd
,
31 unsigned int num_regs
)
33 for (; num_regs
> 0; --num_regs
, ++rd
)
34 writel(rd
->value
, base
+ rd
->offset
);
37 struct samsung_clk_reg_dump
*samsung_clk_alloc_reg_dump(
38 const unsigned long *rdump
,
39 unsigned long nr_rdump
)
41 struct samsung_clk_reg_dump
*rd
;
44 rd
= kcalloc(nr_rdump
, sizeof(*rd
), GFP_KERNEL
);
48 for (i
= 0; i
< nr_rdump
; ++i
)
49 rd
[i
].offset
= rdump
[i
];
54 /* setup the essentials required to support clock lookup using ccf */
55 struct samsung_clk_provider
*__init
samsung_clk_init(struct device_node
*np
,
56 void __iomem
*base
, unsigned long nr_clks
)
58 struct samsung_clk_provider
*ctx
;
59 struct clk
**clk_table
;
62 ctx
= kzalloc(sizeof(struct samsung_clk_provider
), GFP_KERNEL
);
64 panic("could not allocate clock provider context.\n");
66 clk_table
= kcalloc(nr_clks
, sizeof(struct clk
*), GFP_KERNEL
);
68 panic("could not allocate clock lookup table\n");
70 for (i
= 0; i
< nr_clks
; ++i
)
71 clk_table
[i
] = ERR_PTR(-ENOENT
);
74 ctx
->clk_data
.clks
= clk_table
;
75 ctx
->clk_data
.clk_num
= nr_clks
;
76 spin_lock_init(&ctx
->lock
);
81 void __init
samsung_clk_of_add_provider(struct device_node
*np
,
82 struct samsung_clk_provider
*ctx
)
85 if (of_clk_add_provider(np
, of_clk_src_onecell_get
,
87 panic("could not register clk provider\n");
91 /* add a clock instance to the clock lookup table used for dt based lookup */
92 void samsung_clk_add_lookup(struct samsung_clk_provider
*ctx
, struct clk
*clk
,
95 if (ctx
->clk_data
.clks
&& id
)
96 ctx
->clk_data
.clks
[id
] = clk
;
99 /* register a list of aliases */
100 void __init
samsung_clk_register_alias(struct samsung_clk_provider
*ctx
,
101 struct samsung_clock_alias
*list
,
105 unsigned int idx
, ret
;
107 if (!ctx
->clk_data
.clks
) {
108 pr_err("%s: clock table missing\n", __func__
);
112 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
114 pr_err("%s: clock id missing for index %d\n", __func__
,
119 clk
= ctx
->clk_data
.clks
[list
->id
];
121 pr_err("%s: failed to find clock %d\n", __func__
,
126 ret
= clk_register_clkdev(clk
, list
->alias
, list
->dev_name
);
128 pr_err("%s: failed to register lookup %s\n",
129 __func__
, list
->alias
);
133 /* register a list of fixed clocks */
134 void __init
samsung_clk_register_fixed_rate(struct samsung_clk_provider
*ctx
,
135 struct samsung_fixed_rate_clock
*list
, unsigned int nr_clk
)
138 unsigned int idx
, ret
;
140 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
141 clk
= clk_register_fixed_rate(NULL
, list
->name
,
142 list
->parent_name
, list
->flags
, list
->fixed_rate
);
144 pr_err("%s: failed to register clock %s\n", __func__
,
149 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
152 * Unconditionally add a clock lookup for the fixed rate clocks.
153 * There are not many of these on any of Samsung platforms.
155 ret
= clk_register_clkdev(clk
, list
->name
, NULL
);
157 pr_err("%s: failed to register clock lookup for %s",
158 __func__
, list
->name
);
162 /* register a list of fixed factor clocks */
163 void __init
samsung_clk_register_fixed_factor(struct samsung_clk_provider
*ctx
,
164 struct samsung_fixed_factor_clock
*list
, unsigned int nr_clk
)
169 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
170 clk
= clk_register_fixed_factor(NULL
, list
->name
,
171 list
->parent_name
, list
->flags
, list
->mult
, list
->div
);
173 pr_err("%s: failed to register clock %s\n", __func__
,
178 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
182 /* register a list of mux clocks */
183 void __init
samsung_clk_register_mux(struct samsung_clk_provider
*ctx
,
184 struct samsung_mux_clock
*list
,
188 unsigned int idx
, ret
;
190 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
191 clk
= clk_register_mux(NULL
, list
->name
, list
->parent_names
,
192 list
->num_parents
, list
->flags
,
193 ctx
->reg_base
+ list
->offset
,
194 list
->shift
, list
->width
, list
->mux_flags
, &ctx
->lock
);
196 pr_err("%s: failed to register clock %s\n", __func__
,
201 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
203 /* register a clock lookup only if a clock alias is specified */
205 ret
= clk_register_clkdev(clk
, list
->alias
,
208 pr_err("%s: failed to register lookup %s\n",
209 __func__
, list
->alias
);
214 /* register a list of div clocks */
215 void __init
samsung_clk_register_div(struct samsung_clk_provider
*ctx
,
216 struct samsung_div_clock
*list
,
220 unsigned int idx
, ret
;
222 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
224 clk
= clk_register_divider_table(NULL
, list
->name
,
225 list
->parent_name
, list
->flags
,
226 ctx
->reg_base
+ list
->offset
,
227 list
->shift
, list
->width
, list
->div_flags
,
228 list
->table
, &ctx
->lock
);
230 clk
= clk_register_divider(NULL
, list
->name
,
231 list
->parent_name
, list
->flags
,
232 ctx
->reg_base
+ list
->offset
, list
->shift
,
233 list
->width
, list
->div_flags
, &ctx
->lock
);
235 pr_err("%s: failed to register clock %s\n", __func__
,
240 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
242 /* register a clock lookup only if a clock alias is specified */
244 ret
= clk_register_clkdev(clk
, list
->alias
,
247 pr_err("%s: failed to register lookup %s\n",
248 __func__
, list
->alias
);
253 /* register a list of gate clocks */
254 void __init
samsung_clk_register_gate(struct samsung_clk_provider
*ctx
,
255 struct samsung_gate_clock
*list
,
259 unsigned int idx
, ret
;
261 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
262 clk
= clk_register_gate(NULL
, list
->name
, list
->parent_name
,
263 list
->flags
, ctx
->reg_base
+ list
->offset
,
264 list
->bit_idx
, list
->gate_flags
, &ctx
->lock
);
266 pr_err("%s: failed to register clock %s\n", __func__
,
271 /* register a clock lookup only if a clock alias is specified */
273 ret
= clk_register_clkdev(clk
, list
->alias
,
276 pr_err("%s: failed to register lookup %s\n",
277 __func__
, list
->alias
);
280 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
285 * obtain the clock speed of all external fixed clock sources from device
286 * tree and register it
288 void __init
samsung_clk_of_register_fixed_ext(struct samsung_clk_provider
*ctx
,
289 struct samsung_fixed_rate_clock
*fixed_rate_clk
,
290 unsigned int nr_fixed_rate_clk
,
291 const struct of_device_id
*clk_matches
)
293 const struct of_device_id
*match
;
294 struct device_node
*clk_np
;
297 for_each_matching_node_and_match(clk_np
, clk_matches
, &match
) {
298 if (of_property_read_u32(clk_np
, "clock-frequency", &freq
))
300 fixed_rate_clk
[(unsigned long)match
->data
].fixed_rate
= freq
;
302 samsung_clk_register_fixed_rate(ctx
, fixed_rate_clk
, nr_fixed_rate_clk
);
305 /* utility function to get the rate of a specified clock */
306 unsigned long _get_rate(const char *clk_name
)
310 clk
= __clk_lookup(clk_name
);
312 pr_err("%s: could not find clock %s\n", __func__
, clk_name
);
316 return clk_get_rate(clk
);
319 #ifdef CONFIG_PM_SLEEP
320 static int samsung_clk_suspend(void)
322 struct samsung_clock_reg_cache
*reg_cache
;
324 list_for_each_entry(reg_cache
, &clock_reg_cache_list
, node
)
325 samsung_clk_save(reg_cache
->reg_base
, reg_cache
->rdump
,
330 static void samsung_clk_resume(void)
332 struct samsung_clock_reg_cache
*reg_cache
;
334 list_for_each_entry(reg_cache
, &clock_reg_cache_list
, node
)
335 samsung_clk_restore(reg_cache
->reg_base
, reg_cache
->rdump
,
339 static struct syscore_ops samsung_clk_syscore_ops
= {
340 .suspend
= samsung_clk_suspend
,
341 .resume
= samsung_clk_resume
,
344 static void samsung_clk_sleep_init(void __iomem
*reg_base
,
345 const unsigned long *rdump
,
346 unsigned long nr_rdump
)
348 struct samsung_clock_reg_cache
*reg_cache
;
350 reg_cache
= kzalloc(sizeof(struct samsung_clock_reg_cache
),
353 panic("could not allocate register reg_cache.\n");
354 reg_cache
->rdump
= samsung_clk_alloc_reg_dump(rdump
, nr_rdump
);
356 if (!reg_cache
->rdump
)
357 panic("could not allocate register dump storage.\n");
359 if (list_empty(&clock_reg_cache_list
))
360 register_syscore_ops(&samsung_clk_syscore_ops
);
362 reg_cache
->reg_base
= reg_base
;
363 reg_cache
->rd_num
= nr_rdump
;
364 list_add_tail(®_cache
->node
, &clock_reg_cache_list
);
368 static void samsung_clk_sleep_init(void __iomem
*reg_base
,
369 const unsigned long *rdump
,
370 unsigned long nr_rdump
) {}
374 * Common function which registers plls, muxes, dividers and gates
375 * for each CMU. It also add CMU register list to register cache.
377 struct samsung_clk_provider
* __init
samsung_cmu_register_one(
378 struct device_node
*np
,
379 struct samsung_cmu_info
*cmu
)
381 void __iomem
*reg_base
;
382 struct samsung_clk_provider
*ctx
;
384 reg_base
= of_iomap(np
, 0);
386 panic("%s: failed to map registers\n", __func__
);
390 ctx
= samsung_clk_init(np
, reg_base
, cmu
->nr_clk_ids
);
392 panic("%s: unable to alllocate ctx\n", __func__
);
397 samsung_clk_register_pll(ctx
, cmu
->pll_clks
, cmu
->nr_pll_clks
,
400 samsung_clk_register_mux(ctx
, cmu
->mux_clks
,
403 samsung_clk_register_div(ctx
, cmu
->div_clks
, cmu
->nr_div_clks
);
405 samsung_clk_register_gate(ctx
, cmu
->gate_clks
,
408 samsung_clk_register_fixed_rate(ctx
, cmu
->fixed_clks
,
410 if (cmu
->fixed_factor_clks
)
411 samsung_clk_register_fixed_factor(ctx
, cmu
->fixed_factor_clks
,
412 cmu
->nr_fixed_factor_clks
);
414 samsung_clk_sleep_init(reg_base
, cmu
->clk_regs
,
417 samsung_clk_of_add_provider(np
, ctx
);