| From c30ed514892710fa96bb23337e731dc1f4e29ecd Mon Sep 17 00:00:00 2001 |
| From: Andreas Kemnade <andreas@kemnade.info> |
| Date: Sat, 23 Feb 2019 12:47:54 +0100 |
| Subject: mfd: twl-core: Disable IRQ while suspended |
| |
| [ Upstream commit 20bb907f7dc82ecc9e135ad7067ac7eb69c81222 ] |
| |
| Since commit 6e2bd956936 ("i2c: omap: Use noirq system sleep pm ops to idle device for suspend") |
| on gta04 we have handle_twl4030_pih() called in situations where pm_runtime_get() |
| in i2c-omap.c returns -EACCES. |
| |
| [ 86.474365] Freezing remaining freezable tasks ... (elapsed 0.002 seconds) done. |
| [ 86.485473] printk: Suspending console(s) (use no_console_suspend to debug) |
| [ 86.555572] Disabling non-boot CPUs ... |
| [ 86.555664] Successfully put all powerdomains to target state |
| [ 86.563720] twl: Read failed (mod 1, reg 0x01 count 1) |
| [ 86.563751] twl4030: I2C error -13 reading PIH ISR |
| [ 86.563812] twl: Read failed (mod 1, reg 0x01 count 1) |
| [ 86.563812] twl4030: I2C error -13 reading PIH ISR |
| [ 86.563873] twl: Read failed (mod 1, reg 0x01 count 1) |
| [ 86.563903] twl4030: I2C error -13 reading PIH ISR |
| |
| This happens when we wakeup via something behing twl4030 (powerbutton or rtc |
| alarm). This goes on for minutes until the system is finally resumed. |
| Disable the irq on suspend and enable it on resume to avoid |
| having i2c access problems when the irq registers are checked. |
| |
| Fixes: 6e2bd956936 ("i2c: omap: Use noirq system sleep pm ops to idle device for suspend") |
| Signed-off-by: Andreas Kemnade <andreas@kemnade.info> |
| Tested-by: Tony Lindgren <tony@atomide.com> |
| Signed-off-by: Lee Jones <lee.jones@linaro.org> |
| Signed-off-by: Sasha Levin (Microsoft) <sashal@kernel.org> |
| --- |
| drivers/mfd/twl-core.c | 23 +++++++++++++++++++++++ |
| 1 file changed, 23 insertions(+) |
| |
| diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c |
| index 299016bc46d9..104477b512a2 100644 |
| --- a/drivers/mfd/twl-core.c |
| +++ b/drivers/mfd/twl-core.c |
| @@ -1245,6 +1245,28 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id) |
| return status; |
| } |
| |
| +static int __maybe_unused twl_suspend(struct device *dev) |
| +{ |
| + struct i2c_client *client = to_i2c_client(dev); |
| + |
| + if (client->irq) |
| + disable_irq(client->irq); |
| + |
| + return 0; |
| +} |
| + |
| +static int __maybe_unused twl_resume(struct device *dev) |
| +{ |
| + struct i2c_client *client = to_i2c_client(dev); |
| + |
| + if (client->irq) |
| + enable_irq(client->irq); |
| + |
| + return 0; |
| +} |
| + |
| +static SIMPLE_DEV_PM_OPS(twl_dev_pm_ops, twl_suspend, twl_resume); |
| + |
| static const struct i2c_device_id twl_ids[] = { |
| { "twl4030", TWL4030_VAUX2 }, /* "Triton 2" */ |
| { "twl5030", 0 }, /* T2 updated */ |
| @@ -1262,6 +1284,7 @@ static const struct i2c_device_id twl_ids[] = { |
| /* One Client Driver , 4 Clients */ |
| static struct i2c_driver twl_driver = { |
| .driver.name = DRIVER_NAME, |
| + .driver.pm = &twl_dev_pm_ops, |
| .id_table = twl_ids, |
| .probe = twl_probe, |
| .remove = twl_remove, |
| -- |
| 2.20.1 |
| |