]> git.baikalelectronics.ru Git - kernel.git/commitdiff
net: phy: adin: add support for clock output
authorJosua Mayer <josua@solid-run.com>
Tue, 17 May 2022 08:54:30 +0000 (11:54 +0300)
committerJakub Kicinski <kuba@kernel.org>
Thu, 19 May 2022 02:58:25 +0000 (19:58 -0700)
The ADIN1300 supports generating certain clocks on its GP_CLK pin, as
well as providing the reference clock on CLK25_REF.

Add support for selecting the clock via device-tree properties.

Technically the phy also supports a recovered 125MHz clock for
synchronous ethernet. SyncE should be configured dynamically at
runtime, however Linux does not currently have a toggle for this,
so support is explicitly omitted.

Co-developed-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
Signed-off-by: Alvaro Karsz <alvaro.karsz@solid-run.com>
Signed-off-by: Josua Mayer<josua@solid-run.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/adin.c

index 5ce6da62cc8e888a5a3f2c76317fdfd472ae7e6c..ee374a85544a635f3711de9bca8083ff5221b2f3 100644 (file)
 #define ADIN1300_GE_SOFT_RESET_REG             0xff0c
 #define   ADIN1300_GE_SOFT_RESET               BIT(0)
 
+#define ADIN1300_GE_CLK_CFG_REG                        0xff1f
+#define   ADIN1300_GE_CLK_CFG_MASK             GENMASK(5, 0)
+#define   ADIN1300_GE_CLK_CFG_RCVR_125         BIT(5)
+#define   ADIN1300_GE_CLK_CFG_FREE_125         BIT(4)
+#define   ADIN1300_GE_CLK_CFG_REF_EN           BIT(3)
+#define   ADIN1300_GE_CLK_CFG_HRT_RCVR         BIT(2)
+#define   ADIN1300_GE_CLK_CFG_HRT_FREE         BIT(1)
+#define   ADIN1300_GE_CLK_CFG_25               BIT(0)
+
 #define ADIN1300_GE_RGMII_CFG_REG              0xff23
 #define   ADIN1300_GE_RGMII_RX_MSK             GENMASK(8, 6)
 #define   ADIN1300_GE_RGMII_RX_SEL(x)          \
@@ -433,6 +442,33 @@ static int adin_set_tunable(struct phy_device *phydev,
        }
 }
 
+static int adin_config_clk_out(struct phy_device *phydev)
+{
+       struct device *dev = &phydev->mdio.dev;
+       const char *val = NULL;
+       u8 sel = 0;
+
+       device_property_read_string(dev, "adi,phy-output-clock", &val);
+       if (!val) {
+               /* property not present, do not enable GP_CLK pin */
+       } else if (strcmp(val, "25mhz-reference") == 0) {
+               sel |= ADIN1300_GE_CLK_CFG_25;
+       } else if (strcmp(val, "125mhz-free-running") == 0) {
+               sel |= ADIN1300_GE_CLK_CFG_FREE_125;
+       } else if (strcmp(val, "adaptive-free-running") == 0) {
+               sel |= ADIN1300_GE_CLK_CFG_HRT_FREE;
+       } else {
+               phydev_err(phydev, "invalid adi,phy-output-clock\n");
+               return -EINVAL;
+       }
+
+       if (device_property_read_bool(dev, "adi,phy-output-reference-clock"))
+               sel |= ADIN1300_GE_CLK_CFG_REF_EN;
+
+       return phy_modify_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_GE_CLK_CFG_REG,
+                             ADIN1300_GE_CLK_CFG_MASK, sel);
+}
+
 static int adin_config_init(struct phy_device *phydev)
 {
        int rc;
@@ -455,6 +491,10 @@ static int adin_config_init(struct phy_device *phydev)
        if (rc < 0)
                return rc;
 
+       rc = adin_config_clk_out(phydev);
+       if (rc < 0)
+               return rc;
+
        phydev_dbg(phydev, "PHY is using mode '%s'\n",
                   phy_modes(phydev->interface));