Skip to content

Commit

Permalink
net: phy: allow to expose and i2c controller
Browse files Browse the repository at this point in the history
Signed-off-by: Antoine Tenart <antoine.tenart@bootlin.com>
  • Loading branch information
atenart committed Apr 1, 2020
1 parent 834e2c6 commit 61645af
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 0 deletions.
56 changes: 56 additions & 0 deletions drivers/net/phy/phy-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <linux/export.h>
#include <linux/phy.h>
#include <linux/of.h>
#include <linux/i2c.h>

const char *phy_speed_to_str(int speed)
{
Expand Down Expand Up @@ -303,6 +304,61 @@ void phy_resolve_aneg_pause(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(phy_resolve_aneg_pause);

static int mdio_i2c_master_xfer(struct i2c_adapter *adap,
struct i2c_msg msgs[], int num)
{
struct phy_device *phydev = adap->algo_data;

if (!phydev->drv->i2c_xfer)
return -EOPNOTSUPP;

return phydev->drv->i2c_xfer(phydev, msgs, num);
}

static u32 mdio_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
}

/* I2C support */
static struct i2c_algorithm mdio_i2c_algo = {
.master_xfer = mdio_i2c_master_xfer,
.functionality = mdio_i2c_func,
};

int of_phy_init_i2c(struct device *dev, struct device_node *node)
{
struct device_node *i2c_node;
struct i2c_adapter *adap;
int ret;

/* This is optional */
i2c_node = of_find_node_by_name(node, "i2c-controller");
if (!i2c_node)
return 0;

adap = kzalloc(sizeof(*adap), GFP_KERNEL);
if (!adap)
return -ENOMEM;

adap->owner = THIS_MODULE;
adap->dev.of_node = i2c_node;
adap->algo = &mdio_i2c_algo;
adap->timeout = msecs_to_jiffies(1000);
adap->retries = 3;
adap->algo_data = dev;
adap->dev.parent = dev;
strcpy(adap->name, "mdio-i2c");

ret = i2c_add_adapter(adap);
pr_info("%s : Added mdio i2c adapter : %d\n", __func__, ret);
if (ret < 0)
return ret;

return 0;
}
EXPORT_SYMBOL(of_phy_init_i2c);

/**
* phy_resolve_aneg_linkmode - resolve the advertisements into phy settings
* @phydev: The phy_device struct
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/phy/phylink.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,11 @@ struct phylink *phylink_create(struct phylink_config *config,

pl->cur_link_an_mode = pl->cfg_link_an_mode;

if (config->type == PHYLINK_NETDEV)
of_phy_init_i2c(&pl->netdev->dev, to_of_node(fwnode));
else
of_phy_init_i2c(pl->dev, to_of_node(fwnode));

ret = phylink_register_sfp(pl, fwnode);
if (ret < 0) {
kfree(pl);
Expand Down
4 changes: 4 additions & 0 deletions include/linux/phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
#include <linux/i2c.h>
#include <linux/linkmode.h>
#include <linux/mdio.h>
#include <linux/mii.h>
Expand Down Expand Up @@ -652,6 +653,8 @@ struct phy_driver {
struct ethtool_tunable *tuna,
const void *data);
int (*set_loopback)(struct phy_device *dev, bool enable);

int (*i2c_xfer)(struct phy_device *dev, struct i2c_msg msgs[], int num);
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)
Expand Down Expand Up @@ -692,6 +695,7 @@ size_t phy_speeds(unsigned int *speeds, size_t size,
void of_set_phy_supported(struct phy_device *phydev);
void of_set_phy_eee_broken(struct phy_device *phydev);
int phy_speed_down_core(struct phy_device *phydev);
int of_phy_init_i2c(struct device *dev, struct device_node *node);

/**
* phy_is_started - Convenience function to check whether PHY is started
Expand Down

0 comments on commit 61645af

Please sign in to comment.