Linux Audio

Check our new training course

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				      &reg);
 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				      &reg);
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				      &reg);
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, &reg);
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}