diff options
author | Andrew Lunn <andrew@lunn.ch> | 2015-08-31 09:56:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-31 17:48:02 -0400 |
commit | a5597008dbc230876db2d344561d634f4d52ea4a (patch) | |
tree | 5c3d98a0f89ba1590c251eef871074161271aa72 | |
parent | 8b59d19e749b8cb454b7912396c2a6a1b91b9d30 (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.txt | 14 | ||||
-rw-r--r-- | Documentation/networking/stmmac.txt | 2 | ||||
-rw-r--r-- | arch/m68k/coldfire/m5272.c | 2 | ||||
-rw-r--r-- | arch/mips/ar7/platform.c | 5 | ||||
-rw-r--r-- | arch/mips/bcm47xx/setup.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 | ||||
-rw-r--r-- | drivers/net/phy/fixed_phy.c | 26 | ||||
-rw-r--r-- | drivers/of/of_mdio.c | 13 | ||||
-rw-r--r-- | include/linux/phy_fixed.h | 8 |
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 | ||
21 | Old, deprecated 'fixed-link' binding: | 23 | Old, 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 | ||
33 | Example: | 35 | Examples: |
34 | 36 | ||
35 | ethernet@0 { | 37 | ethernet@0 { |
36 | ... | 38 | ... |
@@ -40,3 +42,13 @@ ethernet@0 { | |||
40 | }; | 42 | }; |
41 | ... | 43 | ... |
42 | }; | 44 | }; |
45 | |||
46 | ethernet@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 | ||
255 | During the board's device_init we can configure the first | 255 | During the board's device_init we can configure the first |
256 | MAC for fixed_link by calling: | 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 | and the second one, with a real PHY device attached to the bus, | 258 | and the second one, with a real PHY device attached to the bus, |
259 | by using the stmmac_mdio_bus_data structure (to provide the id, the | 259 | by using the stmmac_mdio_bus_data structure (to provide the id, the |
260 | reset procedure etc). | 260 | reset 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 = { | |||
126 | static int __init init_BSP(void) | 126 | static 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 | } |
269 | device_initcall(bcm47xx_register_bus_complete); | 269 | device_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 | ||
43 | static struct platform_device *pdev; | 45 | static 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, | |||
215 | EXPORT_SYMBOL(fixed_phy_update_state); | 220 | EXPORT_SYMBOL(fixed_phy_update_state); |
216 | 221 | ||
217 | int fixed_phy_add(unsigned int irq, int phy_addr, | 222 | int 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 | ||
257 | err_gpio: | ||
258 | if (gpio_is_valid(fp->link_gpio)) | ||
259 | gpio_free(fp->link_gpio); | ||
243 | err_regs: | 260 | err_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 | ||
267 | struct phy_device *fixed_phy_register(unsigned int irq, | 286 | struct 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) |
15 | extern int fixed_phy_add(unsigned int irq, int phy_id, | 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 | extern struct phy_device *fixed_phy_register(unsigned int irq, | 18 | extern 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); |
20 | extern void fixed_phy_del(int phy_addr); | 22 | extern void fixed_phy_del(int phy_addr); |
21 | extern int fixed_phy_set_link_update(struct phy_device *phydev, | 23 | extern 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 |
28 | static inline int fixed_phy_add(unsigned int irq, int phy_id, | 30 | static 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 | } |
33 | static inline struct phy_device *fixed_phy_register(unsigned int irq, | 36 | static 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); |