Skip to content

Commit b38f2d5

Browse files
Raul E Rangelrafaeljw
authored andcommitted
i2c: acpi: Use ACPI wake capability bit to set wake_irq
Device tree already has a mechanism to pass the wake_irq. It does this by looking for the wakeup-source property and setting the I2C_CLIENT_WAKE flag. This CL adds the ACPI equivalent. It uses the ACPI interrupt wake flag to determine if the interrupt can be used to wake the system. Previously the i2c drivers had to make assumptions and blindly enable the wake IRQ. This can cause spurious wake events. e.g., If there is a device with an Active Low interrupt and the device gets powered off while suspending, the interrupt line will go low since it's no longer powered and wakes the system. For this reason we should respect the board designers wishes and honor the wake bit defined on the interrupt. Signed-off-by: Raul E Rangel <[email protected]> Reviewed-by: Mika Westerberg <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Acked-by: Wolfram Sang <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 5ff8116 commit b38f2d5

File tree

3 files changed

+37
-13
lines changed

3 files changed

+37
-13
lines changed

drivers/i2c/i2c-core-acpi.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ static const struct acpi_device_id i2c_acpi_ignored_device_ids[] = {
137137
{}
138138
};
139139

140+
struct i2c_acpi_irq_context {
141+
int irq;
142+
bool wake_capable;
143+
};
144+
140145
static int i2c_acpi_do_lookup(struct acpi_device *adev,
141146
struct i2c_acpi_lookup *lookup)
142147
{
@@ -168,45 +173,60 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev,
168173
return 0;
169174
}
170175

171-
static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data)
176+
static int i2c_acpi_add_irq_resource(struct acpi_resource *ares, void *data)
172177
{
173-
int *irq = data;
178+
struct i2c_acpi_irq_context *irq_ctx = data;
174179
struct resource r;
175180

176-
if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
177-
*irq = i2c_dev_irq_from_resources(&r, 1);
181+
if (irq_ctx->irq > 0)
182+
return 1;
183+
184+
if (!acpi_dev_resource_interrupt(ares, 0, &r))
185+
return 1;
186+
187+
irq_ctx->irq = i2c_dev_irq_from_resources(&r, 1);
188+
irq_ctx->wake_capable = r.flags & IORESOURCE_IRQ_WAKECAPABLE;
178189

179190
return 1; /* No need to add resource to the list */
180191
}
181192

182193
/**
183194
* i2c_acpi_get_irq - get device IRQ number from ACPI
184195
* @client: Pointer to the I2C client device
196+
* @wake_capable: Set to true if the IRQ is wake capable
185197
*
186198
* Find the IRQ number used by a specific client device.
187199
*
188200
* Return: The IRQ number or an error code.
189201
*/
190-
int i2c_acpi_get_irq(struct i2c_client *client)
202+
int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable)
191203
{
192204
struct acpi_device *adev = ACPI_COMPANION(&client->dev);
193205
struct list_head resource_list;
194-
int irq = -ENOENT;
206+
struct i2c_acpi_irq_context irq_ctx = {
207+
.irq = -ENOENT,
208+
};
195209
int ret;
196210

197211
INIT_LIST_HEAD(&resource_list);
198212

199213
ret = acpi_dev_get_resources(adev, &resource_list,
200-
i2c_acpi_add_resource, &irq);
214+
i2c_acpi_add_irq_resource, &irq_ctx);
201215
if (ret < 0)
202216
return ret;
203217

204218
acpi_dev_free_resource_list(&resource_list);
205219

206-
if (irq == -ENOENT)
207-
irq = acpi_dev_gpio_irq_get(adev, 0);
220+
if (irq_ctx.irq == -ENOENT)
221+
irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, &irq_ctx.wake_capable);
222+
223+
if (irq_ctx.irq < 0)
224+
return irq_ctx.irq;
225+
226+
if (wake_capable)
227+
*wake_capable = irq_ctx.wake_capable;
208228

209-
return irq;
229+
return irq_ctx.irq;
210230
}
211231

212232
static int i2c_acpi_get_info(struct acpi_device *adev,

drivers/i2c/i2c-core-base.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,11 @@ static int i2c_device_probe(struct device *dev)
487487
if (irq == -EINVAL || irq == -ENODATA)
488488
irq = of_irq_get(dev->of_node, 0);
489489
} else if (ACPI_COMPANION(dev)) {
490-
irq = i2c_acpi_get_irq(client);
490+
bool wake_capable;
491+
492+
irq = i2c_acpi_get_irq(client, &wake_capable);
493+
if (irq > 0 && wake_capable)
494+
client->flags |= I2C_CLIENT_WAKE;
491495
}
492496
if (irq == -EPROBE_DEFER) {
493497
status = irq;

drivers/i2c/i2c-core.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ static inline int __i2c_check_suspended(struct i2c_adapter *adap)
6161
#ifdef CONFIG_ACPI
6262
void i2c_acpi_register_devices(struct i2c_adapter *adap);
6363

64-
int i2c_acpi_get_irq(struct i2c_client *client);
64+
int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable);
6565
#else /* CONFIG_ACPI */
6666
static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { }
6767

68-
static inline int i2c_acpi_get_irq(struct i2c_client *client)
68+
static inline int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable)
6969
{
7070
return 0;
7171
}

0 commit comments

Comments
 (0)