152 lines · c
1// SPDX-License-Identifier: GPL-2.02/* LED driver for Aquantia PHY3 *4 * Author: Daniel Golle <daniel@makrotopia.org>5 */6 7#include <linux/phy.h>8 9#include "aquantia.h"10 11int aqr_phy_led_brightness_set(struct phy_device *phydev,12 u8 index, enum led_brightness value)13{14 if (index >= AQR_MAX_LEDS)15 return -EINVAL;16 17 return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),18 VEND1_GLOBAL_LED_PROV_LINK_MASK |19 VEND1_GLOBAL_LED_PROV_FORCE_ON |20 VEND1_GLOBAL_LED_PROV_RX_ACT |21 VEND1_GLOBAL_LED_PROV_TX_ACT,22 value ? VEND1_GLOBAL_LED_PROV_FORCE_ON : 0);23}24 25static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |26 BIT(TRIGGER_NETDEV_LINK_100) |27 BIT(TRIGGER_NETDEV_LINK_1000) |28 BIT(TRIGGER_NETDEV_LINK_2500) |29 BIT(TRIGGER_NETDEV_LINK_5000) |30 BIT(TRIGGER_NETDEV_LINK_10000) |31 BIT(TRIGGER_NETDEV_RX) |32 BIT(TRIGGER_NETDEV_TX));33 34int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,35 unsigned long rules)36{37 if (index >= AQR_MAX_LEDS)38 return -EINVAL;39 40 /* All combinations of the supported triggers are allowed */41 if (rules & ~supported_triggers)42 return -EOPNOTSUPP;43 44 return 0;45}46 47int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,48 unsigned long *rules)49{50 int val;51 52 if (index >= AQR_MAX_LEDS)53 return -EINVAL;54 55 val = phy_read_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index));56 if (val < 0)57 return val;58 59 *rules = 0;60 if (val & VEND1_GLOBAL_LED_PROV_LINK100)61 *rules |= BIT(TRIGGER_NETDEV_LINK_100);62 63 if (val & VEND1_GLOBAL_LED_PROV_LINK1000)64 *rules |= BIT(TRIGGER_NETDEV_LINK_1000);65 66 if (val & VEND1_GLOBAL_LED_PROV_LINK2500)67 *rules |= BIT(TRIGGER_NETDEV_LINK_2500);68 69 if (val & VEND1_GLOBAL_LED_PROV_LINK5000)70 *rules |= BIT(TRIGGER_NETDEV_LINK_5000);71 72 if (val & VEND1_GLOBAL_LED_PROV_LINK10000)73 *rules |= BIT(TRIGGER_NETDEV_LINK_10000);74 75 if (val & VEND1_GLOBAL_LED_PROV_RX_ACT)76 *rules |= BIT(TRIGGER_NETDEV_RX);77 78 if (val & VEND1_GLOBAL_LED_PROV_TX_ACT)79 *rules |= BIT(TRIGGER_NETDEV_TX);80 81 return 0;82}83 84int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,85 unsigned long rules)86{87 u16 val = 0;88 89 if (index >= AQR_MAX_LEDS)90 return -EINVAL;91 92 if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))93 val |= VEND1_GLOBAL_LED_PROV_LINK100;94 95 if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))96 val |= VEND1_GLOBAL_LED_PROV_LINK1000;97 98 if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))99 val |= VEND1_GLOBAL_LED_PROV_LINK2500;100 101 if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK)))102 val |= VEND1_GLOBAL_LED_PROV_LINK5000;103 104 if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK)))105 val |= VEND1_GLOBAL_LED_PROV_LINK10000;106 107 if (rules & BIT(TRIGGER_NETDEV_RX))108 val |= VEND1_GLOBAL_LED_PROV_RX_ACT;109 110 if (rules & BIT(TRIGGER_NETDEV_TX))111 val |= VEND1_GLOBAL_LED_PROV_TX_ACT;112 113 return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),114 VEND1_GLOBAL_LED_PROV_LINK_MASK |115 VEND1_GLOBAL_LED_PROV_FORCE_ON |116 VEND1_GLOBAL_LED_PROV_RX_ACT |117 VEND1_GLOBAL_LED_PROV_TX_ACT, val);118}119 120int aqr_phy_led_active_low_set(struct phy_device *phydev, int index, bool enable)121{122 return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),123 VEND1_GLOBAL_LED_DRIVE_VDD,124 enable ? VEND1_GLOBAL_LED_DRIVE_VDD : 0);125}126 127int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)128{129 struct aqr107_priv *priv = phydev->priv;130 bool active_low = false;131 u32 mode;132 133 if (index >= AQR_MAX_LEDS)134 return -EINVAL;135 136 for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {137 switch (mode) {138 case PHY_LED_ACTIVE_LOW:139 active_low = true;140 break;141 default:142 return -EINVAL;143 }144 }145 146 /* Save LED driver vdd state to restore on SW reset */147 if (active_low)148 priv->leds_active_low |= BIT(index);149 150 return aqr_phy_led_active_low_set(phydev, index, active_low);151}152