149 lines
4.2 KiB
Diff
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;
|
|
}
|