mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-09-18 22:14:16 +00:00
gpiolib: acpi: Move quirks to a separate file
The gpiolib-acpi.c is huge enough even without DMI quirks. Move them to a separate file for a better maintenance. No functional change intended. Reviewed-by: Hans de Goede <hdegoede@redhat.com> Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
This commit is contained in:
parent
5666a8777a
commit
92dc572852
3 changed files with 364 additions and 346 deletions
|
@ -10,6 +10,7 @@ obj-$(CONFIG_OF_GPIO) += gpiolib-of.o
|
|||
obj-$(CONFIG_GPIO_CDEV) += gpiolib-cdev.o
|
||||
obj-$(CONFIG_GPIO_SYSFS) += gpiolib-sysfs.o
|
||||
obj-$(CONFIG_GPIO_ACPI) += gpiolib-acpi.o
|
||||
gpiolib-acpi-y := gpiolib-acpi-core.o gpiolib-acpi-quirks.o
|
||||
obj-$(CONFIG_GPIOLIB) += gpiolib-swnode.o
|
||||
|
||||
# Device drivers. Generally keep list sorted alphabetically
|
||||
|
|
|
@ -23,29 +23,6 @@
|
|||
#include "gpiolib.h"
|
||||
#include "gpiolib-acpi.h"
|
||||
|
||||
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 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[,...]]");
|
||||
|
||||
static char *ignore_interrupt;
|
||||
module_param(ignore_interrupt, charp, 0444);
|
||||
MODULE_PARM_DESC(ignore_interrupt,
|
||||
"controller@pin combos on which to ignore interrupt "
|
||||
"ignore_interrupt=controller@pin[,controller@pin[,...]]");
|
||||
|
||||
struct acpi_gpiolib_dmi_quirk {
|
||||
bool no_edge_events_on_boot;
|
||||
char *ignore_wake;
|
||||
char *ignore_interrupt;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct acpi_gpio_event - ACPI GPIO event handler data
|
||||
*
|
||||
|
@ -115,17 +92,6 @@ struct acpi_gpio_info {
|
|||
unsigned int quirks;
|
||||
};
|
||||
|
||||
/*
|
||||
* For GPIO chips which call acpi_gpiochip_request_interrupts() before late_init
|
||||
* (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
|
||||
* late_initcall_sync() handler, so that other builtin drivers can register their
|
||||
* OpRegions before the event handlers can run. This list contains GPIO chips
|
||||
* for which the acpi_gpiochip_request_irqs() call has been deferred.
|
||||
*/
|
||||
static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
|
||||
static LIST_HEAD(acpi_gpio_deferred_req_irqs_list);
|
||||
static bool acpi_gpio_deferred_req_irqs_done;
|
||||
|
||||
static int acpi_gpiochip_find(struct gpio_chip *gc, const void *data)
|
||||
{
|
||||
/* First check the actual GPIO device */
|
||||
|
@ -350,79 +316,6 @@ static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
|
|||
return desc;
|
||||
}
|
||||
|
||||
bool acpi_gpio_add_to_deferred_list(struct list_head *list)
|
||||
{
|
||||
bool defer;
|
||||
|
||||
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
defer = !acpi_gpio_deferred_req_irqs_done;
|
||||
if (defer)
|
||||
list_add(list, &acpi_gpio_deferred_req_irqs_list);
|
||||
mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
|
||||
return defer;
|
||||
}
|
||||
|
||||
void acpi_gpio_remove_from_deferred_list(struct list_head *list)
|
||||
{
|
||||
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
if (!list_empty(list))
|
||||
list_del_init(list);
|
||||
mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
}
|
||||
|
||||
int acpi_gpio_need_run_edge_events_on_boot(void)
|
||||
{
|
||||
return run_edge_events_on_boot;
|
||||
}
|
||||
|
||||
bool acpi_gpio_in_ignore_list(enum acpi_gpio_ignore_list list, const char *controller_in,
|
||||
unsigned int pin_in)
|
||||
{
|
||||
const char *ignore_list, *controller, *pin_str;
|
||||
unsigned int pin;
|
||||
char *endp;
|
||||
int len;
|
||||
|
||||
switch (list) {
|
||||
case ACPI_GPIO_IGNORE_WAKE:
|
||||
ignore_list = ignore_wake;
|
||||
break;
|
||||
case ACPI_GPIO_IGNORE_INTERRUPT:
|
||||
ignore_list = ignore_interrupt;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
controller = ignore_list;
|
||||
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_...: %s\n", ignore_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool acpi_gpio_irq_is_wake(struct device *parent,
|
||||
const struct acpi_resource_gpio *agpio)
|
||||
{
|
||||
|
@ -1522,242 +1415,3 @@ int acpi_gpio_count(const struct fwnode_handle *fwnode, const char *con_id)
|
|||
}
|
||||
return count ? count : -ENOENT;
|
||||
}
|
||||
|
||||
/* Run deferred acpi_gpiochip_request_irqs() */
|
||||
static int __init acpi_gpio_handle_deferred_request_irqs(void)
|
||||
{
|
||||
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
acpi_gpio_process_deferred_list(&acpi_gpio_deferred_req_irqs_list);
|
||||
acpi_gpio_deferred_req_irqs_done = true;
|
||||
mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* We must use _sync so that this runs after the first deferred_probe run */
|
||||
late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
|
||||
|
||||
static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
|
||||
{
|
||||
/*
|
||||
* The Minix Neo Z83-4 has a micro-USB-B id-pin handler for
|
||||
* a non existing micro-USB-B connector which puts the HDMI
|
||||
* DDC pins in GPIO mode, breaking HDMI support.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.no_edge_events_on_boot = true,
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* The Terra Pad 1061 has a micro-USB-B id-pin handler, which
|
||||
* instead of controlling the actual micro-USB-B turns the 5V
|
||||
* boost for its USB-A connector off. The actual micro-USB-B
|
||||
* connector is wired for charging only.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.no_edge_events_on_boot = true,
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* The Dell Venue 10 Pro 5055, with Bay Trail SoC + TI PMIC uses an
|
||||
* external embedded-controller connected via I2C + an ACPI GPIO
|
||||
* event handler on INT33FFC:02 pin 12, causing spurious wakeups.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Venue 10 Pro 5055"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "INT33FC:02@12",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"),
|
||||
},
|
||||
.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",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Interrupt storm caused from edge triggered floating pin
|
||||
* Found in BIOS UX325UAZ.300
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=216208
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UAZ_UM325UAZ"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_interrupt = "AMDI0030:00@18",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
* Found in BIOS 1.7.8
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "ELAN0415:00@9",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
* Found in BIOS 1.7.8
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "ELAN0415:00@9",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
* Found in BIOS 1.7.7
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "SYNA1202:00@16",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* On the Peaq C1010 2-in-1 INT33FC:00 pin 3 is connected to
|
||||
* a "dolby" button. At the ACPI level an _AEI event-handler
|
||||
* is connected which sets an ACPI variable to 1 on both
|
||||
* edges. This variable can be polled + cleared to 0 using
|
||||
* WMI. But since the variable is set on both edges the WMI
|
||||
* interface is pretty useless even when polling.
|
||||
* So instead the x86-android-tablets code instantiates
|
||||
* a gpio-keys platform device for it.
|
||||
* Ignore the _AEI handler for the pin, so that it is not busy.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_interrupt = "INT33FC:00@3",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
* Found in BIOS 0.35
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/issues/3073
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "GPD"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "PNP0C50:00@8",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from GPIO 11
|
||||
* Found in BIOS 1.04
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/issues/3954
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "Acer Nitro V 14"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_interrupt = "AMDI0030:00@11",
|
||||
},
|
||||
},
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
static int __init acpi_gpio_setup_params(void)
|
||||
{
|
||||
const struct acpi_gpiolib_dmi_quirk *quirk = NULL;
|
||||
const struct dmi_system_id *id;
|
||||
|
||||
id = dmi_first_match(gpiolib_acpi_quirks);
|
||||
if (id)
|
||||
quirk = id->driver_data;
|
||||
|
||||
if (run_edge_events_on_boot < 0) {
|
||||
if (quirk && quirk->no_edge_events_on_boot)
|
||||
run_edge_events_on_boot = 0;
|
||||
else
|
||||
run_edge_events_on_boot = 1;
|
||||
}
|
||||
|
||||
if (ignore_wake == NULL && quirk && quirk->ignore_wake)
|
||||
ignore_wake = quirk->ignore_wake;
|
||||
|
||||
if (ignore_interrupt == NULL && quirk && quirk->ignore_interrupt)
|
||||
ignore_interrupt = quirk->ignore_interrupt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Directly after dmi_setup() which runs as core_initcall() */
|
||||
postcore_initcall(acpi_gpio_setup_params);
|
363
drivers/gpio/gpiolib-acpi-quirks.c
Normal file
363
drivers/gpio/gpiolib-acpi-quirks.c
Normal file
|
@ -0,0 +1,363 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ACPI quirks for GPIO ACPI helpers
|
||||
*
|
||||
* Author: Hans de Goede <hdegoede@redhat.com>
|
||||
*/
|
||||
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/kstrtox.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "gpiolib-acpi.h"
|
||||
|
||||
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 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[,...]]");
|
||||
|
||||
static char *ignore_interrupt;
|
||||
module_param(ignore_interrupt, charp, 0444);
|
||||
MODULE_PARM_DESC(ignore_interrupt,
|
||||
"controller@pin combos on which to ignore interrupt "
|
||||
"ignore_interrupt=controller@pin[,controller@pin[,...]]");
|
||||
|
||||
/*
|
||||
* For GPIO chips which call acpi_gpiochip_request_interrupts() before late_init
|
||||
* (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
|
||||
* late_initcall_sync() handler, so that other builtin drivers can register their
|
||||
* OpRegions before the event handlers can run. This list contains GPIO chips
|
||||
* for which the acpi_gpiochip_request_irqs() call has been deferred.
|
||||
*/
|
||||
static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
|
||||
static LIST_HEAD(acpi_gpio_deferred_req_irqs_list);
|
||||
static bool acpi_gpio_deferred_req_irqs_done;
|
||||
|
||||
bool acpi_gpio_add_to_deferred_list(struct list_head *list)
|
||||
{
|
||||
bool defer;
|
||||
|
||||
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
defer = !acpi_gpio_deferred_req_irqs_done;
|
||||
if (defer)
|
||||
list_add(list, &acpi_gpio_deferred_req_irqs_list);
|
||||
mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
|
||||
return defer;
|
||||
}
|
||||
|
||||
void acpi_gpio_remove_from_deferred_list(struct list_head *list)
|
||||
{
|
||||
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
if (!list_empty(list))
|
||||
list_del_init(list);
|
||||
mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
}
|
||||
|
||||
int acpi_gpio_need_run_edge_events_on_boot(void)
|
||||
{
|
||||
return run_edge_events_on_boot;
|
||||
}
|
||||
|
||||
bool acpi_gpio_in_ignore_list(enum acpi_gpio_ignore_list list,
|
||||
const char *controller_in, unsigned int pin_in)
|
||||
{
|
||||
const char *ignore_list, *controller, *pin_str;
|
||||
unsigned int pin;
|
||||
char *endp;
|
||||
int len;
|
||||
|
||||
switch (list) {
|
||||
case ACPI_GPIO_IGNORE_WAKE:
|
||||
ignore_list = ignore_wake;
|
||||
break;
|
||||
case ACPI_GPIO_IGNORE_INTERRUPT:
|
||||
ignore_list = ignore_interrupt;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
controller = ignore_list;
|
||||
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_...: %s\n", ignore_list);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Run deferred acpi_gpiochip_request_irqs() */
|
||||
static int __init acpi_gpio_handle_deferred_request_irqs(void)
|
||||
{
|
||||
mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
acpi_gpio_process_deferred_list(&acpi_gpio_deferred_req_irqs_list);
|
||||
acpi_gpio_deferred_req_irqs_done = true;
|
||||
mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
/* We must use _sync so that this runs after the first deferred_probe run */
|
||||
late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
|
||||
|
||||
struct acpi_gpiolib_dmi_quirk {
|
||||
bool no_edge_events_on_boot;
|
||||
char *ignore_wake;
|
||||
char *ignore_interrupt;
|
||||
};
|
||||
|
||||
static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
|
||||
{
|
||||
/*
|
||||
* The Minix Neo Z83-4 has a micro-USB-B id-pin handler for
|
||||
* a non existing micro-USB-B connector which puts the HDMI
|
||||
* DDC pins in GPIO mode, breaking HDMI support.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.no_edge_events_on_boot = true,
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* The Terra Pad 1061 has a micro-USB-B id-pin handler, which
|
||||
* instead of controlling the actual micro-USB-B turns the 5V
|
||||
* boost for its USB-A connector off. The actual micro-USB-B
|
||||
* connector is wired for charging only.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.no_edge_events_on_boot = true,
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* The Dell Venue 10 Pro 5055, with Bay Trail SoC + TI PMIC uses an
|
||||
* external embedded-controller connected via I2C + an ACPI GPIO
|
||||
* event handler on INT33FFC:02 pin 12, causing spurious wakeups.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Venue 10 Pro 5055"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "INT33FC:02@12",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"),
|
||||
},
|
||||
.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",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Interrupt storm caused from edge triggered floating pin
|
||||
* Found in BIOS UX325UAZ.300
|
||||
* https://bugzilla.kernel.org/show_bug.cgi?id=216208
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UAZ_UM325UAZ"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_interrupt = "AMDI0030:00@18",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
* Found in BIOS 1.7.8
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "ELAN0415:00@9",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
* Found in BIOS 1.7.8
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "ELAN0415:00@9",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
* Found in BIOS 1.7.7
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "SYNA1202:00@16",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* On the Peaq C1010 2-in-1 INT33FC:00 pin 3 is connected to
|
||||
* a "dolby" button. At the ACPI level an _AEI event-handler
|
||||
* is connected which sets an ACPI variable to 1 on both
|
||||
* edges. This variable can be polled + cleared to 0 using
|
||||
* WMI. But since the variable is set on both edges the WMI
|
||||
* interface is pretty useless even when polling.
|
||||
* So instead the x86-android-tablets code instantiates
|
||||
* a gpio-keys platform device for it.
|
||||
* Ignore the _AEI handler for the pin, so that it is not busy.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_interrupt = "INT33FC:00@3",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from TP_ATTN# pin
|
||||
* Found in BIOS 0.35
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/issues/3073
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "GPD"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "PNP0C50:00@8",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Spurious wakeups from GPIO 11
|
||||
* Found in BIOS 1.04
|
||||
* https://gitlab.freedesktop.org/drm/amd/-/issues/3954
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||
DMI_MATCH(DMI_PRODUCT_FAMILY, "Acer Nitro V 14"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_interrupt = "AMDI0030:00@11",
|
||||
},
|
||||
},
|
||||
{} /* Terminating entry */
|
||||
};
|
||||
|
||||
static int __init acpi_gpio_setup_params(void)
|
||||
{
|
||||
const struct acpi_gpiolib_dmi_quirk *quirk = NULL;
|
||||
const struct dmi_system_id *id;
|
||||
|
||||
id = dmi_first_match(gpiolib_acpi_quirks);
|
||||
if (id)
|
||||
quirk = id->driver_data;
|
||||
|
||||
if (run_edge_events_on_boot < 0) {
|
||||
if (quirk && quirk->no_edge_events_on_boot)
|
||||
run_edge_events_on_boot = 0;
|
||||
else
|
||||
run_edge_events_on_boot = 1;
|
||||
}
|
||||
|
||||
if (ignore_wake == NULL && quirk && quirk->ignore_wake)
|
||||
ignore_wake = quirk->ignore_wake;
|
||||
|
||||
if (ignore_interrupt == NULL && quirk && quirk->ignore_interrupt)
|
||||
ignore_interrupt = quirk->ignore_interrupt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Directly after dmi_setup() which runs as core_initcall() */
|
||||
postcore_initcall(acpi_gpio_setup_params);
|
Loading…
Add table
Reference in a new issue