From e7dff89d771365d2d96e7584a633e196448fefcf Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Fri, 20 Nov 2015 10:51:00 +0000 Subject: mfd: as3722: Handle interrupts on suspend commit 35deff7eb212b661b32177b6043f674fde6314d7 upstream. The as3722 device is registered as an irqchip and the as3722-rtc interrupt is one of it's interrupt sources. When using the as3722-rtc as a wake-up device from suspend, the following is seen: PM: Syncing filesystems ... done. Freezing user space processes ... (elapsed 0.001 seconds) done. Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done. Suspending console(s) (use no_console_suspend to debug) PM: suspend of devices complete after 161.119 msecs PM: late suspend of devices complete after 1.048 msecs PM: noirq suspend of devices complete after 0.756 msecs Disabling non-boot CPUs ... CPU1: shutdown CPU2: shutdown CPU3: shutdown Entering suspend state LP1 Enabling non-boot CPUs ... CPU1 is up CPU2 is up CPU3 is up PM: noirq resume of devices complete after 0.487 msecs as3722 4-0040: Failed to read IRQ status: -16 as3722 4-0040: Failed to read IRQ status: -16 as3722 4-0040: Failed to read IRQ status: -16 as3722 4-0040: Failed to read IRQ status: -16 ... The reason why the as3722 interrupt status cannot be read is because the as3722 interrupt is not masked during suspend and when the as3722-rtc interrupt occurs, to wake-up the device, the interrupt is seen before the i2c controller has been resumed in order to read the as3722 interrupt status. The as3722-rtc driver sets it's interrupt as a wake-up source during suspend, which gets propagated to the parent as3722 interrupt. However, the as3722-rtc driver cannot disable it's interrupt during suspend otherwise we would never be woken up and so the as3722 must disable it's interrupt instead. Fix this by disabling the as3722 interrupt during suspend. To ensure that a wake-up event from the as3722 is not missing, enable the as3722 interrupt as a wake-up source before disabling the interrupt on entering suspend. Signed-off-by: Jon Hunter Signed-off-by: Lee Jones Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/as3722.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/mfd/as3722.c') diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c index 924ea90494ae..3b21eb4bc480 100644 --- a/drivers/mfd/as3722.c +++ b/drivers/mfd/as3722.c @@ -405,6 +405,8 @@ static int as3722_i2c_probe(struct i2c_client *i2c, goto scrub; } + device_init_wakeup(as3722->dev, true); + dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n"); return 0; @@ -422,6 +424,29 @@ static int as3722_i2c_remove(struct i2c_client *i2c) return 0; } +static int as3722_i2c_suspend(struct device *dev) +{ + struct as3722 *as3722 = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(as3722->chip_irq); + disable_irq(as3722->chip_irq); + + return 0; +} + +static int as3722_i2c_resume(struct device *dev) +{ + struct as3722 *as3722 = dev_get_drvdata(dev); + + enable_irq(as3722->chip_irq); + + if (device_may_wakeup(dev)) + disable_irq_wake(as3722->chip_irq); + + return 0; +} + static const struct of_device_id as3722_of_match[] = { { .compatible = "ams,as3722", }, {}, @@ -434,10 +459,15 @@ static const struct i2c_device_id as3722_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, as3722_i2c_id); +static const struct dev_pm_ops as3722_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(as3722_i2c_suspend, as3722_i2c_resume) +}; + static struct i2c_driver as3722_i2c_driver = { .driver = { .name = "as3722", .of_match_table = as3722_of_match, + .pm = &as3722_pm_ops, }, .probe = as3722_i2c_probe, .remove = as3722_i2c_remove, -- cgit v1.2.3 From c78c9f52afe57848a5262afe3c12c7d9930d0831 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Dec 2015 16:21:05 +0100 Subject: mfd: as3722: Mark PM functions as __maybe_unused commit a7b956fd38dd217dd78e3058110929f5ac914df1 upstream. The newly introduced as3722_i2c_suspend/resume functions are built unconditionally, but only used when power management is enabled, so we get a warning otherwise: drivers/mfd/as3722.c:427:12: warning: 'as3722_i2c_suspend' defined but not used [-Wunused-function] drivers/mfd/as3722.c:438:12: warning: 'as3722_i2c_resume' defined but not used [-Wunused-function] This marks them both as __maybe_unused, which avoids an ugly #ifdef and gives us best compile-time coverage. When they are unused, the compiler will silently drop the functions from its output. Signed-off-by: Arnd Bergmann Fixes: 35deff7eb212 ("mfd: as3722: Handle interrupts on suspend") Signed-off-by: Lee Jones Cc: Jon Hunter Signed-off-by: Greg Kroah-Hartman --- drivers/mfd/as3722.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mfd/as3722.c') diff --git a/drivers/mfd/as3722.c b/drivers/mfd/as3722.c index 3b21eb4bc480..e1f597f97f86 100644 --- a/drivers/mfd/as3722.c +++ b/drivers/mfd/as3722.c @@ -424,7 +424,7 @@ static int as3722_i2c_remove(struct i2c_client *i2c) return 0; } -static int as3722_i2c_suspend(struct device *dev) +static int __maybe_unused as3722_i2c_suspend(struct device *dev) { struct as3722 *as3722 = dev_get_drvdata(dev); @@ -435,7 +435,7 @@ static int as3722_i2c_suspend(struct device *dev) return 0; } -static int as3722_i2c_resume(struct device *dev) +static int __maybe_unused as3722_i2c_resume(struct device *dev) { struct as3722 *as3722 = dev_get_drvdata(dev); -- cgit v1.2.3