aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clk/samsung/clk.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/samsung/clk.c')
-rw-r--r--drivers/clk/samsung/clk.c123
1 files changed, 69 insertions, 54 deletions
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 91bec3ebdc8f..49629c71c9e7 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -14,13 +14,6 @@
14#include <linux/syscore_ops.h> 14#include <linux/syscore_ops.h>
15#include "clk.h" 15#include "clk.h"
16 16
17static DEFINE_SPINLOCK(lock);
18static struct clk **clk_table;
19static void __iomem *reg_base;
20#ifdef CONFIG_OF
21static struct clk_onecell_data clk_data;
22#endif
23
24void samsung_clk_save(void __iomem *base, 17void samsung_clk_save(void __iomem *base,
25 struct samsung_clk_reg_dump *rd, 18 struct samsung_clk_reg_dump *rd,
26 unsigned int num_regs) 19 unsigned int num_regs)
@@ -55,40 +48,58 @@ struct samsung_clk_reg_dump *samsung_clk_alloc_reg_dump(
55} 48}
56 49
57/* setup the essentials required to support clock lookup using ccf */ 50/* setup the essentials required to support clock lookup using ccf */
58void __init samsung_clk_init(struct device_node *np, void __iomem *base, 51struct samsung_clk_provider *__init samsung_clk_init(struct device_node *np,
59 unsigned long nr_clks) 52 void __iomem *base, unsigned long nr_clks)
60{ 53{
61 reg_base = base; 54 struct samsung_clk_provider *ctx;
55 struct clk **clk_table;
56 int ret;
57 int i;
62 58
63 clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL); 59 ctx = kzalloc(sizeof(struct samsung_clk_provider), GFP_KERNEL);
60 if (!ctx)
61 panic("could not allocate clock provider context.\n");
62
63 clk_table = kcalloc(nr_clks, sizeof(struct clk *), GFP_KERNEL);
64 if (!clk_table) 64 if (!clk_table)
65 panic("could not allocate clock lookup table\n"); 65 panic("could not allocate clock lookup table\n");
66 66
67 for (i = 0; i < nr_clks; ++i)
68 clk_table[i] = ERR_PTR(-ENOENT);
69
70 ctx->reg_base = base;
71 ctx->clk_data.clks = clk_table;
72 ctx->clk_data.clk_num = nr_clks;
73 spin_lock_init(&ctx->lock);
74
67 if (!np) 75 if (!np)
68 return; 76 return ctx;
69 77
70#ifdef CONFIG_OF 78 ret = of_clk_add_provider(np, of_clk_src_onecell_get,
71 clk_data.clks = clk_table; 79 &ctx->clk_data);
72 clk_data.clk_num = nr_clks; 80 if (ret)
73 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); 81 panic("could not register clock provide\n");
74#endif 82
83 return ctx;
75} 84}
76 85
77/* add a clock instance to the clock lookup table used for dt based lookup */ 86/* add a clock instance to the clock lookup table used for dt based lookup */
78void samsung_clk_add_lookup(struct clk *clk, unsigned int id) 87void samsung_clk_add_lookup(struct samsung_clk_provider *ctx, struct clk *clk,
88 unsigned int id)
79{ 89{
80 if (clk_table && id) 90 if (ctx->clk_data.clks && id)
81 clk_table[id] = clk; 91 ctx->clk_data.clks[id] = clk;
82} 92}
83 93
84/* register a list of aliases */ 94/* register a list of aliases */
85void __init samsung_clk_register_alias(struct samsung_clock_alias *list, 95void __init samsung_clk_register_alias(struct samsung_clk_provider *ctx,
86 unsigned int nr_clk) 96 struct samsung_clock_alias *list,
97 unsigned int nr_clk)
87{ 98{
88 struct clk *clk; 99 struct clk *clk;
89 unsigned int idx, ret; 100 unsigned int idx, ret;
90 101
91 if (!clk_table) { 102 if (!ctx->clk_data.clks) {
92 pr_err("%s: clock table missing\n", __func__); 103 pr_err("%s: clock table missing\n", __func__);
93 return; 104 return;
94 } 105 }
@@ -100,7 +111,7 @@ void __init samsung_clk_register_alias(struct samsung_clock_alias *list,
100 continue; 111 continue;
101 } 112 }
102 113
103 clk = clk_table[list->id]; 114 clk = ctx->clk_data.clks[list->id];
104 if (!clk) { 115 if (!clk) {
105 pr_err("%s: failed to find clock %d\n", __func__, 116 pr_err("%s: failed to find clock %d\n", __func__,
106 list->id); 117 list->id);
@@ -115,7 +126,7 @@ void __init samsung_clk_register_alias(struct samsung_clock_alias *list,
115} 126}
116 127
117/* register a list of fixed clocks */ 128/* register a list of fixed clocks */
118void __init samsung_clk_register_fixed_rate( 129void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx,
119 struct samsung_fixed_rate_clock *list, unsigned int nr_clk) 130 struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
120{ 131{
121 struct clk *clk; 132 struct clk *clk;
@@ -130,7 +141,7 @@ void __init samsung_clk_register_fixed_rate(
130 continue; 141 continue;
131 } 142 }
132 143
133 samsung_clk_add_lookup(clk, list->id); 144 samsung_clk_add_lookup(ctx, clk, list->id);
134 145
135 /* 146 /*
136 * Unconditionally add a clock lookup for the fixed rate clocks. 147 * Unconditionally add a clock lookup for the fixed rate clocks.
@@ -144,7 +155,7 @@ void __init samsung_clk_register_fixed_rate(
144} 155}
145 156
146/* register a list of fixed factor clocks */ 157/* register a list of fixed factor clocks */
147void __init samsung_clk_register_fixed_factor( 158void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx,
148 struct samsung_fixed_factor_clock *list, unsigned int nr_clk) 159 struct samsung_fixed_factor_clock *list, unsigned int nr_clk)
149{ 160{
150 struct clk *clk; 161 struct clk *clk;
@@ -159,28 +170,30 @@ void __init samsung_clk_register_fixed_factor(
159 continue; 170 continue;
160 } 171 }
161 172
162 samsung_clk_add_lookup(clk, list->id); 173 samsung_clk_add_lookup(ctx, clk, list->id);
163 } 174 }
164} 175}
165 176
166/* register a list of mux clocks */ 177/* register a list of mux clocks */
167void __init samsung_clk_register_mux(struct samsung_mux_clock *list, 178void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx,
168 unsigned int nr_clk) 179 struct samsung_mux_clock *list,
180 unsigned int nr_clk)
169{ 181{
170 struct clk *clk; 182 struct clk *clk;
171 unsigned int idx, ret; 183 unsigned int idx, ret;
172 184
173 for (idx = 0; idx < nr_clk; idx++, list++) { 185 for (idx = 0; idx < nr_clk; idx++, list++) {
174 clk = clk_register_mux(NULL, list->name, list->parent_names, 186 clk = clk_register_mux(NULL, list->name, list->parent_names,
175 list->num_parents, list->flags, reg_base + list->offset, 187 list->num_parents, list->flags,
176 list->shift, list->width, list->mux_flags, &lock); 188 ctx->reg_base + list->offset,
189 list->shift, list->width, list->mux_flags, &ctx->lock);
177 if (IS_ERR(clk)) { 190 if (IS_ERR(clk)) {
178 pr_err("%s: failed to register clock %s\n", __func__, 191 pr_err("%s: failed to register clock %s\n", __func__,
179 list->name); 192 list->name);
180 continue; 193 continue;
181 } 194 }
182 195
183 samsung_clk_add_lookup(clk, list->id); 196 samsung_clk_add_lookup(ctx, clk, list->id);
184 197
185 /* register a clock lookup only if a clock alias is specified */ 198 /* register a clock lookup only if a clock alias is specified */
186 if (list->alias) { 199 if (list->alias) {
@@ -194,8 +207,9 @@ void __init samsung_clk_register_mux(struct samsung_mux_clock *list,
194} 207}
195 208
196/* register a list of div clocks */ 209/* register a list of div clocks */
197void __init samsung_clk_register_div(struct samsung_div_clock *list, 210void __init samsung_clk_register_div(struct samsung_clk_provider *ctx,
198 unsigned int nr_clk) 211 struct samsung_div_clock *list,
212 unsigned int nr_clk)
199{ 213{
200 struct clk *clk; 214 struct clk *clk;
201 unsigned int idx, ret; 215 unsigned int idx, ret;
@@ -203,22 +217,22 @@ void __init samsung_clk_register_div(struct samsung_div_clock *list,
203 for (idx = 0; idx < nr_clk; idx++, list++) { 217 for (idx = 0; idx < nr_clk; idx++, list++) {
204 if (list->table) 218 if (list->table)
205 clk = clk_register_divider_table(NULL, list->name, 219 clk = clk_register_divider_table(NULL, list->name,
206 list->parent_name, list->flags, 220 list->parent_name, list->flags,
207 reg_base + list->offset, list->shift, 221 ctx->reg_base + list->offset,
208 list->width, list->div_flags, 222 list->shift, list->width, list->div_flags,
209 list->table, &lock); 223 list->table, &ctx->lock);
210 else 224 else
211 clk = clk_register_divider(NULL, list->name, 225 clk = clk_register_divider(NULL, list->name,
212 list->parent_name, list->flags, 226 list->parent_name, list->flags,
213 reg_base + list->offset, list->shift, 227 ctx->reg_base + list->offset, list->shift,
214 list->width, list->div_flags, &lock); 228 list->width, list->div_flags, &ctx->lock);
215 if (IS_ERR(clk)) { 229 if (IS_ERR(clk)) {
216 pr_err("%s: failed to register clock %s\n", __func__, 230 pr_err("%s: failed to register clock %s\n", __func__,
217 list->name); 231 list->name);
218 continue; 232 continue;
219 } 233 }
220 234
221 samsung_clk_add_lookup(clk, list->id); 235 samsung_clk_add_lookup(ctx, clk, list->id);
222 236
223 /* register a clock lookup only if a clock alias is specified */ 237 /* register a clock lookup only if a clock alias is specified */
224 if (list->alias) { 238 if (list->alias) {
@@ -232,16 +246,17 @@ void __init samsung_clk_register_div(struct samsung_div_clock *list,
232} 246}
233 247
234/* register a list of gate clocks */ 248/* register a list of gate clocks */
235void __init samsung_clk_register_gate(struct samsung_gate_clock *list, 249void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx,
236 unsigned int nr_clk) 250 struct samsung_gate_clock *list,
251 unsigned int nr_clk)
237{ 252{
238 struct clk *clk; 253 struct clk *clk;
239 unsigned int idx, ret; 254 unsigned int idx, ret;
240 255
241 for (idx = 0; idx < nr_clk; idx++, list++) { 256 for (idx = 0; idx < nr_clk; idx++, list++) {
242 clk = clk_register_gate(NULL, list->name, list->parent_name, 257 clk = clk_register_gate(NULL, list->name, list->parent_name,
243 list->flags, reg_base + list->offset, 258 list->flags, ctx->reg_base + list->offset,
244 list->bit_idx, list->gate_flags, &lock); 259 list->bit_idx, list->gate_flags, &ctx->lock);
245 if (IS_ERR(clk)) { 260 if (IS_ERR(clk)) {
246 pr_err("%s: failed to register clock %s\n", __func__, 261 pr_err("%s: failed to register clock %s\n", __func__,
247 list->name); 262 list->name);
@@ -257,7 +272,7 @@ void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
257 __func__, list->alias); 272 __func__, list->alias);
258 } 273 }
259 274
260 samsung_clk_add_lookup(clk, list->id); 275 samsung_clk_add_lookup(ctx, clk, list->id);
261 } 276 }
262} 277}
263 278
@@ -266,21 +281,21 @@ void __init samsung_clk_register_gate(struct samsung_gate_clock *list,
266 * tree and register it 281 * tree and register it
267 */ 282 */
268#ifdef CONFIG_OF 283#ifdef CONFIG_OF
269void __init samsung_clk_of_register_fixed_ext( 284void __init samsung_clk_of_register_fixed_ext(struct samsung_clk_provider *ctx,
270 struct samsung_fixed_rate_clock *fixed_rate_clk, 285 struct samsung_fixed_rate_clock *fixed_rate_clk,
271 unsigned int nr_fixed_rate_clk, 286 unsigned int nr_fixed_rate_clk,
272 struct of_device_id *clk_matches) 287 struct of_device_id *clk_matches)
273{ 288{
274 const struct of_device_id *match; 289 const struct of_device_id *match;
275 struct device_node *np; 290 struct device_node *clk_np;
276 u32 freq; 291 u32 freq;
277 292
278 for_each_matching_node_and_match(np, clk_matches, &match) { 293 for_each_matching_node_and_match(clk_np, clk_matches, &match) {
279 if (of_property_read_u32(np, "clock-frequency", &freq)) 294 if (of_property_read_u32(clk_np, "clock-frequency", &freq))
280 continue; 295 continue;
281 fixed_rate_clk[(u32)match->data].fixed_rate = freq; 296 fixed_rate_clk[(unsigned long)match->data].fixed_rate = freq;
282 } 297 }
283 samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk); 298 samsung_clk_register_fixed_rate(ctx, fixed_rate_clk, nr_fixed_rate_clk);
284} 299}
285#endif 300#endif
286 301