File Index
Files and directories
Sign in
FILE

gpiolib-acpi-quirks.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpio/gpiolib-acpi-quirks.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * ACPI quirks for GPIO ACPI helpers
  4 *
  5 * Author: Hans de Goede <hdegoede@redhat.com>
  6 */
  7
  8#include <linux/dmi.h>
  9#include <linux/kstrtox.h>
 10#include <linux/list.h>
 11#include <linux/module.h>
 12#include <linux/mutex.h>
 13#include <linux/printk.h>
 14#include <linux/string.h>
 15#include <linux/types.h>
 16
 17#include "gpiolib-acpi.h"
 18
 19static int run_edge_events_on_boot = -1;
 20module_param(run_edge_events_on_boot, int, 0444);
 21MODULE_PARM_DESC(run_edge_events_on_boot,
 22		 "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto");
 23
 24static char *ignore_wake;
 25module_param(ignore_wake, charp, 0444);
 26MODULE_PARM_DESC(ignore_wake,
 27		 "controller@pin combos on which to ignore the ACPI wake flag "
 28		 "ignore_wake=controller@pin[,controller@pin[,...]]");
 29
 30static char *ignore_interrupt;
 31module_param(ignore_interrupt, charp, 0444);
 32MODULE_PARM_DESC(ignore_interrupt,
 33		 "controller@pin combos on which to ignore interrupt "
 34		 "ignore_interrupt=controller@pin[,controller@pin[,...]]");
 35
 36/*
 37 * For GPIO chips which call acpi_gpiochip_request_interrupts() before late_init
 38 * (so builtin drivers) we register the ACPI GpioInt IRQ handlers from a
 39 * late_initcall_sync() handler, so that other builtin drivers can register their
 40 * OpRegions before the event handlers can run. This list contains GPIO chips
 41 * for which the acpi_gpiochip_request_irqs() call has been deferred.
 42 */
 43static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock);
 44static LIST_HEAD(acpi_gpio_deferred_req_irqs_list);
 45static bool acpi_gpio_deferred_req_irqs_done;
 46
 47bool acpi_gpio_add_to_deferred_list(struct list_head *list)
 48{
 49	bool defer;
 50
 51	mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
 52	defer = !acpi_gpio_deferred_req_irqs_done;
 53	if (defer)
 54		list_add(list, &acpi_gpio_deferred_req_irqs_list);
 55	mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
 56
 57	return defer;
 58}
 59
 60void acpi_gpio_remove_from_deferred_list(struct list_head *list)
 61{
 62	mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
 63	if (!list_empty(list))
 64		list_del_init(list);
 65	mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
 66}
 67
 68int acpi_gpio_need_run_edge_events_on_boot(void)
 69{
 70	return run_edge_events_on_boot;
 71}
 72
 73bool acpi_gpio_in_ignore_list(enum acpi_gpio_ignore_list list,
 74			      const char *controller_in, unsigned int pin_in)
 75{
 76	const char *ignore_list, *controller, *pin_str;
 77	unsigned int pin;
 78	char *endp;
 79	int len;
 80
 81	switch (list) {
 82	case ACPI_GPIO_IGNORE_WAKE:
 83		ignore_list = ignore_wake;
 84		break;
 85	case ACPI_GPIO_IGNORE_INTERRUPT:
 86		ignore_list = ignore_interrupt;
 87		break;
 88	default:
 89		return false;
 90	}
 91
 92	controller = ignore_list;
 93	while (controller) {
 94		pin_str = strchr(controller, '@');
 95		if (!pin_str)
 96			goto err;
 97
 98		len = pin_str - controller;
 99		if (len == strlen(controller_in) &&
100		    strncmp(controller, controller_in, len) == 0) {
101			pin = simple_strtoul(pin_str + 1, &endp, 10);
102			if (*endp != 0 && *endp != ',')
103				goto err;
104
105			if (pin == pin_in)
106				return true;
107		}
108
109		controller = strchr(controller, ',');
110		if (controller)
111			controller++;
112	}
113
114	return false;
115err:
116	pr_err_once("Error: Invalid value for gpiolib_acpi.ignore_...: %s\n", ignore_list);
117	return false;
118}
119
120/* Run deferred acpi_gpiochip_request_irqs() */
121static int __init acpi_gpio_handle_deferred_request_irqs(void)
122{
123	mutex_lock(&acpi_gpio_deferred_req_irqs_lock);
124	acpi_gpio_process_deferred_list(&acpi_gpio_deferred_req_irqs_list);
125	acpi_gpio_deferred_req_irqs_done = true;
126	mutex_unlock(&acpi_gpio_deferred_req_irqs_lock);
127
128	return 0;
129}
130/* We must use _sync so that this runs after the first deferred_probe run */
131late_initcall_sync(acpi_gpio_handle_deferred_request_irqs);
132
133struct acpi_gpiolib_dmi_quirk {
134	bool no_edge_events_on_boot;
135	char *ignore_wake;
136	char *ignore_interrupt;
137};
138
139static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
140	{
141		/*
142		 * The Minix Neo Z83-4 has a micro-USB-B id-pin handler for
143		 * a non existing micro-USB-B connector which puts the HDMI
144		 * DDC pins in GPIO mode, breaking HDMI support.
145		 */
146		.matches = {
147			DMI_MATCH(DMI_SYS_VENDOR, "MINIX"),
148			DMI_MATCH(DMI_PRODUCT_NAME, "Z83-4"),
149		},
150		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
151			.no_edge_events_on_boot = true,
152		},
153	},
154	{
155		/*
156		 * The Terra Pad 1061 has a micro-USB-B id-pin handler, which
157		 * instead of controlling the actual micro-USB-B turns the 5V
158		 * boost for its USB-A connector off. The actual micro-USB-B
159		 * connector is wired for charging only.
160		 */
161		.matches = {
162			DMI_MATCH(DMI_SYS_VENDOR, "Wortmann_AG"),
163			DMI_MATCH(DMI_PRODUCT_NAME, "TERRA_PAD_1061"),
164		},
165		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
166			.no_edge_events_on_boot = true,
167		},
168	},
169	{
170		/*
171		 * The Dell Venue 10 Pro 5055, with Bay Trail SoC + TI PMIC uses an
172		 * external embedded-controller connected via I2C + an ACPI GPIO
173		 * event handler on INT33FFC:02 pin 12, causing spurious wakeups.
174		 */
175		.matches = {
176			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
177			DMI_MATCH(DMI_PRODUCT_NAME, "Venue 10 Pro 5055"),
178		},
179		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
180			.ignore_wake = "INT33FC:02@12",
181		},
182	},
183	{
184		/*
185		 * HP X2 10 models with Cherry Trail SoC + TI PMIC use an
186		 * external embedded-controller connected via I2C + an ACPI GPIO
187		 * event handler on INT33FF:01 pin 0, causing spurious wakeups.
188		 * When suspending by closing the LID, the power to the USB
189		 * keyboard is turned off, causing INT0002 ACPI events to
190		 * trigger once the XHCI controller notices the keyboard is
191		 * gone. So INT0002 events cause spurious wakeups too. Ignoring
192		 * EC wakes breaks wakeup when opening the lid, the user needs
193		 * to press the power-button to wakeup the system. The
194		 * alternative is suspend simply not working, which is worse.
195		 */
196		.matches = {
197			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
198			DMI_MATCH(DMI_PRODUCT_NAME, "HP x2 Detachable 10-p0XX"),
199		},
200		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
201			.ignore_wake = "INT33FF:01@0,INT0002:00@2",
202		},
203	},
204	{
205		/*
206		 * HP X2 10 models with Bay Trail SoC + AXP288 PMIC use an
207		 * external embedded-controller connected via I2C + an ACPI GPIO
208		 * event handler on INT33FC:02 pin 28, causing spurious wakeups.
209		 */
210		.matches = {
211			DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
212			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
213			DMI_MATCH(DMI_BOARD_NAME, "815D"),
214		},
215		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
216			.ignore_wake = "INT33FC:02@28",
217		},
218	},
219	{
220		/*
221		 * HP X2 10 models with Cherry Trail SoC + AXP288 PMIC use an
222		 * external embedded-controller connected via I2C + an ACPI GPIO
223		 * event handler on INT33FF:01 pin 0, causing spurious wakeups.
224		 */
225		.matches = {
226			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
227			DMI_MATCH(DMI_PRODUCT_NAME, "HP Pavilion x2 Detachable"),
228			DMI_MATCH(DMI_BOARD_NAME, "813E"),
229		},
230		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
231			.ignore_wake = "INT33FF:01@0",
232		},
233	},
234	{
235		/*
236		 * Interrupt storm caused from edge triggered floating pin
237		 * Found in BIOS UX325UAZ.300
238		 * https://bugzilla.kernel.org/show_bug.cgi?id=216208
239		 */
240		.matches = {
241			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
242			DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UAZ_UM325UAZ"),
243		},
244		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
245			.ignore_interrupt = "AMDI0030:00@18",
246		},
247	},
248	{
249		/*
250		 * Spurious wakeups from TP_ATTN# pin
251		 * Found in BIOS 1.7.8
252		 * https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
253		 */
254		.matches = {
255			DMI_MATCH(DMI_BOARD_NAME, "NL5xNU"),
256		},
257		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
258			.ignore_wake = "ELAN0415:00@9",
259		},
260	},
261	{
262		/*
263		 * Spurious wakeups from TP_ATTN# pin
264		 * Found in BIOS 1.7.8
265		 * https://gitlab.freedesktop.org/drm/amd/-/issues/1722#note_1720627
266		 */
267		.matches = {
268			DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
269		},
270		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
271			.ignore_wake = "ELAN0415:00@9",
272		},
273	},
274	{
275		/*
276		 * Spurious wakeups from TP_ATTN# pin
277		 * Found in BIOS 1.7.7
278		 */
279		.matches = {
280			DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"),
281		},
282		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
283			.ignore_wake = "SYNA1202:00@16",
284		},
285	},
286	{
287		/*
288		 * On the Peaq C1010 2-in-1 INT33FC:00 pin 3 is connected to
289		 * a "dolby" button. At the ACPI level an _AEI event-handler
290		 * is connected which sets an ACPI variable to 1 on both
291		 * edges. This variable can be polled + cleared to 0 using
292		 * WMI. But since the variable is set on both edges the WMI
293		 * interface is pretty useless even when polling.
294		 * So instead the x86-android-tablets code instantiates
295		 * a gpio-keys platform device for it.
296		 * Ignore the _AEI handler for the pin, so that it is not busy.
297		 */
298		.matches = {
299			DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"),
300			DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"),
301		},
302		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
303			.ignore_interrupt = "INT33FC:00@3",
304		},
305	},
306	{
307		/*
308		 * Spurious wakeups from TP_ATTN# pin
309		 * Found in BIOS 0.35
310		 * https://gitlab.freedesktop.org/drm/amd/-/issues/3073
311		 */
312		.matches = {
313			DMI_MATCH(DMI_SYS_VENDOR, "GPD"),
314			DMI_MATCH(DMI_PRODUCT_NAME, "G1619-04"),
315		},
316		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
317			.ignore_wake = "PNP0C50:00@8",
318		},
319	},
320	{
321		/*
322		 * Same as G1619-04. New model.
323		 */
324		.matches = {
325			DMI_MATCH(DMI_SYS_VENDOR, "GPD"),
326			DMI_MATCH(DMI_PRODUCT_NAME, "G1619-05"),
327		},
328		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
329			.ignore_wake = "PNP0C50:00@8",
330		},
331	},
332	{
333		/*
334		 * Spurious wakeups from GPIO 11
335		 * Found in BIOS 1.04
336		 * https://gitlab.freedesktop.org/drm/amd/-/issues/3954
337		 */
338		.matches = {
339			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
340			DMI_MATCH(DMI_PRODUCT_FAMILY, "Acer Nitro V 14"),
341		},
342		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
343			.ignore_interrupt = "AMDI0030:00@11",
344		},
345	},
346	{
347		/*
348		 * Wakeup only works when keyboard backlight is turned off
349		 * https://gitlab.freedesktop.org/drm/amd/-/issues/4169
350		 */
351		.matches = {
352			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
353			DMI_MATCH(DMI_PRODUCT_FAMILY, "Acer Nitro V 15"),
354		},
355		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
356			.ignore_interrupt = "AMDI0030:00@8",
357		},
358	},
359	{
360		/*
361		 * Spurious wakeups from TP_ATTN# pin
362		 * Found in BIOS 5.35
363		 * https://gitlab.freedesktop.org/drm/amd/-/issues/4482
364		 */
365		.matches = {
366			DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
367			DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt PX13"),
368		},
369		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
370			.ignore_wake = "ASCP1A00:00@8",
371		},
372	},
373	{
374		/*
375		 * Spurious wakeups, likely from touchpad controller
376		 * Dell Precision 7780
377		 * Found in BIOS 1.24.1
378		 *
379		 * Found in touchpad firmware, installed by Dell Touchpad Firmware Update Utility version 1160.4196.9, A01
380		 * ( Dell-Touchpad-Firmware-Update-Utility_VYGNN_WIN64_1160.4196.9_A00.EXE ),
381		 * released on 11 Jul 2024
382		 *
383		 * https://lore.kernel.org/linux-i2c/197ae95ffd8.dc819e60457077.7692120488609091556@zohomail.com/
384		 */
385		.matches = {
386			DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
387			DMI_MATCH(DMI_PRODUCT_FAMILY, "Precision"),
388			DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7780"),
389			DMI_MATCH(DMI_BOARD_NAME, "0C6JVW"),
390		},
391		.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
392			.ignore_wake = "VEN_0488:00@355",
393		},
394	},
395	{} /* Terminating entry */
396};
397
398static int __init acpi_gpio_setup_params(void)
399{
400	const struct acpi_gpiolib_dmi_quirk *quirk = NULL;
401	const struct dmi_system_id *id;
402
403	id = dmi_first_match(gpiolib_acpi_quirks);
404	if (id)
405		quirk = id->driver_data;
406
407	if (run_edge_events_on_boot < 0) {
408		if (quirk && quirk->no_edge_events_on_boot)
409			run_edge_events_on_boot = 0;
410		else
411			run_edge_events_on_boot = 1;
412	}
413
414	if (ignore_wake == NULL && quirk && quirk->ignore_wake)
415		ignore_wake = quirk->ignore_wake;
416
417	if (ignore_interrupt == NULL && quirk && quirk->ignore_interrupt)
418		ignore_interrupt = quirk->ignore_interrupt;
419
420	return 0;
421}
422
423/* Directly after dmi_setup() which runs as core_initcall() */
424postcore_initcall(acpi_gpio_setup_params);
~/ Read-only file preview.