mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-03 22:44:27 -05:00 
			
		
		
		
	IPQ40xx MDIO driver was upstreamed in kernel version 5.8. So lets backport the upstream version and drop our local one. This also refreshed the kernel config since the symbol name has changed. Signed-off-by: Robert Marko <robert.marko@sartura.hr>
		
			
				
	
	
		
			211 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 466ed24fb22342f3ae1c10758a6a0c6a8c081b2d Mon Sep 17 00:00:00 2001
 | 
						|
From: Robert Marko <robert.marko@sartura.hr>
 | 
						|
Date: Thu, 30 Apr 2020 11:07:05 +0200
 | 
						|
Subject: [PATCH] net: phy: mdio: add IPQ4019 MDIO driver
 | 
						|
 | 
						|
This patch adds the driver for the MDIO interface
 | 
						|
inside of Qualcomm IPQ40xx series SoC-s.
 | 
						|
 | 
						|
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
 | 
						|
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
 | 
						|
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
 | 
						|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
 | 
						|
Cc: Luka Perkov <luka.perkov@sartura.hr>
 | 
						|
Signed-off-by: David S. Miller <davem@davemloft.net>
 | 
						|
---
 | 
						|
 drivers/net/phy/Kconfig        |   7 ++
 | 
						|
 drivers/net/phy/Makefile       |   1 +
 | 
						|
 drivers/net/phy/mdio-ipq4019.c | 160 +++++++++++++++++++++++++++++++++
 | 
						|
 3 files changed, 168 insertions(+)
 | 
						|
 create mode 100644 drivers/net/phy/mdio-ipq4019.c
 | 
						|
 | 
						|
--- a/drivers/net/phy/Kconfig
 | 
						|
+++ b/drivers/net/phy/Kconfig
 | 
						|
@@ -156,6 +156,13 @@ config MDIO_I2C
 | 
						|
 
 | 
						|
 	  This is library mode.
 | 
						|
 
 | 
						|
+config MDIO_IPQ4019
 | 
						|
+	tristate "Qualcomm IPQ4019 MDIO interface support"
 | 
						|
+	depends on HAS_IOMEM && OF_MDIO
 | 
						|
+	help
 | 
						|
+	  This driver supports the MDIO interface found in Qualcomm
 | 
						|
+	  IPQ40xx series Soc-s.
 | 
						|
+
 | 
						|
 config MDIO_MOXART
 | 
						|
 	tristate "MOXA ART MDIO interface support"
 | 
						|
 	depends on ARCH_MOXART || COMPILE_TEST
 | 
						|
--- a/drivers/net/phy/Makefile
 | 
						|
+++ b/drivers/net/phy/Makefile
 | 
						|
@@ -50,6 +50,7 @@ obj-$(CONFIG_MDIO_CAVIUM)	+= mdio-cavium
 | 
						|
 obj-$(CONFIG_MDIO_GPIO)		+= mdio-gpio.o
 | 
						|
 obj-$(CONFIG_MDIO_HISI_FEMAC)	+= mdio-hisi-femac.o
 | 
						|
 obj-$(CONFIG_MDIO_I2C)		+= mdio-i2c.o
 | 
						|
+obj-$(CONFIG_MDIO_IPQ4019)	+= mdio-ipq4019.o
 | 
						|
 obj-$(CONFIG_MDIO_MOXART)	+= mdio-moxart.o
 | 
						|
 obj-$(CONFIG_MDIO_MSCC_MIIM)	+= mdio-mscc-miim.o
 | 
						|
 obj-$(CONFIG_MDIO_OCTEON)	+= mdio-octeon.o
 | 
						|
--- /dev/null
 | 
						|
+++ b/drivers/net/phy/mdio-ipq4019.c
 | 
						|
@@ -0,0 +1,160 @@
 | 
						|
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 | 
						|
+/* Copyright (c) 2015, The Linux Foundation. All rights reserved. */
 | 
						|
+/* Copyright (c) 2020 Sartura Ltd. */
 | 
						|
+
 | 
						|
+#include <linux/delay.h>
 | 
						|
+#include <linux/kernel.h>
 | 
						|
+#include <linux/module.h>
 | 
						|
+#include <linux/io.h>
 | 
						|
+#include <linux/iopoll.h>
 | 
						|
+#include <linux/of_address.h>
 | 
						|
+#include <linux/of_mdio.h>
 | 
						|
+#include <linux/phy.h>
 | 
						|
+#include <linux/platform_device.h>
 | 
						|
+
 | 
						|
+#define MDIO_ADDR_REG				0x44
 | 
						|
+#define MDIO_DATA_WRITE_REG			0x48
 | 
						|
+#define MDIO_DATA_READ_REG			0x4c
 | 
						|
+#define MDIO_CMD_REG				0x50
 | 
						|
+#define MDIO_CMD_ACCESS_BUSY		BIT(16)
 | 
						|
+#define MDIO_CMD_ACCESS_START		BIT(8)
 | 
						|
+#define MDIO_CMD_ACCESS_CODE_READ	0
 | 
						|
+#define MDIO_CMD_ACCESS_CODE_WRITE	1
 | 
						|
+
 | 
						|
+#define ipq4019_MDIO_TIMEOUT	10000
 | 
						|
+#define ipq4019_MDIO_SLEEP		10
 | 
						|
+
 | 
						|
+struct ipq4019_mdio_data {
 | 
						|
+	void __iomem	*membase;
 | 
						|
+};
 | 
						|
+
 | 
						|
+static int ipq4019_mdio_wait_busy(struct mii_bus *bus)
 | 
						|
+{
 | 
						|
+	struct ipq4019_mdio_data *priv = bus->priv;
 | 
						|
+	unsigned int busy;
 | 
						|
+
 | 
						|
+	return readl_poll_timeout(priv->membase + MDIO_CMD_REG, busy,
 | 
						|
+				  (busy & MDIO_CMD_ACCESS_BUSY) == 0,
 | 
						|
+				  ipq4019_MDIO_SLEEP, ipq4019_MDIO_TIMEOUT);
 | 
						|
+}
 | 
						|
+
 | 
						|
+static int ipq4019_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 | 
						|
+{
 | 
						|
+	struct ipq4019_mdio_data *priv = bus->priv;
 | 
						|
+	unsigned int cmd;
 | 
						|
+
 | 
						|
+	/* Reject clause 45 */
 | 
						|
+	if (regnum & MII_ADDR_C45)
 | 
						|
+		return -EOPNOTSUPP;
 | 
						|
+
 | 
						|
+	if (ipq4019_mdio_wait_busy(bus))
 | 
						|
+		return -ETIMEDOUT;
 | 
						|
+
 | 
						|
+	/* issue the phy address and reg */
 | 
						|
+	writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
 | 
						|
+
 | 
						|
+	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_READ;
 | 
						|
+
 | 
						|
+	/* issue read command */
 | 
						|
+	writel(cmd, priv->membase + MDIO_CMD_REG);
 | 
						|
+
 | 
						|
+	/* Wait read complete */
 | 
						|
+	if (ipq4019_mdio_wait_busy(bus))
 | 
						|
+		return -ETIMEDOUT;
 | 
						|
+
 | 
						|
+	/* Read and return data */
 | 
						|
+	return readl(priv->membase + MDIO_DATA_READ_REG);
 | 
						|
+}
 | 
						|
+
 | 
						|
+static int ipq4019_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
 | 
						|
+							 u16 value)
 | 
						|
+{
 | 
						|
+	struct ipq4019_mdio_data *priv = bus->priv;
 | 
						|
+	unsigned int cmd;
 | 
						|
+
 | 
						|
+	/* Reject clause 45 */
 | 
						|
+	if (regnum & MII_ADDR_C45)
 | 
						|
+		return -EOPNOTSUPP;
 | 
						|
+
 | 
						|
+	if (ipq4019_mdio_wait_busy(bus))
 | 
						|
+		return -ETIMEDOUT;
 | 
						|
+
 | 
						|
+	/* issue the phy address and reg */
 | 
						|
+	writel((mii_id << 8) | regnum, priv->membase + MDIO_ADDR_REG);
 | 
						|
+
 | 
						|
+	/* issue write data */
 | 
						|
+	writel(value, priv->membase + MDIO_DATA_WRITE_REG);
 | 
						|
+
 | 
						|
+	cmd = MDIO_CMD_ACCESS_START | MDIO_CMD_ACCESS_CODE_WRITE;
 | 
						|
+	/* issue write command */
 | 
						|
+	writel(cmd, priv->membase + MDIO_CMD_REG);
 | 
						|
+
 | 
						|
+	/* Wait write complete */
 | 
						|
+	if (ipq4019_mdio_wait_busy(bus))
 | 
						|
+		return -ETIMEDOUT;
 | 
						|
+
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static int ipq4019_mdio_probe(struct platform_device *pdev)
 | 
						|
+{
 | 
						|
+	struct ipq4019_mdio_data *priv;
 | 
						|
+	struct mii_bus *bus;
 | 
						|
+	int ret;
 | 
						|
+
 | 
						|
+	bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
 | 
						|
+	if (!bus)
 | 
						|
+		return -ENOMEM;
 | 
						|
+
 | 
						|
+	priv = bus->priv;
 | 
						|
+
 | 
						|
+	priv->membase = devm_platform_ioremap_resource(pdev, 0);
 | 
						|
+	if (IS_ERR(priv->membase))
 | 
						|
+		return PTR_ERR(priv->membase);
 | 
						|
+
 | 
						|
+	bus->name = "ipq4019_mdio";
 | 
						|
+	bus->read = ipq4019_mdio_read;
 | 
						|
+	bus->write = ipq4019_mdio_write;
 | 
						|
+	bus->parent = &pdev->dev;
 | 
						|
+	snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);
 | 
						|
+
 | 
						|
+	ret = of_mdiobus_register(bus, pdev->dev.of_node);
 | 
						|
+	if (ret) {
 | 
						|
+		dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
 | 
						|
+		return ret;
 | 
						|
+	}
 | 
						|
+
 | 
						|
+	platform_set_drvdata(pdev, bus);
 | 
						|
+
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static int ipq4019_mdio_remove(struct platform_device *pdev)
 | 
						|
+{
 | 
						|
+	struct mii_bus *bus = platform_get_drvdata(pdev);
 | 
						|
+
 | 
						|
+	mdiobus_unregister(bus);
 | 
						|
+
 | 
						|
+	return 0;
 | 
						|
+}
 | 
						|
+
 | 
						|
+static const struct of_device_id ipq4019_mdio_dt_ids[] = {
 | 
						|
+	{ .compatible = "qcom,ipq4019-mdio" },
 | 
						|
+	{ }
 | 
						|
+};
 | 
						|
+MODULE_DEVICE_TABLE(of, ipq4019_mdio_dt_ids);
 | 
						|
+
 | 
						|
+static struct platform_driver ipq4019_mdio_driver = {
 | 
						|
+	.probe = ipq4019_mdio_probe,
 | 
						|
+	.remove = ipq4019_mdio_remove,
 | 
						|
+	.driver = {
 | 
						|
+		.name = "ipq4019-mdio",
 | 
						|
+		.of_match_table = ipq4019_mdio_dt_ids,
 | 
						|
+	},
 | 
						|
+};
 | 
						|
+
 | 
						|
+module_platform_driver(ipq4019_mdio_driver);
 | 
						|
+
 | 
						|
+MODULE_DESCRIPTION("ipq4019 MDIO interface driver");
 | 
						|
+MODULE_AUTHOR("Qualcomm Atheros");
 | 
						|
+MODULE_LICENSE("Dual BSD/GPL");
 |