aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Petazzoni <thomas.petazzoni@free-electrons.com>2014-05-16 10:14:04 -0400
committerDavid S. Miller <davem@davemloft.net>2014-05-16 17:18:49 -0400
commita75951217472c522c324adb0a4de3ba69d656ef5 (patch)
tree5202fc459802039f73709b959fecedca4d539353
parent9b744942290c168287013f0a19ff7392f65c8107 (diff)
net: phy: extend fixed driver with fixed_phy_register()
The existing fixed_phy_add() function has several drawbacks that prevents it from being used as is for OF-based declaration of fixed PHYs: * The address of the PHY on the fake bus needs to be passed, while a dynamic allocation is desired. * Since the phy_device instantiation is post-poned until the next mdiobus scan, there is no way to associate the fixed PHY with its OF node, which later prevents of_phy_connect() from finding this fixed PHY from a given OF node. To solve this, this commit introduces fixed_phy_register(), which will allocate an available PHY address, add the PHY using fixed_phy_add() and instantiate the phy_device structure associated with the provided OF node. Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Acked-by: Florian Fainelli <f.fainelli@gmail.com> Acked-by: Grant Likely <grant.likely@linaro.org> Tested-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/phy/fixed.c61
-rw-r--r--include/linux/phy_fixed.h11
2 files changed, 72 insertions, 0 deletions
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index e41546da105e..d60d875cb445 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -21,6 +21,7 @@
21#include <linux/phy_fixed.h> 21#include <linux/phy_fixed.h>
22#include <linux/err.h> 22#include <linux/err.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/of.h>
24 25
25#define MII_REGS_NUM 29 26#define MII_REGS_NUM 29
26 27
@@ -203,6 +204,66 @@ err_regs:
203} 204}
204EXPORT_SYMBOL_GPL(fixed_phy_add); 205EXPORT_SYMBOL_GPL(fixed_phy_add);
205 206
207void fixed_phy_del(int phy_addr)
208{
209 struct fixed_mdio_bus *fmb = &platform_fmb;
210 struct fixed_phy *fp, *tmp;
211
212 list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
213 if (fp->addr == phy_addr) {
214 list_del(&fp->node);
215 kfree(fp);
216 return;
217 }
218 }
219}
220EXPORT_SYMBOL_GPL(fixed_phy_del);
221
222static int phy_fixed_addr;
223static DEFINE_SPINLOCK(phy_fixed_addr_lock);
224
225int fixed_phy_register(unsigned int irq,
226 struct fixed_phy_status *status,
227 struct device_node *np)
228{
229 struct fixed_mdio_bus *fmb = &platform_fmb;
230 struct phy_device *phy;
231 int phy_addr;
232 int ret;
233
234 /* Get the next available PHY address, up to PHY_MAX_ADDR */
235 spin_lock(&phy_fixed_addr_lock);
236 if (phy_fixed_addr == PHY_MAX_ADDR) {
237 spin_unlock(&phy_fixed_addr_lock);
238 return -ENOSPC;
239 }
240 phy_addr = phy_fixed_addr++;
241 spin_unlock(&phy_fixed_addr_lock);
242
243 ret = fixed_phy_add(PHY_POLL, phy_addr, status);
244 if (ret < 0)
245 return ret;
246
247 phy = get_phy_device(fmb->mii_bus, phy_addr, false);
248 if (!phy || IS_ERR(phy)) {
249 fixed_phy_del(phy_addr);
250 return -EINVAL;
251 }
252
253 of_node_get(np);
254 phy->dev.of_node = np;
255
256 ret = phy_device_register(phy);
257 if (ret) {
258 phy_device_free(phy);
259 of_node_put(np);
260 fixed_phy_del(phy_addr);
261 return ret;
262 }
263
264 return 0;
265}
266
206static int __init fixed_mdio_bus_init(void) 267static int __init fixed_mdio_bus_init(void)
207{ 268{
208 struct fixed_mdio_bus *fmb = &platform_fmb; 269 struct fixed_mdio_bus *fmb = &platform_fmb;
diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h
index 509d8f5f984e..4f2478b47136 100644
--- a/include/linux/phy_fixed.h
+++ b/include/linux/phy_fixed.h
@@ -9,15 +9,26 @@ struct fixed_phy_status {
9 int asym_pause; 9 int asym_pause;
10}; 10};
11 11
12struct device_node;
13
12#ifdef CONFIG_FIXED_PHY 14#ifdef CONFIG_FIXED_PHY
13extern int fixed_phy_add(unsigned int irq, int phy_id, 15extern int fixed_phy_add(unsigned int irq, int phy_id,
14 struct fixed_phy_status *status); 16 struct fixed_phy_status *status);
17extern int fixed_phy_register(unsigned int irq,
18 struct fixed_phy_status *status,
19 struct device_node *np);
15#else 20#else
16static inline int fixed_phy_add(unsigned int irq, int phy_id, 21static inline int fixed_phy_add(unsigned int irq, int phy_id,
17 struct fixed_phy_status *status) 22 struct fixed_phy_status *status)
18{ 23{
19 return -ENODEV; 24 return -ENODEV;
20} 25}
26static inline int fixed_phy_register(unsigned int irq,
27 struct fixed_phy_status *status,
28 struct device_node *np)
29{
30 return -ENODEV;
31}
21#endif /* CONFIG_FIXED_PHY */ 32#endif /* CONFIG_FIXED_PHY */
22 33
23/* 34/*