aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Lunn <andrew@lunn.ch>2015-08-31 09:56:53 -0400
committerDavid S. Miller <davem@davemloft.net>2015-08-31 17:48:02 -0400
commita5597008dbc230876db2d344561d634f4d52ea4a (patch)
tree5c3d98a0f89ba1590c251eef871074161271aa72
parent8b59d19e749b8cb454b7912396c2a6a1b91b9d30 (diff)
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>
-rw-r--r--Documentation/devicetree/bindings/net/fixed-link.txt14
-rw-r--r--Documentation/networking/stmmac.txt2
-rw-r--r--arch/m68k/coldfire/m5272.c2
-rw-r--r--arch/mips/ar7/platform.c5
-rw-r--r--arch/mips/bcm47xx/setup.c2
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c2
-rw-r--r--drivers/net/phy/fixed_phy.c26
-rw-r--r--drivers/of/of_mdio.c13
-rw-r--r--include/linux/phy_fixed.h8
9 files changed, 59 insertions, 15 deletions
diff --git a/Documentation/devicetree/bindings/net/fixed-link.txt b/Documentation/devicetree/bindings/net/fixed-link.txt
index 82bf7e0f47b6..ec5d889fe3d8 100644
--- a/Documentation/devicetree/bindings/net/fixed-link.txt
+++ b/Documentation/devicetree/bindings/net/fixed-link.txt
@@ -17,6 +17,8 @@ properties:
17 enabled. 17 enabled.
18* 'asym-pause' (boolean, optional), to indicate that asym_pause should 18* 'asym-pause' (boolean, optional), to indicate that asym_pause should
19 be enabled. 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
21Old, deprecated 'fixed-link' binding: 23Old, deprecated 'fixed-link' binding:
22 24
@@ -30,7 +32,7 @@ Old, deprecated 'fixed-link' binding:
30 - e: asymmetric pause configuration: 0 for no asymmetric pause, 1 for 32 - e: asymmetric pause configuration: 0 for no asymmetric pause, 1 for
31 asymmetric pause 33 asymmetric pause
32 34
33Example: 35Examples:
34 36
35ethernet@0 { 37ethernet@0 {
36 ... 38 ...
@@ -40,3 +42,13 @@ ethernet@0 {
40 }; 42 };
41 ... 43 ...
42}; 44};
45
46ethernet@1 {
47 ...
48 fixed-link {
49 speed = <1000>;
50 pause;
51 link-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
52 };
53 ...
54};
diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt
index 2903b1cf4d70..d64a14714236 100644
--- a/Documentation/networking/stmmac.txt
+++ b/Documentation/networking/stmmac.txt
@@ -254,7 +254,7 @@ static struct fixed_phy_status stmmac0_fixed_phy_status = {
254 254
255During the board's device_init we can configure the first 255During the board's device_init we can configure the first
256MAC for fixed_link by calling: 256MAC 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);
258and the second one, with a real PHY device attached to the bus, 258and the second one, with a real PHY device attached to the bus,
259by using the stmmac_mdio_bus_data structure (to provide the id, the 259by using the stmmac_mdio_bus_data structure (to provide the id, the
260reset procedure etc). 260reset procedure etc).
diff --git a/arch/m68k/coldfire/m5272.c b/arch/m68k/coldfire/m5272.c
index b15219ed22bf..c525e4c08f84 100644
--- a/arch/m68k/coldfire/m5272.c
+++ b/arch/m68k/coldfire/m5272.c
@@ -126,7 +126,7 @@ static struct fixed_phy_status nettel_fixed_phy_status __initdata = {
126static int __init init_BSP(void) 126static int __init init_BSP(void)
127{ 127{
128 m5272_uarts_init(); 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 return 0; 130 return 0;
131} 131}
132 132
diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c
index be9ff1673ded..298b97715d5f 100644
--- a/arch/mips/ar7/platform.c
+++ b/arch/mips/ar7/platform.c
@@ -679,7 +679,8 @@ static int __init ar7_register_devices(void)
679 } 679 }
680 680
681 if (ar7_has_high_cpmac()) { 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 if (!res) { 684 if (!res) {
684 cpmac_get_mac(1, cpmac_high_data.dev_addr); 685 cpmac_get_mac(1, cpmac_high_data.dev_addr);
685 686
@@ -692,7 +693,7 @@ static int __init ar7_register_devices(void)
692 } else 693 } else
693 cpmac_low_data.phy_mask = 0xffffffff; 694 cpmac_low_data.phy_mask = 0xffffffff;
694 695
695 res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status); 696 res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status, -1);
696 if (!res) { 697 if (!res) {
697 cpmac_get_mac(0, cpmac_low_data.dev_addr); 698 cpmac_get_mac(0, cpmac_low_data.dev_addr);
698 res = platform_device_register(&cpmac_low); 699 res = platform_device_register(&cpmac_low);
diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c
index 98c075f81795..17503a05938e 100644
--- a/arch/mips/bcm47xx/setup.c
+++ b/arch/mips/bcm47xx/setup.c
@@ -263,7 +263,7 @@ static int __init bcm47xx_register_bus_complete(void)
263 bcm47xx_leds_register(); 263 bcm47xx_leds_register();
264 bcm47xx_workarounds(); 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 return 0; 267 return 0;
268} 268}
269device_initcall(bcm47xx_register_bus_complete); 269device_initcall(bcm47xx_register_bus_complete);
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index b3679ad1c1c7..c8affad76f36 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -585,7 +585,7 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv)
585 .asym_pause = 0, 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 if (!phydev || IS_ERR(phydev)) { 589 if (!phydev || IS_ERR(phydev)) {
590 dev_err(kdev, "failed to register fixed PHY device\n"); 590 dev_err(kdev, "failed to register fixed PHY device\n");
591 return -ENODEV; 591 return -ENODEV;
diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c
index 2f9457f05a2e..1bb70e3cc03e 100644
--- a/drivers/net/phy/fixed_phy.c
+++ b/drivers/net/phy/fixed_phy.c
@@ -22,6 +22,7 @@
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#include <linux/of.h>
25#include <linux/gpio.h>
25 26
26#define MII_REGS_NUM 29 27#define MII_REGS_NUM 29
27 28
@@ -38,6 +39,7 @@ struct fixed_phy {
38 struct fixed_phy_status status; 39 struct fixed_phy_status status;
39 int (*link_update)(struct net_device *, struct fixed_phy_status *); 40 int (*link_update)(struct net_device *, struct fixed_phy_status *);
40 struct list_head node; 41 struct list_head node;
42 int link_gpio;
41}; 43};
42 44
43static struct platform_device *pdev; 45static struct platform_device *pdev;
@@ -52,6 +54,9 @@ static int fixed_phy_update_regs(struct fixed_phy *fp)
52 u16 lpagb = 0; 54 u16 lpagb = 0;
53 u16 lpa = 0; 55 u16 lpa = 0;
54 56
57 if (gpio_is_valid(fp->link_gpio))
58 fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio);
59
55 if (!fp->status.link) 60 if (!fp->status.link)
56 goto done; 61 goto done;
57 bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; 62 bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
@@ -215,7 +220,8 @@ int fixed_phy_update_state(struct phy_device *phydev,
215EXPORT_SYMBOL(fixed_phy_update_state); 220EXPORT_SYMBOL(fixed_phy_update_state);
216 221
217int fixed_phy_add(unsigned int irq, int phy_addr, 222int fixed_phy_add(unsigned int irq, int phy_addr,
218 struct fixed_phy_status *status) 223 struct fixed_phy_status *status,
224 int link_gpio)
219{ 225{
220 int ret; 226 int ret;
221 struct fixed_mdio_bus *fmb = &platform_fmb; 227 struct fixed_mdio_bus *fmb = &platform_fmb;
@@ -231,15 +237,26 @@ int fixed_phy_add(unsigned int irq, int phy_addr,
231 237
232 fp->addr = phy_addr; 238 fp->addr = phy_addr;
233 fp->status = *status; 239 fp->status = *status;
240 fp->link_gpio = link_gpio;
241
242 if (gpio_is_valid(fp->link_gpio)) {
243 ret = gpio_request_one(fp->link_gpio, GPIOF_DIR_IN,
244 "fixed-link-gpio-link");
245 if (ret)
246 goto err_regs;
247 }
234 248
235 ret = fixed_phy_update_regs(fp); 249 ret = fixed_phy_update_regs(fp);
236 if (ret) 250 if (ret)
237 goto err_regs; 251 goto err_gpio;
238 252
239 list_add_tail(&fp->node, &fmb->phys); 253 list_add_tail(&fp->node, &fmb->phys);
240 254
241 return 0; 255 return 0;
242 256
257err_gpio:
258 if (gpio_is_valid(fp->link_gpio))
259 gpio_free(fp->link_gpio);
243err_regs: 260err_regs:
244 kfree(fp); 261 kfree(fp);
245 return ret; 262 return ret;
@@ -254,6 +271,8 @@ void fixed_phy_del(int phy_addr)
254 list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { 271 list_for_each_entry_safe(fp, tmp, &fmb->phys, node) {
255 if (fp->addr == phy_addr) { 272 if (fp->addr == phy_addr) {
256 list_del(&fp->node); 273 list_del(&fp->node);
274 if (gpio_is_valid(fp->link_gpio))
275 gpio_free(fp->link_gpio);
257 kfree(fp); 276 kfree(fp);
258 return; 277 return;
259 } 278 }
@@ -266,6 +285,7 @@ static DEFINE_SPINLOCK(phy_fixed_addr_lock);
266 285
267struct phy_device *fixed_phy_register(unsigned int irq, 286struct phy_device *fixed_phy_register(unsigned int irq,
268 struct fixed_phy_status *status, 287 struct fixed_phy_status *status,
288 int link_gpio,
269 struct device_node *np) 289 struct device_node *np)
270{ 290{
271 struct fixed_mdio_bus *fmb = &platform_fmb; 291 struct fixed_mdio_bus *fmb = &platform_fmb;
@@ -282,7 +302,7 @@ struct phy_device *fixed_phy_register(unsigned int irq,
282 phy_addr = phy_fixed_addr++; 302 phy_addr = phy_fixed_addr++;
283 spin_unlock(&phy_fixed_addr_lock); 303 spin_unlock(&phy_fixed_addr_lock);
284 304
285 ret = fixed_phy_add(PHY_POLL, phy_addr, status); 305 ret = fixed_phy_add(PHY_POLL, phy_addr, status, link_gpio);
286 if (ret < 0) 306 if (ret < 0)
287 return ERR_PTR(ret); 307 return ERR_PTR(ret);
288 308
diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c
index 7c8c23cc6896..1350fa25cdb0 100644
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -16,6 +16,7 @@
16#include <linux/phy.h> 16#include <linux/phy.h>
17#include <linux/phy_fixed.h> 17#include <linux/phy_fixed.h>
18#include <linux/of.h> 18#include <linux/of.h>
19#include <linux/of_gpio.h>
19#include <linux/of_irq.h> 20#include <linux/of_irq.h>
20#include <linux/of_mdio.h> 21#include <linux/of_mdio.h>
21#include <linux/module.h> 22#include <linux/module.h>
@@ -294,6 +295,7 @@ int of_phy_register_fixed_link(struct device_node *np)
294 struct fixed_phy_status status = {}; 295 struct fixed_phy_status status = {};
295 struct device_node *fixed_link_node; 296 struct device_node *fixed_link_node;
296 const __be32 *fixed_link_prop; 297 const __be32 *fixed_link_prop;
298 int link_gpio;
297 int len, err; 299 int len, err;
298 struct phy_device *phy; 300 struct phy_device *phy;
299 const char *managed; 301 const char *managed;
@@ -302,7 +304,7 @@ int of_phy_register_fixed_link(struct device_node *np)
302 if (err == 0) { 304 if (err == 0) {
303 if (strcmp(managed, "in-band-status") == 0) { 305 if (strcmp(managed, "in-band-status") == 0) {
304 /* status is zeroed, namely its .link member */ 306 /* status is zeroed, namely its .link member */
305 phy = fixed_phy_register(PHY_POLL, &status, np); 307 phy = fixed_phy_register(PHY_POLL, &status, -1, np);
306 return IS_ERR(phy) ? PTR_ERR(phy) : 0; 308 return IS_ERR(phy) ? PTR_ERR(phy) : 0;
307 } 309 }
308 } 310 }
@@ -318,8 +320,13 @@ int of_phy_register_fixed_link(struct device_node *np)
318 status.pause = of_property_read_bool(fixed_link_node, "pause"); 320 status.pause = of_property_read_bool(fixed_link_node, "pause");
319 status.asym_pause = of_property_read_bool(fixed_link_node, 321 status.asym_pause = of_property_read_bool(fixed_link_node,
320 "asym-pause"); 322 "asym-pause");
323 link_gpio = of_get_named_gpio_flags(fixed_link_node,
324 "link-gpios", 0, NULL);
321 of_node_put(fixed_link_node); 325 of_node_put(fixed_link_node);
322 phy = fixed_phy_register(PHY_POLL, &status, np); 326 if (link_gpio == -EPROBE_DEFER)
327 return -EPROBE_DEFER;
328
329 phy = fixed_phy_register(PHY_POLL, &status, link_gpio, np);
323 return IS_ERR(phy) ? PTR_ERR(phy) : 0; 330 return IS_ERR(phy) ? PTR_ERR(phy) : 0;
324 } 331 }
325 332
@@ -331,7 +338,7 @@ int of_phy_register_fixed_link(struct device_node *np)
331 status.speed = be32_to_cpu(fixed_link_prop[2]); 338 status.speed = be32_to_cpu(fixed_link_prop[2]);
332 status.pause = be32_to_cpu(fixed_link_prop[3]); 339 status.pause = be32_to_cpu(fixed_link_prop[3]);
333 status.asym_pause = be32_to_cpu(fixed_link_prop[4]); 340 status.asym_pause = be32_to_cpu(fixed_link_prop[4]);
334 phy = fixed_phy_register(PHY_POLL, &status, np); 341 phy = fixed_phy_register(PHY_POLL, &status, -1, np);
335 return IS_ERR(phy) ? PTR_ERR(phy) : 0; 342 return IS_ERR(phy) ? PTR_ERR(phy) : 0;
336 } 343 }
337 344
diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h
index fe5732d53eda..2400d2ea4f34 100644
--- a/include/linux/phy_fixed.h
+++ b/include/linux/phy_fixed.h
@@ -13,9 +13,11 @@ struct device_node;
13 13
14#if IS_ENABLED(CONFIG_FIXED_PHY) 14#if IS_ENABLED(CONFIG_FIXED_PHY)
15extern int fixed_phy_add(unsigned int irq, int phy_id, 15extern 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);
17extern struct phy_device *fixed_phy_register(unsigned int irq, 18extern struct phy_device *fixed_phy_register(unsigned int irq,
18 struct fixed_phy_status *status, 19 struct fixed_phy_status *status,
20 int link_gpio,
19 struct device_node *np); 21 struct device_node *np);
20extern void fixed_phy_del(int phy_addr); 22extern void fixed_phy_del(int phy_addr);
21extern int fixed_phy_set_link_update(struct phy_device *phydev, 23extern int fixed_phy_set_link_update(struct phy_device *phydev,
@@ -26,12 +28,14 @@ extern int fixed_phy_update_state(struct phy_device *phydev,
26 const struct fixed_phy_status *changed); 28 const struct fixed_phy_status *changed);
27#else 29#else
28static inline int fixed_phy_add(unsigned int irq, int phy_id, 30static inline int fixed_phy_add(unsigned int irq, int phy_id,
29 struct fixed_phy_status *status) 31 struct fixed_phy_status *status,
32 int link_gpio)
30{ 33{
31 return -ENODEV; 34 return -ENODEV;
32} 35}
33static inline struct phy_device *fixed_phy_register(unsigned int irq, 36static inline struct phy_device *fixed_phy_register(unsigned int irq,
34 struct fixed_phy_status *status, 37 struct fixed_phy_status *status,
38 int gpio_link,
35 struct device_node *np) 39 struct device_node *np)
36{ 40{
37 return ERR_PTR(-ENODEV); 41 return ERR_PTR(-ENODEV);