From d585c55b9f70cf9e8c66820d7efe7130c683f19e Mon Sep 17 00:00:00 2001 From: Antoine Tenart Date: Fri, 21 Feb 2020 11:51:27 +0100 Subject: [PATCH 2/3] net: phy: add an MDIO SMBus library Signed-off-by: Antoine Tenart --- drivers/net/mdio/Kconfig | 11 +++++++ drivers/net/mdio/Makefile | 1 + drivers/net/mdio/mdio-smbus.c | 62 +++++++++++++++++++++++++++++++++++ drivers/net/phy/Kconfig | 1 + include/linux/mdio/mdio-i2c.h | 16 +++++++++ 5 files changed, 91 insertions(+) create mode 100644 drivers/net/mdio/mdio-smbus.c --- a/drivers/net/mdio/Kconfig +++ b/drivers/net/mdio/Kconfig @@ -54,6 +54,17 @@ config MDIO_SUN4I interface units of the Allwinner SoC that have an EMAC (A10, A12, A10s, etc.) +config MDIO_SMBUS + tristate + depends on I2C_SMBUS + help + Support SMBus based PHYs. This provides a MDIO bus bridged + to SMBus to allow PHYs connected in SMBus mode to be accessed + using the existing infrastructure. + + This is library mode. + + config MDIO_XGENE tristate "APM X-Gene SoC MDIO bus controller" depends on ARCH_XGENE || COMPILE_TEST --- a/drivers/net/mdio/Makefile +++ b/drivers/net/mdio/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-ms obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o obj-$(CONFIG_MDIO_REGMAP) += mdio-regmap.o +obj-$(CONFIG_MDIO_SMBUS) += mdio-smbus.o obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o --- /dev/null +++ b/drivers/net/mdio/mdio-smbus.c @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * MDIO SMBus bridge + * + * Copyright (C) 2020 Antoine Tenart + * + * Network PHYs can appear on SMBus when they are part of SFP modules. + */ +#include +#include +#include + +static int smbus_mii_read(struct mii_bus *mii, int phy_id, int reg) +{ + struct i2c_adapter *i2c = mii->priv; + union i2c_smbus_data data; + int ret; + + ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0, I2C_SMBUS_READ, + reg, I2C_SMBUS_BYTE_DATA, &data); + if (ret < 0) + return 0xff; + + return data.byte; +} + +static int smbus_mii_write(struct mii_bus *mii, int phy_id, int reg, u16 val) +{ + struct i2c_adapter *i2c = mii->priv; + union i2c_smbus_data data; + int ret; + + data.byte = val; + + ret = i2c_smbus_xfer(i2c, i2c_mii_phy_addr(phy_id), 0, I2C_SMBUS_WRITE, + reg, I2C_SMBUS_BYTE_DATA, &data); + return ret < 0 ? ret : 0; +} + +struct mii_bus *mdio_smbus_alloc(struct device *parent, struct i2c_adapter *i2c) +{ + struct mii_bus *mii; + + if (!i2c_check_functionality(i2c, I2C_FUNC_SMBUS_BYTE_DATA)) + return ERR_PTR(-EINVAL); + + mii = mdiobus_alloc(); + if (!mii) + return ERR_PTR(-ENOMEM); + + snprintf(mii->id, MII_BUS_ID_SIZE, "smbus:%s", dev_name(parent)); + mii->parent = parent; + mii->read = smbus_mii_read; + mii->write = smbus_mii_write; + mii->priv = i2c; + + return mii; +} + +MODULE_AUTHOR("Antoine Tenart"); +MODULE_DESCRIPTION("MDIO SMBus bridge library"); +MODULE_LICENSE("GPL"); --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -65,6 +65,7 @@ config SFP depends on I2C && PHYLINK depends on HWMON || HWMON=n select MDIO_I2C + select MDIO_SMBUS comment "Switch configuration API + drivers" --- a/include/linux/mdio/mdio-i2c.h +++ b/include/linux/mdio/mdio-i2c.h @@ -20,5 +20,8 @@ enum mdio_i2c_proto { struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, enum mdio_i2c_proto protocol); +struct mii_bus *mdio_smbus_alloc(struct device *parent, struct i2c_adapter *i2c); +bool i2c_mii_valid_phy_id(int phy_id); +unsigned int i2c_mii_phy_addr(int phy_id); #endif --- a/drivers/net/mdio/mdio-i2c.c +++ b/drivers/net/mdio/mdio-i2c.c @@ -20,12 +20,12 @@ * specified to be present in SFP modules. These correspond with PHY * addresses 16 and 17. Disallow access to these "phy" addresses. */ -static bool i2c_mii_valid_phy_id(int phy_id) +bool i2c_mii_valid_phy_id(int phy_id) { return phy_id != 0x10 && phy_id != 0x11; } -static unsigned int i2c_mii_phy_addr(int phy_id) +unsigned int i2c_mii_phy_addr(int phy_id) { return phy_id + 0x40; }