if (brightness) { /* Selector 0x0f == Force LED ON */ if (led == 1)
reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELF; else
reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELF;
} else { /* Selector 0x0e == Force LED OFF */ if (led == 1)
reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE; else
reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE;
}
/* The following is a lookup table to check what rules we can support on a * certain LED given restrictions such as that some rules only work with fiber * (SFP) connections and some blink on activity by default.
*/ #define MV88E6XXX_PORTS_0_3 (BIT(0) | BIT(1) | BIT(2) | BIT(3)) #define MV88E6XXX_PORTS_4_5 (BIT(4) | BIT(5)) #define MV88E6XXX_PORT_4 BIT(4) #define MV88E6XXX_PORT_5 BIT(5)
/* mv88e6xxx_led_match_selector() - look up the appropriate LED mode selector * @p: port state container * @led: LED number, 0 or 1 * @blink_activity: blink the LED (usually blink on indicated activity) * @fiber: the link is connected to fiber such as SFP * @rules: LED status flags from the LED classdev core * @selector: fill in the selector in this parameter with an OR operation
*/ staticint mv88e6xxx_led_match_selector(struct mv88e6xxx_port *p, int led, bool blink_activity, bool fiber, unsignedlong rules, u16 *selector)
{ conststruct mv88e6xxx_led_hwconfig *conf; int i;
/* No rules means we turn the LED off */ if (!rules) { if (led == 1)
*selector |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELE; else
*selector |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELE; return 0;
}
/* TODO: these rules are for MV88E6352, when adding other families, * think about making sure you select the table that match the * specific switch family.
*/ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
conf = &mv88e6352_led_hwconfigs[i];
if (conf->led != led) continue;
if (!(conf->portmask & BIT(p->port))) continue;
if (conf->blink_activity != blink_activity) continue;
if (conf->fiber != fiber) continue;
if (conf->rules == rules) {
dev_dbg(p->chip->dev, "port%d LED %d set selector %04x for rules %08lx\n",
p->port, led, conf->selector, rules);
*selector |= conf->selector; return 0;
}
}
return -EOPNOTSUPP;
}
/* mv88e6xxx_led_match_selector() - find Linux netdev rules from a selector value * @p: port state container * @selector: the selector value from the LED actity register * @led: LED number, 0 or 1 * @rules: Linux netdev activity rules found from selector
*/ staticint
mv88e6xxx_led_match_rule(struct mv88e6xxx_port *p, u16 selector, int led, unsignedlong *rules)
{ conststruct mv88e6xxx_led_hwconfig *conf; int i;
/* Find the selector in the table, we just look for the right selector * and ignore if the activity has special properties such as blinking * or is fiber-only.
*/ for (i = 0; i < ARRAY_SIZE(mv88e6352_led_hwconfigs); i++) {
conf = &mv88e6352_led_hwconfigs[i];
if (conf->led != led) continue;
if (!(conf->portmask & BIT(p->port))) continue;
if (conf->selector == selector) {
dev_dbg(p->chip->dev, "port%d LED %d has selector %04x, rules %08lx\n",
p->port, led, selector, conf->rules);
*rules = conf->rules; return 0;
}
}
return -EINVAL;
}
/* mv88e6xxx_led_get_selector() - get the appropriate LED mode selector * @p: port state container * @led: LED number, 0 or 1 * @fiber: the link is connected to fiber such as SFP * @rules: LED status flags from the LED classdev core * @selector: fill in the selector in this parameter with an OR operation
*/ staticint mv88e6xxx_led_get_selector(struct mv88e6xxx_port *p, int led, bool fiber, unsignedlong rules, u16 *selector)
{ int err;
/* What happens here is that we first try to locate a trigger with solid * indicator (such as LED is on for a 1000 link) else we try a second * sweep to find something suitable with a trigger that will blink on * activity.
*/
err = mv88e6xxx_led_match_selector(p, led, false, fiber, rules, selector); if (err) return mv88e6xxx_led_match_selector(p, led, true, fiber, rules, selector);
return 0;
}
/* Sets up the hardware blinking period */ staticint mv88e6xxx_led_set_blinking_period(struct mv88e6xxx_port *p, int led, unsignedlong delay_on, unsignedlong delay_off)
{ unsignedlong period;
u16 reg;
period = delay_on + delay_off;
reg = 0;
switch (period) { case 21:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_21MS; break; case 42:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_42MS; break; case 84:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_84MS; break; case 168:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_168MS; break; case 336:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_336MS; break; case 672:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_BLINK_RATE_672MS; break; default: /* Fall back to software blinking */ return -EINVAL;
}
/* This is essentially PWM duty cycle: how long time of the period * will the LED be on. Zero isn't great in most cases.
*/ switch (delay_on) { case 0: /* This is usually pretty useless and will make the LED look OFF */
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_NONE; break; case 21:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS; break; case 42:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_42MS; break; case 84:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_84MS; break; case 168:
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_168MS; break; default: /* Just use something non-zero */
reg |= MV88E6XXX_PORT_LED_CONTROL_0x06_PULSE_STRETCH_21MS; break;
}
/* Set up blink rate */
reg |= MV88E6XXX_PORT_LED_CONTROL_POINTER_STRETCH_BLINK;
/* This will select the forced blinking status */ if (led == 1)
reg |= MV88E6XXX_PORT_LED_CONTROL_LED1_SELD; else
reg |= MV88E6XXX_PORT_LED_CONTROL_LED0_SELD;
/* LEDs are on ports 1,2,3,4, 5 and 6 (index 0..5), no more */ if (port > 5) return -EOPNOTSUPP;
p = &chip->ports[port]; if (!p->fwnode) return 0;
dev = chip->dev;
leds = fwnode_get_named_child_node(p->fwnode, "leds"); if (!leds) {
dev_dbg(dev, "No Leds node specified in device tree for port %d!\n",
port); return 0;
}
fwnode_for_each_child_node(leds, led) { /* Reg represent the led number of the port, max 2 * LEDs can be connected to each port, in some designs * only one LED is connected.
*/ if (fwnode_property_read_u32(led, "reg", &led_num)) continue; if (led_num > 1) {
dev_err(dev, "invalid LED specified port %d\n", port);
ret = -EINVAL; goto err_put_led;
}
if (led_num == 0)
l = &p->led0; else
l = &p->led1;
state = led_init_default_state_get(led); switch (state) { case LEDS_DEFSTATE_ON:
l->brightness = 1;
mv88e6xxx_led_brightness_set(p, led_num, 1); break; case LEDS_DEFSTATE_KEEP: break; default:
l->brightness = 0;
mv88e6xxx_led_brightness_set(p, led_num, 0);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.