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>
This commit is contained in:
Josua Mayer 2022-05-17 11:54:30 +03:00 committed by Jakub Kicinski
parent 1f77204e11
commit ce3342161e

View File

@ -99,6 +99,15 @@
#define ADIN1300_GE_SOFT_RESET_REG 0xff0c #define ADIN1300_GE_SOFT_RESET_REG 0xff0c
#define ADIN1300_GE_SOFT_RESET BIT(0) #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_CFG_REG 0xff23
#define ADIN1300_GE_RGMII_RX_MSK GENMASK(8, 6) #define ADIN1300_GE_RGMII_RX_MSK GENMASK(8, 6)
#define ADIN1300_GE_RGMII_RX_SEL(x) \ #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) static int adin_config_init(struct phy_device *phydev)
{ {
int rc; int rc;
@ -455,6 +491,10 @@ static int adin_config_init(struct phy_device *phydev)
if (rc < 0) if (rc < 0)
return rc; return rc;
rc = adin_config_clk_out(phydev);
if (rc < 0)
return rc;
phydev_dbg(phydev, "PHY is using mode '%s'\n", phydev_dbg(phydev, "PHY is using mode '%s'\n",
phy_modes(phydev->interface)); phy_modes(phydev->interface));