Commit 1236568e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v4.18-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

Pull GPIO fix from Linus Walleij:
 "This is a single fix affecting X86 ACPI, and as such pretty important.

  It is going to stable as well and have all the high-notch x86 platform
  developers agreeing on it"

* tag 'gpio-v4.18-3' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio:
  gpiolib-acpi: make sure we trigger edge events at least once on boot
parents 1ffaddd0 ca876c74
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
struct acpi_gpio_event { struct acpi_gpio_event {
struct list_head node; struct list_head node;
struct list_head initial_sync_list;
acpi_handle handle; acpi_handle handle;
unsigned int pin; unsigned int pin;
unsigned int irq; unsigned int irq;
...@@ -50,6 +51,9 @@ struct acpi_gpio_chip { ...@@ -50,6 +51,9 @@ struct acpi_gpio_chip {
struct list_head events; struct list_head events;
}; };
static LIST_HEAD(acpi_gpio_initial_sync_list);
static DEFINE_MUTEX(acpi_gpio_initial_sync_list_lock);
static int acpi_gpiochip_find(struct gpio_chip *gc, void *data) static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
{ {
if (!gc->parent) if (!gc->parent)
...@@ -85,6 +89,21 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin) ...@@ -85,6 +89,21 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
return gpiochip_get_desc(chip, pin); return gpiochip_get_desc(chip, pin);
} }
static void acpi_gpio_add_to_initial_sync_list(struct acpi_gpio_event *event)
{
mutex_lock(&acpi_gpio_initial_sync_list_lock);
list_add(&event->initial_sync_list, &acpi_gpio_initial_sync_list);
mutex_unlock(&acpi_gpio_initial_sync_list_lock);
}
static void acpi_gpio_del_from_initial_sync_list(struct acpi_gpio_event *event)
{
mutex_lock(&acpi_gpio_initial_sync_list_lock);
if (!list_empty(&event->initial_sync_list))
list_del_init(&event->initial_sync_list);
mutex_unlock(&acpi_gpio_initial_sync_list_lock);
}
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data) static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
{ {
struct acpi_gpio_event *event = data; struct acpi_gpio_event *event = data;
...@@ -136,7 +155,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, ...@@ -136,7 +155,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
irq_handler_t handler = NULL; irq_handler_t handler = NULL;
struct gpio_desc *desc; struct gpio_desc *desc;
unsigned long irqflags; unsigned long irqflags;
int ret, pin, irq; int ret, pin, irq, value;
if (!acpi_gpio_get_irq_resource(ares, &agpio)) if (!acpi_gpio_get_irq_resource(ares, &agpio))
return AE_OK; return AE_OK;
...@@ -167,6 +186,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, ...@@ -167,6 +186,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
gpiod_direction_input(desc); gpiod_direction_input(desc);
value = gpiod_get_value(desc);
ret = gpiochip_lock_as_irq(chip, pin); ret = gpiochip_lock_as_irq(chip, pin);
if (ret) { if (ret) {
dev_err(chip->parent, "Failed to lock GPIO as interrupt\n"); dev_err(chip->parent, "Failed to lock GPIO as interrupt\n");
...@@ -208,6 +229,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, ...@@ -208,6 +229,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
event->irq = irq; event->irq = irq;
event->pin = pin; event->pin = pin;
event->desc = desc; event->desc = desc;
INIT_LIST_HEAD(&event->initial_sync_list);
ret = request_threaded_irq(event->irq, NULL, handler, irqflags, ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
"ACPI:Event", event); "ACPI:Event", event);
...@@ -222,6 +244,18 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares, ...@@ -222,6 +244,18 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
enable_irq_wake(irq); enable_irq_wake(irq);
list_add_tail(&event->node, &acpi_gpio->events); list_add_tail(&event->node, &acpi_gpio->events);
/*
* Make sure we trigger the initial state of the IRQ when using RISING
* or FALLING. Note we run the handlers on late_init, the AML code
* may refer to OperationRegions from other (builtin) drivers which
* may be probed after us.
*/
if (handler == acpi_gpio_irq_handler &&
(((irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
((irqflags & IRQF_TRIGGER_FALLING) && value == 0)))
acpi_gpio_add_to_initial_sync_list(event);
return AE_OK; return AE_OK;
fail_free_event: fail_free_event:
...@@ -294,6 +328,8 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip) ...@@ -294,6 +328,8 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) { list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
struct gpio_desc *desc; struct gpio_desc *desc;
acpi_gpio_del_from_initial_sync_list(event);
if (irqd_is_wakeup_set(irq_get_irq_data(event->irq))) if (irqd_is_wakeup_set(irq_get_irq_data(event->irq)))
disable_irq_wake(event->irq); disable_irq_wake(event->irq);
...@@ -1158,3 +1194,21 @@ bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id) ...@@ -1158,3 +1194,21 @@ bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id)
return con_id == NULL; return con_id == NULL;
} }
/* Sync the initial state of handlers after all builtin drivers have probed */
static int acpi_gpio_initial_sync(void)
{
struct acpi_gpio_event *event, *ep;
mutex_lock(&acpi_gpio_initial_sync_list_lock);
list_for_each_entry_safe(event, ep, &acpi_gpio_initial_sync_list,
initial_sync_list) {
acpi_evaluate_object(event->handle, NULL, NULL, NULL);
list_del_init(&event->initial_sync_list);
}
mutex_unlock(&acpi_gpio_initial_sync_list_lock);
return 0;
}
/* We must use _sync so that this runs after the first deferred_probe run */
late_initcall_sync(acpi_gpio_initial_sync);
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