Loading...
Note: File does not exist in v5.14.15.
1// SPDX-License-Identifier: GPL-2.0-or-later
2#include <linux/bitfield.h>
3#include <linux/leds.h>
4#include <linux/property.h>
5
6#include "chip.h"
7#include "global2.h"
8#include "port.h"
9
10/* Offset 0x16: LED control */
11
12static int mv88e6xxx_port_led_write(struct mv88e6xxx_chip *chip, int port, u16 reg)
13{
14 reg |= MV88E6XXX_PORT_LED_CONTROL_UPDATE;
15
16 return mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, reg);
17}
18
19static int mv88e6xxx_port_led_read(struct mv88e6xxx_chip *chip, int port,
20 u16 ptr, u16 *val)
21{
22 int err;
23
24 err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_LED_CONTROL, ptr);
25 if (err)
26 return err;
27
28 err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_LED_CONTROL, val);
29 *val &= 0x3ff;
30
31 return err;
32}
33
34static int mv88e6xxx_led_brightness_set(struct mv88e6xxx_port *p, int led,
35 int brightness)
36{
37 u16 reg;
38 int err;
39
40 err = mv88e6xxx_port_led_read(p->chip, p->port,
41 MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
42 ®);
43 if (err)
44 return err;
45
46 if (led == 1)
47 reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
48 else
49 reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
50
51 if (brightness) {
52 /* Selector 0x0f == Force LED ON */
53 if (led == 1)
54 reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELF;
55 else
56 reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELF;
57 } else {
58 /* Selector 0x0e == Force LED OFF */
59 if (led == 1)
60 reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE;
61 else
62 reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE;
63 }
64
65 reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
66
67 return mv88e6xxx_port_led_write(p->chip, p->port, reg);
68}
69
70static int mv88e6xxx_led0_brightness_set_blocking(struct led_classdev *ldev,
71 enum led_brightness brightness)
72{
73 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
74 int err;
75
76 mv88e6xxx_reg_lock(p->chip);
77 err = mv88e6xxx_led_brightness_set(p, 0, brightness);
78 mv88e6xxx_reg_unlock(p->chip);
79
80 return err;
81}
82
83static int mv88e6xxx_led1_brightness_set_blocking(struct led_classdev *ldev,
84 enum led_brightness brightness)
85{
86 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
87 int err;
88
89 mv88e6xxx_reg_lock(p->chip);
90 err = mv88e6xxx_led_brightness_set(p, 1, brightness);
91 mv88e6xxx_reg_unlock(p->chip);
92
93 return err;
94}
95
96struct mv88e6xxx_led_hwconfig {
97 int led;
98 u8 portmask;
99 unsigned long rules;
100 bool fiber;
101 bool blink_activity;
102 u16 selector;
103};
104
105/* The following is a lookup table to check what rules we can support on a
106 * certain LED given restrictions such as that some rules only work with fiber
107 * (SFP) connections and some blink on activity by default.
108 */
109#define MV88E6XXX_PORTS_0_3 (BIT(0) | BIT(1) | BIT(2) | BIT(3))
110#define MV88E6XXX_PORTS_4_5 (BIT(4) | BIT(5))
111#define MV88E6XXX_PORT_4 BIT(4)
112#define MV88E6XXX_PORT_5 BIT(5)
113
114/* Entries are listed in selector order.
115 *
116 * These configurations vary across different switch families, list
117 * different tables per-family here.
118 */
119static const struct mv88e6xxx_led_hwconfig mv88e6352_led_hwconfigs[] = {
120 {
121 .led = 0,
122 .portmask = MV88E6XXX_PORT_4,
123 .rules = BIT(TRIGGER_NETDEV_LINK),
124 .blink_activity = true,
125 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL0,
126 },
127 {
128 .led = 1,
129 .portmask = MV88E6XXX_PORT_5,
130 .rules = BIT(TRIGGER_NETDEV_LINK_1000),
131 .blink_activity = true,
132 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL0,
133 },
134 {
135 .led = 0,
136 .portmask = MV88E6XXX_PORTS_0_3,
137 .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
138 .blink_activity = true,
139 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1,
140 },
141 {
142 .led = 1,
143 .portmask = MV88E6XXX_PORTS_0_3,
144 .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100),
145 .blink_activity = true,
146 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1,
147 },
148 {
149 .led = 0,
150 .portmask = MV88E6XXX_PORTS_4_5,
151 .rules = BIT(TRIGGER_NETDEV_LINK_100),
152 .blink_activity = true,
153 .fiber = true,
154 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL1,
155 },
156 {
157 .led = 1,
158 .portmask = MV88E6XXX_PORTS_4_5,
159 .rules = BIT(TRIGGER_NETDEV_LINK_1000),
160 .blink_activity = true,
161 .fiber = true,
162 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL1,
163 },
164 {
165 .led = 0,
166 .portmask = MV88E6XXX_PORTS_0_3,
167 .rules = BIT(TRIGGER_NETDEV_LINK_1000),
168 .blink_activity = true,
169 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2,
170 },
171 {
172 .led = 1,
173 .portmask = MV88E6XXX_PORTS_0_3,
174 .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_100),
175 .blink_activity = true,
176 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2,
177 },
178 {
179 .led = 0,
180 .portmask = MV88E6XXX_PORTS_4_5,
181 .rules = BIT(TRIGGER_NETDEV_LINK_1000),
182 .blink_activity = true,
183 .fiber = true,
184 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL2,
185 },
186 {
187 .led = 1,
188 .portmask = MV88E6XXX_PORTS_4_5,
189 .rules = BIT(TRIGGER_NETDEV_LINK_100),
190 .blink_activity = true,
191 .fiber = true,
192 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL2,
193 },
194 {
195 .led = 0,
196 .portmask = MV88E6XXX_PORTS_0_3,
197 .rules = BIT(TRIGGER_NETDEV_LINK),
198 .blink_activity = true,
199 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL3,
200 },
201 {
202 .led = 1,
203 .portmask = MV88E6XXX_PORTS_0_3,
204 .rules = BIT(TRIGGER_NETDEV_LINK_1000),
205 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3,
206 },
207 {
208 .led = 1,
209 .portmask = MV88E6XXX_PORTS_4_5,
210 .rules = BIT(TRIGGER_NETDEV_LINK),
211 .fiber = true,
212 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL3,
213 },
214 {
215 .led = 1,
216 .portmask = MV88E6XXX_PORT_4,
217 .rules = BIT(TRIGGER_NETDEV_LINK),
218 .blink_activity = true,
219 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL4,
220 },
221 {
222 .led = 1,
223 .portmask = MV88E6XXX_PORT_5,
224 .rules = BIT(TRIGGER_NETDEV_LINK),
225 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL5,
226 },
227 {
228 .led = 0,
229 .portmask = MV88E6XXX_PORTS_0_3,
230 .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
231 .blink_activity = true,
232 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6,
233 },
234 {
235 .led = 1,
236 .portmask = MV88E6XXX_PORTS_0_3,
237 .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
238 .blink_activity = true,
239 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6,
240 },
241 {
242 .led = 0,
243 .portmask = MV88E6XXX_PORT_4,
244 .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
245 .blink_activity = true,
246 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL6,
247 },
248 {
249 .led = 1,
250 .portmask = MV88E6XXX_PORT_5,
251 .rules = BIT(TRIGGER_NETDEV_FULL_DUPLEX),
252 .blink_activity = true,
253 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL6,
254 },
255 {
256 .led = 0,
257 .portmask = MV88E6XXX_PORTS_0_3,
258 .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
259 .blink_activity = true,
260 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL7,
261 },
262 {
263 .led = 1,
264 .portmask = MV88E6XXX_PORTS_0_3,
265 .rules = BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_LINK_1000),
266 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL7,
267 },
268 {
269 .led = 0,
270 .portmask = MV88E6XXX_PORTS_0_3,
271 .rules = BIT(TRIGGER_NETDEV_LINK),
272 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8,
273 },
274 {
275 .led = 1,
276 .portmask = MV88E6XXX_PORTS_0_3,
277 .rules = BIT(TRIGGER_NETDEV_LINK),
278 .blink_activity = true,
279 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL8,
280 },
281 {
282 .led = 0,
283 .portmask = MV88E6XXX_PORT_5,
284 .rules = BIT(TRIGGER_NETDEV_LINK),
285 .blink_activity = true,
286 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL8,
287 },
288 {
289 .led = 0,
290 .portmask = MV88E6XXX_PORTS_0_3,
291 .rules = BIT(TRIGGER_NETDEV_LINK_10),
292 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SEL9,
293 },
294 {
295 .led = 1,
296 .portmask = MV88E6XXX_PORTS_0_3,
297 .rules = BIT(TRIGGER_NETDEV_LINK_100),
298 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SEL9,
299 },
300 {
301 .led = 0,
302 .portmask = MV88E6XXX_PORTS_0_3,
303 .rules = BIT(TRIGGER_NETDEV_LINK_10),
304 .blink_activity = true,
305 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELA,
306 },
307 {
308 .led = 1,
309 .portmask = MV88E6XXX_PORTS_0_3,
310 .rules = BIT(TRIGGER_NETDEV_LINK_100),
311 .blink_activity = true,
312 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELA,
313 },
314 {
315 .led = 0,
316 .portmask = MV88E6XXX_PORTS_0_3,
317 .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
318 .selector = MV88E6XXX_PORT_LED_CONTROL_LED0_SELB,
319 },
320 {
321 .led = 1,
322 .portmask = MV88E6XXX_PORTS_0_3,
323 .rules = BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK_1000),
324 .blink_activity = true,
325 .selector = MV88E6XXX_PORT_LED_CONTROL_LED1_SELB,
326 },
327};
328
329/* mv88e6xxx_led_match_selector() - look up the appropriate LED mode selector
330 * @p: port state container
331 * @led: LED number, 0 or 1
332 * @blink_activity: blink the LED (usually blink on indicated activity)
333 * @fiber: the link is connected to fiber such as SFP
334 * @rules: LED status flags from the LED classdev core
335 * @selector: fill in the selector in this parameter with an OR operation
336 */
337static int mv88e6xxx_led_match_selector(struct mv88e6xxx_port *p, int led, bool blink_activity,
338 bool fiber, unsigned long rules, u16 *selector)
339{
340 const struct mv88e6xxx_led_hwconfig *conf;
341 int i;
342
343 /* No rules means we turn the LED off */
344 if (!rules) {
345 if (led == 1)
346 *selector |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE;
347 else
348 *selector |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE;
349 return 0;
350 }
351
352 /* TODO: these rules are for MV88E6352, when adding other families,
353 * think about making sure you select the table that match the
354 * specific switch family.
355 */
356 for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
357 conf = &mv88e6352_led_hwconfigs[i];
358
359 if (conf->led != led)
360 continue;
361
362 if (!(conf->portmask & BIT(p->port)))
363 continue;
364
365 if (conf->blink_activity != blink_activity)
366 continue;
367
368 if (conf->fiber != fiber)
369 continue;
370
371 if (conf->rules == rules) {
372 dev_dbg(p->chip->dev, "port%d LED %d set selector %04x for rules %08lx\n",
373 p->port, led, conf->selector, rules);
374 *selector |= conf->selector;
375 return 0;
376 }
377 }
378
379 return -EOPNOTSUPP;
380}
381
382/* mv88e6xxx_led_match_selector() - find Linux netdev rules from a selector value
383 * @p: port state container
384 * @selector: the selector value from the LED actity register
385 * @led: LED number, 0 or 1
386 * @rules: Linux netdev activity rules found from selector
387 */
388static int
389mv88e6xxx_led_match_rule(struct mv88e6xxx_port *p, u16 selector, int led, unsigned long *rules)
390{
391 const struct mv88e6xxx_led_hwconfig *conf;
392 int i;
393
394 /* Find the selector in the table, we just look for the right selector
395 * and ignore if the activity has special properties such as blinking
396 * or is fiber-only.
397 */
398 for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
399 conf = &mv88e6352_led_hwconfigs[i];
400
401 if (conf->led != led)
402 continue;
403
404 if (!(conf->portmask & BIT(p->port)))
405 continue;
406
407 if (conf->selector == selector) {
408 dev_dbg(p->chip->dev, "port%d LED %d has selector %04x, rules %08lx\n",
409 p->port, led, selector, conf->rules);
410 *rules = conf->rules;
411 return 0;
412 }
413 }
414
415 return -EINVAL;
416}
417
418/* mv88e6xxx_led_get_selector() - get the appropriate LED mode selector
419 * @p: port state container
420 * @led: LED number, 0 or 1
421 * @fiber: the link is connected to fiber such as SFP
422 * @rules: LED status flags from the LED classdev core
423 * @selector: fill in the selector in this parameter with an OR operation
424 */
425static int mv88e6xxx_led_get_selector(struct mv88e6xxx_port *p, int led,
426 bool fiber, unsigned long rules, u16 *selector)
427{
428 int err;
429
430 /* What happens here is that we first try to locate a trigger with solid
431 * indicator (such as LED is on for a 1000 link) else we try a second
432 * sweep to find something suitable with a trigger that will blink on
433 * activity.
434 */
435 err = mv88e6xxx_led_match_selector(p, led, false, fiber, rules, selector);
436 if (err)
437 return mv88e6xxx_led_match_selector(p, led, true, fiber, rules, selector);
438
439 return 0;
440}
441
442/* Sets up the hardware blinking period */
443static int mv88e6xxx_led_set_blinking_period(struct mv88e6xxx_port *p, int led,
444 unsigned long delay_on, unsigned long delay_off)
445{
446 unsigned long period;
447 u16 reg;
448
449 period = delay_on + delay_off;
450
451 reg = 0;
452
453 switch (period) {
454 case 21:
455 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS;
456 break;
457 case 42:
458 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS;
459 break;
460 case 84:
461 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS;
462 break;
463 case 168:
464 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS;
465 break;
466 case 336:
467 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS;
468 break;
469 case 672:
470 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS;
471 break;
472 default:
473 /* Fall back to software blinking */
474 return -EINVAL;
475 }
476
477 /* This is essentially PWM duty cycle: how long time of the period
478 * will the LED be on. Zero isn't great in most cases.
479 */
480 switch (delay_on) {
481 case 0:
482 /* This is usually pretty useless and will make the LED look OFF */
483 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE;
484 break;
485 case 21:
486 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS;
487 break;
488 case 42:
489 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS;
490 break;
491 case 84:
492 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS;
493 break;
494 case 168:
495 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS;
496 break;
497 default:
498 /* Just use something non-zero */
499 reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS;
500 break;
501 }
502
503 /* Set up blink rate */
504 reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK;
505
506 return mv88e6xxx_port_led_write(p->chip, p->port, reg);
507}
508
509static int mv88e6xxx_led_blink_set(struct mv88e6xxx_port *p, int led,
510 unsigned long *delay_on, unsigned long *delay_off)
511{
512 u16 reg;
513 int err;
514
515 /* Choose a sensible default 336 ms (~3 Hz) */
516 if ((*delay_on == 0) && (*delay_off == 0)) {
517 *delay_on = 168;
518 *delay_off = 168;
519 }
520
521 /* No off delay is just on */
522 if (*delay_off == 0)
523 return mv88e6xxx_led_brightness_set(p, led, 1);
524
525 err = mv88e6xxx_led_set_blinking_period(p, led, *delay_on, *delay_off);
526 if (err)
527 return err;
528
529 err = mv88e6xxx_port_led_read(p->chip, p->port,
530 MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
531 ®);
532 if (err)
533 return err;
534
535 if (led == 1)
536 reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
537 else
538 reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
539
540 /* This will select the forced blinking status */
541 if (led == 1)
542 reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELD;
543 else
544 reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELD;
545
546 reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
547
548 return mv88e6xxx_port_led_write(p->chip, p->port, reg);
549}
550
551static int mv88e6xxx_led0_blink_set(struct led_classdev *ldev,
552 unsigned long *delay_on,
553 unsigned long *delay_off)
554{
555 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
556 int err;
557
558 mv88e6xxx_reg_lock(p->chip);
559 err = mv88e6xxx_led_blink_set(p, 0, delay_on, delay_off);
560 mv88e6xxx_reg_unlock(p->chip);
561
562 return err;
563}
564
565static int mv88e6xxx_led1_blink_set(struct led_classdev *ldev,
566 unsigned long *delay_on,
567 unsigned long *delay_off)
568{
569 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
570 int err;
571
572 mv88e6xxx_reg_lock(p->chip);
573 err = mv88e6xxx_led_blink_set(p, 1, delay_on, delay_off);
574 mv88e6xxx_reg_unlock(p->chip);
575
576 return err;
577}
578
579static int
580mv88e6xxx_led0_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
581{
582 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
583 u16 selector = 0;
584
585 return mv88e6xxx_led_get_selector(p, 0, p->fiber, rules, &selector);
586}
587
588static int
589mv88e6xxx_led1_hw_control_is_supported(struct led_classdev *ldev, unsigned long rules)
590{
591 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
592 u16 selector = 0;
593
594 return mv88e6xxx_led_get_selector(p, 1, p->fiber, rules, &selector);
595}
596
597static int mv88e6xxx_led_hw_control_set(struct mv88e6xxx_port *p,
598 int led, unsigned long rules)
599{
600 u16 reg;
601 int err;
602
603 err = mv88e6xxx_port_led_read(p->chip, p->port,
604 MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL,
605 ®);
606 if (err)
607 return err;
608
609 if (led == 1)
610 reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
611 else
612 reg &= ~MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
613
614 err = mv88e6xxx_led_get_selector(p, led, p->fiber, rules, ®);
615 if (err)
616 return err;
617
618 reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL;
619
620 if (led == 0)
621 dev_dbg(p->chip->dev, "LED 0 hw control on port %d trigger selector 0x%02x\n",
622 p->port,
623 (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK));
624 else
625 dev_dbg(p->chip->dev, "LED 1 hw control on port %d trigger selector 0x%02x\n",
626 p->port,
627 (unsigned int)(reg & MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK) >> 4);
628
629 return mv88e6xxx_port_led_write(p->chip, p->port, reg);
630}
631
632static int
633mv88e6xxx_led_hw_control_get(struct mv88e6xxx_port *p, int led, unsigned long *rules)
634{
635 u16 val;
636 int err;
637
638 mv88e6xxx_reg_lock(p->chip);
639 err = mv88e6xxx_port_led_read(p->chip, p->port,
640 MV88E6XXX_PORT_LED_CONTROL_POINTER_LED01_CTRL, &val);
641 mv88e6xxx_reg_unlock(p->chip);
642 if (err)
643 return err;
644
645 /* Mask out the selector bits for this port */
646 if (led == 1) {
647 val &= MV88E6XXX_PORT_LED_CONTROL_LED1_SEL_MASK;
648 /* It's forced blinking/OFF/ON */
649 if (val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELD ||
650 val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELE ||
651 val == MV88E6XXX_PORT_LED_CONTROL_LED1_SELF) {
652 *rules = 0;
653 return 0;
654 }
655 } else {
656 val &= MV88E6XXX_PORT_LED_CONTROL_LED0_SEL_MASK;
657 /* It's forced blinking/OFF/ON */
658 if (val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELD ||
659 val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELE ||
660 val == MV88E6XXX_PORT_LED_CONTROL_LED0_SELF) {
661 *rules = 0;
662 return 0;
663 }
664 }
665
666 err = mv88e6xxx_led_match_rule(p, val, led, rules);
667 if (!err)
668 return 0;
669
670 dev_dbg(p->chip->dev, "couldn't find matching selector for %04x\n", val);
671 *rules = 0;
672 return 0;
673}
674
675static int
676mv88e6xxx_led0_hw_control_set(struct led_classdev *ldev, unsigned long rules)
677{
678 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
679 int err;
680
681 mv88e6xxx_reg_lock(p->chip);
682 err = mv88e6xxx_led_hw_control_set(p, 0, rules);
683 mv88e6xxx_reg_unlock(p->chip);
684
685 return err;
686}
687
688static int
689mv88e6xxx_led1_hw_control_set(struct led_classdev *ldev, unsigned long rules)
690{
691 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
692 int err;
693
694 mv88e6xxx_reg_lock(p->chip);
695 err = mv88e6xxx_led_hw_control_set(p, 1, rules);
696 mv88e6xxx_reg_unlock(p->chip);
697
698 return err;
699}
700
701static int
702mv88e6xxx_led0_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
703{
704 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
705
706 return mv88e6xxx_led_hw_control_get(p, 0, rules);
707}
708
709static int
710mv88e6xxx_led1_hw_control_get(struct led_classdev *ldev, unsigned long *rules)
711{
712 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
713
714 return mv88e6xxx_led_hw_control_get(p, 1, rules);
715}
716
717static struct device *mv88e6xxx_led_hw_control_get_device(struct mv88e6xxx_port *p)
718{
719 struct dsa_port *dp;
720
721 dp = dsa_to_port(p->chip->ds, p->port);
722 if (!dp)
723 return NULL;
724 if (dp->user)
725 return &dp->user->dev;
726 return NULL;
727}
728
729static struct device *
730mv88e6xxx_led0_hw_control_get_device(struct led_classdev *ldev)
731{
732 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led0);
733
734 return mv88e6xxx_led_hw_control_get_device(p);
735}
736
737static struct device *
738mv88e6xxx_led1_hw_control_get_device(struct led_classdev *ldev)
739{
740 struct mv88e6xxx_port *p = container_of(ldev, struct mv88e6xxx_port, led1);
741
742 return mv88e6xxx_led_hw_control_get_device(p);
743}
744
745int mv88e6xxx_port_setup_leds(struct mv88e6xxx_chip *chip, int port)
746{
747 struct fwnode_handle *led = NULL, *leds = NULL;
748 struct led_init_data init_data = { };
749 enum led_default_state state;
750 struct mv88e6xxx_port *p;
751 struct led_classdev *l;
752 struct device *dev;
753 u32 led_num;
754 int ret;
755
756 /* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */
757 if (port > 5)
758 return -EOPNOTSUPP;
759
760 p = &chip->ports[port];
761 if (!p->fwnode)
762 return 0;
763
764 dev = chip->dev;
765
766 leds = fwnode_get_named_child_node(p->fwnode, "leds");
767 if (!leds) {
768 dev_dbg(dev, "No Leds node specified in device tree for port %d!\n",
769 port);
770 return 0;
771 }
772
773 fwnode_for_each_child_node(leds, led) {
774 /* Reg represent the led number of the port, max 2
775 * LEDs can be connected to each port, in some designs
776 * only one LED is connected.
777 */
778 if (fwnode_property_read_u32(led, "reg", &led_num))
779 continue;
780 if (led_num > 1) {
781 dev_err(dev, "invalid LED specified port %d\n", port);
782 return -EINVAL;
783 }
784
785 if (led_num == 0)
786 l = &p->led0;
787 else
788 l = &p->led1;
789
790 state = led_init_default_state_get(led);
791 switch (state) {
792 case LEDS_DEFSTATE_ON:
793 l->brightness = 1;
794 mv88e6xxx_led_brightness_set(p, led_num, 1);
795 break;
796 case LEDS_DEFSTATE_KEEP:
797 break;
798 default:
799 l->brightness = 0;
800 mv88e6xxx_led_brightness_set(p, led_num, 0);
801 }
802
803 l->max_brightness = 1;
804 if (led_num == 0) {
805 l->brightness_set_blocking = mv88e6xxx_led0_brightness_set_blocking;
806 l->blink_set = mv88e6xxx_led0_blink_set;
807 l->hw_control_is_supported = mv88e6xxx_led0_hw_control_is_supported;
808 l->hw_control_set = mv88e6xxx_led0_hw_control_set;
809 l->hw_control_get = mv88e6xxx_led0_hw_control_get;
810 l->hw_control_get_device = mv88e6xxx_led0_hw_control_get_device;
811 } else {
812 l->brightness_set_blocking = mv88e6xxx_led1_brightness_set_blocking;
813 l->blink_set = mv88e6xxx_led1_blink_set;
814 l->hw_control_is_supported = mv88e6xxx_led1_hw_control_is_supported;
815 l->hw_control_set = mv88e6xxx_led1_hw_control_set;
816 l->hw_control_get = mv88e6xxx_led1_hw_control_get;
817 l->hw_control_get_device = mv88e6xxx_led1_hw_control_get_device;
818 }
819 l->hw_control_trigger = "netdev";
820
821 init_data.default_label = ":port";
822 init_data.fwnode = led;
823 init_data.devname_mandatory = true;
824 init_data.devicename = kasprintf(GFP_KERNEL, "%s:0%d:0%d", chip->info->name,
825 port, led_num);
826 if (!init_data.devicename)
827 return -ENOMEM;
828
829 ret = devm_led_classdev_register_ext(dev, l, &init_data);
830 kfree(init_data.devicename);
831
832 if (ret) {
833 dev_err(dev, "Failed to init LED %d for port %d", led_num, port);
834 return ret;
835 }
836 }
837
838 return 0;
839}