diff options
-rw-r--r-- | drivers/clk/mvebu/kirkwood.c | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index ddb666a86500..f73a2fa8a561 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c | |||
@@ -13,9 +13,11 @@ | |||
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/slab.h> | ||
16 | #include <linux/clk-provider.h> | 17 | #include <linux/clk-provider.h> |
17 | #include <linux/io.h> | 18 | #include <linux/io.h> |
18 | #include <linux/of.h> | 19 | #include <linux/of.h> |
20 | #include <linux/of_address.h> | ||
19 | #include "common.h" | 21 | #include "common.h" |
20 | 22 | ||
21 | /* | 23 | /* |
@@ -225,6 +227,91 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = { | |||
225 | { } | 227 | { } |
226 | }; | 228 | }; |
227 | 229 | ||
230 | |||
231 | /* | ||
232 | * Clock Muxing Control | ||
233 | */ | ||
234 | |||
235 | struct clk_muxing_soc_desc { | ||
236 | const char *name; | ||
237 | const char **parents; | ||
238 | int num_parents; | ||
239 | int shift; | ||
240 | int width; | ||
241 | unsigned long flags; | ||
242 | }; | ||
243 | |||
244 | struct clk_muxing_ctrl { | ||
245 | spinlock_t *lock; | ||
246 | struct clk **muxes; | ||
247 | int num_muxes; | ||
248 | }; | ||
249 | |||
250 | #define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) | ||
251 | |||
252 | static struct clk *clk_muxing_get_src( | ||
253 | struct of_phandle_args *clkspec, void *data) | ||
254 | { | ||
255 | struct clk_muxing_ctrl *ctrl = (struct clk_muxing_ctrl *)data; | ||
256 | int n; | ||
257 | |||
258 | if (clkspec->args_count < 1) | ||
259 | return ERR_PTR(-EINVAL); | ||
260 | |||
261 | for (n = 0; n < ctrl->num_muxes; n++) { | ||
262 | struct clk_mux *mux = | ||
263 | to_clk_mux(__clk_get_hw(ctrl->muxes[n])); | ||
264 | if (clkspec->args[0] == mux->shift) | ||
265 | return ctrl->muxes[n]; | ||
266 | } | ||
267 | return ERR_PTR(-ENODEV); | ||
268 | } | ||
269 | |||
270 | static void __init kirkwood_clk_muxing_setup(struct device_node *np, | ||
271 | const struct clk_muxing_soc_desc *desc) | ||
272 | { | ||
273 | struct clk_muxing_ctrl *ctrl; | ||
274 | void __iomem *base; | ||
275 | int n; | ||
276 | |||
277 | base = of_iomap(np, 0); | ||
278 | if (WARN_ON(!base)) | ||
279 | return; | ||
280 | |||
281 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | ||
282 | if (WARN_ON(!ctrl)) | ||
283 | goto ctrl_out; | ||
284 | |||
285 | /* lock must already be initialized */ | ||
286 | ctrl->lock = &ctrl_gating_lock; | ||
287 | |||
288 | /* Count, allocate, and register clock muxes */ | ||
289 | for (n = 0; desc[n].name;) | ||
290 | n++; | ||
291 | |||
292 | ctrl->num_muxes = n; | ||
293 | ctrl->muxes = kcalloc(ctrl->num_muxes, sizeof(struct clk *), | ||
294 | GFP_KERNEL); | ||
295 | if (WARN_ON(!ctrl->muxes)) | ||
296 | goto muxes_out; | ||
297 | |||
298 | for (n = 0; n < ctrl->num_muxes; n++) { | ||
299 | ctrl->muxes[n] = clk_register_mux(NULL, desc[n].name, | ||
300 | desc[n].parents, desc[n].num_parents, | ||
301 | desc[n].flags, base, desc[n].shift, | ||
302 | desc[n].width, desc[n].flags, ctrl->lock); | ||
303 | WARN_ON(IS_ERR(ctrl->muxes[n])); | ||
304 | } | ||
305 | |||
306 | of_clk_add_provider(np, clk_muxing_get_src, ctrl); | ||
307 | |||
308 | return; | ||
309 | muxes_out: | ||
310 | kfree(ctrl); | ||
311 | ctrl_out: | ||
312 | iounmap(base); | ||
313 | } | ||
314 | |||
228 | static void __init kirkwood_clk_init(struct device_node *np) | 315 | static void __init kirkwood_clk_init(struct device_node *np) |
229 | { | 316 | { |
230 | struct device_node *cgnp = | 317 | struct device_node *cgnp = |