Commit dd22cc90 authored by Peng Fan's avatar Peng Fan Committed by Sudeep Holla

firmware: arm_scmi: Add support for system suspend in power control driver

SCMI supports system suspend notification from the platform. The suuport
for the same can be added in SCMI power control driver. However, currently
there is no way to pass suspend level to pm_suspend() call from this
driver, so use suspend-to-ram(S2R) will be used.

Couple of things to note:
1) The userspace can still configure whatever default behaviour expected
   for S2R.
2) The userspace needs to keep the wakeup source enabled, otherwise the
   system may never resume back.
Signed-off-by: default avatarPeng Fan <peng.fan@nxp.com>
Reviewed-by: default avatarCristian Marussi <cristian.marussi@arm.com>
Link: https://lore.kernel.org/r/20240428075105.2187837-1-peng.fan@oss.nxp.comSigned-off-by: default avatarSudeep Holla <sudeep.holla@arm.com>
parent 08070351
......@@ -50,6 +50,7 @@
#include <linux/reboot.h>
#include <linux/scmi_protocol.h>
#include <linux/slab.h>
#include <linux/suspend.h>
#include <linux/time64.h>
#include <linux/timer.h>
#include <linux/types.h>
......@@ -78,6 +79,7 @@ enum scmi_syspower_state {
* @reboot_nb: A notifier_block optionally used to track reboot progress
* @forceful_work: A worker used to trigger a forceful transition once a
* graceful has timed out.
* @suspend_work: A worker used to trigger system suspend
*/
struct scmi_syspower_conf {
struct device *dev;
......@@ -90,6 +92,7 @@ struct scmi_syspower_conf {
struct notifier_block reboot_nb;
struct delayed_work forceful_work;
struct work_struct suspend_work;
};
#define userspace_nb_to_sconf(x) \
......@@ -249,6 +252,9 @@ static void scmi_request_graceful_transition(struct scmi_syspower_conf *sc,
case SCMI_SYSTEM_WARMRESET:
orderly_reboot();
break;
case SCMI_SYSTEM_SUSPEND:
schedule_work(&sc->suspend_work);
break;
default:
break;
}
......@@ -277,7 +283,8 @@ static int scmi_userspace_notifier(struct notifier_block *nb,
struct scmi_system_power_state_notifier_report *er = data;
struct scmi_syspower_conf *sc = userspace_nb_to_sconf(nb);
if (er->system_state >= SCMI_SYSTEM_POWERUP) {
if (er->system_state >= SCMI_SYSTEM_MAX ||
er->system_state == SCMI_SYSTEM_POWERUP) {
dev_err(sc->dev, "Ignoring unsupported system_state: 0x%X\n",
er->system_state);
return NOTIFY_DONE;
......@@ -315,6 +322,16 @@ static int scmi_userspace_notifier(struct notifier_block *nb,
return NOTIFY_OK;
}
static void scmi_suspend_work_func(struct work_struct *work)
{
struct scmi_syspower_conf *sc =
container_of(work, struct scmi_syspower_conf, suspend_work);
pm_suspend(PM_SUSPEND_MEM);
sc->state = SCMI_SYSPOWER_IDLE;
}
static int scmi_syspower_probe(struct scmi_device *sdev)
{
int ret;
......@@ -338,6 +355,8 @@ static int scmi_syspower_probe(struct scmi_device *sdev)
sc->userspace_nb.notifier_call = &scmi_userspace_notifier;
sc->dev = &sdev->dev;
INIT_WORK(&sc->suspend_work, scmi_suspend_work_func);
return handle->notify_ops->devm_event_notifier_register(sdev,
SCMI_PROTOCOL_SYSTEM,
SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment