leds: rgb: wago-m4-led-wrapper: add sysfs cmd passthrough
Add a `wago_led_cmd` sysfs attribute to the leds-m4 platform device that allows raw ASCII commands to be forwarded directly to the M4 co-processor via RPMsg. This is useful for testing and debugging M4 LED firmware without going through the LED class abstraction. The attribute strips trailing whitespace and re-appends a single newline before forwarding, matching the protocol expected by the Zephyr application. A read of the attribute reports the RPMsg channel state (online/offline). The sysfs group is created during probe and removed on teardown. Signed-off-by: Heinrich Toews <ht@twx-software.de>
This commit is contained in:
@@ -50,6 +50,10 @@
|
||||
* echo "0 128 128" > /sys/class/leds/m4-led3/multi_intensity
|
||||
* echo 255 > /sys/class/leds/m4-led3/brightness
|
||||
*
|
||||
* # Send raw commands directly to the M4 for testing:
|
||||
* echo "CMD-IDL" > /sys/bus/platform/devices/leds-m4/wago_led_cmd
|
||||
* echo "CMD-CYC-50-128" > /sys/bus/platform/devices/leds-m4/wago_led_cmd
|
||||
*
|
||||
* Author: WAGO GmbH & Co. KG
|
||||
*/
|
||||
|
||||
@@ -202,16 +206,71 @@ static int wago_send_cmd(struct wago_m4_led_priv *priv, const char *cmd)
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
* LED multiclass brightness_set callback (non-blocking, fire-and-forget)
|
||||
* Sysfs attribute: wago_led_cmd
|
||||
*
|
||||
* Called by the LED core whenever userspace writes to:
|
||||
* /sys/class/leds/m4-led<N>/brightness (master)
|
||||
* /sys/class/leds/m4-led<N>/multi_intensity (R G B)
|
||||
* Allows sending raw ASCII commands to the M4 directly from the shell.
|
||||
* The command string is forwarded as-is via RPMsg (fire-and-forget).
|
||||
*
|
||||
* Registered as brightness_set (not brightness_set_blocking) because we no
|
||||
* longer wait for an ACK. The LED core may call this from any context.
|
||||
* Usage:
|
||||
* echo "CMD-IDL" > /sys/bus/platform/devices/leds-m4/wago_led_cmd
|
||||
* echo "CMD-CYC-50-128" > /sys/bus/platform/devices/leds-m4/wago_led_cmd
|
||||
* echo "CMD-BLK-0-R-200-255" > /sys/bus/platform/devices/leds-m4/wago_led_cmd
|
||||
* echo "CMD-FAD-0-G-20-5" > /sys/bus/platform/devices/leds-m4/wago_led_cmd
|
||||
* echo "CMD-WLED-3-B-128" > /sys/bus/platform/devices/leds-m4/wago_led_cmd
|
||||
* ---------------------------------------------------------------------- */
|
||||
|
||||
static ssize_t wago_led_cmd_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct wago_m4_led_priv *priv = dev_get_drvdata(dev);
|
||||
char cmd[WAGO_CMD_MAX_LEN];
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
/* Strip trailing newline added by echo and copy into local buffer */
|
||||
len = min(count, sizeof(cmd) - 2);
|
||||
memcpy(cmd, buf, len);
|
||||
|
||||
/* Remove trailing whitespace / newline */
|
||||
while (len > 0 && (cmd[len - 1] == '\n' ||
|
||||
cmd[len - 1] == '\r' ||
|
||||
cmd[len - 1] == ' '))
|
||||
len--;
|
||||
|
||||
/* Re-add a single newline — the Zephyr app expects it */
|
||||
cmd[len++] = '\n';
|
||||
cmd[len] = '\0';
|
||||
|
||||
mutex_lock(&priv->send_lock);
|
||||
ret = wago_send_cmd(priv, cmd);
|
||||
mutex_unlock(&priv->send_lock);
|
||||
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
static ssize_t wago_led_cmd_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct wago_m4_led_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
return sysfs_emit(buf, "%s\n",
|
||||
priv->rpdev ? "online" : "offline");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(wago_led_cmd);
|
||||
|
||||
static struct attribute *wago_led_attrs[] = {
|
||||
&dev_attr_wago_led_cmd.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group wago_led_attr_group = {
|
||||
.attrs = wago_led_attrs,
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void wago_led_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness brightness)
|
||||
{
|
||||
@@ -549,6 +608,14 @@ static int wago_m4_led_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &wago_led_attr_group);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to create sysfs group: %d\n", ret);
|
||||
unregister_rpmsg_driver(&wago_rpmsg_driver);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule the boot work. The first attempt fires after
|
||||
* WAGO_BOOT_INITIAL_DELAY_MS, giving the rootfs a head start.
|
||||
@@ -572,6 +639,7 @@ static int wago_m4_led_remove(struct platform_device *pdev)
|
||||
/* Cancel any pending boot retry before tearing down */
|
||||
cancel_delayed_work_sync(&priv->boot_work);
|
||||
|
||||
sysfs_remove_group(&pdev->dev.kobj, &wago_led_attr_group);
|
||||
unregister_rpmsg_driver(&wago_rpmsg_driver);
|
||||
wago_rproc_stop(priv);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user