[PATCH v4 6/6] firmware: imx: sm-misc: Dump syslog info
From: Peng Fan <peng.fan@nxp.com>
Date: 2025-09-04 10:41:59
Also in:
arm-scmi, imx, lkml
Subsystem:
the rest · Maintainer:
Linus Torvalds
Add sysfs interface to read System Manager syslog info Reviewed-by: Cristian Marussi <cristian.marussi@arm.com> Signed-off-by: Peng Fan <peng.fan@nxp.com> --- drivers/firmware/imx/sm-misc.c | 232 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 232 insertions(+)
diff --git a/drivers/firmware/imx/sm-misc.c b/drivers/firmware/imx/sm-misc.c
index fc3ee12c2be878e0285183e3381c9514a63d5142..e742a2fff06b44ab7f07e9f97f723ef7ca1ff259 100644
--- a/drivers/firmware/imx/sm-misc.c
+++ b/drivers/firmware/imx/sm-misc.c@@ -3,6 +3,7 @@ * Copyright 2024 NXP */ +#include <linux/device/devres.h> #include <linux/firmware/imx/sm.h> #include <linux/module.h> #include <linux/of.h>
@@ -44,10 +45,232 @@ static int scmi_imx_misc_ctrl_notifier(struct notifier_block *nb, return 0; } +static ssize_t +wakevector_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scmi_imx_misc_syslog *syslog = dev_get_drvdata(device); + u16 size = sizeof(*syslog) / 4; + int ret; + + if (!ph) + return 0; + + ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog); + if (ret) + return ret; + + if (size * 4 < offsetofend(struct scmi_imx_misc_sys_sleep_rec, wakesource)) { + dev_err(device, "%s: returned truncated data\n", __func__); + return -EINVAL; + } + + return sysfs_emit(buf, "%u\n", syslog->syssleeprecord.wakesource); +} +static DEVICE_ATTR_RO(wakevector); + +static ssize_t +syssleepmode_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scmi_imx_misc_syslog *syslog = dev_get_drvdata(device); + u16 size = sizeof(*syslog) / 4; + int ret; + + if (!ph) + return 0; + + ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog); + if (ret) + return ret; + + if (size * 4 < offsetofend(struct scmi_imx_misc_sys_sleep_rec, syssleepmode)) { + dev_err(device, "%s: returned truncated data\n", __func__); + return -EINVAL; + } + + return sysfs_emit(buf, "%u\n", syslog->syssleeprecord.syssleepmode); +} +static DEVICE_ATTR_RO(syssleepmode); + +static ssize_t +syssleepflags_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scmi_imx_misc_syslog *syslog = dev_get_drvdata(device); + u16 size = sizeof(*syslog) / 4; + int ret; + + if (!ph) + return 0; + + ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog); + if (ret) + return ret; + + if (size * 4 < offsetofend(struct scmi_imx_misc_sys_sleep_rec, syssleepflags)) { + dev_err(device, "%s: returned truncated data\n", __func__); + return -EINVAL; + } + + return sysfs_emit(buf, "0x%08x\n", syslog->syssleeprecord.syssleepflags); +} +static DEVICE_ATTR_RO(syssleepflags); + +static ssize_t +mixpwrstat_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scmi_imx_misc_syslog *syslog = dev_get_drvdata(device); + u16 size = sizeof(*syslog) / 4; + int ret; + + if (!ph) + return 0; + + ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog); + if (ret) + return ret; + + if (size * 4 < offsetofend(struct scmi_imx_misc_sys_sleep_rec, mixpwrstat)) { + dev_err(device, "%s: returned truncated data\n", __func__); + return -EINVAL; + } + + return sysfs_emit(buf, "0x%08x\n", syslog->syssleeprecord.mixpwrstat); +} +static DEVICE_ATTR_RO(mixpwrstat); + +static ssize_t +mempwrstat_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scmi_imx_misc_syslog *syslog = dev_get_drvdata(device); + u16 size = sizeof(*syslog) / 4; + int ret; + + if (!ph) + return 0; + + ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog); + if (ret) + return ret; + + if (size * 4 < offsetofend(struct scmi_imx_misc_sys_sleep_rec, mempwrstat)) { + dev_err(device, "%s: returned truncated data\n", __func__); + return -EINVAL; + } + + return sysfs_emit(buf, "0x%08x\n", syslog->syssleeprecord.mempwrstat); +} +static DEVICE_ATTR_RO(mempwrstat); + +static ssize_t +pllpwrstat_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scmi_imx_misc_syslog *syslog = dev_get_drvdata(device); + u16 size = sizeof(*syslog) / 4; + int ret; + + if (!ph) + return 0; + + ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog); + if (ret) + return ret; + + if (size * 4 < offsetofend(struct scmi_imx_misc_sys_sleep_rec, pllpwrstat)) { + dev_err(device, "%s: returned truncated data\n", __func__); + return -EINVAL; + } + + return sysfs_emit(buf, "0x%08x\n", syslog->syssleeprecord.pllpwrstat); +} +static DEVICE_ATTR_RO(pllpwrstat); + +static ssize_t +sleepentryusec_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scmi_imx_misc_syslog *syslog = dev_get_drvdata(device); + u16 size = sizeof(*syslog) / 4; + int ret; + + if (!ph) + return 0; + + ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog); + if (ret) + return ret; + + if (size * 4 < offsetofend(struct scmi_imx_misc_sys_sleep_rec, sleepentryusec)) { + dev_err(device, "%s: returned truncated data\n", __func__); + return -EINVAL; + } + + return sysfs_emit(buf, "%u\n", syslog->syssleeprecord.sleepentryusec); +} +static DEVICE_ATTR_RO(sleepentryusec); + +static ssize_t +sleepexitusec_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scmi_imx_misc_syslog *syslog = dev_get_drvdata(device); + u16 size = sizeof(*syslog) / 4; + int ret; + + if (!ph) + return 0; + + ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog); + if (ret) + return ret; + + if (size * 4 < offsetofend(struct scmi_imx_misc_sys_sleep_rec, sleepexitusec)) { + dev_err(device, "%s: returned truncated data\n", __func__); + return -EINVAL; + } + + return sysfs_emit(buf, "%u\n", syslog->syssleeprecord.sleepexitusec); +} +static DEVICE_ATTR_RO(sleepexitusec); + +static ssize_t +sleepcnt_show(struct device *device, struct device_attribute *attr, char *buf) +{ + struct scmi_imx_misc_syslog *syslog = dev_get_drvdata(device); + u16 size = sizeof(*syslog) / 4; + int ret; + + if (!ph) + return 0; + + ret = imx_misc_ctrl_ops->misc_syslog(ph, &size, syslog); + if (ret) + return ret; + + if (size * 4 < offsetofend(struct scmi_imx_misc_sys_sleep_rec, sleepcnt)) { + dev_err(device, "%s: returned truncated data\n", __func__); + return -EINVAL; + } + + return sysfs_emit(buf, "%u\n", syslog->syssleeprecord.sleepcnt); +} +static DEVICE_ATTR_RO(sleepcnt); + +static struct attribute *sm_misc_attrs[] = { + &dev_attr_wakevector.attr, + &dev_attr_syssleepmode.attr, + &dev_attr_syssleepflags.attr, + &dev_attr_mixpwrstat.attr, + &dev_attr_mempwrstat.attr, + &dev_attr_pllpwrstat.attr, + &dev_attr_sleepentryusec.attr, + &dev_attr_sleepexitusec.attr, + &dev_attr_sleepcnt.attr, + NULL, +}; +ATTRIBUTE_GROUPS(sm_misc); + static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev) { const struct scmi_handle *handle = sdev->handle; struct device_node *np = sdev->dev.of_node; + struct scmi_imx_misc_syslog *syslog; u32 src_id, flags; int ret, i, num;
@@ -63,6 +286,12 @@ static int scmi_imx_misc_ctrl_probe(struct scmi_device *sdev) if (IS_ERR(imx_misc_ctrl_ops)) return PTR_ERR(imx_misc_ctrl_ops); + syslog = devm_kzalloc(&sdev->dev, sizeof(*syslog), GFP_KERNEL); + if (!syslog) + return -ENOMEM; + + dev_set_drvdata(&sdev->dev, syslog); + num = of_property_count_u32_elems(np, "nxp,ctrl-ids"); if (num % 2) { dev_err(&sdev->dev, "Invalid wakeup-sources\n");
@@ -108,6 +337,9 @@ static const struct scmi_device_id scmi_id_table[] = { MODULE_DEVICE_TABLE(scmi, scmi_id_table); static struct scmi_driver scmi_imx_misc_ctrl_driver = { + .driver = { + .dev_groups = sm_misc_groups, + }, .name = "scmi-imx-misc-ctrl", .probe = scmi_imx_misc_ctrl_probe, .id_table = scmi_id_table,
--
2.37.1