52faa4809b2ae028d9bca67a02aaa9b147474d09
[openwrt/staging/ldir.git] /
1 From 7c145a34ba6e380616af93262fcab9fc7261d851 Mon Sep 17 00:00:00 2001
2 From: Christian Marangi <ansuelsmth@gmail.com>
3 Date: Mon, 29 May 2023 18:32:38 +0200
4 Subject: [PATCH 08/13] leds: trigger: netdev: add support for LED hw control
5
6 Add support for LED hw control for the netdev trigger.
7
8 The trigger on calling set_baseline_state to configure a new mode, will
9 do various check to verify if hw control can be used for the requested
10 mode in can_hw_control() function.
11
12 It will first check if the LED driver supports hw control for the netdev
13 trigger, then will use hw_control_is_supported() and finally will call
14 hw_control_set() to apply the requested mode.
15
16 To use such mode, interval MUST be set to the default value and net_dev
17 MUST be set. If one of these 2 value are not valid, hw control will
18 never be used and normal software fallback is used.
19
20 The default interval value is moved to a define to make sure they are
21 always synced.
22
23 Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
24 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
25 Signed-off-by: David S. Miller <davem@davemloft.net>
26 ---
27 drivers/leds/trigger/ledtrig-netdev.c | 43 +++++++++++++++++++++++++--
28 1 file changed, 41 insertions(+), 2 deletions(-)
29
30 --- a/drivers/leds/trigger/ledtrig-netdev.c
31 +++ b/drivers/leds/trigger/ledtrig-netdev.c
32 @@ -24,6 +24,8 @@
33 #include <linux/timer.h>
34 #include "../leds.h"
35
36 +#define NETDEV_LED_DEFAULT_INTERVAL 50
37 +
38 /*
39 * Configurable sysfs attributes:
40 *
41 @@ -68,6 +70,13 @@ static void set_baseline_state(struct le
42 int current_brightness;
43 struct led_classdev *led_cdev = trigger_data->led_cdev;
44
45 + /* Already validated, hw control is possible with the requested mode */
46 + if (trigger_data->hw_control) {
47 + led_cdev->hw_control_set(led_cdev, trigger_data->mode);
48 +
49 + return;
50 + }
51 +
52 current_brightness = led_cdev->brightness;
53 if (current_brightness)
54 led_cdev->blink_brightness = current_brightness;
55 @@ -103,12 +112,42 @@ static bool supports_hw_control(struct l
56
57 static bool can_hw_control(struct led_netdev_data *trigger_data)
58 {
59 + unsigned long default_interval = msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL);
60 + unsigned int interval = atomic_read(&trigger_data->interval);
61 struct led_classdev *led_cdev = trigger_data->led_cdev;
62 + int ret;
63
64 if (!supports_hw_control(led_cdev))
65 return false;
66
67 - return false;
68 + /*
69 + * Interval must be set to the default
70 + * value. Any different value is rejected if in hw
71 + * control.
72 + */
73 + if (interval != default_interval)
74 + return false;
75 +
76 + /*
77 + * net_dev must be set with hw control, otherwise no
78 + * blinking can be happening and there is nothing to
79 + * offloaded.
80 + */
81 + if (!trigger_data->net_dev)
82 + return false;
83 +
84 + /* Check if the requested mode is supported */
85 + ret = led_cdev->hw_control_is_supported(led_cdev, trigger_data->mode);
86 + /* Fall back to software blinking if not supported */
87 + if (ret == -EOPNOTSUPP)
88 + return false;
89 + if (ret) {
90 + dev_warn(led_cdev->dev,
91 + "Current mode check failed with error %d\n", ret);
92 + return false;
93 + }
94 +
95 + return true;
96 }
97
98 static ssize_t device_name_show(struct device *dev,
99 @@ -413,7 +452,7 @@ static int netdev_trig_activate(struct l
100 trigger_data->device_name[0] = 0;
101
102 trigger_data->mode = 0;
103 - atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
104 + atomic_set(&trigger_data->interval, msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL));
105 trigger_data->last_activity = 0;
106
107 led_set_trigger_data(led_cdev, trigger_data);