1 // SPDX-License-Identifier: GPL-2.0 2 /* LED driver for Aquantia PHY 3 * 4 * Author: Daniel Golle <daniel@makrotopia.org> 5 */ 6 7 #include <linux/phy.h> 8 9 #include "aquantia.h" 10 11 int 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 25 static 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 34 int 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 47 int 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 84 int 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 120 int 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 127 int 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