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 19 static int run_edge_events_on_boot = -1; 20 module_param(run_edge_events_on_boot, int, 0444); 21 MODULE_PARM_DESC(run_edge_events_on_boot, 22 "Run edge _AEI event-handlers at boot: 0=no, 1=yes, -1=auto"); 23 24 static char *ignore_wake; 25 module_param(ignore_wake, charp, 0444); 26 MODULE_PARM_DESC(ignore_wake, 27 "controller@pin combos on which to ignore the ACPI wake flag " 28 "ignore_wake=controller@pin[,controller@pin[,...]]"); 29 30 static char *ignore_interrupt; 31 module_param(ignore_interrupt, charp, 0444); 32 MODULE_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 */ 43 static DEFINE_MUTEX(acpi_gpio_deferred_req_irqs_lock); 44 static LIST_HEAD(acpi_gpio_deferred_req_irqs_list); 45 static bool acpi_gpio_deferred_req_irqs_done; 46 47 bool 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 60 void 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 68 int acpi_gpio_need_run_edge_events_on_boot(void) 69 { 70 return run_edge_events_on_boot; 71 } 72 73 bool 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; 115 err: 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() */ 121 static 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 */ 131 late_initcall_sync(acpi_gpio_handle_deferred_request_irqs); 132 133 struct acpi_gpiolib_dmi_quirk { 134 bool no_edge_events_on_boot; 135 char *ignore_wake; 136 char *ignore_interrupt; 137 }; 138 139 static 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 * Spurious wakeups from GPIO 11 323 * Found in BIOS 1.04 324 * https://gitlab.freedesktop.org/drm/amd/-/issues/3954 325 */ 326 .matches = { 327 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 328 DMI_MATCH(DMI_PRODUCT_FAMILY, "Acer Nitro V 14"), 329 }, 330 .driver_data = &(struct acpi_gpiolib_dmi_quirk) { 331 .ignore_interrupt = "AMDI0030:00@11", 332 }, 333 }, 334 { 335 /* 336 * Wakeup only works when keyboard backlight is turned off 337 * https://gitlab.freedesktop.org/drm/amd/-/issues/4169 338 */ 339 .matches = { 340 DMI_MATCH(DMI_SYS_VENDOR, "Acer"), 341 DMI_MATCH(DMI_PRODUCT_FAMILY, "Acer Nitro V 15"), 342 }, 343 .driver_data = &(struct acpi_gpiolib_dmi_quirk) { 344 .ignore_interrupt = "AMDI0030:00@8", 345 }, 346 }, 347 { 348 /* 349 * Spurious wakeups from TP_ATTN# pin 350 * Found in BIOS 5.35 351 * https://gitlab.freedesktop.org/drm/amd/-/issues/4482 352 */ 353 .matches = { 354 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), 355 DMI_MATCH(DMI_PRODUCT_FAMILY, "ProArt PX13"), 356 }, 357 .driver_data = &(struct acpi_gpiolib_dmi_quirk) { 358 .ignore_wake = "ASCP1A00:00@8", 359 }, 360 }, 361 {} /* Terminating entry */ 362 }; 363 364 static int __init acpi_gpio_setup_params(void) 365 { 366 const struct acpi_gpiolib_dmi_quirk *quirk = NULL; 367 const struct dmi_system_id *id; 368 369 id = dmi_first_match(gpiolib_acpi_quirks); 370 if (id) 371 quirk = id->driver_data; 372 373 if (run_edge_events_on_boot < 0) { 374 if (quirk && quirk->no_edge_events_on_boot) 375 run_edge_events_on_boot = 0; 376 else 377 run_edge_events_on_boot = 1; 378 } 379 380 if (ignore_wake == NULL && quirk && quirk->ignore_wake) 381 ignore_wake = quirk->ignore_wake; 382 383 if (ignore_interrupt == NULL && quirk && quirk->ignore_interrupt) 384 ignore_interrupt = quirk->ignore_interrupt; 385 386 return 0; 387 } 388 389 /* Directly after dmi_setup() which runs as core_initcall() */ 390 postcore_initcall(acpi_gpio_setup_params); 391