diff options
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/sunxi/Makefile | 3 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-a20-gmac.c | 119 | ||||
-rw-r--r-- | drivers/clk/sunxi/clk-sunxi.c | 98 |
3 files changed, 121 insertions, 99 deletions
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile index 2c3d2fed2560..839029e36144 100644 --- a/drivers/clk/sunxi/Makefile +++ b/drivers/clk/sunxi/Makefile | |||
@@ -3,4 +3,5 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y += clk-sunxi.o clk-factors.o | 5 | obj-y += clk-sunxi.o clk-factors.o |
6 | obj-y += clk-a10-hosc.o \ No newline at end of file | 6 | obj-y += clk-a10-hosc.o |
7 | obj-y += clk-a20-gmac.o | ||
diff --git a/drivers/clk/sunxi/clk-a20-gmac.c b/drivers/clk/sunxi/clk-a20-gmac.c new file mode 100644 index 000000000000..633ddc4389ef --- /dev/null +++ b/drivers/clk/sunxi/clk-a20-gmac.c | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Emilio López | ||
3 | * Emilio López <emilio@elopez.com.ar> | ||
4 | * | ||
5 | * Copyright 2013 Chen-Yu Tsai | ||
6 | * Chen-Yu Tsai <wens@csie.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/clk-provider.h> | ||
20 | #include <linux/clkdev.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/of_address.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | static DEFINE_SPINLOCK(gmac_lock); | ||
26 | |||
27 | /** | ||
28 | * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module | ||
29 | * | ||
30 | * This clock looks something like this | ||
31 | * ________________________ | ||
32 | * MII TX clock from PHY >-----|___________ _________|----> to GMAC core | ||
33 | * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY | ||
34 | * Ext. 125MHz RGMII TX clk >--|__divider__/ | | ||
35 | * |________________________| | ||
36 | * | ||
37 | * The external 125 MHz reference is optional, i.e. GMAC can use its | ||
38 | * internal TX clock just fine. The A31 GMAC clock module does not have | ||
39 | * the divider controls for the external reference. | ||
40 | * | ||
41 | * To keep it simple, let the GMAC use either the MII TX clock for MII mode, | ||
42 | * and its internal TX clock for GMII and RGMII modes. The GMAC driver should | ||
43 | * select the appropriate source and gate/ungate the output to the PHY. | ||
44 | * | ||
45 | * Only the GMAC should use this clock. Altering the clock so that it doesn't | ||
46 | * match the GMAC's operation parameters will result in the GMAC not being | ||
47 | * able to send traffic out. The GMAC driver should set the clock rate and | ||
48 | * enable/disable this clock to configure the required state. The clock | ||
49 | * driver then responds by auto-reparenting the clock. | ||
50 | */ | ||
51 | |||
52 | #define SUN7I_A20_GMAC_GPIT 2 | ||
53 | #define SUN7I_A20_GMAC_MASK 0x3 | ||
54 | #define SUN7I_A20_GMAC_PARENTS 2 | ||
55 | |||
56 | static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) | ||
57 | { | ||
58 | struct clk *clk; | ||
59 | struct clk_mux *mux; | ||
60 | struct clk_gate *gate; | ||
61 | const char *clk_name = node->name; | ||
62 | const char *parents[SUN7I_A20_GMAC_PARENTS]; | ||
63 | void *reg; | ||
64 | |||
65 | if (of_property_read_string(node, "clock-output-names", &clk_name)) | ||
66 | return; | ||
67 | |||
68 | /* allocate mux and gate clock structs */ | ||
69 | mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | ||
70 | if (!mux) | ||
71 | return; | ||
72 | |||
73 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
74 | if (!gate) | ||
75 | goto free_mux; | ||
76 | |||
77 | /* gmac clock requires exactly 2 parents */ | ||
78 | parents[0] = of_clk_get_parent_name(node, 0); | ||
79 | parents[1] = of_clk_get_parent_name(node, 1); | ||
80 | if (!parents[0] || !parents[1]) | ||
81 | goto free_gate; | ||
82 | |||
83 | reg = of_iomap(node, 0); | ||
84 | if (!reg) | ||
85 | goto free_gate; | ||
86 | |||
87 | /* set up gate and fixed rate properties */ | ||
88 | gate->reg = reg; | ||
89 | gate->bit_idx = SUN7I_A20_GMAC_GPIT; | ||
90 | gate->lock = &gmac_lock; | ||
91 | mux->reg = reg; | ||
92 | mux->mask = SUN7I_A20_GMAC_MASK; | ||
93 | mux->flags = CLK_MUX_INDEX_BIT; | ||
94 | mux->lock = &gmac_lock; | ||
95 | |||
96 | clk = clk_register_composite(NULL, clk_name, | ||
97 | parents, SUN7I_A20_GMAC_PARENTS, | ||
98 | &mux->hw, &clk_mux_ops, | ||
99 | NULL, NULL, | ||
100 | &gate->hw, &clk_gate_ops, | ||
101 | 0); | ||
102 | |||
103 | if (IS_ERR(clk)) | ||
104 | goto iounmap_reg; | ||
105 | |||
106 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
107 | clk_register_clkdev(clk, clk_name, NULL); | ||
108 | |||
109 | return; | ||
110 | |||
111 | iounmap_reg: | ||
112 | iounmap(reg); | ||
113 | free_gate: | ||
114 | kfree(gate); | ||
115 | free_mux: | ||
116 | kfree(mux); | ||
117 | } | ||
118 | CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", | ||
119 | sun7i_a20_gmac_clk_setup); | ||
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c index 4a8294dad613..880095048d4d 100644 --- a/drivers/clk/sunxi/clk-sunxi.c +++ b/drivers/clk/sunxi/clk-sunxi.c | |||
@@ -351,104 +351,6 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate, | |||
351 | *p = calcp; | 351 | *p = calcp; |
352 | } | 352 | } |
353 | 353 | ||
354 | |||
355 | |||
356 | /** | ||
357 | * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module | ||
358 | * | ||
359 | * This clock looks something like this | ||
360 | * ________________________ | ||
361 | * MII TX clock from PHY >-----|___________ _________|----> to GMAC core | ||
362 | * GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY | ||
363 | * Ext. 125MHz RGMII TX clk >--|__divider__/ | | ||
364 | * |________________________| | ||
365 | * | ||
366 | * The external 125 MHz reference is optional, i.e. GMAC can use its | ||
367 | * internal TX clock just fine. The A31 GMAC clock module does not have | ||
368 | * the divider controls for the external reference. | ||
369 | * | ||
370 | * To keep it simple, let the GMAC use either the MII TX clock for MII mode, | ||
371 | * and its internal TX clock for GMII and RGMII modes. The GMAC driver should | ||
372 | * select the appropriate source and gate/ungate the output to the PHY. | ||
373 | * | ||
374 | * Only the GMAC should use this clock. Altering the clock so that it doesn't | ||
375 | * match the GMAC's operation parameters will result in the GMAC not being | ||
376 | * able to send traffic out. The GMAC driver should set the clock rate and | ||
377 | * enable/disable this clock to configure the required state. The clock | ||
378 | * driver then responds by auto-reparenting the clock. | ||
379 | */ | ||
380 | |||
381 | #define SUN7I_A20_GMAC_GPIT 2 | ||
382 | #define SUN7I_A20_GMAC_MASK 0x3 | ||
383 | #define SUN7I_A20_GMAC_PARENTS 2 | ||
384 | |||
385 | static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) | ||
386 | { | ||
387 | struct clk *clk; | ||
388 | struct clk_mux *mux; | ||
389 | struct clk_gate *gate; | ||
390 | const char *clk_name = node->name; | ||
391 | const char *parents[SUN7I_A20_GMAC_PARENTS]; | ||
392 | void *reg; | ||
393 | |||
394 | if (of_property_read_string(node, "clock-output-names", &clk_name)) | ||
395 | return; | ||
396 | |||
397 | /* allocate mux and gate clock structs */ | ||
398 | mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | ||
399 | if (!mux) | ||
400 | return; | ||
401 | |||
402 | gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
403 | if (!gate) | ||
404 | goto free_mux; | ||
405 | |||
406 | /* gmac clock requires exactly 2 parents */ | ||
407 | parents[0] = of_clk_get_parent_name(node, 0); | ||
408 | parents[1] = of_clk_get_parent_name(node, 1); | ||
409 | if (!parents[0] || !parents[1]) | ||
410 | goto free_gate; | ||
411 | |||
412 | reg = of_iomap(node, 0); | ||
413 | if (!reg) | ||
414 | goto free_gate; | ||
415 | |||
416 | /* set up gate and fixed rate properties */ | ||
417 | gate->reg = reg; | ||
418 | gate->bit_idx = SUN7I_A20_GMAC_GPIT; | ||
419 | gate->lock = &clk_lock; | ||
420 | mux->reg = reg; | ||
421 | mux->mask = SUN7I_A20_GMAC_MASK; | ||
422 | mux->flags = CLK_MUX_INDEX_BIT; | ||
423 | mux->lock = &clk_lock; | ||
424 | |||
425 | clk = clk_register_composite(NULL, clk_name, | ||
426 | parents, SUN7I_A20_GMAC_PARENTS, | ||
427 | &mux->hw, &clk_mux_ops, | ||
428 | NULL, NULL, | ||
429 | &gate->hw, &clk_gate_ops, | ||
430 | 0); | ||
431 | |||
432 | if (IS_ERR(clk)) | ||
433 | goto iounmap_reg; | ||
434 | |||
435 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
436 | clk_register_clkdev(clk, clk_name, NULL); | ||
437 | |||
438 | return; | ||
439 | |||
440 | iounmap_reg: | ||
441 | iounmap(reg); | ||
442 | free_gate: | ||
443 | kfree(gate); | ||
444 | free_mux: | ||
445 | kfree(mux); | ||
446 | } | ||
447 | CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", | ||
448 | sun7i_a20_gmac_clk_setup); | ||
449 | |||
450 | |||
451 | |||
452 | /** | 354 | /** |
453 | * clk_sunxi_mmc_phase_control() - configures MMC clock phase control | 355 | * clk_sunxi_mmc_phase_control() - configures MMC clock phase control |
454 | */ | 356 | */ |