GPIO fixes for v4.18:
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. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJbaHj7AAoJEEEQszewGV1z8tUQAJ3XHPqbXRfrvOrFP0MOw2qj 5UOfNBgNyjpXMb3SLex+zOe80HVh2OjR2HBwZQqd4LVZcCu7ZasewrW17XZFwsN4 IerMIEBNtU8kA6HBvreU+U4owgV9FGEpZz5/Mp0TkjoIpm2XCvrYDhZ3mr+lLx+h +lsMtgTlH5pEb/e/Hck0s9PO9mjzDq0sHlgaGEYKqf2fxUPWIeIw0uJw0fQrKFau muUd044zD5ACIGMYnLpsjoV1WBlDmEzAUHJNeEGcQ7zeXS1LOwGJjc+XfQ3xmoZq WqianLPoLbdP02cNgOJZK2VthQuqSiCg7VBEmYe5T2bLwChRxwQmxYkJH98AXlt/ 367bI4wYcnIwxZJz/dMvb/M5ietY7qGAI6+S+TrWUt+BY1UGy2eLMLKgLLBug/VJ T3S9qVFgYW+MP8Z9dvY0J8ABXKA+mhUd4wWstkq02s2JM7xwTIMd5cx8drh6SBqS FE2dGmaqLK6KJxOk5vWxTiE9plDPcKllzPa5y6asZ8kut+aDBEK8Dbtmbaubjq5N /RJkdgITcjKwIxFcPJx4PBpwStW1YR++rYiHHprxFd4FH2wnlCN7jzD+RME+j+YO MU8U8jeO/8z5cUThawmtBKNZR3lKcp+okDpF9Oozzii6whsVFF+41Y/mWPo7c+ce bNU+BjEH0qi26WLCt+Vm =36C6 -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
1236568ee3
|
@ -25,6 +25,7 @@
|
|||
|
||||
struct acpi_gpio_event {
|
||||
struct list_head node;
|
||||
struct list_head initial_sync_list;
|
||||
acpi_handle handle;
|
||||
unsigned int pin;
|
||||
unsigned int irq;
|
||||
|
@ -50,6 +51,9 @@ struct acpi_gpio_chip {
|
|||
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)
|
||||
{
|
||||
if (!gc->parent)
|
||||
|
@ -85,6 +89,21 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int 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)
|
||||
{
|
||||
struct acpi_gpio_event *event = data;
|
||||
|
@ -136,7 +155,7 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
|||
irq_handler_t handler = NULL;
|
||||
struct gpio_desc *desc;
|
||||
unsigned long irqflags;
|
||||
int ret, pin, irq;
|
||||
int ret, pin, irq, value;
|
||||
|
||||
if (!acpi_gpio_get_irq_resource(ares, &agpio))
|
||||
return AE_OK;
|
||||
|
@ -167,6 +186,8 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
|||
|
||||
gpiod_direction_input(desc);
|
||||
|
||||
value = gpiod_get_value(desc);
|
||||
|
||||
ret = gpiochip_lock_as_irq(chip, pin);
|
||||
if (ret) {
|
||||
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,
|
|||
event->irq = irq;
|
||||
event->pin = pin;
|
||||
event->desc = desc;
|
||||
INIT_LIST_HEAD(&event->initial_sync_list);
|
||||
|
||||
ret = request_threaded_irq(event->irq, NULL, handler, irqflags,
|
||||
"ACPI:Event", event);
|
||||
|
@ -222,6 +244,18 @@ static acpi_status acpi_gpiochip_request_interrupt(struct acpi_resource *ares,
|
|||
enable_irq_wake(irq);
|
||||
|
||||
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;
|
||||
|
||||
fail_free_event:
|
||||
|
@ -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) {
|
||||
struct gpio_desc *desc;
|
||||
|
||||
acpi_gpio_del_from_initial_sync_list(event);
|
||||
|
||||
if (irqd_is_wakeup_set(irq_get_irq_data(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)
|
|||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue