Commit 61f7f7c8 authored by Hans de Goede's avatar Hans de Goede Committed by Linus Walleij

gpiolib: acpi: Add gpiolib_acpi_run_edge_events_on_boot option and blacklist

Another day; another DSDT bug we need to workaround...

Since commit ca876c74 ("gpiolib-acpi: make sure we trigger edge events
at least once on boot") we call _AEI edge handlers at boot.

In some rare cases this causes problems. One example of this is the Minix
Neo Z83-4 mini PC, this device has a clear DSDT bug where it has some copy
and pasted code for dealing with Micro USB-B connector host/device role
switching, while the mini PC does not even have a micro-USB connector.
This code, which should not be there, messes with the DDC data pin from
the HDMI connector (switching it to GPIO mode) breaking HDMI support.

To avoid problems like this, this commit adds a new
gpiolib_acpi.run_edge_events_on_boot kernel commandline option, which
allows disabling the running of _AEI edge event handlers at boot.

The default value is -1/auto which uses a DMI based blacklist, the initial
version of this blacklist contains the Neo Z83-4 fixing the HDMI breakage.

Cc: stable@vger.kernel.org
Cc: Daniel Drake <drake@endlessm.com>
Cc: Ian W MORRISON <ianwmorrison@gmail.com>
Reported-by: default avatarIan W MORRISON <ianwmorrison@gmail.com>
Suggested-by: default avatarIan W MORRISON <ianwmorrison@gmail.com>
Fixes: ca876c74 ("gpiolib-acpi: make sure we trigger edge events at least once on boot")
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20190827202835.213456-1-hdegoede@redhat.comAcked-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: default avatarIan W MORRISON <ianwmorrison@gmail.com>
Signed-off-by: default avatarLinus Walleij <linus.walleij@linaro.org>
parent 1dea33e8
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* Mika Westerberg <mika.westerberg@linux.intel.com> * Mika Westerberg <mika.westerberg@linux.intel.com>
*/ */
#include <linux/dmi.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
...@@ -19,6 +20,11 @@ ...@@ -19,6 +20,11 @@
#include "gpiolib.h" #include "gpiolib.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");
/** /**
* struct acpi_gpio_event - ACPI GPIO event handler data * struct acpi_gpio_event - ACPI GPIO event handler data
* *
...@@ -170,10 +176,13 @@ static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio, ...@@ -170,10 +176,13 @@ static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
event->irq_requested = true; event->irq_requested = true;
/* Make sure we trigger the initial state of edge-triggered IRQs */ /* Make sure we trigger the initial state of edge-triggered IRQs */
value = gpiod_get_raw_value_cansleep(event->desc); if (run_edge_events_on_boot &&
if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) || (event->irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))) {
((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0)) value = gpiod_get_raw_value_cansleep(event->desc);
event->handler(event->irq, event); if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
event->handler(event->irq, event);
}
} }
static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio) static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
...@@ -1283,3 +1292,28 @@ static int acpi_gpio_handle_deferred_request_irqs(void) ...@@ -1283,3 +1292,28 @@ static int acpi_gpio_handle_deferred_request_irqs(void)
} }
/* We must use _sync so that this runs after the first deferred_probe run */ /* We must use _sync so that this runs after the first deferred_probe run */
late_initcall_sync(acpi_gpio_handle_deferred_request_irqs); late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
static const struct dmi_system_id run_edge_events_on_boot_blacklist[] = {
{
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
}
},
{} /* Terminating entry */
};
static int acpi_gpio_setup_params(void)
{
if (run_edge_events_on_boot < 0) {
if (dmi_check_system(run_edge_events_on_boot_blacklist))
run_edge_events_on_boot = 0;
else
run_edge_events_on_boot = 1;
}
return 0;
}
/* Directly after dmi_setup() which runs as core_initcall() */
postcore_initcall(acpi_gpio_setup_params);
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