Skip to content

Commit 3fffd12

Browse files
dtorWolfram Sang
authored andcommitted
i2c: allow specifying separate wakeup interrupt in device tree
Instead of having each i2c driver individually parse device tree data in case it or platform supports separate wakeup interrupt, and handle enabling and disabling wakeup interrupts in their power management routines, let's have i2c core do that for us. Platforms wishing to specify separate wakeup interrupt for the device should use named interrupt syntax in their DTSes: interrupt-parent = <&intc1>; interrupts = <5 0>, <6 0>; interrupt-names = "irq", "wakeup"; This patch is inspired by work done by Vignesh R <vigneshr@ti.com> for pixcir_i2c_ts driver. Note that the original code tried to preserve any existing wakeup settings from userspace but was not quite right in that regard: it would preserve wakeup flag set by userspace upon driver rebinding; but it would re-arm the wakeup flag if it was disabled by userspace. We think that resetting the flag upon re-binding the driver is proper behavior as the driver is responsible for setting up and handling wakeups. Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com> Tested-by: Vignesh R <vigneshr@ti.com> [wsa: updated the commit message] Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
1 parent 6602c45 commit 3fffd12

File tree

2 files changed

+56
-11
lines changed

2 files changed

+56
-11
lines changed

Documentation/devicetree/bindings/i2c/i2c.txt

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Required properties
1212
- compatible - name of I2C bus controller following generic names
1313
recommended practice.
1414

15-
For other required properties e.g. to describe register sets, interrupts,
15+
For other required properties e.g. to describe register sets,
1616
clocks, etc. check the binding documentation of the specific driver.
1717

1818
The cells properties above define that an address of children of an I2C bus
@@ -29,5 +29,17 @@ Optional properties
2929
These properties may not be supported by all drivers. However, if a driver
3030
wants to support one of the below features, it should adapt the bindings below.
3131

32-
- clock-frequency - frequency of bus clock in Hz
32+
- clock-frequency - frequency of bus clock in Hz.
3333
- wakeup-source - device can be used as a wakeup source.
34+
35+
- interrupts - interrupts used by the device.
36+
- interrupt-names - "irq" and "wakeup" names are recognized by I2C core,
37+
other names are left to individual drivers.
38+
39+
Binding may contain optional "interrupts" property, describing interrupts
40+
used by the device. I2C core will assign "irq" interrupt (or the very first
41+
interrupt if not using interrupt names) as primary interrupt for the slave.
42+
43+
Also, if device is marked as a wakeup source, I2C core will set up "wakeup"
44+
interrupt for the device. If "wakeup" interrupt name is not present in the
45+
binding, then primary interrupt will be used as wakeup interrupt.

drivers/i2c/i2c-core.c

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include <linux/rwsem.h>
4949
#include <linux/pm_runtime.h>
5050
#include <linux/pm_domain.h>
51+
#include <linux/pm_wakeirq.h>
5152
#include <linux/acpi.h>
5253
#include <linux/jump_label.h>
5354
#include <asm/uaccess.h>
@@ -645,11 +646,13 @@ static int i2c_device_probe(struct device *dev)
645646
if (!client->irq) {
646647
int irq = -ENOENT;
647648

648-
if (dev->of_node)
649-
irq = of_irq_get(dev->of_node, 0);
650-
else if (ACPI_COMPANION(dev))
649+
if (dev->of_node) {
650+
irq = of_irq_get_byname(dev->of_node, "irq");
651+
if (irq == -EINVAL || irq == -ENODATA)
652+
irq = of_irq_get(dev->of_node, 0);
653+
} else if (ACPI_COMPANION(dev)) {
651654
irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0);
652-
655+
}
653656
if (irq == -EPROBE_DEFER)
654657
return irq;
655658
if (irq < 0)
@@ -662,23 +665,49 @@ static int i2c_device_probe(struct device *dev)
662665
if (!driver->probe || !driver->id_table)
663666
return -ENODEV;
664667

665-
if (!device_can_wakeup(&client->dev))
666-
device_init_wakeup(&client->dev,
667-
client->flags & I2C_CLIENT_WAKE);
668+
if (client->flags & I2C_CLIENT_WAKE) {
669+
int wakeirq = -ENOENT;
670+
671+
if (dev->of_node) {
672+
wakeirq = of_irq_get_byname(dev->of_node, "wakeup");
673+
if (wakeirq == -EPROBE_DEFER)
674+
return wakeirq;
675+
}
676+
677+
device_init_wakeup(&client->dev, true);
678+
679+
if (wakeirq > 0 && wakeirq != client->irq)
680+
status = dev_pm_set_dedicated_wake_irq(dev, wakeirq);
681+
else if (client->irq > 0)
682+
status = dev_pm_set_wake_irq(dev, wakeirq);
683+
else
684+
status = 0;
685+
686+
if (status)
687+
dev_warn(&client->dev, "failed to set up wakeup irq");
688+
}
689+
668690
dev_dbg(dev, "probe\n");
669691

670692
status = of_clk_set_defaults(dev->of_node, false);
671693
if (status < 0)
672-
return status;
694+
goto err_clear_wakeup_irq;
673695

674696
status = dev_pm_domain_attach(&client->dev, true);
675697
if (status != -EPROBE_DEFER) {
676698
status = driver->probe(client, i2c_match_id(driver->id_table,
677699
client));
678700
if (status)
679-
dev_pm_domain_detach(&client->dev, true);
701+
goto err_detach_pm_domain;
680702
}
681703

704+
return 0;
705+
706+
err_detach_pm_domain:
707+
dev_pm_domain_detach(&client->dev, true);
708+
err_clear_wakeup_irq:
709+
dev_pm_clear_wake_irq(&client->dev);
710+
device_init_wakeup(&client->dev, false);
682711
return status;
683712
}
684713

@@ -698,6 +727,10 @@ static int i2c_device_remove(struct device *dev)
698727
}
699728

700729
dev_pm_domain_detach(&client->dev, true);
730+
731+
dev_pm_clear_wake_irq(&client->dev);
732+
device_init_wakeup(&client->dev, false);
733+
701734
return status;
702735
}
703736

0 commit comments

Comments
 (0)