From: Artem Shimko <a.shimko.dev@gmail.com>
To: andrew@lunn.ch, hkallweit1@gmail.com, linux@armlinux.org.uk,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, robh@kernel.org, krzk+dt@kernel.org,
conor+dt@kernel.org, maxime.chevallier@bootlin.com, pavel@ucw.cz,
linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
linux-leds@vger.kernel.org
Cc: Artem Shimko <a.shimko.dev@gmail.com>, netdev@vger.kernel.org
Subject: [PATCH net-next 3/3] net: phy: dap8211r: add led hardware control support
Date: Fri, 13 Nov 2026 14:05:45 +0300 [thread overview]
Message-ID: <20261113110546.173624-4-a.shimko.dev@gmail.com> (raw)
In-Reply-To: <20261113110546.173624-1-a.shimko.dev@gmail.com>
Add support for hardware-controlled leds on the dap8211r phy. The chip
exposes three led that can be programmed to react to link, speed,
duplex, and tx/rx activity.
Implement callbacks for led_hw_is_supported(), led_hw_control_set()
led_hw_control_get().
Signed-off-by: Artem Shimko <a.shimko.dev@gmail.com>
---
drivers/net/phy/dap8211r.c | 181 +++++++++++++++++++++++++++++++++++++
1 file changed, 181 insertions(+)
diff --git a/drivers/net/phy/dap8211r.c b/drivers/net/phy/dap8211r.c
index 4eb50c26397f..2e371c231d32 100644
--- a/drivers/net/phy/dap8211r.c
+++ b/drivers/net/phy/dap8211r.c
@@ -12,6 +12,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/bitops.h>
#include <linux/errno.h>
#include <linux/ethtool.h>
#include <linux/kernel.h>
@@ -57,6 +58,33 @@
*/
#define DAP8211R_DEFAULT_DEL_SEL 0xD
+#define DAP8211R_LED_ID_0 0
+#define DAP8211R_LED_ID_1 1
+#define DAP8211R_LED_ID_2 2
+#define DAP8211R_LED_0 0xA00C
+#define DAP8211R_LED_1 0xA00D
+#define DAP8211R_LED_2 0xA00E
+#define DAP8211R_LED_ACT_BLINK BIT(13)
+#define DAP8211R_LED_FULL_DUPLEX BIT(12)
+#define DAP8211R_LED_HALF_DUPLEX BIT(11)
+#define DAP8211R_LED_TX BIT(10)
+#define DAP8211R_LED_RX BIT(9)
+#define DAP8211R_LED_LINK_1000 BIT(6)
+#define DAP8211R_LED_LINK_100 BIT(5)
+#define DAP8211R_LED_LINK_10 BIT(4)
+
+#define DAP8211R_LED_LINK (DAP8211R_LED_LINK_10 | \
+ DAP8211R_LED_LINK_100 | \
+ DAP8211R_LED_LINK_1000)
+
+#define DAP8211R_LED_SUPPORTED_TRG (BIT(TRIGGER_NETDEV_LINK_10) | \
+ BIT(TRIGGER_NETDEV_LINK_100) | \
+ BIT(TRIGGER_NETDEV_LINK_1000) | \
+ BIT(TRIGGER_NETDEV_TX) | \
+ BIT(TRIGGER_NETDEV_RX) | \
+ BIT(TRIGGER_NETDEV_HALF_DUPLEX) | \
+ BIT(TRIGGER_NETDEV_FULL_DUPLEX))
+
static const int dap8211r_internal_delay[] = {0, 150, 300, 450, 600, 750, 900,
1050, 1200, 1350, 1500, 1650, 1800,
1950, 2100, 2250};
@@ -142,6 +170,156 @@ static int dap8211r_modify_ext(struct phy_device *phydev, u16 reg, u16 mask, u16
return ret;
}
+/**
+ * dap8211r_led_hw_is_supported() - Check if the requested LED rules are supported
+ * @phydev: PHY device structure
+ * @index: LED index
+ * @rules: Bitmask of requested netdev trigger rules
+ *
+ * Validates the requested combination of rules which can be represented in the
+ * hardware register.
+ *
+ * Return: 0 on success, -EINVAL for an invalid LED index,
+ * or -EOPNOTSUPP if any requested rule is not supported by the PHY
+ */
+static int dap8211r_led_hw_is_supported(struct phy_device *phydev, u8 index, unsigned long rules)
+{
+ switch (index) {
+ case DAP8211R_LED_ID_0:
+ fallthrough;
+ case DAP8211R_LED_ID_1:
+ fallthrough;
+ case DAP8211R_LED_ID_2:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return (rules & ~DAP8211R_LED_SUPPORTED_TRG) ? -EOPNOTSUPP : 0;
+}
+
+/**
+ * dap8211r_led_hw_control_set() - Program the LED control register
+ * @phydev: PHY device structure
+ * @index: LED index
+ * @rules: Bitmask of requested netdev trigger rules
+ *
+ * Translates the requested trigger rules into the corresponding bit
+ * positions of the LED control register and writes the resulting value
+ * to the PHY.
+ *
+ * Note that the ACT_BLINK bit (13) must be set together with TX/RX rules,
+ * otherwise the LED will not blink on traffic if no other rule (such as
+ * link or duplex) is active.
+ *
+ * Return: 0 on success, -EINVAL for an invalid LED index, or a negative error code
+ */
+static int dap8211r_led_hw_control_set(struct phy_device *phydev, u8 index, unsigned long rules)
+{
+ u16 led_mode = 0, led_reg;
+
+ switch (index) {
+ case DAP8211R_LED_ID_0:
+ led_reg = DAP8211R_LED_0;
+ break;
+ case DAP8211R_LED_ID_1:
+ led_reg = DAP8211R_LED_1;
+ break;
+ case DAP8211R_LED_ID_2:
+ led_reg = DAP8211R_LED_2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (test_bit(TRIGGER_NETDEV_LINK, &rules))
+ led_mode |= DAP8211R_LED_LINK;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
+ led_mode |= DAP8211R_LED_LINK_10;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
+ led_mode |= DAP8211R_LED_LINK_100;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
+ led_mode |= DAP8211R_LED_LINK_1000;
+
+ if (test_bit(TRIGGER_NETDEV_RX, &rules))
+ led_mode |= DAP8211R_LED_RX | DAP8211R_LED_ACT_BLINK;
+
+ if (test_bit(TRIGGER_NETDEV_TX, &rules))
+ led_mode |= DAP8211R_LED_TX | DAP8211R_LED_ACT_BLINK;
+
+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
+ led_mode |= DAP8211R_LED_HALF_DUPLEX;
+
+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
+ led_mode |= DAP8211R_LED_FULL_DUPLEX;
+
+ if (!led_mode)
+ return -EOPNOTSUPP;
+
+ return dap8211r_write_ext(phydev, led_reg, led_mode);
+}
+
+/**
+ * dap8211r_led_hw_control_get() - Read the current LED configuration
+ * @phydev: PHY device structure
+ * @index: LED index
+ * @rules: Pointer to a bitmask where the current rules will be stored
+ *
+ * Reads the LED control register and translates the hardware bit
+ * positions back into the corresponding netdev trigger rules bitmask.
+ *
+ * Return: 0 on success, -EINVAL for an invalid LED index, or a negative error code
+ */
+static int dap8211r_led_hw_control_get(struct phy_device *phydev, u8 index, unsigned long *rules)
+{
+ u16 led_reg;
+ int led_mode = 0;
+
+ switch (index) {
+ case DAP8211R_LED_ID_0:
+ led_reg = DAP8211R_LED_0;
+ break;
+ case DAP8211R_LED_ID_1:
+ led_reg = DAP8211R_LED_1;
+ break;
+ case DAP8211R_LED_ID_2:
+ led_reg = DAP8211R_LED_2;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ led_mode = dap8211r_read_ext(phydev, led_reg);
+ if (led_mode < 0)
+ return led_mode;
+
+ if (led_mode & DAP8211R_LED_LINK_10)
+ __set_bit(TRIGGER_NETDEV_LINK_10, rules);
+
+ if (led_mode & DAP8211R_LED_LINK_100)
+ __set_bit(TRIGGER_NETDEV_LINK_100, rules);
+
+ if (led_mode & DAP8211R_LED_LINK_1000)
+ __set_bit(TRIGGER_NETDEV_LINK_1000, rules);
+
+ if (led_mode & DAP8211R_LED_RX)
+ __set_bit(TRIGGER_NETDEV_RX, rules);
+
+ if (led_mode & DAP8211R_LED_TX)
+ __set_bit(TRIGGER_NETDEV_TX, rules);
+
+ if (led_mode & DAP8211R_LED_HALF_DUPLEX)
+ __set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
+
+ if (led_mode & DAP8211R_LED_FULL_DUPLEX)
+ __set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
+
+ return 0;
+}
+
/**
* dap8211r_config_init() - Initialize PHY
* @phydev: PHY device structure
@@ -230,6 +408,9 @@ static struct phy_driver dap8211r_driver[] = {
.config_aneg = genphy_config_aneg,
.suspend = genphy_suspend,
.resume = genphy_resume,
+ .led_hw_is_supported = dap8211r_led_hw_is_supported,
+ .led_hw_control_set = dap8211r_led_hw_control_set,
+ .led_hw_control_get = dap8211r_led_hw_control_get,
},
};
module_phy_driver(dap8211r_driver);
--
2.43.0
prev parent reply other threads:[~2026-11-13 11:05 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-13 11:05 [PATCH net-next 0/3] net: phy: dap8211r: add LED hardware control Artem Shimko
2026-11-13 11:05 ` [PATCH net-next 1/3] dt-bindings: net: dptel,dap8211r: add led nodes Artem Shimko
2026-11-13 11:05 ` [PATCH net-next 2/3] net: phy: dap8211r: add extended register write helper Artem Shimko
2026-11-13 11:05 ` Artem Shimko [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261113110546.173624-4-a.shimko.dev@gmail.com \
--to=a.shimko.dev@gmail.com \
--cc=andrew@lunn.ch \
--cc=conor+dt@kernel.org \
--cc=davem@davemloft.net \
--cc=devicetree@vger.kernel.org \
--cc=edumazet@google.com \
--cc=hkallweit1@gmail.com \
--cc=krzk+dt@kernel.org \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-leds@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=maxime.chevallier@bootlin.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=pavel@ucw.cz \
--cc=robh@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox