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

phy: fixed_phy: Add gpio to determine link up/down.

An SFP module may have a link up/down status pin which can be
connection to a GPIO line of the host. Add support for reading such an
GPIO in the fixed_phy driver.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Andrew Lunn and committed by
David S. Miller
a5597008 8b59d19e

+59 -15
+13 -1
Documentation/devicetree/bindings/net/fixed-link.txt
··· 17 17 enabled. 18 18 * 'asym-pause' (boolean, optional), to indicate that asym_pause should 19 19 be enabled. 20 + * 'link-gpios' ('gpio-list', optional), to indicate if a gpio can be read 21 + to determine if the link is up. 20 22 21 23 Old, deprecated 'fixed-link' binding: 22 24 ··· 32 30 - e: asymmetric pause configuration: 0 for no asymmetric pause, 1 for 33 31 asymmetric pause 34 32 35 - Example: 33 + Examples: 36 34 37 35 ethernet@0 { 38 36 ... 39 37 fixed-link { 40 38 speed = <1000>; 41 39 full-duplex; 40 + }; 41 + ... 42 + }; 43 + 44 + ethernet@1 { 45 + ... 46 + fixed-link { 47 + speed = <1000>; 48 + pause; 49 + link-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; 42 50 }; 43 51 ... 44 52 };
+1 -1
Documentation/networking/stmmac.txt
··· 254 254 255 255 During the board's device_init we can configure the first 256 256 MAC for fixed_link by calling: 257 - fixed_phy_add(PHY_POLL, 1, &stmmac0_fixed_phy_status));) 257 + fixed_phy_add(PHY_POLL, 1, &stmmac0_fixed_phy_status, -1); 258 258 and the second one, with a real PHY device attached to the bus, 259 259 by using the stmmac_mdio_bus_data structure (to provide the id, the 260 260 reset procedure etc).
+1 -1
arch/m68k/coldfire/m5272.c
··· 126 126 static int __init init_BSP(void) 127 127 { 128 128 m5272_uarts_init(); 129 - fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status); 129 + fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status, -1); 130 130 return 0; 131 131 } 132 132
+3 -2
arch/mips/ar7/platform.c
··· 679 679 } 680 680 681 681 if (ar7_has_high_cpmac()) { 682 - res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status); 682 + res = fixed_phy_add(PHY_POLL, cpmac_high.id, 683 + &fixed_phy_status, -1); 683 684 if (!res) { 684 685 cpmac_get_mac(1, cpmac_high_data.dev_addr); 685 686 ··· 693 692 } else 694 693 cpmac_low_data.phy_mask = 0xffffffff; 695 694 696 - res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status); 695 + res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status, -1); 697 696 if (!res) { 698 697 cpmac_get_mac(0, cpmac_low_data.dev_addr); 699 698 res = platform_device_register(&cpmac_low);
+1 -1
arch/mips/bcm47xx/setup.c
··· 263 263 bcm47xx_leds_register(); 264 264 bcm47xx_workarounds(); 265 265 266 - fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status); 266 + fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status, -1); 267 267 return 0; 268 268 } 269 269 device_initcall(bcm47xx_register_bus_complete);
+1 -1
drivers/net/ethernet/broadcom/genet/bcmmii.c
··· 585 585 .asym_pause = 0, 586 586 }; 587 587 588 - phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL); 588 + phydev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL); 589 589 if (!phydev || IS_ERR(phydev)) { 590 590 dev_err(kdev, "failed to register fixed PHY device\n"); 591 591 return -ENODEV;
+23 -3
drivers/net/phy/fixed_phy.c
··· 22 22 #include <linux/err.h> 23 23 #include <linux/slab.h> 24 24 #include <linux/of.h> 25 + #include <linux/gpio.h> 25 26 26 27 #define MII_REGS_NUM 29 27 28 ··· 39 38 struct fixed_phy_status status; 40 39 int (*link_update)(struct net_device *, struct fixed_phy_status *); 41 40 struct list_head node; 41 + int link_gpio; 42 42 }; 43 43 44 44 static struct platform_device *pdev; ··· 53 51 u16 bmcr = 0; 54 52 u16 lpagb = 0; 55 53 u16 lpa = 0; 54 + 55 + if (gpio_is_valid(fp->link_gpio)) 56 + fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio); 56 57 57 58 if (!fp->status.link) 58 59 goto done; ··· 220 215 EXPORT_SYMBOL(fixed_phy_update_state); 221 216 222 217 int fixed_phy_add(unsigned int irq, int phy_addr, 223 - struct fixed_phy_status *status) 218 + struct fixed_phy_status *status, 219 + int link_gpio) 224 220 { 225 221 int ret; 226 222 struct fixed_mdio_bus *fmb = &platform_fmb; ··· 237 231 238 232 fp->addr = phy_addr; 239 233 fp->status = *status; 234 + fp->link_gpio = link_gpio; 235 + 236 + if (gpio_is_valid(fp->link_gpio)) { 237 + ret = gpio_request_one(fp->link_gpio, GPIOF_DIR_IN, 238 + "fixed-link-gpio-link"); 239 + if (ret) 240 + goto err_regs; 241 + } 240 242 241 243 ret = fixed_phy_update_regs(fp); 242 244 if (ret) 243 - goto err_regs; 245 + goto err_gpio; 244 246 245 247 list_add_tail(&fp->node, &fmb->phys); 246 248 247 249 return 0; 248 250 251 + err_gpio: 252 + if (gpio_is_valid(fp->link_gpio)) 253 + gpio_free(fp->link_gpio); 249 254 err_regs: 250 255 kfree(fp); 251 256 return ret; ··· 271 254 list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { 272 255 if (fp->addr == phy_addr) { 273 256 list_del(&fp->node); 257 + if (gpio_is_valid(fp->link_gpio)) 258 + gpio_free(fp->link_gpio); 274 259 kfree(fp); 275 260 return; 276 261 } ··· 285 266 286 267 struct phy_device *fixed_phy_register(unsigned int irq, 287 268 struct fixed_phy_status *status, 269 + int link_gpio, 288 270 struct device_node *np) 289 271 { 290 272 struct fixed_mdio_bus *fmb = &platform_fmb; ··· 302 282 phy_addr = phy_fixed_addr++; 303 283 spin_unlock(&phy_fixed_addr_lock); 304 284 305 - ret = fixed_phy_add(PHY_POLL, phy_addr, status); 285 + ret = fixed_phy_add(PHY_POLL, phy_addr, status, link_gpio); 306 286 if (ret < 0) 307 287 return ERR_PTR(ret); 308 288
+10 -3
drivers/of/of_mdio.c
··· 16 16 #include <linux/phy.h> 17 17 #include <linux/phy_fixed.h> 18 18 #include <linux/of.h> 19 + #include <linux/of_gpio.h> 19 20 #include <linux/of_irq.h> 20 21 #include <linux/of_mdio.h> 21 22 #include <linux/module.h> ··· 295 294 struct fixed_phy_status status = {}; 296 295 struct device_node *fixed_link_node; 297 296 const __be32 *fixed_link_prop; 297 + int link_gpio; 298 298 int len, err; 299 299 struct phy_device *phy; 300 300 const char *managed; ··· 304 302 if (err == 0) { 305 303 if (strcmp(managed, "in-band-status") == 0) { 306 304 /* status is zeroed, namely its .link member */ 307 - phy = fixed_phy_register(PHY_POLL, &status, np); 305 + phy = fixed_phy_register(PHY_POLL, &status, -1, np); 308 306 return IS_ERR(phy) ? PTR_ERR(phy) : 0; 309 307 } 310 308 } ··· 320 318 status.pause = of_property_read_bool(fixed_link_node, "pause"); 321 319 status.asym_pause = of_property_read_bool(fixed_link_node, 322 320 "asym-pause"); 321 + link_gpio = of_get_named_gpio_flags(fixed_link_node, 322 + "link-gpios", 0, NULL); 323 323 of_node_put(fixed_link_node); 324 - phy = fixed_phy_register(PHY_POLL, &status, np); 324 + if (link_gpio == -EPROBE_DEFER) 325 + return -EPROBE_DEFER; 326 + 327 + phy = fixed_phy_register(PHY_POLL, &status, link_gpio, np); 325 328 return IS_ERR(phy) ? PTR_ERR(phy) : 0; 326 329 } 327 330 ··· 338 331 status.speed = be32_to_cpu(fixed_link_prop[2]); 339 332 status.pause = be32_to_cpu(fixed_link_prop[3]); 340 333 status.asym_pause = be32_to_cpu(fixed_link_prop[4]); 341 - phy = fixed_phy_register(PHY_POLL, &status, np); 334 + phy = fixed_phy_register(PHY_POLL, &status, -1, np); 342 335 return IS_ERR(phy) ? PTR_ERR(phy) : 0; 343 336 } 344 337
+6 -2
include/linux/phy_fixed.h
··· 13 13 14 14 #if IS_ENABLED(CONFIG_FIXED_PHY) 15 15 extern int fixed_phy_add(unsigned int irq, int phy_id, 16 - struct fixed_phy_status *status); 16 + struct fixed_phy_status *status, 17 + int link_gpio); 17 18 extern struct phy_device *fixed_phy_register(unsigned int irq, 18 19 struct fixed_phy_status *status, 20 + int link_gpio, 19 21 struct device_node *np); 20 22 extern void fixed_phy_del(int phy_addr); 21 23 extern int fixed_phy_set_link_update(struct phy_device *phydev, ··· 28 26 const struct fixed_phy_status *changed); 29 27 #else 30 28 static inline int fixed_phy_add(unsigned int irq, int phy_id, 31 - struct fixed_phy_status *status) 29 + struct fixed_phy_status *status, 30 + int link_gpio) 32 31 { 33 32 return -ENODEV; 34 33 } 35 34 static inline struct phy_device *fixed_phy_register(unsigned int irq, 36 35 struct fixed_phy_status *status, 36 + int gpio_link, 37 37 struct device_node *np) 38 38 { 39 39 return ERR_PTR(-ENODEV);