| From fd6258d20e37b52572d9668850bf6ae07f065b7f Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 20 Jan 2025 12:36:53 +0100 |
| Subject: leds: trigger: netdev: Configure LED blink interval for HW offload |
| |
| From: Marek Vasut <marex@denx.de> |
| |
| [ Upstream commit c629c972b310af41e9e072febb6dae9a299edde6 ] |
| |
| In case a PHY LED implements .blink_set callback to set LED blink |
| interval, call it even if .hw_control is already set, as that LED |
| blink interval likely controls the blink rate of that HW offloaded |
| LED. For PHY LEDs, that can be their activity blinking interval. |
| |
| The software blinking is not affected by this change. |
| |
| With this change, the LED interval setting looks something like this: |
| $ echo netdev > /sys/class/leds/led:green:lan/trigger |
| $ echo 1 > /sys/class/leds/led:green:lan/brightness |
| $ echo 250 > /sys/class/leds/led:green:lan/interval |
| |
| Signed-off-by: Marek Vasut <marex@denx.de> |
| Link: https://lore.kernel.org/r/20250120113740.91807-1-marex@denx.de |
| Signed-off-by: Lee Jones <lee@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/leds/trigger/ledtrig-netdev.c | 16 +++++++++++++--- |
| 1 file changed, 13 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c |
| index c15efe3e50780..4e048e08c4fde 100644 |
| --- a/drivers/leds/trigger/ledtrig-netdev.c |
| +++ b/drivers/leds/trigger/ledtrig-netdev.c |
| @@ -68,6 +68,7 @@ struct led_netdev_data { |
| unsigned int last_activity; |
| |
| unsigned long mode; |
| + unsigned long blink_delay; |
| int link_speed; |
| __ETHTOOL_DECLARE_LINK_MODE_MASK(supported_link_modes); |
| u8 duplex; |
| @@ -86,6 +87,10 @@ static void set_baseline_state(struct led_netdev_data *trigger_data) |
| /* Already validated, hw control is possible with the requested mode */ |
| if (trigger_data->hw_control) { |
| led_cdev->hw_control_set(led_cdev, trigger_data->mode); |
| + if (led_cdev->blink_set) { |
| + led_cdev->blink_set(led_cdev, &trigger_data->blink_delay, |
| + &trigger_data->blink_delay); |
| + } |
| |
| return; |
| } |
| @@ -454,10 +459,11 @@ static ssize_t interval_store(struct device *dev, |
| size_t size) |
| { |
| struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev); |
| + struct led_classdev *led_cdev = trigger_data->led_cdev; |
| unsigned long value; |
| int ret; |
| |
| - if (trigger_data->hw_control) |
| + if (trigger_data->hw_control && !led_cdev->blink_set) |
| return -EINVAL; |
| |
| ret = kstrtoul(buf, 0, &value); |
| @@ -466,9 +472,13 @@ static ssize_t interval_store(struct device *dev, |
| |
| /* impose some basic bounds on the timer interval */ |
| if (value >= 5 && value <= 10000) { |
| - cancel_delayed_work_sync(&trigger_data->work); |
| + if (trigger_data->hw_control) { |
| + trigger_data->blink_delay = value; |
| + } else { |
| + cancel_delayed_work_sync(&trigger_data->work); |
| |
| - atomic_set(&trigger_data->interval, msecs_to_jiffies(value)); |
| + atomic_set(&trigger_data->interval, msecs_to_jiffies(value)); |
| + } |
| set_baseline_state(trigger_data); /* resets timer */ |
| } |
| |
| -- |
| 2.39.5 |
| |