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