diff --git a/Documentation/ABI/testing/sysfs-class-led b/Documentation/ABI/testing/sysfs-class-led index d4c918cc11a1..f6d4e17e1a3b 100644 --- a/Documentation/ABI/testing/sysfs-class-led +++ b/Documentation/ABI/testing/sysfs-class-led @@ -28,7 +28,9 @@ Description: Writing 0 to this file clears active trigger. Writing non-zero to this file while trigger is active changes the - top brightness trigger is going to use. + top brightness trigger is going to use, unless the current + trigger is offloaded to hardware (in which case writing any + value will deactivate the trigger). diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 7110bfbe3b83..39cc2f3ea63f 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -64,6 +64,9 @@ static ssize_t brightness_store(struct device *dev, if (state == LED_OFF) led_trigger_remove(led_cdev); + else + led_trigger_remove_hw_control(led_cdev); + led_set_brightness(led_cdev, state); ret = size; diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c index bf2543538ed0..804a04b326c4 100644 --- a/drivers/leds/led-triggers.c +++ b/drivers/leds/led-triggers.c @@ -287,6 +287,15 @@ void led_trigger_remove(struct led_classdev *led_cdev) } EXPORT_SYMBOL_GPL(led_trigger_remove); +void led_trigger_remove_hw_control(struct led_classdev *led_cdev) +{ + guard(rwsem_write)(&led_cdev->trigger_lock); + + if (__led_trigger_is_hw_controlled(led_cdev)) + led_trigger_set(led_cdev, NULL); +} +EXPORT_SYMBOL_GPL(led_trigger_remove_hw_control); + static bool led_match_default_trigger(struct led_classdev *led_cdev, struct led_trigger *trig) { diff --git a/include/linux/leds.h b/include/linux/leds.h index 46ad2e03e1c6..d778709f5b1b 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -533,6 +533,7 @@ void led_trigger_blink_oneshot(struct led_trigger *trigger, void led_trigger_set_default(struct led_classdev *led_cdev); int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger); void led_trigger_remove(struct led_classdev *led_cdev); +void led_trigger_remove_hw_control(struct led_classdev *led_cdev); bool led_trigger_is_hw_controlled(struct led_classdev *led_cdev); @@ -586,6 +587,7 @@ static inline int led_trigger_set(struct led_classdev *led_cdev, } static inline void led_trigger_remove(struct led_classdev *led_cdev) {} +static inline void led_trigger_remove_hw_control(struct led_classdev *led_cdev) {} static inline bool led_trigger_is_hw_controlled(struct led_classdev *led_cdev) {