openwrt/target/linux/realtek/patches-6.6/712-net-phy-add-an-MDIO-SMB...

149 lines
4.2 KiB
Diff

From d585c55b9f70cf9e8c66820d7efe7130c683f19e Mon Sep 17 00:00:00 2001
From: Antoine Tenart <antoine.tenart@bootlin.com>
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 <antoine.tenart@bootlin.com>
---
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 <linux/i2c.h>
+#include <linux/phy.h>
+#include <linux/mdio/mdio-i2c.h>
+
+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;
}