[PATCH 2/3] net: phy: dp83867: Add ability to configure LEDs
From: Markus Moll <hidden>
Date: 2020-03-04 10:59:31
Subsystem:
ethernet phy library, networking drivers, the rest · Maintainers:
Andrew Lunn, Heiner Kallweit, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
The DP83867 PHY has configurable LED outputs. This code adds the devicetree property ti,led-modes as an array of four LED mode values corresponding to LED_0 through LED_3. Accepted values can be found in dt-bindings/net/ti-dp83867.h. Signed-off-by: Markus Moll <redacted> --- drivers/net/phy/dp83867.c | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+)
diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c
index 13f7f2d5a2e..ddf1ec8390e 100644
--- a/drivers/net/phy/dp83867.c
+++ b/drivers/net/phy/dp83867.c@@ -26,6 +26,7 @@ #define MII_DP83867_MICR 0x12 #define MII_DP83867_ISR 0x13 #define DP83867_CFG2 0x14 +#define DP83867_LEDCR1 0x18 #define DP83867_CFG3 0x1e #define DP83867_CTRL 0x1f
@@ -145,6 +146,16 @@ /* CFG4 bits */ #define DP83867_CFG4_PORT_MIRROR_EN BIT(0) +/* LEDCR1 bits */ +#define DP83867_LED_RESERVED 0xC +#define DP83867_LED_MAX 0xE +#define DP83867_LED_3_SHIFT 12 +#define DP83867_LED_2_SHIFT 8 +#define DP83867_LED_1_SHIFT 4 +#define DP83867_LED_0_SHIFT 0 + +#define NUM_LEDS 4 + enum { DP83867_PORT_MIRROING_KEEP, DP83867_PORT_MIRROING_EN,
@@ -162,6 +173,7 @@ struct dp83867_private { bool set_clk_output; u32 clk_output_sel; bool sgmii_ref_clk_en; + u32 led_modes[NUM_LEDS]; }; static int dp83867_ack_interrupt(struct phy_device *phydev)
@@ -483,6 +495,30 @@ static int dp83867_verify_rgmii_cfg(struct phy_device *phydev) return 0; } +static int dp83867_validate_led_modes(struct phy_device *phydev) +{ + struct dp83867_private *dp83867 = phydev->priv; + int i; + + for (i = 0; i < ARRAY_SIZE(dp83867->led_modes); i++) { + if (dp83867->led_modes[i] == DP83867_LED_RESERVED) { + phydev_err(phydev, + "ti,led-modes value %u invalid\n", + dp83867->led_modes[i]); + return -EINVAL; + } + + if (dp83867->led_modes[i] > DP83867_LED_MAX) { + phydev_err(phydev, + "ti,led-modes value %u out of range\n", + dp83867->led_modes[i]); + return -EINVAL; + } + } + + return 0; +} + #ifdef CONFIG_OF_MDIO static int dp83867_of_init(struct phy_device *phydev) {
@@ -578,6 +614,17 @@ static int dp83867_of_init(struct phy_device *phydev) return -EINVAL; } + /* default LED modes according to data sheet */ + dp83867->led_modes[0] = DP83867_LED_LINK; + dp83867->led_modes[1] = DP83867_LED_LINK_1000_BT; + dp83867->led_modes[2] = DP83867_LED_ACT_RX_TX; + dp83867->led_modes[3] = DP83867_LED_LINK_100_BTX; + + ret = of_property_read_u32_array(of_node, "ti,led-modes", + &dp83867->led_modes[0], NUM_LEDS); + if (!ret && dp83867_validate_led_modes(phydev)) + return -EINVAL; + return 0; } #else
@@ -617,6 +664,16 @@ static int dp83867_config_init(struct phy_device *phydev) if (ret) return ret; + /* Set LED modes */ + val = 0; + val |= (dp83867->led_modes[0] << DP83867_LED_0_SHIFT); + val |= (dp83867->led_modes[1] << DP83867_LED_1_SHIFT); + val |= (dp83867->led_modes[2] << DP83867_LED_2_SHIFT); + val |= (dp83867->led_modes[3] << DP83867_LED_3_SHIFT); + ret = phy_write(phydev, DP83867_LEDCR1, val); + if (ret) + return ret; + /* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */ if (dp83867->rxctrl_strap_quirk) phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
--
2.25.0