Commit b3e5464e authored by Joakim Tjernlund's avatar Joakim Tjernlund Committed by David S. Miller

Fixed PHY: Add fixed_phy_change_carrier()

Drivers can use this as .ndo_change_carrier() to change carrier
via /sys/class/net/ethX/carrier.
Signed-off-by: default avatarJoakim Tjernlund <joakim.tjernlund@infinera.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4beaacc6
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/seqlock.h> #include <linux/seqlock.h>
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/netdevice.h>
#include "swphy.h" #include "swphy.h"
...@@ -38,6 +39,7 @@ struct fixed_phy { ...@@ -38,6 +39,7 @@ struct fixed_phy {
struct phy_device *phydev; struct phy_device *phydev;
seqcount_t seqcount; seqcount_t seqcount;
struct fixed_phy_status status; struct fixed_phy_status status;
bool no_carrier;
int (*link_update)(struct net_device *, struct fixed_phy_status *); int (*link_update)(struct net_device *, struct fixed_phy_status *);
struct list_head node; struct list_head node;
int link_gpio; int link_gpio;
...@@ -48,9 +50,28 @@ static struct fixed_mdio_bus platform_fmb = { ...@@ -48,9 +50,28 @@ static struct fixed_mdio_bus platform_fmb = {
.phys = LIST_HEAD_INIT(platform_fmb.phys), .phys = LIST_HEAD_INIT(platform_fmb.phys),
}; };
int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier)
{
struct fixed_mdio_bus *fmb = &platform_fmb;
struct phy_device *phydev = dev->phydev;
struct fixed_phy *fp;
if (!phydev || !phydev->mdio.bus)
return -EINVAL;
list_for_each_entry(fp, &fmb->phys, node) {
if (fp->addr == phydev->mdio.addr) {
fp->no_carrier = !new_carrier;
return 0;
}
}
return -EINVAL;
}
EXPORT_SYMBOL_GPL(fixed_phy_change_carrier);
static void fixed_phy_update(struct fixed_phy *fp) static void fixed_phy_update(struct fixed_phy *fp)
{ {
if (gpio_is_valid(fp->link_gpio)) if (!fp->no_carrier && gpio_is_valid(fp->link_gpio))
fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio); fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio);
} }
...@@ -66,6 +87,7 @@ static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num) ...@@ -66,6 +87,7 @@ static int fixed_mdio_read(struct mii_bus *bus, int phy_addr, int reg_num)
do { do {
s = read_seqcount_begin(&fp->seqcount); s = read_seqcount_begin(&fp->seqcount);
fp->status.link = !fp->no_carrier;
/* Issue callback if user registered it. */ /* Issue callback if user registered it. */
if (fp->link_update) { if (fp->link_update) {
fp->link_update(fp->phydev->attached_dev, fp->link_update(fp->phydev->attached_dev,
......
...@@ -13,6 +13,7 @@ struct fixed_phy_status { ...@@ -13,6 +13,7 @@ struct fixed_phy_status {
struct device_node; struct device_node;
#if IS_ENABLED(CONFIG_FIXED_PHY) #if IS_ENABLED(CONFIG_FIXED_PHY)
extern int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier);
extern int fixed_phy_add(unsigned int irq, int phy_id, extern int fixed_phy_add(unsigned int irq, int phy_id,
struct fixed_phy_status *status, struct fixed_phy_status *status,
int link_gpio); int link_gpio);
...@@ -47,6 +48,10 @@ static inline int fixed_phy_set_link_update(struct phy_device *phydev, ...@@ -47,6 +48,10 @@ static inline int fixed_phy_set_link_update(struct phy_device *phydev,
{ {
return -ENODEV; return -ENODEV;
} }
static inline int fixed_phy_change_carrier(struct net_device *dev, bool new_carrier)
{
return -EINVAL;
}
#endif /* CONFIG_FIXED_PHY */ #endif /* CONFIG_FIXED_PHY */
#endif /* __PHY_FIXED_H */ #endif /* __PHY_FIXED_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment