]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/clk/samsung/clk.c
jfs: fix error path in ialloc
[karo-tx-linux.git] / 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/syscore_ops.h>
15 #include "clk.h"
16
17 static DEFINE_SPINLOCK(lock);
18 static struct clk **clk_table;
19 static void __iomem *reg_base;
20 #ifdef CONFIG_OF
21 static struct clk_onecell_data clk_data;
22 #endif
23
24 #ifdef CONFIG_PM_SLEEP
25 static struct samsung_clk_reg_dump *reg_dump;
26 static unsigned long nr_reg_dump;
27
28 static int samsung_clk_suspend(void)
29 {
30         struct samsung_clk_reg_dump *rd = reg_dump;
31         unsigned long i;
32
33         for (i = 0; i < nr_reg_dump; i++, rd++)
34                 rd->value = __raw_readl(reg_base + rd->offset);
35
36         return 0;
37 }
38
39 static void samsung_clk_resume(void)
40 {
41         struct samsung_clk_reg_dump *rd = reg_dump;
42         unsigned long i;
43
44         for (i = 0; i < nr_reg_dump; i++, rd++)
45                 __raw_writel(rd->value, reg_base + rd->offset);
46 }
47
48 static struct syscore_ops samsung_clk_syscore_ops = {
49         .suspend        = samsung_clk_suspend,
50         .resume         = samsung_clk_resume,
51 };
52 #endif /* CONFIG_PM_SLEEP */
53
54 /* setup the essentials required to support clock lookup using ccf */
55 void __init samsung_clk_init(struct device_node *np, void __iomem *base,
56                 unsigned long nr_clks, unsigned long *rdump,
57                 unsigned long nr_rdump, unsigned long *soc_rdump,
58                 unsigned long nr_soc_rdump)
59 {
60         reg_base = base;
61
62 #ifdef CONFIG_PM_SLEEP
63         if (rdump && nr_rdump) {
64                 unsigned int idx;
65                 reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
66                                 * (nr_rdump + nr_soc_rdump), GFP_KERNEL);
67                 if (!reg_dump) {
68                         pr_err("%s: memory alloc for register dump failed\n",
69                                         __func__);
70                         return;
71                 }
72
73                 for (idx = 0; idx < nr_rdump; idx++)
74                         reg_dump[idx].offset = rdump[idx];
75                 for (idx = 0; idx < nr_soc_rdump; idx++)
76                         reg_dump[nr_rdump + idx].offset = soc_rdump[idx];
77                 nr_reg_dump = nr_rdump + nr_soc_rdump;
78                 register_syscore_ops(&samsung_clk_syscore_ops);
79         }
80 #endif
81
82         clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
83         if (!clk_table)
84                 panic("could not allocate clock lookup table\n");
85
86         if (!np)
87                 return;
88
89 #ifdef CONFIG_OF
90         clk_data.clks = clk_table;
91         clk_data.clk_num = nr_clks;
92         of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
93 #endif
94 }
95
96 /* add a clock instance to the clock lookup table used for dt based lookup */
97 void samsung_clk_add_lookup(struct clk *clk, unsigned int id)
98 {
99         if (clk_table && id)
100                 clk_table[id] = clk;
101 }
102
103 /* register a list of aliases */
104 void __init samsung_clk_register_alias(struct samsung_clock_alias *list,
105                                         unsigned int nr_clk)
106 {
107         struct clk *clk;
108         unsigned int idx, ret;
109
110         if (!clk_table) {
111                 pr_err("%s: clock table missing\n", __func__);
112                 return;
113         }
114
115         for (idx = 0; idx < nr_clk; idx++, list++) {
116                 if (!list->id) {
117                         pr_err("%s: clock id missing for index %d\n", __func__,
118                                 idx);
119                         continue;
120                 }
121
122                 clk = clk_table[list->id];
123                 if (!clk) {
124                         pr_err("%s: failed to find clock %d\n", __func__,
125                                 list->id);
126                         continue;
127                 }
128
129                 ret = clk_register_clkdev(clk, list->alias, list->dev_name);
130                 if (ret)
131                         pr_err("%s: failed to register lookup %s\n",
132                                         __func__, list->alias);
133         }
134 }
135
136 /* register a list of fixed clocks */
137 void __init samsung_clk_register_fixed_rate(
138                 struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
139 {
140         struct clk *clk;
141         unsigned int idx, ret;
142
143         for (idx = 0; idx < nr_clk; idx++, list++) {
144                 clk = clk_register_fixed_rate(NULL, list->name,
145                         list->parent_name, list->flags, list->fixed_rate);
146                 if (IS_ERR(clk)) {
147                         pr_err("%s: failed to register clock %s\n", __func__,
148                                 list->name);
149                         continue;
150                 }
151
152                 samsung_clk_add_lookup(clk, list->id);
153
154                 /*
155                  * Unconditionally add a clock lookup for the fixed rate clocks.
156                  * There are not many of these on any of Samsung platforms.
157                  */
158                 ret = clk_register_clkdev(clk, list->name, NULL);
159                 if (ret)
160                         pr_err("%s: failed to register clock lookup for %s",
161                                 __func__, list->name);
162         }
163 }
164
165 /* register a list of fixed factor clocks */
166 void __init samsung_clk_register_fixed_factor(
167                 struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
168 {
169         struct clk *clk;
170         unsigned int idx;
171
172         for (idx = 0; idx < nr_clk; idx++, list++) {
173                 clk = clk_register_fixed_factor(NULL, list->name,
174                         list->parent_name, list->flags, list->mult, list->div);
175                 if (IS_ERR(clk)) {
176                         pr_err("%s: failed to register clock %s\n", __func__,
177                                 list->name);
178                         continue;
179                 }
180
181                 samsung_clk_add_lookup(clk, list->id);
182         }
183 }
184
185 /* register a list of mux clocks */
186 void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
187                                         unsigned int nr_clk)
188 {
189         struct clk *clk;
190         unsigned int idx, ret;
191
192         for (idx = 0; idx < nr_clk; idx++, list++) {
193                 clk = clk_register_mux(NULL, list->name, list->parent_names,
194                         list->num_parents, list->flags, reg_base + list->offset,
195                         list->shift, list->width, list->mux_flags, &lock);
196                 if (IS_ERR(clk)) {
197                         pr_err("%s: failed to register clock %s\n", __func__,
198                                 list->name);
199                         continue;
200                 }
201
202                 samsung_clk_add_lookup(clk, list->id);
203
204                 /* register a clock lookup only if a clock alias is specified */
205                 if (list->alias) {
206                         ret = clk_register_clkdev(clk, list->alias,
207                                                 list->dev_name);
208                         if (ret)
209                                 pr_err("%s: failed to register lookup %s\n",
210                                                 __func__, list->alias);
211                 }
212         }
213 }
214
215 /* register a list of div clocks */
216 void __init samsung_clk_register_div(struct samsung_div_clock *list,
217                                         unsigned int nr_clk)
218 {
219         struct clk *clk;
220         unsigned int idx, ret;
221
222         for (idx = 0; idx < nr_clk; idx++, list++) {
223                 if (list->table)
224                         clk = clk_register_divider_table(NULL, list->name,
225                                         list->parent_name, list->flags,
226                                         reg_base + list->offset, list->shift,
227                                         list->width, list->div_flags,
228                                         list->table, &lock);
229                 else
230                         clk = clk_register_divider(NULL, list->name,
231                                         list->parent_name, list->flags,
232                                         reg_base + list->offset, list->shift,
233                                         list->width, list->div_flags, &lock);
234                 if (IS_ERR(clk)) {
235                         pr_err("%s: failed to register clock %s\n", __func__,
236                                 list->name);
237                         continue;
238                 }
239
240                 samsung_clk_add_lookup(clk, list->id);
241
242                 /* register a clock lookup only if a clock alias is specified */
243                 if (list->alias) {
244                         ret = clk_register_clkdev(clk, list->alias,
245                                                 list->dev_name);
246                         if (ret)
247                                 pr_err("%s: failed to register lookup %s\n",
248                                                 __func__, list->alias);
249                 }
250         }
251 }
252
253 /* register a list of gate clocks */
254 void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
255                                                 unsigned int nr_clk)
256 {
257         struct clk *clk;
258         unsigned int idx, ret;
259
260         for (idx = 0; idx < nr_clk; idx++, list++) {
261                 clk = clk_register_gate(NULL, list->name, list->parent_name,
262                                 list->flags, reg_base + list->offset,
263                                 list->bit_idx, list->gate_flags, &lock);
264                 if (IS_ERR(clk)) {
265                         pr_err("%s: failed to register clock %s\n", __func__,
266                                 list->name);
267                         continue;
268                 }
269
270                 /* register a clock lookup only if a clock alias is specified */
271                 if (list->alias) {
272                         ret = clk_register_clkdev(clk, list->alias,
273                                                         list->dev_name);
274                         if (ret)
275                                 pr_err("%s: failed to register lookup %s\n",
276                                         __func__, list->alias);
277                 }
278
279                 samsung_clk_add_lookup(clk, list->id);
280         }
281 }
282
283 /*
284  * obtain the clock speed of all external fixed clock sources from device
285  * tree and register it
286  */
287 #ifdef CONFIG_OF
288 void __init samsung_clk_of_register_fixed_ext(
289                         struct samsung_fixed_rate_clock *fixed_rate_clk,
290                         unsigned int nr_fixed_rate_clk,
291                         struct of_device_id *clk_matches)
292 {
293         const struct of_device_id *match;
294         struct device_node *np;
295         u32 freq;
296
297         for_each_matching_node_and_match(np, clk_matches, &match) {
298                 if (of_property_read_u32(np, "clock-frequency", &freq))
299                         continue;
300                 fixed_rate_clk[(u32)match->data].fixed_rate = freq;
301         }
302         samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk);
303 }
304 #endif
305
306 /* utility function to get the rate of a specified clock */
307 unsigned long _get_rate(const char *clk_name)
308 {
309         struct clk *clk;
310         unsigned long rate;
311
312         clk = clk_get(NULL, clk_name);
313         if (IS_ERR(clk)) {
314                 pr_err("%s: could not find clock %s\n", __func__, clk_name);
315                 return 0;
316         }
317         rate = clk_get_rate(clk);
318         clk_put(clk);
319         return rate;
320 }