|
18 | 18 | #define RTL8168_LED_CTRL_LINK_100 BIT(1) |
19 | 19 | #define RTL8168_LED_CTRL_LINK_10 BIT(0) |
20 | 20 |
|
| 21 | +#define RTL8125_LED_CTRL_ACT BIT(9) |
| 22 | +#define RTL8125_LED_CTRL_LINK_2500 BIT(5) |
| 23 | +#define RTL8125_LED_CTRL_LINK_1000 BIT(3) |
| 24 | +#define RTL8125_LED_CTRL_LINK_100 BIT(1) |
| 25 | +#define RTL8125_LED_CTRL_LINK_10 BIT(0) |
| 26 | + |
21 | 27 | #define RTL8168_NUM_LEDS 3 |
| 28 | +#define RTL8125_NUM_LEDS 4 |
22 | 29 |
|
23 | 30 | struct r8169_led_classdev { |
24 | 31 | struct led_classdev led; |
@@ -156,3 +163,102 @@ void rtl8168_init_leds(struct net_device *ndev) |
156 | 163 | for (i = 0; i < RTL8168_NUM_LEDS; i++) |
157 | 164 | rtl8168_setup_ldev(leds + i, ndev, i); |
158 | 165 | } |
| 166 | + |
| 167 | +static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev, |
| 168 | + unsigned long flags) |
| 169 | +{ |
| 170 | + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); |
| 171 | + struct rtl8169_private *tp = netdev_priv(ldev->ndev); |
| 172 | + |
| 173 | + if (!r8169_trigger_mode_is_valid(flags)) { |
| 174 | + /* Switch LED off to indicate that mode isn't supported */ |
| 175 | + rtl8125_set_led_mode(tp, ldev->index, 0); |
| 176 | + return -EOPNOTSUPP; |
| 177 | + } |
| 178 | + |
| 179 | + return 0; |
| 180 | +} |
| 181 | + |
| 182 | +static int rtl8125_led_hw_control_set(struct led_classdev *led_cdev, |
| 183 | + unsigned long flags) |
| 184 | +{ |
| 185 | + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); |
| 186 | + struct rtl8169_private *tp = netdev_priv(ldev->ndev); |
| 187 | + u16 mode = 0; |
| 188 | + |
| 189 | + if (flags & BIT(TRIGGER_NETDEV_LINK_10)) |
| 190 | + mode |= RTL8125_LED_CTRL_LINK_10; |
| 191 | + if (flags & BIT(TRIGGER_NETDEV_LINK_100)) |
| 192 | + mode |= RTL8125_LED_CTRL_LINK_100; |
| 193 | + if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) |
| 194 | + mode |= RTL8125_LED_CTRL_LINK_1000; |
| 195 | + if (flags & BIT(TRIGGER_NETDEV_LINK_2500)) |
| 196 | + mode |= RTL8125_LED_CTRL_LINK_2500; |
| 197 | + if (flags & (BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX))) |
| 198 | + mode |= RTL8125_LED_CTRL_ACT; |
| 199 | + |
| 200 | + return rtl8125_set_led_mode(tp, ldev->index, mode); |
| 201 | +} |
| 202 | + |
| 203 | +static int rtl8125_led_hw_control_get(struct led_classdev *led_cdev, |
| 204 | + unsigned long *flags) |
| 205 | +{ |
| 206 | + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); |
| 207 | + struct rtl8169_private *tp = netdev_priv(ldev->ndev); |
| 208 | + int mode; |
| 209 | + |
| 210 | + mode = rtl8125_get_led_mode(tp, ldev->index); |
| 211 | + if (mode < 0) |
| 212 | + return mode; |
| 213 | + |
| 214 | + if (mode & RTL8125_LED_CTRL_LINK_10) |
| 215 | + *flags |= BIT(TRIGGER_NETDEV_LINK_10); |
| 216 | + if (mode & RTL8125_LED_CTRL_LINK_100) |
| 217 | + *flags |= BIT(TRIGGER_NETDEV_LINK_100); |
| 218 | + if (mode & RTL8125_LED_CTRL_LINK_1000) |
| 219 | + *flags |= BIT(TRIGGER_NETDEV_LINK_1000); |
| 220 | + if (mode & RTL8125_LED_CTRL_LINK_2500) |
| 221 | + *flags |= BIT(TRIGGER_NETDEV_LINK_2500); |
| 222 | + if (mode & RTL8125_LED_CTRL_ACT) |
| 223 | + *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); |
| 224 | + |
| 225 | + return 0; |
| 226 | +} |
| 227 | + |
| 228 | +static void rtl8125_setup_led_ldev(struct r8169_led_classdev *ldev, |
| 229 | + struct net_device *ndev, int index) |
| 230 | +{ |
| 231 | + struct rtl8169_private *tp = netdev_priv(ndev); |
| 232 | + struct led_classdev *led_cdev = &ldev->led; |
| 233 | + char led_name[LED_MAX_NAME_SIZE]; |
| 234 | + |
| 235 | + ldev->ndev = ndev; |
| 236 | + ldev->index = index; |
| 237 | + |
| 238 | + r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); |
| 239 | + led_cdev->name = led_name; |
| 240 | + led_cdev->hw_control_trigger = "netdev"; |
| 241 | + led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; |
| 242 | + led_cdev->hw_control_is_supported = rtl8125_led_hw_control_is_supported; |
| 243 | + led_cdev->hw_control_set = rtl8125_led_hw_control_set; |
| 244 | + led_cdev->hw_control_get = rtl8125_led_hw_control_get; |
| 245 | + led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; |
| 246 | + |
| 247 | + /* ignore errors */ |
| 248 | + devm_led_classdev_register(&ndev->dev, led_cdev); |
| 249 | +} |
| 250 | + |
| 251 | +void rtl8125_init_leds(struct net_device *ndev) |
| 252 | +{ |
| 253 | + /* bind resource mgmt to netdev */ |
| 254 | + struct device *dev = &ndev->dev; |
| 255 | + struct r8169_led_classdev *leds; |
| 256 | + int i; |
| 257 | + |
| 258 | + leds = devm_kcalloc(dev, RTL8125_NUM_LEDS, sizeof(*leds), GFP_KERNEL); |
| 259 | + if (!leds) |
| 260 | + return; |
| 261 | + |
| 262 | + for (i = 0; i < RTL8125_NUM_LEDS; i++) |
| 263 | + rtl8125_setup_led_ldev(leds + i, ndev, i); |
| 264 | +} |
0 commit comments