diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 77a4d2b8545e56..32e7680f7ebb47 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -3021,6 +3021,39 @@ static int phy_led_blink_set(struct led_classdev *led_cdev, return err; } +static int phy_led_hw_control_configure(struct led_classdev *led_cdev, + unsigned long rules, + enum led_blink_hw_cmd cmd) +{ + struct phy_led *phyled = to_phy_led(led_cdev); + struct phy_device *phydev = phyled->phydev; + unsigned long active_rules; + int err; + + mutex_lock(&phydev->lock); + switch (cmd) { + case LED_BLINK_HW_SUPPORTED: + err = phydev->drv->led_hw_is_supported(phydev, phyled->index, + rules); + break; + case LED_BLINK_HW_ENABLE: + err = phydev->drv->led_hw_control_set(phydev, phyled->index, + rules); + break; + case LED_BLINK_HW_STATUS: + err = phydev->drv->led_hw_control_get(phydev, phyled->index, + &active_rules); + if (!err) + err = active_rules; + break; + default: + err = -EOPNOTSUPP; + } + mutex_unlock(&phydev->lock); + + return err; +} + static int of_phy_led(struct phy_device *phydev, struct device_node *led) { @@ -3045,6 +3078,10 @@ static int of_phy_led(struct phy_device *phydev, cdev->brightness_set_blocking = phy_led_set_brightness; if (phydev->drv->led_blink_set) cdev->blink_set = phy_led_blink_set; + if (phydev->drv->led_hw_is_supported && + phydev->drv->led_hw_control_set && + phydev->drv->led_hw_control_get) + cdev->hw_control_configure = phy_led_hw_control_configure; cdev->max_brightness = 1; init_data.devicename = dev_name(&phydev->mdio.dev); init_data.fwnode = of_fwnode_handle(led); diff --git a/include/linux/phy.h b/include/linux/phy.h index 3e42791f725e14..7e9ea5166eb7fc 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -1091,6 +1091,20 @@ struct phy_driver { int (*led_blink_set)(struct phy_device *dev, u32 index, unsigned long *delay_on, unsigned long *delay_off); + /* Can the HW support the given rules. Return 0 if yes, + * -EOPNOTSUPP if not, or an error code. + */ + int (*led_hw_is_supported)(struct phy_device *dev, u32 index, + unsigned long rules); + /* Set the HW to control the LED as described by rules. */ + int (*led_hw_control_set)(struct phy_device *dev, u32 index, + unsigned long rules); + /* Get the rules used to describe how the HW is currently + * configure. + */ + int (*led_hw_control_get)(struct phy_device *dev, u32 index, + unsigned long *rules); + }; #define to_phy_driver(d) container_of(to_mdio_common_driver(d), \ struct phy_driver, mdiodrv)