Skip to content

Commit 01e5b72

Browse files
lunndavem330
authored andcommitted
net: phy: Add a binding for PHY LEDs
Define common binding parsing for all PHY drivers with LEDs using phylib. Parse the DT as part of the phy_probe and add LEDs to the linux LED class infrastructure. For the moment, provide a dummy brightness function, which will later be replaced with a call into the PHY driver. This allows testing since the LED core might otherwise reject an LED whose brightness cannot be set. Add a dependency on LED_CLASS. It either needs to be built in, or not enabled, since a modular build can result in linker errors. Signed-off-by: Andrew Lunn <[email protected]> Signed-off-by: Christian Marangi <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent e5029ed commit 01e5b72

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

drivers/net/phy/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ menuconfig PHYLIB
1818
depends on NETDEVICES
1919
select MDIO_DEVICE
2020
select MDIO_DEVRES
21+
depends on LEDS_CLASS || LEDS_CLASS=n
2122
help
2223
Ethernet controllers are usually attached to PHY
2324
devices. This option provides infrastructure for

drivers/net/phy/phy_device.c

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@
1919
#include <linux/interrupt.h>
2020
#include <linux/io.h>
2121
#include <linux/kernel.h>
22+
#include <linux/list.h>
2223
#include <linux/mdio.h>
2324
#include <linux/mii.h>
2425
#include <linux/mm.h>
2526
#include <linux/module.h>
27+
#include <linux/of.h>
2628
#include <linux/netdevice.h>
2729
#include <linux/phy.h>
2830
#include <linux/phy_led_triggers.h>
@@ -674,6 +676,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
674676
device_initialize(&mdiodev->dev);
675677

676678
dev->state = PHY_DOWN;
679+
INIT_LIST_HEAD(&dev->leds);
677680

678681
mutex_init(&dev->lock);
679682
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
@@ -2988,6 +2991,74 @@ static bool phy_drv_supports_irq(struct phy_driver *phydrv)
29882991
return phydrv->config_intr && phydrv->handle_interrupt;
29892992
}
29902993

2994+
/* Dummy implementation until calls into PHY driver are added */
2995+
static int phy_led_set_brightness(struct led_classdev *led_cdev,
2996+
enum led_brightness value)
2997+
{
2998+
return 0;
2999+
}
3000+
3001+
static int of_phy_led(struct phy_device *phydev,
3002+
struct device_node *led)
3003+
{
3004+
struct device *dev = &phydev->mdio.dev;
3005+
struct led_init_data init_data = {};
3006+
struct led_classdev *cdev;
3007+
struct phy_led *phyled;
3008+
int err;
3009+
3010+
phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL);
3011+
if (!phyled)
3012+
return -ENOMEM;
3013+
3014+
cdev = &phyled->led_cdev;
3015+
3016+
err = of_property_read_u8(led, "reg", &phyled->index);
3017+
if (err)
3018+
return err;
3019+
3020+
cdev->brightness_set_blocking = phy_led_set_brightness;
3021+
cdev->max_brightness = 1;
3022+
init_data.devicename = dev_name(&phydev->mdio.dev);
3023+
init_data.fwnode = of_fwnode_handle(led);
3024+
init_data.devname_mandatory = true;
3025+
3026+
err = devm_led_classdev_register_ext(dev, cdev, &init_data);
3027+
if (err)
3028+
return err;
3029+
3030+
list_add(&phyled->list, &phydev->leds);
3031+
3032+
return 0;
3033+
}
3034+
3035+
static int of_phy_leds(struct phy_device *phydev)
3036+
{
3037+
struct device_node *node = phydev->mdio.dev.of_node;
3038+
struct device_node *leds, *led;
3039+
int err;
3040+
3041+
if (!IS_ENABLED(CONFIG_OF_MDIO))
3042+
return 0;
3043+
3044+
if (!node)
3045+
return 0;
3046+
3047+
leds = of_get_child_by_name(node, "leds");
3048+
if (!leds)
3049+
return 0;
3050+
3051+
for_each_available_child_of_node(leds, led) {
3052+
err = of_phy_led(phydev, led);
3053+
if (err) {
3054+
of_node_put(led);
3055+
return err;
3056+
}
3057+
}
3058+
3059+
return 0;
3060+
}
3061+
29913062
/**
29923063
* fwnode_mdio_find_device - Given a fwnode, find the mdio_device
29933064
* @fwnode: pointer to the mdio_device's fwnode
@@ -3183,6 +3254,11 @@ static int phy_probe(struct device *dev)
31833254
/* Set the state to READY by default */
31843255
phydev->state = PHY_READY;
31853256

3257+
/* Get the LEDs from the device tree, and instantiate standard
3258+
* LEDs for them.
3259+
*/
3260+
err = of_phy_leds(phydev);
3261+
31863262
out:
31873263
/* Re-assert the reset signal on error */
31883264
if (err)

include/linux/phy.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/compiler.h>
1515
#include <linux/spinlock.h>
1616
#include <linux/ethtool.h>
17+
#include <linux/leds.h>
1718
#include <linux/linkmode.h>
1819
#include <linux/netlink.h>
1920
#include <linux/mdio.h>
@@ -600,6 +601,7 @@ struct macsec_ops;
600601
* @phy_num_led_triggers: Number of triggers in @phy_led_triggers
601602
* @led_link_trigger: LED trigger for link up/down
602603
* @last_triggered: last LED trigger for link speed
604+
* @leds: list of PHY LED structures
603605
* @master_slave_set: User requested master/slave configuration
604606
* @master_slave_get: Current master/slave advertisement
605607
* @master_slave_state: Current master/slave configuration
@@ -699,6 +701,7 @@ struct phy_device {
699701

700702
struct phy_led_trigger *led_link_trigger;
701703
#endif
704+
struct list_head leds;
702705

703706
/*
704707
* Interrupt number for this PHY
@@ -834,6 +837,19 @@ struct phy_plca_status {
834837
bool pst;
835838
};
836839

840+
/**
841+
* struct phy_led: An LED driven by the PHY
842+
*
843+
* @list: List of LEDs
844+
* @led_cdev: Standard LED class structure
845+
* @index: Number of the LED
846+
*/
847+
struct phy_led {
848+
struct list_head list;
849+
struct led_classdev led_cdev;
850+
u8 index;
851+
};
852+
837853
/**
838854
* struct phy_driver - Driver structure for a particular PHY type
839855
*

0 commit comments

Comments
 (0)