diff options
Diffstat (limited to 'drivers/clk/samsung/clk.c')
-rw-r--r-- | drivers/clk/samsung/clk.c | 123 |
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 | ||
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 | void samsung_clk_save(void __iomem *base, | 17 | void 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 */ |
58 | void __init samsung_clk_init(struct device_node *np, void __iomem *base, | 51 | struct 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 */ |
78 | void samsung_clk_add_lookup(struct clk *clk, unsigned int id) | 87 | void 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 */ |
85 | void __init samsung_clk_register_alias(struct samsung_clock_alias *list, | 95 | void __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 */ |
118 | void __init samsung_clk_register_fixed_rate( | 129 | void __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 */ |
147 | void __init samsung_clk_register_fixed_factor( | 158 | void __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 */ |
167 | void __init samsung_clk_register_mux(struct samsung_mux_clock *list, | 178 | void __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 */ |
197 | void __init samsung_clk_register_div(struct samsung_div_clock *list, | 210 | void __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 */ |
235 | void __init samsung_clk_register_gate(struct samsung_gate_clock *list, | 249 | void __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 |
269 | void __init samsung_clk_of_register_fixed_ext( | 284 | void __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 | ||