@@ -92,4 +92,8 @@ static inline void i8042_platform_exit(void)
#endif
}
+static inline void i8042_platform_suspend(struct device *dev, bool may_wakeup)
+{
+}
+
#endif /* _I8042_IO_H */
@@ -73,4 +73,8 @@ static inline void i8042_platform_exit(void)
#endif
}
+static inline void i8042_platform_suspend(struct device *dev, bool may_wakeup)
+{
+}
+
#endif /* _I8042_IP22_H */
@@ -66,4 +66,8 @@ static inline void i8042_platform_exit(void)
#endif
}
+static inline void i8042_platform_suspend(struct device *dev, bool may_wakeup)
+{
+}
+
#endif /* _I8042_JAZZ_H */
@@ -52,6 +52,10 @@ static inline void i8042_platform_exit(void)
{
}
+static inline void i8042_platform_suspend(struct device *dev, bool may_wakeup)
+{
+}
+
#else
#include "i8042-io.h"
@@ -72,4 +72,8 @@ static inline void i8042_platform_exit(void)
}
+static inline void i8042_platform_suspend(struct device *dev, bool may_wakeup)
+{
+}
+
#endif /* _I8042_SNIRM_H */
@@ -154,4 +154,8 @@ static inline void i8042_platform_exit(void)
}
#endif /* !CONFIG_PCI */
+static inline void i8042_platform_suspend(struct device *dev, bool may_wakeup)
+{
+}
+
#endif /* _I8042_SPARCIO_H */
@@ -875,6 +875,10 @@ static inline int i8042_pnp_init(void) { return 0; }
static inline void i8042_pnp_exit(void) { }
#endif
+static inline void i8042_platform_suspend(struct device *dev, bool may_wakeup)
+{
+}
+
static int __init i8042_platform_init(void)
{
int retval;
@@ -79,6 +79,10 @@ module_param_named(nopnp, i8042_nopnp, bool, 0);
MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
#endif
+static bool i8042_enable_wakeup;
+module_param_named(enable_wakeup, i8042_enable_wakeup, bool, 0);
+MODULE_PARM_DESC(enable_wakeup, "Enable i8042 as wakeup-capable device");
+
#define DEBUG
#ifdef DEBUG
static bool i8042_debug;
@@ -1081,10 +1085,17 @@ static void i8042_dritek_enable(void)
* before suspending.
*/
-static int i8042_controller_resume(bool force_reset)
+static int i8042_controller_resume(bool force_reset, bool soft_resume)
{
int error;
+ /*
+ * If device is selected as a wakeup source, it was not powered down
+ * or reset during suspend, so we have very little to do.
+ */
+ if (soft_resume)
+ goto soft;
+
error = i8042_controller_check();
if (error)
return error;
@@ -1128,6 +1139,7 @@ static int i8042_controller_resume(bool force_reset)
if (i8042_ports[I8042_KBD_PORT_NO].serio)
i8042_enable_kbd_port();
+soft:
i8042_interrupt(0, NULL);
return 0;
@@ -1145,6 +1157,20 @@ static int i8042_pm_reset(struct device *dev)
return 0;
}
+static int i8042_pm_suspend(struct device *dev)
+{
+ i8042_platform_suspend(dev, device_may_wakeup(dev));
+
+ /*
+ * If device is selected as a wakeup source, don't powerdown or reset
+ * during suspend.
+ */
+ if (device_may_wakeup(dev))
+ return 0;
+
+ return i8042_pm_reset(dev);
+}
+
static int i8042_pm_resume(struct device *dev)
{
/*
@@ -1152,7 +1178,7 @@ static int i8042_pm_resume(struct device *dev)
* to bring it in a sane state. (In case of S2D we expect
* BIOS to reset the controller for us.)
*/
- return i8042_controller_resume(true);
+ return i8042_controller_resume(true, device_may_wakeup(dev));
}
static int i8042_pm_thaw(struct device *dev)
@@ -1164,11 +1190,11 @@ static int i8042_pm_thaw(struct device *dev)
static int i8042_pm_restore(struct device *dev)
{
- return i8042_controller_resume(false);
+ return i8042_controller_resume(false, false);
}
static const struct dev_pm_ops i8042_pm_ops = {
- .suspend = i8042_pm_reset,
+ .suspend = i8042_pm_suspend,
.resume = i8042_pm_resume,
.thaw = i8042_pm_thaw,
.poweroff = i8042_pm_reset,
@@ -1402,6 +1428,9 @@ static int __init i8042_probe(struct platform_device *dev)
i8042_dritek_enable();
#endif
+ if (i8042_enable_wakeup)
+ device_set_wakeup_capable(&dev->dev, true);
+
if (!i8042_noaux) {
error = i8042_setup_aux();
if (error && error != -ENODEV && error != -EBUSY)
@@ -928,7 +928,7 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env)
#endif /* CONFIG_HOTPLUG */
#ifdef CONFIG_PM
-static int serio_suspend(struct device *dev)
+static int serio_poweroff(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
@@ -937,7 +937,17 @@ static int serio_suspend(struct device *dev)
return 0;
}
-static int serio_resume(struct device *dev)
+static int serio_suspend(struct device *dev)
+{
+ /* If parent controller is configured as a wakeup source, don't
+ * power off. */
+ if (device_may_wakeup(dev->parent))
+ return 0;
+
+ return serio_poweroff(dev);
+}
+
+static int serio_restore(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
@@ -950,11 +960,21 @@ static int serio_resume(struct device *dev)
return 0;
}
+static int serio_resume(struct device *dev)
+{
+ /* If parent controller is configured as a wakeup source, we didn't
+ * power off during suspend, and hence have nothing to do. */
+ if (device_may_wakeup(dev->parent))
+ return 0;
+
+ return serio_restore(dev);
+}
+
static const struct dev_pm_ops serio_pm_ops = {
.suspend = serio_suspend,
.resume = serio_resume,
- .poweroff = serio_suspend,
- .restore = serio_resume,
+ .poweroff = serio_poweroff,
+ .restore = serio_restore,
};
#endif /* CONFIG_PM */