xref: /linux/drivers/net/dsa/motorcomm/leds.c (revision cece0b573deb5d102547835da720f60d7b7888cc)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2026 David Yang
4  */
5 
6 #include <linux/uleds.h>
7 
8 #include "chip.h"
9 #include "leds.h"
10 #include "smi.h"
11 
12 #define to_yt921x_led(led_cdev) \
13 	container_of_const((led_cdev), struct yt921x_led, cdev)
14 #define to_yt921x_port(led) ((led)->port)
15 
16 static u32 yt921x_led_regaddr(struct yt921x_priv *priv, int port, int group)
17 {
18 	switch (group) {
19 	case 0:
20 	default:
21 		return YT921X_LED0_PORTn(port);
22 	case 1:
23 		return YT921X_LED1_PORTn(port);
24 	case 2:
25 		return YT921X_LED2_PORTn(port);
26 	}
27 }
28 
29 static int
30 yt921x_led_force_set(struct yt921x_priv *priv, int port, int group, bool on)
31 {
32 	struct yt921x_port *pp = &priv->ports[port];
33 	u32 ctrl;
34 	u32 mask;
35 
36 	/* No reversion - LED is sacrificed in case of IO error */
37 	pp->led_duty_mask &= ~BIT(group);
38 	pp->led_cycle_mask &= ~BIT(group);
39 
40 	mask = YT921X_LED2_PORT_FORCEn_M(group);
41 	ctrl = on ? YT921X_LED2_PORT_FORCEn_ON(group) :
42 	       YT921X_LED2_PORT_FORCEn_OFF(group);
43 	return yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port), mask,
44 				      ctrl);
45 }
46 
47 static int
48 yt921x_led_blink_select(const struct yt921x_priv *priv, unsigned long on,
49 			unsigned long off, unsigned short *cyclep,
50 			unsigned char *dutyp)
51 {
52 	static const unsigned char dutys[] = {
53 		YT921X_LED_DUTY(1, 6),
54 		YT921X_LED_DUTY(1, 4),
55 		YT921X_LED_DUTY(1, 3),
56 		YT921X_LED_DUTY(1, 2),
57 	};
58 	unsigned int cycle_upper;
59 	unsigned int cycle_req;
60 	unsigned int duty_req;
61 	unsigned int cycle;
62 	unsigned int duty;
63 
64 	cycle = YT921X_LED_BLINK_MAX;
65 	cycle_upper = cycle * 11585 / 8192 + 1;  /* M_SQRT2 * cycle */
66 	if (check_add_overflow(on, off, &cycle_req) || cycle_req >= cycle_upper)
67 		return -EOPNOTSUPP;
68 
69 	for (; cycle > YT921X_LED_BLINK_MIN; cycle_upper >>= 1, cycle >>= 1)
70 		if (cycle_req >= cycle_upper >> 1)
71 			break;
72 	*cyclep = cycle;
73 
74 	duty_req = DIV_ROUND_CLOSEST(YT921X_LED_DUTY_DENOM *
75 				     (on > off ? off : on), cycle_req);
76 	for (unsigned int i = ARRAY_SIZE(dutys) - 1;; i--)
77 		if (i == 0 || duty_req >= (dutys[i - 1] + dutys[i]) / 2) {
78 			duty = dutys[i];
79 			break;
80 		}
81 	if (on > off)
82 		duty = YT921X_LED_DUTY_DENOM - duty;
83 	*dutyp = duty;
84 
85 	return 0;
86 }
87 
88 static int
89 yt921x_led_blink_set(struct yt921x_priv *priv, int port, int group,
90 		     unsigned long *onp, unsigned long *offp)
91 {
92 	struct yt921x_port *pp = &priv->ports[port];
93 	unsigned short cycle;
94 	unsigned char duty;
95 	bool use_cycle;
96 	u32 ctrl;
97 	u32 mask;
98 	u32 val;
99 	int res;
100 
101 	if (!*onp && !*offp) {
102 		cycle = YT921X_LED_BLINK_DEF;
103 		duty = (pp->led_duty_mask & ~BIT(group)) ? pp->led_duty :
104 		       YT921X_LED_DUTY(1, 2);
105 
106 		use_cycle = false;
107 	} else if (!*onp || !*offp) {
108 		return yt921x_led_force_set(priv, port, group, *onp);
109 	} else {
110 		res = yt921x_led_blink_select(priv, *onp, *offp, &cycle, &duty);
111 		if (res)
112 			return res;
113 
114 		use_cycle = cycle < YT921X_LED_BLINK_DEF;
115 
116 		if (use_cycle && cycle != pp->led_cycle &&
117 		    (pp->led_cycle_mask & ~BIT(group)))
118 			return -EOPNOTSUPP;
119 		if (duty != pp->led_duty && (pp->led_duty_mask & ~BIT(group)))
120 			return -EOPNOTSUPP;
121 	}
122 
123 	pp->led_cycle_mask &= ~BIT(group);
124 	pp->led_duty_mask &= ~BIT(group);
125 
126 	/* The chip seems to jam a while if changing duty directly */
127 	res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
128 	if (res)
129 		return res;
130 
131 	ctrl = val & ~YT921X_LED2_PORT_FORCEn_M(group);
132 	ctrl |= YT921X_LED2_PORT_FORCEn_OFF(group);
133 	if (val != ctrl) {
134 		res = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);
135 		if (res)
136 			return res;
137 	}
138 
139 	mask = YT921X_LED1_PORT_BLINK_DUTY_M | YT921X_LED1_PORT_BLINK_DUTY_COMP;
140 	switch (duty >= YT921X_LED_DUTY(1, 2) ? duty :
141 		YT921X_LED_DUTY_DENOM - duty) {
142 	default:
143 		duty = YT921X_LED_DUTY(1, 2);
144 		fallthrough;
145 	case YT921X_LED_DUTY(1, 2):
146 		ctrl = YT921X_LED1_PORT_BLINK_DUTY_1_2;
147 		break;
148 	case YT921X_LED_DUTY(2, 3):
149 		ctrl = YT921X_LED1_PORT_BLINK_DUTY_2_3;
150 		break;
151 	case YT921X_LED_DUTY(3, 4):
152 		ctrl = YT921X_LED1_PORT_BLINK_DUTY_3_4;
153 		break;
154 	case YT921X_LED_DUTY(5, 6):
155 		ctrl = YT921X_LED1_PORT_BLINK_DUTY_5_6;
156 		break;
157 	}
158 	if (duty < YT921X_LED_DUTY(1, 2))
159 		ctrl |= YT921X_LED1_PORT_BLINK_DUTY_COMP;
160 	if (use_cycle) {
161 		mask |= YT921X_LED1_PORT_OTHER_BLINK_M;
162 		ctrl |= YT921X_LED1_PORT_OTHER_BLINK(9 - __fls(cycle));
163 	}
164 	res = yt921x_reg_update_bits(priv, YT921X_LED1_PORTn(port), mask, ctrl);
165 	if (res)
166 		return res;
167 
168 	ctrl = val & ~(YT921X_LED2_PORT_FORCEn_M(group) |
169 		       YT921X_LED2_PORT_FORCE_BLINKn_M(group));
170 	ctrl |= YT921X_LED2_PORT_FORCEn_BLINK(group);
171 	if (use_cycle)
172 		ctrl |= YT921X_LED2_PORT_FORCE_BLINKn_OTHER(group);
173 	else
174 		ctrl |= YT921X_LED2_PORT_FORCE_BLINKn(group, __fls(cycle) - 9);
175 	res = yt921x_reg_write(priv, YT921X_LED2_PORTn(port), ctrl);
176 	if (res)
177 		return res;
178 
179 	if (use_cycle) {
180 		pp->led_cycle_mask |= BIT(group);
181 		pp->led_cycle = cycle;
182 	}
183 	pp->led_duty_mask |= BIT(group);
184 	pp->led_duty = duty;
185 
186 	*onp = DIV_ROUND_CLOSEST(duty * cycle, YT921X_LED_DUTY_DENOM);
187 	*offp = cycle - *onp;
188 	return 0;
189 }
190 
191 struct yt921x_led_trigger_map {
192 	unsigned long flags;
193 	u32 mask;
194 };
195 
196 static const struct yt921x_led_trigger_map yt921x_led_trigger_maps[] = {
197 	{BIT(TRIGGER_NETDEV_LINK),
198 	 YT921X_LEDx_PORT_ACT_DUPLEX_HALF | YT921X_LEDx_PORT_ACT_DUPLEX_FULL},
199 	{BIT(TRIGGER_NETDEV_LINK_10), YT921X_LEDx_PORT_ACT_10M},
200 	{BIT(TRIGGER_NETDEV_LINK_100), YT921X_LEDx_PORT_ACT_100M},
201 	{BIT(TRIGGER_NETDEV_LINK_1000), YT921X_LEDx_PORT_ACT_1000M},
202 	{BIT(TRIGGER_NETDEV_HALF_DUPLEX), YT921X_LEDx_PORT_ACT_DUPLEX_HALF},
203 	{BIT(TRIGGER_NETDEV_FULL_DUPLEX), YT921X_LEDx_PORT_ACT_DUPLEX_FULL},
204 	{BIT(TRIGGER_NETDEV_TX), YT921X_LEDx_PORT_ACT_TX_BLINK},
205 	{BIT(TRIGGER_NETDEV_RX), YT921X_LEDx_PORT_ACT_RX_BLINK},
206 	{BIT(TRIGGER_NETDEV_TX_ERR) | BIT(TRIGGER_NETDEV_RX_ERR),
207 	 YT921X_LEDx_PORT_ACT_COLLISION_BLINK},
208 };
209 
210 static bool
211 yt921x_led_trigger_is_supported(const struct yt921x_priv *priv, int port,
212 				int group, unsigned long flags)
213 {
214 	if (!flags)
215 		return true;
216 
217 	for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_led_trigger_maps); i++) {
218 		const struct yt921x_led_trigger_map *map = &yt921x_led_trigger_maps[i];
219 
220 		if ((flags & map->flags) == map->flags) {
221 			flags &= ~map->flags;
222 			if (!flags)
223 				return true;
224 		}
225 	}
226 
227 	return false;
228 }
229 
230 static int
231 yt921x_led_trigger_get(struct yt921x_priv *priv, int port, int group,
232 		       unsigned long *flagsp)
233 {
234 	u32 addr;
235 	u32 val;
236 	int res;
237 
238 	res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
239 	if (res)
240 		return res;
241 
242 	if ((val & YT921X_LED2_PORT_FORCEn_M(group)) !=
243 	    YT921X_LED2_PORT_FORCEn_DONTCARE(group)) {
244 		*flagsp = 0;
245 		return 0;
246 	}
247 
248 	if (group != 2) {
249 		addr = yt921x_led_regaddr(priv, port, group);
250 		res = yt921x_reg_read(priv, addr, &val);
251 		if (res)
252 			return res;
253 	}
254 
255 	*flagsp = 0;
256 	for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_led_trigger_maps); i++) {
257 		const struct yt921x_led_trigger_map *map = &yt921x_led_trigger_maps[i];
258 
259 		if ((val & map->mask) == map->mask)
260 			*flagsp |= map->flags;
261 	}
262 
263 	return 0;
264 }
265 
266 static int
267 yt921x_led_trigger_set(struct yt921x_priv *priv, int port, int group,
268 		       unsigned long flags)
269 {
270 	struct yt921x_port *pp = &priv->ports[port];
271 	u32 addr;
272 	u32 ctrl;
273 	u32 mask;
274 	int res;
275 
276 	ctrl = 0;
277 	for (unsigned int i = 0; i < ARRAY_SIZE(yt921x_led_trigger_maps); i++) {
278 		const struct yt921x_led_trigger_map *map = &yt921x_led_trigger_maps[i];
279 
280 		if ((flags & map->flags) == map->flags) {
281 			flags &= ~map->flags;
282 			ctrl |= map->mask;
283 			if (!flags)
284 				break;
285 		}
286 	}
287 	if (flags)
288 		return -EOPNOTSUPP;
289 
290 	pp->led_duty_mask &= ~BIT(group);
291 	pp->led_cycle_mask &= ~BIT(group);
292 
293 	mask = !group ? YT921X_LED0_PORT_ACT_M : YT921X_LEDx_PORT_ACT_M;
294 	if (group == 2) {
295 		mask |= YT921X_LED2_PORT_FORCEn_M(group);
296 		ctrl |= YT921X_LED2_PORT_FORCEn_DONTCARE(group);
297 	}
298 	addr = yt921x_led_regaddr(priv, port, group);
299 	res = yt921x_reg_update_bits(priv, addr, mask, ctrl);
300 	if (res)
301 		return res;
302 
303 	if (group != 2) {
304 		mask = YT921X_LED2_PORT_FORCEn_M(group);
305 		ctrl = YT921X_LED2_PORT_FORCEn_DONTCARE(group);
306 		res = yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port),
307 					     mask, ctrl);
308 		if (res)
309 			return res;
310 	}
311 
312 	return 0;
313 }
314 
315 static int
316 yt921x_cled_brightness_set_blocking(struct led_classdev *led_cdev,
317 				    enum led_brightness brightness)
318 {
319 	struct yt921x_led *led = to_yt921x_led(led_cdev);
320 	struct yt921x_port *pp = to_yt921x_port(led);
321 	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
322 	int res;
323 
324 	mutex_lock(&priv->reg_lock);
325 	res = yt921x_led_force_set(priv, pp->index, led->group, brightness);
326 	mutex_unlock(&priv->reg_lock);
327 
328 	return res;
329 }
330 
331 static int
332 yt921x_cled_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on,
333 		      unsigned long *delay_off)
334 {
335 	struct yt921x_led *led = to_yt921x_led(led_cdev);
336 	struct yt921x_port *pp = to_yt921x_port(led);
337 	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
338 	int res;
339 
340 	mutex_lock(&priv->reg_lock);
341 	res = yt921x_led_blink_set(priv, pp->index, led->group, delay_on,
342 				   delay_off);
343 	mutex_unlock(&priv->reg_lock);
344 
345 	return res;
346 }
347 
348 static struct device __maybe_unused *
349 yt921x_cled_hw_control_get_device(struct led_classdev *led_cdev)
350 {
351 	struct yt921x_led *led = to_yt921x_led(led_cdev);
352 	struct yt921x_port *pp = to_yt921x_port(led);
353 	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
354 	struct dsa_port *dp;
355 
356 	dp = dsa_to_port(&priv->ds, pp->index);
357 	if (!dp)
358 		return NULL;
359 
360 	if (dsa_port_is_user(dp))
361 		return !dp->user ? NULL : &dp->user->dev;
362 	if (dsa_port_is_cpu(dp))
363 		return !dp->conduit ? NULL : &dp->conduit->dev;
364 
365 	return NULL;
366 }
367 
368 static int __maybe_unused
369 yt921x_cled_hw_control_is_supported(struct led_classdev *led_cdev,
370 				    unsigned long flags)
371 {
372 	struct yt921x_led *led = to_yt921x_led(led_cdev);
373 	struct yt921x_port *pp = to_yt921x_port(led);
374 	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
375 
376 	if (yt921x_led_trigger_is_supported(priv, pp->index, led->group, flags))
377 		return 0;
378 	return -EOPNOTSUPP;
379 }
380 
381 static int __maybe_unused
382 yt921x_cled_hw_control_get(struct led_classdev *led_cdev, unsigned long *flagsp)
383 {
384 	struct yt921x_led *led = to_yt921x_led(led_cdev);
385 	struct yt921x_port *pp = to_yt921x_port(led);
386 	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
387 	int res;
388 
389 	mutex_lock(&priv->reg_lock);
390 	res = yt921x_led_trigger_get(priv, pp->index, led->group, flagsp);
391 	mutex_unlock(&priv->reg_lock);
392 
393 	return res;
394 }
395 
396 static int __maybe_unused
397 yt921x_cled_hw_control_set(struct led_classdev *led_cdev, unsigned long flags)
398 {
399 	struct yt921x_led *led = to_yt921x_led(led_cdev);
400 	struct yt921x_port *pp = to_yt921x_port(led);
401 	struct yt921x_priv *priv = yt921x_port_to_priv(pp);
402 	int res;
403 
404 	mutex_lock(&priv->reg_lock);
405 	res = yt921x_led_trigger_set(priv, pp->index, led->group, flags);
406 	mutex_unlock(&priv->reg_lock);
407 
408 	return res;
409 }
410 
411 static int
412 yt921x_led_setup(struct yt921x_priv *priv, int port,
413 		 struct fwnode_handle *fwnode)
414 {
415 	struct device *dev = yt921x_priv_to_device(priv);
416 	struct yt921x_port *pp = &priv->ports[port];
417 	struct led_init_data init_data;
418 	struct led_classdev *led_cdev;
419 	char name[LED_MAX_NAME_SIZE];
420 	enum led_default_state state;
421 	struct yt921x_led *led;
422 	int polarity_orig;
423 	bool force_high;
424 	bool force_low;
425 	u32 led2_orig;
426 	int polarity;
427 	u32 group;
428 	u32 mask;
429 	u32 ctrl;
430 	u32 val;
431 	bool on;
432 	int res;
433 	int ret;
434 
435 	res = fwnode_property_read_u32(fwnode, "reg", &group);
436 	if (res) {
437 		dev_err(dev, "Missing LED reg for %pfw\n", fwnode);
438 		return res;
439 	}
440 	if (group >= YT921X_LED_GROUP_NUM) {
441 		dev_err(dev, "Invalid LED reg %u for port %d\n", group, port);
442 		return -EINVAL;
443 	}
444 	if (pp->leds[group]) {
445 		res = -EEXIST;
446 		goto err;
447 	}
448 
449 	force_high = fwnode_property_read_bool(fwnode, "active-high");
450 	force_low = fwnode_property_read_bool(fwnode, "active-low");
451 	if (force_high && force_low) {
452 		dev_err(dev, "Duplicate polarities for LED %02d:%02u\n",
453 			port, group);
454 		return -EINVAL;
455 	}
456 	polarity = force_high ? 1 : force_low ? -1 : 0;
457 
458 	led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
459 	if (!led) {
460 		res = -ENOMEM;
461 		goto err;
462 	}
463 	pp->leds[group] = led;
464 
465 	led->port = pp;
466 	led->group = group;
467 
468 	state = led_init_default_state_get(fwnode);
469 
470 	mutex_lock(&priv->reg_lock);
471 
472 	/* Inversion is internal - force on will give low logic.
473 	 * In the rest of the file, treat LEDs as if active-low.
474 	 */
475 	polarity_orig = 0;
476 	if (polarity) {
477 		res = yt921x_reg_read(priv, YT921X_LED_PAR_INV, &val);
478 		if (res)
479 			goto err_inv;
480 
481 		mask = YT921X_LED_PAR_INV_INVnm(group, port);
482 		ctrl = polarity > 0 ? val | mask : val & ~mask;
483 		if (ctrl != val) {
484 			res = yt921x_reg_write(priv, YT921X_LED_PAR_INV, ctrl);
485 			if (res)
486 				goto err_inv;
487 
488 			polarity_orig = -polarity;
489 		}
490 	}
491 
492 	led2_orig = U32_MAX;
493 	res = yt921x_reg_read(priv, YT921X_LED2_PORTn(port), &val);
494 	if (res)
495 		goto err_led2;
496 	mask = YT921X_LED2_PORT_FORCEn_M(group);
497 
498 	switch (state) {
499 	case LEDS_DEFSTATE_OFF:
500 	case LEDS_DEFSTATE_ON:
501 	default:
502 		on = state == LEDS_DEFSTATE_ON;
503 		ctrl = (val & ~mask) |
504 		       (on ? YT921X_LED2_PORT_FORCEn_ON(group) :
505 			YT921X_LED2_PORT_FORCEn_OFF(group));
506 		if (ctrl != val) {
507 			res = yt921x_reg_write(priv, YT921X_LED2_PORTn(port),
508 					       ctrl);
509 			if (res)
510 				goto err_led2;
511 
512 			led2_orig = val & mask;
513 		}
514 		break;
515 	case LEDS_DEFSTATE_KEEP:
516 		on = (val & mask) == YT921X_LED2_PORT_FORCEn_ON(group);
517 		break;
518 	}
519 
520 	mutex_unlock(&priv->reg_lock);
521 
522 	led_cdev = &led->cdev;
523 	led_cdev->brightness = on;
524 	led_cdev->max_brightness = 1;
525 	led_cdev->flags = LED_RETAIN_AT_SHUTDOWN;
526 	led_cdev->brightness_set_blocking = yt921x_cled_brightness_set_blocking;
527 	led_cdev->blink_set = yt921x_cled_blink_set;
528 #ifdef CONFIG_LEDS_TRIGGERS
529 	led_cdev->hw_control_trigger = "netdev";
530 	led_cdev->hw_control_get_device = yt921x_cled_hw_control_get_device;
531 	led_cdev->hw_control_is_supported = yt921x_cled_hw_control_is_supported;
532 	led_cdev->hw_control_get = yt921x_cled_hw_control_get;
533 	led_cdev->hw_control_set = yt921x_cled_hw_control_set;
534 #endif
535 
536 	snprintf(name, sizeof(name), YT921X_NAME "-%u:%02d:%02u",
537 		 priv->ds.index, port, group);
538 	init_data = (typeof(init_data)){
539 		.fwnode = fwnode,
540 		.default_label = ":port",
541 		.devicename = name,
542 		.devname_mandatory = true,
543 	};
544 	res = devm_led_classdev_register_ext(dev, led_cdev, &init_data);
545 	if (res)
546 		goto revoke;
547 
548 	return 0;
549 
550 revoke:
551 	mutex_lock(&priv->reg_lock);
552 	if (led2_orig != U32_MAX) {
553 		ret = yt921x_reg_update_bits(priv, YT921X_LED2_PORTn(port),
554 					     YT921X_LED2_PORT_FORCEn_M(group),
555 					     led2_orig);
556 		if (ret)
557 			dev_err(dev,
558 				"Failed to restore %s for LED %02d:%02u: %d\n",
559 				"LED2_PORT", port, group, ret);
560 	}
561 err_led2:
562 	if (polarity_orig) {
563 		ret = yt921x_reg_toggle_bits(priv, YT921X_LED_PAR_INV,
564 					     YT921X_LED_PAR_INV_INVnm(group, port),
565 					     polarity_orig > 0);
566 		if (ret)
567 			dev_err(dev,
568 				"Failed to restore %s for LED %02d:%02u: %d\n",
569 				"LED_PAR_INV", port, group, ret);
570 	}
571 err_inv:
572 	mutex_unlock(&priv->reg_lock);
573 
574 	pp->leds[group] = NULL;
575 	devm_kfree(dev, led);
576 
577 err:
578 	dev_err(dev, "Failed to initialize LED %02d:%02u: %d\n",
579 		port, group, res);
580 	return res;
581 }
582 
583 static void yt921x_leds_remove_port(struct yt921x_priv *priv, int port)
584 {
585 	struct device *dev = yt921x_priv_to_device(priv);
586 	struct yt921x_port *pp = &priv->ports[port];
587 
588 	for (int group = 0; group < YT921X_LED_GROUP_NUM; group++) {
589 		struct yt921x_led *led = pp->leds[group];
590 
591 		if (led) {
592 			devm_led_classdev_unregister(dev, &led->cdev);
593 			pp->leds[group] = NULL;
594 			devm_kfree(dev, led);
595 		}
596 	}
597 
598 	pp->led_duty_mask = 0;
599 	pp->led_cycle_mask = 0;
600 }
601 
602 static int yt921x_leds_setup_port(struct yt921x_priv *priv, int port)
603 {
604 	struct device *dev = yt921x_priv_to_device(priv);
605 	struct dsa_switch *ds = &priv->ds;
606 	struct device_node *leds_np;
607 	struct dsa_port *dp;
608 
609 	dp = dsa_to_port(ds, port);
610 	leds_np = of_get_child_by_name(dp->dn, "leds");
611 	if (!leds_np)
612 		return 0;
613 
614 	if (port >= YT921X_LED_PORT_NUM) {
615 		dev_err(dev, "Cannot configure LEDs for port %d\n", port);
616 		of_node_put(leds_np);
617 		return -EINVAL;
618 	}
619 
620 	for_each_child_of_node_scoped(leds_np, led_np) {
621 		yt921x_led_setup(priv, port, of_fwnode_handle(led_np));
622 		/* Allow partial configuration: LEDs are optional */
623 	}
624 
625 	of_node_put(leds_np);
626 	return 0;
627 }
628 
629 void yt921x_leds_remove(struct yt921x_priv *priv)
630 {
631 	for (int port = 0; port < YT921X_LED_PORT_NUM; port++)
632 		yt921x_leds_remove_port(priv, port);
633 }
634 
635 int yt921x_leds_setup(struct yt921x_priv *priv)
636 {
637 	struct dsa_switch *ds = &priv->ds;
638 	struct dsa_port *dp;
639 
640 	/* LEDs are always enabled. There is no way to disable them altogether
641 	 * (as far as I know).
642 	 */
643 
644 	dsa_switch_for_each_port(dp, ds) {
645 		int port = dp->index;
646 
647 		if (!dp->dn)
648 			continue;
649 
650 		yt921x_leds_setup_port(priv, port);
651 		/* Allow partial configuration: LEDs are optional */
652 	}
653 
654 	return 0;
655 }
656