From 5117ce8c35d1645e9839bc892b5944556faddb1c Mon Sep 17 00:00:00 2001 From: Donggeun Yoo Date: Wed, 16 Sep 2026 07:31:37 +0900 Subject: [PATCH 1/2] net: phy: qca808x: accept the active-high LED polarity mode commit a274465cc3be ("net: phy: support 'active-high' property for PHY LEDs") added PHY_LED_ACTIVE_HIGH, but qca808x_led_polarity_set() still rejects everything except PHY_LED_ACTIVE_LOW. An LED node carrying 'active-high' therefore falls into the default case and returns -EINVAL, which phy_probe() propagates: the mdio device is left unbound and phy_attach_direct() falls back to the genphy driver, so the PHY loses every qca808x-specific feature, not just the LED. Accept the mode. The register write below already handles both polarities. Cc: stable+noautosel@kernel.org # never worked Signed-off-by: Donggeun Yoo Reviewed-by: Christian Marangi Link: https://patch.msgid.link/20260915223138.321307-2-donggeunyoo.kernel@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/qcom/qca808x.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index 8eb51b1a006c..3ba58f14e248 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -603,6 +603,9 @@ static int qca808x_led_polarity_set(struct phy_device *phydev, int index, case PHY_LED_ACTIVE_LOW: active_low = true; break; + case PHY_LED_ACTIVE_HIGH: + active_low = false; + break; default: return -EINVAL; } From f1b4766d67bb2d496eb74b0ecfe0dc55a9ab03e0 Mon Sep 17 00:00:00 2001 From: Donggeun Yoo Date: Wed, 16 Sep 2026 07:31:38 +0900 Subject: [PATCH 2/2] net: phy: qca808x: keep an explicit active-high LED across the reset With the previous patch an 'active-high' LED node is accepted, so led_polarity_mode can now hold 0. qca808x_config_init() only re-asserts QCA808X_LED_ACTIVE_HIGH when the mode is -1, the value that means device tree asked for nothing, so an explicit active-high does not reach the register. That matters because the bit does not survive a reset. phy_init_hw() runs .soft_reset before .config_init on every attach and resume, and commit f203c8c77c76 ("net: phy: qcom: qca808x: default to LED active High if not set") records why: "on PHY reset, the Active High bit is not set resulting in the LED driven as active-low". The polarity written from device tree during phy_probe() is therefore gone by the time the link comes up, and the LED runs inverted. Re-assert the bit for anything other than an explicit active-low, which is the one case that wants it clear and gets that from the reset for free. Name the unset value while here: led_polarity_mode otherwise holds a PHY_LED_ACTIVE_* value, so spelling the comparison PHY_LED_ACTIVE_LOW says what it means where -1, 0 and 1 did not. Cc: stable+noautosel@kernel.org # never worked Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260908105959.70453-1-donggeunyoo.kernel%40gmail.com Signed-off-by: Donggeun Yoo Reviewed-by: Christian Marangi Link: https://patch.msgid.link/20260915223138.321307-3-donggeunyoo.kernel@gmail.com Signed-off-by: Jakub Kicinski --- drivers/net/phy/qcom/qca808x.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/qcom/qca808x.c b/drivers/net/phy/qcom/qca808x.c index 3ba58f14e248..bab26e4c6140 100644 --- a/drivers/net/phy/qcom/qca808x.c +++ b/drivers/net/phy/qcom/qca808x.c @@ -87,6 +87,9 @@ #define QCA8081_PHY_ID 0x004dd101 +/* led_polarity_mode otherwise holds a PHY_LED_ACTIVE_* value */ +#define QCA808X_PHY_LED_UNSET -1 + MODULE_DESCRIPTION("Qualcomm Atheros QCA808X PHY driver"); MODULE_AUTHOR("Matus Ujhelyi"); MODULE_LICENSE("GPL"); @@ -187,8 +190,7 @@ static int qca808x_probe(struct phy_device *phydev) if (!priv) return -ENOMEM; - /* Init LED polarity mode to -1 */ - priv->led_polarity_mode = -1; + priv->led_polarity_mode = QCA808X_PHY_LED_UNSET; phydev->priv = priv; @@ -200,8 +202,8 @@ static int qca808x_config_init(struct phy_device *phydev) struct qca808x_priv *priv = phydev->priv; int ret; - /* Default to LED Active High if active-low not in DT */ - if (priv->led_polarity_mode == -1) { + /* Set LED Active High unless active-low was requested in DT */ + if (priv->led_polarity_mode != PHY_LED_ACTIVE_LOW) { ret = phy_set_bits_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_POLARITY_CTRL, QCA808X_LED_ACTIVE_HIGH); @@ -615,7 +617,7 @@ static int qca808x_led_polarity_set(struct phy_device *phydev, int index, * To detect this, check if last requested polarity mode * match the new one. */ - if (priv->led_polarity_mode >= 0 && + if (priv->led_polarity_mode != QCA808X_PHY_LED_UNSET && priv->led_polarity_mode != active_low) { phydev_err(phydev, "PHY polarity is global. Mismatched polarity on different LED\n"); return -EINVAL;