leds: core: Add led_mc_set_brightness() function
authorHans de Goede <hdegoede@redhat.com>
Fri, 31 May 2024 11:41:22 +0000 (13:41 +0200)
committerLee Jones <lee@kernel.org>
Fri, 31 May 2024 11:57:41 +0000 (12:57 +0100)
Add a new led_mc_set_brightness() function for in kernel color/brightness
changing of multi-color LEDs.

led-class-multicolor can be build as a module and led_mc_set_brightness()
will have the builtin callers, so put led_mc_set_brightness() inside
led-core instead, just like how led_set_brightness() is part of the core
and not of the led-class object.

This also adds a new LED_MULTI_COLOR led_classdev flag to allow
led_mc_set_brightness() to verify that it is operating on a multi-color
LED classdev, avoiding casting the passed in LED classdev to a multi-color
LED classdev, when it actually is not a multi-color LED.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Link: https://lore.kernel.org/r/20240531114124.45346-5-hdegoede@redhat.com
Signed-off-by: Lee Jones <lee@kernel.org>
drivers/leds/led-class-multicolor.c
drivers/leds/led-core.c
include/linux/leds.h

index ec62a48116135c5cf8069bfdbd4aa23aa9dcca39..df01c0e66c8b2e01eec6f18f0df17ac945786793 100644 (file)
@@ -134,6 +134,7 @@ int led_classdev_multicolor_register_ext(struct device *parent,
                return -EINVAL;
 
        led_cdev = &mcled_cdev->led_cdev;
+       led_cdev->flags |= LED_MULTI_COLOR;
        mcled_cdev->led_cdev.groups = led_multicolor_groups;
 
        return led_classdev_register_ext(parent, led_cdev, init_data);
index 89c9806cc97f3d2ba10447c1dc63467989791d81..ef7d1c6767ca05175732ba818d77bf6dcf5c83c0 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/led-class-multicolor.h>
 #include <linux/leds.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -362,6 +363,36 @@ int led_set_brightness_sync(struct led_classdev *led_cdev, unsigned int value)
 }
 EXPORT_SYMBOL_GPL(led_set_brightness_sync);
 
+/*
+ * This is a led-core function because just like led_set_brightness()
+ * it is used in the kernel by e.g. triggers.
+ */
+void led_mc_set_brightness(struct led_classdev *led_cdev,
+                          unsigned int *intensity_value, unsigned int num_colors,
+                          unsigned int brightness)
+{
+       struct led_classdev_mc *mcled_cdev;
+       unsigned int i;
+
+       if (!(led_cdev->flags & LED_MULTI_COLOR)) {
+               dev_err_once(led_cdev->dev, "error not a multi-color LED\n");
+               return;
+       }
+
+       mcled_cdev = lcdev_to_mccdev(led_cdev);
+       if (num_colors != mcled_cdev->num_colors) {
+               dev_err_once(led_cdev->dev, "error num_colors mismatch %u != %u\n",
+                            num_colors, mcled_cdev->num_colors);
+               return;
+       }
+
+       for (i = 0; i < mcled_cdev->num_colors; i++)
+               mcled_cdev->subled_info[i].intensity = intensity_value[i];
+
+       led_set_brightness(led_cdev, brightness);
+}
+EXPORT_SYMBOL_GPL(led_mc_set_brightness);
+
 int led_update_brightness(struct led_classdev *led_cdev)
 {
        int ret;
index 6300313c46b79957a2febfc5a312eab8d7fd9a05..ae07e44f1dcb6f6e9a1e01ad36147162831486d0 100644 (file)
@@ -107,6 +107,7 @@ struct led_classdev {
 #define LED_BRIGHT_HW_CHANGED  BIT(21)
 #define LED_RETAIN_AT_SHUTDOWN BIT(22)
 #define LED_INIT_DEFAULT_TRIGGER BIT(23)
+#define LED_MULTI_COLOR                BIT(24)
 
        /* set_brightness_work / blink_timer flags, atomic, private. */
        unsigned long           work_flags;
@@ -373,6 +374,25 @@ void led_set_brightness(struct led_classdev *led_cdev, unsigned int brightness);
  */
 int led_set_brightness_sync(struct led_classdev *led_cdev, unsigned int value);
 
+/**
+ * led_mc_set_brightness - set mc LED color intensity values and brightness
+ * @led_cdev: the LED to set
+ * @intensity_value: array of per color intensity values to set
+ * @num_colors: amount of entries in intensity_value array
+ * @brightness: the brightness to set the LED to
+ *
+ * Set a multi-color LED's per color intensity values and brightness.
+ * If necessary, this cancels the software blink timer. This function is
+ * guaranteed not to sleep.
+ *
+ * Calling this function on a non multi-color led_classdev or with the wrong
+ * num_colors value is an error. In this case an error will be logged once
+ * and the call will do nothing.
+ */
+void led_mc_set_brightness(struct led_classdev *led_cdev,
+                          unsigned int *intensity_value, unsigned int num_colors,
+                          unsigned int brightness);
+
 /**
  * led_update_brightness - update LED brightness
  * @led_cdev: the LED to query