1
2
3
4
5
6
7
8
9
10
11
12#include <linux/kernel.h>
13#include <linux/device.h>
14#include <linux/netdevice.h>
15#include <linux/err.h>
16#include <linux/phy.h>
17#include <linux/of.h>
18#include <linux/of_mdio.h>
19#include <linux/module.h>
20
21MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>");
22MODULE_LICENSE("GPL");
23
24
25
26
27
28
29
30
31
32int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
33{
34 struct phy_device *phy;
35 struct device_node *child;
36 int rc, i;
37
38
39
40 mdio->phy_mask = ~0;
41
42
43 if (mdio->irq)
44 for (i=0; i<PHY_MAX_ADDR; i++)
45 mdio->irq[i] = PHY_POLL;
46
47
48 rc = mdiobus_register(mdio);
49 if (rc)
50 return rc;
51
52
53 for_each_child_of_node(np, child) {
54 const u32 *addr;
55 int len;
56
57
58 addr = of_get_property(child, "reg", &len);
59 if (!addr || len < sizeof(*addr) || *addr >= 32 || *addr < 0) {
60 dev_err(&mdio->dev, "%s has invalid PHY address\n",
61 child->full_name);
62 continue;
63 }
64
65 if (mdio->irq) {
66 mdio->irq[*addr] = irq_of_parse_and_map(child, 0);
67 if (!mdio->irq[*addr])
68 mdio->irq[*addr] = PHY_POLL;
69 }
70
71 phy = get_phy_device(mdio, *addr);
72 if (!phy) {
73 dev_err(&mdio->dev, "error probing PHY at address %i\n",
74 *addr);
75 continue;
76 }
77 phy_scan_fixups(phy);
78
79
80
81 of_node_get(child);
82 dev_archdata_set_node(&phy->dev.archdata, child);
83
84
85 rc = phy_device_register(phy);
86 if (rc) {
87 phy_device_free(phy);
88 of_node_put(child);
89 continue;
90 }
91
92 dev_dbg(&mdio->dev, "registered phy %s at address %i\n",
93 child->name, *addr);
94 }
95
96 return 0;
97}
98EXPORT_SYMBOL(of_mdiobus_register);
99
100
101static int of_phy_match(struct device *dev, void *phy_np)
102{
103 return dev_archdata_get_node(&dev->archdata) == phy_np;
104}
105
106
107
108
109
110
111
112struct phy_device *of_phy_find_device(struct device_node *phy_np)
113{
114 struct device *d;
115 if (!phy_np)
116 return NULL;
117
118 d = bus_find_device(&mdio_bus_type, NULL, phy_np, of_phy_match);
119 return d ? to_phy_device(d) : NULL;
120}
121EXPORT_SYMBOL(of_phy_find_device);
122
123
124
125
126
127
128
129
130
131
132struct phy_device *of_phy_connect(struct net_device *dev,
133 struct device_node *phy_np,
134 void (*hndlr)(struct net_device *), u32 flags,
135 phy_interface_t iface)
136{
137 struct phy_device *phy = of_phy_find_device(phy_np);
138
139 if (!phy)
140 return NULL;
141
142 return phy_connect_direct(dev, phy, hndlr, flags, iface) ? NULL : phy;
143}
144EXPORT_SYMBOL(of_phy_connect);
145
146
147
148
149
150
151
152
153
154
155
156struct phy_device *of_phy_connect_fixed_link(struct net_device *dev,
157 void (*hndlr)(struct net_device *),
158 phy_interface_t iface)
159{
160 struct device_node *net_np;
161 char bus_id[MII_BUS_ID_SIZE + 3];
162 struct phy_device *phy;
163 const u32 *phy_id;
164 int sz;
165
166 if (!dev->dev.parent)
167 return NULL;
168
169 net_np = dev_archdata_get_node(&dev->dev.parent->archdata);
170 if (!net_np)
171 return NULL;
172
173 phy_id = of_get_property(net_np, "fixed-link", &sz);
174 if (!phy_id || sz < sizeof(*phy_id))
175 return NULL;
176
177 sprintf(bus_id, PHY_ID_FMT, "0", phy_id[0]);
178
179 phy = phy_connect(dev, bus_id, hndlr, 0, iface);
180 return IS_ERR(phy) ? NULL : phy;
181}
182EXPORT_SYMBOL(of_phy_connect_fixed_link);
183