generic: mxl-gpy: allow configuring LED registers
[openwrt/staging/jow.git] / target / linux / generic / hack-5.15 / 765-mxl-gpy-control-LED-reg-from-DT.patch
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
5
6 Add dynamic configuration for the LED control registers on MXL PHYs.
7
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.
11
12 For the time being, use this hack to configure PHY driven device-LEDs to
13 show the correct state.
14
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.
18
19 Signed-off-by: David Bauer <mail@david-bauer.net>
20 ---
21 drivers/net/phy/mxl-gpy.c | 37 ++++++++++++++++++++++++++++++++++++-
22 1 file changed, 36 insertions(+), 1 deletion(-)
23
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
28 @@ -8,6 +8,7 @@
29
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>
35
36 @@ -30,6 +31,7 @@
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 */
42
43 #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
44 @@ -53,10 +55,15 @@
45 PHY_IMASK_ADSC | \
46 PHY_IMASK_ANC)
47
48 +#define PHY_LED_NUM_LEDS 4
49 +
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)
53
54 +/* LED */
55 +#define VSPEC1_LED(x) (0x1 + x)
56 +
57 /* SGMII */
58 #define VSPEC1_SGMII_CTRL 0x08
59 #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */
60 @@ -80,6 +87,31 @@ static const struct {
61 {9, 0x73},
62 };
63
64 +static int gpy_led_write(struct phy_device *phydev)
65 +{
66 + struct device_node *node = phydev->mdio.dev.of_node;
67 + u32 led_regs[PHY_LED_NUM_LEDS];
68 + int i, ret;
69 +
70 + if (!IS_ENABLED(CONFIG_OF_MDIO))
71 + return 0;
72 +
73 + if (of_property_read_u32_array(node, "mxl,led-config", led_regs, PHY_LED_NUM_LEDS))
74 + return 0;
75 +
76 + /* Enable LED function handling on all ports*/
77 + phy_write(phydev, PHY_LED, 0xFF00);
78 +
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]);
82 + if (ret < 0)
83 + return ret;
84 + }
85 +
86 + return 0;
87 +}
88 +
89 static int gpy_config_init(struct phy_device *phydev)
90 {
91 int ret;
92 @@ -91,7 +123,10 @@ static int gpy_config_init(struct phy_device *phydev)
93
94 /* Clear all pending interrupts */
95 ret = phy_read(phydev, PHY_ISTAT);
96 - return ret < 0 ? ret : 0;
97 + if (ret < 0)
98 + return ret;
99 +
100 + return gpy_led_write(phydev);
101 }
102
103 static int gpy_probe(struct phy_device *phydev)
104 --
105 2.39.2
106