-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net: phy: leds: add support for led triggers on phy link state change
Create an option CONFIG_LED_TRIGGER_PHY (default n), which will create a set of led triggers for each instantiated PHY device. There is one LED trigger per link-speed, per-phy. The triggers are registered during phy_attach and unregistered during phy_detach. This allows for a user to configure their system to allow a set of LEDs not controlled by the phy to represent link state changes on the phy. LEDS controlled by the phy are unaffected. For example, we have a board where some of the leds in the RJ45 socket are controlled by the phy, but others are not. Using the triggers provided by this patch the leds not controlled by the phy can be configured to show the current speed of the ethernet connection. The leds controlled by the phy are unaffected. Signed-off-by: Josh Cartwright <josh.cartwright@ni.com> Signed-off-by: Nathan Sullivan <nathan.sullivan@ni.com> Signed-off-by: Zach Brown <zach.brown@ni.com> Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Zach Brown
authored and
David S. Miller
committed
Oct 18, 2016
1 parent
1f9127c
commit 2e0bc45
Showing
7 changed files
with
214 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/* Copyright (C) 2016 National Instruments Corp. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
#include <linux/leds.h> | ||
#include <linux/phy.h> | ||
#include <linux/netdevice.h> | ||
|
||
static struct phy_led_trigger *phy_speed_to_led_trigger(struct phy_device *phy, | ||
unsigned int speed) | ||
{ | ||
unsigned int i; | ||
|
||
for (i = 0; i < phy->phy_num_led_triggers; i++) { | ||
if (phy->phy_led_triggers[i].speed == speed) | ||
return &phy->phy_led_triggers[i]; | ||
} | ||
return NULL; | ||
} | ||
|
||
void phy_led_trigger_change_speed(struct phy_device *phy) | ||
{ | ||
struct phy_led_trigger *plt; | ||
|
||
if (!phy->link) | ||
goto out_change_speed; | ||
|
||
if (phy->speed == 0) | ||
return; | ||
|
||
plt = phy_speed_to_led_trigger(phy, phy->speed); | ||
if (!plt) { | ||
netdev_alert(phy->attached_dev, | ||
"No phy led trigger registered for speed(%d)\n", | ||
phy->speed); | ||
goto out_change_speed; | ||
} | ||
|
||
if (plt != phy->last_triggered) { | ||
led_trigger_event(&phy->last_triggered->trigger, LED_OFF); | ||
led_trigger_event(&plt->trigger, LED_FULL); | ||
phy->last_triggered = plt; | ||
} | ||
return; | ||
|
||
out_change_speed: | ||
if (phy->last_triggered) { | ||
led_trigger_event(&phy->last_triggered->trigger, | ||
LED_OFF); | ||
phy->last_triggered = NULL; | ||
} | ||
} | ||
EXPORT_SYMBOL_GPL(phy_led_trigger_change_speed); | ||
|
||
static int phy_led_trigger_register(struct phy_device *phy, | ||
struct phy_led_trigger *plt, | ||
unsigned int speed) | ||
{ | ||
char name_suffix[PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE]; | ||
|
||
plt->speed = speed; | ||
|
||
if (speed < SPEED_1000) | ||
snprintf(name_suffix, sizeof(name_suffix), "%dMbps", speed); | ||
else if (speed == SPEED_2500) | ||
snprintf(name_suffix, sizeof(name_suffix), "2.5Gbps"); | ||
else | ||
snprintf(name_suffix, sizeof(name_suffix), "%dGbps", | ||
DIV_ROUND_CLOSEST(speed, 1000)); | ||
|
||
snprintf(plt->name, sizeof(plt->name), PHY_ID_FMT ":%s", | ||
phy->mdio.bus->id, phy->mdio.addr, name_suffix); | ||
plt->trigger.name = plt->name; | ||
|
||
return led_trigger_register(&plt->trigger); | ||
} | ||
|
||
static void phy_led_trigger_unregister(struct phy_led_trigger *plt) | ||
{ | ||
led_trigger_unregister(&plt->trigger); | ||
} | ||
|
||
int phy_led_triggers_register(struct phy_device *phy) | ||
{ | ||
int i, err; | ||
unsigned int speeds[50]; | ||
|
||
phy->phy_num_led_triggers = phy_supported_speeds(phy, speeds, | ||
ARRAY_SIZE(speeds)); | ||
if (!phy->phy_num_led_triggers) | ||
return 0; | ||
|
||
phy->phy_led_triggers = devm_kzalloc(&phy->mdio.dev, | ||
sizeof(struct phy_led_trigger) * | ||
phy->phy_num_led_triggers, | ||
GFP_KERNEL); | ||
if (!phy->phy_led_triggers) | ||
return -ENOMEM; | ||
|
||
for (i = 0; i < phy->phy_num_led_triggers; i++) { | ||
err = phy_led_trigger_register(phy, &phy->phy_led_triggers[i], | ||
speeds[i]); | ||
if (err) | ||
goto out_unreg; | ||
} | ||
|
||
phy->last_triggered = NULL; | ||
phy_led_trigger_change_speed(phy); | ||
|
||
return 0; | ||
out_unreg: | ||
while (i--) | ||
phy_led_trigger_unregister(&phy->phy_led_triggers[i]); | ||
devm_kfree(&phy->mdio.dev, phy->phy_led_triggers); | ||
return err; | ||
} | ||
EXPORT_SYMBOL_GPL(phy_led_triggers_register); | ||
|
||
void phy_led_triggers_unregister(struct phy_device *phy) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < phy->phy_num_led_triggers; i++) | ||
phy_led_trigger_unregister(&phy->phy_led_triggers[i]); | ||
|
||
devm_kfree(&phy->mdio.dev, phy->phy_led_triggers); | ||
} | ||
EXPORT_SYMBOL_GPL(phy_led_triggers_unregister); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* Copyright (C) 2016 National Instruments Corp. | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
*/ | ||
#ifndef __PHY_LED_TRIGGERS | ||
#define __PHY_LED_TRIGGERS | ||
|
||
struct phy_device; | ||
|
||
#ifdef CONFIG_LED_TRIGGER_PHY | ||
|
||
#include <linux/leds.h> | ||
|
||
#define PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE 10 | ||
#define PHY_MII_BUS_ID_SIZE (20 - 3) | ||
|
||
#define PHY_LINK_LED_TRIGGER_NAME_SIZE (PHY_MII_BUS_ID_SIZE + \ | ||
FIELD_SIZEOF(struct mdio_device, addr)+\ | ||
PHY_LED_TRIGGER_SPEED_SUFFIX_SIZE) | ||
|
||
struct phy_led_trigger { | ||
struct led_trigger trigger; | ||
char name[PHY_LINK_LED_TRIGGER_NAME_SIZE]; | ||
unsigned int speed; | ||
}; | ||
|
||
|
||
extern int phy_led_triggers_register(struct phy_device *phy); | ||
extern void phy_led_triggers_unregister(struct phy_device *phy); | ||
extern void phy_led_trigger_change_speed(struct phy_device *phy); | ||
|
||
#else | ||
|
||
static inline int phy_led_triggers_register(struct phy_device *phy) | ||
{ | ||
return 0; | ||
} | ||
static inline void phy_led_triggers_unregister(struct phy_device *phy) { } | ||
static inline void phy_led_trigger_change_speed(struct phy_device *phy) { } | ||
|
||
#endif | ||
|
||
#endif |