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