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 const 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 const struct samsung_fixed_rate_clock
*list
,
139 unsigned int idx
, ret
;
141 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
142 clk
= clk_register_fixed_rate(NULL
, list
->name
,
143 list
->parent_name
, list
->flags
, list
->fixed_rate
);
145 pr_err("%s: failed to register clock %s\n", __func__
,
150 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
153 * Unconditionally add a clock lookup for the fixed rate clocks.
154 * There are not many of these on any of Samsung platforms.
156 ret
= clk_register_clkdev(clk
, list
->name
, NULL
);
158 pr_err("%s: failed to register clock lookup for %s",
159 __func__
, list
->name
);
163 /* register a list of fixed factor clocks */
164 void __init
samsung_clk_register_fixed_factor(struct samsung_clk_provider
*ctx
,
165 const struct samsung_fixed_factor_clock
*list
, unsigned int nr_clk
)
170 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
171 clk
= clk_register_fixed_factor(NULL
, list
->name
,
172 list
->parent_name
, list
->flags
, list
->mult
, list
->div
);
174 pr_err("%s: failed to register clock %s\n", __func__
,
179 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
183 /* register a list of mux clocks */
184 void __init
samsung_clk_register_mux(struct samsung_clk_provider
*ctx
,
185 const struct samsung_mux_clock
*list
,
189 unsigned int idx
, ret
;
191 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
192 clk
= clk_register_mux(NULL
, list
->name
, list
->parent_names
,
193 list
->num_parents
, list
->flags
,
194 ctx
->reg_base
+ list
->offset
,
195 list
->shift
, list
->width
, list
->mux_flags
, &ctx
->lock
);
197 pr_err("%s: failed to register clock %s\n", __func__
,
202 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
204 /* register a clock lookup only if a clock alias is specified */
206 ret
= clk_register_clkdev(clk
, list
->alias
,
209 pr_err("%s: failed to register lookup %s\n",
210 __func__
, list
->alias
);
215 /* register a list of div clocks */
216 void __init
samsung_clk_register_div(struct samsung_clk_provider
*ctx
,
217 const struct samsung_div_clock
*list
,
221 unsigned int idx
, ret
;
223 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
225 clk
= clk_register_divider_table(NULL
, list
->name
,
226 list
->parent_name
, list
->flags
,
227 ctx
->reg_base
+ list
->offset
,
228 list
->shift
, list
->width
, list
->div_flags
,
229 list
->table
, &ctx
->lock
);
231 clk
= clk_register_divider(NULL
, list
->name
,
232 list
->parent_name
, list
->flags
,
233 ctx
->reg_base
+ list
->offset
, list
->shift
,
234 list
->width
, list
->div_flags
, &ctx
->lock
);
236 pr_err("%s: failed to register clock %s\n", __func__
,
241 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
243 /* register a clock lookup only if a clock alias is specified */
245 ret
= clk_register_clkdev(clk
, list
->alias
,
248 pr_err("%s: failed to register lookup %s\n",
249 __func__
, list
->alias
);
254 /* register a list of gate clocks */
255 void __init
samsung_clk_register_gate(struct samsung_clk_provider
*ctx
,
256 const struct samsung_gate_clock
*list
,
260 unsigned int idx
, ret
;
262 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
263 clk
= clk_register_gate(NULL
, list
->name
, list
->parent_name
,
264 list
->flags
, ctx
->reg_base
+ list
->offset
,
265 list
->bit_idx
, list
->gate_flags
, &ctx
->lock
);
267 pr_err("%s: failed to register clock %s\n", __func__
,
272 /* register a clock lookup only if a clock alias is specified */
274 ret
= clk_register_clkdev(clk
, list
->alias
,
277 pr_err("%s: failed to register lookup %s\n",
278 __func__
, list
->alias
);
281 samsung_clk_add_lookup(ctx
, clk
, list
->id
);
286 * obtain the clock speed of all external fixed clock sources from device
287 * tree and register it
289 void __init
samsung_clk_of_register_fixed_ext(struct samsung_clk_provider
*ctx
,
290 struct samsung_fixed_rate_clock
*fixed_rate_clk
,
291 unsigned int nr_fixed_rate_clk
,
292 const struct of_device_id
*clk_matches
)
294 const struct of_device_id
*match
;
295 struct device_node
*clk_np
;
298 for_each_matching_node_and_match(clk_np
, clk_matches
, &match
) {
299 if (of_property_read_u32(clk_np
, "clock-frequency", &freq
))
301 fixed_rate_clk
[(unsigned long)match
->data
].fixed_rate
= freq
;
303 samsung_clk_register_fixed_rate(ctx
, fixed_rate_clk
, nr_fixed_rate_clk
);
306 /* utility function to get the rate of a specified clock */
307 unsigned long _get_rate(const char *clk_name
)
311 clk
= __clk_lookup(clk_name
);
313 pr_err("%s: could not find clock %s\n", __func__
, clk_name
);
317 return clk_get_rate(clk
);
320 #ifdef CONFIG_PM_SLEEP
321 static int samsung_clk_suspend(void)
323 struct samsung_clock_reg_cache
*reg_cache
;
325 list_for_each_entry(reg_cache
, &clock_reg_cache_list
, node
)
326 samsung_clk_save(reg_cache
->reg_base
, reg_cache
->rdump
,
331 static void samsung_clk_resume(void)
333 struct samsung_clock_reg_cache
*reg_cache
;
335 list_for_each_entry(reg_cache
, &clock_reg_cache_list
, node
)
336 samsung_clk_restore(reg_cache
->reg_base
, reg_cache
->rdump
,
340 static struct syscore_ops samsung_clk_syscore_ops
= {
341 .suspend
= samsung_clk_suspend
,
342 .resume
= samsung_clk_resume
,
345 static void samsung_clk_sleep_init(void __iomem
*reg_base
,
346 const unsigned long *rdump
,
347 unsigned long nr_rdump
)
349 struct samsung_clock_reg_cache
*reg_cache
;
351 reg_cache
= kzalloc(sizeof(struct samsung_clock_reg_cache
),
354 panic("could not allocate register reg_cache.\n");
355 reg_cache
->rdump
= samsung_clk_alloc_reg_dump(rdump
, nr_rdump
);
357 if (!reg_cache
->rdump
)
358 panic("could not allocate register dump storage.\n");
360 if (list_empty(&clock_reg_cache_list
))
361 register_syscore_ops(&samsung_clk_syscore_ops
);
363 reg_cache
->reg_base
= reg_base
;
364 reg_cache
->rd_num
= nr_rdump
;
365 list_add_tail(®_cache
->node
, &clock_reg_cache_list
);
369 static void samsung_clk_sleep_init(void __iomem
*reg_base
,
370 const unsigned long *rdump
,
371 unsigned long nr_rdump
) {}
375 * Common function which registers plls, muxes, dividers and gates
376 * for each CMU. It also add CMU register list to register cache.
378 struct samsung_clk_provider
* __init
samsung_cmu_register_one(
379 struct device_node
*np
,
380 struct samsung_cmu_info
*cmu
)
382 void __iomem
*reg_base
;
383 struct samsung_clk_provider
*ctx
;
385 reg_base
= of_iomap(np
, 0);
387 panic("%s: failed to map registers\n", __func__
);
391 ctx
= samsung_clk_init(np
, reg_base
, cmu
->nr_clk_ids
);
393 panic("%s: unable to allocate ctx\n", __func__
);
398 samsung_clk_register_pll(ctx
, cmu
->pll_clks
, cmu
->nr_pll_clks
,
401 samsung_clk_register_mux(ctx
, cmu
->mux_clks
,
404 samsung_clk_register_div(ctx
, cmu
->div_clks
, cmu
->nr_div_clks
);
406 samsung_clk_register_gate(ctx
, cmu
->gate_clks
,
409 samsung_clk_register_fixed_rate(ctx
, cmu
->fixed_clks
,
411 if (cmu
->fixed_factor_clks
)
412 samsung_clk_register_fixed_factor(ctx
, cmu
->fixed_factor_clks
,
413 cmu
->nr_fixed_factor_clks
);
415 samsung_clk_sleep_init(reg_base
, cmu
->clk_regs
,
418 samsung_clk_of_add_provider(np
, ctx
);