leds: rgb: wago-m4: switch to brightness_set_blocking

wago_led_set() acquires send_lock (a mutex) and is therefore a
sleeping function. Assigning it to brightness_set violates the LED
core API contract: brightness_set is called directly from atomic
context (timer/softirq) and must not sleep. On non-RT kernels this
would trigger BUG: scheduling while atomic.

Use brightness_set_blocking instead. The LED core automatically
defers calls through a workqueue, making the sleeping path safe.
Update the function signature to return int and add return 0 as
required by the blocking callback prototype.

Reported-by: Oleg Karfich <oleg.karfich@wago.com>
Signed-off-by: Heinrich Toews <ht@twx-software.de>
This commit is contained in:
Heinrich Toews
2026-06-18 17:38:07 +02:00
parent 7766560288
commit 869a9bb515
+4 -2
View File
@@ -350,7 +350,7 @@ static const struct attribute_group wago_led_attr_group = {
#endif /* CONFIG_LEDS_WAGO_M4_WRAPPER_SYSFS_PASSTHROUGH */
static void wago_led_set(struct led_classdev *led_cdev,
static int wago_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(led_cdev);
@@ -393,6 +393,8 @@ static void wago_led_set(struct led_classdev *led_cdev,
mutex_lock(&priv->send_lock);
wago_send(priv, &msg, sizeof(msg));
mutex_unlock(&priv->send_lock);
return 0;
}
/* -------------------------------------------------------------------------
@@ -420,7 +422,7 @@ static void wago_led_init_subled(struct wago_led *led)
led->mc_cdev.subled_info = led->subled_info;
led->mc_cdev.num_colors = WAGO_LED_NUM_CHANNELS;
led->mc_cdev.led_cdev.brightness_set = wago_led_set;
led->mc_cdev.led_cdev.brightness_set_blocking = wago_led_set;
led->mc_cdev.led_cdev.max_brightness = LED_FULL;
led->mc_cdev.led_cdev.flags = LED_CORE_SUSPENDRESUME;
led->mc_cdev.led_cdev.color = LED_COLOR_ID_MULTI;