<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">--- a/drivers/leds/leds-iei-wt61p803-puzzle.c
+++ b/drivers/leds/leds-iei-wt61p803-puzzle.c
@@ -9,9 +9,13 @@
 #include &lt;linux/mfd/iei-wt61p803-puzzle.h&gt;
 #include &lt;linux/mod_devicetable.h&gt;
 #include &lt;linux/module.h&gt;
+#include &lt;linux/of.h&gt;
 #include &lt;linux/platform_device.h&gt;
 #include &lt;linux/property.h&gt;
 #include &lt;linux/slab.h&gt;
+#include &lt;linux/workqueue.h&gt;
+
+#define IEI_LEDS_MAX		4
 
 enum iei_wt61p803_puzzle_led_state {
 	IEI_LED_OFF = 0x30,
@@ -33,7 +37,11 @@ struct iei_wt61p803_puzzle_led {
 	struct iei_wt61p803_puzzle *mcu;
 	unsigned char response_buffer[IEI_WT61P803_PUZZLE_BUF_SIZE];
 	struct mutex lock; /* mutex to protect led_power_state */
+	struct work_struct work;
 	int led_power_state;
+	int id;
+	u8 blinking;
+	bool active_low;
 };
 
 static inline struct iei_wt61p803_puzzle_led *cdev_to_iei_wt61p803_puzzle_led
@@ -51,10 +59,18 @@ static int iei_wt61p803_puzzle_led_brigh
 	size_t reply_size;
 	int ret;
 
+	if (priv-&gt;blinking) {
+		if (brightness == LED_OFF)
+			priv-&gt;blinking = 0;
+		else
+			return 0;
+	}
+
 	led_power_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
 	led_power_cmd[1] = IEI_WT61P803_PUZZLE_CMD_LED;
-	led_power_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_POWER;
-	led_power_cmd[3] = brightness == LED_OFF ? IEI_LED_OFF : IEI_LED_ON;
+	led_power_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_SET(priv-&gt;id);
+	led_power_cmd[3] = ((brightness == LED_OFF) ^ priv-&gt;active_low) ?
+				IEI_LED_OFF : priv-&gt;blinking?priv-&gt;blinking:IEI_LED_ON;
 
 	ret = iei_wt61p803_puzzle_write_command(priv-&gt;mcu, led_power_cmd,
 						sizeof(led_power_cmd),
@@ -90,39 +106,166 @@ static enum led_brightness iei_wt61p803_
 	return led_state;
 }
 
+static void iei_wt61p803_puzzle_led_apply_blink(struct work_struct *work)
+{
+	struct iei_wt61p803_puzzle_led *priv = container_of(work, struct iei_wt61p803_puzzle_led, work);
+	unsigned char led_blink_cmd[5] = {};
+	unsigned char resp_buf[IEI_WT61P803_PUZZLE_BUF_SIZE];
+	size_t reply_size;
+
+	led_blink_cmd[0] = IEI_WT61P803_PUZZLE_CMD_HEADER_START;
+	led_blink_cmd[1] = IEI_WT61P803_PUZZLE_CMD_LED;
+	led_blink_cmd[2] = IEI_WT61P803_PUZZLE_CMD_LED_SET(priv-&gt;id);
+	led_blink_cmd[3] = priv-&gt;blinking;
+
+	iei_wt61p803_puzzle_write_command(priv-&gt;mcu, led_blink_cmd,
+					  sizeof(led_blink_cmd),
+					  resp_buf,
+					  &amp;reply_size);
+
+	return;
+}
+
+static int iei_wt61p803_puzzle_led_set_blink(struct led_classdev *cdev,
+					     unsigned long *delay_on,
+					     unsigned long *delay_off)
+{
+	struct iei_wt61p803_puzzle_led *priv = cdev_to_iei_wt61p803_puzzle_led(cdev);
+	u8 blink_mode = 0;
+	int ret = 0;
+
+	/* set defaults */
+	if (!*delay_on &amp;&amp; !*delay_off) {
+		*delay_on = 500;
+		*delay_off = 500;
+	}
+
+	/* minimum delay for soft-driven blinking is 100ms to keep load low */
+	if (*delay_on &lt; 100)
+		*delay_on = 100;
+
+	if (*delay_off &lt; 100)
+		*delay_off = 100;
+
+	/* offload blinking to hardware, if possible */
+	if (*delay_on != *delay_off) {
+		ret = -EINVAL;
+	} else if (*delay_on == 100) {
+		blink_mode = IEI_LED_BLINK_5HZ;
+		*delay_on = 100;
+		*delay_off = 100;
+	} else if (*delay_on &lt;= 500) {
+		blink_mode = IEI_LED_BLINK_1HZ;
+		*delay_on = 500;
+		*delay_off = 500;
+	} else {
+		ret = -EINVAL;
+	}
+
+	mutex_lock(&amp;priv-&gt;lock);
+	priv-&gt;blinking = blink_mode;
+	mutex_unlock(&amp;priv-&gt;lock);
+
+	if (blink_mode)
+		schedule_work(&amp;priv-&gt;work);
+
+	return ret;
+}
+
+
+static int iei_wt61p803_puzzle_led_set_dt_default(struct led_classdev *cdev,
+				     struct device_node *np)
+{
+	const char *state;
+	int ret = 0;
+
+	state = of_get_property(np, "default-state", NULL);
+	if (state) {
+		if (!strcmp(state, "on")) {
+			ret =
+			iei_wt61p803_puzzle_led_brightness_set_blocking(
+				cdev, cdev-&gt;max_brightness);
+		} else  {
+			ret = iei_wt61p803_puzzle_led_brightness_set_blocking(
+				cdev, LED_OFF);
+		}
+	}
+
+	return ret;
+}
+
 static int iei_wt61p803_puzzle_led_probe(struct platform_device *pdev)
 {
 	struct device *dev = &amp;pdev-&gt;dev;
+	struct device_node *np = dev_of_node(dev);
+	struct device_node *child;
 	struct iei_wt61p803_puzzle *mcu = dev_get_drvdata(dev-&gt;parent);
 	struct iei_wt61p803_puzzle_led *priv;
-	struct led_init_data init_data = {};
-	struct fwnode_handle *child;
 	int ret;
+	u32 reg;
 
-	if (device_get_child_node_count(dev) != 1)
+	if (device_get_child_node_count(dev) &gt; IEI_LEDS_MAX)
 		return -EINVAL;
 
-	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
-
-	priv-&gt;mcu = mcu;
-	priv-&gt;led_power_state = 1;
-	mutex_init(&amp;priv-&gt;lock);
-	dev_set_drvdata(dev, priv);
-
-	child = device_get_next_child_node(dev, NULL);
-	init_data.fwnode = child;
-
-	priv-&gt;cdev.brightness_set_blocking = iei_wt61p803_puzzle_led_brightness_set_blocking;
-	priv-&gt;cdev.brightness_get = iei_wt61p803_puzzle_led_brightness_get;
-	priv-&gt;cdev.max_brightness = 1;
+	for_each_available_child_of_node(np, child) {
+		struct led_init_data init_data = {};
 
-	ret = devm_led_classdev_register_ext(dev, &amp;priv-&gt;cdev, &amp;init_data);
-	if (ret)
-		dev_err(dev, "Could not register LED\n");
+		ret = of_property_read_u32(child, "reg", &amp;reg);
+		if (ret) {
+			dev_err(dev, "Failed to read led 'reg' property\n");
+			goto put_child_node;
+		}
+
+		if (reg &gt; IEI_LEDS_MAX) {
+			dev_err(dev, "Invalid led reg %u\n", reg);
+			ret = -EINVAL;
+			goto put_child_node;
+		}
+
+		priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+		if (!priv) {
+			ret = -ENOMEM;
+			goto put_child_node;
+		}
+
+		mutex_init(&amp;priv-&gt;lock);
+
+		dev_set_drvdata(dev, priv);
+
+		if (of_property_read_bool(child, "active-low"))
+			priv-&gt;active_low = true;
+
+		priv-&gt;mcu = mcu;
+		priv-&gt;id = reg;
+		priv-&gt;led_power_state = 1;
+		priv-&gt;blinking = 0;
+		init_data.fwnode = of_fwnode_handle(child);
+
+		priv-&gt;cdev.brightness_set_blocking = iei_wt61p803_puzzle_led_brightness_set_blocking;
+		priv-&gt;cdev.brightness_get = iei_wt61p803_puzzle_led_brightness_get;
+		priv-&gt;cdev.blink_set = iei_wt61p803_puzzle_led_set_blink;
+
+		priv-&gt;cdev.max_brightness = 1;
+
+		INIT_WORK(&amp;priv-&gt;work, iei_wt61p803_puzzle_led_apply_blink);
+
+		ret = iei_wt61p803_puzzle_led_set_dt_default(&amp;priv-&gt;cdev, child);
+		if (ret) {
+			dev_err(dev, "Could apply default from DT\n");
+			goto put_child_node;
+		}
+
+		ret = devm_led_classdev_register_ext(dev, &amp;priv-&gt;cdev, &amp;init_data);
+		if (ret) {
+			dev_err(dev, "Could not register LED\n");
+			goto put_child_node;
+		}
+	}
+
+	return ret;
 
-	fwnode_handle_put(child);
+put_child_node:
+	of_node_put(child);
 	return ret;
 }
 
--- a/include/linux/mfd/iei-wt61p803-puzzle.h
+++ b/include/linux/mfd/iei-wt61p803-puzzle.h
@@ -36,7 +36,7 @@
 #define IEI_WT61P803_PUZZLE_CMD_FUNCTION_OTHER_POWER_LOSS 0x41 /* A */
 
 #define IEI_WT61P803_PUZZLE_CMD_LED			0x52 /* R */
-#define IEI_WT61P803_PUZZLE_CMD_LED_POWER		0x31 /* 1 */
+#define IEI_WT61P803_PUZZLE_CMD_LED_SET(n)		(0x30 | (n))
 
 #define IEI_WT61P803_PUZZLE_CMD_TEMP			0x54 /* T */
 #define IEI_WT61P803_PUZZLE_CMD_TEMP_ALL		0x41 /* A */
--- a/drivers/mfd/iei-wt61p803-puzzle.c
+++ b/drivers/mfd/iei-wt61p803-puzzle.c
@@ -176,6 +176,9 @@ static int iei_wt61p803_puzzle_recv_buf(
 	struct iei_wt61p803_puzzle *mcu = serdev_device_get_drvdata(serdev);
 	int ret;
 
+	print_hex_dump_debug("puzzle-mcu rx: ", DUMP_PREFIX_NONE,
+			     16, 1, data, size, false);
+
 	ret = iei_wt61p803_puzzle_process_resp(mcu, data, size);
 	/* Return the number of processed bytes if function returns error,
 	 * discard the remaining incoming data, since the frame this data
@@ -246,6 +249,9 @@ int iei_wt61p803_puzzle_write_command(st
 
 	cmd[size - 1] = iei_wt61p803_puzzle_checksum(cmd, size - 1);
 
+	print_hex_dump_debug("puzzle-mcu tx: ", DUMP_PREFIX_NONE,
+			     16, 1, cmd, size, false);
+
 	/* Initialize reply struct */
 	reinit_completion(&amp;mcu-&gt;reply-&gt;received);
 	mcu-&gt;reply-&gt;size = 0;
</pre></body></html>