]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: phy: dp83td510: introduce LED framework support
authorOleksij Rempel <o.rempel@pengutronix.de>
Wed, 5 Feb 2025 10:38:46 +0000 (11:38 +0100)
committerJakub Kicinski <kuba@kernel.org>
Tue, 11 Feb 2025 01:49:19 +0000 (17:49 -0800)
Add LED brightness, mode, HW control and polarity functions to enable
external LED control in the TI DP83TD510 PHY.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Link: https://patch.msgid.link/20250205103846.2273833-1-o.rempel@pengutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/phy/dp83td510.c

index a42af9c168ec59548a18ea3a1ccb032eda55ef61..23af1ac194fa9c0957ade37a7eb7a388534023cd 100644 (file)
@@ -204,10 +204,191 @@ struct dp83td510_priv {
 #define DP83TD510E_UNKN_030E                           0x30e
 #define DP83TD510E_030E_VAL                            0x2520
 
+#define DP83TD510E_LEDS_CFG_1                          0x460
+#define DP83TD510E_LED_FN(idx, val)            (((val) & 0xf) << ((idx) * 4))
+#define DP83TD510E_LED_FN_MASK(idx)                    (0xf << ((idx) * 4))
+/* link OK */
+#define DP83TD510E_LED_MODE_LINK_OK                    0x0
+/* TX/RX activity */
+#define DP83TD510E_LED_MODE_TX_RX_ACTIVITY             0x1
+/* TX activity */
+#define DP83TD510E_LED_MODE_TX_ACTIVITY                        0x2
+/* RX activity */
+#define DP83TD510E_LED_MODE_RX_ACTIVITY                        0x3
+/* LR */
+#define DP83TD510E_LED_MODE_LR                         0x4
+/* SR */
+#define DP83TD510E_LED_MODE_SR                         0x5
+/* LED SPEED: High for 10Base-T */
+#define DP83TD510E_LED_MODE_LED_SPEED                  0x6
+/* Duplex mode */
+#define DP83TD510E_LED_MODE_DUPLEX                     0x7
+/* link + blink on activity with stretch option */
+#define DP83TD510E_LED_MODE_LINK_BLINK                 0x8
+/* blink on activity with stretch option */
+#define DP83TD510E_LED_MODE_BLINK_ACTIVITY             0x9
+/* blink on tx activity with stretch option */
+#define DP83TD510E_LED_MODE_BLINK_TX                   0xa
+/* blink on rx activity with stretch option */
+#define DP83TD510E_LED_MODE_BLINK_RX                   0xb
+/* link_lost */
+#define DP83TD510E_LED_MODE_LINK_LOST                  0xc
+/* PRBS error: toggles on error */
+#define DP83TD510E_LED_MODE_PRBS_ERROR                 0xd
+/* XMII TX/RX Error with stretch option */
+#define DP83TD510E_LED_MODE_XMII_ERR                   0xe
+
+#define DP83TD510E_LED_COUNT                           4
+
+#define DP83TD510E_LEDS_CFG_2                          0x469
+#define DP83TD510E_LED_POLARITY(idx)                   BIT((idx) * 4 + 2)
+#define DP83TD510E_LED_DRV_VAL(idx)                    BIT((idx) * 4 + 1)
+#define DP83TD510E_LED_DRV_EN(idx)                     BIT((idx) * 4)
+
 #define DP83TD510E_ALCD_STAT                           0xa9f
 #define DP83TD510E_ALCD_COMPLETE                       BIT(15)
 #define DP83TD510E_ALCD_CABLE_LENGTH                   GENMASK(10, 0)
 
+static int dp83td510_led_brightness_set(struct phy_device *phydev, u8 index,
+                                       enum led_brightness brightness)
+{
+       u32 val;
+
+       if (index >= DP83TD510E_LED_COUNT)
+               return -EINVAL;
+
+       val = DP83TD510E_LED_DRV_EN(index);
+
+       if (brightness)
+               val |= DP83TD510E_LED_DRV_VAL(index);
+
+       return phy_modify_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_LEDS_CFG_2,
+                             DP83TD510E_LED_DRV_VAL(index) |
+                             DP83TD510E_LED_DRV_EN(index), val);
+}
+
+static int dp83td510_led_mode(u8 index, unsigned long rules)
+{
+       if (index >= DP83TD510E_LED_COUNT)
+               return -EINVAL;
+
+       switch (rules) {
+       case BIT(TRIGGER_NETDEV_LINK):
+               return DP83TD510E_LED_MODE_LINK_OK;
+       case BIT(TRIGGER_NETDEV_LINK_10):
+               return DP83TD510E_LED_MODE_LED_SPEED;
+       case BIT(TRIGGER_NETDEV_FULL_DUPLEX):
+               return DP83TD510E_LED_MODE_DUPLEX;
+       case BIT(TRIGGER_NETDEV_TX):
+               return DP83TD510E_LED_MODE_TX_ACTIVITY;
+       case BIT(TRIGGER_NETDEV_RX):
+               return DP83TD510E_LED_MODE_RX_ACTIVITY;
+       case BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX):
+               return DP83TD510E_LED_MODE_TX_RX_ACTIVITY;
+       case BIT(TRIGGER_NETDEV_LINK) | BIT(TRIGGER_NETDEV_TX) |
+                       BIT(TRIGGER_NETDEV_RX):
+               return DP83TD510E_LED_MODE_LINK_BLINK;
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+static int dp83td510_led_hw_is_supported(struct phy_device *phydev, u8 index,
+                                        unsigned long rules)
+{
+       int ret;
+
+       ret = dp83td510_led_mode(index, rules);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int dp83td510_led_hw_control_set(struct phy_device *phydev, u8 index,
+                                       unsigned long rules)
+{
+       int mode, ret;
+
+       mode = dp83td510_led_mode(index, rules);
+       if (mode < 0)
+               return mode;
+
+       ret = phy_modify_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_LEDS_CFG_1,
+                            DP83TD510E_LED_FN_MASK(index),
+                            DP83TD510E_LED_FN(index, mode));
+       if (ret)
+               return ret;
+
+       return phy_modify_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_LEDS_CFG_2,
+                               DP83TD510E_LED_DRV_EN(index), 0);
+}
+
+static int dp83td510_led_hw_control_get(struct phy_device *phydev,
+                                       u8 index, unsigned long *rules)
+{
+       int val;
+
+       val = phy_read_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_LEDS_CFG_1);
+       if (val < 0)
+               return val;
+
+       val &= DP83TD510E_LED_FN_MASK(index);
+       val >>= index * 4;
+
+       switch (val) {
+       case DP83TD510E_LED_MODE_LINK_OK:
+               *rules = BIT(TRIGGER_NETDEV_LINK);
+               break;
+       /* LED mode: LED SPEED (10BaseT1L indicator) */
+       case DP83TD510E_LED_MODE_LED_SPEED:
+               *rules = BIT(TRIGGER_NETDEV_LINK_10);
+               break;
+       case DP83TD510E_LED_MODE_DUPLEX:
+               *rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX);
+               break;
+       case DP83TD510E_LED_MODE_TX_ACTIVITY:
+               *rules = BIT(TRIGGER_NETDEV_TX);
+               break;
+       case DP83TD510E_LED_MODE_RX_ACTIVITY:
+               *rules = BIT(TRIGGER_NETDEV_RX);
+               break;
+       case DP83TD510E_LED_MODE_TX_RX_ACTIVITY:
+               *rules = BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
+               break;
+       case DP83TD510E_LED_MODE_LINK_BLINK:
+               *rules = BIT(TRIGGER_NETDEV_LINK) |
+                        BIT(TRIGGER_NETDEV_TX) |
+                        BIT(TRIGGER_NETDEV_RX);
+               break;
+       default:
+               *rules = 0;
+               break;
+       }
+
+       return 0;
+}
+
+static int dp83td510_led_polarity_set(struct phy_device *phydev, int index,
+                                     unsigned long modes)
+{
+       u16 polarity = DP83TD510E_LED_POLARITY(index);
+       u32 mode;
+
+       for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
+               switch (mode) {
+               case PHY_LED_ACTIVE_LOW:
+                       polarity = 0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return phy_modify_mmd(phydev, MDIO_MMD_VEND2, DP83TD510E_LEDS_CFG_2,
+                             DP83TD510E_LED_POLARITY(index), polarity);
+}
+
 /**
  * dp83td510_update_stats - Update the PHY statistics for the DP83TD510 PHY.
  * @phydev: Pointer to the phy_device structure.
@@ -712,6 +893,12 @@ static struct phy_driver dp83td510_driver[] = {
        .get_phy_stats  = dp83td510_get_phy_stats,
        .update_stats   = dp83td510_update_stats,
 
+       .led_brightness_set = dp83td510_led_brightness_set,
+       .led_hw_is_supported = dp83td510_led_hw_is_supported,
+       .led_hw_control_set = dp83td510_led_hw_control_set,
+       .led_hw_control_get = dp83td510_led_hw_control_get,
+       .led_polarity_set = dp83td510_led_polarity_set,
+
        .suspend        = genphy_suspend,
        .resume         = genphy_resume,
 } };