xref: /openbmc/linux/drivers/gpio/gpiolib-acpi.c (revision fd5e9fccbd504c5179ab57ff695c610bca8809d6)
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