diff mbox series

[v3,2/2] leds: multicolor: Read default-intensities property

Message ID 9175a8b9fdd23a5b379457e7246ae4364cabc110.1651744128.git.sven.schwermer@disruptive-technologies.com
State New
Headers show
Series [v3,1/2] dt-bindings: leds: Add multi-color default-intensities property | expand

Commit Message

Sven Schwermer May 5, 2022, 9:50 a.m. UTC
From: Sven Schwermer <sven.schwermer@disruptive-technologies.com>

This allows to assign intensity values taken from the firmware interface
(if available) to the indivisual sub LEDs (colors) at driver probe time,
i.e. most commonly at kernel boot time. This is crucial for setting a
specific color and early in the boot process. While it would be possible
to set a static color in the bootloader, this mechanism allows setting a
pattern (e.g. blinking) at a specific color.

Signed-off-by: Sven Schwermer <sven.schwermer@disruptive-technologies.com>
---

Notes:
    V1->V2: Fix mixup
    V2->V3: Use color-intensity mapping instead of simple intensity array

 drivers/leds/led-class-multicolor.c | 48 +++++++++++++++++++++++++++++
 1 file changed, 48 insertions(+)
diff mbox series

Patch

diff --git a/drivers/leds/led-class-multicolor.c b/drivers/leds/led-class-multicolor.c
index e317408583df..2900dd02fe41 100644
--- a/drivers/leds/led-class-multicolor.c
+++ b/drivers/leds/led-class-multicolor.c
@@ -9,6 +9,7 @@ 
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
+#include <linux/property.h>
 
 #include "leds.h"
 
@@ -116,6 +117,50 @@  static struct attribute *led_multicolor_attrs[] = {
 };
 ATTRIBUTE_GROUPS(led_multicolor);
 
+static void multi_load_default_intensities(struct device *parent,
+					   struct led_classdev_mc *mcled_cdev,
+					   struct fwnode_handle *fwnode)
+{
+	u32 intensities[2 * LED_COLOR_ID_MAX];
+	unsigned int j;
+	int len;
+	int ret;
+	int i;
+
+	len = fwnode_property_read_u32_array(fwnode, "default-intensities",
+					     NULL, 0);
+	if (len < 0) {
+		if (len != -ENODATA)
+			dev_warn(parent,
+				 "failed to read default-intensities property length: %d", ret);
+		return;
+	}
+	if (len % 2 != 0) {
+		dev_warn(parent, "default-intensities property has uneven number of values");
+		return;
+	}
+	if (len > ARRAY_SIZE(intensities)) {
+		dev_warn(parent, "default-intensities property has too many values");
+		return;
+	}
+
+	ret = fwnode_property_read_u32_array(fwnode, "default-intensities",
+					     intensities, len);
+	if (ret < 0) {
+		dev_warn(parent, "failed to read default-intensities property values: %d", ret);
+		return;
+	}
+
+	for (i = 0; i < len; i += 2) {
+		for (j = 0; j < mcled_cdev->num_colors; j++) {
+			if (intensities[i] == mcled_cdev->subled_info[j].color_index) {
+				mcled_cdev->subled_info[j].intensity = intensities[i + 1];
+				break;
+			}
+		}
+	}
+}
+
 int led_classdev_multicolor_register_ext(struct device *parent,
 				     struct led_classdev_mc *mcled_cdev,
 				     struct led_init_data *init_data)
@@ -134,6 +179,9 @@  int led_classdev_multicolor_register_ext(struct device *parent,
 	led_cdev = &mcled_cdev->led_cdev;
 	mcled_cdev->led_cdev.groups = led_multicolor_groups;
 
+	if (init_data && init_data->fwnode)
+		multi_load_default_intensities(parent, mcled_cdev, init_data->fwnode);
+
 	return led_classdev_register_ext(parent, led_cdev, init_data);
 }
 EXPORT_SYMBOL_GPL(led_classdev_multicolor_register_ext);