xref: /linux/drivers/net/ethernet/realtek/r8169_leds.c (revision 3a07362fab1653d3aca31a9155c8cc776138fd02)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* r8169_leds.c: Realtek 8169/8168/8101/8125 ethernet driver.
3  *
4  * Copyright (c) 2023 Heiner Kallweit <hkallweit1@gmail.com>
5  *
6  * See MAINTAINERS file for support contact information.
7  */
8 
9 #include <linux/leds.h>
10 #include <linux/netdevice.h>
11 #include <uapi/linux/uleds.h>
12 
13 #include "r8169.h"
14 
15 #define RTL8168_LED_CTRL_OPTION2	BIT(15)
16 #define RTL8168_LED_CTRL_ACT		BIT(3)
17 #define RTL8168_LED_CTRL_LINK_1000	BIT(2)
18 #define RTL8168_LED_CTRL_LINK_100	BIT(1)
19 #define RTL8168_LED_CTRL_LINK_10	BIT(0)
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 
27 #define RTL8168_NUM_LEDS		3
28 #define RTL8125_NUM_LEDS		4
29 
30 struct r8169_led_classdev {
31 	struct led_classdev led;
32 	struct net_device *ndev;
33 	int index;
34 };
35 
36 #define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led)
37 
r8169_trigger_mode_is_valid(unsigned long flags)38 static bool r8169_trigger_mode_is_valid(unsigned long flags)
39 {
40 	bool rx, tx;
41 
42 	if (flags & BIT(TRIGGER_NETDEV_HALF_DUPLEX))
43 		return false;
44 	if (flags & BIT(TRIGGER_NETDEV_FULL_DUPLEX))
45 		return false;
46 
47 	rx = flags & BIT(TRIGGER_NETDEV_RX);
48 	tx = flags & BIT(TRIGGER_NETDEV_TX);
49 
50 	return rx == tx;
51 }
52 
rtl8168_led_hw_control_is_supported(struct led_classdev * led_cdev,unsigned long flags)53 static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev,
54 					       unsigned long flags)
55 {
56 	struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
57 	struct rtl8169_private *tp = netdev_priv(ldev->ndev);
58 	int shift = ldev->index * 4;
59 
60 	if (!r8169_trigger_mode_is_valid(flags)) {
61 		/* Switch LED off to indicate that mode isn't supported */
62 		rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0);
63 		return -EOPNOTSUPP;
64 	}
65 
66 	return 0;
67 }
68 
rtl8168_led_hw_control_set(struct led_classdev * led_cdev,unsigned long flags)69 static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev,
70 				      unsigned long flags)
71 {
72 	struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
73 	struct rtl8169_private *tp = netdev_priv(ldev->ndev);
74 	int shift = ldev->index * 4;
75 	u16 mode = 0;
76 
77 	if (flags & BIT(TRIGGER_NETDEV_LINK_10))
78 		mode |= RTL8168_LED_CTRL_LINK_10;
79 	if (flags & BIT(TRIGGER_NETDEV_LINK_100))
80 		mode |= RTL8168_LED_CTRL_LINK_100;
81 	if (flags & BIT(TRIGGER_NETDEV_LINK_1000))
82 		mode |= RTL8168_LED_CTRL_LINK_1000;
83 	if (flags & BIT(TRIGGER_NETDEV_TX))
84 		mode |= RTL8168_LED_CTRL_ACT;
85 
86 	return rtl8168_led_mod_ctrl(tp, 0x000f << shift, mode << shift);
87 }
88 
rtl8168_led_hw_control_get(struct led_classdev * led_cdev,unsigned long * flags)89 static int rtl8168_led_hw_control_get(struct led_classdev *led_cdev,
90 				      unsigned long *flags)
91 {
92 	struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
93 	struct rtl8169_private *tp = netdev_priv(ldev->ndev);
94 	int shift = ldev->index * 4;
95 	int mode;
96 
97 	mode = rtl8168_get_led_mode(tp);
98 	if (mode < 0)
99 		return mode;
100 
101 	if (mode & RTL8168_LED_CTRL_OPTION2) {
102 		rtl8168_led_mod_ctrl(tp, RTL8168_LED_CTRL_OPTION2, 0);
103 		netdev_notice(ldev->ndev, "Deactivating unsupported Option2 LED mode\n");
104 	}
105 
106 	mode = (mode >> shift) & 0x000f;
107 
108 	if (mode & RTL8168_LED_CTRL_ACT)
109 		*flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
110 
111 	if (mode & RTL8168_LED_CTRL_LINK_10)
112 		*flags |= BIT(TRIGGER_NETDEV_LINK_10);
113 	if (mode & RTL8168_LED_CTRL_LINK_100)
114 		*flags |= BIT(TRIGGER_NETDEV_LINK_100);
115 	if (mode & RTL8168_LED_CTRL_LINK_1000)
116 		*flags |= BIT(TRIGGER_NETDEV_LINK_1000);
117 
118 	return 0;
119 }
120 
121 static struct device *
r8169_led_hw_control_get_device(struct led_classdev * led_cdev)122 	r8169_led_hw_control_get_device(struct led_classdev *led_cdev)
123 {
124 	struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
125 
126 	return &ldev->ndev->dev;
127 }
128 
rtl8168_setup_ldev(struct r8169_led_classdev * ldev,struct net_device * ndev,int index)129 static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev,
130 			       struct net_device *ndev, int index)
131 {
132 	struct rtl8169_private *tp = netdev_priv(ndev);
133 	struct led_classdev *led_cdev = &ldev->led;
134 	char led_name[LED_MAX_NAME_SIZE];
135 
136 	ldev->ndev = ndev;
137 	ldev->index = index;
138 
139 	r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE);
140 	led_cdev->name = led_name;
141 	led_cdev->hw_control_trigger = "netdev";
142 	led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN;
143 	led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported;
144 	led_cdev->hw_control_set = rtl8168_led_hw_control_set;
145 	led_cdev->hw_control_get = rtl8168_led_hw_control_get;
146 	led_cdev->hw_control_get_device = r8169_led_hw_control_get_device;
147 
148 	/* ignore errors */
149 	led_classdev_register(&ndev->dev, led_cdev);
150 }
151 
rtl8168_init_leds(struct net_device * ndev)152 struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev)
153 {
154 	struct r8169_led_classdev *leds;
155 	int i;
156 
157 	leds = kcalloc(RTL8168_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL);
158 	if (!leds)
159 		return NULL;
160 
161 	for (i = 0; i < RTL8168_NUM_LEDS; i++)
162 		rtl8168_setup_ldev(leds + i, ndev, i);
163 
164 	return leds;
165 }
166 
rtl8125_led_hw_control_is_supported(struct led_classdev * led_cdev,unsigned long flags)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 
rtl8125_led_hw_control_set(struct led_classdev * led_cdev,unsigned long flags)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 
rtl8125_led_hw_control_get(struct led_classdev * led_cdev,unsigned long * flags)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 
rtl8125_setup_led_ldev(struct r8169_led_classdev * ldev,struct net_device * ndev,int index)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 	led_classdev_register(&ndev->dev, led_cdev);
249 }
250 
rtl8125_init_leds(struct net_device * ndev)251 struct r8169_led_classdev *rtl8125_init_leds(struct net_device *ndev)
252 {
253 	struct r8169_led_classdev *leds;
254 	int i;
255 
256 	leds = kcalloc(RTL8125_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL);
257 	if (!leds)
258 		return NULL;
259 
260 	for (i = 0; i < RTL8125_NUM_LEDS; i++)
261 		rtl8125_setup_led_ldev(leds + i, ndev, i);
262 
263 	return leds;
264 }
265 
r8169_remove_leds(struct r8169_led_classdev * leds)266 void r8169_remove_leds(struct r8169_led_classdev *leds)
267 {
268 	if (!leds)
269 		return;
270 
271 	for (struct r8169_led_classdev *l = leds; l->ndev; l++)
272 		led_classdev_unregister(&l->led);
273 
274 	kfree(leds);
275 }
276