1dae5f0afSLinus Walleij // SPDX-License-Identifier: GPL-2.0
2e29482e8SMathias Nyman /*
3e29482e8SMathias Nyman * ACPI helpers for GPIO API
4e29482e8SMathias Nyman *
5e29482e8SMathias Nyman * Copyright (C) 2012, Intel Corporation
6e29482e8SMathias Nyman * Authors: Mathias Nyman <mathias.nyman@linux.intel.com>
7e29482e8SMathias Nyman * Mika Westerberg <mika.westerberg@linux.intel.com>
8e29482e8SMathias Nyman */
9e29482e8SMathias Nyman
10380c7ba3SAndy Shevchenko #include <linux/acpi.h>
1161f7f7c8SHans de Goede #include <linux/dmi.h>
12e29482e8SMathias Nyman #include <linux/errno.h>
13380c7ba3SAndy Shevchenko #include <linux/export.h>
14380c7ba3SAndy Shevchenko #include <linux/interrupt.h>
15380c7ba3SAndy Shevchenko #include <linux/irq.h>
16380c7ba3SAndy Shevchenko #include <linux/mutex.h>
17380c7ba3SAndy Shevchenko #include <linux/pinctrl/pinctrl.h>
18380c7ba3SAndy Shevchenko
19936e15ddSMika Westerberg #include <linux/gpio/consumer.h>
205ccff852SMika Westerberg #include <linux/gpio/driver.h>
21031ba28aSLinus Walleij #include <linux/gpio/machine.h>
22e29482e8SMathias Nyman
235ccff852SMika Westerberg #include "gpiolib.h"
2477cb907aSAndy Shevchenko #include "gpiolib-acpi.h"
255ccff852SMika Westerberg
2661f7f7c8SHans de Goede static int run_edge_events_on_boot = -1;
2761f7f7c8SHans de Goede module_param(run_edge_events_on_boot, int, 0444);
2861f7f7c8SHans de Goede MODULE_PARM_DESC(run_edge_events_on_boot,
2961f7f7c8SHans de Goede "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto");
3061f7f7c8SHans de Goede
312ccb21f5SHans de Goede static char *ignore_wake;
322ccb21f5SHans de Goede module_param(ignore_wake, charp, 0444);
332ccb21f5SHans de Goede MODULE_PARM_DESC(ignore_wake,
342ccb21f5SHans de Goede "controller@pin combos on which to ignore the ACPI wake flag "
352ccb21f5SHans de Goede "ignore_wake=controller@pin[,controller@pin[,...]]");
362ccb21f5SHans de Goede
376b6af7bdSMario Limonciello static char *ignore_interrupt;
386b6af7bdSMario Limonciello module_param(ignore_interrupt, charp, 0444);
396b6af7bdSMario Limonciello MODULE_PARM_DESC(ignore_interrupt,
406b6af7bdSMario Limonciello "controller@pin combos on which to ignore interrupt "
416b6af7bdSMario Limonciello "ignore_interrupt=controller@pin[,controller@pin[,...]]");
426b6af7bdSMario Limonciello
432ccb21f5SHans de Goede struct acpi_gpiolib_dmi_quirk {
442ccb21f5SHans de Goede bool no_edge_events_on_boot;
452ccb21f5SHans de Goede char *ignore_wake;
466b6af7bdSMario Limonciello char *ignore_interrupt;
472ccb21f5SHans de Goede };
48aa23ca3dSHans de Goede
49e59f5e08SHans de Goede /**
50e59f5e08SHans de Goede * struct acpi_gpio_event - ACPI GPIO event handler data
51e59f5e08SHans de Goede *
52e59f5e08SHans de Goede * @node: list-entry of the events list of the struct acpi_gpio_chip
53e59f5e08SHans de Goede * @handle: handle of ACPI method to execute when the IRQ triggers
5485edcd01SAndy Shevchenko * @handler: handler function to pass to request_irq() when requesting the IRQ
5585edcd01SAndy Shevchenko * @pin: GPIO pin number on the struct gpio_chip
5685edcd01SAndy Shevchenko * @irq: Linux IRQ number for the event, for request_irq() / free_irq()
5785edcd01SAndy Shevchenko * @irqflags: flags to pass to request_irq() when requesting the IRQ
58e59f5e08SHans de Goede * @irq_is_wake: If the ACPI flags indicate the IRQ is a wakeup source
5985edcd01SAndy Shevchenko * @irq_requested:True if request_irq() has been done
6085edcd01SAndy Shevchenko * @desc: struct gpio_desc for the GPIO pin for this event
61e59f5e08SHans de Goede */
624b01a14bSMika Westerberg struct acpi_gpio_event {
637fc7acb9SRafael J. Wysocki struct list_head node;
644b01a14bSMika Westerberg acpi_handle handle;
65e59f5e08SHans de Goede irq_handler_t handler;
667fc7acb9SRafael J. Wysocki unsigned int pin;
677fc7acb9SRafael J. Wysocki unsigned int irq;
68e59f5e08SHans de Goede unsigned long irqflags;
69e59f5e08SHans de Goede bool irq_is_wake;
70e59f5e08SHans de Goede bool irq_requested;
71e46cf32cSAlexandre Courbot struct gpio_desc *desc;
727fc7acb9SRafael J. Wysocki };
737fc7acb9SRafael J. Wysocki
74473ed7beSMika Westerberg struct acpi_gpio_connection {
75473ed7beSMika Westerberg struct list_head node;
76e46cf32cSAlexandre Courbot unsigned int pin;
77473ed7beSMika Westerberg struct gpio_desc *desc;
78473ed7beSMika Westerberg };
79473ed7beSMika Westerberg
80aa92b6f6SMika Westerberg struct acpi_gpio_chip {
81473ed7beSMika Westerberg /*
82473ed7beSMika Westerberg * ACPICA requires that the first field of the context parameter
83473ed7beSMika Westerberg * passed to acpi_install_address_space_handler() is large enough
84473ed7beSMika Westerberg * to hold struct acpi_connection_info.
85473ed7beSMika Westerberg */
86473ed7beSMika Westerberg struct acpi_connection_info conn_info;
87473ed7beSMika Westerberg struct list_head conns;
88473ed7beSMika Westerberg struct mutex conn_lock;
89aa92b6f6SMika Westerberg struct gpio_chip *chip;
904b01a14bSMika Westerberg struct list_head events;
9178d3a92eSHans de Goede struct list_head deferred_req_irqs_list_entry;
92aa92b6f6SMika Westerberg };
93aa92b6f6SMika Westerberg
94b7452d67SDmitry Torokhov /**
95b7452d67SDmitry Torokhov * struct acpi_gpio_info - ACPI GPIO specific information
96b7452d67SDmitry Torokhov * @adev: reference to ACPI device which consumes GPIO resource
97b7452d67SDmitry Torokhov * @flags: GPIO initialization flags
98b7452d67SDmitry Torokhov * @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
99b7452d67SDmitry Torokhov * @pin_config: pin bias as provided by ACPI
100b7452d67SDmitry Torokhov * @polarity: interrupt polarity as provided by ACPI
101b7452d67SDmitry Torokhov * @triggering: triggering type as provided by ACPI
102b7452d67SDmitry Torokhov * @wake_capable: wake capability as provided by ACPI
103b7452d67SDmitry Torokhov * @debounce: debounce timeout as provided by ACPI
104b7452d67SDmitry Torokhov * @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
105b7452d67SDmitry Torokhov */
106b7452d67SDmitry Torokhov struct acpi_gpio_info {
107b7452d67SDmitry Torokhov struct acpi_device *adev;
108b7452d67SDmitry Torokhov enum gpiod_flags flags;
109b7452d67SDmitry Torokhov bool gpioint;
110b7452d67SDmitry Torokhov int pin_config;
111b7452d67SDmitry Torokhov int polarity;
112b7452d67SDmitry Torokhov int triggering;
113b7452d67SDmitry Torokhov bool wake_capable;
114b7452d67SDmitry Torokhov unsigned int debounce;
115b7452d67SDmitry Torokhov unsigned int quirks;
116b7452d67SDmitry Torokhov };
117b7452d67SDmitry Torokhov
11878d3a92eSHans de Goede /*
11985edcd01SAndy Shevchenko * For GPIO chips which call acpi_gpiochip_request_interrupts() before late_init
120e59f5e08SHans de Goede * (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
12185edcd01SAndy Shevchenko * late_initcall_sync() handler, so that other builtin drivers can register their
12285edcd01SAndy Shevchenko * OpRegions before the event handlers can run. This list contains GPIO chips
123e59f5e08SHans de Goede * for which the acpi_gpiochip_request_irqs() call has been deferred.
12478d3a92eSHans de Goede */
12578d3a92eSHans de Goede static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
12678d3a92eSHans de Goede static LIST_HEAD(acpi_gpio_deferred_req_irqs_list);
12778d3a92eSHans de Goede static bool acpi_gpio_deferred_req_irqs_done;
128ca876c74SBenjamin Tissoires
acpi_gpiochip_find(struct gpio_chip * gc,void * data)129e29482e8SMathias Nyman static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
130e29482e8SMathias Nyman {
131cb9f455eSDevyn Liu /* First check the actual GPIO device */
132cb9f455eSDevyn Liu if (device_match_acpi_handle(&gc->gpiodev->dev, data))
133cb9f455eSDevyn Liu return true;
134cb9f455eSDevyn Liu
135cb9f455eSDevyn Liu /*
136cb9f455eSDevyn Liu * When the ACPI device is artificially split to the banks of GPIOs,
137cb9f455eSDevyn Liu * where each of them is represented by a separate GPIO device,
138cb9f455eSDevyn Liu * the firmware node of the physical device may not be shared among
139cb9f455eSDevyn Liu * the banks as they may require different values for the same property,
140cb9f455eSDevyn Liu * e.g., number of GPIOs in a certain bank. In such case the ACPI handle
141cb9f455eSDevyn Liu * of a GPIO device is NULL and can not be used. Hence we have to check
142cb9f455eSDevyn Liu * the parent device to be sure that there is no match before bailing
143cb9f455eSDevyn Liu * out.
144cb9f455eSDevyn Liu */
145cb9f455eSDevyn Liu if (gc->parent)
146cb9f455eSDevyn Liu return device_match_acpi_handle(gc->parent, data);
147cb9f455eSDevyn Liu
148cb9f455eSDevyn Liu return false;
149e29482e8SMathias Nyman }
150e29482e8SMathias Nyman
151e29482e8SMathias Nyman /**
152936e15ddSMika Westerberg * acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API
153e29482e8SMathias Nyman * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
154e29482e8SMathias Nyman * @pin: ACPI GPIO pin number (0-based, controller-relative)
155e29482e8SMathias Nyman *
156f35bbf61SMika Westerberg * Return: GPIO descriptor to use with Linux generic GPIO API, or ERR_PTR
157f35bbf61SMika Westerberg * error value. Specifically returns %-EPROBE_DEFER if the referenced GPIO
15885edcd01SAndy Shevchenko * controller does not have GPIO chip registered at the moment. This is to
159f35bbf61SMika Westerberg * support probe deferral.
160e29482e8SMathias Nyman */
acpi_get_gpiod(char * path,unsigned int pin)1610c2cae09SAndy Shevchenko static struct gpio_desc *acpi_get_gpiod(char *path, unsigned int pin)
162e29482e8SMathias Nyman {
163e29482e8SMathias Nyman struct gpio_chip *chip;
164e29482e8SMathias Nyman acpi_handle handle;
165e29482e8SMathias Nyman acpi_status status;
166e29482e8SMathias Nyman
167e29482e8SMathias Nyman status = acpi_get_handle(NULL, path, &handle);
168e29482e8SMathias Nyman if (ACPI_FAILURE(status))
169936e15ddSMika Westerberg return ERR_PTR(-ENODEV);
170e29482e8SMathias Nyman
171e29482e8SMathias Nyman chip = gpiochip_find(handle, acpi_gpiochip_find);
172e29482e8SMathias Nyman if (!chip)
173f35bbf61SMika Westerberg return ERR_PTR(-EPROBE_DEFER);
174e29482e8SMathias Nyman
17503c4749dSMika Westerberg return gpiochip_get_desc(chip, pin);
176e29482e8SMathias Nyman }
1770d1c28a4SMathias Nyman
17843582f29SDaniel Scally /**
17943582f29SDaniel Scally * acpi_get_and_request_gpiod - Translate ACPI GPIO pin to GPIO descriptor and
18043582f29SDaniel Scally * hold a refcount to the GPIO device.
18143582f29SDaniel Scally * @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
18243582f29SDaniel Scally * @pin: ACPI GPIO pin number (0-based, controller-relative)
18343582f29SDaniel Scally * @label: Label to pass to gpiod_request()
18443582f29SDaniel Scally *
18543582f29SDaniel Scally * This function is a simple pass-through to acpi_get_gpiod(), except that
18643582f29SDaniel Scally * as it is intended for use outside of the GPIO layer (in a similar fashion to
18743582f29SDaniel Scally * gpiod_get_index() for example) it also holds a reference to the GPIO device.
18843582f29SDaniel Scally */
acpi_get_and_request_gpiod(char * path,unsigned int pin,char * label)1890c2cae09SAndy Shevchenko struct gpio_desc *acpi_get_and_request_gpiod(char *path, unsigned int pin, char *label)
19043582f29SDaniel Scally {
19143582f29SDaniel Scally struct gpio_desc *gpio;
19243582f29SDaniel Scally int ret;
19343582f29SDaniel Scally
19443582f29SDaniel Scally gpio = acpi_get_gpiod(path, pin);
19543582f29SDaniel Scally if (IS_ERR(gpio))
19643582f29SDaniel Scally return gpio;
19743582f29SDaniel Scally
19843582f29SDaniel Scally ret = gpiod_request(gpio, label);
19943582f29SDaniel Scally if (ret)
20043582f29SDaniel Scally return ERR_PTR(ret);
20143582f29SDaniel Scally
20243582f29SDaniel Scally return gpio;
20343582f29SDaniel Scally }
20443582f29SDaniel Scally EXPORT_SYMBOL_GPL(acpi_get_and_request_gpiod);
20543582f29SDaniel Scally
acpi_gpio_irq_handler(int irq,void * data)2060d1c28a4SMathias Nyman static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
2070d1c28a4SMathias Nyman {
2086072b9dcSMika Westerberg struct acpi_gpio_event *event = data;
2090d1c28a4SMathias Nyman
2106072b9dcSMika Westerberg acpi_evaluate_object(event->handle, NULL, NULL, NULL);
2110d1c28a4SMathias Nyman
2120d1c28a4SMathias Nyman return IRQ_HANDLED;
2130d1c28a4SMathias Nyman }
2140d1c28a4SMathias Nyman
acpi_gpio_irq_handler_evt(int irq,void * data)2157fc7acb9SRafael J. Wysocki static irqreturn_t acpi_gpio_irq_handler_evt(int irq, void *data)
2167fc7acb9SRafael J. Wysocki {
2174b01a14bSMika Westerberg struct acpi_gpio_event *event = data;
2187fc7acb9SRafael J. Wysocki
2194b01a14bSMika Westerberg acpi_execute_simple_method(event->handle, NULL, event->pin);
2207fc7acb9SRafael J. Wysocki
2217fc7acb9SRafael J. Wysocki return IRQ_HANDLED;
2227fc7acb9SRafael J. Wysocki }
2237fc7acb9SRafael J. Wysocki
acpi_gpio_chip_dh(acpi_handle handle,void * data)224aa92b6f6SMika Westerberg static void acpi_gpio_chip_dh(acpi_handle handle, void *data)
2257fc7acb9SRafael J. Wysocki {
2267fc7acb9SRafael J. Wysocki /* The address of this function is used as a key. */
2277fc7acb9SRafael J. Wysocki }
2287fc7acb9SRafael J. Wysocki
acpi_gpio_get_irq_resource(struct acpi_resource * ares,struct acpi_resource_gpio ** agpio)22925e3ef89SAndy Shevchenko bool acpi_gpio_get_irq_resource(struct acpi_resource *ares,
23025e3ef89SAndy Shevchenko struct acpi_resource_gpio **agpio)
23125e3ef89SAndy Shevchenko {
23225e3ef89SAndy Shevchenko struct acpi_resource_gpio *gpio;
23325e3ef89SAndy Shevchenko
23425e3ef89SAndy Shevchenko if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
23525e3ef89SAndy Shevchenko return false;
23625e3ef89SAndy Shevchenko
23725e3ef89SAndy Shevchenko gpio = &ares->data.gpio;
23825e3ef89SAndy Shevchenko if (gpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_INT)
23925e3ef89SAndy Shevchenko return false;
24025e3ef89SAndy Shevchenko
24125e3ef89SAndy Shevchenko *agpio = gpio;
24225e3ef89SAndy Shevchenko return true;
24325e3ef89SAndy Shevchenko }
24425e3ef89SAndy Shevchenko EXPORT_SYMBOL_GPL(acpi_gpio_get_irq_resource);
24525e3ef89SAndy Shevchenko
246043d7f09SDaniel Scally /**
247043d7f09SDaniel Scally * acpi_gpio_get_io_resource - Fetch details of an ACPI resource if it is a GPIO
248043d7f09SDaniel Scally * I/O resource or return False if not.
249043d7f09SDaniel Scally * @ares: Pointer to the ACPI resource to fetch
250043d7f09SDaniel Scally * @agpio: Pointer to a &struct acpi_resource_gpio to store the output pointer
251043d7f09SDaniel Scally */
acpi_gpio_get_io_resource(struct acpi_resource * ares,struct acpi_resource_gpio ** agpio)252043d7f09SDaniel Scally bool acpi_gpio_get_io_resource(struct acpi_resource *ares,
253043d7f09SDaniel Scally struct acpi_resource_gpio **agpio)
254043d7f09SDaniel Scally {
255043d7f09SDaniel Scally struct acpi_resource_gpio *gpio;
256043d7f09SDaniel Scally
257043d7f09SDaniel Scally if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
258043d7f09SDaniel Scally return false;
259043d7f09SDaniel Scally
260043d7f09SDaniel Scally gpio = &ares->data.gpio;
261043d7f09SDaniel Scally if (gpio->connection_type != ACPI_RESOURCE_GPIO_TYPE_IO)
262043d7f09SDaniel Scally return false;
263043d7f09SDaniel Scally
264043d7f09SDaniel Scally *agpio = gpio;
265043d7f09SDaniel Scally return true;
266043d7f09SDaniel Scally }
267043d7f09SDaniel Scally EXPORT_SYMBOL_GPL(acpi_gpio_get_io_resource);
268043d7f09SDaniel Scally
acpi_gpiochip_request_irq(struct acpi_gpio_chip * acpi_gpio,struct acpi_gpio_event * event)269e59f5e08SHans de Goede static void acpi_gpiochip_request_irq(struct acpi_gpio_chip *acpi_gpio,
270e59f5e08SHans de Goede struct acpi_gpio_event *event)
271e59f5e08SHans de Goede {
272be3dc15fSAndy Shevchenko struct device *parent = acpi_gpio->chip->parent;
273e59f5e08SHans de Goede int ret, value;
274e59f5e08SHans de Goede
275e59f5e08SHans de Goede ret = request_threaded_irq(event->irq, NULL, event->handler,
2766e5d5791SYang Li event->irqflags | IRQF_ONESHOT, "ACPI:Event", event);
277e59f5e08SHans de Goede if (ret) {
278be3dc15fSAndy Shevchenko dev_err(parent, "Failed to setup interrupt handler for %d\n", event->irq);
279e59f5e08SHans de Goede return;
280e59f5e08SHans de Goede }
281e59f5e08SHans de Goede
282e59f5e08SHans de Goede if (event->irq_is_wake)
283e59f5e08SHans de Goede enable_irq_wake(event->irq);
284e59f5e08SHans de Goede
285e59f5e08SHans de Goede event->irq_requested = true;
286e59f5e08SHans de Goede
287e59f5e08SHans de Goede /* Make sure we trigger the initial state of edge-triggered IRQs */
28861f7f7c8SHans de Goede if (run_edge_events_on_boot &&
28961f7f7c8SHans de Goede (event->irqflags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING))) {
290e59f5e08SHans de Goede value = gpiod_get_raw_value_cansleep(event->desc);
291e59f5e08SHans de Goede if (((event->irqflags & IRQF_TRIGGER_RISING) && value == 1) ||
292e59f5e08SHans de Goede ((event->irqflags & IRQF_TRIGGER_FALLING) && value == 0))
293e59f5e08SHans de Goede event->handler(event->irq, event);
294e59f5e08SHans de Goede }
29561f7f7c8SHans de Goede }
296e59f5e08SHans de Goede
acpi_gpiochip_request_irqs(struct acpi_gpio_chip * acpi_gpio)297e59f5e08SHans de Goede static void acpi_gpiochip_request_irqs(struct acpi_gpio_chip *acpi_gpio)
298e59f5e08SHans de Goede {
299e59f5e08SHans de Goede struct acpi_gpio_event *event;
300e59f5e08SHans de Goede
301e59f5e08SHans de Goede list_for_each_entry(event, &acpi_gpio->events, node)
302e59f5e08SHans de Goede acpi_gpiochip_request_irq(acpi_gpio, event);
303e59f5e08SHans de Goede }
304e59f5e08SHans de Goede
3051a81f191SAndy Shevchenko static enum gpiod_flags
acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio * agpio,int polarity)30656f7058aSVasile-Laurentiu Stanimir acpi_gpio_to_gpiod_flags(const struct acpi_resource_gpio *agpio, int polarity)
3071a81f191SAndy Shevchenko {
308bca40480SAndy Shevchenko /* GpioInt() implies input configuration */
309bca40480SAndy Shevchenko if (agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT)
310bca40480SAndy Shevchenko return GPIOD_IN;
311bca40480SAndy Shevchenko
3121a81f191SAndy Shevchenko switch (agpio->io_restriction) {
3131a81f191SAndy Shevchenko case ACPI_IO_RESTRICT_INPUT:
3141a81f191SAndy Shevchenko return GPIOD_IN;
3151a81f191SAndy Shevchenko case ACPI_IO_RESTRICT_OUTPUT:
3161a81f191SAndy Shevchenko /*
3171a81f191SAndy Shevchenko * ACPI GPIO resources don't contain an initial value for the
3181a81f191SAndy Shevchenko * GPIO. Therefore we deduce that value from the pull field
31956f7058aSVasile-Laurentiu Stanimir * and the polarity instead. If the pin is pulled up we assume
32056f7058aSVasile-Laurentiu Stanimir * default to be high, if it is pulled down we assume default
32156f7058aSVasile-Laurentiu Stanimir * to be low, otherwise we leave pin untouched. For active low
32256f7058aSVasile-Laurentiu Stanimir * polarity values will be switched. See also
32356f7058aSVasile-Laurentiu Stanimir * Documentation/firmware-guide/acpi/gpio-properties.rst.
3241a81f191SAndy Shevchenko */
3251a81f191SAndy Shevchenko switch (agpio->pin_config) {
3261a81f191SAndy Shevchenko case ACPI_PIN_CONFIG_PULLUP:
32756f7058aSVasile-Laurentiu Stanimir return polarity == GPIO_ACTIVE_LOW ? GPIOD_OUT_LOW : GPIOD_OUT_HIGH;
3281a81f191SAndy Shevchenko case ACPI_PIN_CONFIG_PULLDOWN:
32956f7058aSVasile-Laurentiu Stanimir return polarity == GPIO_ACTIVE_LOW ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
3301a81f191SAndy Shevchenko default:
3311a81f191SAndy Shevchenko break;
3321a81f191SAndy Shevchenko }
33340b37008SLinus Walleij break;
3341a81f191SAndy Shevchenko default:
3351a81f191SAndy Shevchenko break;
3361a81f191SAndy Shevchenko }
3371a81f191SAndy Shevchenko
3381a81f191SAndy Shevchenko /*
3391a81f191SAndy Shevchenko * Assume that the BIOS has configured the direction and pull
3401a81f191SAndy Shevchenko * accordingly.
3411a81f191SAndy Shevchenko */
3421a81f191SAndy Shevchenko return GPIOD_ASIS;
3431a81f191SAndy Shevchenko }
3441a81f191SAndy Shevchenko
acpi_request_own_gpiod(struct gpio_chip * chip,struct acpi_resource_gpio * agpio,unsigned int index,const char * label)3452e2b496cSAndy Shevchenko static struct gpio_desc *acpi_request_own_gpiod(struct gpio_chip *chip,
3462e2b496cSAndy Shevchenko struct acpi_resource_gpio *agpio,
3472e2b496cSAndy Shevchenko unsigned int index,
3482e2b496cSAndy Shevchenko const char *label)
3492e2b496cSAndy Shevchenko {
3502e2b496cSAndy Shevchenko int polarity = GPIO_ACTIVE_HIGH;
3512e2b496cSAndy Shevchenko enum gpiod_flags flags = acpi_gpio_to_gpiod_flags(agpio, polarity);
3522e2b496cSAndy Shevchenko unsigned int pin = agpio->pin_table[index];
3532e2b496cSAndy Shevchenko struct gpio_desc *desc;
3542e2b496cSAndy Shevchenko int ret;
3552e2b496cSAndy Shevchenko
3562e2b496cSAndy Shevchenko desc = gpiochip_request_own_desc(chip, pin, label, polarity, flags);
3572e2b496cSAndy Shevchenko if (IS_ERR(desc))
3582e2b496cSAndy Shevchenko return desc;
3592e2b496cSAndy Shevchenko
360660c619bSAndy Shevchenko /* ACPI uses hundredths of milliseconds units */
361660c619bSAndy Shevchenko ret = gpio_set_debounce_timeout(desc, agpio->debounce_timeout * 10);
3622e2b496cSAndy Shevchenko if (ret)
363cef0d022SHans de Goede dev_warn(chip->parent,
364cef0d022SHans de Goede "Failed to set debounce-timeout for pin 0x%04X, err %d\n",
365cef0d022SHans de Goede pin, ret);
3662e2b496cSAndy Shevchenko
367cef0d022SHans de Goede return desc;
3682e2b496cSAndy Shevchenko }
3692e2b496cSAndy Shevchenko
acpi_gpio_in_ignore_list(const char * ignore_list,const char * controller_in,unsigned int pin_in)3706b6af7bdSMario Limonciello static bool acpi_gpio_in_ignore_list(const char *ignore_list, const char *controller_in,
3716b6af7bdSMario Limonciello unsigned int pin_in)
3722ccb21f5SHans de Goede {
3732ccb21f5SHans de Goede const char *controller, *pin_str;
3740c2cae09SAndy Shevchenko unsigned int pin;
3752ccb21f5SHans de Goede char *endp;
3760c2cae09SAndy Shevchenko int len;
3772ccb21f5SHans de Goede
3786b6af7bdSMario Limonciello controller = ignore_list;
3792ccb21f5SHans de Goede while (controller) {
3802ccb21f5SHans de Goede pin_str = strchr(controller, '@');
3812ccb21f5SHans de Goede if (!pin_str)
3822ccb21f5SHans de Goede goto err;
3832ccb21f5SHans de Goede
3842ccb21f5SHans de Goede len = pin_str - controller;
3852ccb21f5SHans de Goede if (len == strlen(controller_in) &&
3862ccb21f5SHans de Goede strncmp(controller, controller_in, len) == 0) {
3872ccb21f5SHans de Goede pin = simple_strtoul(pin_str + 1, &endp, 10);
3882ccb21f5SHans de Goede if (*endp != 0 && *endp != ',')
3892ccb21f5SHans de Goede goto err;
3902ccb21f5SHans de Goede
3912ccb21f5SHans de Goede if (pin == pin_in)
3922ccb21f5SHans de Goede return true;
3932ccb21f5SHans de Goede }
3942ccb21f5SHans de Goede
3952ccb21f5SHans de Goede controller = strchr(controller, ',');
3962ccb21f5SHans de Goede if (controller)
3972ccb21f5SHans de Goede controller++;
3982ccb21f5SHans de Goede }
3992ccb21f5SHans de Goede
4002ccb21f5SHans de Goede return false;
4012ccb21f5SHans de Goede err:
4026b6af7bdSMario Limonciello pr_err_once("Error: Invalid value for gpiolib_acpi.ignore_...: %s\n", ignore_list);
4032ccb21f5SHans de Goede return false;
4042ccb21f5SHans de Goede }
4052ccb21f5SHans de Goede
acpi_gpio_irq_is_wake(struct device * parent,const struct acpi_resource_gpio * agpio)4062ccb21f5SHans de Goede static bool acpi_gpio_irq_is_wake(struct device *parent,
4070e3b175fSMario Limonciello const struct acpi_resource_gpio *agpio)
4082ccb21f5SHans de Goede {
4090c2cae09SAndy Shevchenko unsigned int pin = agpio->pin_table[0];
4102ccb21f5SHans de Goede
4112ccb21f5SHans de Goede if (agpio->wake_capable != ACPI_WAKE_CAPABLE)
4122ccb21f5SHans de Goede return false;
4132ccb21f5SHans de Goede
4146b6af7bdSMario Limonciello if (acpi_gpio_in_ignore_list(ignore_wake, dev_name(parent), pin)) {
4150c2cae09SAndy Shevchenko dev_info(parent, "Ignoring wakeup on pin %u\n", pin);
4162ccb21f5SHans de Goede return false;
4172ccb21f5SHans de Goede }
4182ccb21f5SHans de Goede
4192ccb21f5SHans de Goede return true;
4202ccb21f5SHans de Goede }
4212ccb21f5SHans de Goede
422d4fc46f1SHans de Goede /* Always returns AE_OK so that we keep looping over the resources */
acpi_gpiochip_alloc_event(struct acpi_resource * ares,void * context)423e59f5e08SHans de Goede static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
4246072b9dcSMika Westerberg void *context)
4256072b9dcSMika Westerberg {
4266072b9dcSMika Westerberg struct acpi_gpio_chip *acpi_gpio = context;
4276072b9dcSMika Westerberg struct gpio_chip *chip = acpi_gpio->chip;
4286072b9dcSMika Westerberg struct acpi_resource_gpio *agpio;
4296072b9dcSMika Westerberg acpi_handle handle, evt_handle;
4306072b9dcSMika Westerberg struct acpi_gpio_event *event;
4316072b9dcSMika Westerberg irq_handler_t handler = NULL;
4326072b9dcSMika Westerberg struct gpio_desc *desc;
4330c2cae09SAndy Shevchenko unsigned int pin;
4340c2cae09SAndy Shevchenko int ret, irq;
4356072b9dcSMika Westerberg
43625e3ef89SAndy Shevchenko if (!acpi_gpio_get_irq_resource(ares, &agpio))
4376072b9dcSMika Westerberg return AE_OK;
4386072b9dcSMika Westerberg
43958383c78SLinus Walleij handle = ACPI_HANDLE(chip->parent);
4406072b9dcSMika Westerberg pin = agpio->pin_table[0];
4416072b9dcSMika Westerberg
4426072b9dcSMika Westerberg if (pin <= 255) {
443213d266eSLinus Torvalds char ev_name[8];
444213d266eSLinus Torvalds sprintf(ev_name, "_%c%02X",
4456072b9dcSMika Westerberg agpio->triggering == ACPI_EDGE_SENSITIVE ? 'E' : 'L',
4466072b9dcSMika Westerberg pin);
4476072b9dcSMika Westerberg if (ACPI_SUCCESS(acpi_get_handle(handle, ev_name, &evt_handle)))
4486072b9dcSMika Westerberg handler = acpi_gpio_irq_handler;
4496072b9dcSMika Westerberg }
4506072b9dcSMika Westerberg if (!handler) {
4516072b9dcSMika Westerberg if (ACPI_SUCCESS(acpi_get_handle(handle, "_EVT", &evt_handle)))
4526072b9dcSMika Westerberg handler = acpi_gpio_irq_handler_evt;
4536072b9dcSMika Westerberg }
4546072b9dcSMika Westerberg if (!handler)
455c06632eaSHans de Goede return AE_OK;
4566072b9dcSMika Westerberg
4572e2b496cSAndy Shevchenko desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event");
4586072b9dcSMika Westerberg if (IS_ERR(desc)) {
4593f86a7e0SHans de Goede dev_err(chip->parent,
4603f86a7e0SHans de Goede "Failed to request GPIO for pin 0x%04X, err %ld\n",
4613f86a7e0SHans de Goede pin, PTR_ERR(desc));
462d4fc46f1SHans de Goede return AE_OK;
4636072b9dcSMika Westerberg }
4646072b9dcSMika Westerberg
465e3a2e878SAlexandre Courbot ret = gpiochip_lock_as_irq(chip, pin);
4666072b9dcSMika Westerberg if (ret) {
4673f86a7e0SHans de Goede dev_err(chip->parent,
4683f86a7e0SHans de Goede "Failed to lock GPIO pin 0x%04X as interrupt, err %d\n",
4693f86a7e0SHans de Goede pin, ret);
4706072b9dcSMika Westerberg goto fail_free_desc;
4716072b9dcSMika Westerberg }
4726072b9dcSMika Westerberg
4736072b9dcSMika Westerberg irq = gpiod_to_irq(desc);
4746072b9dcSMika Westerberg if (irq < 0) {
4753f86a7e0SHans de Goede dev_err(chip->parent,
4763f86a7e0SHans de Goede "Failed to translate GPIO pin 0x%04X to IRQ, err %d\n",
4773f86a7e0SHans de Goede pin, irq);
4786072b9dcSMika Westerberg goto fail_unlock_irq;
4796072b9dcSMika Westerberg }
4806072b9dcSMika Westerberg
4816b6af7bdSMario Limonciello if (acpi_gpio_in_ignore_list(ignore_interrupt, dev_name(chip->parent), pin)) {
4826b6af7bdSMario Limonciello dev_info(chip->parent, "Ignoring interrupt on pin %u\n", pin);
4836b6af7bdSMario Limonciello return AE_OK;
4846b6af7bdSMario Limonciello }
4856b6af7bdSMario Limonciello
486e59f5e08SHans de Goede event = kzalloc(sizeof(*event), GFP_KERNEL);
487e59f5e08SHans de Goede if (!event)
488e59f5e08SHans de Goede goto fail_unlock_irq;
489e59f5e08SHans de Goede
490e59f5e08SHans de Goede event->irqflags = IRQF_ONESHOT;
4916072b9dcSMika Westerberg if (agpio->triggering == ACPI_LEVEL_SENSITIVE) {
4926072b9dcSMika Westerberg if (agpio->polarity == ACPI_ACTIVE_HIGH)
493e59f5e08SHans de Goede event->irqflags |= IRQF_TRIGGER_HIGH;
4946072b9dcSMika Westerberg else
495e59f5e08SHans de Goede event->irqflags |= IRQF_TRIGGER_LOW;
4966072b9dcSMika Westerberg } else {
4976072b9dcSMika Westerberg switch (agpio->polarity) {
4986072b9dcSMika Westerberg case ACPI_ACTIVE_HIGH:
499e59f5e08SHans de Goede event->irqflags |= IRQF_TRIGGER_RISING;
5006072b9dcSMika Westerberg break;
5016072b9dcSMika Westerberg case ACPI_ACTIVE_LOW:
502e59f5e08SHans de Goede event->irqflags |= IRQF_TRIGGER_FALLING;
5036072b9dcSMika Westerberg break;
5046072b9dcSMika Westerberg default:
505e59f5e08SHans de Goede event->irqflags |= IRQF_TRIGGER_RISING |
5066072b9dcSMika Westerberg IRQF_TRIGGER_FALLING;
5076072b9dcSMika Westerberg break;
5086072b9dcSMika Westerberg }
5096072b9dcSMika Westerberg }
5106072b9dcSMika Westerberg
5116072b9dcSMika Westerberg event->handle = evt_handle;
512e59f5e08SHans de Goede event->handler = handler;
5136072b9dcSMika Westerberg event->irq = irq;
5142ccb21f5SHans de Goede event->irq_is_wake = acpi_gpio_irq_is_wake(chip->parent, agpio);
5156072b9dcSMika Westerberg event->pin = pin;
516e46cf32cSAlexandre Courbot event->desc = desc;
5176072b9dcSMika Westerberg
5186072b9dcSMika Westerberg list_add_tail(&event->node, &acpi_gpio->events);
519ca876c74SBenjamin Tissoires
5206072b9dcSMika Westerberg return AE_OK;
5216072b9dcSMika Westerberg
5226072b9dcSMika Westerberg fail_unlock_irq:
523e3a2e878SAlexandre Courbot gpiochip_unlock_as_irq(chip, pin);
5246072b9dcSMika Westerberg fail_free_desc:
5256072b9dcSMika Westerberg gpiochip_free_own_desc(desc);
5266072b9dcSMika Westerberg
527d4fc46f1SHans de Goede return AE_OK;
5286072b9dcSMika Westerberg }
5296072b9dcSMika Westerberg
5300d1c28a4SMathias Nyman /**
5310d1c28a4SMathias Nyman * acpi_gpiochip_request_interrupts() - Register isr for gpio chip ACPI events
532afa82fabSMika Westerberg * @chip: GPIO chip
5330d1c28a4SMathias Nyman *
5340d1c28a4SMathias Nyman * ACPI5 platforms can use GPIO signaled ACPI events. These GPIO interrupts are
5350d1c28a4SMathias Nyman * handled by ACPI event methods which need to be called from the GPIO
53685edcd01SAndy Shevchenko * chip's interrupt handler. acpi_gpiochip_request_interrupts() finds out which
53785edcd01SAndy Shevchenko * GPIO pins have ACPI event methods and assigns interrupt handlers that calls
53885edcd01SAndy Shevchenko * the ACPI event methods for those pins.
5390d1c28a4SMathias Nyman */
acpi_gpiochip_request_interrupts(struct gpio_chip * chip)540afa82fabSMika Westerberg void acpi_gpiochip_request_interrupts(struct gpio_chip *chip)
5410d1c28a4SMathias Nyman {
542afa82fabSMika Westerberg struct acpi_gpio_chip *acpi_gpio;
543afa82fabSMika Westerberg acpi_handle handle;
544afa82fabSMika Westerberg acpi_status status;
54578d3a92eSHans de Goede bool defer;
5460d1c28a4SMathias Nyman
54758383c78SLinus Walleij if (!chip->parent || !chip->to_irq)
548afa82fabSMika Westerberg return;
549afa82fabSMika Westerberg
55058383c78SLinus Walleij handle = ACPI_HANDLE(chip->parent);
551afa82fabSMika Westerberg if (!handle)
552afa82fabSMika Westerberg return;
553afa82fabSMika Westerberg
554afa82fabSMika Westerberg status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
555afa82fabSMika Westerberg if (ACPI_FAILURE(status))
5560d1c28a4SMathias Nyman return;
5570d1c28a4SMathias Nyman
5585adc4093SHans de Goede if (acpi_quirk_skip_gpio_event_handlers())
5595adc4093SHans de Goede return;
5605adc4093SHans de Goede
561eac001bfSXiang Yang acpi_walk_resources(handle, METHOD_NAME__AEI,
562e59f5e08SHans de Goede acpi_gpiochip_alloc_event, acpi_gpio);
563e59f5e08SHans de Goede
56478d3a92eSHans de Goede mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
56578d3a92eSHans de Goede defer = !acpi_gpio_deferred_req_irqs_done;
56678d3a92eSHans de Goede if (defer)
56778d3a92eSHans de Goede list_add(&acpi_gpio->deferred_req_irqs_list_entry,
56878d3a92eSHans de Goede &acpi_gpio_deferred_req_irqs_list);
56978d3a92eSHans de Goede mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
57078d3a92eSHans de Goede
57178d3a92eSHans de Goede if (defer)
57278d3a92eSHans de Goede return;
57378d3a92eSHans de Goede
574e59f5e08SHans de Goede acpi_gpiochip_request_irqs(acpi_gpio);
5750d1c28a4SMathias Nyman }
5762b528fffSHanjun Guo EXPORT_SYMBOL_GPL(acpi_gpiochip_request_interrupts);
5777fc7acb9SRafael J. Wysocki
57870b53411SMika Westerberg /**
5796072b9dcSMika Westerberg * acpi_gpiochip_free_interrupts() - Free GPIO ACPI event interrupts.
580afa82fabSMika Westerberg * @chip: GPIO chip
58170b53411SMika Westerberg *
5826072b9dcSMika Westerberg * Free interrupts associated with GPIO ACPI event method for the given
5836072b9dcSMika Westerberg * GPIO chip.
58470b53411SMika Westerberg */
acpi_gpiochip_free_interrupts(struct gpio_chip * chip)585afa82fabSMika Westerberg void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
58670b53411SMika Westerberg {
587afa82fabSMika Westerberg struct acpi_gpio_chip *acpi_gpio;
5884b01a14bSMika Westerberg struct acpi_gpio_event *event, *ep;
589afa82fabSMika Westerberg acpi_handle handle;
590afa82fabSMika Westerberg acpi_status status;
59170b53411SMika Westerberg
59258383c78SLinus Walleij if (!chip->parent || !chip->to_irq)
593afa82fabSMika Westerberg return;
594afa82fabSMika Westerberg
59558383c78SLinus Walleij handle = ACPI_HANDLE(chip->parent);
596afa82fabSMika Westerberg if (!handle)
597afa82fabSMika Westerberg return;
598afa82fabSMika Westerberg
599afa82fabSMika Westerberg status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
600afa82fabSMika Westerberg if (ACPI_FAILURE(status))
60170b53411SMika Westerberg return;
60270b53411SMika Westerberg
60378d3a92eSHans de Goede mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
60478d3a92eSHans de Goede if (!list_empty(&acpi_gpio->deferred_req_irqs_list_entry))
60578d3a92eSHans de Goede list_del_init(&acpi_gpio->deferred_req_irqs_list_entry);
60678d3a92eSHans de Goede mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
60778d3a92eSHans de Goede
6084b01a14bSMika Westerberg list_for_each_entry_safe_reverse(event, ep, &acpi_gpio->events, node) {
609e59f5e08SHans de Goede if (event->irq_requested) {
610e59f5e08SHans de Goede if (event->irq_is_wake)
6118a146fbeSHans de Goede disable_irq_wake(event->irq);
6128a146fbeSHans de Goede
6136072b9dcSMika Westerberg free_irq(event->irq, event);
614e59f5e08SHans de Goede }
615e59f5e08SHans de Goede
616e3a2e878SAlexandre Courbot gpiochip_unlock_as_irq(chip, event->pin);
61786252329SHans de Goede gpiochip_free_own_desc(event->desc);
6184b01a14bSMika Westerberg list_del(&event->node);
6194b01a14bSMika Westerberg kfree(event);
62070b53411SMika Westerberg }
62170b53411SMika Westerberg }
6222b528fffSHanjun Guo EXPORT_SYMBOL_GPL(acpi_gpiochip_free_interrupts);
62370b53411SMika Westerberg
acpi_dev_add_driver_gpios(struct acpi_device * adev,const struct acpi_gpio_mapping * gpios)624f028d524SRafael J. Wysocki int acpi_dev_add_driver_gpios(struct acpi_device *adev,
625f028d524SRafael J. Wysocki const struct acpi_gpio_mapping *gpios)
626f028d524SRafael J. Wysocki {
627f028d524SRafael J. Wysocki if (adev && gpios) {
628f028d524SRafael J. Wysocki adev->driver_gpios = gpios;
629f028d524SRafael J. Wysocki return 0;
630f028d524SRafael J. Wysocki }
631f028d524SRafael J. Wysocki return -EINVAL;
632f028d524SRafael J. Wysocki }
633f028d524SRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
634f028d524SRafael J. Wysocki
acpi_dev_remove_driver_gpios(struct acpi_device * adev)6352838bf94SAndy Shevchenko void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
6362838bf94SAndy Shevchenko {
6372838bf94SAndy Shevchenko if (adev)
6382838bf94SAndy Shevchenko adev->driver_gpios = NULL;
6392838bf94SAndy Shevchenko }
6402838bf94SAndy Shevchenko EXPORT_SYMBOL_GPL(acpi_dev_remove_driver_gpios);
6412838bf94SAndy Shevchenko
acpi_dev_release_driver_gpios(void * adev)6422ff64a84SAndy Shevchenko static void acpi_dev_release_driver_gpios(void *adev)
64385c73d50SAndy Shevchenko {
6442ff64a84SAndy Shevchenko acpi_dev_remove_driver_gpios(adev);
64585c73d50SAndy Shevchenko }
64685c73d50SAndy Shevchenko
devm_acpi_dev_add_driver_gpios(struct device * dev,const struct acpi_gpio_mapping * gpios)64785c73d50SAndy Shevchenko int devm_acpi_dev_add_driver_gpios(struct device *dev,
64885c73d50SAndy Shevchenko const struct acpi_gpio_mapping *gpios)
64985c73d50SAndy Shevchenko {
6502ff64a84SAndy Shevchenko struct acpi_device *adev = ACPI_COMPANION(dev);
65185c73d50SAndy Shevchenko int ret;
65285c73d50SAndy Shevchenko
6532ff64a84SAndy Shevchenko ret = acpi_dev_add_driver_gpios(adev, gpios);
6542ff64a84SAndy Shevchenko if (ret)
65585c73d50SAndy Shevchenko return ret;
6562ff64a84SAndy Shevchenko
6572ff64a84SAndy Shevchenko return devm_add_action_or_reset(dev, acpi_dev_release_driver_gpios, adev);
65885c73d50SAndy Shevchenko }
65985c73d50SAndy Shevchenko EXPORT_SYMBOL_GPL(devm_acpi_dev_add_driver_gpios);
66085c73d50SAndy Shevchenko
acpi_get_driver_gpio_data(struct acpi_device * adev,const char * name,int index,struct fwnode_reference_args * args,unsigned int * quirks)661f028d524SRafael J. Wysocki static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
662f028d524SRafael J. Wysocki const char *name, int index,
663977d5ad3SSakari Ailus struct fwnode_reference_args *args,
664ce0929d2SAndy Shevchenko unsigned int *quirks)
665f028d524SRafael J. Wysocki {
666f028d524SRafael J. Wysocki const struct acpi_gpio_mapping *gm;
667f028d524SRafael J. Wysocki
668af3b462aSAndy Shevchenko if (!adev || !adev->driver_gpios)
669f028d524SRafael J. Wysocki return false;
670f028d524SRafael J. Wysocki
671f028d524SRafael J. Wysocki for (gm = adev->driver_gpios; gm->name; gm++)
672f028d524SRafael J. Wysocki if (!strcmp(name, gm->name) && gm->data && index < gm->size) {
673f028d524SRafael J. Wysocki const struct acpi_gpio_params *par = gm->data + index;
674f028d524SRafael J. Wysocki
675977d5ad3SSakari Ailus args->fwnode = acpi_fwnode_handle(adev);
676f028d524SRafael J. Wysocki args->args[0] = par->crs_entry_index;
677f028d524SRafael J. Wysocki args->args[1] = par->line_index;
678f028d524SRafael J. Wysocki args->args[2] = par->active_low;
679f028d524SRafael J. Wysocki args->nargs = 3;
680ce0929d2SAndy Shevchenko
681ce0929d2SAndy Shevchenko *quirks = gm->quirks;
682f028d524SRafael J. Wysocki return true;
683f028d524SRafael J. Wysocki }
684f028d524SRafael J. Wysocki
685f028d524SRafael J. Wysocki return false;
686f028d524SRafael J. Wysocki }
687f028d524SRafael J. Wysocki
6885c34b6c1SAndy Shevchenko static int
__acpi_gpio_update_gpiod_flags(enum gpiod_flags * flags,enum gpiod_flags update)6895c34b6c1SAndy Shevchenko __acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, enum gpiod_flags update)
690a31f5c3aSAndy Shevchenko {
69172893f0cSHans de Goede const enum gpiod_flags mask =
69272893f0cSHans de Goede GPIOD_FLAGS_BIT_DIR_SET | GPIOD_FLAGS_BIT_DIR_OUT |
69372893f0cSHans de Goede GPIOD_FLAGS_BIT_DIR_VAL;
694a31f5c3aSAndy Shevchenko int ret = 0;
695a31f5c3aSAndy Shevchenko
696a31f5c3aSAndy Shevchenko /*
697a31f5c3aSAndy Shevchenko * Check if the BIOS has IoRestriction with explicitly set direction
698a31f5c3aSAndy Shevchenko * and update @flags accordingly. Otherwise use whatever caller asked
699a31f5c3aSAndy Shevchenko * for.
700a31f5c3aSAndy Shevchenko */
701a31f5c3aSAndy Shevchenko if (update & GPIOD_FLAGS_BIT_DIR_SET) {
702a31f5c3aSAndy Shevchenko enum gpiod_flags diff = *flags ^ update;
703a31f5c3aSAndy Shevchenko
704a31f5c3aSAndy Shevchenko /*
705a31f5c3aSAndy Shevchenko * Check if caller supplied incompatible GPIO initialization
706a31f5c3aSAndy Shevchenko * flags.
707a31f5c3aSAndy Shevchenko *
708a31f5c3aSAndy Shevchenko * Return %-EINVAL to notify that firmware has different
709a31f5c3aSAndy Shevchenko * settings and we are going to use them.
710a31f5c3aSAndy Shevchenko */
711a31f5c3aSAndy Shevchenko if (((*flags & GPIOD_FLAGS_BIT_DIR_SET) && (diff & GPIOD_FLAGS_BIT_DIR_OUT)) ||
712a31f5c3aSAndy Shevchenko ((*flags & GPIOD_FLAGS_BIT_DIR_OUT) && (diff & GPIOD_FLAGS_BIT_DIR_VAL)))
713a31f5c3aSAndy Shevchenko ret = -EINVAL;
71472893f0cSHans de Goede *flags = (*flags & ~mask) | (update & mask);
715a31f5c3aSAndy Shevchenko }
716a31f5c3aSAndy Shevchenko return ret;
717a31f5c3aSAndy Shevchenko }
718a31f5c3aSAndy Shevchenko
acpi_gpio_update_gpiod_flags(enum gpiod_flags * flags,struct acpi_gpio_info * info)719b7452d67SDmitry Torokhov static int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
720b7452d67SDmitry Torokhov struct acpi_gpio_info *info)
7215c34b6c1SAndy Shevchenko {
7225c34b6c1SAndy Shevchenko struct device *dev = &info->adev->dev;
7231b2ca32aSAndy Shevchenko enum gpiod_flags old = *flags;
7245c34b6c1SAndy Shevchenko int ret;
7255c34b6c1SAndy Shevchenko
7261b2ca32aSAndy Shevchenko ret = __acpi_gpio_update_gpiod_flags(&old, info->flags);
7271b2ca32aSAndy Shevchenko if (info->quirks & ACPI_GPIO_QUIRK_NO_IO_RESTRICTION) {
7281b2ca32aSAndy Shevchenko if (ret)
7291b2ca32aSAndy Shevchenko dev_warn(dev, FW_BUG "GPIO not in correct mode, fixing\n");
7301b2ca32aSAndy Shevchenko } else {
7315c34b6c1SAndy Shevchenko if (ret)
7325c34b6c1SAndy Shevchenko dev_dbg(dev, "Override GPIO initialization flags\n");
7331b2ca32aSAndy Shevchenko *flags = old;
7341b2ca32aSAndy Shevchenko }
7355c34b6c1SAndy Shevchenko
7365c34b6c1SAndy Shevchenko return ret;
7375c34b6c1SAndy Shevchenko }
7385c34b6c1SAndy Shevchenko
acpi_gpio_update_gpiod_lookup_flags(unsigned long * lookupflags,struct acpi_gpio_info * info)739b7452d67SDmitry Torokhov static int acpi_gpio_update_gpiod_lookup_flags(unsigned long *lookupflags,
740606be344SAndy Shevchenko struct acpi_gpio_info *info)
741606be344SAndy Shevchenko {
7422d3b6db1SAndy Shevchenko switch (info->pin_config) {
7432d3b6db1SAndy Shevchenko case ACPI_PIN_CONFIG_PULLUP:
7442d3b6db1SAndy Shevchenko *lookupflags |= GPIO_PULL_UP;
7452d3b6db1SAndy Shevchenko break;
7462d3b6db1SAndy Shevchenko case ACPI_PIN_CONFIG_PULLDOWN:
7472d3b6db1SAndy Shevchenko *lookupflags |= GPIO_PULL_DOWN;
7482d3b6db1SAndy Shevchenko break;
7496fd03f02SNuno Sá case ACPI_PIN_CONFIG_NOPULL:
7506fd03f02SNuno Sá *lookupflags |= GPIO_PULL_DISABLE;
7516fd03f02SNuno Sá break;
7522d3b6db1SAndy Shevchenko default:
7532d3b6db1SAndy Shevchenko break;
7542d3b6db1SAndy Shevchenko }
7552d3b6db1SAndy Shevchenko
756606be344SAndy Shevchenko if (info->polarity == GPIO_ACTIVE_LOW)
757606be344SAndy Shevchenko *lookupflags |= GPIO_ACTIVE_LOW;
758606be344SAndy Shevchenko
759606be344SAndy Shevchenko return 0;
760606be344SAndy Shevchenko }
761606be344SAndy Shevchenko
76212028d2dSMika Westerberg struct acpi_gpio_lookup {
76312028d2dSMika Westerberg struct acpi_gpio_info info;
76412028d2dSMika Westerberg int index;
76574301f27SAndy Shevchenko u16 pin_index;
766d079524aSRafael J. Wysocki bool active_low;
767936e15ddSMika Westerberg struct gpio_desc *desc;
76812028d2dSMika Westerberg int n;
76912028d2dSMika Westerberg };
77012028d2dSMika Westerberg
acpi_populate_gpio_lookup(struct acpi_resource * ares,void * data)771031ba28aSLinus Walleij static int acpi_populate_gpio_lookup(struct acpi_resource *ares, void *data)
77212028d2dSMika Westerberg {
77312028d2dSMika Westerberg struct acpi_gpio_lookup *lookup = data;
77412028d2dSMika Westerberg
77512028d2dSMika Westerberg if (ares->type != ACPI_RESOURCE_TYPE_GPIO)
77612028d2dSMika Westerberg return 1;
77712028d2dSMika Westerberg
7784d1f7a6eSAndy Shevchenko if (!lookup->desc) {
77912028d2dSMika Westerberg const struct acpi_resource_gpio *agpio = &ares->data.gpio;
7804d1f7a6eSAndy Shevchenko bool gpioint = agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
78162d5247dSAndy Shevchenko struct gpio_desc *desc;
78274301f27SAndy Shevchenko u16 pin_index;
7830d9a693cSMika Westerberg
7844d1f7a6eSAndy Shevchenko if (lookup->info.quirks & ACPI_GPIO_QUIRK_ONLY_GPIOIO && gpioint)
7854d1f7a6eSAndy Shevchenko lookup->index++;
7864d1f7a6eSAndy Shevchenko
7874d1f7a6eSAndy Shevchenko if (lookup->n++ != lookup->index)
7884d1f7a6eSAndy Shevchenko return 1;
7894d1f7a6eSAndy Shevchenko
7904d1f7a6eSAndy Shevchenko pin_index = lookup->pin_index;
7910d9a693cSMika Westerberg if (pin_index >= agpio->pin_table_length)
7920d9a693cSMika Westerberg return 1;
79312028d2dSMika Westerberg
79462d5247dSAndy Shevchenko if (lookup->info.quirks & ACPI_GPIO_QUIRK_ABSOLUTE_NUMBER)
79562d5247dSAndy Shevchenko desc = gpio_to_desc(agpio->pin_table[pin_index]);
79662d5247dSAndy Shevchenko else
79762d5247dSAndy Shevchenko desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
7980d9a693cSMika Westerberg agpio->pin_table[pin_index]);
79962d5247dSAndy Shevchenko lookup->desc = desc;
8002d3b6db1SAndy Shevchenko lookup->info.pin_config = agpio->pin_config;
8018dcb7a15SAndy Shevchenko lookup->info.debounce = agpio->debounce_timeout;
8024d1f7a6eSAndy Shevchenko lookup->info.gpioint = gpioint;
8030e3b175fSMario Limonciello lookup->info.wake_capable = acpi_gpio_irq_is_wake(&lookup->info.adev->dev, agpio);
8040d9a693cSMika Westerberg
8050d9a693cSMika Westerberg /*
806e567c35fSAndy Shevchenko * Polarity and triggering are only specified for GpioInt
807e567c35fSAndy Shevchenko * resource.
80852044723SChristophe RICARD * Note: we expect here:
80952044723SChristophe RICARD * - ACPI_ACTIVE_LOW == GPIO_ACTIVE_LOW
81052044723SChristophe RICARD * - ACPI_ACTIVE_HIGH == GPIO_ACTIVE_HIGH
8110d9a693cSMika Westerberg */
81252044723SChristophe RICARD if (lookup->info.gpioint) {
81352044723SChristophe RICARD lookup->info.polarity = agpio->polarity;
81452044723SChristophe RICARD lookup->info.triggering = agpio->triggering;
815a31f5c3aSAndy Shevchenko } else {
816f67a6c11SAndy Shevchenko lookup->info.polarity = lookup->active_low;
81752044723SChristophe RICARD }
818bca40480SAndy Shevchenko
819bca40480SAndy Shevchenko lookup->info.flags = acpi_gpio_to_gpiod_flags(agpio, lookup->info.polarity);
82012028d2dSMika Westerberg }
82112028d2dSMika Westerberg
82212028d2dSMika Westerberg return 1;
82312028d2dSMika Westerberg }
82412028d2dSMika Westerberg
acpi_gpio_resource_lookup(struct acpi_gpio_lookup * lookup,struct acpi_gpio_info * info)825d079524aSRafael J. Wysocki static int acpi_gpio_resource_lookup(struct acpi_gpio_lookup *lookup,
826d079524aSRafael J. Wysocki struct acpi_gpio_info *info)
827d079524aSRafael J. Wysocki {
8285870cff4SAndy Shevchenko struct acpi_device *adev = lookup->info.adev;
829d079524aSRafael J. Wysocki struct list_head res_list;
830d079524aSRafael J. Wysocki int ret;
831d079524aSRafael J. Wysocki
832d079524aSRafael J. Wysocki INIT_LIST_HEAD(&res_list);
833d079524aSRafael J. Wysocki
8345870cff4SAndy Shevchenko ret = acpi_dev_get_resources(adev, &res_list,
835031ba28aSLinus Walleij acpi_populate_gpio_lookup,
836d079524aSRafael J. Wysocki lookup);
837d079524aSRafael J. Wysocki if (ret < 0)
838d079524aSRafael J. Wysocki return ret;
839d079524aSRafael J. Wysocki
840d079524aSRafael J. Wysocki acpi_dev_free_resource_list(&res_list);
841d079524aSRafael J. Wysocki
842d079524aSRafael J. Wysocki if (!lookup->desc)
843d079524aSRafael J. Wysocki return -ENOENT;
844d079524aSRafael J. Wysocki
845f67a6c11SAndy Shevchenko if (info)
846d079524aSRafael J. Wysocki *info = lookup->info;
847d079524aSRafael J. Wysocki return 0;
848d079524aSRafael J. Wysocki }
849d079524aSRafael J. Wysocki
acpi_gpio_property_lookup(struct fwnode_handle * fwnode,const char * propname,int index,struct acpi_gpio_lookup * lookup)850504a3374SRafael J. Wysocki static int acpi_gpio_property_lookup(struct fwnode_handle *fwnode,
851d079524aSRafael J. Wysocki const char *propname, int index,
852d079524aSRafael J. Wysocki struct acpi_gpio_lookup *lookup)
853d079524aSRafael J. Wysocki {
854977d5ad3SSakari Ailus struct fwnode_reference_args args;
855ce0929d2SAndy Shevchenko unsigned int quirks = 0;
856d079524aSRafael J. Wysocki int ret;
857d079524aSRafael J. Wysocki
858d079524aSRafael J. Wysocki memset(&args, 0, sizeof(args));
8596f7194a1SMika Westerberg ret = __acpi_node_get_property_reference(fwnode, propname, index, 3,
8606f7194a1SMika Westerberg &args);
861504a3374SRafael J. Wysocki if (ret) {
862af3b462aSAndy Shevchenko struct acpi_device *adev;
863504a3374SRafael J. Wysocki
864af3b462aSAndy Shevchenko adev = to_acpi_device_node(fwnode);
865af3b462aSAndy Shevchenko if (!acpi_get_driver_gpio_data(adev, propname, index, &args, &quirks))
866504a3374SRafael J. Wysocki return ret;
867504a3374SRafael J. Wysocki }
868d079524aSRafael J. Wysocki /*
869d079524aSRafael J. Wysocki * The property was found and resolved, so need to lookup the GPIO based
870d079524aSRafael J. Wysocki * on returned args.
871d079524aSRafael J. Wysocki */
872977d5ad3SSakari Ailus if (!to_acpi_device_node(args.fwnode))
873977d5ad3SSakari Ailus return -EINVAL;
8746f7194a1SMika Westerberg if (args.nargs != 3)
8756f7194a1SMika Westerberg return -EPROTO;
8766f7194a1SMika Westerberg
877d079524aSRafael J. Wysocki lookup->index = args.args[0];
878d079524aSRafael J. Wysocki lookup->pin_index = args.args[1];
879d079524aSRafael J. Wysocki lookup->active_low = !!args.args[2];
8806f7194a1SMika Westerberg
881977d5ad3SSakari Ailus lookup->info.adev = to_acpi_device_node(args.fwnode);
882ce0929d2SAndy Shevchenko lookup->info.quirks = quirks;
883977d5ad3SSakari Ailus
884d079524aSRafael J. Wysocki return 0;
885d079524aSRafael J. Wysocki }
886d079524aSRafael J. Wysocki
88712028d2dSMika Westerberg /**
888936e15ddSMika Westerberg * acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
8890d9a693cSMika Westerberg * @adev: pointer to a ACPI device to get GPIO from
8900d9a693cSMika Westerberg * @propname: Property name of the GPIO (optional)
89112028d2dSMika Westerberg * @index: index of GpioIo/GpioInt resource (starting from %0)
89212028d2dSMika Westerberg * @info: info pointer to fill in (optional)
89312028d2dSMika Westerberg *
8940d9a693cSMika Westerberg * Function goes through ACPI resources for @adev and based on @index looks
895936e15ddSMika Westerberg * up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
89612028d2dSMika Westerberg * and returns it. @index matches GpioIo/GpioInt resources only so if there
89712028d2dSMika Westerberg * are total %3 GPIO resources, the index goes from %0 to %2.
89812028d2dSMika Westerberg *
8990d9a693cSMika Westerberg * If @propname is specified the GPIO is looked using device property. In
9000d9a693cSMika Westerberg * that case @index is used to select the GPIO entry in the property value
9010d9a693cSMika Westerberg * (in case of multiple).
9020d9a693cSMika Westerberg *
90385edcd01SAndy Shevchenko * If the GPIO cannot be translated or there is an error, an ERR_PTR is
90412028d2dSMika Westerberg * returned.
90512028d2dSMika Westerberg *
90612028d2dSMika Westerberg * Note: if the GPIO resource has multiple entries in the pin list, this
90712028d2dSMika Westerberg * function only returns the first.
90812028d2dSMika Westerberg */
acpi_get_gpiod_by_index(struct acpi_device * adev,const char * propname,int index,struct acpi_gpio_info * info)909031ba28aSLinus Walleij static struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
91016ba046eSDmitry Torokhov const char *propname,
91116ba046eSDmitry Torokhov int index,
91212028d2dSMika Westerberg struct acpi_gpio_info *info)
91312028d2dSMika Westerberg {
91412028d2dSMika Westerberg struct acpi_gpio_lookup lookup;
91512028d2dSMika Westerberg int ret;
91612028d2dSMika Westerberg
9170d9a693cSMika Westerberg if (!adev)
918936e15ddSMika Westerberg return ERR_PTR(-ENODEV);
91912028d2dSMika Westerberg
92012028d2dSMika Westerberg memset(&lookup, 0, sizeof(lookup));
92112028d2dSMika Westerberg lookup.index = index;
92212028d2dSMika Westerberg
9230d9a693cSMika Westerberg if (propname) {
9240d9a693cSMika Westerberg dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
9250d9a693cSMika Westerberg
926504a3374SRafael J. Wysocki ret = acpi_gpio_property_lookup(acpi_fwnode_handle(adev),
927504a3374SRafael J. Wysocki propname, index, &lookup);
928d079524aSRafael J. Wysocki if (ret)
9290d9a693cSMika Westerberg return ERR_PTR(ret);
9300d9a693cSMika Westerberg
93174301f27SAndy Shevchenko dev_dbg(&adev->dev, "GPIO: _DSD returned %s %d %u %u\n",
9325870cff4SAndy Shevchenko dev_name(&lookup.info.adev->dev), lookup.index,
933d079524aSRafael J. Wysocki lookup.pin_index, lookup.active_low);
9340d9a693cSMika Westerberg } else {
9350d9a693cSMika Westerberg dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
9365870cff4SAndy Shevchenko lookup.info.adev = adev;
9370d9a693cSMika Westerberg }
9380d9a693cSMika Westerberg
939d079524aSRafael J. Wysocki ret = acpi_gpio_resource_lookup(&lookup, info);
940d079524aSRafael J. Wysocki return ret ? ERR_PTR(ret) : lookup.desc;
94112028d2dSMika Westerberg }
942664e3e5aSMika Westerberg
94316ba046eSDmitry Torokhov /**
94416ba046eSDmitry Torokhov * acpi_get_gpiod_from_data() - get a GPIO descriptor from ACPI data node
94516ba046eSDmitry Torokhov * @fwnode: pointer to an ACPI firmware node to get the GPIO information from
94616ba046eSDmitry Torokhov * @propname: Property name of the GPIO
94716ba046eSDmitry Torokhov * @index: index of GpioIo/GpioInt resource (starting from %0)
94816ba046eSDmitry Torokhov * @info: info pointer to fill in (optional)
94916ba046eSDmitry Torokhov *
95016ba046eSDmitry Torokhov * This function uses the property-based GPIO lookup to get to the GPIO
95116ba046eSDmitry Torokhov * resource with the relevant information from a data-only ACPI firmware node
95216ba046eSDmitry Torokhov * and uses that to obtain the GPIO descriptor to return.
95316ba046eSDmitry Torokhov *
95416ba046eSDmitry Torokhov * If the GPIO cannot be translated or there is an error an ERR_PTR is
95516ba046eSDmitry Torokhov * returned.
95616ba046eSDmitry Torokhov */
acpi_get_gpiod_from_data(struct fwnode_handle * fwnode,const char * propname,int index,struct acpi_gpio_info * info)95716ba046eSDmitry Torokhov static struct gpio_desc *acpi_get_gpiod_from_data(struct fwnode_handle *fwnode,
95816ba046eSDmitry Torokhov const char *propname,
95916ba046eSDmitry Torokhov int index,
96016ba046eSDmitry Torokhov struct acpi_gpio_info *info)
96116ba046eSDmitry Torokhov {
96216ba046eSDmitry Torokhov struct acpi_gpio_lookup lookup;
96316ba046eSDmitry Torokhov int ret;
96416ba046eSDmitry Torokhov
96516ba046eSDmitry Torokhov if (!is_acpi_data_node(fwnode))
96616ba046eSDmitry Torokhov return ERR_PTR(-ENODEV);
96716ba046eSDmitry Torokhov
96816ba046eSDmitry Torokhov if (!propname)
96916ba046eSDmitry Torokhov return ERR_PTR(-EINVAL);
97016ba046eSDmitry Torokhov
971479ac419SAndy Shevchenko memset(&lookup, 0, sizeof(lookup));
97216ba046eSDmitry Torokhov lookup.index = index;
97316ba046eSDmitry Torokhov
97416ba046eSDmitry Torokhov ret = acpi_gpio_property_lookup(fwnode, propname, index, &lookup);
97516ba046eSDmitry Torokhov if (ret)
97616ba046eSDmitry Torokhov return ERR_PTR(ret);
97716ba046eSDmitry Torokhov
97816ba046eSDmitry Torokhov ret = acpi_gpio_resource_lookup(&lookup, info);
97916ba046eSDmitry Torokhov return ret ? ERR_PTR(ret) : lookup.desc;
98016ba046eSDmitry Torokhov }
98116ba046eSDmitry Torokhov
acpi_can_fallback_to_crs(struct acpi_device * adev,const char * con_id)9824f78d91cSDmitry Torokhov static bool acpi_can_fallback_to_crs(struct acpi_device *adev,
9834f78d91cSDmitry Torokhov const char *con_id)
9844f78d91cSDmitry Torokhov {
9854f78d91cSDmitry Torokhov /* Never allow fallback if the device has properties */
9864f78d91cSDmitry Torokhov if (acpi_dev_has_props(adev) || adev->driver_gpios)
9874f78d91cSDmitry Torokhov return false;
9884f78d91cSDmitry Torokhov
9894f78d91cSDmitry Torokhov return con_id == NULL;
9904f78d91cSDmitry Torokhov }
9914f78d91cSDmitry Torokhov
acpi_find_gpio(struct fwnode_handle * fwnode,const char * con_id,unsigned int idx,enum gpiod_flags * dflags,unsigned long * lookupflags)9922b6bce80SDmitry Torokhov struct gpio_desc *acpi_find_gpio(struct fwnode_handle *fwnode,
993031ba28aSLinus Walleij const char *con_id,
994031ba28aSLinus Walleij unsigned int idx,
995a31f5c3aSAndy Shevchenko enum gpiod_flags *dflags,
996fed7026aSAndy Shevchenko unsigned long *lookupflags)
997031ba28aSLinus Walleij {
99816ba046eSDmitry Torokhov struct acpi_device *adev = to_acpi_device_node(fwnode);
999031ba28aSLinus Walleij struct acpi_gpio_info info;
1000031ba28aSLinus Walleij struct gpio_desc *desc;
1001031ba28aSLinus Walleij char propname[32];
1002031ba28aSLinus Walleij int i;
1003031ba28aSLinus Walleij
1004031ba28aSLinus Walleij /* Try first from _DSD */
1005031ba28aSLinus Walleij for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
10069e66504aSAndy Shevchenko if (con_id) {
1007031ba28aSLinus Walleij snprintf(propname, sizeof(propname), "%s-%s",
1008031ba28aSLinus Walleij con_id, gpio_suffixes[i]);
1009031ba28aSLinus Walleij } else {
1010031ba28aSLinus Walleij snprintf(propname, sizeof(propname), "%s",
1011031ba28aSLinus Walleij gpio_suffixes[i]);
1012031ba28aSLinus Walleij }
1013031ba28aSLinus Walleij
101416ba046eSDmitry Torokhov if (adev)
101516ba046eSDmitry Torokhov desc = acpi_get_gpiod_by_index(adev,
101616ba046eSDmitry Torokhov propname, idx, &info);
101716ba046eSDmitry Torokhov else
101816ba046eSDmitry Torokhov desc = acpi_get_gpiod_from_data(fwnode,
101916ba046eSDmitry Torokhov propname, idx, &info);
1020693bdaa1SDmitry Torokhov if (!IS_ERR(desc))
1021031ba28aSLinus Walleij break;
1022693bdaa1SDmitry Torokhov if (PTR_ERR(desc) == -EPROBE_DEFER)
1023693bdaa1SDmitry Torokhov return ERR_CAST(desc);
1024031ba28aSLinus Walleij }
1025031ba28aSLinus Walleij
1026031ba28aSLinus Walleij /* Then from plain _CRS GPIOs */
1027031ba28aSLinus Walleij if (IS_ERR(desc)) {
102816ba046eSDmitry Torokhov if (!adev || !acpi_can_fallback_to_crs(adev, con_id))
1029031ba28aSLinus Walleij return ERR_PTR(-ENOENT);
1030031ba28aSLinus Walleij
1031031ba28aSLinus Walleij desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
1032031ba28aSLinus Walleij if (IS_ERR(desc))
1033031ba28aSLinus Walleij return desc;
1034fe06b56cSAndy Shevchenko }
1035031ba28aSLinus Walleij
1036fe06b56cSAndy Shevchenko if (info.gpioint &&
1037a31f5c3aSAndy Shevchenko (*dflags == GPIOD_OUT_LOW || *dflags == GPIOD_OUT_HIGH)) {
1038be3dc15fSAndy Shevchenko dev_dbg(&adev->dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n");
1039031ba28aSLinus Walleij return ERR_PTR(-ENOENT);
1040031ba28aSLinus Walleij }
1041031ba28aSLinus Walleij
10425c34b6c1SAndy Shevchenko acpi_gpio_update_gpiod_flags(dflags, &info);
1043606be344SAndy Shevchenko acpi_gpio_update_gpiod_lookup_flags(lookupflags, &info);
1044031ba28aSLinus Walleij return desc;
1045031ba28aSLinus Walleij }
1046031ba28aSLinus Walleij
1047c884fbd4SMika Westerberg /**
10484c992560SRaul E Rangel * acpi_dev_gpio_irq_wake_get_by() - Find GpioInt and translate it to Linux IRQ number
1049c884fbd4SMika Westerberg * @adev: pointer to a ACPI device to get IRQ from
105080939021SAndy Shevchenko * @name: optional name of GpioInt resource
1051c884fbd4SMika Westerberg * @index: index of GpioInt resource (starting from %0)
10524c992560SRaul E Rangel * @wake_capable: Set to true if the IRQ is wake capable
1053c884fbd4SMika Westerberg *
1054c884fbd4SMika Westerberg * If the device has one or more GpioInt resources, this function can be
1055c884fbd4SMika Westerberg * used to translate from the GPIO offset in the resource to the Linux IRQ
1056c884fbd4SMika Westerberg * number.
1057c884fbd4SMika Westerberg *
1058a31f5c3aSAndy Shevchenko * The function is idempotent, though each time it runs it will configure GPIO
1059a31f5c3aSAndy Shevchenko * pin direction according to the flags in GpioInt resource.
1060a31f5c3aSAndy Shevchenko *
106180939021SAndy Shevchenko * The function takes optional @name parameter. If the resource has a property
106280939021SAndy Shevchenko * name, then only those will be taken into account.
106380939021SAndy Shevchenko *
10644c992560SRaul E Rangel * The GPIO is considered wake capable if the GpioInt resource specifies
10654c992560SRaul E Rangel * SharedAndWake or ExclusiveAndWake.
10664c992560SRaul E Rangel *
1067c884fbd4SMika Westerberg * Return: Linux IRQ number (> %0) on success, negative errno on failure.
1068c884fbd4SMika Westerberg */
acpi_dev_gpio_irq_wake_get_by(struct acpi_device * adev,const char * name,int index,bool * wake_capable)10694c992560SRaul E Rangel int acpi_dev_gpio_irq_wake_get_by(struct acpi_device *adev, const char *name, int index,
10704c992560SRaul E Rangel bool *wake_capable)
1071c884fbd4SMika Westerberg {
1072c884fbd4SMika Westerberg int idx, i;
107352044723SChristophe RICARD unsigned int irq_flags;
1074a31f5c3aSAndy Shevchenko int ret;
1075c884fbd4SMika Westerberg
1076c884fbd4SMika Westerberg for (i = 0, idx = 0; idx <= index; i++) {
1077c884fbd4SMika Westerberg struct acpi_gpio_info info;
1078c884fbd4SMika Westerberg struct gpio_desc *desc;
1079c884fbd4SMika Westerberg
108080939021SAndy Shevchenko desc = acpi_get_gpiod_by_index(adev, name, i, &info);
108152044723SChristophe RICARD
10826798d727SHans de Goede /* Ignore -EPROBE_DEFER, it only matters if idx matches */
10836798d727SHans de Goede if (IS_ERR(desc) && PTR_ERR(desc) != -EPROBE_DEFER)
10846798d727SHans de Goede return PTR_ERR(desc);
10856798d727SHans de Goede
10866798d727SHans de Goede if (info.gpioint && idx++ == index) {
10872d6c06f5SAndy Shevchenko unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
1088e7b73132SAndy Shevchenko enum gpiod_flags dflags = GPIOD_ASIS;
1089a31f5c3aSAndy Shevchenko char label[32];
10906798d727SHans de Goede int irq;
10916798d727SHans de Goede
10926798d727SHans de Goede if (IS_ERR(desc))
10936798d727SHans de Goede return PTR_ERR(desc);
10946798d727SHans de Goede
10956798d727SHans de Goede irq = gpiod_to_irq(desc);
109652044723SChristophe RICARD if (irq < 0)
109752044723SChristophe RICARD return irq;
109852044723SChristophe RICARD
1099e7b73132SAndy Shevchenko acpi_gpio_update_gpiod_flags(&dflags, &info);
1100e7b73132SAndy Shevchenko acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
1101e7b73132SAndy Shevchenko
1102a31f5c3aSAndy Shevchenko snprintf(label, sizeof(label), "GpioInt() %d", index);
1103e7b73132SAndy Shevchenko ret = gpiod_configure_flags(desc, label, lflags, dflags);
1104a31f5c3aSAndy Shevchenko if (ret < 0)
1105a31f5c3aSAndy Shevchenko return ret;
1106a31f5c3aSAndy Shevchenko
1107660c619bSAndy Shevchenko /* ACPI uses hundredths of milliseconds units */
1108660c619bSAndy Shevchenko ret = gpio_set_debounce_timeout(desc, info.debounce * 10);
11098dcb7a15SAndy Shevchenko if (ret)
11108dcb7a15SAndy Shevchenko return ret;
11118dcb7a15SAndy Shevchenko
111252044723SChristophe RICARD irq_flags = acpi_dev_get_irq_type(info.triggering,
111352044723SChristophe RICARD info.polarity);
111452044723SChristophe RICARD
1115bdfd6ab8SHans de Goede /*
1116bdfd6ab8SHans de Goede * If the IRQ is not already in use then set type
1117bdfd6ab8SHans de Goede * if specified and different than the current one.
1118bdfd6ab8SHans de Goede */
1119bdfd6ab8SHans de Goede if (can_request_irq(irq, irq_flags)) {
112052044723SChristophe RICARD if (irq_flags != IRQ_TYPE_NONE &&
112152044723SChristophe RICARD irq_flags != irq_get_trigger_type(irq))
112252044723SChristophe RICARD irq_set_irq_type(irq, irq_flags);
1123bdfd6ab8SHans de Goede } else {
1124bdfd6ab8SHans de Goede dev_dbg(&adev->dev, "IRQ %d already in use\n", irq);
1125bdfd6ab8SHans de Goede }
112652044723SChristophe RICARD
1127d63f11c0SMario Limonciello /* avoid suspend issues with GPIOs when systems are using S3 */
1128d63f11c0SMario Limonciello if (wake_capable && acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)
11294c992560SRaul E Rangel *wake_capable = info.wake_capable;
11304c992560SRaul E Rangel
113152044723SChristophe RICARD return irq;
113252044723SChristophe RICARD }
113352044723SChristophe RICARD
1134c884fbd4SMika Westerberg }
11356798d727SHans de Goede return -ENOENT;
1136c884fbd4SMika Westerberg }
11374c992560SRaul E Rangel EXPORT_SYMBOL_GPL(acpi_dev_gpio_irq_wake_get_by);
1138c884fbd4SMika Westerberg
1139473ed7beSMika Westerberg static acpi_status
acpi_gpio_adr_space_handler(u32 function,acpi_physical_address address,u32 bits,u64 * value,void * handler_context,void * region_context)1140473ed7beSMika Westerberg acpi_gpio_adr_space_handler(u32 function, acpi_physical_address address,
1141473ed7beSMika Westerberg u32 bits, u64 *value, void *handler_context,
1142473ed7beSMika Westerberg void *region_context)
1143473ed7beSMika Westerberg {
1144473ed7beSMika Westerberg struct acpi_gpio_chip *achip = region_context;
1145473ed7beSMika Westerberg struct gpio_chip *chip = achip->chip;
1146473ed7beSMika Westerberg struct acpi_resource_gpio *agpio;
1147473ed7beSMika Westerberg struct acpi_resource *ares;
114874301f27SAndy Shevchenko u16 pin_index = address;
1149473ed7beSMika Westerberg acpi_status status;
1150c15d821dSSrinivas Pandruvada int length;
1151473ed7beSMika Westerberg int i;
1152473ed7beSMika Westerberg
1153473ed7beSMika Westerberg status = acpi_buffer_to_resource(achip->conn_info.connection,
1154473ed7beSMika Westerberg achip->conn_info.length, &ares);
1155473ed7beSMika Westerberg if (ACPI_FAILURE(status))
1156473ed7beSMika Westerberg return status;
1157473ed7beSMika Westerberg
1158473ed7beSMika Westerberg if (WARN_ON(ares->type != ACPI_RESOURCE_TYPE_GPIO)) {
1159473ed7beSMika Westerberg ACPI_FREE(ares);
1160473ed7beSMika Westerberg return AE_BAD_PARAMETER;
1161473ed7beSMika Westerberg }
1162473ed7beSMika Westerberg
1163473ed7beSMika Westerberg agpio = &ares->data.gpio;
1164473ed7beSMika Westerberg
1165473ed7beSMika Westerberg if (WARN_ON(agpio->io_restriction == ACPI_IO_RESTRICT_INPUT &&
1166473ed7beSMika Westerberg function == ACPI_WRITE)) {
1167473ed7beSMika Westerberg ACPI_FREE(ares);
1168473ed7beSMika Westerberg return AE_BAD_PARAMETER;
1169473ed7beSMika Westerberg }
1170473ed7beSMika Westerberg
117174301f27SAndy Shevchenko length = min_t(u16, agpio->pin_table_length, pin_index + bits);
1172c15d821dSSrinivas Pandruvada for (i = pin_index; i < length; ++i) {
11730c2cae09SAndy Shevchenko unsigned int pin = agpio->pin_table[i];
1174473ed7beSMika Westerberg struct acpi_gpio_connection *conn;
1175473ed7beSMika Westerberg struct gpio_desc *desc;
1176473ed7beSMika Westerberg bool found;
1177473ed7beSMika Westerberg
1178473ed7beSMika Westerberg mutex_lock(&achip->conn_lock);
1179473ed7beSMika Westerberg
1180473ed7beSMika Westerberg found = false;
1181473ed7beSMika Westerberg list_for_each_entry(conn, &achip->conns, node) {
1182e46cf32cSAlexandre Courbot if (conn->pin == pin) {
1183473ed7beSMika Westerberg found = true;
1184e46cf32cSAlexandre Courbot desc = conn->desc;
1185473ed7beSMika Westerberg break;
1186473ed7beSMika Westerberg }
1187473ed7beSMika Westerberg }
1188c103a10fSMika Westerberg
1189c103a10fSMika Westerberg /*
1190c103a10fSMika Westerberg * The same GPIO can be shared between operation region and
1191c103a10fSMika Westerberg * event but only if the access here is ACPI_READ. In that
1192c103a10fSMika Westerberg * case we "borrow" the event GPIO instead.
1193c103a10fSMika Westerberg */
1194c163f90cSErik Schmauss if (!found && agpio->shareable == ACPI_SHARED &&
1195c103a10fSMika Westerberg function == ACPI_READ) {
1196c103a10fSMika Westerberg struct acpi_gpio_event *event;
1197c103a10fSMika Westerberg
1198c103a10fSMika Westerberg list_for_each_entry(event, &achip->events, node) {
1199c103a10fSMika Westerberg if (event->pin == pin) {
1200c103a10fSMika Westerberg desc = event->desc;
1201c103a10fSMika Westerberg found = true;
1202c103a10fSMika Westerberg break;
1203c103a10fSMika Westerberg }
1204c103a10fSMika Westerberg }
1205c103a10fSMika Westerberg }
1206c103a10fSMika Westerberg
1207473ed7beSMika Westerberg if (!found) {
12082e2b496cSAndy Shevchenko desc = acpi_request_own_gpiod(chip, agpio, i, "ACPI:OpRegion");
1209e46cf32cSAlexandre Courbot if (IS_ERR(desc)) {
1210473ed7beSMika Westerberg mutex_unlock(&achip->conn_lock);
1211ce698f4eSAndy Shevchenko status = AE_ERROR;
1212473ed7beSMika Westerberg goto out;
1213473ed7beSMika Westerberg }
1214473ed7beSMika Westerberg
1215473ed7beSMika Westerberg conn = kzalloc(sizeof(*conn), GFP_KERNEL);
1216473ed7beSMika Westerberg if (!conn) {
1217473ed7beSMika Westerberg gpiochip_free_own_desc(desc);
1218473ed7beSMika Westerberg mutex_unlock(&achip->conn_lock);
1219ce698f4eSAndy Shevchenko status = AE_NO_MEMORY;
1220473ed7beSMika Westerberg goto out;
1221473ed7beSMika Westerberg }
1222473ed7beSMika Westerberg
1223e46cf32cSAlexandre Courbot conn->pin = pin;
1224473ed7beSMika Westerberg conn->desc = desc;
1225473ed7beSMika Westerberg list_add_tail(&conn->node, &achip->conns);
1226473ed7beSMika Westerberg }
1227473ed7beSMika Westerberg
1228473ed7beSMika Westerberg mutex_unlock(&achip->conn_lock);
1229473ed7beSMika Westerberg
1230473ed7beSMika Westerberg if (function == ACPI_WRITE)
12312c4d00cbSAndy Shevchenko gpiod_set_raw_value_cansleep(desc, !!(*value & BIT(i)));
1232473ed7beSMika Westerberg else
1233dc62b56aSAaron Lu *value |= (u64)gpiod_get_raw_value_cansleep(desc) << i;
1234473ed7beSMika Westerberg }
1235473ed7beSMika Westerberg
1236473ed7beSMika Westerberg out:
1237473ed7beSMika Westerberg ACPI_FREE(ares);
1238473ed7beSMika Westerberg return status;
1239473ed7beSMika Westerberg }
1240473ed7beSMika Westerberg
acpi_gpiochip_request_regions(struct acpi_gpio_chip * achip)1241473ed7beSMika Westerberg static void acpi_gpiochip_request_regions(struct acpi_gpio_chip *achip)
1242473ed7beSMika Westerberg {
1243473ed7beSMika Westerberg struct gpio_chip *chip = achip->chip;
124458383c78SLinus Walleij acpi_handle handle = ACPI_HANDLE(chip->parent);
1245473ed7beSMika Westerberg acpi_status status;
1246473ed7beSMika Westerberg
1247473ed7beSMika Westerberg INIT_LIST_HEAD(&achip->conns);
1248473ed7beSMika Westerberg mutex_init(&achip->conn_lock);
1249473ed7beSMika Westerberg status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
1250473ed7beSMika Westerberg acpi_gpio_adr_space_handler,
1251473ed7beSMika Westerberg NULL, achip);
1252473ed7beSMika Westerberg if (ACPI_FAILURE(status))
125358383c78SLinus Walleij dev_err(chip->parent,
125458383c78SLinus Walleij "Failed to install GPIO OpRegion handler\n");
1255473ed7beSMika Westerberg }
1256473ed7beSMika Westerberg
acpi_gpiochip_free_regions(struct acpi_gpio_chip * achip)1257473ed7beSMika Westerberg static void acpi_gpiochip_free_regions(struct acpi_gpio_chip *achip)
1258473ed7beSMika Westerberg {
1259473ed7beSMika Westerberg struct gpio_chip *chip = achip->chip;
126058383c78SLinus Walleij acpi_handle handle = ACPI_HANDLE(chip->parent);
1261473ed7beSMika Westerberg struct acpi_gpio_connection *conn, *tmp;
1262473ed7beSMika Westerberg acpi_status status;
1263473ed7beSMika Westerberg
1264473ed7beSMika Westerberg status = acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GPIO,
1265473ed7beSMika Westerberg acpi_gpio_adr_space_handler);
1266473ed7beSMika Westerberg if (ACPI_FAILURE(status)) {
126758383c78SLinus Walleij dev_err(chip->parent,
126858383c78SLinus Walleij "Failed to remove GPIO OpRegion handler\n");
1269473ed7beSMika Westerberg return;
1270473ed7beSMika Westerberg }
1271473ed7beSMika Westerberg
1272473ed7beSMika Westerberg list_for_each_entry_safe_reverse(conn, tmp, &achip->conns, node) {
1273473ed7beSMika Westerberg gpiochip_free_own_desc(conn->desc);
1274473ed7beSMika Westerberg list_del(&conn->node);
1275473ed7beSMika Westerberg kfree(conn);
1276473ed7beSMika Westerberg }
1277473ed7beSMika Westerberg }
1278473ed7beSMika Westerberg
1279fed7026aSAndy Shevchenko static struct gpio_desc *
acpi_gpiochip_parse_own_gpio(struct acpi_gpio_chip * achip,struct fwnode_handle * fwnode,const char ** name,unsigned long * lflags,enum gpiod_flags * dflags)1280fed7026aSAndy Shevchenko acpi_gpiochip_parse_own_gpio(struct acpi_gpio_chip *achip,
1281fed7026aSAndy Shevchenko struct fwnode_handle *fwnode,
1282fed7026aSAndy Shevchenko const char **name,
1283fed7026aSAndy Shevchenko unsigned long *lflags,
128480c8d927SAndy Shevchenko enum gpiod_flags *dflags)
1285c80f1ba7SMika Westerberg {
1286c80f1ba7SMika Westerberg struct gpio_chip *chip = achip->chip;
1287c80f1ba7SMika Westerberg struct gpio_desc *desc;
1288c80f1ba7SMika Westerberg u32 gpios[2];
1289c80f1ba7SMika Westerberg int ret;
1290c80f1ba7SMika Westerberg
12912d6c06f5SAndy Shevchenko *lflags = GPIO_LOOKUP_FLAGS_DEFAULT;
129232fa6552SAndy Shevchenko *dflags = GPIOD_ASIS;
1293c82064f2SArnd Bergmann *name = NULL;
1294c82064f2SArnd Bergmann
1295c80f1ba7SMika Westerberg ret = fwnode_property_read_u32_array(fwnode, "gpios", gpios,
1296c80f1ba7SMika Westerberg ARRAY_SIZE(gpios));
1297c80f1ba7SMika Westerberg if (ret < 0)
1298c80f1ba7SMika Westerberg return ERR_PTR(ret);
1299c80f1ba7SMika Westerberg
130003c4749dSMika Westerberg desc = gpiochip_get_desc(chip, gpios[0]);
1301c80f1ba7SMika Westerberg if (IS_ERR(desc))
1302c80f1ba7SMika Westerberg return desc;
1303c80f1ba7SMika Westerberg
1304c80f1ba7SMika Westerberg if (gpios[1])
1305c80f1ba7SMika Westerberg *lflags |= GPIO_ACTIVE_LOW;
1306c80f1ba7SMika Westerberg
1307c80f1ba7SMika Westerberg if (fwnode_property_present(fwnode, "input"))
1308c80f1ba7SMika Westerberg *dflags |= GPIOD_IN;
1309c80f1ba7SMika Westerberg else if (fwnode_property_present(fwnode, "output-low"))
1310c80f1ba7SMika Westerberg *dflags |= GPIOD_OUT_LOW;
1311c80f1ba7SMika Westerberg else if (fwnode_property_present(fwnode, "output-high"))
1312c80f1ba7SMika Westerberg *dflags |= GPIOD_OUT_HIGH;
1313c80f1ba7SMika Westerberg else
1314c80f1ba7SMika Westerberg return ERR_PTR(-EINVAL);
1315c80f1ba7SMika Westerberg
1316c80f1ba7SMika Westerberg fwnode_property_read_string(fwnode, "line-name", name);
1317c80f1ba7SMika Westerberg
1318c80f1ba7SMika Westerberg return desc;
1319c80f1ba7SMika Westerberg }
1320c80f1ba7SMika Westerberg
acpi_gpiochip_scan_gpios(struct acpi_gpio_chip * achip)1321c80f1ba7SMika Westerberg static void acpi_gpiochip_scan_gpios(struct acpi_gpio_chip *achip)
1322c80f1ba7SMika Westerberg {
1323c80f1ba7SMika Westerberg struct gpio_chip *chip = achip->chip;
1324c80f1ba7SMika Westerberg struct fwnode_handle *fwnode;
1325c80f1ba7SMika Westerberg
1326c80f1ba7SMika Westerberg device_for_each_child_node(chip->parent, fwnode) {
1327fed7026aSAndy Shevchenko unsigned long lflags;
132880c8d927SAndy Shevchenko enum gpiod_flags dflags;
1329c80f1ba7SMika Westerberg struct gpio_desc *desc;
1330c80f1ba7SMika Westerberg const char *name;
1331c80f1ba7SMika Westerberg int ret;
1332c80f1ba7SMika Westerberg
1333c80f1ba7SMika Westerberg if (!fwnode_property_present(fwnode, "gpio-hog"))
1334c80f1ba7SMika Westerberg continue;
1335c80f1ba7SMika Westerberg
1336c80f1ba7SMika Westerberg desc = acpi_gpiochip_parse_own_gpio(achip, fwnode, &name,
1337c80f1ba7SMika Westerberg &lflags, &dflags);
1338c80f1ba7SMika Westerberg if (IS_ERR(desc))
1339c80f1ba7SMika Westerberg continue;
1340c80f1ba7SMika Westerberg
1341c80f1ba7SMika Westerberg ret = gpiod_hog(desc, name, lflags, dflags);
1342c80f1ba7SMika Westerberg if (ret) {
1343c80f1ba7SMika Westerberg dev_err(chip->parent, "Failed to hog GPIO\n");
13441b6998c9SWei Yongjun fwnode_handle_put(fwnode);
1345c80f1ba7SMika Westerberg return;
1346c80f1ba7SMika Westerberg }
1347c80f1ba7SMika Westerberg }
1348c80f1ba7SMika Westerberg }
1349c80f1ba7SMika Westerberg
acpi_gpiochip_add(struct gpio_chip * chip)1350664e3e5aSMika Westerberg void acpi_gpiochip_add(struct gpio_chip *chip)
1351664e3e5aSMika Westerberg {
1352aa92b6f6SMika Westerberg struct acpi_gpio_chip *acpi_gpio;
1353a9e10e58SDaniel Scally struct acpi_device *adev;
1354aa92b6f6SMika Westerberg acpi_status status;
1355aa92b6f6SMika Westerberg
135658383c78SLinus Walleij if (!chip || !chip->parent)
1357e9595f84SMika Westerberg return;
1358e9595f84SMika Westerberg
1359a9e10e58SDaniel Scally adev = ACPI_COMPANION(chip->parent);
1360a9e10e58SDaniel Scally if (!adev)
1361aa92b6f6SMika Westerberg return;
1362aa92b6f6SMika Westerberg
1363aa92b6f6SMika Westerberg acpi_gpio = kzalloc(sizeof(*acpi_gpio), GFP_KERNEL);
1364aa92b6f6SMika Westerberg if (!acpi_gpio) {
136558383c78SLinus Walleij dev_err(chip->parent,
1366aa92b6f6SMika Westerberg "Failed to allocate memory for ACPI GPIO chip\n");
1367aa92b6f6SMika Westerberg return;
1368aa92b6f6SMika Westerberg }
1369aa92b6f6SMika Westerberg
1370aa92b6f6SMika Westerberg acpi_gpio->chip = chip;
1371c103a10fSMika Westerberg INIT_LIST_HEAD(&acpi_gpio->events);
137278d3a92eSHans de Goede INIT_LIST_HEAD(&acpi_gpio->deferred_req_irqs_list_entry);
1373aa92b6f6SMika Westerberg
1374a9e10e58SDaniel Scally status = acpi_attach_data(adev->handle, acpi_gpio_chip_dh, acpi_gpio);
1375aa92b6f6SMika Westerberg if (ACPI_FAILURE(status)) {
137658383c78SLinus Walleij dev_err(chip->parent, "Failed to attach ACPI GPIO chip\n");
1377aa92b6f6SMika Westerberg kfree(acpi_gpio);
1378aa92b6f6SMika Westerberg return;
1379aa92b6f6SMika Westerberg }
1380aa92b6f6SMika Westerberg
1381473ed7beSMika Westerberg acpi_gpiochip_request_regions(acpi_gpio);
1382c80f1ba7SMika Westerberg acpi_gpiochip_scan_gpios(acpi_gpio);
1383a9e10e58SDaniel Scally acpi_dev_clear_dependencies(adev);
1384664e3e5aSMika Westerberg }
1385664e3e5aSMika Westerberg
acpi_gpiochip_remove(struct gpio_chip * chip)1386664e3e5aSMika Westerberg void acpi_gpiochip_remove(struct gpio_chip *chip)
1387664e3e5aSMika Westerberg {
1388aa92b6f6SMika Westerberg struct acpi_gpio_chip *acpi_gpio;
1389aa92b6f6SMika Westerberg acpi_handle handle;
1390aa92b6f6SMika Westerberg acpi_status status;
1391aa92b6f6SMika Westerberg
139258383c78SLinus Walleij if (!chip || !chip->parent)
1393e9595f84SMika Westerberg return;
1394e9595f84SMika Westerberg
139558383c78SLinus Walleij handle = ACPI_HANDLE(chip->parent);
1396aa92b6f6SMika Westerberg if (!handle)
1397aa92b6f6SMika Westerberg return;
1398aa92b6f6SMika Westerberg
1399aa92b6f6SMika Westerberg status = acpi_get_data(handle, acpi_gpio_chip_dh, (void **)&acpi_gpio);
1400aa92b6f6SMika Westerberg if (ACPI_FAILURE(status)) {
140158383c78SLinus Walleij dev_warn(chip->parent, "Failed to retrieve ACPI GPIO chip\n");
1402aa92b6f6SMika Westerberg return;
1403aa92b6f6SMika Westerberg }
1404aa92b6f6SMika Westerberg
1405473ed7beSMika Westerberg acpi_gpiochip_free_regions(acpi_gpio);
1406aa92b6f6SMika Westerberg
1407aa92b6f6SMika Westerberg acpi_detach_data(handle, acpi_gpio_chip_dh);
1408aa92b6f6SMika Westerberg kfree(acpi_gpio);
1409664e3e5aSMika Westerberg }
141066858527SRojhalat Ibrahim
acpi_gpio_package_count(const union acpi_object * obj)14116f7194a1SMika Westerberg static int acpi_gpio_package_count(const union acpi_object *obj)
141266858527SRojhalat Ibrahim {
141366858527SRojhalat Ibrahim const union acpi_object *element = obj->package.elements;
141466858527SRojhalat Ibrahim const union acpi_object *end = element + obj->package.count;
141566858527SRojhalat Ibrahim unsigned int count = 0;
141666858527SRojhalat Ibrahim
141766858527SRojhalat Ibrahim while (element < end) {
14186f7194a1SMika Westerberg switch (element->type) {
14196f7194a1SMika Westerberg case ACPI_TYPE_LOCAL_REFERENCE:
14206f7194a1SMika Westerberg element += 3;
1421df561f66SGustavo A. R. Silva fallthrough;
14226f7194a1SMika Westerberg case ACPI_TYPE_INTEGER:
142366858527SRojhalat Ibrahim element++;
14246f7194a1SMika Westerberg count++;
14256f7194a1SMika Westerberg break;
14266f7194a1SMika Westerberg
14276f7194a1SMika Westerberg default:
14286f7194a1SMika Westerberg return -EPROTO;
142966858527SRojhalat Ibrahim }
14306f7194a1SMika Westerberg }
14316f7194a1SMika Westerberg
143266858527SRojhalat Ibrahim return count;
143366858527SRojhalat Ibrahim }
143466858527SRojhalat Ibrahim
acpi_find_gpio_count(struct acpi_resource * ares,void * data)143566858527SRojhalat Ibrahim static int acpi_find_gpio_count(struct acpi_resource *ares, void *data)
143666858527SRojhalat Ibrahim {
143766858527SRojhalat Ibrahim unsigned int *count = data;
143866858527SRojhalat Ibrahim
143966858527SRojhalat Ibrahim if (ares->type == ACPI_RESOURCE_TYPE_GPIO)
144066858527SRojhalat Ibrahim *count += ares->data.gpio.pin_table_length;
144166858527SRojhalat Ibrahim
144266858527SRojhalat Ibrahim return 1;
144366858527SRojhalat Ibrahim }
144466858527SRojhalat Ibrahim
144566858527SRojhalat Ibrahim /**
144685edcd01SAndy Shevchenko * acpi_gpio_count - count the GPIOs associated with a device / function
144785edcd01SAndy Shevchenko * @dev: GPIO consumer, can be %NULL for system-global GPIOs
144866858527SRojhalat Ibrahim * @con_id: function within the GPIO consumer
144985edcd01SAndy Shevchenko *
145085edcd01SAndy Shevchenko * Return:
145185edcd01SAndy Shevchenko * The number of GPIOs associated with a device / function or %-ENOENT,
145285edcd01SAndy Shevchenko * if no GPIO has been assigned to the requested function.
145366858527SRojhalat Ibrahim */
acpi_gpio_count(struct device * dev,const char * con_id)145466858527SRojhalat Ibrahim int acpi_gpio_count(struct device *dev, const char *con_id)
145566858527SRojhalat Ibrahim {
145666858527SRojhalat Ibrahim struct acpi_device *adev = ACPI_COMPANION(dev);
145766858527SRojhalat Ibrahim const union acpi_object *obj;
145866858527SRojhalat Ibrahim const struct acpi_gpio_mapping *gm;
145966858527SRojhalat Ibrahim int count = -ENOENT;
146066858527SRojhalat Ibrahim int ret;
146166858527SRojhalat Ibrahim char propname[32];
146266858527SRojhalat Ibrahim unsigned int i;
146366858527SRojhalat Ibrahim
146466858527SRojhalat Ibrahim /* Try first from _DSD */
146566858527SRojhalat Ibrahim for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
14669e66504aSAndy Shevchenko if (con_id)
146766858527SRojhalat Ibrahim snprintf(propname, sizeof(propname), "%s-%s",
146866858527SRojhalat Ibrahim con_id, gpio_suffixes[i]);
146966858527SRojhalat Ibrahim else
147066858527SRojhalat Ibrahim snprintf(propname, sizeof(propname), "%s",
147166858527SRojhalat Ibrahim gpio_suffixes[i]);
147266858527SRojhalat Ibrahim
147366858527SRojhalat Ibrahim ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
147466858527SRojhalat Ibrahim &obj);
147566858527SRojhalat Ibrahim if (ret == 0) {
147666858527SRojhalat Ibrahim if (obj->type == ACPI_TYPE_LOCAL_REFERENCE)
147766858527SRojhalat Ibrahim count = 1;
147866858527SRojhalat Ibrahim else if (obj->type == ACPI_TYPE_PACKAGE)
147966858527SRojhalat Ibrahim count = acpi_gpio_package_count(obj);
148066858527SRojhalat Ibrahim } else if (adev->driver_gpios) {
148166858527SRojhalat Ibrahim for (gm = adev->driver_gpios; gm->name; gm++)
148266858527SRojhalat Ibrahim if (strcmp(propname, gm->name) == 0) {
148366858527SRojhalat Ibrahim count = gm->size;
148466858527SRojhalat Ibrahim break;
148566858527SRojhalat Ibrahim }
148666858527SRojhalat Ibrahim }
14874ed55016SAndy Shevchenko if (count > 0)
148866858527SRojhalat Ibrahim break;
148966858527SRojhalat Ibrahim }
149066858527SRojhalat Ibrahim
149166858527SRojhalat Ibrahim /* Then from plain _CRS GPIOs */
149266858527SRojhalat Ibrahim if (count < 0) {
149366858527SRojhalat Ibrahim struct list_head resource_list;
149466858527SRojhalat Ibrahim unsigned int crs_count = 0;
149566858527SRojhalat Ibrahim
14966fe9da42SAndy Shevchenko if (!acpi_can_fallback_to_crs(adev, con_id))
14976fe9da42SAndy Shevchenko return count;
14986fe9da42SAndy Shevchenko
149966858527SRojhalat Ibrahim INIT_LIST_HEAD(&resource_list);
150066858527SRojhalat Ibrahim acpi_dev_get_resources(adev, &resource_list,
150166858527SRojhalat Ibrahim acpi_find_gpio_count, &crs_count);
150266858527SRojhalat Ibrahim acpi_dev_free_resource_list(&resource_list);
150366858527SRojhalat Ibrahim if (crs_count > 0)
150466858527SRojhalat Ibrahim count = crs_count;
150566858527SRojhalat Ibrahim }
15064ed55016SAndy Shevchenko return count ? count : -ENOENT;
150766858527SRojhalat Ibrahim }
150810cf4899SDmitry Torokhov
1509e59f5e08SHans de Goede /* Run deferred acpi_gpiochip_request_irqs() */
acpi_gpio_handle_deferred_request_irqs(void)151004fd1ca7SHans de Goede static int __init acpi_gpio_handle_deferred_request_irqs(void)
1511ca876c74SBenjamin Tissoires {
151278d3a92eSHans de Goede struct acpi_gpio_chip *acpi_gpio, *tmp;
1513ca876c74SBenjamin Tissoires
151478d3a92eSHans de Goede mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
151578d3a92eSHans de Goede list_for_each_entry_safe(acpi_gpio, tmp,
151678d3a92eSHans de Goede &acpi_gpio_deferred_req_irqs_list,
1517e59f5e08SHans de Goede deferred_req_irqs_list_entry)
1518e59f5e08SHans de Goede acpi_gpiochip_request_irqs(acpi_gpio);
151978d3a92eSHans de Goede
152078d3a92eSHans de Goede acpi_gpio_deferred_req_irqs_done = true;
152178d3a92eSHans de Goede mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
1522ca876c74SBenjamin Tissoires
1523ca876c74SBenjamin Tissoires return 0;
1524ca876c74SBenjamin Tissoires }
1525ca876c74SBenjamin Tissoires /* We must use _sync so that this runs after the first deferred_probe run */
1526e59f5e08SHans de Goede late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
152761f7f7c8SHans de Goede
152804fd1ca7SHans de Goede static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
152961f7f7c8SHans de Goede {
15302727315dSHans de Goede /*
15312727315dSHans de Goede * The Minix Neo Z83-4 has a micro-USB-B id-pin handler for
15322727315dSHans de Goede * a non existing micro-USB-B connector which puts the HDMI
15332727315dSHans de Goede * DDC pins in GPIO mode, breaking HDMI support.
15342727315dSHans de Goede */
153561f7f7c8SHans de Goede .matches = {
153661f7f7c8SHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
153761f7f7c8SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
15381ad1b540SHans de Goede },
15392ccb21f5SHans de Goede .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
15402ccb21f5SHans de Goede .no_edge_events_on_boot = true,
15412ccb21f5SHans de Goede },
154261f7f7c8SHans de Goede },
15432727315dSHans de Goede {
15442727315dSHans de Goede /*
15452727315dSHans de Goede * The Terra Pad 1061 has a micro-USB-B id-pin handler, which
15462727315dSHans de Goede * instead of controlling the actual micro-USB-B turns the 5V
15472727315dSHans de Goede * boost for its USB-A connector off. The actual micro-USB-B
15482727315dSHans de Goede * connector is wired for charging only.
15492727315dSHans de Goede */
15502727315dSHans de Goede .matches = {
15512727315dSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"),
15522727315dSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"),
15531ad1b540SHans de Goede },
15542ccb21f5SHans de Goede .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
15552ccb21f5SHans de Goede .no_edge_events_on_boot = true,
15562ccb21f5SHans de Goede },
15572727315dSHans de Goede },
1558aa23ca3dSHans de Goede {
1559aa23ca3dSHans de Goede /*
1560da91ece2SHans de Goede * The Dell Venue 10 Pro 5055, with Bay Trail SoC + TI PMIC uses an
1561da91ece2SHans de Goede * external embedded-controller connected via I2C + an ACPI GPIO
1562da91ece2SHans de Goede * event handler on INT33FFC:02 pin 12, causing spurious wakeups.
1563da91ece2SHans de Goede */
1564da91ece2SHans de Goede .matches = {
1565da91ece2SHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
1566da91ece2SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "Venue 10 Pro 5055"),
1567da91ece2SHans de Goede },
1568da91ece2SHans de Goede .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1569da91ece2SHans de Goede .ignore_wake = "INT33FC:02@12",
1570da91ece2SHans de Goede },
1571da91ece2SHans de Goede },
1572da91ece2SHans de Goede {
1573da91ece2SHans de Goede /*
1574efaa87faSHans de Goede * HP X2 10 models with Cherry Trail SoC + TI PMIC use an
1575efaa87faSHans de Goede * external embedded-controller connected via I2C + an ACPI GPIO
1576efaa87faSHans de Goede * event handler on INT33FF:01 pin 0, causing spurious wakeups.
1577efaa87faSHans de Goede * When suspending by closing the LID, the power to the USB
1578efaa87faSHans de Goede * keyboard is turned off, causing INT0002 ACPI events to
1579efaa87faSHans de Goede * trigger once the XHCI controller notices the keyboard is
1580efaa87faSHans de Goede * gone. So INT0002 events cause spurious wakeups too. Ignoring
1581efaa87faSHans de Goede * EC wakes breaks wakeup when opening the lid, the user needs
1582aa23ca3dSHans de Goede * to press the power-button to wakeup the system. The
1583aa23ca3dSHans de Goede * alternative is suspend simply not working, which is worse.
1584aa23ca3dSHans de Goede */
1585aa23ca3dSHans de Goede .matches = {
1586aa23ca3dSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "HP"),
1587aa23ca3dSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"),
1588aa23ca3dSHans de Goede },
15892ccb21f5SHans de Goede .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
15902ccb21f5SHans de Goede .ignore_wake = "INT33FF:01@0,INT0002:00@2",
15912ccb21f5SHans de Goede },
1592aa23ca3dSHans de Goede },
15930e91506bSHans de Goede {
15940e91506bSHans de Goede /*
15950e91506bSHans de Goede * HP X2 10 models with Bay Trail SoC + AXP288 PMIC use an
15960e91506bSHans de Goede * external embedded-controller connected via I2C + an ACPI GPIO
15970e91506bSHans de Goede * event handler on INT33FC:02 pin 28, causing spurious wakeups.
15980e91506bSHans de Goede */
15990e91506bSHans de Goede .matches = {
16000e91506bSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
16010e91506bSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
16020e91506bSHans de Goede DMI_MATCH(DMI_BOARD_NAME, "815D"),
16030e91506bSHans de Goede },
16040e91506bSHans de Goede .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
16050e91506bSHans de Goede .ignore_wake = "INT33FC:02@28",
16060e91506bSHans de Goede },
16070e91506bSHans de Goede },
16080c625ccfSHans de Goede {
16090c625ccfSHans de Goede /*
16100c625ccfSHans de Goede * HP X2 10 models with Cherry Trail SoC + AXP288 PMIC use an
16110c625ccfSHans de Goede * external embedded-controller connected via I2C + an ACPI GPIO
16120c625ccfSHans de Goede * event handler on INT33FF:01 pin 0, causing spurious wakeups.
16130c625ccfSHans de Goede */
16140c625ccfSHans de Goede .matches = {
16150c625ccfSHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "HP"),
16160c625ccfSHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
16170c625ccfSHans de Goede DMI_MATCH(DMI_BOARD_NAME, "813E"),
16180c625ccfSHans de Goede },
16190c625ccfSHans de Goede .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
16200c625ccfSHans de Goede .ignore_wake = "INT33FF:01@0",
16210c625ccfSHans de Goede },
16220c625ccfSHans de Goede },
16230ea76c40SMario Limonciello {
16240ea76c40SMario Limonciello /*
16250ea76c40SMario Limonciello * Interrupt storm caused from edge triggered floating pin
16260ea76c40SMario Limonciello * Found in BIOS UX325UAZ.300
16270ea76c40SMario Limonciello * https://bugzilla.kernel.org/show_bug.cgi?id=216208
16280ea76c40SMario Limonciello */
16290ea76c40SMario Limonciello .matches = {
16300ea76c40SMario Limonciello DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
16310ea76c40SMario Limonciello DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UAZ_UM325UAZ"),
16320ea76c40SMario Limonciello },
16330ea76c40SMario Limonciello .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
16340ea76c40SMario Limonciello .ignore_interrupt = "AMDI0030:00@18",
16350ea76c40SMario Limonciello },
16360ea76c40SMario Limonciello },
16374cb78618SMario Limonciello {
16384cb78618SMario Limonciello /*
16394cb78618SMario Limonciello * Spurious wakeups from TP_ATTN# pin
16404cb78618SMario Limonciello * Found in BIOS 1.7.8
16414cb78618SMario Limonciello * https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
16424cb78618SMario Limonciello */
16434cb78618SMario Limonciello .matches = {
1644782eea0cSWerner Sembach DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
1645782eea0cSWerner Sembach },
1646782eea0cSWerner Sembach .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1647782eea0cSWerner Sembach .ignore_wake = "ELAN0415:00@9",
1648782eea0cSWerner Sembach },
1649782eea0cSWerner Sembach },
1650782eea0cSWerner Sembach {
1651782eea0cSWerner Sembach /*
1652782eea0cSWerner Sembach * Spurious wakeups from TP_ATTN# pin
1653782eea0cSWerner Sembach * Found in BIOS 1.7.8
1654782eea0cSWerner Sembach * https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
1655782eea0cSWerner Sembach */
1656782eea0cSWerner Sembach .matches = {
16574cb78618SMario Limonciello DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
16584cb78618SMario Limonciello },
16594cb78618SMario Limonciello .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
16604cb78618SMario Limonciello .ignore_wake = "ELAN0415:00@9",
16614cb78618SMario Limonciello },
16624cb78618SMario Limonciello },
1663a69982c3SWerner Sembach {
1664a69982c3SWerner Sembach /*
1665a69982c3SWerner Sembach * Spurious wakeups from TP_ATTN# pin
1666a69982c3SWerner Sembach * Found in BIOS 1.7.7
1667a69982c3SWerner Sembach */
1668a69982c3SWerner Sembach .matches = {
1669a69982c3SWerner Sembach DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"),
1670a69982c3SWerner Sembach },
1671a69982c3SWerner Sembach .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1672a69982c3SWerner Sembach .ignore_wake = "SYNA1202:00@16",
1673a69982c3SWerner Sembach },
1674a69982c3SWerner Sembach },
167530d8ff06SHans de Goede {
167630d8ff06SHans de Goede /*
167730d8ff06SHans de Goede * On the Peaq C1010 2-in-1 INT33FC:00 pin 3 is connected to
167830d8ff06SHans de Goede * a "dolby" button. At the ACPI level an _AEI event-handler
167930d8ff06SHans de Goede * is connected which sets an ACPI variable to 1 on both
168030d8ff06SHans de Goede * edges. This variable can be polled + cleared to 0 using
168130d8ff06SHans de Goede * WMI. But since the variable is set on both edges the WMI
168230d8ff06SHans de Goede * interface is pretty useless even when polling.
168330d8ff06SHans de Goede * So instead the x86-android-tablets code instantiates
168430d8ff06SHans de Goede * a gpio-keys platform device for it.
168530d8ff06SHans de Goede * Ignore the _AEI handler for the pin, so that it is not busy.
168630d8ff06SHans de Goede */
168730d8ff06SHans de Goede .matches = {
168830d8ff06SHans de Goede DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"),
168930d8ff06SHans de Goede DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"),
169030d8ff06SHans de Goede },
169130d8ff06SHans de Goede .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
169230d8ff06SHans de Goede .ignore_interrupt = "INT33FC:00@3",
169330d8ff06SHans de Goede },
169430d8ff06SHans de Goede },
1695c9c63d6aSMario Limonciello {
1696c9c63d6aSMario Limonciello /*
1697c9c63d6aSMario Limonciello * Spurious wakeups from TP_ATTN# pin
1698c9c63d6aSMario Limonciello * Found in BIOS 0.35
1699c9c63d6aSMario Limonciello * https://gitlab.freedesktop.org/drm/amd/-/issues/3073
1700c9c63d6aSMario Limonciello */
1701c9c63d6aSMario Limonciello .matches = {
1702c9c63d6aSMario Limonciello DMI_MATCH(DMI_SYS_VENDOR, "GPD"),
1703c9c63d6aSMario Limonciello DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"),
1704c9c63d6aSMario Limonciello },
1705c9c63d6aSMario Limonciello .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1706c9c63d6aSMario Limonciello .ignore_wake = "PNP0C50:00@8",
1707c9c63d6aSMario Limonciello },
1708c9c63d6aSMario Limonciello },
1709*98fde755SMario Limonciello {
1710*98fde755SMario Limonciello /*
1711*98fde755SMario Limonciello * Spurious wakeups from GPIO 11
1712*98fde755SMario Limonciello * Found in BIOS 1.04
1713*98fde755SMario Limonciello * https://gitlab.freedesktop.org/drm/amd/-/issues/3954
1714*98fde755SMario Limonciello */
1715*98fde755SMario Limonciello .matches = {
1716*98fde755SMario Limonciello DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
1717*98fde755SMario Limonciello DMI_MATCH(DMI_PRODUCT_FAMILY, "Acer Nitro V 14"),
1718*98fde755SMario Limonciello },
1719*98fde755SMario Limonciello .driver_data = &(struct acpi_gpiolib_dmi_quirk) {
1720*98fde755SMario Limonciello .ignore_interrupt = "AMDI0030:00@11",
1721*98fde755SMario Limonciello },
1722*98fde755SMario Limonciello },
172361f7f7c8SHans de Goede {} /* Terminating entry */
172461f7f7c8SHans de Goede };
172561f7f7c8SHans de Goede
acpi_gpio_setup_params(void)172604fd1ca7SHans de Goede static int __init acpi_gpio_setup_params(void)
172761f7f7c8SHans de Goede {
17282ccb21f5SHans de Goede const struct acpi_gpiolib_dmi_quirk *quirk = NULL;
17291ad1b540SHans de Goede const struct dmi_system_id *id;
17301ad1b540SHans de Goede
17311ad1b540SHans de Goede id = dmi_first_match(gpiolib_acpi_quirks);
17321ad1b540SHans de Goede if (id)
17332ccb21f5SHans de Goede quirk = id->driver_data;
17341ad1b540SHans de Goede
173561f7f7c8SHans de Goede if (run_edge_events_on_boot < 0) {
17362ccb21f5SHans de Goede if (quirk && quirk->no_edge_events_on_boot)
173761f7f7c8SHans de Goede run_edge_events_on_boot = 0;
173861f7f7c8SHans de Goede else
173961f7f7c8SHans de Goede run_edge_events_on_boot = 1;
174061f7f7c8SHans de Goede }
174161f7f7c8SHans de Goede
17422ccb21f5SHans de Goede if (ignore_wake == NULL && quirk && quirk->ignore_wake)
17432ccb21f5SHans de Goede ignore_wake = quirk->ignore_wake;
1744aa23ca3dSHans de Goede
17456b6af7bdSMario Limonciello if (ignore_interrupt == NULL && quirk && quirk->ignore_interrupt)
17466b6af7bdSMario Limonciello ignore_interrupt = quirk->ignore_interrupt;
17476b6af7bdSMario Limonciello
174861f7f7c8SHans de Goede return 0;
174961f7f7c8SHans de Goede }
175061f7f7c8SHans de Goede
175161f7f7c8SHans de Goede /* Directly after dmi_setup() which runs as core_initcall() */
175261f7f7c8SHans de Goede postcore_initcall(acpi_gpio_setup_params);
1753