These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / clk / samsung / clk.c
1 /*
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/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>
20
21 #include "clk.h"
22
23 static LIST_HEAD(clock_reg_cache_list);
24
25 void samsung_clk_save(void __iomem *base,
26                                     struct samsung_clk_reg_dump *rd,
27                                     unsigned int num_regs)
28 {
29         for (; num_regs > 0; --num_regs, ++rd)
30                 rd->value = readl(base + rd->offset);
31 }
32
33 void samsung_clk_restore(void __iomem *base,
34                                       const struct samsung_clk_reg_dump *rd,
35                                       unsigned int num_regs)
36 {
37         for (; num_regs > 0; --num_regs, ++rd)
38                 writel(rd->value, base + rd->offset);
39 }
40
41 struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
42                                                 const unsigned long *rdump,
43                                                 unsigned long nr_rdump)
44 {
45         struct samsung_clk_reg_dump *rd;
46         unsigned int i;
47
48         rd = kcalloc(nr_rdump, sizeof(*rd), GFP_KERNEL);
49         if (!rd)
50                 return NULL;
51
52         for (i = 0; i < nr_rdump; ++i)
53                 rd[i].offset = rdump[i];
54
55         return rd;
56 }
57
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)
61 {
62         struct samsung_clk_provider *ctx;
63         struct clk **clk_table;
64         int i;
65
66         ctx = kzalloc(sizeof(struct samsung_clk_provider), GFP_KERNEL);
67         if (!ctx)
68                 panic("could not allocate clock provider context.\n");
69
70         clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
71         if (!clk_table)
72                 panic("could not allocate clock lookup table\n");
73
74         for (i = 0; i < nr_clks; ++i)
75                 clk_table[i] = ERR_PTR(-ENOENT);
76
77         ctx->reg_base = base;
78         ctx->clk_data.clks = clk_table;
79         ctx->clk_data.clk_num = nr_clks;
80         spin_lock_init(&ctx->lock);
81
82         return ctx;
83 }
84
85 void __init samsung_clk_of_add_provider(struct device_node *np,
86                                 struct samsung_clk_provider *ctx)
87 {
88         if (np) {
89                 if (of_clk_add_provider(np, of_clk_src_onecell_get,
90                                         &ctx->clk_data))
91                         panic("could not register clk provider\n");
92         }
93 }
94
95 /* add a clock instance to the clock lookup table used for dt based lookup */
96 void samsung_clk_add_lookup(struct samsung_clk_provider *ctx, struct clk *clk,
97                                 unsigned int id)
98 {
99         if (ctx->clk_data.clks && id)
100                 ctx->clk_data.clks[id] = clk;
101 }
102
103 /* register a list of aliases */
104 void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx,
105                                 const struct samsung_clock_alias *list,
106                                 unsigned int nr_clk)
107 {
108         struct clk *clk;
109         unsigned int idx, ret;
110
111         if (!ctx->clk_data.clks) {
112                 pr_err("%s: clock table missing\n", __func__);
113                 return;
114         }
115
116         for (idx = 0; idx < nr_clk; idx++, list++) {
117                 if (!list->id) {
118                         pr_err("%s: clock id missing for index %d\n", __func__,
119                                 idx);
120                         continue;
121                 }
122
123                 clk = ctx->clk_data.clks[list->id];
124                 if (!clk) {
125                         pr_err("%s: failed to find clock %d\n", __func__,
126                                 list->id);
127                         continue;
128                 }
129
130                 ret = clk_register_clkdev(clk, list->alias, list->dev_name);
131                 if (ret)
132                         pr_err("%s: failed to register lookup %s\n",
133                                         __func__, list->alias);
134         }
135 }
136
137 /* register a list of fixed clocks */
138 void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
139                 const struct samsung_fixed_rate_clock *list,
140                 unsigned int nr_clk)
141 {
142         struct clk *clk;
143         unsigned int idx, ret;
144
145         for (idx = 0; idx < nr_clk; idx++, list++) {
146                 clk = clk_register_fixed_rate(NULL, list->name,
147                         list->parent_name, list->flags, list->fixed_rate);
148                 if (IS_ERR(clk)) {
149                         pr_err("%s: failed to register clock %s\n", __func__,
150                                 list->name);
151                         continue;
152                 }
153
154                 samsung_clk_add_lookup(ctx, clk, list->id);
155
156                 /*
157                  * Unconditionally add a clock lookup for the fixed rate clocks.
158                  * There are not many of these on any of Samsung platforms.
159                  */
160                 ret = clk_register_clkdev(clk, list->name, NULL);
161                 if (ret)
162                         pr_err("%s: failed to register clock lookup for %s",
163                                 __func__, list->name);
164         }
165 }
166
167 /* register a list of fixed factor clocks */
168 void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
169                 const struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
170 {
171         struct clk *clk;
172         unsigned int idx;
173
174         for (idx = 0; idx < nr_clk; idx++, list++) {
175                 clk = clk_register_fixed_factor(NULL, list->name,
176                         list->parent_name, list->flags, list->mult, list->div);
177                 if (IS_ERR(clk)) {
178                         pr_err("%s: failed to register clock %s\n", __func__,
179                                 list->name);
180                         continue;
181                 }
182
183                 samsung_clk_add_lookup(ctx, clk, list->id);
184         }
185 }
186
187 /* register a list of mux clocks */
188 void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
189                                 const struct samsung_mux_clock *list,
190                                 unsigned int nr_clk)
191 {
192         struct clk *clk;
193         unsigned int idx, ret;
194
195         for (idx = 0; idx < nr_clk; idx++, list++) {
196                 clk = clk_register_mux(NULL, list->name, list->parent_names,
197                         list->num_parents, list->flags,
198                         ctx->reg_base + list->offset,
199                         list->shift, list->width, list->mux_flags, &ctx->lock);
200                 if (IS_ERR(clk)) {
201                         pr_err("%s: failed to register clock %s\n", __func__,
202                                 list->name);
203                         continue;
204                 }
205
206                 samsung_clk_add_lookup(ctx, clk, list->id);
207
208                 /* register a clock lookup only if a clock alias is specified */
209                 if (list->alias) {
210                         ret = clk_register_clkdev(clk, list->alias,
211                                                 list->dev_name);
212                         if (ret)
213                                 pr_err("%s: failed to register lookup %s\n",
214                                                 __func__, list->alias);
215                 }
216         }
217 }
218
219 /* register a list of div clocks */
220 void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
221                                 const struct samsung_div_clock *list,
222                                 unsigned int nr_clk)
223 {
224         struct clk *clk;
225         unsigned int idx, ret;
226
227         for (idx = 0; idx < nr_clk; idx++, list++) {
228                 if (list->table)
229                         clk = clk_register_divider_table(NULL, list->name,
230                                 list->parent_name, list->flags,
231                                 ctx->reg_base + list->offset,
232                                 list->shift, list->width, list->div_flags,
233                                 list->table, &ctx->lock);
234                 else
235                         clk = clk_register_divider(NULL, list->name,
236                                 list->parent_name, list->flags,
237                                 ctx->reg_base + list->offset, list->shift,
238                                 list->width, list->div_flags, &ctx->lock);
239                 if (IS_ERR(clk)) {
240                         pr_err("%s: failed to register clock %s\n", __func__,
241                                 list->name);
242                         continue;
243                 }
244
245                 samsung_clk_add_lookup(ctx, clk, list->id);
246
247                 /* register a clock lookup only if a clock alias is specified */
248                 if (list->alias) {
249                         ret = clk_register_clkdev(clk, list->alias,
250                                                 list->dev_name);
251                         if (ret)
252                                 pr_err("%s: failed to register lookup %s\n",
253                                                 __func__, list->alias);
254                 }
255         }
256 }
257
258 /* register a list of gate clocks */
259 void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
260                                 const struct samsung_gate_clock *list,
261                                 unsigned int nr_clk)
262 {
263         struct clk *clk;
264         unsigned int idx, ret;
265
266         for (idx = 0; idx < nr_clk; idx++, list++) {
267                 clk = clk_register_gate(NULL, list->name, list->parent_name,
268                                 list->flags, ctx->reg_base + list->offset,
269                                 list->bit_idx, list->gate_flags, &ctx->lock);
270                 if (IS_ERR(clk)) {
271                         pr_err("%s: failed to register clock %s\n", __func__,
272                                 list->name);
273                         continue;
274                 }
275
276                 /* register a clock lookup only if a clock alias is specified */
277                 if (list->alias) {
278                         ret = clk_register_clkdev(clk, list->alias,
279                                                         list->dev_name);
280                         if (ret)
281                                 pr_err("%s: failed to register lookup %s\n",
282                                         __func__, list->alias);
283                 }
284
285                 samsung_clk_add_lookup(ctx, clk, list->id);
286         }
287 }
288
289 /*
290  * obtain the clock speed of all external fixed clock sources from device
291  * tree and register it
292  */
293 void __init samsung_clk_of_register_fixed_ext(struct samsung_clk_provider *ctx,
294                         struct samsung_fixed_rate_clock *fixed_rate_clk,
295                         unsigned int nr_fixed_rate_clk,
296                         const struct of_device_id *clk_matches)
297 {
298         const struct of_device_id *match;
299         struct device_node *clk_np;
300         u32 freq;
301
302         for_each_matching_node_and_match(clk_np, clk_matches, &match) {
303                 if (of_property_read_u32(clk_np, "clock-frequency", &freq))
304                         continue;
305                 fixed_rate_clk[(unsigned long)match->data].fixed_rate = freq;
306         }
307         samsung_clk_register_fixed_rate(ctx, fixed_rate_clk, nr_fixed_rate_clk);
308 }
309
310 /* utility function to get the rate of a specified clock */
311 unsigned long _get_rate(const char *clk_name)
312 {
313         struct clk *clk;
314
315         clk = __clk_lookup(clk_name);
316         if (!clk) {
317                 pr_err("%s: could not find clock %s\n", __func__, clk_name);
318                 return 0;
319         }
320
321         return clk_get_rate(clk);
322 }
323
324 #ifdef CONFIG_PM_SLEEP
325 static int samsung_clk_suspend(void)
326 {
327         struct samsung_clock_reg_cache *reg_cache;
328
329         list_for_each_entry(reg_cache, &clock_reg_cache_list, node)
330                 samsung_clk_save(reg_cache->reg_base, reg_cache->rdump,
331                                 reg_cache->rd_num);
332         return 0;
333 }
334
335 static void samsung_clk_resume(void)
336 {
337         struct samsung_clock_reg_cache *reg_cache;
338
339         list_for_each_entry(reg_cache, &clock_reg_cache_list, node)
340                 samsung_clk_restore(reg_cache->reg_base, reg_cache->rdump,
341                                 reg_cache->rd_num);
342 }
343
344 static struct syscore_ops samsung_clk_syscore_ops = {
345         .suspend = samsung_clk_suspend,
346         .resume = samsung_clk_resume,
347 };
348
349 static void samsung_clk_sleep_init(void __iomem *reg_base,
350                 const unsigned long *rdump,
351                 unsigned long nr_rdump)
352 {
353         struct samsung_clock_reg_cache *reg_cache;
354
355         reg_cache = kzalloc(sizeof(struct samsung_clock_reg_cache),
356                         GFP_KERNEL);
357         if (!reg_cache)
358                 panic("could not allocate register reg_cache.\n");
359         reg_cache->rdump = samsung_clk_alloc_reg_dump(rdump, nr_rdump);
360
361         if (!reg_cache->rdump)
362                 panic("could not allocate register dump storage.\n");
363
364         if (list_empty(&clock_reg_cache_list))
365                 register_syscore_ops(&samsung_clk_syscore_ops);
366
367         reg_cache->reg_base = reg_base;
368         reg_cache->rd_num = nr_rdump;
369         list_add_tail(&reg_cache->node, &clock_reg_cache_list);
370 }
371
372 #else
373 static void samsung_clk_sleep_init(void __iomem *reg_base,
374                 const unsigned long *rdump,
375                 unsigned long nr_rdump) {}
376 #endif
377
378 /*
379  * Common function which registers plls, muxes, dividers and gates
380  * for each CMU. It also add CMU register list to register cache.
381  */
382 struct samsung_clk_provider * __init samsung_cmu_register_one(
383                         struct device_node *np,
384                         struct samsung_cmu_info *cmu)
385 {
386         void __iomem *reg_base;
387         struct samsung_clk_provider *ctx;
388
389         reg_base = of_iomap(np, 0);
390         if (!reg_base) {
391                 panic("%s: failed to map registers\n", __func__);
392                 return NULL;
393         }
394
395         ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids);
396         if (!ctx) {
397                 panic("%s: unable to allocate ctx\n", __func__);
398                 return ctx;
399         }
400
401         if (cmu->pll_clks)
402                 samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks,
403                         reg_base);
404         if (cmu->mux_clks)
405                 samsung_clk_register_mux(ctx, cmu->mux_clks,
406                         cmu->nr_mux_clks);
407         if (cmu->div_clks)
408                 samsung_clk_register_div(ctx, cmu->div_clks, cmu->nr_div_clks);
409         if (cmu->gate_clks)
410                 samsung_clk_register_gate(ctx, cmu->gate_clks,
411                         cmu->nr_gate_clks);
412         if (cmu->fixed_clks)
413                 samsung_clk_register_fixed_rate(ctx, cmu->fixed_clks,
414                         cmu->nr_fixed_clks);
415         if (cmu->fixed_factor_clks)
416                 samsung_clk_register_fixed_factor(ctx, cmu->fixed_factor_clks,
417                         cmu->nr_fixed_factor_clks);
418         if (cmu->clk_regs)
419                 samsung_clk_sleep_init(reg_base, cmu->clk_regs,
420                         cmu->nr_clk_regs);
421
422         samsung_clk_of_add_provider(np, ctx);
423
424         return ctx;
425 }