Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: phy: adin: add support for clock output

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>

authored by

Josua Mayer and committed by
Jakub Kicinski
ce334216 1f77204e

+40
+40
drivers/net/phy/adin.c
··· 99 99 #define ADIN1300_GE_SOFT_RESET_REG 0xff0c 100 100 #define ADIN1300_GE_SOFT_RESET BIT(0) 101 101 102 + #define ADIN1300_GE_CLK_CFG_REG 0xff1f 103 + #define ADIN1300_GE_CLK_CFG_MASK GENMASK(5, 0) 104 + #define ADIN1300_GE_CLK_CFG_RCVR_125 BIT(5) 105 + #define ADIN1300_GE_CLK_CFG_FREE_125 BIT(4) 106 + #define ADIN1300_GE_CLK_CFG_REF_EN BIT(3) 107 + #define ADIN1300_GE_CLK_CFG_HRT_RCVR BIT(2) 108 + #define ADIN1300_GE_CLK_CFG_HRT_FREE BIT(1) 109 + #define ADIN1300_GE_CLK_CFG_25 BIT(0) 110 + 102 111 #define ADIN1300_GE_RGMII_CFG_REG 0xff23 103 112 #define ADIN1300_GE_RGMII_RX_MSK GENMASK(8, 6) 104 113 #define ADIN1300_GE_RGMII_RX_SEL(x) \ ··· 442 433 } 443 434 } 444 435 436 + static int adin_config_clk_out(struct phy_device *phydev) 437 + { 438 + struct device *dev = &phydev->mdio.dev; 439 + const char *val = NULL; 440 + u8 sel = 0; 441 + 442 + device_property_read_string(dev, "adi,phy-output-clock", &val); 443 + if (!val) { 444 + /* property not present, do not enable GP_CLK pin */ 445 + } else if (strcmp(val, "25mhz-reference") == 0) { 446 + sel |= ADIN1300_GE_CLK_CFG_25; 447 + } else if (strcmp(val, "125mhz-free-running") == 0) { 448 + sel |= ADIN1300_GE_CLK_CFG_FREE_125; 449 + } else if (strcmp(val, "adaptive-free-running") == 0) { 450 + sel |= ADIN1300_GE_CLK_CFG_HRT_FREE; 451 + } else { 452 + phydev_err(phydev, "invalid adi,phy-output-clock\n"); 453 + return -EINVAL; 454 + } 455 + 456 + if (device_property_read_bool(dev, "adi,phy-output-reference-clock")) 457 + sel |= ADIN1300_GE_CLK_CFG_REF_EN; 458 + 459 + return phy_modify_mmd(phydev, MDIO_MMD_VEND1, ADIN1300_GE_CLK_CFG_REG, 460 + ADIN1300_GE_CLK_CFG_MASK, sel); 461 + } 462 + 445 463 static int adin_config_init(struct phy_device *phydev) 446 464 { 447 465 int rc; ··· 488 452 return rc; 489 453 490 454 rc = adin_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS); 455 + if (rc < 0) 456 + return rc; 457 + 458 + rc = adin_config_clk_out(phydev); 491 459 if (rc < 0) 492 460 return rc; 493 461