Skip to content

Commit 1dfb642

Browse files
committed
Merge tag 'gpio-v5.6-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio
Pull GPIO fixes from Linus Walleij: - One core quirk by myself to fix the .irq_disable() semantics when the gpiolib core takes over this callback. - The rest is an elaborate series of four patches fixing Intel laptop ACPI wakeup quirks. * tag 'gpio-v5.6-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: gpiolib: acpi: Add quirk to ignore EC wakeups on HP x2 10 CHT + AXP288 model gpiolib: acpi: Add quirk to ignore EC wakeups on HP x2 10 BYT + AXP288 model gpiolib: acpi: Rework honor_wakeup option into an ignore_wake option gpiolib: acpi: Correct comment for HP x2 10 honor_wakeup quirk gpiolib: Fix irq_disable() semantics
2 parents e2cf67f + 0c625cc commit 1dfb642

File tree

2 files changed

+122
-27
lines changed

2 files changed

+122
-27
lines changed

drivers/gpio/gpiolib-acpi.c

Lines changed: 114 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,21 @@
2121
#include "gpiolib.h"
2222
#include "gpiolib-acpi.h"
2323

24-
#define QUIRK_NO_EDGE_EVENTS_ON_BOOT 0x01l
25-
#define QUIRK_NO_WAKEUP 0x02l
26-
2724
static int run_edge_events_on_boot = -1;
2825
module_param(run_edge_events_on_boot, int, 0444);
2926
MODULE_PARM_DESC(run_edge_events_on_boot,
3027
"Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto");
3128

32-
static int honor_wakeup = -1;
33-
module_param(honor_wakeup, int, 0444);
34-
MODULE_PARM_DESC(honor_wakeup,
35-
"Honor the ACPI wake-capable flag: 0=no, 1=yes, -1=auto");
29+
static char *ignore_wake;
30+
module_param(ignore_wake, charp, 0444);
31+
MODULE_PARM_DESC(ignore_wake,
32+
"controller@pin combos on which to ignore the ACPI wake flag "
33+
"ignore_wake=controller@pin[,controller@pin[,...]]");
34+
35+
struct acpi_gpiolib_dmi_quirk {
36+
bool no_edge_events_on_boot;
37+
char *ignore_wake;
38+
};
3639

3740
/**
3841
* struct acpi_gpio_event - ACPI GPIO event handler data
@@ -202,6 +205,57 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
202205
acpi_gpiochip_request_irq(acpi_gpio, event);
203206
}
204207

208+
static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in)
209+
{
210+
const char *controller, *pin_str;
211+
int len, pin;
212+
char *endp;
213+
214+
controller = ignore_wake;
215+
while (controller) {
216+
pin_str = strchr(controller, '@');
217+
if (!pin_str)
218+
goto err;
219+
220+
len = pin_str - controller;
221+
if (len == strlen(controller_in) &&
222+
strncmp(controller, controller_in, len) == 0) {
223+
pin = simple_strtoul(pin_str + 1, &endp, 10);
224+
if (*endp != 0 && *endp != ',')
225+
goto err;
226+
227+
if (pin == pin_in)
228+
return true;
229+
}
230+
231+
controller = strchr(controller, ',');
232+
if (controller)
233+
controller++;
234+
}
235+
236+
return false;
237+
err:
238+
pr_err_once("Error invalid value for gpiolib_acpi.ignore_wake: %s\n",
239+
ignore_wake);
240+
return false;
241+
}
242+
243+
static bool acpi_gpio_irq_is_wake(struct device *parent,
244+
struct acpi_resource_gpio *agpio)
245+
{
246+
int pin = agpio->pin_table[0];
247+
248+
if (agpio->wake_capable != ACPI_WAKE_CAPABLE)
249+
return false;
250+
251+
if (acpi_gpio_in_ignore_list(dev_name(parent), pin)) {
252+
dev_info(parent, "Ignoring wakeup on pin %d\n", pin);
253+
return false;
254+
}
255+
256+
return true;
257+
}
258+
205259
/* Always returns AE_OK so that we keep looping over the resources */
206260
static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
207261
void *context)
@@ -289,7 +343,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
289343
event->handle = evt_handle;
290344
event->handler = handler;
291345
event->irq = irq;
292-
event->irq_is_wake = honor_wakeup && agpio->wake_capable == ACPI_WAKE_CAPABLE;
346+
event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio);
293347
event->pin = pin;
294348
event->desc = desc;
295349

@@ -1328,7 +1382,9 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
13281382
DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
13291383
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
13301384
},
1331-
.driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT,
1385+
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1386+
.no_edge_events_on_boot = true,
1387+
},
13321388
},
13331389
{
13341390
/*
@@ -1341,50 +1397,82 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
13411397
DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"),
13421398
DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"),
13431399
},
1344-
.driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT,
1400+
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1401+
.no_edge_events_on_boot = true,
1402+
},
13451403
},
13461404
{
13471405
/*
1348-
* Various HP X2 10 Cherry Trail models use an external
1349-
* embedded-controller connected via I2C + an ACPI GPIO
1350-
* event handler. The embedded controller generates various
1351-
* spurious wakeup events when suspended. So disable wakeup
1352-
* for its handler (it uses the only ACPI GPIO event handler).
1353-
* This breaks wakeup when opening the lid, the user needs
1406+
* HP X2 10 models with Cherry Trail SoC + TI PMIC use an
1407+
* external embedded-controller connected via I2C + an ACPI GPIO
1408+
* event handler on INT33FF:01 pin 0, causing spurious wakeups.
1409+
* When suspending by closing the LID, the power to the USB
1410+
* keyboard is turned off, causing INT0002 ACPI events to
1411+
* trigger once the XHCI controller notices the keyboard is
1412+
* gone. So INT0002 events cause spurious wakeups too. Ignoring
1413+
* EC wakes breaks wakeup when opening the lid, the user needs
13541414
* to press the power-button to wakeup the system. The
13551415
* alternative is suspend simply not working, which is worse.
13561416
*/
13571417
.matches = {
13581418
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
13591419
DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"),
13601420
},
1361-
.driver_data = (void *)QUIRK_NO_WAKEUP,
1421+
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1422+
.ignore_wake = "INT33FF:01@0,INT0002:00@2",
1423+
},
1424+
},
1425+
{
1426+
/*
1427+
* HP X2 10 models with Bay Trail SoC + AXP288 PMIC use an
1428+
* external embedded-controller connected via I2C + an ACPI GPIO
1429+
* event handler on INT33FC:02 pin 28, causing spurious wakeups.
1430+
*/
1431+
.matches = {
1432+
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
1433+
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
1434+
DMI_MATCH(DMI_BOARD_NAME, "815D"),
1435+
},
1436+
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1437+
.ignore_wake = "INT33FC:02@28",
1438+
},
1439+
},
1440+
{
1441+
/*
1442+
* HP X2 10 models with Cherry Trail SoC + AXP288 PMIC use an
1443+
* external embedded-controller connected via I2C + an ACPI GPIO
1444+
* event handler on INT33FF:01 pin 0, causing spurious wakeups.
1445+
*/
1446+
.matches = {
1447+
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
1448+
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
1449+
DMI_MATCH(DMI_BOARD_NAME, "813E"),
1450+
},
1451+
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1452+
.ignore_wake = "INT33FF:01@0",
1453+
},
13621454
},
13631455
{} /* Terminating entry */
13641456
};
13651457

13661458
static int acpi_gpio_setup_params(void)
13671459
{
1460+
const struct acpi_gpiolib_dmi_quirk *quirk = NULL;
13681461
const struct dmi_system_id *id;
1369-
long quirks = 0;
13701462

13711463
id = dmi_first_match(gpiolib_acpi_quirks);
13721464
if (id)
1373-
quirks = (long)id->driver_data;
1465+
quirk = id->driver_data;
13741466

13751467
if (run_edge_events_on_boot < 0) {
1376-
if (quirks & QUIRK_NO_EDGE_EVENTS_ON_BOOT)
1468+
if (quirk && quirk->no_edge_events_on_boot)
13771469
run_edge_events_on_boot = 0;
13781470
else
13791471
run_edge_events_on_boot = 1;
13801472
}
13811473

1382-
if (honor_wakeup < 0) {
1383-
if (quirks & QUIRK_NO_WAKEUP)
1384-
honor_wakeup = 0;
1385-
else
1386-
honor_wakeup = 1;
1387-
}
1474+
if (ignore_wake == NULL && quirk && quirk->ignore_wake)
1475+
ignore_wake = quirk->ignore_wake;
13881476

13891477
return 0;
13901478
}

drivers/gpio/gpiolib.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2306,9 +2306,16 @@ static void gpiochip_irq_disable(struct irq_data *d)
23062306
{
23072307
struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
23082308

2309+
/*
2310+
* Since we override .irq_disable() we need to mimic the
2311+
* behaviour of __irq_disable() in irq/chip.c.
2312+
* First call .irq_disable() if it exists, else mimic the
2313+
* behaviour of mask_irq() which calls .irq_mask() if
2314+
* it exists.
2315+
*/
23092316
if (chip->irq.irq_disable)
23102317
chip->irq.irq_disable(d);
2311-
else
2318+
else if (chip->irq.chip->irq_mask)
23122319
chip->irq.chip->irq_mask(d);
23132320
gpiochip_disable_irq(chip, d->hwirq);
23142321
}

0 commit comments

Comments
 (0)