Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Thomas Petazzoni and committed by
David S. Miller
a7595121 9b744942

+72
+61
drivers/net/phy/fixed.c
··· 21 21 #include <linux/phy_fixed.h> 22 22 #include <linux/err.h> 23 23 #include <linux/slab.h> 24 + #include <linux/of.h> 24 25 25 26 #define MII_REGS_NUM 29 26 27 ··· 203 202 return ret; 204 203 } 205 204 EXPORT_SYMBOL_GPL(fixed_phy_add); 205 + 206 + void fixed_phy_del(int phy_addr) 207 + { 208 + struct fixed_mdio_bus *fmb = &platform_fmb; 209 + struct fixed_phy *fp, *tmp; 210 + 211 + list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { 212 + if (fp->addr == phy_addr) { 213 + list_del(&fp->node); 214 + kfree(fp); 215 + return; 216 + } 217 + } 218 + } 219 + EXPORT_SYMBOL_GPL(fixed_phy_del); 220 + 221 + static int phy_fixed_addr; 222 + static DEFINE_SPINLOCK(phy_fixed_addr_lock); 223 + 224 + int fixed_phy_register(unsigned int irq, 225 + struct fixed_phy_status *status, 226 + struct device_node *np) 227 + { 228 + struct fixed_mdio_bus *fmb = &platform_fmb; 229 + struct phy_device *phy; 230 + int phy_addr; 231 + int ret; 232 + 233 + /* Get the next available PHY address, up to PHY_MAX_ADDR */ 234 + spin_lock(&phy_fixed_addr_lock); 235 + if (phy_fixed_addr == PHY_MAX_ADDR) { 236 + spin_unlock(&phy_fixed_addr_lock); 237 + return -ENOSPC; 238 + } 239 + phy_addr = phy_fixed_addr++; 240 + spin_unlock(&phy_fixed_addr_lock); 241 + 242 + ret = fixed_phy_add(PHY_POLL, phy_addr, status); 243 + if (ret < 0) 244 + return ret; 245 + 246 + phy = get_phy_device(fmb->mii_bus, phy_addr, false); 247 + if (!phy || IS_ERR(phy)) { 248 + fixed_phy_del(phy_addr); 249 + return -EINVAL; 250 + } 251 + 252 + of_node_get(np); 253 + phy->dev.of_node = np; 254 + 255 + ret = phy_device_register(phy); 256 + if (ret) { 257 + phy_device_free(phy); 258 + of_node_put(np); 259 + fixed_phy_del(phy_addr); 260 + return ret; 261 + } 262 + 263 + return 0; 264 + } 206 265 207 266 static int __init fixed_mdio_bus_init(void) 208 267 {
+11
include/linux/phy_fixed.h
··· 9 9 int asym_pause; 10 10 }; 11 11 12 + struct device_node; 13 + 12 14 #ifdef CONFIG_FIXED_PHY 13 15 extern int fixed_phy_add(unsigned int irq, int phy_id, 14 16 struct fixed_phy_status *status); 17 + extern int fixed_phy_register(unsigned int irq, 18 + struct fixed_phy_status *status, 19 + struct device_node *np); 15 20 #else 16 21 static inline int fixed_phy_add(unsigned int irq, int phy_id, 17 22 struct fixed_phy_status *status) 23 + { 24 + return -ENODEV; 25 + } 26 + static inline int fixed_phy_register(unsigned int irq, 27 + struct fixed_phy_status *status, 28 + struct device_node *np) 18 29 { 19 30 return -ENODEV; 20 31 }