FILE
gpiolib-acpi-quirks.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpio/gpiolib-acpi-quirks.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.