--- /dev/null
+From c11d5dbbe73fa7b450aaa77bb18df86a9714b422 Mon Sep 17 00:00:00 2001
+From: Christian Marangi <ansuelsmth@gmail.com>
+Date: Sat, 1 Jun 2024 01:35:02 +0200
+Subject: [PATCH 1/2] net: phy: aquantia: move priv and hw stat to header
+
+In preparation for LEDs support, move priv and hw stat to header to
+reference priv struct also in other .c outside aquantia.main
+
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/aquantia/aquantia.h | 38 ++++++++++++++++++++++++
+ drivers/net/phy/aquantia/aquantia_main.c | 37 -----------------------
+ 2 files changed, 38 insertions(+), 37 deletions(-)
+
+--- a/drivers/net/phy/aquantia/aquantia.h
++++ b/drivers/net/phy/aquantia/aquantia.h
+@@ -82,6 +82,18 @@
+ #define VEND1_GLOBAL_RSVD_STAT9_MODE GENMASK(7, 0)
+ #define VEND1_GLOBAL_RSVD_STAT9_1000BT2 0x23
+
++/* MDIO_MMD_C22EXT */
++#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292
++#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294
++#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297
++#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313
++#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315
++#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317
++#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318
++#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319
++#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
++#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
++
+ #define VEND1_GLOBAL_INT_STD_STATUS 0xfc00
+ #define VEND1_GLOBAL_INT_VEND_STATUS 0xfc01
+
+@@ -108,6 +120,32 @@
+ #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
+ #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
+
++struct aqr107_hw_stat {
++ const char *name;
++ int reg;
++ int size;
++};
++
++#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
++static const struct aqr107_hw_stat aqr107_hw_stats[] = {
++ SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26),
++ SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26),
++ SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8),
++ SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26),
++ SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26),
++ SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8),
++ SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8),
++ SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8),
++ SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16),
++ SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22),
++};
++
++#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
++
++struct aqr107_priv {
++ u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
++};
++
+ #if IS_REACHABLE(CONFIG_HWMON)
+ int aqr_hwmon_probe(struct phy_device *phydev);
+ #else
+--- a/drivers/net/phy/aquantia/aquantia_main.c
++++ b/drivers/net/phy/aquantia/aquantia_main.c
+@@ -84,49 +84,12 @@
+ #define MDIO_AN_RX_VEND_STAT3 0xe832
+ #define MDIO_AN_RX_VEND_STAT3_AFR BIT(0)
+
+-/* MDIO_MMD_C22EXT */
+-#define MDIO_C22EXT_STAT_SGMII_RX_GOOD_FRAMES 0xd292
+-#define MDIO_C22EXT_STAT_SGMII_RX_BAD_FRAMES 0xd294
+-#define MDIO_C22EXT_STAT_SGMII_RX_FALSE_CARRIER 0xd297
+-#define MDIO_C22EXT_STAT_SGMII_TX_GOOD_FRAMES 0xd313
+-#define MDIO_C22EXT_STAT_SGMII_TX_BAD_FRAMES 0xd315
+-#define MDIO_C22EXT_STAT_SGMII_TX_FALSE_CARRIER 0xd317
+-#define MDIO_C22EXT_STAT_SGMII_TX_COLLISIONS 0xd318
+-#define MDIO_C22EXT_STAT_SGMII_TX_LINE_COLLISIONS 0xd319
+-#define MDIO_C22EXT_STAT_SGMII_TX_FRAME_ALIGN_ERR 0xd31a
+-#define MDIO_C22EXT_STAT_SGMII_TX_RUNT_FRAMES 0xd31b
+-
+ /* Sleep and timeout for checking if the Processor-Intensive
+ * MDIO operation is finished
+ */
+ #define AQR107_OP_IN_PROG_SLEEP 1000
+ #define AQR107_OP_IN_PROG_TIMEOUT 100000
+
+-struct aqr107_hw_stat {
+- const char *name;
+- int reg;
+- int size;
+-};
+-
+-#define SGMII_STAT(n, r, s) { n, MDIO_C22EXT_STAT_SGMII_ ## r, s }
+-static const struct aqr107_hw_stat aqr107_hw_stats[] = {
+- SGMII_STAT("sgmii_rx_good_frames", RX_GOOD_FRAMES, 26),
+- SGMII_STAT("sgmii_rx_bad_frames", RX_BAD_FRAMES, 26),
+- SGMII_STAT("sgmii_rx_false_carrier_events", RX_FALSE_CARRIER, 8),
+- SGMII_STAT("sgmii_tx_good_frames", TX_GOOD_FRAMES, 26),
+- SGMII_STAT("sgmii_tx_bad_frames", TX_BAD_FRAMES, 26),
+- SGMII_STAT("sgmii_tx_false_carrier_events", TX_FALSE_CARRIER, 8),
+- SGMII_STAT("sgmii_tx_collisions", TX_COLLISIONS, 8),
+- SGMII_STAT("sgmii_tx_line_collisions", TX_LINE_COLLISIONS, 8),
+- SGMII_STAT("sgmii_tx_frame_alignment_err", TX_FRAME_ALIGN_ERR, 16),
+- SGMII_STAT("sgmii_tx_runt_frames", TX_RUNT_FRAMES, 22),
+-};
+-#define AQR107_SGMII_STAT_SZ ARRAY_SIZE(aqr107_hw_stats)
+-
+-struct aqr107_priv {
+- u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
+-};
+-
+ static int aqr107_get_sset_count(struct phy_device *phydev)
+ {
+ return AQR107_SGMII_STAT_SZ;
--- /dev/null
+From 61578f67937881abf54c8bd258eb913312dbe4c1 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Sat, 1 Jun 2024 01:35:03 +0200
+Subject: [PATCH 2/2] net: phy: aquantia: add support for PHY LEDs
+
+Aquantia Ethernet PHYs got 3 LED output pins which are typically used
+to indicate link status and activity.
+Add a minimal LED controller driver supporting the most common uses
+with the 'netdev' trigger as well as software-driven forced control of
+the LEDs.
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+[ rework indentation, fix checkpatch error and improve some functions ]
+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+---
+ drivers/net/phy/aquantia/Makefile | 2 +-
+ drivers/net/phy/aquantia/aquantia.h | 40 ++++++
+ drivers/net/phy/aquantia/aquantia_leds.c | 150 +++++++++++++++++++++++
+ drivers/net/phy/aquantia/aquantia_main.c | 63 +++++++++-
+ 4 files changed, 252 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/net/phy/aquantia/aquantia_leds.c
+
+--- a/drivers/net/phy/aquantia/Makefile
++++ b/drivers/net/phy/aquantia/Makefile
+@@ -1,5 +1,5 @@
+ # SPDX-License-Identifier: GPL-2.0
+-aquantia-objs += aquantia_main.o aquantia_firmware.o
++aquantia-objs += aquantia_main.o aquantia_firmware.o aquantia_leds.o
+ ifdef CONFIG_HWMON
+ aquantia-objs += aquantia_hwmon.o
+ endif
+--- a/drivers/net/phy/aquantia/aquantia.h
++++ b/drivers/net/phy/aquantia/aquantia.h
+@@ -58,6 +58,28 @@
+ #define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL_OVD BIT(6)
+ #define VEND1_GLOBAL_CONTROL2_UP_RUN_STALL BIT(0)
+
++#define VEND1_GLOBAL_LED_PROV 0xc430
++#define AQR_LED_PROV(x) (VEND1_GLOBAL_LED_PROV + (x))
++#define VEND1_GLOBAL_LED_PROV_LINK2500 BIT(14)
++#define VEND1_GLOBAL_LED_PROV_LINK5000 BIT(15)
++#define VEND1_GLOBAL_LED_PROV_FORCE_ON BIT(8)
++#define VEND1_GLOBAL_LED_PROV_LINK10000 BIT(7)
++#define VEND1_GLOBAL_LED_PROV_LINK1000 BIT(6)
++#define VEND1_GLOBAL_LED_PROV_LINK100 BIT(5)
++#define VEND1_GLOBAL_LED_PROV_RX_ACT BIT(3)
++#define VEND1_GLOBAL_LED_PROV_TX_ACT BIT(2)
++#define VEND1_GLOBAL_LED_PROV_ACT_STRETCH GENMASK(0, 1)
++
++#define VEND1_GLOBAL_LED_PROV_LINK_MASK (VEND1_GLOBAL_LED_PROV_LINK100 | \
++ VEND1_GLOBAL_LED_PROV_LINK1000 | \
++ VEND1_GLOBAL_LED_PROV_LINK10000 | \
++ VEND1_GLOBAL_LED_PROV_LINK5000 | \
++ VEND1_GLOBAL_LED_PROV_LINK2500)
++
++#define VEND1_GLOBAL_LED_DRIVE 0xc438
++#define VEND1_GLOBAL_LED_DRIVE_VDD BIT(1)
++#define AQR_LED_DRIVE(x) (VEND1_GLOBAL_LED_DRIVE + (x))
++
+ #define VEND1_THERMAL_PROV_HIGH_TEMP_FAIL 0xc421
+ #define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
+ #define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
+@@ -120,6 +142,8 @@
+ #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL2 BIT(1)
+ #define VEND1_GLOBAL_INT_VEND_MASK_GLOBAL3 BIT(0)
+
++#define AQR_MAX_LEDS 3
++
+ struct aqr107_hw_stat {
+ const char *name;
+ int reg;
+@@ -144,6 +168,7 @@ static const struct aqr107_hw_stat aqr10
+
+ struct aqr107_priv {
+ u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
++ unsigned long leds_active_low;
+ };
+
+ #if IS_REACHABLE(CONFIG_HWMON)
+@@ -153,3 +178,18 @@ static inline int aqr_hwmon_probe(struct
+ #endif
+
+ int aqr_firmware_load(struct phy_device *phydev);
++
++int aqr_phy_led_blink_set(struct phy_device *phydev, u8 index,
++ unsigned long *delay_on,
++ unsigned long *delay_off);
++int aqr_phy_led_brightness_set(struct phy_device *phydev,
++ u8 index, enum led_brightness value);
++int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++ unsigned long rules);
++int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
++ unsigned long *rules);
++int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
++ unsigned long rules);
++int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable);
++int aqr_phy_led_polarity_set(struct phy_device *phydev, int index,
++ unsigned long modes);
+--- /dev/null
++++ b/drivers/net/phy/aquantia/aquantia_leds.c
+@@ -0,0 +1,150 @@
++// SPDX-License-Identifier: GPL-2.0
++/* LED driver for Aquantia PHY
++ *
++ * Author: Daniel Golle <daniel@makrotopia.org>
++ */
++
++#include <linux/phy.h>
++
++#include "aquantia.h"
++
++int aqr_phy_led_brightness_set(struct phy_device *phydev,
++ u8 index, enum led_brightness value)
++{
++ if (index >= AQR_MAX_LEDS)
++ return -EINVAL;
++
++ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),
++ VEND1_GLOBAL_LED_PROV_LINK_MASK |
++ VEND1_GLOBAL_LED_PROV_FORCE_ON |
++ VEND1_GLOBAL_LED_PROV_RX_ACT |
++ VEND1_GLOBAL_LED_PROV_TX_ACT,
++ value ? VEND1_GLOBAL_LED_PROV_FORCE_ON : 0);
++}
++
++static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
++ BIT(TRIGGER_NETDEV_LINK_100) |
++ BIT(TRIGGER_NETDEV_LINK_1000) |
++ BIT(TRIGGER_NETDEV_LINK_2500) |
++ BIT(TRIGGER_NETDEV_LINK_5000) |
++ BIT(TRIGGER_NETDEV_LINK_10000) |
++ BIT(TRIGGER_NETDEV_RX) |
++ BIT(TRIGGER_NETDEV_TX));
++
++int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ if (index >= AQR_MAX_LEDS)
++ return -EINVAL;
++
++ /* All combinations of the supported triggers are allowed */
++ if (rules & ~supported_triggers)
++ return -EOPNOTSUPP;
++
++ return 0;
++}
++
++int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
++ unsigned long *rules)
++{
++ int val;
++
++ if (index >= AQR_MAX_LEDS)
++ return -EINVAL;
++
++ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index));
++ if (val < 0)
++ return val;
++
++ *rules = 0;
++ if (val & VEND1_GLOBAL_LED_PROV_LINK100)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
++
++ if (val & VEND1_GLOBAL_LED_PROV_LINK1000)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
++
++ if (val & VEND1_GLOBAL_LED_PROV_LINK2500)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
++
++ if (val & VEND1_GLOBAL_LED_PROV_LINK5000)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_5000);
++
++ if (val & VEND1_GLOBAL_LED_PROV_LINK10000)
++ *rules |= BIT(TRIGGER_NETDEV_LINK_10000);
++
++ if (val & VEND1_GLOBAL_LED_PROV_RX_ACT)
++ *rules |= BIT(TRIGGER_NETDEV_RX);
++
++ if (val & VEND1_GLOBAL_LED_PROV_TX_ACT)
++ *rules |= BIT(TRIGGER_NETDEV_TX);
++
++ return 0;
++}
++
++int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
++ unsigned long rules)
++{
++ u16 val = 0;
++
++ if (index >= AQR_MAX_LEDS)
++ return -EINVAL;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
++ val |= VEND1_GLOBAL_LED_PROV_LINK100;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
++ val |= VEND1_GLOBAL_LED_PROV_LINK1000;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
++ val |= VEND1_GLOBAL_LED_PROV_LINK2500;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK)))
++ val |= VEND1_GLOBAL_LED_PROV_LINK5000;
++
++ if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK)))
++ val |= VEND1_GLOBAL_LED_PROV_LINK10000;
++
++ if (rules & BIT(TRIGGER_NETDEV_RX))
++ val |= VEND1_GLOBAL_LED_PROV_RX_ACT;
++
++ if (rules & BIT(TRIGGER_NETDEV_TX))
++ val |= VEND1_GLOBAL_LED_PROV_TX_ACT;
++
++ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),
++ VEND1_GLOBAL_LED_PROV_LINK_MASK |
++ VEND1_GLOBAL_LED_PROV_FORCE_ON |
++ VEND1_GLOBAL_LED_PROV_RX_ACT |
++ VEND1_GLOBAL_LED_PROV_TX_ACT, val);
++}
++
++int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable)
++{
++ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
++ VEND1_GLOBAL_LED_DRIVE_VDD, enable);
++}
++
++int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
++{
++ struct aqr107_priv *priv = phydev->priv;
++ bool active_low = false;
++ u32 mode;
++
++ if (index >= AQR_MAX_LEDS)
++ return -EINVAL;
++
++ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
++ switch (mode) {
++ case PHY_LED_ACTIVE_LOW:
++ active_low = true;
++ break;
++ default:
++ return -EINVAL;
++ }
++ }
++
++ /* Save LED driver vdd state to restore on SW reset */
++ if (active_low)
++ priv->leds_active_low |= BIT(index);
++
++ return aqr_phy_led_active_low_set(phydev, index, active_low);
++}
+--- a/drivers/net/phy/aquantia/aquantia_main.c
++++ b/drivers/net/phy/aquantia/aquantia_main.c
+@@ -475,7 +475,9 @@ static void aqr107_chip_info(struct phy_
+
+ static int aqr107_config_init(struct phy_device *phydev)
+ {
+- int ret;
++ struct aqr107_priv *priv = phydev->priv;
++ u32 led_active_low;
++ int ret, index = 0;
+
+ /* Check that the PHY interface type is compatible */
+ if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
+@@ -496,7 +498,19 @@ static int aqr107_config_init(struct phy
+ if (!ret)
+ aqr107_chip_info(phydev);
+
+- return aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
++ ret = aqr107_set_downshift(phydev, MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT);
++ if (ret)
++ return ret;
++
++ /* Restore LED polarity state after reset */
++ for_each_set_bit(led_active_low, &priv->leds_active_low, AQR_MAX_LEDS) {
++ ret = aqr_phy_led_active_low_set(phydev, index, led_active_low);
++ if (ret)
++ return ret;
++ index++;
++ }
++
++ return 0;
+ }
+
+ static int aqcs109_config_init(struct phy_device *phydev)
+@@ -703,6 +717,11 @@ static struct phy_driver aqr_driver[] =
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+ .link_change_notify = aqr107_link_change_notify,
++ .led_brightness_set = aqr_phy_led_brightness_set,
++ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++ .led_hw_control_set = aqr_phy_led_hw_control_set,
++ .led_hw_control_get = aqr_phy_led_hw_control_get,
++ .led_polarity_set = aqr_phy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
+@@ -722,6 +741,11 @@ static struct phy_driver aqr_driver[] =
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+ .link_change_notify = aqr107_link_change_notify,
++ .led_brightness_set = aqr_phy_led_brightness_set,
++ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++ .led_hw_control_set = aqr_phy_led_hw_control_set,
++ .led_hw_control_get = aqr_phy_led_hw_control_get,
++ .led_polarity_set = aqr_phy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR111),
+@@ -741,6 +765,11 @@ static struct phy_driver aqr_driver[] =
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+ .link_change_notify = aqr107_link_change_notify,
++ .led_brightness_set = aqr_phy_led_brightness_set,
++ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++ .led_hw_control_set = aqr_phy_led_hw_control_set,
++ .led_hw_control_get = aqr_phy_led_hw_control_get,
++ .led_polarity_set = aqr_phy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0),
+@@ -760,6 +789,11 @@ static struct phy_driver aqr_driver[] =
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+ .link_change_notify = aqr107_link_change_notify,
++ .led_brightness_set = aqr_phy_led_brightness_set,
++ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++ .led_hw_control_set = aqr_phy_led_hw_control_set,
++ .led_hw_control_get = aqr_phy_led_hw_control_get,
++ .led_polarity_set = aqr_phy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR405),
+@@ -786,6 +820,11 @@ static struct phy_driver aqr_driver[] =
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+ .link_change_notify = aqr107_link_change_notify,
++ .led_brightness_set = aqr_phy_led_brightness_set,
++ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++ .led_hw_control_set = aqr_phy_led_hw_control_set,
++ .led_hw_control_get = aqr_phy_led_hw_control_get,
++ .led_polarity_set = aqr_phy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
+@@ -823,6 +862,11 @@ static struct phy_driver aqr_driver[] =
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+ .link_change_notify = aqr107_link_change_notify,
++ .led_brightness_set = aqr_phy_led_brightness_set,
++ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++ .led_hw_control_set = aqr_phy_led_hw_control_set,
++ .led_hw_control_get = aqr_phy_led_hw_control_get,
++ .led_polarity_set = aqr_phy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
+@@ -842,6 +886,11 @@ static struct phy_driver aqr_driver[] =
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+ .link_change_notify = aqr107_link_change_notify,
++ .led_brightness_set = aqr_phy_led_brightness_set,
++ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++ .led_hw_control_set = aqr_phy_led_hw_control_set,
++ .led_hw_control_get = aqr_phy_led_hw_control_get,
++ .led_polarity_set = aqr_phy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR114C),
+@@ -861,6 +910,11 @@ static struct phy_driver aqr_driver[] =
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+ .link_change_notify = aqr107_link_change_notify,
++ .led_brightness_set = aqr_phy_led_brightness_set,
++ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++ .led_hw_control_set = aqr_phy_led_hw_control_set,
++ .led_hw_control_get = aqr_phy_led_hw_control_get,
++ .led_polarity_set = aqr_phy_led_polarity_set,
+ },
+ {
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR813),
+@@ -880,6 +934,11 @@ static struct phy_driver aqr_driver[] =
+ .get_strings = aqr107_get_strings,
+ .get_stats = aqr107_get_stats,
+ .link_change_notify = aqr107_link_change_notify,
++ .led_brightness_set = aqr_phy_led_brightness_set,
++ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
++ .led_hw_control_set = aqr_phy_led_hw_control_set,
++ .led_hw_control_get = aqr_phy_led_hw_control_get,
++ .led_polarity_set = aqr_phy_led_polarity_set,
+ },
+ };
+
--- a/drivers/net/phy/aquantia/aquantia_main.c
+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -127,6 +127,29 @@ struct aqr107_priv {
- u64 sgmii_stats[AQR107_SGMII_STAT_SZ];
- };
+@@ -90,6 +90,29 @@
+ #define AQR107_OP_IN_PROG_SLEEP 1000
+ #define AQR107_OP_IN_PROG_TIMEOUT 100000
+/* registers in MDIO_MMD_VEND1 region */
+#define AQUANTIA_VND1_GLOBAL_SC 0x000
static int aqr107_get_sset_count(struct phy_device *phydev)
{
return AQR107_SGMII_STAT_SZ;
-@@ -233,6 +256,51 @@ static int aqr_config_aneg(struct phy_de
+@@ -196,6 +219,51 @@ static int aqr_config_aneg(struct phy_de
return genphy_c45_check_and_restart_aneg(phydev, changed);
}
static int aqr_config_intr(struct phy_device *phydev)
{
bool en = phydev->interrupts == PHY_INTERRUPT_ENABLED;
-@@ -838,7 +906,7 @@ static struct phy_driver aqr_driver[] =
+@@ -807,7 +875,7 @@ static struct phy_driver aqr_driver[] =
PHY_ID_MATCH_MODEL(PHY_ID_AQR112),
.name = "Aquantia AQR112",
.probe = aqr107_probe,
.config_intr = aqr_config_intr,
.handle_interrupt = aqr_handle_interrupt,
.get_tunable = aqr107_get_tunable,
-@@ -863,7 +931,7 @@ static struct phy_driver aqr_driver[] =
+@@ -830,7 +898,7 @@ static struct phy_driver aqr_driver[] =
PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
.name = "Aquantia AQR412",
.probe = aqr107_probe,
--- a/drivers/net/phy/aquantia/aquantia_main.c
+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -289,10 +289,16 @@ static int aqr_config_aneg_set_prot(stru
+@@ -252,10 +252,16 @@ static int aqr_config_aneg_set_prot(stru
phy_write_mmd(phydev, MDIO_MMD_VEND1, AQUANTIA_VND1_GSTART_RATE,
aquantia_syscfg[if_type].start_rate);
#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
-@@ -1062,6 +1064,30 @@ static struct phy_driver aqr_driver[] =
+@@ -1014,6 +1016,30 @@ static struct phy_driver aqr_driver[] =
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
.led_polarity_set = aqr_phy_led_polarity_set,
- #endif
},
+{
+ PHY_ID_MATCH_MODEL(PHY_ID_AQR112C),
};
module_phy_driver(aqr_driver);
-@@ -1082,6 +1108,8 @@ static struct mdio_device_id __maybe_unu
+@@ -1034,6 +1060,8 @@ static struct mdio_device_id __maybe_unu
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR113C) },
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR114C) },
{ PHY_ID_MATCH_MODEL(PHY_ID_AQR813) },
+++ /dev/null
-From c6a1759365fc35463138a7d9e335ee53f384b8df Mon Sep 17 00:00:00 2001
-From: Daniel Golle <daniel@makrotopia.org>
-Date: Fri, 10 May 2024 02:53:52 +0100
-Subject: [PATCH] net: phy: aquantia: add support for PHY LEDs
-
-Aquantia Ethernet PHYs got 3 LED output pins which are typically used
-to indicate link status and activity.
-Add a minimal LED controller driver supporting the most common uses
-with the 'netdev' trigger as well as software-driven forced control of
-the LEDs.
-
-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
----
- drivers/net/phy/aquantia/Makefile | 3 +
- drivers/net/phy/aquantia/aquantia.h | 84 +++++++++++++
- drivers/net/phy/aquantia/aquantia_leds.c | 152 +++++++++++++++++++++++
- drivers/net/phy/aquantia/aquantia_main.c | 127 +++++++++++++------
- 4 files changed, 329 insertions(+), 37 deletions(-)
- create mode 100644 drivers/net/phy/aquantia/aquantia_leds.c
-
---- a/drivers/net/phy/aquantia/Makefile
-+++ b/drivers/net/phy/aquantia/Makefile
-@@ -3,4 +3,7 @@ aquantia-objs += aquantia_main.o aquan
- ifdef CONFIG_HWMON
- aquantia-objs += aquantia_hwmon.o
- endif
-+ifdef CONFIG_PHYLIB_LEDS
-+aquantia-objs += aquantia_leds.o
-+endif
- obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
---- a/drivers/net/phy/aquantia/aquantia.h
-+++ b/drivers/net/phy/aquantia/aquantia.h
-@@ -62,6 +62,26 @@
- #define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
- #define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
- #define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424
-+
-+#define AQR_NUM_LEDS 3
-+
-+#define VEND1_GLOBAL_LED_PROV 0xc430
-+#define AQR_LED_PROV(x) (VEND1_GLOBAL_LED_PROV + x)
-+#define VEND1_GLOBAL_LED_PROV_ACT_STRETCH GENMASK(0, 1)
-+#define VEND1_GLOBAL_LED_PROV_TX_ACT BIT(2)
-+#define VEND1_GLOBAL_LED_PROV_RX_ACT BIT(3)
-+#define VEND1_GLOBAL_LED_PROV_LINK_MASK (GENMASK(15, 14) | GENMASK(8, 5))
-+#define VEND1_GLOBAL_LED_PROV_LINK100 BIT(5)
-+#define VEND1_GLOBAL_LED_PROV_LINK1000 BIT(6)
-+#define VEND1_GLOBAL_LED_PROV_LINK10000 BIT(7)
-+#define VEND1_GLOBAL_LED_PROV_FORCE_ON BIT(8)
-+#define VEND1_GLOBAL_LED_PROV_LINK2500 BIT(14)
-+#define VEND1_GLOBAL_LED_PROV_LINK5000 BIT(15)
-+
-+#define VEND1_GLOBAL_LED_DRIVE 0xc438
-+#define VEND1_GLOBAL_LED_DRIVE_VDD BIT(1)
-+#define AQR_LED_DRIVE(x) (VEND1_GLOBAL_LED_DRIVE + x)
-+
- #define VEND1_THERMAL_STAT1 0xc820
- #define VEND1_THERMAL_STAT2 0xc821
- #define VEND1_THERMAL_STAT2_VALID BIT(0)
-@@ -115,3 +135,23 @@ static inline int aqr_hwmon_probe(struct
- #endif
-
- int aqr_firmware_load(struct phy_device *phydev);
-+
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+int aqr_phy_led_blink_set(struct phy_device *phydev, u8 index,
-+ unsigned long *delay_on,
-+ unsigned long *delay_off);
-+
-+int aqr_phy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value);
-+
-+int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules);
-+
-+int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules);
-+
-+int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules);
-+
-+int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes);
-+#endif
---- /dev/null
-+++ b/drivers/net/phy/aquantia/aquantia_leds.c
-@@ -0,0 +1,140 @@
-+// SPDX-License-Identifier: GPL-2.0
-+/* LED driver for Aquantia PHY
-+ *
-+ * Author: Daniel Golle <daniel@makrotopia.org>
-+ */
-+
-+#include <linux/phy.h>
-+
-+#include "aquantia.h"
-+
-+int aqr_phy_led_brightness_set(struct phy_device *phydev,
-+ u8 index, enum led_brightness value)
-+{
-+ if (index > 2)
-+ return -EINVAL;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index), VEND1_GLOBAL_LED_PROV_LINK_MASK |
-+ VEND1_GLOBAL_LED_PROV_FORCE_ON |
-+ VEND1_GLOBAL_LED_PROV_RX_ACT |
-+ VEND1_GLOBAL_LED_PROV_TX_ACT,
-+ value ? VEND1_GLOBAL_LED_PROV_FORCE_ON : 0);
-+}
-+
-+static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
-+ BIT(TRIGGER_NETDEV_LINK_100) |
-+ BIT(TRIGGER_NETDEV_LINK_1000) |
-+ BIT(TRIGGER_NETDEV_LINK_2500) |
-+ BIT(TRIGGER_NETDEV_LINK_5000) |
-+ BIT(TRIGGER_NETDEV_LINK_10000) |
-+ BIT(TRIGGER_NETDEV_RX) |
-+ BIT(TRIGGER_NETDEV_TX));
-+
-+int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ if (index >= AQR_NUM_LEDS)
-+ return -EINVAL;
-+
-+ /* All combinations of the supported triggers are allowed */
-+ if (rules & ~supported_triggers)
-+ return -EOPNOTSUPP;
-+
-+ return 0;
-+}
-+
-+int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
-+ unsigned long *rules)
-+{
-+ int val;
-+
-+ if (index >= AQR_NUM_LEDS)
-+ return -EINVAL;
-+
-+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index));
-+ if (val < 0)
-+ return val;
-+
-+ *rules = 0;
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK100)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK1000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK2500)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK5000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_5000);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_LINK10000)
-+ *rules |= BIT(TRIGGER_NETDEV_LINK_10000);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_RX_ACT)
-+ *rules |= BIT(TRIGGER_NETDEV_RX);
-+
-+ if (val & VEND1_GLOBAL_LED_PROV_TX_ACT)
-+ *rules |= BIT(TRIGGER_NETDEV_TX);
-+
-+ return 0;
-+}
-+
-+int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
-+ unsigned long rules)
-+{
-+ u16 val = 0;
-+
-+ if (index >= AQR_NUM_LEDS)
-+ return -EINVAL;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK100;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK1000;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK2500;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK5000;
-+
-+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK)))
-+ val |= VEND1_GLOBAL_LED_PROV_LINK10000;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_RX))
-+ val |= VEND1_GLOBAL_LED_PROV_RX_ACT;
-+
-+ if (rules & BIT(TRIGGER_NETDEV_TX))
-+ val |= VEND1_GLOBAL_LED_PROV_TX_ACT;
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),
-+ VEND1_GLOBAL_LED_PROV_LINK_MASK |
-+ VEND1_GLOBAL_LED_PROV_FORCE_ON |
-+ VEND1_GLOBAL_LED_PROV_RX_ACT |
-+ VEND1_GLOBAL_LED_PROV_TX_ACT, val);
-+}
-+
-+int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
-+{
-+ bool active_low = false;
-+ u32 mode;
-+
-+ if (index >= AQR_NUM_LEDS)
-+ return -EINVAL;
-+
-+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
-+ switch (mode) {
-+ case PHY_LED_ACTIVE_LOW:
-+ active_low = true;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+ }
-+
-+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
-+ VEND1_GLOBAL_LED_DRIVE_VDD,
-+ active_low ? VEND1_GLOBAL_LED_DRIVE_VDD : 0);
-+}
---- a/drivers/net/phy/aquantia/aquantia_main.c
-+++ b/drivers/net/phy/aquantia/aquantia_main.c
-@@ -740,6 +740,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
-@@ -759,6 +766,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR111),
-@@ -778,6 +792,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0),
-@@ -797,6 +818,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR405),
-@@ -823,6 +851,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
-@@ -841,6 +876,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR113),
-@@ -860,6 +902,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
-@@ -879,6 +928,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR114C),
-@@ -898,6 +954,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- {
- PHY_ID_MATCH_MODEL(PHY_ID_AQR813),
-@@ -917,6 +980,13 @@ static struct phy_driver aqr_driver[] =
- .get_strings = aqr107_get_strings,
- .get_stats = aqr107_get_stats,
- .link_change_notify = aqr107_link_change_notify,
-+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
-+ .led_brightness_set = aqr_phy_led_brightness_set,
-+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
-+ .led_hw_control_set = aqr_phy_led_hw_control_set,
-+ .led_hw_control_get = aqr_phy_led_hw_control_get,
-+ .led_polarity_set = aqr_phy_led_polarity_set,
-+#endif
- },
- };
-
+++ /dev/null
-From 6e6fff51ae5e54092611d174fa45fa78c237a415 Mon Sep 17 00:00:00 2001
-From: Christian Marangi <ansuelsmth@gmail.com>
-Date: Tue, 21 May 2024 20:01:46 +0200
-Subject: [PATCH] net: phy: move LED polarity to phy_init_hw
-
-Some PHY reset the polarity on reset and this cause the LED to
-malfunction as LED polarity is configured only when LED is
-registered.
-
-To better handle this, move the LED polarity configuration in
-phy_init_hw to reconfigure it after PHY reset.
-
-Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
----
- drivers/net/phy/phy_device.c | 53 +++++++++++++++++++++++++-----------
- 1 file changed, 37 insertions(+), 16 deletions(-)
-
---- a/drivers/net/phy/phy_device.c
-+++ b/drivers/net/phy/phy_device.c
-@@ -1223,6 +1223,37 @@ static int phy_poll_reset(struct phy_dev
- return 0;
- }
-
-+static int of_phy_led_init(struct phy_device *phydev)
-+{
-+ struct phy_led *phyled;
-+
-+ list_for_each_entry(phyled, &phydev->leds, list) {
-+ struct led_classdev *cdev = &phyled->led_cdev;
-+ struct device_node *np = cdev->dev->of_node;
-+ unsigned long modes = 0;
-+ int err;
-+
-+ if (of_property_read_bool(np, "active-low"))
-+ set_bit(PHY_LED_ACTIVE_LOW, &modes);
-+ if (of_property_read_bool(np, "inactive-high-impedance"))
-+ set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
-+
-+ if (!modes)
-+ continue;
-+
-+ /* Return error if asked to set polarity modes but not supported */
-+ if (!phydev->drv->led_polarity_set)
-+ return -EINVAL;
-+
-+ err = phydev->drv->led_polarity_set(phydev, phyled->index,
-+ modes);
-+ if (err)
-+ return err;
-+ }
-+
-+ return 0;
-+}
-+
- int phy_init_hw(struct phy_device *phydev)
- {
- int ret = 0;
-@@ -1261,6 +1292,12 @@ int phy_init_hw(struct phy_device *phyde
- return ret;
- }
-
-+ if (IS_ENABLED(CONFIG_PHYLIB_LEDS)) {
-+ ret = of_phy_led_init(phydev);
-+ if (ret < 0)
-+ return ret;
-+ }
-+
- return 0;
- }
- EXPORT_SYMBOL(phy_init_hw);
-@@ -3206,7 +3243,6 @@ static int of_phy_led(struct phy_device
- struct device *dev = &phydev->mdio.dev;
- struct led_init_data init_data = {};
- struct led_classdev *cdev;
-- unsigned long modes = 0;
- struct phy_led *phyled;
- u32 index;
- int err;
-@@ -3224,21 +3260,6 @@ static int of_phy_led(struct phy_device
- if (index > U8_MAX)
- return -EINVAL;
-
-- if (of_property_read_bool(led, "active-low"))
-- set_bit(PHY_LED_ACTIVE_LOW, &modes);
-- if (of_property_read_bool(led, "inactive-high-impedance"))
-- set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
--
-- if (modes) {
-- /* Return error if asked to set polarity modes but not supported */
-- if (!phydev->drv->led_polarity_set)
-- return -EINVAL;
--
-- err = phydev->drv->led_polarity_set(phydev, index, modes);
-- if (err)
-- return err;
-- }
--
- phyled->index = index;
- if (phydev->drv->led_brightness_set)
- cdev->brightness_set_blocking = phy_led_set_brightness;