On Fri, Mar 17, 2023 at 03:31:15AM +0100, Christian Marangi wrote: > From: Andrew Lunn <andrew@xxxxxxx> > > 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. > Hi Andrew, Personally, I see no good reason to provide a dummy implementation of "phy_led_set_brightness", especially if you implement it in the next patch. You only use that function only the function pointer in "led_classdev". I think you can just skip it in this patch. Please find the rest of my comments inline. Thanks, Michal > Signed-off-by: Andrew Lunn <andrew@xxxxxxx> > Signed-off-by: Christian Marangi <ansuelsmth@xxxxxxxxx> > --- > drivers/net/phy/Kconfig | 1 + > drivers/net/phy/phy_device.c | 75 ++++++++++++++++++++++++++++++++++++ > include/linux/phy.h | 16 ++++++++ > 3 files changed, 92 insertions(+) > > diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig > index f5df2edc94a5..666efa6b1c8e 100644 > --- a/drivers/net/phy/Kconfig > +++ b/drivers/net/phy/Kconfig > @@ -16,6 +16,7 @@ config PHYLINK > menuconfig PHYLIB > tristate "PHY Device support and infrastructure" > depends on NETDEVICES > + depends on LEDS_CLASS > select MDIO_DEVICE > select MDIO_DEVRES > help > diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c > index 9ba8f973f26f..ee800f93c8c3 100644 > --- a/drivers/net/phy/phy_device.c > +++ b/drivers/net/phy/phy_device.c > @@ -19,10 +19,12 @@ > #include <linux/interrupt.h> > #include <linux/io.h> > #include <linux/kernel.h> > +#include <linux/list.h> > #include <linux/mdio.h> > #include <linux/mii.h> > #include <linux/mm.h> > #include <linux/module.h> > +#include <linux/of.h> > #include <linux/netdevice.h> > #include <linux/phy.h> > #include <linux/phy_led_triggers.h> > @@ -658,6 +660,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id, > device_initialize(&mdiodev->dev); > > dev->state = PHY_DOWN; > + INIT_LIST_HEAD(&dev->leds); > > mutex_init(&dev->lock); > INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine); > @@ -2964,6 +2967,73 @@ static bool phy_drv_supports_irq(struct phy_driver *phydrv) > return phydrv->config_intr && phydrv->handle_interrupt; > } > > +/* Dummy implementation until calls into PHY driver are added */ > +static int phy_led_set_brightness(struct led_classdev *led_cdev, > + enum led_brightness value) > +{ > + return 0; > +} It can be removed from this patch. > + > +static int of_phy_led(struct phy_device *phydev, > + struct device_node *led) > +{ > + struct device *dev = &phydev->mdio.dev; > + struct led_init_data init_data = {}; > + struct led_classdev *cdev; > + struct phy_led *phyled; > + int err; > + > + phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL); > + if (!phyled) > + return -ENOMEM; > + > + cdev = &phyled->led_cdev; > + > + err = of_property_read_u32(led, "reg", &phyled->index); > + if (err) > + return err; Memory leak. 'phyled' is not freed in case of error. > + > + cdev->brightness_set_blocking = phy_led_set_brightness; Please move this initialization to the patch where you are actually implementing this callback. > + cdev->max_brightness = 1; > + init_data.devicename = dev_name(&phydev->mdio.dev); > + init_data.fwnode = of_fwnode_handle(led); > + > + err = devm_led_classdev_register_ext(dev, cdev, &init_data); > + if (err) > + return err; Another memory leak. > + > + list_add(&phyled->list, &phydev->leds); Where do you free the memory allocated for phy_led structure? > + > + return 0; > +} > + > +static int of_phy_leds(struct phy_device *phydev) > +{ > + struct device_node *node = phydev->mdio.dev.of_node; > + struct device_node *leds, *led; > + int err; > + > + if (!IS_ENABLED(CONFIG_OF_MDIO)) > + return 0; > + > + if (!node) > + return 0; > + > + leds = of_get_child_by_name(node, "leds"); > + if (!leds) > + return 0; > + > + for_each_available_child_of_node(leds, led) { > + err = of_phy_led(phydev, led); > + if (err) { > + of_node_put(led); > + return err; > + } > + } > + > + return 0; > +} > + > /** > * fwnode_mdio_find_device - Given a fwnode, find the mdio_device > * @fwnode: pointer to the mdio_device's fwnode > @@ -3142,6 +3212,11 @@ static int phy_probe(struct device *dev) > /* Set the state to READY by default */ > phydev->state = PHY_READY; > > + /* Get the LEDs from the device tree, and instantiate standard > + * LEDs for them. > + */ > + err = of_phy_leds(phydev); > + > out: > /* Assert the reset signal */ > if (err) > diff --git a/include/linux/phy.h b/include/linux/phy.h > index fbeba4fee8d4..88a77ff60be9 100644 > --- a/include/linux/phy.h > +++ b/include/linux/phy.h > @@ -14,6 +14,7 @@ > #include <linux/compiler.h> > #include <linux/spinlock.h> > #include <linux/ethtool.h> > +#include <linux/leds.h> > #include <linux/linkmode.h> > #include <linux/netlink.h> > #include <linux/mdio.h> > @@ -595,6 +596,7 @@ struct macsec_ops; > * @phy_num_led_triggers: Number of triggers in @phy_led_triggers > * @led_link_trigger: LED trigger for link up/down > * @last_triggered: last LED trigger for link speed > + * @leds: list of PHY LED structures > * @master_slave_set: User requested master/slave configuration > * @master_slave_get: Current master/slave advertisement > * @master_slave_state: Current master/slave configuration > @@ -690,6 +692,7 @@ struct phy_device { > > struct phy_led_trigger *led_link_trigger; > #endif > + struct list_head leds; > > /* > * Interrupt number for this PHY > @@ -825,6 +828,19 @@ struct phy_plca_status { > bool pst; > }; > > +/** > + * struct phy_led: An LED driven by the PHY > + * > + * @list: List of LEDs > + * @led_cdev: Standard LED class structure > + * @index: Number of the LED > + */ > +struct phy_led { > + struct list_head list; > + struct led_classdev led_cdev; > + u32 index; > +}; > + > /** > * struct phy_driver - Driver structure for a particular PHY type > * > -- > 2.39.2 >