net: mdio: Add the reset function for IPQ MDIO driver
authorLuo Jie <luoj@codeaurora.org>
Thu, 12 Aug 2021 10:06:40 +0000 (18:06 +0800)
committerDavid S. Miller <davem@davemloft.net>
Mon, 16 Aug 2021 09:30:27 +0000 (10:30 +0100)
1. configure the MDIO clock source frequency.
2. the LDO resource is needed to configure the ethernet LDO available
for CMN_PLL.

Signed-off-by: Luo Jie <luoj@codeaurora.org>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/mdio/Kconfig
drivers/net/mdio/mdio-ipq4019.c

index 99a6c13..a94d34c 100644 (file)
@@ -169,6 +169,7 @@ config MDIO_OCTEON
 config MDIO_IPQ4019
        tristate "Qualcomm IPQ4019 MDIO interface support"
        depends on HAS_IOMEM && OF_MDIO
+       depends on COMMON_CLK
        help
          This driver supports the MDIO interface found in Qualcomm
          IPQ40xx series Soc-s.
index 9cd71d8..e14d437 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/of_mdio.h>
 #include <linux/phy.h>
 #include <linux/platform_device.h>
+#include <linux/clk.h>
 
 #define MDIO_MODE_REG                          0x40
 #define MDIO_ADDR_REG                          0x44
 #define IPQ4019_MDIO_TIMEOUT   10000
 #define IPQ4019_MDIO_SLEEP             10
 
+/* MDIO clock source frequency is fixed to 100M */
+#define IPQ_MDIO_CLK_RATE      100000000
+
+#define IPQ_PHY_SET_DELAY_US   100000
+
 struct ipq4019_mdio_data {
        void __iomem    *membase;
+       void __iomem *eth_ldo_rdy;
+       struct clk *mdio_clk;
 };
 
 static int ipq4019_mdio_wait_busy(struct mii_bus *bus)
@@ -171,10 +179,35 @@ static int ipq4019_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
        return 0;
 }
 
+static int ipq_mdio_reset(struct mii_bus *bus)
+{
+       struct ipq4019_mdio_data *priv = bus->priv;
+       u32 val;
+       int ret;
+
+       /* To indicate CMN_PLL that ethernet_ldo has been ready if platform resource 1
+        * is specified in the device tree.
+        */
+       if (priv->eth_ldo_rdy) {
+               val = readl(priv->eth_ldo_rdy);
+               val |= BIT(0);
+               writel(val, priv->eth_ldo_rdy);
+               fsleep(IPQ_PHY_SET_DELAY_US);
+       }
+
+       /* Configure MDIO clock source frequency if clock is specified in the device tree */
+       ret = clk_set_rate(priv->mdio_clk, IPQ_MDIO_CLK_RATE);
+       if (ret)
+               return ret;
+
+       return clk_prepare_enable(priv->mdio_clk);
+}
+
 static int ipq4019_mdio_probe(struct platform_device *pdev)
 {
        struct ipq4019_mdio_data *priv;
        struct mii_bus *bus;
+       struct resource *res;
        int ret;
 
        bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*priv));
@@ -187,9 +220,19 @@ static int ipq4019_mdio_probe(struct platform_device *pdev)
        if (IS_ERR(priv->membase))
                return PTR_ERR(priv->membase);
 
+       priv->mdio_clk = devm_clk_get_optional(&pdev->dev, "gcc_mdio_ahb_clk");
+       if (IS_ERR(priv->mdio_clk))
+               return PTR_ERR(priv->mdio_clk);
+
+       /* The platform resource is provided on the chipset IPQ5018 */
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (res)
+               priv->eth_ldo_rdy = devm_ioremap_resource(&pdev->dev, res);
+
        bus->name = "ipq4019_mdio";
        bus->read = ipq4019_mdio_read;
        bus->write = ipq4019_mdio_write;
+       bus->reset = ipq_mdio_reset;
        bus->parent = &pdev->dev;
        snprintf(bus->id, MII_BUS_ID_SIZE, "%s%d", pdev->name, pdev->id);