Blame view

drivers/clk/sunxi/clk-a20-gmac.c 3.12 KB
c942fddf8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
59cb10e32   Maxime Ripard   clk: sunxi: Move ...
2
3
4
5
6
7
  /*
   * Copyright 2013 Emilio López
   * Emilio López <emilio@elopez.com.ar>
   *
   * Copyright 2013 Chen-Yu Tsai
   * Chen-Yu Tsai <wens@csie.org>
59cb10e32   Maxime Ripard   clk: sunxi: Move ...
8
9
10
   */
  
  #include <linux/clk-provider.h>
62e59c4e6   Stephen Boyd   clk: Remove io.h ...
11
  #include <linux/io.h>
59cb10e32   Maxime Ripard   clk: sunxi: Move ...
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  #include <linux/of.h>
  #include <linux/of_address.h>
  #include <linux/slab.h>
  
  static DEFINE_SPINLOCK(gmac_lock);
  
  /**
   * sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module
   *
   * This clock looks something like this
   *                               ________________________
   *  MII TX clock from PHY >-----|___________    _________|----> to GMAC core
   *  GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY
   *  Ext. 125MHz RGMII TX clk >--|__divider__/            |
   *                              |________________________|
   *
   * The external 125 MHz reference is optional, i.e. GMAC can use its
   * internal TX clock just fine. The A31 GMAC clock module does not have
   * the divider controls for the external reference.
   *
   * To keep it simple, let the GMAC use either the MII TX clock for MII mode,
   * and its internal TX clock for GMII and RGMII modes. The GMAC driver should
   * select the appropriate source and gate/ungate the output to the PHY.
   *
   * Only the GMAC should use this clock. Altering the clock so that it doesn't
   * match the GMAC's operation parameters will result in the GMAC not being
   * able to send traffic out. The GMAC driver should set the clock rate and
   * enable/disable this clock to configure the required state. The clock
   * driver then responds by auto-reparenting the clock.
   */
  
  #define SUN7I_A20_GMAC_GPIT	2
  #define SUN7I_A20_GMAC_MASK	0x3
  #define SUN7I_A20_GMAC_PARENTS	2
c1ec51603   Hans de Goede   clk: sunxi: gmac-...
46
47
48
49
  static u32 sun7i_a20_gmac_mux_table[SUN7I_A20_GMAC_PARENTS] = {
  	0x00, /* Select mii_phy_tx_clk */
  	0x02, /* Select gmac_int_tx_clk */
  };
59cb10e32   Maxime Ripard   clk: sunxi: Move ...
50
51
52
53
54
55
56
  static void __init sun7i_a20_gmac_clk_setup(struct device_node *node)
  {
  	struct clk *clk;
  	struct clk_mux *mux;
  	struct clk_gate *gate;
  	const char *clk_name = node->name;
  	const char *parents[SUN7I_A20_GMAC_PARENTS];
89a9456d6   Emilio López   clk: sunxi: add _...
57
  	void __iomem *reg;
59cb10e32   Maxime Ripard   clk: sunxi: Move ...
58
59
60
61
62
63
64
65
66
67
68
69
70
71
  
  	if (of_property_read_string(node, "clock-output-names", &clk_name))
  		return;
  
  	/* allocate mux and gate clock structs */
  	mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
  	if (!mux)
  		return;
  
  	gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
  	if (!gate)
  		goto free_mux;
  
  	/* gmac clock requires exactly 2 parents */
8a53fb2bc   Dinh Nguyen   clk: sunxi: make ...
72
  	if (of_clk_parent_fill(node, parents, 2) != 2)
59cb10e32   Maxime Ripard   clk: sunxi: Move ...
73
74
75
76
77
78
79
80
81
82
83
84
  		goto free_gate;
  
  	reg = of_iomap(node, 0);
  	if (!reg)
  		goto free_gate;
  
  	/* set up gate and fixed rate properties */
  	gate->reg = reg;
  	gate->bit_idx = SUN7I_A20_GMAC_GPIT;
  	gate->lock = &gmac_lock;
  	mux->reg = reg;
  	mux->mask = SUN7I_A20_GMAC_MASK;
c1ec51603   Hans de Goede   clk: sunxi: gmac-...
85
  	mux->table = sun7i_a20_gmac_mux_table;
59cb10e32   Maxime Ripard   clk: sunxi: Move ...
86
87
88
89
90
91
92
93
94
95
96
97
98
  	mux->lock = &gmac_lock;
  
  	clk = clk_register_composite(NULL, clk_name,
  			parents, SUN7I_A20_GMAC_PARENTS,
  			&mux->hw, &clk_mux_ops,
  			NULL, NULL,
  			&gate->hw, &clk_gate_ops,
  			0);
  
  	if (IS_ERR(clk))
  		goto iounmap_reg;
  
  	of_clk_add_provider(node, of_clk_src_simple_get, clk);
59cb10e32   Maxime Ripard   clk: sunxi: Move ...
99
100
101
102
103
104
105
106
107
108
109
110
  
  	return;
  
  iounmap_reg:
  	iounmap(reg);
  free_gate:
  	kfree(gate);
  free_mux:
  	kfree(mux);
  }
  CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk",
  		sun7i_a20_gmac_clk_setup);