1 From 94b90966095f3fa625897e8f53d215882f6e19b3 Mon Sep 17 00:00:00 2001
2 From: David Bauer <mail@david-bauer.net>
3 Date: Sat, 11 Mar 2023 17:00:01 +0100
4 Subject: [PATCH] mxl-gpy: control LED reg from DT
6 Add dynamic configuration for the LED control registers on MXL PHYs.
8 This patch has been tested with MaxLinear GPY211C. It is unlikely to be
9 accepted upstream, as upstream plans on integrating their own framework
10 for handling these LEDs.
12 For the time being, use this hack to configure PHY driven device-LEDs to
13 show the correct state.
15 A possible alternative might be to expose the LEDs using the kernel LED
16 framework and bind it to the netdevice. This might also be upstreamable,
17 although it is a considerable extra amount of work.
19 Signed-off-by: David Bauer <mail@david-bauer.net>
21 drivers/net/phy/mxl-gpy.c | 37 ++++++++++++++++++++++++++++++++++++-
22 1 file changed, 36 insertions(+), 1 deletion(-)
24 diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c
25 index 5ce1bf03bbd7..ec10ad5ccad6 100644
26 --- a/drivers/net/phy/mxl-gpy.c
27 +++ b/drivers/net/phy/mxl-gpy.c
30 #include <linux/module.h>
31 #include <linux/bitfield.h>
32 +#include <linux/of.h>
33 #include <linux/phy.h>
34 #include <linux/netdevice.h>
37 #define PHY_MIISTAT 0x18 /* MII state */
38 #define PHY_IMASK 0x19 /* interrupt mask */
39 #define PHY_ISTAT 0x1A /* interrupt status */
40 +#define PHY_LED 0x1B /* LED control */
41 #define PHY_FWV 0x1E /* firmware version */
43 #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
48 +#define PHY_LED_NUM_LEDS 4
50 #define PHY_FWV_REL_MASK BIT(15)
51 #define PHY_FWV_TYPE_MASK GENMASK(11, 8)
52 #define PHY_FWV_MINOR_MASK GENMASK(7, 0)
55 +#define VSPEC1_LED(x) (0x1 + x)
58 #define VSPEC1_SGMII_CTRL 0x08
59 #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */
60 @@ -80,6 +87,31 @@ static const struct {
64 +static int gpy_led_write(struct phy_device *phydev)
66 + struct device_node *node = phydev->mdio.dev.of_node;
67 + u32 led_regs[PHY_LED_NUM_LEDS];
70 + if (!IS_ENABLED(CONFIG_OF_MDIO))
73 + if (of_property_read_u32_array(node, "mxl,led-config", led_regs, PHY_LED_NUM_LEDS))
76 + /* Enable LED function handling on all ports*/
77 + phy_write(phydev, PHY_LED, 0xFF00);
79 + /* Write LED register values */
80 + for (i = 0; i < PHY_LED_NUM_LEDS; i++) {
81 + ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(i), (u16)led_regs[i]);
89 static int gpy_config_init(struct phy_device *phydev)
92 @@ -91,7 +123,10 @@ static int gpy_config_init(struct phy_device *phydev)
94 /* Clear all pending interrupts */
95 ret = phy_read(phydev, PHY_ISTAT);
96 - return ret < 0 ? ret : 0;
100 + return gpy_led_write(phydev);
103 static int gpy_probe(struct phy_device *phydev)