Commit 1dfb642b authored by Linus Torvalds's avatar Linus Torvalds

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
parents e2cf67f6 0c625ccf
...@@ -21,18 +21,21 @@ ...@@ -21,18 +21,21 @@
#include "gpiolib.h" #include "gpiolib.h"
#include "gpiolib-acpi.h" #include "gpiolib-acpi.h"
#define QUIRK_NO_EDGE_EVENTS_ON_BOOT 0x01l
#define QUIRK_NO_WAKEUP 0x02l
static int run_edge_events_on_boot = -1; static int run_edge_events_on_boot = -1;
module_param(run_edge_events_on_boot, int, 0444); module_param(run_edge_events_on_boot, int, 0444);
MODULE_PARM_DESC(run_edge_events_on_boot, MODULE_PARM_DESC(run_edge_events_on_boot,
"Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto"); "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto");
static int honor_wakeup = -1; static char *ignore_wake;
module_param(honor_wakeup, int, 0444); module_param(ignore_wake, charp, 0444);
MODULE_PARM_DESC(honor_wakeup, MODULE_PARM_DESC(ignore_wake,
"Honor the ACPI wake-capable flag: 0=no, 1=yes, -1=auto"); "controller@pin combos on which to ignore the ACPI wake flag "
"ignore_wake=controller@pin[,controller@pin[,...]]");
struct acpi_gpiolib_dmi_quirk {
bool no_edge_events_on_boot;
char *ignore_wake;
};
/** /**
* struct acpi_gpio_event - ACPI GPIO event handler data * 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) ...@@ -202,6 +205,57 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
acpi_gpiochip_request_irq(acpi_gpio, event); acpi_gpiochip_request_irq(acpi_gpio, event);
} }
static bool acpi_gpio_in_ignore_list(const char *controller_in, int pin_in)
{
const char *controller, *pin_str;
int len, pin;
char *endp;
controller = ignore_wake;
while (controller) {
pin_str = strchr(controller, '@');
if (!pin_str)
goto err;
len = pin_str - controller;
if (len == strlen(controller_in) &&
strncmp(controller, controller_in, len) == 0) {
pin = simple_strtoul(pin_str + 1, &endp, 10);
if (*endp != 0 && *endp != ',')
goto err;
if (pin == pin_in)
return true;
}
controller = strchr(controller, ',');
if (controller)
controller++;
}
return false;
err:
pr_err_once("Error invalid value for gpiolib_acpi.ignore_wake: %s\n",
ignore_wake);
return false;
}
static bool acpi_gpio_irq_is_wake(struct device *parent,
struct acpi_resource_gpio *agpio)
{
int pin = agpio->pin_table[0];
if (agpio->wake_capable != ACPI_WAKE_CAPABLE)
return false;
if (acpi_gpio_in_ignore_list(dev_name(parent), pin)) {
dev_info(parent, "Ignoring wakeup on pin %d\n", pin);
return false;
}
return true;
}
/* Always returns AE_OK so that we keep looping over the resources */ /* Always returns AE_OK so that we keep looping over the resources */
static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
void *context) void *context)
...@@ -289,7 +343,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares, ...@@ -289,7 +343,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
event->handle = evt_handle; event->handle = evt_handle;
event->handler = handler; event->handler = handler;
event->irq = irq; event->irq = irq;
event->irq_is_wake = honor_wakeup && agpio->wake_capable == ACPI_WAKE_CAPABLE; event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio);
event->pin = pin; event->pin = pin;
event->desc = desc; event->desc = desc;
...@@ -1328,7 +1382,9 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = { ...@@ -1328,7 +1382,9 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "MINIX"), DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"), DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
}, },
.driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT, .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
.no_edge_events_on_boot = true,
},
}, },
{ {
/* /*
...@@ -1341,16 +1397,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = { ...@@ -1341,16 +1397,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"), DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"),
DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"), DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"),
}, },
.driver_data = (void *)QUIRK_NO_EDGE_EVENTS_ON_BOOT, .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
.no_edge_events_on_boot = true,
},
}, },
{ {
/* /*
* Various HP X2 10 Cherry Trail models use an external * HP X2 10 models with Cherry Trail SoC + TI PMIC use an
* embedded-controller connected via I2C + an ACPI GPIO * external embedded-controller connected via I2C + an ACPI GPIO
* event handler. The embedded controller generates various * event handler on INT33FF:01 pin 0, causing spurious wakeups.
* spurious wakeup events when suspended. So disable wakeup * When suspending by closing the LID, the power to the USB
* for its handler (it uses the only ACPI GPIO event handler). * keyboard is turned off, causing INT0002 ACPI events to
* This breaks wakeup when opening the lid, the user needs * trigger once the XHCI controller notices the keyboard is
* gone. So INT0002 events cause spurious wakeups too. Ignoring
* EC wakes breaks wakeup when opening the lid, the user needs
* to press the power-button to wakeup the system. The * to press the power-button to wakeup the system. The
* alternative is suspend simply not working, which is worse. * alternative is suspend simply not working, which is worse.
*/ */
...@@ -1358,33 +1418,61 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = { ...@@ -1358,33 +1418,61 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"), DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"), DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"),
}, },
.driver_data = (void *)QUIRK_NO_WAKEUP, .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
.ignore_wake = "INT33FF:01@0,INT0002:00@2",
},
},
{
/*
* HP X2 10 models with Bay Trail SoC + AXP288 PMIC use an
* external embedded-controller connected via I2C + an ACPI GPIO
* event handler on INT33FC:02 pin 28, causing spurious wakeups.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
DMI_MATCH(DMI_BOARD_NAME, "815D"),
},
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
.ignore_wake = "INT33FC:02@28",
},
},
{
/*
* HP X2 10 models with Cherry Trail SoC + AXP288 PMIC use an
* external embedded-controller connected via I2C + an ACPI GPIO
* event handler on INT33FF:01 pin 0, causing spurious wakeups.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
DMI_MATCH(DMI_BOARD_NAME, "813E"),
},
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
.ignore_wake = "INT33FF:01@0",
},
}, },
{} /* Terminating entry */ {} /* Terminating entry */
}; };
static int acpi_gpio_setup_params(void) static int acpi_gpio_setup_params(void)
{ {
const struct acpi_gpiolib_dmi_quirk *quirk = NULL;
const struct dmi_system_id *id; const struct dmi_system_id *id;
long quirks = 0;
id = dmi_first_match(gpiolib_acpi_quirks); id = dmi_first_match(gpiolib_acpi_quirks);
if (id) if (id)
quirks = (long)id->driver_data; quirk = id->driver_data;
if (run_edge_events_on_boot < 0) { if (run_edge_events_on_boot < 0) {
if (quirks & QUIRK_NO_EDGE_EVENTS_ON_BOOT) if (quirk && quirk->no_edge_events_on_boot)
run_edge_events_on_boot = 0; run_edge_events_on_boot = 0;
else else
run_edge_events_on_boot = 1; run_edge_events_on_boot = 1;
} }
if (honor_wakeup < 0) { if (ignore_wake == NULL && quirk && quirk->ignore_wake)
if (quirks & QUIRK_NO_WAKEUP) ignore_wake = quirk->ignore_wake;
honor_wakeup = 0;
else
honor_wakeup = 1;
}
return 0; return 0;
} }
......
...@@ -2306,9 +2306,16 @@ static void gpiochip_irq_disable(struct irq_data *d) ...@@ -2306,9 +2306,16 @@ static void gpiochip_irq_disable(struct irq_data *d)
{ {
struct gpio_chip *chip = irq_data_get_irq_chip_data(d); struct gpio_chip *chip = irq_data_get_irq_chip_data(d);
/*
* Since we override .irq_disable() we need to mimic the
* behaviour of __irq_disable() in irq/chip.c.
* First call .irq_disable() if it exists, else mimic the
* behaviour of mask_irq() which calls .irq_mask() if
* it exists.
*/
if (chip->irq.irq_disable) if (chip->irq.irq_disable)
chip->irq.irq_disable(d); chip->irq.irq_disable(d);
else else if (chip->irq.chip->irq_mask)
chip->irq.chip->irq_mask(d); chip->irq.chip->irq_mask(d);
gpiochip_disable_irq(chip, d->hwirq); gpiochip_disable_irq(chip, d->hwirq);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment