diff options
author | Emilio López <emilio@elopez.com.ar> | 2013-03-27 17:20:37 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2013-04-04 16:51:35 -0400 |
commit | 13569a709ad12aef4d9c2b352c92e95ab7dd201f (patch) | |
tree | 82c1411a3a64b0d1988c17eb93443a8864765f48 /drivers/clk/sunxi | |
parent | 056b205316cc3dcf8a67cf813a26ff8a72bf3cb9 (diff) |
clk: sunxi: Add support for AXI, AHB, APB0 and APB1 gates
This patchset adds DT support for all the AXI, AHB, APB0 and APB1
gates present on sunxi SoCs.
Signed-off-by: Emilio López <emilio@elopez.com.ar>
Reviewed-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/sunxi')
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index d528a2496690..244de90d5360 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
@@ -302,6 +302,82 @@ static void __init sunxi_divider_clk_setup(struct device_node *node, | |||
302 | } | 302 | } |
303 | 303 | ||
304 | 304 | ||
305 | |||
306 | /** | ||
307 | * sunxi_gates_clk_setup() - Setup function for leaf gates on clocks | ||
308 | */ | ||
309 | |||
310 | #define SUNXI_GATES_MAX_SIZE 64 | ||
311 | |||
312 | struct gates_data { | ||
313 | DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE); | ||
314 | }; | ||
315 | |||
316 | static const __initconst struct gates_data axi_gates_data = { | ||
317 | .mask = {1}, | ||
318 | }; | ||
319 | |||
320 | static const __initconst struct gates_data ahb_gates_data = { | ||
321 | .mask = {0x7F77FFF, 0x14FB3F}, | ||
322 | }; | ||
323 | |||
324 | static const __initconst struct gates_data apb0_gates_data = { | ||
325 | .mask = {0x4EF}, | ||
326 | }; | ||
327 | |||
328 | static const __initconst struct gates_data apb1_gates_data = { | ||
329 | .mask = {0xFF00F7}, | ||
330 | }; | ||
331 | |||
332 | static void __init sunxi_gates_clk_setup(struct device_node *node, | ||
333 | struct gates_data *data) | ||
334 | { | ||
335 | struct clk_onecell_data *clk_data; | ||
336 | const char *clk_parent; | ||
337 | const char *clk_name; | ||
338 | void *reg; | ||
339 | int qty; | ||
340 | int i = 0; | ||
341 | int j = 0; | ||
342 | int ignore; | ||
343 | |||
344 | reg = of_iomap(node, 0); | ||
345 | |||
346 | clk_parent = of_clk_get_parent_name(node, 0); | ||
347 | |||
348 | /* Worst-case size approximation and memory allocation */ | ||
349 | qty = find_last_bit(data->mask, SUNXI_GATES_MAX_SIZE); | ||
350 | clk_data = kmalloc(sizeof(struct clk_onecell_data), GFP_KERNEL); | ||
351 | if (!clk_data) | ||
352 | return; | ||
353 | clk_data->clks = kzalloc((qty+1) * sizeof(struct clk *), GFP_KERNEL); | ||
354 | if (!clk_data->clks) { | ||
355 | kfree(clk_data); | ||
356 | return; | ||
357 | } | ||
358 | |||
359 | for_each_set_bit(i, data->mask, SUNXI_GATES_MAX_SIZE) { | ||
360 | of_property_read_string_index(node, "clock-output-names", | ||
361 | j, &clk_name); | ||
362 | |||
363 | /* No driver claims this clock, but it should remain gated */ | ||
364 | ignore = !strcmp("ahb_sdram", clk_name) ? CLK_IGNORE_UNUSED : 0; | ||
365 | |||
366 | clk_data->clks[i] = clk_register_gate(NULL, clk_name, | ||
367 | clk_parent, ignore, | ||
368 | reg + 4 * (i/32), i % 32, | ||
369 | 0, &clk_lock); | ||
370 | WARN_ON(IS_ERR(clk_data->clks[i])); | ||
371 | |||
372 | j++; | ||
373 | } | ||
374 | |||
375 | /* Adjust to the real max */ | ||
376 | clk_data->clk_num = i; | ||
377 | |||
378 | of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); | ||
379 | } | ||
380 | |||
305 | /* Matches for of_clk_init */ | 381 | /* Matches for of_clk_init */ |
306 | static const __initconst struct of_device_id clk_match[] = { | 382 | static const __initconst struct of_device_id clk_match[] = { |
307 | {.compatible = "fixed-clock", .data = of_fixed_clk_setup,}, | 383 | {.compatible = "fixed-clock", .data = of_fixed_clk_setup,}, |
@@ -331,6 +407,15 @@ static const __initconst struct of_device_id clk_mux_match[] = { | |||
331 | {} | 407 | {} |
332 | }; | 408 | }; |
333 | 409 | ||
410 | /* Matches for gate clocks */ | ||
411 | static const __initconst struct of_device_id clk_gates_match[] = { | ||
412 | {.compatible = "allwinner,sun4i-axi-gates-clk", .data = &axi_gates_data,}, | ||
413 | {.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &ahb_gates_data,}, | ||
414 | {.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &apb0_gates_data,}, | ||
415 | {.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &apb1_gates_data,}, | ||
416 | {} | ||
417 | }; | ||
418 | |||
334 | static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_match, | 419 | static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_match, |
335 | void *function) | 420 | void *function) |
336 | { | 421 | { |
@@ -359,4 +444,7 @@ void __init sunxi_init_clocks(void) | |||
359 | 444 | ||
360 | /* Register mux clocks */ | 445 | /* Register mux clocks */ |
361 | of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); | 446 | of_sunxi_table_clock_setup(clk_mux_match, sunxi_mux_clk_setup); |
447 | |||
448 | /* Register gate clocks */ | ||
449 | of_sunxi_table_clock_setup(clk_gates_match, sunxi_gates_clk_setup); | ||
362 | } | 450 | } |