GPIO fixes for the v5.6 series:
- 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 4 patches fixing Intel laptop ACPI wakeup quirks. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEElDRnuGcz/wPCXQWMQRCzN7AZXXMFAl57qSIACgkQQRCzN7AZ XXMmqxAAiggbsjiMkufxHxDqKl0tLRkbQwlsnz5VQlH0XCPBYSRidbIfQdiDFTbD yoBENIYeW/9aVlb0Q7a2T5H4zy1Ye3MiqObZt97ECr7DyxwNrAbPS/IgOFmsjSmu C4HZgX6/fQpBlJnKVgMBwzdgKShX4Fb4l1gFnY7uRRjBGVkp5ZArqJALJ747zFR0 yj/kpA+hGgO24AJspF+QaLFfKkjMXKv2zgaa3HEtsYqUBH/3yBZigLKJs3koXHYB 3c7EbWxnpYLiPi/T51aN7ZbbNX7Ag6wW6rLm/6460MCYDRSOB+7fCJCZc2KZJomr 4ntq1HHxSrjOiqce+MSvc+WLI6pqjN73tyWJwhFgBfwr32Ara5FR6CO0KJT9M5d+ 0i8Na0Dyp2LlZM530ygOOn48p+tiU6NVoR/BXUnXBBuYtFsOmfTtrQGh++Uw+rcJ wraFAsSzzr7JmXzh+tUEeGGdI4EYy1T6+DppEfSbyty9W6YnWvqHP9xcyuicUyi2 g9Btl0hRhSqQZozDYjROPQox1qjUKHLnI66n/W9pVUN61GlFlSH/38yRAEpD0DZW GlzSEkfL5SN5DQjaAOC2z0z+kfFSGdtCYMOKkyl+cKGbLCRc43PrzHB3oH+wF1Mu 0J+Hilrk9y4sGTX67jIQPV/t1qhoorRFzihuUkHBdGt//XCqtI4= =+dEG -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
1dfb642b10
@ -21,18 +21,21 @@
|
||||
#include "gpiolib.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;
|
||||
module_param(run_edge_events_on_boot, int, 0444);
|
||||
MODULE_PARM_DESC(run_edge_events_on_boot,
|
||||
"Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto");
|
||||
|
||||
static int honor_wakeup = -1;
|
||||
module_param(honor_wakeup, int, 0444);
|
||||
MODULE_PARM_DESC(honor_wakeup,
|
||||
"Honor the ACPI wake-capable flag: 0=no, 1=yes, -1=auto");
|
||||
static char *ignore_wake;
|
||||
module_param(ignore_wake, charp, 0444);
|
||||
MODULE_PARM_DESC(ignore_wake,
|
||||
"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
|
||||
@ -202,6 +205,57 @@ static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
|
||||
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 */
|
||||
static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
|
||||
void *context)
|
||||
@ -289,7 +343,7 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
|
||||
event->handle = evt_handle;
|
||||
event->handler = handler;
|
||||
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->desc = desc;
|
||||
|
||||
@ -1328,7 +1382,9 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
|
||||
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[] = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"),
|
||||
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
|
||||
* embedded-controller connected via I2C + an ACPI GPIO
|
||||
* event handler. The embedded controller generates various
|
||||
* spurious wakeup events when suspended. So disable wakeup
|
||||
* for its handler (it uses the only ACPI GPIO event handler).
|
||||
* This breaks wakeup when opening the lid, the user needs
|
||||
* HP X2 10 models with Cherry Trail SoC + TI PMIC use an
|
||||
* external embedded-controller connected via I2C + an ACPI GPIO
|
||||
* event handler on INT33FF:01 pin 0, causing spurious wakeups.
|
||||
* When suspending by closing the LID, the power to the USB
|
||||
* keyboard is turned off, causing INT0002 ACPI events to
|
||||
* 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
|
||||
* alternative is suspend simply not working, which is worse.
|
||||
*/
|
||||
@ -1358,33 +1418,61 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
|
||||
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 */
|
||||
};
|
||||
|
||||
static int acpi_gpio_setup_params(void)
|
||||
{
|
||||
const struct acpi_gpiolib_dmi_quirk *quirk = NULL;
|
||||
const struct dmi_system_id *id;
|
||||
long quirks = 0;
|
||||
|
||||
id = dmi_first_match(gpiolib_acpi_quirks);
|
||||
if (id)
|
||||
quirks = (long)id->driver_data;
|
||||
quirk = id->driver_data;
|
||||
|
||||
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;
|
||||
else
|
||||
run_edge_events_on_boot = 1;
|
||||
}
|
||||
|
||||
if (honor_wakeup < 0) {
|
||||
if (quirks & QUIRK_NO_WAKEUP)
|
||||
honor_wakeup = 0;
|
||||
else
|
||||
honor_wakeup = 1;
|
||||
}
|
||||
if (ignore_wake == NULL && quirk && quirk->ignore_wake)
|
||||
ignore_wake = quirk->ignore_wake;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2306,9 +2306,16 @@ static void gpiochip_irq_disable(struct irq_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)
|
||||
chip->irq.irq_disable(d);
|
||||
else
|
||||
else if (chip->irq.chip->irq_mask)
|
||||
chip->irq.chip->irq_mask(d);
|
||||
gpiochip_disable_irq(chip, d->hwirq);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user