blob: a64823627d3a00588d20c164e12dab569b935a8c [file] [log] [blame]
Thomas Abraham721c42a2013-03-09 17:02:44 +09001/*
2 * Copyright (c) 2013 Samsung Electronics Co., Ltd.
3 * Copyright (c) 2013 Linaro Ltd.
4 * Author: Thomas Abraham <thomas.ab@samsung.com>
5 *
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.
9 *
10 * This file includes utility functions to register clocks to common
11 * clock framework for Samsung platforms.
12*/
13
14#include <linux/syscore_ops.h>
15#include "clk.h"
16
Naveen Krishna Ch16a90132014-09-22 10:17:02 +053017static LIST_HEAD(clock_reg_cache_list);
18
Tomasz Figa3ccefbd2014-02-14 08:16:00 +090019void samsung_clk_save(void __iomem *base,
20 struct samsung_clk_reg_dump *rd,
21 unsigned int num_regs)
22{
23 for (; num_regs > 0; --num_regs, ++rd)
24 rd->value = readl(base + rd->offset);
25}
26
27void samsung_clk_restore(void __iomem *base,
28 const struct samsung_clk_reg_dump *rd,
29 unsigned int num_regs)
30{
31 for (; num_regs > 0; --num_regs, ++rd)
32 writel(rd->value, base + rd->offset);
33}
34
Tomasz Figac3b6c1d2014-02-14 08:16:00 +090035struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
36 const unsigned long *rdump,
37 unsigned long nr_rdump)
Tomasz Figa3ccefbd2014-02-14 08:16:00 +090038{
39 struct samsung_clk_reg_dump *rd;
40 unsigned int i;
41
42 rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL);
43 if (!rd)
44 return NULL;
45
46 for (i = 0; i < nr_rdump; ++i)
47 rd[i].offset = rdump[i];
48
49 return rd;
50}
51
Thomas Abraham721c42a2013-03-09 17:02:44 +090052/* setup the essentials required to support clock lookup using ccf */
Rahul Sharma976face2014-03-12 20:26:44 +053053struct samsung_clk_provider *__init samsung_clk_init(struct device_node *np,
54 void __iomem *base, unsigned long nr_clks)
Thomas Abraham721c42a2013-03-09 17:02:44 +090055{
Rahul Sharma976face2014-03-12 20:26:44 +053056 struct samsung_clk_provider *ctx;
57 struct clk **clk_table;
Tomasz Figa91a12632014-02-06 19:33:11 +010058 int i;
59
Rahul Sharma976face2014-03-12 20:26:44 +053060 ctx = kzalloc(sizeof(struct samsung_clk_provider), GFP_KERNEL);
61 if (!ctx)
62 panic("could not allocate clock provider context.\n");
Thomas Abraham721c42a2013-03-09 17:02:44 +090063
Tomasz Figa91a12632014-02-06 19:33:11 +010064 clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
Heiko Stueber24661962013-03-18 13:43:52 +090065 if (!clk_table)
66 panic("could not allocate clock lookup table\n");
67
Tomasz Figa91a12632014-02-06 19:33:11 +010068 for (i = 0; i < nr_clks; ++i)
69 clk_table[i] = ERR_PTR(-ENOENT);
70
Rahul Sharma976face2014-03-12 20:26:44 +053071 ctx->reg_base = base;
72 ctx->clk_data.clks = clk_table;
73 ctx->clk_data.clk_num = nr_clks;
74 spin_lock_init(&ctx->lock);
Heiko Stuebner6e92bf5a2013-03-18 13:43:52 +090075
Rahul Sharma976face2014-03-12 20:26:44 +053076 return ctx;
Thomas Abraham721c42a2013-03-09 17:02:44 +090077}
78
Sylwester Nawrockid5e136a2014-06-18 17:46:52 +020079void __init samsung_clk_of_add_provider(struct device_node *np,
80 struct samsung_clk_provider *ctx)
81{
82 if (np) {
83 if (of_clk_add_provider(np, of_clk_src_onecell_get,
84 &ctx->clk_data))
85 panic("could not register clk provider\n");
86 }
87}
88
Thomas Abraham721c42a2013-03-09 17:02:44 +090089/* add a clock instance to the clock lookup table used for dt based lookup */
Rahul Sharma976face2014-03-12 20:26:44 +053090void samsung_clk_add_lookup(struct samsung_clk_provider *ctx, struct clk *clk,
91 unsigned int id)
Thomas Abraham721c42a2013-03-09 17:02:44 +090092{
Rahul Sharma976face2014-03-12 20:26:44 +053093 if (ctx->clk_data.clks && id)
94 ctx->clk_data.clks[id] = clk;
Thomas Abraham721c42a2013-03-09 17:02:44 +090095}
96
Heiko Stuebner5e2e0192013-03-18 13:43:56 +090097/* register a list of aliases */
Rahul Sharma976face2014-03-12 20:26:44 +053098void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx,
99 struct samsung_clock_alias *list,
100 unsigned int nr_clk)
Heiko Stuebner5e2e0192013-03-18 13:43:56 +0900101{
102 struct clk *clk;
103 unsigned int idx, ret;
104
Rahul Sharma976face2014-03-12 20:26:44 +0530105 if (!ctx->clk_data.clks) {
Heiko Stuebner5e2e0192013-03-18 13:43:56 +0900106 pr_err("%s: clock table missing\n", __func__);
107 return;
108 }
109
110 for (idx = 0; idx < nr_clk; idx++, list++) {
111 if (!list->id) {
112 pr_err("%s: clock id missing for index %d\n", __func__,
113 idx);
114 continue;
115 }
116
Rahul Sharma976face2014-03-12 20:26:44 +0530117 clk = ctx->clk_data.clks[list->id];
Heiko Stuebner5e2e0192013-03-18 13:43:56 +0900118 if (!clk) {
119 pr_err("%s: failed to find clock %d\n", __func__,
120 list->id);
121 continue;
122 }
123
124 ret = clk_register_clkdev(clk, list->alias, list->dev_name);
125 if (ret)
126 pr_err("%s: failed to register lookup %s\n",
127 __func__, list->alias);
128 }
129}
130
Thomas Abraham721c42a2013-03-09 17:02:44 +0900131/* register a list of fixed clocks */
Rahul Sharma976face2014-03-12 20:26:44 +0530132void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
Thomas Abraham721c42a2013-03-09 17:02:44 +0900133 struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
134{
135 struct clk *clk;
136 unsigned int idx, ret;
137
138 for (idx = 0; idx < nr_clk; idx++, list++) {
139 clk = clk_register_fixed_rate(NULL, list->name,
140 list->parent_name, list->flags, list->fixed_rate);
141 if (IS_ERR(clk)) {
142 pr_err("%s: failed to register clock %s\n", __func__,
143 list->name);
144 continue;
145 }
146
Rahul Sharma976face2014-03-12 20:26:44 +0530147 samsung_clk_add_lookup(ctx, clk, list->id);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900148
149 /*
150 * Unconditionally add a clock lookup for the fixed rate clocks.
151 * There are not many of these on any of Samsung platforms.
152 */
153 ret = clk_register_clkdev(clk, list->name, NULL);
154 if (ret)
155 pr_err("%s: failed to register clock lookup for %s",
156 __func__, list->name);
157 }
158}
159
160/* register a list of fixed factor clocks */
Rahul Sharma976face2014-03-12 20:26:44 +0530161void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
Thomas Abraham721c42a2013-03-09 17:02:44 +0900162 struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
163{
164 struct clk *clk;
165 unsigned int idx;
166
167 for (idx = 0; idx < nr_clk; idx++, list++) {
168 clk = clk_register_fixed_factor(NULL, list->name,
169 list->parent_name, list->flags, list->mult, list->div);
170 if (IS_ERR(clk)) {
171 pr_err("%s: failed to register clock %s\n", __func__,
172 list->name);
173 continue;
174 }
175
Rahul Sharma976face2014-03-12 20:26:44 +0530176 samsung_clk_add_lookup(ctx, clk, list->id);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900177 }
178}
179
180/* register a list of mux clocks */
Rahul Sharma976face2014-03-12 20:26:44 +0530181void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
182 struct samsung_mux_clock *list,
183 unsigned int nr_clk)
Thomas Abraham721c42a2013-03-09 17:02:44 +0900184{
185 struct clk *clk;
186 unsigned int idx, ret;
187
188 for (idx = 0; idx < nr_clk; idx++, list++) {
189 clk = clk_register_mux(NULL, list->name, list->parent_names,
Rahul Sharma976face2014-03-12 20:26:44 +0530190 list->num_parents, list->flags,
191 ctx->reg_base + list->offset,
192 list->shift, list->width, list->mux_flags, &ctx->lock);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900193 if (IS_ERR(clk)) {
194 pr_err("%s: failed to register clock %s\n", __func__,
195 list->name);
196 continue;
197 }
198
Rahul Sharma976face2014-03-12 20:26:44 +0530199 samsung_clk_add_lookup(ctx, clk, list->id);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900200
201 /* register a clock lookup only if a clock alias is specified */
202 if (list->alias) {
203 ret = clk_register_clkdev(clk, list->alias,
204 list->dev_name);
205 if (ret)
206 pr_err("%s: failed to register lookup %s\n",
207 __func__, list->alias);
208 }
209 }
210}
211
212/* register a list of div clocks */
Rahul Sharma976face2014-03-12 20:26:44 +0530213void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
214 struct samsung_div_clock *list,
215 unsigned int nr_clk)
Thomas Abraham721c42a2013-03-09 17:02:44 +0900216{
217 struct clk *clk;
218 unsigned int idx, ret;
219
220 for (idx = 0; idx < nr_clk; idx++, list++) {
Heiko Stuebner798ed612013-03-18 13:43:52 +0900221 if (list->table)
222 clk = clk_register_divider_table(NULL, list->name,
Rahul Sharma976face2014-03-12 20:26:44 +0530223 list->parent_name, list->flags,
224 ctx->reg_base + list->offset,
225 list->shift, list->width, list->div_flags,
226 list->table, &ctx->lock);
Heiko Stuebner798ed612013-03-18 13:43:52 +0900227 else
228 clk = clk_register_divider(NULL, list->name,
Rahul Sharma976face2014-03-12 20:26:44 +0530229 list->parent_name, list->flags,
230 ctx->reg_base + list->offset, list->shift,
231 list->width, list->div_flags, &ctx->lock);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900232 if (IS_ERR(clk)) {
233 pr_err("%s: failed to register clock %s\n", __func__,
234 list->name);
235 continue;
236 }
237
Rahul Sharma976face2014-03-12 20:26:44 +0530238 samsung_clk_add_lookup(ctx, clk, list->id);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900239
240 /* register a clock lookup only if a clock alias is specified */
241 if (list->alias) {
242 ret = clk_register_clkdev(clk, list->alias,
243 list->dev_name);
244 if (ret)
245 pr_err("%s: failed to register lookup %s\n",
246 __func__, list->alias);
247 }
248 }
249}
250
251/* register a list of gate clocks */
Rahul Sharma976face2014-03-12 20:26:44 +0530252void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
253 struct samsung_gate_clock *list,
254 unsigned int nr_clk)
Thomas Abraham721c42a2013-03-09 17:02:44 +0900255{
256 struct clk *clk;
257 unsigned int idx, ret;
258
259 for (idx = 0; idx < nr_clk; idx++, list++) {
260 clk = clk_register_gate(NULL, list->name, list->parent_name,
Rahul Sharma976face2014-03-12 20:26:44 +0530261 list->flags, ctx->reg_base + list->offset,
262 list->bit_idx, list->gate_flags, &ctx->lock);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900263 if (IS_ERR(clk)) {
264 pr_err("%s: failed to register clock %s\n", __func__,
265 list->name);
266 continue;
267 }
268
269 /* register a clock lookup only if a clock alias is specified */
270 if (list->alias) {
271 ret = clk_register_clkdev(clk, list->alias,
272 list->dev_name);
273 if (ret)
274 pr_err("%s: failed to register lookup %s\n",
275 __func__, list->alias);
276 }
277
Rahul Sharma976face2014-03-12 20:26:44 +0530278 samsung_clk_add_lookup(ctx, clk, list->id);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900279 }
280}
281
282/*
283 * obtain the clock speed of all external fixed clock sources from device
284 * tree and register it
285 */
Sachin Kamat6cec9082013-04-08 21:35:25 +0900286#ifdef CONFIG_OF
Rahul Sharma976face2014-03-12 20:26:44 +0530287void __init samsung_clk_of_register_fixed_ext(struct samsung_clk_provider *ctx,
Thomas Abraham721c42a2013-03-09 17:02:44 +0900288 struct samsung_fixed_rate_clock *fixed_rate_clk,
289 unsigned int nr_fixed_rate_clk,
Krzysztof Kozlowski305cfab2014-06-26 14:00:06 +0200290 const struct of_device_id *clk_matches)
Thomas Abraham721c42a2013-03-09 17:02:44 +0900291{
292 const struct of_device_id *match;
Rahul Sharma976face2014-03-12 20:26:44 +0530293 struct device_node *clk_np;
Thomas Abraham721c42a2013-03-09 17:02:44 +0900294 u32 freq;
295
Rahul Sharma976face2014-03-12 20:26:44 +0530296 for_each_matching_node_and_match(clk_np, clk_matches, &match) {
297 if (of_property_read_u32(clk_np, "clock-frequency", &freq))
Thomas Abraham721c42a2013-03-09 17:02:44 +0900298 continue;
Pankaj Dubey42fb57c2014-02-26 11:42:41 +0900299 fixed_rate_clk[(unsigned long)match->data].fixed_rate = freq;
Thomas Abraham721c42a2013-03-09 17:02:44 +0900300 }
Rahul Sharma976face2014-03-12 20:26:44 +0530301 samsung_clk_register_fixed_rate(ctx, fixed_rate_clk, nr_fixed_rate_clk);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900302}
Sachin Kamat6cec9082013-04-08 21:35:25 +0900303#endif
Thomas Abraham721c42a2013-03-09 17:02:44 +0900304
305/* utility function to get the rate of a specified clock */
306unsigned long _get_rate(const char *clk_name)
307{
308 struct clk *clk;
Thomas Abraham721c42a2013-03-09 17:02:44 +0900309
Tomasz Figa3a647892013-08-26 19:09:00 +0200310 clk = __clk_lookup(clk_name);
311 if (!clk) {
Thomas Abraham721c42a2013-03-09 17:02:44 +0900312 pr_err("%s: could not find clock %s\n", __func__, clk_name);
313 return 0;
314 }
Tomasz Figa3a647892013-08-26 19:09:00 +0200315
316 return clk_get_rate(clk);
Thomas Abraham721c42a2013-03-09 17:02:44 +0900317}
Naveen Krishna Ch16a90132014-09-22 10:17:02 +0530318
319#ifdef CONFIG_PM_SLEEP
320static int samsung_clk_suspend(void)
321{
322 struct samsung_clock_reg_cache *reg_cache;
323
324 list_for_each_entry(reg_cache, &clock_reg_cache_list, node)
325 samsung_clk_save(reg_cache->reg_base, reg_cache->rdump,
326 reg_cache->rd_num);
327 return 0;
328}
329
330static void samsung_clk_resume(void)
331{
332 struct samsung_clock_reg_cache *reg_cache;
333
334 list_for_each_entry(reg_cache, &clock_reg_cache_list, node)
335 samsung_clk_restore(reg_cache->reg_base, reg_cache->rdump,
336 reg_cache->rd_num);
337}
338
339static struct syscore_ops samsung_clk_syscore_ops = {
340 .suspend = samsung_clk_suspend,
341 .resume = samsung_clk_resume,
342};
343
344static void samsung_clk_sleep_init(void __iomem *reg_base,
345 const unsigned long *rdump,
346 unsigned long nr_rdump)
347{
348 struct samsung_clock_reg_cache *reg_cache;
349
350 reg_cache = kzalloc(sizeof(struct samsung_clock_reg_cache),
351 GFP_KERNEL);
352 if (!reg_cache)
353 panic("could not allocate register reg_cache.\n");
354 reg_cache->rdump = samsung_clk_alloc_reg_dump(rdump, nr_rdump);
355
356 if (!reg_cache->rdump)
357 panic("could not allocate register dump storage.\n");
358
359 if (list_empty(&clock_reg_cache_list))
360 register_syscore_ops(&samsung_clk_syscore_ops);
361
362 reg_cache->reg_base = reg_base;
363 reg_cache->rd_num = nr_rdump;
364 list_add_tail(&reg_cache->node, &clock_reg_cache_list);
365}
366
367#else
368static void samsung_clk_sleep_init(void __iomem *reg_base,
369 const unsigned long *rdump,
370 unsigned long nr_rdump) {}
371#endif
372
373/*
374 * Common function which registers plls, muxes, dividers and gates
375 * for each CMU. It also add CMU register list to register cache.
376 */
377void __init samsung_cmu_register_one(struct device_node *np,
378 struct samsung_cmu_info *cmu)
379{
380 void __iomem *reg_base;
381 struct samsung_clk_provider *ctx;
382
383 reg_base = of_iomap(np, 0);
384 if (!reg_base)
385 panic("%s: failed to map registers\n", __func__);
386
387 ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids);
388 if (!ctx)
389 panic("%s: unable to alllocate ctx\n", __func__);
390
391 if (cmu->pll_clks)
392 samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks,
393 reg_base);
394 if (cmu->mux_clks)
395 samsung_clk_register_mux(ctx, cmu->mux_clks,
396 cmu->nr_mux_clks);
397 if (cmu->div_clks)
398 samsung_clk_register_div(ctx, cmu->div_clks, cmu->nr_div_clks);
399 if (cmu->gate_clks)
400 samsung_clk_register_gate(ctx, cmu->gate_clks,
401 cmu->nr_gate_clks);
402 if (cmu->fixed_clks)
403 samsung_clk_register_fixed_rate(ctx, cmu->fixed_clks,
404 cmu->nr_fixed_clks);
405 if (cmu->clk_regs)
406 samsung_clk_sleep_init(reg_base, cmu->clk_regs,
407 cmu->nr_clk_regs);
408
409 samsung_clk_of_add_provider(np, ctx);
410}