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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.