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/slab.h>
15 #include <linux/clkdev.h>
16 #include <linux/clk.h>
17 #include <linux/clk-provider.h>
18 #include <linux/of_address.h>
19 #include <linux/syscore_ops.h>
23 static LIST_HEAD(clock_reg_cache_list
);
25 void samsung_clk_save(void __iomem
*base
,
26 struct samsung_clk_reg_dump
*rd
,
27 unsigned int num_regs
)
29 for (; num_regs
> 0; --num_regs
, ++rd
)
30 rd
->value
= readl(base
+ rd
->offset
);
33 void samsung_clk_restore(void __iomem
*base
,
34 const struct samsung_clk_reg_dump
*rd
,
35 unsigned int num_regs
)
37 for (; num_regs
> 0; --num_regs
, ++rd
)
38 writel(rd
->value
, base
+ rd
->offset
);
41 struct samsung_clk_reg_dump
*samsung_clk_alloc_reg_dump(
42 const unsigned long *rdump
,
43 unsigned long nr_rdump
)
45 struct samsung_clk_reg_dump
*rd
;
48 rd
= kcalloc(nr_rdump
, sizeof(*rd
), GFP_KERNEL
);
52 for (i
= 0; i
< nr_rdump
; ++i
)
53 rd
[i
].offset
= rdump
[i
];
58 /* setup the essentials required to support clock lookup using ccf */
59 struct samsung_clk_provider
*__init
samsung_clk_init(struct device_node
*np
,
60 void __iomem
*base
, unsigned long nr_clks
)
62 struct samsung_clk_provider
*ctx
;
65 ctx
= kzalloc(sizeof(struct samsung_clk_provider
) +
66 sizeof(*ctx
->clk_data
.hws
) * nr_clks
, GFP_KERNEL
);
68 panic("could not allocate clock provider context.\n");
70 for (i
= 0; i
< nr_clks
; ++i
)
71 ctx
->clk_data
.hws
[i
] = ERR_PTR(-ENOENT
);
74 ctx
->clk_data
.num
= nr_clks
;
75 spin_lock_init(&ctx
->lock
);
80 void __init
samsung_clk_of_add_provider(struct device_node
*np
,
81 struct samsung_clk_provider
*ctx
)
84 if (of_clk_add_hw_provider(np
, of_clk_hw_onecell_get
,
86 panic("could not register clk provider\n");
90 /* add a clock instance to the clock lookup table used for dt based lookup */
91 void samsung_clk_add_lookup(struct samsung_clk_provider
*ctx
,
92 struct clk_hw
*clk_hw
, unsigned int id
)
95 ctx
->clk_data
.hws
[id
] = clk_hw
;
98 /* register a list of aliases */
99 void __init
samsung_clk_register_alias(struct samsung_clk_provider
*ctx
,
100 const struct samsung_clock_alias
*list
,
103 struct clk_hw
*clk_hw
;
104 unsigned int idx
, ret
;
106 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
108 pr_err("%s: clock id missing for index %d\n", __func__
,
113 clk_hw
= ctx
->clk_data
.hws
[list
->id
];
115 pr_err("%s: failed to find clock %d\n", __func__
,
120 ret
= clk_hw_register_clkdev(clk_hw
, list
->alias
,
123 pr_err("%s: failed to register lookup %s\n",
124 __func__
, list
->alias
);
128 /* register a list of fixed clocks */
129 void __init
samsung_clk_register_fixed_rate(struct samsung_clk_provider
*ctx
,
130 const struct samsung_fixed_rate_clock
*list
,
133 struct clk_hw
*clk_hw
;
134 unsigned int idx
, ret
;
136 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
137 clk_hw
= clk_hw_register_fixed_rate(ctx
->dev
, list
->name
,
138 list
->parent_name
, list
->flags
, list
->fixed_rate
);
139 if (IS_ERR(clk_hw
)) {
140 pr_err("%s: failed to register clock %s\n", __func__
,
145 samsung_clk_add_lookup(ctx
, clk_hw
, list
->id
);
148 * Unconditionally add a clock lookup for the fixed rate clocks.
149 * There are not many of these on any of Samsung platforms.
151 ret
= clk_hw_register_clkdev(clk_hw
, list
->name
, NULL
);
153 pr_err("%s: failed to register clock lookup for %s",
154 __func__
, list
->name
);
158 /* register a list of fixed factor clocks */
159 void __init
samsung_clk_register_fixed_factor(struct samsung_clk_provider
*ctx
,
160 const struct samsung_fixed_factor_clock
*list
, unsigned int nr_clk
)
162 struct clk_hw
*clk_hw
;
165 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
166 clk_hw
= clk_hw_register_fixed_factor(ctx
->dev
, list
->name
,
167 list
->parent_name
, list
->flags
, list
->mult
, list
->div
);
168 if (IS_ERR(clk_hw
)) {
169 pr_err("%s: failed to register clock %s\n", __func__
,
174 samsung_clk_add_lookup(ctx
, clk_hw
, list
->id
);
178 /* register a list of mux clocks */
179 void __init
samsung_clk_register_mux(struct samsung_clk_provider
*ctx
,
180 const struct samsung_mux_clock
*list
,
183 struct clk_hw
*clk_hw
;
186 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
187 clk_hw
= clk_hw_register_mux(ctx
->dev
, list
->name
,
188 list
->parent_names
, list
->num_parents
, list
->flags
,
189 ctx
->reg_base
+ list
->offset
,
190 list
->shift
, list
->width
, list
->mux_flags
, &ctx
->lock
);
191 if (IS_ERR(clk_hw
)) {
192 pr_err("%s: failed to register clock %s\n", __func__
,
197 samsung_clk_add_lookup(ctx
, clk_hw
, list
->id
);
201 /* register a list of div clocks */
202 void __init
samsung_clk_register_div(struct samsung_clk_provider
*ctx
,
203 const struct samsung_div_clock
*list
,
206 struct clk_hw
*clk_hw
;
209 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
211 clk_hw
= clk_hw_register_divider_table(ctx
->dev
,
212 list
->name
, list
->parent_name
, list
->flags
,
213 ctx
->reg_base
+ list
->offset
,
214 list
->shift
, list
->width
, list
->div_flags
,
215 list
->table
, &ctx
->lock
);
217 clk_hw
= clk_hw_register_divider(ctx
->dev
, list
->name
,
218 list
->parent_name
, list
->flags
,
219 ctx
->reg_base
+ list
->offset
, list
->shift
,
220 list
->width
, list
->div_flags
, &ctx
->lock
);
221 if (IS_ERR(clk_hw
)) {
222 pr_err("%s: failed to register clock %s\n", __func__
,
227 samsung_clk_add_lookup(ctx
, clk_hw
, list
->id
);
231 /* register a list of gate clocks */
232 void __init
samsung_clk_register_gate(struct samsung_clk_provider
*ctx
,
233 const struct samsung_gate_clock
*list
,
236 struct clk_hw
*clk_hw
;
239 for (idx
= 0; idx
< nr_clk
; idx
++, list
++) {
240 clk_hw
= clk_hw_register_gate(ctx
->dev
, list
->name
, list
->parent_name
,
241 list
->flags
, ctx
->reg_base
+ list
->offset
,
242 list
->bit_idx
, list
->gate_flags
, &ctx
->lock
);
243 if (IS_ERR(clk_hw
)) {
244 pr_err("%s: failed to register clock %s\n", __func__
,
249 samsung_clk_add_lookup(ctx
, clk_hw
, list
->id
);
254 * obtain the clock speed of all external fixed clock sources from device
255 * tree and register it
257 void __init
samsung_clk_of_register_fixed_ext(struct samsung_clk_provider
*ctx
,
258 struct samsung_fixed_rate_clock
*fixed_rate_clk
,
259 unsigned int nr_fixed_rate_clk
,
260 const struct of_device_id
*clk_matches
)
262 const struct of_device_id
*match
;
263 struct device_node
*clk_np
;
266 for_each_matching_node_and_match(clk_np
, clk_matches
, &match
) {
267 if (of_property_read_u32(clk_np
, "clock-frequency", &freq
))
269 fixed_rate_clk
[(unsigned long)match
->data
].fixed_rate
= freq
;
271 samsung_clk_register_fixed_rate(ctx
, fixed_rate_clk
, nr_fixed_rate_clk
);
274 /* utility function to get the rate of a specified clock */
275 unsigned long _get_rate(const char *clk_name
)
279 clk
= __clk_lookup(clk_name
);
281 pr_err("%s: could not find clock %s\n", __func__
, clk_name
);
285 return clk_get_rate(clk
);
288 #ifdef CONFIG_PM_SLEEP
289 static int samsung_clk_suspend(void)
291 struct samsung_clock_reg_cache
*reg_cache
;
293 list_for_each_entry(reg_cache
, &clock_reg_cache_list
, node
)
294 samsung_clk_save(reg_cache
->reg_base
, reg_cache
->rdump
,
299 static void samsung_clk_resume(void)
301 struct samsung_clock_reg_cache
*reg_cache
;
303 list_for_each_entry(reg_cache
, &clock_reg_cache_list
, node
)
304 samsung_clk_restore(reg_cache
->reg_base
, reg_cache
->rdump
,
308 static struct syscore_ops samsung_clk_syscore_ops
= {
309 .suspend
= samsung_clk_suspend
,
310 .resume
= samsung_clk_resume
,
313 void samsung_clk_sleep_init(void __iomem
*reg_base
,
314 const unsigned long *rdump
,
315 unsigned long nr_rdump
)
317 struct samsung_clock_reg_cache
*reg_cache
;
319 reg_cache
= kzalloc(sizeof(struct samsung_clock_reg_cache
),
322 panic("could not allocate register reg_cache.\n");
323 reg_cache
->rdump
= samsung_clk_alloc_reg_dump(rdump
, nr_rdump
);
325 if (!reg_cache
->rdump
)
326 panic("could not allocate register dump storage.\n");
328 if (list_empty(&clock_reg_cache_list
))
329 register_syscore_ops(&samsung_clk_syscore_ops
);
331 reg_cache
->reg_base
= reg_base
;
332 reg_cache
->rd_num
= nr_rdump
;
333 list_add_tail(®_cache
->node
, &clock_reg_cache_list
);
337 void samsung_clk_sleep_init(void __iomem
*reg_base
,
338 const unsigned long *rdump
,
339 unsigned long nr_rdump
) {}
343 * Common function which registers plls, muxes, dividers and gates
344 * for each CMU. It also add CMU register list to register cache.
346 struct samsung_clk_provider
* __init
samsung_cmu_register_one(
347 struct device_node
*np
,
348 const struct samsung_cmu_info
*cmu
)
350 void __iomem
*reg_base
;
351 struct samsung_clk_provider
*ctx
;
353 reg_base
= of_iomap(np
, 0);
355 panic("%s: failed to map registers\n", __func__
);
359 ctx
= samsung_clk_init(np
, reg_base
, cmu
->nr_clk_ids
);
361 panic("%s: unable to allocate ctx\n", __func__
);
366 samsung_clk_register_pll(ctx
, cmu
->pll_clks
, cmu
->nr_pll_clks
,
369 samsung_clk_register_mux(ctx
, cmu
->mux_clks
,
372 samsung_clk_register_div(ctx
, cmu
->div_clks
, cmu
->nr_div_clks
);
374 samsung_clk_register_gate(ctx
, cmu
->gate_clks
,
377 samsung_clk_register_fixed_rate(ctx
, cmu
->fixed_clks
,
379 if (cmu
->fixed_factor_clks
)
380 samsung_clk_register_fixed_factor(ctx
, cmu
->fixed_factor_clks
,
381 cmu
->nr_fixed_factor_clks
);
383 samsung_clk_sleep_init(reg_base
, cmu
->clk_regs
,
386 samsung_clk_of_add_provider(np
, ctx
);