sunxi: driver refresh for 3.13
[openwrt.git] / target / linux / sunxi / patches-3.13 / 253-clk-sunxi-add-a20a31-gmac-clock.patch
1 From 967f938d4b16233fd7596e94803a36161847c6a8 Mon Sep 17 00:00:00 2001
2 From: Chen-Yu Tsai <wens@csie.org>
3 Date: Mon, 10 Feb 2014 18:35:47 +0800
4 Subject: [PATCH] clk: sunxi: Add Allwinner A20/A31 GMAC clock unit
5
6 The Allwinner A20/A31 clock module controls the transmit clock source
7 and interface type of the GMAC ethernet controller. Model this as
8 a single clock for GMAC drivers to use.
9
10 Signed-off-by: Chen-Yu Tsai <wens@csie.org>
11 ---
12  Documentation/devicetree/bindings/clock/sunxi.txt | 30 +++++++
13  drivers/clk/sunxi/clk-sunxi.c                     | 96 +++++++++++++++++++++++
14  2 files changed, 126 insertions(+)
15
16 diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt
17 index 93d003c..0da774c 100644
18 --- a/Documentation/devicetree/bindings/clock/sunxi.txt
19 +++ b/Documentation/devicetree/bindings/clock/sunxi.txt
20 @@ -37,6 +37,7 @@ Required properties:
21         "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
22         "allwinner,sun4i-mod0-clk" - for the module 0 family of clocks
23         "allwinner,sun7i-a20-out-clk" - for the external output clocks
24 +       "allwinner,sun7i-a20-gmac-clk" - for the GMAC clock module on A20/A31
25  
26  Required properties for all clocks:
27  - reg : shall be the control register address for the clock.
28 @@ -50,6 +51,9 @@ Required properties for all clocks:
29         If the clock module only has one output, the name shall be the
30         module name.
31  
32 +For "allwinner,sun7i-a20-gmac-clk", the parent clocks shall be fixed rate
33 +dummy clocks at 25 MHz and 125 MHz, respectively. See example.
34 +
35  Clock consumers should specify the desired clocks they use with a
36  "clocks" phandle cell. Consumers that are using a gated clock should
37  provide an additional ID in their clock property. This ID is the
38 @@ -96,3 +100,29 @@ mmc0_clk: clk@01c20088 {
39         clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
40         clock-output-names = "mmc0";
41  };
42 +
43 +mii_phy_tx_clk: clk@2 {
44 +       #clock-cells = <0>;
45 +       compatible = "fixed-clock";
46 +       clock-frequency = <25000000>;
47 +       clock-output-names = "mii_phy_tx";
48 +};
49 +
50 +gmac_int_tx_clk: clk@3 {
51 +       #clock-cells = <0>;
52 +       compatible = "fixed-clock";
53 +       clock-frequency = <125000000>;
54 +       clock-output-names = "gmac_int_tx";
55 +};
56 +
57 +gmac_clk: clk@01c20164 {
58 +       #clock-cells = <0>;
59 +       compatible = "allwinner,sun7i-a20-gmac-clk";
60 +       reg = <0x01c20164 0x4>;
61 +       /*
62 +        * The first clock must be fixed at 25MHz;
63 +        * the second clock must be fixed at 125MHz
64 +        */
65 +       clocks = <&mii_phy_tx_clk>, <&gmac_int_tx_clk>;
66 +       clock-output-names = "gmac";
67 +};
68 diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
69 index 0dce6fd..3283179 100644
70 --- a/drivers/clk/sunxi/clk-sunxi.c
71 +++ b/drivers/clk/sunxi/clk-sunxi.c
72 @@ -404,6 +404,102 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
73  
74  
75  /**
76 + * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
77 + *
78 + * This clock looks something like this
79 + *                               ________________________
80 + *  MII TX clock from PHY >-----|___________    _________|----> to GMAC core
81 + *  GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
82 + *  Ext. 125MHz RGMII TX clk >--|__divider__/            |
83 + *                              |________________________|
84 + *
85 + * The external 125 MHz reference is optional, i.e. GMAC can use its
86 + * internal TX clock just fine. The A31 GMAC clock module does not have
87 + * the divider controls for the external reference.
88 + *
89 + * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
90 + * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
91 + * select the appropriate source and gate/ungate the output to the PHY.
92 + *
93 + * Only the GMAC should use this clock. Altering the clock so that it doesn't
94 + * match the GMAC's operation parameters will result in the GMAC not being
95 + * able to send traffic out. The GMAC driver should set the clock rate and
96 + * enable/disable this clock to configure the required state. The clock
97 + * driver then responds by auto-reparenting the clock.
98 + */
99 +
100 +#define SUN7I_A20_GMAC_GPIT    2
101 +#define SUN7I_A20_GMAC_MASK    0x3
102 +#define SUN7I_A20_GMAC_PARENTS 2
103 +
104 +static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
105 +{
106 +       struct clk *clk;
107 +       struct clk_mux *mux;
108 +       struct clk_gate *gate;
109 +       const char *clk_name = node->name;
110 +       const char *parents[SUN7I_A20_GMAC_PARENTS];
111 +       void *reg;
112 +
113 +       if (of_property_read_string(node, "clock-output-names", &clk_name))
114 +               return;
115 +
116 +       /* allocate mux and gate clock structs */
117 +       mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
118 +       if (!mux)
119 +               return;
120 +
121 +       gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
122 +       if (!gate)
123 +               goto free_mux;
124 +
125 +       /* gmac clock requires exactly 2 parents */
126 +       parents[0] = of_clk_get_parent_name(node, 0);
127 +       parents[1] = of_clk_get_parent_name(node, 1);
128 +       if (!parents[0] || !parents[1])
129 +               goto free_gate;
130 +
131 +       reg = of_iomap(node, 0);
132 +       if (!reg)
133 +               goto free_gate;
134 +
135 +       /* set up gate and fixed rate properties */
136 +       gate->reg = reg;
137 +       gate->bit_idx = SUN7I_A20_GMAC_GPIT;
138 +       gate->lock = &clk_lock;
139 +       mux->reg = reg;
140 +       mux->mask = SUN7I_A20_GMAC_MASK;
141 +       mux->flags = CLK_MUX_INDEX_BIT;
142 +       mux->lock = &clk_lock;
143 +
144 +       clk = clk_register_composite(NULL, clk_name,
145 +                       parents, SUN7I_A20_GMAC_PARENTS,
146 +                       &mux->hw, &clk_mux_ops,
147 +                       NULL, NULL,
148 +                       &gate->hw, &clk_gate_ops,
149 +                       0);
150 +
151 +       if (IS_ERR(clk))
152 +               goto iounmap_reg;
153 +
154 +       of_clk_add_provider(node, of_clk_src_simple_get, clk);
155 +       clk_register_clkdev(clk, clk_name, NULL);
156 +
157 +       return;
158 +
159 +iounmap_reg:
160 +       iounmap(reg);
161 +free_gate:
162 +       kfree(gate);
163 +free_mux:
164 +       kfree(mux);
165 +}
166 +CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
167 +               sun7i_a20_gmac_clk_setup);
168 +
169 +
170 +
171 +/**
172   * sunxi_factors_clk_setup() - Setup function for factor clocks
173   */
174  
175 -- 
176 1.8.5.5
177