1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * lg-laptop.c - LG Gram ACPI features and hotkeys Driver 4 * 5 * Copyright (C) 2018 Matan Ziv-Av <matan@svgalib.org> 6 */ 7 8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 10 #include <linux/acpi.h> 11 #include <linux/input.h> 12 #include <linux/input/sparse-keymap.h> 13 #include <linux/kernel.h> 14 #include <linux/leds.h> 15 #include <linux/module.h> 16 #include <linux/platform_device.h> 17 #include <linux/types.h> 18 19 #define LED_DEVICE(_name, max) struct led_classdev _name = { \ 20 .name = __stringify(_name), \ 21 .max_brightness = max, \ 22 .brightness_set = _name##_set, \ 23 .brightness_get = _name##_get, \ 24 } 25 26 MODULE_AUTHOR("Matan Ziv-Av"); 27 MODULE_DESCRIPTION("LG WMI Hotkey Driver"); 28 MODULE_LICENSE("GPL"); 29 30 #define WMI_EVENT_GUID0 "E4FB94F9-7F2B-4173-AD1A-CD1D95086248" 31 #define WMI_EVENT_GUID1 "023B133E-49D1-4E10-B313-698220140DC2" 32 #define WMI_EVENT_GUID2 "37BE1AC0-C3F2-4B1F-BFBE-8FDEAF2814D6" 33 #define WMI_EVENT_GUID3 "911BAD44-7DF8-4FBB-9319-BABA1C4B293B" 34 #define WMI_METHOD_WMAB "C3A72B38-D3EF-42D3-8CBB-D5A57049F66D" 35 #define WMI_METHOD_WMBB "2B4F501A-BD3C-4394-8DCF-00A7D2BC8210" 36 #define WMI_EVENT_GUID WMI_EVENT_GUID0 37 38 #define WMAB_METHOD "\\XINI.WMAB" 39 #define WMBB_METHOD "\\XINI.WMBB" 40 #define SB_GGOV_METHOD "\\_SB.GGOV" 41 #define GOV_TLED 0x2020008 42 #define WM_GET 1 43 #define WM_SET 2 44 #define WM_KEY_LIGHT 0x400 45 #define WM_TLED 0x404 46 #define WM_FN_LOCK 0x407 47 #define WM_BATT_LIMIT 0x61 48 #define WM_READER_MODE 0xBF 49 #define WM_FAN_MODE 0x33 50 #define WMBB_USB_CHARGE 0x10B 51 #define WMBB_BATT_LIMIT 0x10C 52 53 #define PLATFORM_NAME "lg-laptop" 54 55 MODULE_ALIAS("wmi:" WMI_EVENT_GUID0); 56 MODULE_ALIAS("wmi:" WMI_EVENT_GUID1); 57 MODULE_ALIAS("wmi:" WMI_EVENT_GUID2); 58 MODULE_ALIAS("wmi:" WMI_EVENT_GUID3); 59 MODULE_ALIAS("wmi:" WMI_METHOD_WMAB); 60 MODULE_ALIAS("wmi:" WMI_METHOD_WMBB); 61 MODULE_ALIAS("acpi*:LGEX0815:*"); 62 63 static struct platform_device *pf_device; 64 static struct input_dev *wmi_input_dev; 65 66 static u32 inited; 67 #define INIT_INPUT_WMI_0 0x01 68 #define INIT_INPUT_WMI_2 0x02 69 #define INIT_INPUT_ACPI 0x04 70 #define INIT_TPAD_LED 0x08 71 #define INIT_KBD_LED 0x10 72 #define INIT_SPARSE_KEYMAP 0x80 73 74 static const struct key_entry wmi_keymap[] = { 75 {KE_KEY, 0x70, {KEY_F15} }, /* LG control panel (F1) */ 76 {KE_KEY, 0x74, {KEY_F13} }, /* Touchpad toggle (F5) */ 77 {KE_KEY, 0xf020000, {KEY_F14} }, /* Read mode (F9) */ 78 {KE_KEY, 0x10000000, {KEY_F16} },/* Keyboard backlight (F8) - pressing 79 * this key both sends an event and 80 * changes backlight level. 81 */ 82 {KE_KEY, 0x80, {KEY_RFKILL} }, 83 {KE_END, 0} 84 }; 85 86 static int ggov(u32 arg0) 87 { 88 union acpi_object args[1]; 89 union acpi_object *r; 90 acpi_status status; 91 acpi_handle handle; 92 struct acpi_object_list arg; 93 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 94 int res; 95 96 args[0].type = ACPI_TYPE_INTEGER; 97 args[0].integer.value = arg0; 98 99 status = acpi_get_handle(NULL, (acpi_string) SB_GGOV_METHOD, &handle); 100 if (ACPI_FAILURE(status)) { 101 pr_err("Cannot get handle"); 102 return -ENODEV; 103 } 104 105 arg.count = 1; 106 arg.pointer = args; 107 108 status = acpi_evaluate_object(handle, NULL, &arg, &buffer); 109 if (ACPI_FAILURE(status)) { 110 acpi_handle_err(handle, "GGOV: call failed.\n"); 111 return -EINVAL; 112 } 113 114 r = buffer.pointer; 115 if (r->type != ACPI_TYPE_INTEGER) { 116 kfree(r); 117 return -EINVAL; 118 } 119 120 res = r->integer.value; 121 kfree(r); 122 123 return res; 124 } 125 126 static union acpi_object *lg_wmab(u32 method, u32 arg1, u32 arg2) 127 { 128 union acpi_object args[3]; 129 acpi_status status; 130 acpi_handle handle; 131 struct acpi_object_list arg; 132 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 133 134 args[0].type = ACPI_TYPE_INTEGER; 135 args[0].integer.value = method; 136 args[1].type = ACPI_TYPE_INTEGER; 137 args[1].integer.value = arg1; 138 args[2].type = ACPI_TYPE_INTEGER; 139 args[2].integer.value = arg2; 140 141 status = acpi_get_handle(NULL, (acpi_string) WMAB_METHOD, &handle); 142 if (ACPI_FAILURE(status)) { 143 pr_err("Cannot get handle"); 144 return NULL; 145 } 146 147 arg.count = 3; 148 arg.pointer = args; 149 150 status = acpi_evaluate_object(handle, NULL, &arg, &buffer); 151 if (ACPI_FAILURE(status)) { 152 acpi_handle_err(handle, "WMAB: call failed.\n"); 153 return NULL; 154 } 155 156 return buffer.pointer; 157 } 158 159 static union acpi_object *lg_wmbb(u32 method_id, u32 arg1, u32 arg2) 160 { 161 union acpi_object args[3]; 162 acpi_status status; 163 acpi_handle handle; 164 struct acpi_object_list arg; 165 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 166 u8 buf[32]; 167 168 *(u32 *)buf = method_id; 169 *(u32 *)(buf + 4) = arg1; 170 *(u32 *)(buf + 16) = arg2; 171 args[0].type = ACPI_TYPE_INTEGER; 172 args[0].integer.value = 0; /* ignored */ 173 args[1].type = ACPI_TYPE_INTEGER; 174 args[1].integer.value = 1; /* Must be 1 or 2. Does not matter which */ 175 args[2].type = ACPI_TYPE_BUFFER; 176 args[2].buffer.length = 32; 177 args[2].buffer.pointer = buf; 178 179 status = acpi_get_handle(NULL, (acpi_string)WMBB_METHOD, &handle); 180 if (ACPI_FAILURE(status)) { 181 pr_err("Cannot get handle"); 182 return NULL; 183 } 184 185 arg.count = 3; 186 arg.pointer = args; 187 188 status = acpi_evaluate_object(handle, NULL, &arg, &buffer); 189 if (ACPI_FAILURE(status)) { 190 acpi_handle_err(handle, "WMAB: call failed.\n"); 191 return NULL; 192 } 193 194 return (union acpi_object *)buffer.pointer; 195 } 196 197 static void wmi_notify(u32 value, void *context) 198 { 199 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 200 union acpi_object *obj; 201 acpi_status status; 202 long data = (long)context; 203 204 pr_debug("event guid %li\n", data); 205 status = wmi_get_event_data(value, &response); 206 if (ACPI_FAILURE(status)) { 207 pr_err("Bad event status 0x%x\n", status); 208 return; 209 } 210 211 obj = (union acpi_object *)response.pointer; 212 if (!obj) 213 return; 214 215 if (obj->type == ACPI_TYPE_INTEGER) { 216 int eventcode = obj->integer.value; 217 struct key_entry *key; 218 219 key = 220 sparse_keymap_entry_from_scancode(wmi_input_dev, eventcode); 221 if (key && key->type == KE_KEY) 222 sparse_keymap_report_entry(wmi_input_dev, key, 1, true); 223 } 224 225 pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type, 226 obj->integer.value); 227 kfree(response.pointer); 228 } 229 230 static void wmi_input_setup(void) 231 { 232 acpi_status status; 233 234 wmi_input_dev = input_allocate_device(); 235 if (wmi_input_dev) { 236 wmi_input_dev->name = "LG WMI hotkeys"; 237 wmi_input_dev->phys = "wmi/input0"; 238 wmi_input_dev->id.bustype = BUS_HOST; 239 240 if (sparse_keymap_setup(wmi_input_dev, wmi_keymap, NULL) || 241 input_register_device(wmi_input_dev)) { 242 pr_info("Cannot initialize input device"); 243 input_free_device(wmi_input_dev); 244 return; 245 } 246 247 inited |= INIT_SPARSE_KEYMAP; 248 status = wmi_install_notify_handler(WMI_EVENT_GUID0, wmi_notify, 249 (void *)0); 250 if (ACPI_SUCCESS(status)) 251 inited |= INIT_INPUT_WMI_0; 252 253 status = wmi_install_notify_handler(WMI_EVENT_GUID2, wmi_notify, 254 (void *)2); 255 if (ACPI_SUCCESS(status)) 256 inited |= INIT_INPUT_WMI_2; 257 } else { 258 pr_info("Cannot allocate input device"); 259 } 260 } 261 262 static void acpi_notify(struct acpi_device *device, u32 event) 263 { 264 struct key_entry *key; 265 266 acpi_handle_debug(device->handle, "notify: %d\n", event); 267 if (inited & INIT_SPARSE_KEYMAP) { 268 key = sparse_keymap_entry_from_scancode(wmi_input_dev, 0x80); 269 if (key && key->type == KE_KEY) 270 sparse_keymap_report_entry(wmi_input_dev, key, 1, true); 271 } 272 } 273 274 static ssize_t fan_mode_store(struct device *dev, 275 struct device_attribute *attr, 276 const char *buffer, size_t count) 277 { 278 bool value; 279 union acpi_object *r; 280 u32 m; 281 int ret; 282 283 ret = kstrtobool(buffer, &value); 284 if (ret) 285 return ret; 286 287 r = lg_wmab(WM_FAN_MODE, WM_GET, 0); 288 if (!r) 289 return -EIO; 290 291 if (r->type != ACPI_TYPE_INTEGER) { 292 kfree(r); 293 return -EIO; 294 } 295 296 m = r->integer.value; 297 kfree(r); 298 r = lg_wmab(WM_FAN_MODE, WM_SET, (m & 0xffffff0f) | (value << 4)); 299 kfree(r); 300 r = lg_wmab(WM_FAN_MODE, WM_SET, (m & 0xfffffff0) | value); 301 kfree(r); 302 303 return count; 304 } 305 306 static ssize_t fan_mode_show(struct device *dev, 307 struct device_attribute *attr, char *buffer) 308 { 309 unsigned int status; 310 union acpi_object *r; 311 312 r = lg_wmab(WM_FAN_MODE, WM_GET, 0); 313 if (!r) 314 return -EIO; 315 316 if (r->type != ACPI_TYPE_INTEGER) { 317 kfree(r); 318 return -EIO; 319 } 320 321 status = r->integer.value & 0x01; 322 kfree(r); 323 324 return snprintf(buffer, PAGE_SIZE, "%d\n", status); 325 } 326 327 static ssize_t usb_charge_store(struct device *dev, 328 struct device_attribute *attr, 329 const char *buffer, size_t count) 330 { 331 bool value; 332 union acpi_object *r; 333 int ret; 334 335 ret = kstrtobool(buffer, &value); 336 if (ret) 337 return ret; 338 339 r = lg_wmbb(WMBB_USB_CHARGE, WM_SET, value); 340 if (!r) 341 return -EIO; 342 343 kfree(r); 344 return count; 345 } 346 347 static ssize_t usb_charge_show(struct device *dev, 348 struct device_attribute *attr, char *buffer) 349 { 350 unsigned int status; 351 union acpi_object *r; 352 353 r = lg_wmbb(WMBB_USB_CHARGE, WM_GET, 0); 354 if (!r) 355 return -EIO; 356 357 if (r->type != ACPI_TYPE_BUFFER) { 358 kfree(r); 359 return -EIO; 360 } 361 362 status = !!r->buffer.pointer[0x10]; 363 364 kfree(r); 365 366 return snprintf(buffer, PAGE_SIZE, "%d\n", status); 367 } 368 369 static ssize_t reader_mode_store(struct device *dev, 370 struct device_attribute *attr, 371 const char *buffer, size_t count) 372 { 373 bool value; 374 union acpi_object *r; 375 int ret; 376 377 ret = kstrtobool(buffer, &value); 378 if (ret) 379 return ret; 380 381 r = lg_wmab(WM_READER_MODE, WM_SET, value); 382 if (!r) 383 return -EIO; 384 385 kfree(r); 386 return count; 387 } 388 389 static ssize_t reader_mode_show(struct device *dev, 390 struct device_attribute *attr, char *buffer) 391 { 392 unsigned int status; 393 union acpi_object *r; 394 395 r = lg_wmab(WM_READER_MODE, WM_GET, 0); 396 if (!r) 397 return -EIO; 398 399 if (r->type != ACPI_TYPE_INTEGER) { 400 kfree(r); 401 return -EIO; 402 } 403 404 status = !!r->integer.value; 405 406 kfree(r); 407 408 return snprintf(buffer, PAGE_SIZE, "%d\n", status); 409 } 410 411 static ssize_t fn_lock_store(struct device *dev, 412 struct device_attribute *attr, 413 const char *buffer, size_t count) 414 { 415 bool value; 416 union acpi_object *r; 417 int ret; 418 419 ret = kstrtobool(buffer, &value); 420 if (ret) 421 return ret; 422 423 r = lg_wmab(WM_FN_LOCK, WM_SET, value); 424 if (!r) 425 return -EIO; 426 427 kfree(r); 428 return count; 429 } 430 431 static ssize_t fn_lock_show(struct device *dev, 432 struct device_attribute *attr, char *buffer) 433 { 434 unsigned int status; 435 union acpi_object *r; 436 437 r = lg_wmab(WM_FN_LOCK, WM_GET, 0); 438 if (!r) 439 return -EIO; 440 441 if (r->type != ACPI_TYPE_BUFFER) { 442 kfree(r); 443 return -EIO; 444 } 445 446 status = !!r->buffer.pointer[0]; 447 kfree(r); 448 449 return snprintf(buffer, PAGE_SIZE, "%d\n", status); 450 } 451 452 static ssize_t battery_care_limit_store(struct device *dev, 453 struct device_attribute *attr, 454 const char *buffer, size_t count) 455 { 456 unsigned long value; 457 int ret; 458 459 ret = kstrtoul(buffer, 10, &value); 460 if (ret) 461 return ret; 462 463 if (value == 100 || value == 80) { 464 union acpi_object *r; 465 466 r = lg_wmab(WM_BATT_LIMIT, WM_SET, value); 467 if (!r) 468 return -EIO; 469 470 kfree(r); 471 return count; 472 } 473 474 return -EINVAL; 475 } 476 477 static ssize_t battery_care_limit_show(struct device *dev, 478 struct device_attribute *attr, 479 char *buffer) 480 { 481 unsigned int status; 482 union acpi_object *r; 483 484 r = lg_wmab(WM_BATT_LIMIT, WM_GET, 0); 485 if (!r) 486 return -EIO; 487 488 if (r->type != ACPI_TYPE_INTEGER) { 489 kfree(r); 490 return -EIO; 491 } 492 493 status = r->integer.value; 494 kfree(r); 495 if (status != 80 && status != 100) 496 status = 0; 497 498 return snprintf(buffer, PAGE_SIZE, "%d\n", status); 499 } 500 501 static DEVICE_ATTR_RW(fan_mode); 502 static DEVICE_ATTR_RW(usb_charge); 503 static DEVICE_ATTR_RW(reader_mode); 504 static DEVICE_ATTR_RW(fn_lock); 505 static DEVICE_ATTR_RW(battery_care_limit); 506 507 static struct attribute *dev_attributes[] = { 508 &dev_attr_fan_mode.attr, 509 &dev_attr_usb_charge.attr, 510 &dev_attr_reader_mode.attr, 511 &dev_attr_fn_lock.attr, 512 &dev_attr_battery_care_limit.attr, 513 NULL 514 }; 515 516 static const struct attribute_group dev_attribute_group = { 517 .attrs = dev_attributes, 518 }; 519 520 static void tpad_led_set(struct led_classdev *cdev, 521 enum led_brightness brightness) 522 { 523 union acpi_object *r; 524 525 r = lg_wmab(WM_TLED, WM_SET, brightness > LED_OFF); 526 kfree(r); 527 } 528 529 static enum led_brightness tpad_led_get(struct led_classdev *cdev) 530 { 531 return ggov(GOV_TLED) > 0 ? LED_ON : LED_OFF; 532 } 533 534 static LED_DEVICE(tpad_led, 1); 535 536 static void kbd_backlight_set(struct led_classdev *cdev, 537 enum led_brightness brightness) 538 { 539 u32 val; 540 union acpi_object *r; 541 542 val = 0x22; 543 if (brightness <= LED_OFF) 544 val = 0; 545 if (brightness >= LED_FULL) 546 val = 0x24; 547 r = lg_wmab(WM_KEY_LIGHT, WM_SET, val); 548 kfree(r); 549 } 550 551 static enum led_brightness kbd_backlight_get(struct led_classdev *cdev) 552 { 553 union acpi_object *r; 554 int val; 555 556 r = lg_wmab(WM_KEY_LIGHT, WM_GET, 0); 557 558 if (!r) 559 return LED_OFF; 560 561 if (r->type != ACPI_TYPE_BUFFER || r->buffer.pointer[1] != 0x05) { 562 kfree(r); 563 return LED_OFF; 564 } 565 566 switch (r->buffer.pointer[0] & 0x27) { 567 case 0x24: 568 val = LED_FULL; 569 break; 570 case 0x22: 571 val = LED_HALF; 572 break; 573 default: 574 val = LED_OFF; 575 } 576 577 kfree(r); 578 579 return val; 580 } 581 582 static LED_DEVICE(kbd_backlight, 255); 583 584 static void wmi_input_destroy(void) 585 { 586 if (inited & INIT_INPUT_WMI_2) 587 wmi_remove_notify_handler(WMI_EVENT_GUID2); 588 589 if (inited & INIT_INPUT_WMI_0) 590 wmi_remove_notify_handler(WMI_EVENT_GUID0); 591 592 if (inited & INIT_SPARSE_KEYMAP) 593 input_unregister_device(wmi_input_dev); 594 595 inited &= ~(INIT_INPUT_WMI_0 | INIT_INPUT_WMI_2 | INIT_SPARSE_KEYMAP); 596 } 597 598 static struct platform_driver pf_driver = { 599 .driver = { 600 .name = PLATFORM_NAME, 601 } 602 }; 603 604 static int acpi_add(struct acpi_device *device) 605 { 606 int ret; 607 608 if (pf_device) 609 return 0; 610 611 ret = platform_driver_register(&pf_driver); 612 if (ret) 613 return ret; 614 615 pf_device = platform_device_register_simple(PLATFORM_NAME, 616 PLATFORM_DEVID_NONE, 617 NULL, 0); 618 if (IS_ERR(pf_device)) { 619 ret = PTR_ERR(pf_device); 620 pf_device = NULL; 621 pr_err("unable to register platform device\n"); 622 goto out_platform_registered; 623 } 624 625 ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group); 626 if (ret) 627 goto out_platform_device; 628 629 if (!led_classdev_register(&pf_device->dev, &kbd_backlight)) 630 inited |= INIT_KBD_LED; 631 632 if (!led_classdev_register(&pf_device->dev, &tpad_led)) 633 inited |= INIT_TPAD_LED; 634 635 wmi_input_setup(); 636 637 return 0; 638 639 out_platform_device: 640 platform_device_unregister(pf_device); 641 out_platform_registered: 642 platform_driver_unregister(&pf_driver); 643 return ret; 644 } 645 646 static int acpi_remove(struct acpi_device *device) 647 { 648 sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group); 649 if (inited & INIT_KBD_LED) 650 led_classdev_unregister(&kbd_backlight); 651 652 if (inited & INIT_TPAD_LED) 653 led_classdev_unregister(&tpad_led); 654 655 wmi_input_destroy(); 656 platform_device_unregister(pf_device); 657 pf_device = NULL; 658 platform_driver_unregister(&pf_driver); 659 660 return 0; 661 } 662 663 static const struct acpi_device_id device_ids[] = { 664 {"LGEX0815", 0}, 665 {"", 0} 666 }; 667 MODULE_DEVICE_TABLE(acpi, device_ids); 668 669 static struct acpi_driver acpi_driver = { 670 .name = "LG Gram Laptop Support", 671 .class = "lg-laptop", 672 .ids = device_ids, 673 .ops = { 674 .add = acpi_add, 675 .remove = acpi_remove, 676 .notify = acpi_notify, 677 }, 678 .owner = THIS_MODULE, 679 }; 680 681 static int __init acpi_init(void) 682 { 683 int result; 684 685 result = acpi_bus_register_driver(&acpi_driver); 686 if (result < 0) { 687 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error registering driver\n")); 688 return -ENODEV; 689 } 690 691 return 0; 692 } 693 694 static void __exit acpi_exit(void) 695 { 696 acpi_bus_unregister_driver(&acpi_driver); 697 } 698 699 module_init(acpi_init); 700 module_exit(acpi_exit); 701