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.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)
|
|||||||
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,
|
|||||||
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[] = {
|
|||||||
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[] = {
|
|||||||
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[] = {
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user