Blame view

drivers/of/of_mdio.c 4.93 KB
8bc487d15   Grant Likely   openfirmware: Add...
1
2
3
4
5
6
7
8
9
10
  /*
   * OF helpers for the MDIO (Ethernet PHY) API
   *
   * Copyright (c) 2009 Secret Lab Technologies, Ltd.
   *
   * This file is released under the GPLv2
   *
   * This file provides helper functions for extracting PHY device information
   * out of the OpenFirmware device tree and using it to populate an mii_bus.
   */
24c30dbbc   Anton Vorontsov   of/mdio: Add supp...
11
12
13
14
  #include <linux/kernel.h>
  #include <linux/device.h>
  #include <linux/netdevice.h>
  #include <linux/err.h>
8bc487d15   Grant Likely   openfirmware: Add...
15
16
  #include <linux/phy.h>
  #include <linux/of.h>
e38734449   Grant Likely   of/irq: Move irq_...
17
  #include <linux/of_irq.h>
8bc487d15   Grant Likely   openfirmware: Add...
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
46
47
48
49
50
51
52
53
  #include <linux/of_mdio.h>
  #include <linux/module.h>
  
  MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
  MODULE_LICENSE("GPL");
  
  /**
   * of_mdiobus_register - Register mii_bus and create PHYs from the device tree
   * @mdio: pointer to mii_bus structure
   * @np: pointer to device_node of MDIO bus.
   *
   * This function registers the mii_bus structure and registers a phy_device
   * for each child node of @np.
   */
  int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
  {
  	struct phy_device *phy;
  	struct device_node *child;
  	int rc, i;
  
  	/* Mask out all PHYs from auto probing.  Instead the PHYs listed in
  	 * the device tree are populated after the bus has been registered */
  	mdio->phy_mask = ~0;
  
  	/* Clear all the IRQ properties */
  	if (mdio->irq)
  		for (i=0; i<PHY_MAX_ADDR; i++)
  			mdio->irq[i] = PHY_POLL;
  
  	/* Register the MDIO bus */
  	rc = mdiobus_register(mdio);
  	if (rc)
  		return rc;
  
  	/* Loop over the child nodes and register a phy_device for each one */
  	for_each_child_of_node(np, child) {
194588604   David Daney   of/mdio: Fix some...
54
55
  		const __be32 *paddr;
  		u32 addr;
8bc487d15   Grant Likely   openfirmware: Add...
56
57
58
  		int len;
  
  		/* A PHY must have a reg property in the range [0-31] */
194588604   David Daney   of/mdio: Fix some...
59
60
  		paddr = of_get_property(child, "reg", &len);
  		if (!paddr || len < sizeof(*paddr)) {
8bc487d15   Grant Likely   openfirmware: Add...
61
62
63
64
65
  			dev_err(&mdio->dev, "%s has invalid PHY address
  ",
  				child->full_name);
  			continue;
  		}
194588604   David Daney   of/mdio: Fix some...
66
67
68
69
70
71
72
  		addr = be32_to_cpup(paddr);
  		if (addr >= 32) {
  			dev_err(&mdio->dev, "%s PHY address %i is too large
  ",
  				child->full_name, addr);
  			continue;
  		}
8bc487d15   Grant Likely   openfirmware: Add...
73
  		if (mdio->irq) {
194588604   David Daney   of/mdio: Fix some...
74
75
76
  			mdio->irq[addr] = irq_of_parse_and_map(child, 0);
  			if (!mdio->irq[addr])
  				mdio->irq[addr] = PHY_POLL;
8bc487d15   Grant Likely   openfirmware: Add...
77
  		}
194588604   David Daney   of/mdio: Fix some...
78
  		phy = get_phy_device(mdio, addr);
9bd73715a   Dan Carpenter   of: check for IS_...
79
  		if (!phy || IS_ERR(phy)) {
8bc487d15   Grant Likely   openfirmware: Add...
80
81
  			dev_err(&mdio->dev, "error probing PHY at address %i
  ",
194588604   David Daney   of/mdio: Fix some...
82
  				addr);
8bc487d15   Grant Likely   openfirmware: Add...
83
84
  			continue;
  		}
8bc487d15   Grant Likely   openfirmware: Add...
85
86
87
88
  
  		/* Associate the OF node with the device structure so it
  		 * can be looked up later */
  		of_node_get(child);
d706c1b05   Grant Likely   driver-core: Add ...
89
  		phy->dev.of_node = child;
8bc487d15   Grant Likely   openfirmware: Add...
90
91
92
93
94
95
96
97
98
99
100
  
  		/* All data is now stored in the phy struct; register it */
  		rc = phy_device_register(phy);
  		if (rc) {
  			phy_device_free(phy);
  			of_node_put(child);
  			continue;
  		}
  
  		dev_dbg(&mdio->dev, "registered phy %s at address %i
  ",
194588604   David Daney   of/mdio: Fix some...
101
  			child->name, addr);
8bc487d15   Grant Likely   openfirmware: Add...
102
103
104
105
106
  	}
  
  	return 0;
  }
  EXPORT_SYMBOL(of_mdiobus_register);
08a7963aa   Jérôme Pouiller   of: Remove nested...
107
108
109
  /* Helper function for of_phy_find_device */
  static int of_phy_match(struct device *dev, void *phy_np)
  {
61c7a080a   Grant Likely   of: Always use 's...
110
  	return dev->of_node == phy_np;
08a7963aa   Jérôme Pouiller   of: Remove nested...
111
  }
8bc487d15   Grant Likely   openfirmware: Add...
112
113
114
115
116
117
118
119
120
  /**
   * of_phy_find_device - Give a PHY node, find the phy_device
   * @phy_np: Pointer to the phy's device tree node
   *
   * Returns a pointer to the phy_device.
   */
  struct phy_device *of_phy_find_device(struct device_node *phy_np)
  {
  	struct device *d;
8bc487d15   Grant Likely   openfirmware: Add...
121
122
  	if (!phy_np)
  		return NULL;
08a7963aa   Jérôme Pouiller   of: Remove nested...
123
  	d = bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match);
8bc487d15   Grant Likely   openfirmware: Add...
124
125
126
127
128
129
130
131
132
133
134
  	return d ? to_phy_device(d) : NULL;
  }
  EXPORT_SYMBOL(of_phy_find_device);
  
  /**
   * of_phy_connect - Connect to the phy described in the device tree
   * @dev: pointer to net_device claiming the phy
   * @phy_np: Pointer to device tree node for the PHY
   * @hndlr: Link state callback for the network device
   * @iface: PHY data interface type
   *
25985edce   Lucas De Marchi   Fix common misspe...
135
   * Returns a pointer to the phy_device if successful.  NULL otherwise
8bc487d15   Grant Likely   openfirmware: Add...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
   */
  struct phy_device *of_phy_connect(struct net_device *dev,
  				  struct device_node *phy_np,
  				  void (*hndlr)(struct net_device *), u32 flags,
  				  phy_interface_t iface)
  {
  	struct phy_device *phy = of_phy_find_device(phy_np);
  
  	if (!phy)
  		return NULL;
  
  	return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy;
  }
  EXPORT_SYMBOL(of_phy_connect);
24c30dbbc   Anton Vorontsov   of/mdio: Add supp...
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  
  /**
   * of_phy_connect_fixed_link - Parse fixed-link property and return a dummy phy
   * @dev: pointer to net_device claiming the phy
   * @hndlr: Link state callback for the network device
   * @iface: PHY data interface type
   *
   * This function is a temporary stop-gap and will be removed soon.  It is
   * only to support the fs_enet, ucc_geth and gianfar Ethernet drivers.  Do
   * not call this function from new drivers.
   */
  struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
  					     void (*hndlr)(struct net_device *),
  					     phy_interface_t iface)
  {
  	struct device_node *net_np;
  	char bus_id[MII_BUS_ID_SIZE + 3];
  	struct phy_device *phy;
337148812   Jeremy Kerr   of: assume big-en...
168
  	const __be32 *phy_id;
24c30dbbc   Anton Vorontsov   of/mdio: Add supp...
169
170
171
172
  	int sz;
  
  	if (!dev->dev.parent)
  		return NULL;
61c7a080a   Grant Likely   of: Always use 's...
173
  	net_np = dev->dev.parent->of_node;
24c30dbbc   Anton Vorontsov   of/mdio: Add supp...
174
175
176
177
178
179
  	if (!net_np)
  		return NULL;
  
  	phy_id = of_get_property(net_np, "fixed-link", &sz);
  	if (!phy_id || sz < sizeof(*phy_id))
  		return NULL;
337148812   Jeremy Kerr   of: assume big-en...
180
  	sprintf(bus_id, PHY_ID_FMT, "0", be32_to_cpu(phy_id[0]));
24c30dbbc   Anton Vorontsov   of/mdio: Add supp...
181
182
183
184
185
  
  	phy = phy_connect(dev, bus_id, hndlr, 0, iface);
  	return IS_ERR(phy) ? NULL : phy;
  }
  EXPORT_SYMBOL(of_phy_connect_fixed_link);