Skip to content

Commit

Permalink
i2c: Prevent runtime suspend of adapter when Host Notify is required
Browse files Browse the repository at this point in the history
Multiple users have reported their Synaptics touchpad has stopped
working between v4.20.1 and v4.20.2 when using SMBus interface.

The culprit for this appeared to be commit c5eb119 ("PCI / PM: Allow
runtime PM without callback functions") that fixed the runtime PM for
i2c-i801 SMBus adapter. Those Synaptics touchpad are using i2c-i801
for SMBus communication and testing showed they are able to get back
working by preventing the runtime suspend of adapter.

Normally when i2c-i801 SMBus adapter transmits with the client it resumes
before operation and autosuspends after.

However, if client requires SMBus Host Notify protocol, what those
Synaptics touchpads do, then the host adapter must not go to runtime
suspend since then it cannot process incoming SMBus Host Notify commands
the client may send.

Fix this by keeping I2C/SMBus adapter active in case client requires
Host Notify.

Reported-by: Keijo Vaara <[email protected]>
Link: https://bugzilla.kernel.org/show_bug.cgi?id=203297
Fixes: c5eb119 ("PCI / PM: Allow runtime PM without callback functions")
Cc: [email protected] # v4.20+
Signed-off-by: Jarkko Nikula <[email protected]>
Acked-by: Rafael J. Wysocki <[email protected]>
Tested-by: Keijo Vaara <[email protected]>
Signed-off-by: Wolfram Sang <[email protected]>
  • Loading branch information
jhnikula authored and Wolfram Sang committed May 2, 2019
1 parent 95e0cf3 commit 72bfcee
Showing 1 changed file with 4 additions and 0 deletions.
4 changes: 4 additions & 0 deletions drivers/i2c/i2c-core-base.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ static int i2c_device_probe(struct device *dev)

if (client->flags & I2C_CLIENT_HOST_NOTIFY) {
dev_dbg(dev, "Using Host Notify IRQ\n");
/* Keep adapter active when Host Notify is required */
pm_runtime_get_sync(&client->adapter->dev);
irq = i2c_smbus_host_notify_to_irq(client);
} else if (dev->of_node) {
irq = of_irq_get_byname(dev->of_node, "irq");
Expand Down Expand Up @@ -431,6 +433,8 @@ static int i2c_device_remove(struct device *dev)
device_init_wakeup(&client->dev, false);

client->irq = client->init_irq;
if (client->flags & I2C_CLIENT_HOST_NOTIFY)
pm_runtime_put(&client->adapter->dev);

return status;
}
Expand Down

0 comments on commit 72bfcee

Please sign in to comment.