[PATCH v2 1/2] PM / wakeup: Add callback for wake-up change notification

From: Geert Uytterhoeven
Date: Tue Jun 19 2018 - 09:55:42 EST


Add a callback to inform a device that its wake-up setting has been
changed. This allows a device to synchronize device configuration with
an external user action.

E.g. on systems using a Rohm BD9571MWV PMIC and a toggle accessory power
switch, the system suspend/resume procedure is:
1. Configure PMIC for DDR backup mode (by software), which changes the
role of the accessory power switch from a power to a wake-up
switch,
2. Switch accessory power switch off (manually), to prepare for system
suspend,
3. Suspend system (by software),
4. Switch accessory power switch on (manually), to wake up the system.

As step 2 involves a manual operation, step 1 cannot be combined
with step 3 and performed in the PMIC's suspend callback (unlike on
systems with a momentary power switch).

Adding the new callback allows to move step 1 to the new callback, to be
performed in response to the user writing "enabled" to the PMIC's
"wakeup" virtual file in sysfs.

Signed-off-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
---
Is there a better way to handle this?

Currently step 1 is done in userspace using i2set, which is very
user-unfriendly
(https://elinux.org/R-Car/Boards/Salvator-XS#PSCI_System_Suspend).

v2:
- Improve patch description.
---
drivers/base/power/wakeup.c | 4 ++++
include/linux/pm.h | 1 +
2 files changed, 5 insertions(+)

diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 5fa1898755a34878..933560d658692fe3 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -255,6 +255,8 @@ static int device_wakeup_attach(struct device *dev, struct wakeup_source *ws)
if (dev->power.wakeirq)
device_wakeup_attach_irq(dev, dev->power.wakeirq);
spin_unlock_irq(&dev->power.lock);
+ if (dev->power.wakeup_change_notify)
+ dev->power.wakeup_change_notify(dev, true);
return 0;
}

@@ -372,6 +374,8 @@ static struct wakeup_source *device_wakeup_detach(struct device *dev)
{
struct wakeup_source *ws;

+ if (dev->power.wakeup_change_notify)
+ dev->power.wakeup_change_notify(dev, false);
spin_lock_irq(&dev->power.lock);
ws = dev->power.wakeup;
dev->power.wakeup = NULL;
diff --git a/include/linux/pm.h b/include/linux/pm.h
index e723b78d835706f2..3dec274bffffc6f8 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -599,6 +599,7 @@ struct dev_pm_info {
struct list_head entry;
struct completion completion;
struct wakeup_source *wakeup;
+ void (*wakeup_change_notify)(struct device *dev, bool enable);
bool wakeup_path:1;
bool syscore:1;
bool no_pm_callbacks:1; /* Owned by the PM core */
--
2.17.1