From nobody Sun Oct 5 12:52:21 2025 Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 86403212D83; Mon, 4 Aug 2025 11:50:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.11.138.130 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754308214; cv=none; b=RKqoVXc1MhMvtiK4lPpjkBrfyyv9wJf8IdLWn5X+jh8EZgKrVNRXwDFLs4wcfvCWcTJriSRmzWe5V3yZPbwIjv6trJ/5uXUj3e3WrQeRyWkxfo0WS0A5OCIdFEMcPDvyYZS7LJWKfB5pYsKNvmcRRpPk+LITp/sj21AHZR+igmE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754308214; c=relaxed/simple; bh=PXGjcA5GCbkRBqObq0KqFnQxUF7xeheMXf2IQzSt1Bo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=kGHzaqf28E01o784k+JgzNWh47mdZhHMEOutDNI/RR6VNHJzglEckevAZEfLkN+TUEJNDntbdymrznubPzpu4dSqKKpf67+R4t90VTfKclE9JxENCNMa0o0rOT9EapCg6tWRdJ/0t2bM1J1Vn3glp8Vq0YFnPkuB8XvEPosAG+M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sntech.de; spf=pass smtp.mailfrom=sntech.de; dkim=pass (2048-bit key) header.d=sntech.de header.i=@sntech.de header.b=ZOoXfSfO; arc=none smtp.client-ip=185.11.138.130 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sntech.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=sntech.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=sntech.de header.i=@sntech.de header.b="ZOoXfSfO" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sntech.de; s=gloria202408; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-Type; bh=8iBcZ3OtVhbVYqsfwwCcpWfdIFjsudrQi0+7eI/zvFE=; b=ZOoXfSfOBIbUI8bADIvJ1GwBMI T7yuIE5bTOCJ0UPHgHx37HmieUjUPvND5O+6dq8QJte0gXzhavQGdLMrCPJsOUA8OxZqGpL11O2iO tUkhDIfq72H/GmlzSei41v3sFPmL6WZ99JgXqWTCHM8ulZVGuKurzgd18RP95x+lrH3A3oneklPpF hD2k3QGLhl1A/aUnhQmBPeG6qsNQiCBpXyHMwn6NXAwP8T1zbOkbHmzi3dRL1uEkLqtBA93h0Nr0S 9ckKFho9/VsVuJi0HU4lm0BgLg2YhWf595yeVId4kh5YQfmH18Xrk4ZUJ1qPMpZ97uOTWV+benfOp etipw8yw==; Received: from [194.95.143.137] (helo=phil.dip.tu-dresden.de) by gloria.sntech.de with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uithc-0003cE-9R; Mon, 04 Aug 2025 13:50:04 +0200 From: Heiko Stuebner To: lee@kernel.org, pavel@kernel.org Cc: heiko@sntech.de, linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 1/2] leds: qnap-mcu: fix state numbering for usb LED Date: Mon, 4 Aug 2025 13:49:48 +0200 Message-ID: <20250804114949.3127417-2-heiko@sntech.de> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250804114949.3127417-1-heiko@sntech.de> References: <20250804114949.3127417-1-heiko@sntech.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The "@Cx" commands span a number of different functions, from the status and usb LEDs to the buzzer and power button. So change the usb-LED enum to start at 0 and adapt the offset accordingly to not suggest @CD would relate to the usb-LED - while in fact "@CD" is a state of the status LED. Signed-off-by: Heiko Stuebner --- drivers/leds/leds-qnap-mcu.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/leds/leds-qnap-mcu.c b/drivers/leds/leds-qnap-mcu.c index 4e4709456261..fe055c5511b8 100644 --- a/drivers/leds/leds-qnap-mcu.c +++ b/drivers/leds/leds-qnap-mcu.c @@ -104,9 +104,9 @@ static int qnap_mcu_register_err_led(struct device *dev= , struct qnap_mcu *mcu, i } =20 enum qnap_mcu_usb_led_mode { - QNAP_MCU_USB_LED_ON =3D 1, - QNAP_MCU_USB_LED_OFF =3D 3, - QNAP_MCU_USB_LED_BLINK =3D 2, + QNAP_MCU_USB_LED_ON =3D 0, + QNAP_MCU_USB_LED_OFF =3D 2, + QNAP_MCU_USB_LED_BLINK =3D 1, }; =20 struct qnap_mcu_usb_led { @@ -137,7 +137,7 @@ static int qnap_mcu_usb_led_set(struct led_classdev *le= d_cdev, * Byte 3 is shared between the usb led target on/off/blink * and also the buzzer control (in the input driver) */ - cmd[2] =3D 'D' + usb_led->mode; + cmd[2] =3D 'E' + usb_led->mode; =20 return qnap_mcu_exec_with_ack(usb_led->mcu, cmd, sizeof(cmd)); } @@ -161,7 +161,7 @@ static int qnap_mcu_usb_led_blink_set(struct led_classd= ev *led_cdev, * Byte 3 is shared between the USB LED target on/off/blink * and also the buzzer control (in the input driver) */ - cmd[2] =3D 'D' + usb_led->mode; + cmd[2] =3D 'E' + usb_led->mode; =20 return qnap_mcu_exec_with_ack(usb_led->mcu, cmd, sizeof(cmd)); } --=20 2.47.2 From nobody Sun Oct 5 12:52:21 2025 Received: from gloria.sntech.de (gloria.sntech.de [185.11.138.130]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 91F9923817D; Mon, 4 Aug 2025 11:50:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.11.138.130 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754308214; cv=none; b=gcg7wbnf54G7XueiMi3P+UPZBJWZU21PzFulqb0ysfDj6kOOimmCXy98XaX0NeliqhB/Lt+EB4QR5nd6AOLguqWo3ra4QP4hh8WftjzQbB6jsOajFH6g6qSJCAoxBD1gueAhhJCg/fa8oFuCLyKBvJB4033Vnxi3wTb2l6xoEz4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754308214; c=relaxed/simple; bh=mUcDTxTcvH9vf/PGlrGUaQ2EdvA/71aUCNo6FcsesZ8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ouCwHZ/LTd33gA/1f5Wd0I8Bvq3daP1qgR884jWr5nx3qfQ3fkoJ69wqBdjP8bhT8dvBuDkIW8K8zrrIDpjkWfethy748xdJx8m7+BaA/R7Ges6pTCP+61Fpq32Ao8N/YQw8WP4Njn/nIeni+wrK4WphvaEqHZKCsWPa94wqsnk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sntech.de; spf=pass smtp.mailfrom=sntech.de; dkim=pass (2048-bit key) header.d=sntech.de header.i=@sntech.de header.b=UCDAcv47; arc=none smtp.client-ip=185.11.138.130 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=sntech.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=sntech.de Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=sntech.de header.i=@sntech.de header.b="UCDAcv47" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sntech.de; s=gloria202408; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-Type; bh=rUHH4Nk6xIhgeCZagXp4wb88amVQtbbOEVNBe86h1q4=; b=UCDAcv47ElhvhOYzJYfkAZWM+F YPPrJWmsEyFAbCfXQzdqLD41mo0cXvBjPakTz0yQcTRMXKboenSpLbgwvzO2DtiEkVj2UQuXwbVBw /40rHbhKNQEnd9v9k25tHsUDh/npr8zpadqY5C0PlS4Hv8rf1+eb8mcGwA7eRsYn8e1r4058/5jJv qivh8y7/GYdxwUFqyT7re5FyNZlbyU+3txuStwh0LNWRYL3X0YEJlzszYVkgpbILVRitB7L1wgk6q JqMcuSAnmPpFcOrYznPP18SwAV3oHZtLkMaRcs//tnSPkqMbOpYrKvQJcDle/anUldUf2Bd/aqian FwZfNB2g==; Received: from [194.95.143.137] (helo=phil.dip.tu-dresden.de) by gloria.sntech.de with esmtpsa (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1uithc-0003cE-F8; Mon, 04 Aug 2025 13:50:04 +0200 From: Heiko Stuebner To: lee@kernel.org, pavel@kernel.org Cc: heiko@sntech.de, linux-leds@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v2 2/2] leds: qnap-mcu: add support for the red and green status LEDs Date: Mon, 4 Aug 2025 13:49:49 +0200 Message-ID: <20250804114949.3127417-3-heiko@sntech.de> X-Mailer: git-send-email 2.47.2 In-Reply-To: <20250804114949.3127417-1-heiko@sntech.de> References: <20250804114949.3127417-1-heiko@sntech.de> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" There is one more set of two LEDs on the qnap devices to indicate status. One LED is green, the other is red and while they occupy the same space on the front panel, they cannot be enabled at the same time. But they can interact via blink functions, the MCU can flash them alternately, going red -> green -> red -> ... either in 500ms or 1s intervals. They can of course also blink individually. Add specific LED functions for them and register them on probe. Signed-off-by: Heiko Stuebner --- drivers/leds/leds-qnap-mcu.c | 165 +++++++++++++++++++++++++++++++++++ 1 file changed, 165 insertions(+) diff --git a/drivers/leds/leds-qnap-mcu.c b/drivers/leds/leds-qnap-mcu.c index fe055c5511b8..fe1bec584f53 100644 --- a/drivers/leds/leds-qnap-mcu.c +++ b/drivers/leds/leds-qnap-mcu.c @@ -190,6 +190,166 @@ static int qnap_mcu_register_usb_led(struct device *d= ev, struct qnap_mcu *mcu) return qnap_mcu_usb_led_set(&usb_led->cdev, 0); } =20 +enum qnap_mcu_status_led_mode { + QNAP_MCU_STATUS_LED_OFF =3D 0, + QNAP_MCU_STATUS_LED_ON =3D 1, + QNAP_MCU_STATUS_LED_BLINK_FAST =3D 2, /* 500ms / 500ms */ + QNAP_MCU_STATUS_LED_BLINK_SLOW =3D 3, /* 1s / 1s */ +}; + +struct qnap_mcu_status_led { + struct led_classdev cdev; + struct qnap_mcu_status_led *red; + u8 mode; +}; + +struct qnap_mcu_status { + struct qnap_mcu *mcu; + struct qnap_mcu_status_led red; + struct qnap_mcu_status_led green; +}; + +static inline struct qnap_mcu_status_led *cdev_to_qnap_mcu_status_led(stru= ct led_classdev *led_cdev) +{ + return container_of(led_cdev, struct qnap_mcu_status_led, cdev); +} + +static inline struct qnap_mcu_status *statusled_to_qnap_mcu_status(struct = qnap_mcu_status_led *led) +{ + return container_of(led->red, struct qnap_mcu_status, red); +} + +static u8 qnap_mcu_status_led_encode(struct qnap_mcu_status *status) +{ + if (status->red.mode =3D=3D QNAP_MCU_STATUS_LED_OFF) { + switch (status->green.mode) { + case QNAP_MCU_STATUS_LED_OFF: + return '9'; + case QNAP_MCU_STATUS_LED_ON: + return '6'; + case QNAP_MCU_STATUS_LED_BLINK_FAST: + return '5'; + case QNAP_MCU_STATUS_LED_BLINK_SLOW: + return 'A'; + } + } else if (status->green.mode =3D=3D QNAP_MCU_STATUS_LED_OFF) { + switch (status->red.mode) { + case QNAP_MCU_STATUS_LED_OFF: + return '9'; + case QNAP_MCU_STATUS_LED_ON: + return '7'; + case QNAP_MCU_STATUS_LED_BLINK_FAST: + return '4'; + case QNAP_MCU_STATUS_LED_BLINK_SLOW: + return 'B'; + } + } else if (status->green.mode =3D=3D QNAP_MCU_STATUS_LED_ON && + status->red.mode =3D=3D QNAP_MCU_STATUS_LED_ON) { + return 'D'; + } else if (status->green.mode =3D=3D QNAP_MCU_STATUS_LED_BLINK_SLOW && + status->red.mode =3D=3D QNAP_MCU_STATUS_LED_BLINK_SLOW) { + return 'C'; + } + + /* + * Here both LEDs are on in some fashion, either both blinking fast, + * or in different speeds, so default to fast blinking for both. + */ + return '8'; +} + +static int qnap_mcu_status_led_update(struct qnap_mcu *mcu, + struct qnap_mcu_status *status) +{ + u8 cmd[] =3D { '@', 'C', 0 }; + + cmd[2] =3D qnap_mcu_status_led_encode(status); + + return qnap_mcu_exec_with_ack(mcu, cmd, sizeof(cmd)); +} + +static int qnap_mcu_status_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct qnap_mcu_status_led *status_led =3D cdev_to_qnap_mcu_status_led(le= d_cdev); + struct qnap_mcu_status *base =3D statusled_to_qnap_mcu_status(status_led); + + /* Don't disturb a possible set blink-mode if LED stays on */ + if (brightness !=3D 0 && status_led->mode >=3D QNAP_MCU_STATUS_LED_BLINK_= FAST) + return 0; + + status_led->mode =3D brightness ? QNAP_MCU_STATUS_LED_ON : + QNAP_MCU_STATUS_LED_OFF; + + return qnap_mcu_status_led_update(base->mcu, base); +} + +static int qnap_mcu_status_led_blink_set(struct led_classdev *led_cdev, + unsigned long *delay_on, + unsigned long *delay_off) +{ + struct qnap_mcu_status_led *status_led =3D cdev_to_qnap_mcu_status_led(le= d_cdev); + struct qnap_mcu_status *base =3D statusled_to_qnap_mcu_status(status_led); + + if (status_led->mode =3D=3D QNAP_MCU_STATUS_LED_OFF) + return 0; + + if (*delay_on <=3D 500) { + *delay_on =3D 500; + *delay_off =3D 500; + status_led->mode =3D QNAP_MCU_STATUS_LED_BLINK_FAST; + } else { + *delay_on =3D 1000; + *delay_off =3D 1000; + status_led->mode =3D QNAP_MCU_STATUS_LED_BLINK_SLOW; + } + + return qnap_mcu_status_led_update(base->mcu, base); +} + +static int qnap_mcu_register_status_leds(struct device *dev, struct qnap_m= cu *mcu) +{ + struct qnap_mcu_status *status; + int ret; + + status =3D devm_kzalloc(dev, sizeof(*status), GFP_KERNEL); + if (!status) + return -ENOMEM; + + status->mcu =3D mcu; + + /* + * point to the red led, so that statusled_to_qnap_mcu_status + * can resolve the main status struct containing both leds + */ + status->red.red =3D &status->red; + status->green.red =3D &status->red; + + status->red.mode =3D QNAP_MCU_STATUS_LED_OFF; + status->red.cdev.name =3D "red:status"; + status->red.cdev.brightness_set_blocking =3D qnap_mcu_status_led_set; + status->red.cdev.blink_set =3D qnap_mcu_status_led_blink_set; + status->red.cdev.brightness =3D 0; + status->red.cdev.max_brightness =3D 1; + + status->green.mode =3D QNAP_MCU_STATUS_LED_OFF; + status->green.cdev.name =3D "green:status"; + status->green.cdev.brightness_set_blocking =3D qnap_mcu_status_led_set; + status->green.cdev.blink_set =3D qnap_mcu_status_led_blink_set; + status->green.cdev.brightness =3D 0; + status->green.cdev.max_brightness =3D 1; + + ret =3D devm_led_classdev_register(dev, &status->red.cdev); + if (ret) + return ret; + + ret =3D devm_led_classdev_register(dev, &status->green.cdev); + if (ret) + return ret; + + return qnap_mcu_status_led_update(status->mcu, status); +} + static int qnap_mcu_leds_probe(struct platform_device *pdev) { struct qnap_mcu *mcu =3D dev_get_drvdata(pdev->dev.parent); @@ -210,6 +370,11 @@ static int qnap_mcu_leds_probe(struct platform_device = *pdev) "failed to register USB LED\n"); } =20 + ret =3D qnap_mcu_register_status_leds(&pdev->dev, mcu); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to register status LEDs\n"); + return 0; } =20 --=20 2.47.2