diff options
author | Chen-Yu Tsai <wens@csie.org> | 2014-02-10 05:35:47 -0500 |
---|---|---|
committer | Emilio López <emilio@elopez.com.ar> | 2014-02-18 08:34:28 -0500 |
commit | e4c6d6c11bee5ff11feb837a0a76103b3eba252f (patch) | |
tree | de46fbc31e9fa56f85dcf2182a44d383fc7176da /drivers/clk/sunxi | |
parent | 92ef67c53ad92487c3c8de75e7940384c2edd793 (diff) |
clk: sunxi: Add Allwinner A20/A31 GMAC clock unit
The Allwinner A20/A31 clock module controls the transmit clock source
and interface type of the GMAC ethernet controller. Model this as
a single clock for GMAC drivers to use.
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Emilio López <emilio@elopez.com.ar>
Diffstat (limited to 'drivers/clk/sunxi')
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index d4cf297e8fac..335c98721218 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
@@ -411,6 +411,102 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate, | |||
411 | 411 | ||
412 | 412 | ||
413 | /** | 413 | /** |
414 | * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module | ||
415 | * | ||
416 | * This clock looks something like this | ||
417 | * ________________________ | ||
418 | * MII TX clock from PHY >-----|___________ _________|----> to GMAC core | ||
419 | * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY | ||
420 | * Ext. 125MHz RGMII TX clk >--|__divider__/ | | ||
421 | * |________________________| | ||
422 | * | ||
423 | * The external 125 MHz reference is optional, i.e. GMAC can use its | ||
424 | * internal TX clock just fine. The A31 GMAC clock module does not have | ||
425 | * the divider controls for the external reference. | ||
426 | * | ||
427 | * To keep it simple, let the GMAC use either the MII TX clock for MII mode, | ||
428 | * and its internal TX clock for GMII and RGMII modes. The GMAC driver should | ||
429 | * select the appropriate source and gate/ungate the output to the PHY. | ||
430 | * | ||
431 | * Only the GMAC should use this clock. Altering the clock so that it doesn't | ||
432 | * match the GMAC's operation parameters will result in the GMAC not being | ||
433 | * able to send traffic out. The GMAC driver should set the clock rate and | ||
434 | * enable/disable this clock to configure the required state. The clock | ||
435 | * driver then responds by auto-reparenting the clock. | ||
436 | */ | ||
437 | |||
438 | #define SUN7I_A20_GMAC_GPIT 2 | ||
439 | #define SUN7I_A20_GMAC_MASK 0x3 | ||
440 | #define SUN7I_A20_GMAC_PARENTS 2 | ||
441 | |||
442 | static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) | ||
443 | { | ||
444 | struct clk *clk; | ||
445 | struct clk_mux *mux; | ||
446 | struct clk_gate *gate; | ||
447 | const char *clk_name = node->name; | ||
448 | const char *parents[SUN7I_A20_GMAC_PARENTS]; | ||
449 | void *reg; | ||
450 | |||
451 | if (of_property_read_string(node, "clock-output-names", &clk_name)) | ||
452 | return; | ||
453 | |||
454 | /* allocate mux and gate clock structs */ | ||
455 | mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | ||
456 | if (!mux) | ||
457 | return; | ||
458 | |||
459 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
460 | if (!gate) | ||
461 | goto free_mux; | ||
462 | |||
463 | /* gmac clock requires exactly 2 parents */ | ||
464 | parents[0] = of_clk_get_parent_name(node, 0); | ||
465 | parents[1] = of_clk_get_parent_name(node, 1); | ||
466 | if (!parents[0] || !parents[1]) | ||
467 | goto free_gate; | ||
468 | |||
469 | reg = of_iomap(node, 0); | ||
470 | if (!reg) | ||
471 | goto free_gate; | ||
472 | |||
473 | /* set up gate and fixed rate properties */ | ||
474 | gate->reg = reg; | ||
475 | gate->bit_idx = SUN7I_A20_GMAC_GPIT; | ||
476 | gate->lock = &clk_lock; | ||
477 | mux->reg = reg; | ||
478 | mux->mask = SUN7I_A20_GMAC_MASK; | ||
479 | mux->flags = CLK_MUX_INDEX_BIT; | ||
480 | mux->lock = &clk_lock; | ||
481 | |||
482 | clk = clk_register_composite(NULL, clk_name, | ||
483 | parents, SUN7I_A20_GMAC_PARENTS, | ||
484 | &mux->hw, &clk_mux_ops, | ||
485 | NULL, NULL, | ||
486 | &gate->hw, &clk_gate_ops, | ||
487 | 0); | ||
488 | |||
489 | if (IS_ERR(clk)) | ||
490 | goto iounmap_reg; | ||
491 | |||
492 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
493 | clk_register_clkdev(clk, clk_name, NULL); | ||
494 | |||
495 | return; | ||
496 | |||
497 | iounmap_reg: | ||
498 | iounmap(reg); | ||
499 | free_gate: | ||
500 | kfree(gate); | ||
501 | free_mux: | ||
502 | kfree(mux); | ||
503 | } | ||
504 | CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", | ||
505 | sun7i_a20_gmac_clk_setup); | ||
506 | |||
507 | |||
508 | |||
509 | /** | ||
414 | * sunxi_factors_clk_setup() - Setup function for factor clocks | 510 | * sunxi_factors_clk_setup() - Setup function for factor clocks |
415 | */ | 511 | */ |
416 | 512 | ||