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 | |
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>
-rw-r--r-- | Documentation/devicetree/bindings/clock/sunxi.txt | 30 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 96 |
2 files changed, 126 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index c37c764cbbc5..256a9089f677 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt | |||
@@ -38,6 +38,7 @@ Required properties: | |||
38 | "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 | 38 | "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 |
39 | "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks | 39 | "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks |
40 | "allwinner,sun7i-a20-out-clk" - for the external output clocks | 40 | "allwinner,sun7i-a20-out-clk" - for the external output clocks |
41 | "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31 | ||
41 | "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 | 42 | "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 |
42 | "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 | 43 | "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 |
43 | 44 | ||
@@ -56,6 +57,9 @@ Required properties for all clocks: | |||
56 | And "allwinner,*-usb-clk" clocks also require: | 57 | And "allwinner,*-usb-clk" clocks also require: |
57 | - reset-cells : shall be set to 1 | 58 | - reset-cells : shall be set to 1 |
58 | 59 | ||
60 | For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate | ||
61 | dummy clocks at 25 MHz and 125 MHz, respectively. See example. | ||
62 | |||
59 | Clock consumers should specify the desired clocks they use with a | 63 | Clock consumers should specify the desired clocks they use with a |
60 | "clocks" phandle cell. Consumers that are using a gated clock should | 64 | "clocks" phandle cell. Consumers that are using a gated clock should |
61 | provide an additional ID in their clock property. This ID is the | 65 | provide an additional ID in their clock property. This ID is the |
@@ -102,3 +106,29 @@ mmc0_clk: clk@01c20088 { | |||
102 | clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; | 106 | clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; |
103 | clock-output-names = "mmc0"; | 107 | clock-output-names = "mmc0"; |
104 | }; | 108 | }; |
109 | |||
110 | mii_phy_tx_clk: clk@2 { | ||
111 | #clock-cells = <0>; | ||
112 | compatible = "fixed-clock"; | ||
113 | clock-frequency = <25000000>; | ||
114 | clock-output-names = "mii_phy_tx"; | ||
115 | }; | ||
116 | |||
117 | gmac_int_tx_clk: clk@3 { | ||
118 | #clock-cells = <0>; | ||
119 | compatible = "fixed-clock"; | ||
120 | clock-frequency = <125000000>; | ||
121 | clock-output-names = "gmac_int_tx"; | ||
122 | }; | ||
123 | |||
124 | gmac_clk: clk@01c20164 { | ||
125 | #clock-cells = <0>; | ||
126 | compatible = "allwinner,sun7i-a20-gmac-clk"; | ||
127 | reg = <0x01c20164 0x4>; | ||
128 | /* | ||
129 | * The first clock must be fixed at 25MHz; | ||
130 | * the second clock must be fixed at 125MHz | ||
131 | */ | ||
132 | clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>; | ||
133 | clock-output-names = "gmac"; | ||
134 | }; | ||
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 | ||