FILE
lg-laptop.c
File preview with syntax highlighting.
linux-6.19.14/drivers/platform/x86/lg-laptop.c
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/bitfield.h> 12#include <linux/bits.h> 13#include <linux/device.h> 14#include <linux/dev_printk.h> 15#include <linux/dmi.h> 16#include <linux/input.h> 17#include <linux/input/sparse-keymap.h> 18#include <linux/kernel.h> 19#include <linux/leds.h> 20#include <linux/module.h> 21#include <linux/platform_device.h> 22#include <linux/string_choices.h> 23#include <linux/types.h> 24 25#include <acpi/battery.h> 26 27#define LED_DEVICE(_name, max, flag) struct led_classdev _name = { \ 28 .name = __stringify(_name), \ 29 .max_brightness = max, \ 30 .brightness_set = _name##_set, \ 31 .brightness_get = _name##_get, \ 32 .flags = flag, \ 33} 34 35MODULE_AUTHOR("Matan Ziv-Av"); 36MODULE_DESCRIPTION("LG WMI Hotkey Driver"); 37MODULE_LICENSE("GPL"); 38 39static bool fw_debug; 40module_param(fw_debug, bool, 0); 41MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages"); 42 43#define LG_ADDRESS_SPACE_ID 0x8F 44 45#define LG_ADDRESS_SPACE_DEBUG_FLAG_ADR 0x00 46#define LG_ADDRESS_SPACE_HD_AUDIO_POWER_ADDR 0x01 47#define LG_ADDRESS_SPACE_FAN_MODE_ADR 0x03 48 49#define LG_ADDRESS_SPACE_DTTM_FLAG_ADR 0x20 50#define LG_ADDRESS_SPACE_CPU_TEMP_ADR 0x21 51#define LG_ADDRESS_SPACE_CPU_TRIP_LOW_ADR 0x22 52#define LG_ADDRESS_SPACE_CPU_TRIP_HIGH_ADR 0x23 53#define LG_ADDRESS_SPACE_MB_TEMP_ADR 0x24 54#define LG_ADDRESS_SPACE_MB_TRIP_LOW_ADR 0x25 55#define LG_ADDRESS_SPACE_MB_TRIP_HIGH_ADR 0x26 56 57#define LG_ADDRESS_SPACE_DEBUG_MSG_START_ADR 0x3E8 58#define LG_ADDRESS_SPACE_DEBUG_MSG_END_ADR 0x5E8 59 60#define WMI_EVENT_GUID0 "E4FB94F9-7F2B-4173-AD1A-CD1D95086248" 61#define WMI_EVENT_GUID1 "023B133E-49D1-4E10-B313-698220140DC2" 62#define WMI_EVENT_GUID2 "37BE1AC0-C3F2-4B1F-BFBE-8FDEAF2814D6" 63#define WMI_EVENT_GUID3 "911BAD44-7DF8-4FBB-9319-BABA1C4B293B" 64#define WMI_METHOD_WMAB "C3A72B38-D3EF-42D3-8CBB-D5A57049F66D" 65#define WMI_METHOD_WMBB "2B4F501A-BD3C-4394-8DCF-00A7D2BC8210" 66#define WMI_EVENT_GUID WMI_EVENT_GUID0 67 68#define SB_GGOV_METHOD "\\_SB.GGOV" 69#define GOV_TLED 0x2020008 70#define WM_GET 1 71#define WM_SET 2 72#define WM_KEY_LIGHT 0x400 73#define WM_TLED 0x404 74#define WM_FN_LOCK 0x407 75#define WM_BATT_LIMIT 0x61 76#define WM_READER_MODE 0xBF 77#define WM_FAN_MODE 0x33 78#define WMBB_USB_CHARGE 0x10B 79#define WMBB_BATT_LIMIT 0x10C 80 81#define FAN_MODE_LOWER GENMASK(1, 0) 82#define FAN_MODE_UPPER GENMASK(5, 4) 83 84#define PLATFORM_NAME "lg-laptop" 85 86MODULE_ALIAS("wmi:" WMI_EVENT_GUID0); 87MODULE_ALIAS("wmi:" WMI_EVENT_GUID1); 88MODULE_ALIAS("wmi:" WMI_EVENT_GUID2); 89MODULE_ALIAS("wmi:" WMI_EVENT_GUID3); 90MODULE_ALIAS("wmi:" WMI_METHOD_WMAB); 91MODULE_ALIAS("wmi:" WMI_METHOD_WMBB); 92 93static struct platform_device *pf_device; 94static struct input_dev *wmi_input_dev; 95 96static u32 inited; 97#define INIT_INPUT_WMI_0 0x01 98#define INIT_INPUT_WMI_2 0x02 99#define INIT_INPUT_ACPI 0x04 100#define INIT_SPARSE_KEYMAP 0x80 101 102static int battery_limit_use_wmbb; 103static struct led_classdev kbd_backlight; 104static enum led_brightness get_kbd_backlight_level(struct device *dev); 105 106static const struct key_entry wmi_keymap[] = { 107 {KE_KEY, 0x70, {KEY_F15} }, /* LG control panel (F1) */ 108 {KE_KEY, 0x74, {KEY_F21} }, /* Touchpad toggle (F5) */ 109 {KE_KEY, 0xf020000, {KEY_F14} }, /* Read mode (F9) */ 110 {KE_KEY, 0x10000000, {KEY_F16} },/* Keyboard backlight (F8) - pressing 111 * this key both sends an event and 112 * changes backlight level. 113 */ 114 {KE_END, 0} 115}; 116 117static int ggov(u32 arg0) 118{ 119 union acpi_object args[1]; 120 union acpi_object *r; 121 acpi_status status; 122 acpi_handle handle; 123 struct acpi_object_list arg; 124 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 125 int res; 126 127 args[0].type = ACPI_TYPE_INTEGER; 128 args[0].integer.value = arg0; 129 130 status = acpi_get_handle(NULL, (acpi_string) SB_GGOV_METHOD, &handle); 131 if (ACPI_FAILURE(status)) { 132 pr_err("Cannot get handle"); 133 return -ENODEV; 134 } 135 136 arg.count = 1; 137 arg.pointer = args; 138 139 status = acpi_evaluate_object(handle, NULL, &arg, &buffer); 140 if (ACPI_FAILURE(status)) { 141 acpi_handle_err(handle, "GGOV: call failed.\n"); 142 return -EINVAL; 143 } 144 145 r = buffer.pointer; 146 if (r->type != ACPI_TYPE_INTEGER) { 147 kfree(r); 148 return -EINVAL; 149 } 150 151 res = r->integer.value; 152 kfree(r); 153 154 return res; 155} 156 157static union acpi_object *lg_wmab(struct device *dev, u32 method, u32 arg1, u32 arg2) 158{ 159 union acpi_object args[3]; 160 acpi_status status; 161 struct acpi_object_list arg; 162 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 163 164 args[0].type = ACPI_TYPE_INTEGER; 165 args[0].integer.value = method; 166 args[1].type = ACPI_TYPE_INTEGER; 167 args[1].integer.value = arg1; 168 args[2].type = ACPI_TYPE_INTEGER; 169 args[2].integer.value = arg2; 170 171 arg.count = 3; 172 arg.pointer = args; 173 174 status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMAB", &arg, &buffer); 175 if (ACPI_FAILURE(status)) { 176 dev_err(dev, "WMAB: call failed.\n"); 177 return NULL; 178 } 179 180 return buffer.pointer; 181} 182 183static union acpi_object *lg_wmbb(struct device *dev, u32 method_id, u32 arg1, u32 arg2) 184{ 185 union acpi_object args[3]; 186 acpi_status status; 187 struct acpi_object_list arg; 188 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 189 u8 buf[32]; 190 191 *(u32 *)buf = method_id; 192 *(u32 *)(buf + 4) = arg1; 193 *(u32 *)(buf + 16) = arg2; 194 args[0].type = ACPI_TYPE_INTEGER; 195 args[0].integer.value = 0; /* ignored */ 196 args[1].type = ACPI_TYPE_INTEGER; 197 args[1].integer.value = 1; /* Must be 1 or 2. Does not matter which */ 198 args[2].type = ACPI_TYPE_BUFFER; 199 args[2].buffer.length = 32; 200 args[2].buffer.pointer = buf; 201 202 arg.count = 3; 203 arg.pointer = args; 204 205 status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMBB", &arg, &buffer); 206 if (ACPI_FAILURE(status)) { 207 dev_err(dev, "WMBB: call failed.\n"); 208 return NULL; 209 } 210 211 return (union acpi_object *)buffer.pointer; 212} 213 214static void wmi_notify(union acpi_object *obj, void *context) 215{ 216 long data = (long)context; 217 218 pr_debug("event guid %li\n", data); 219 if (!obj) 220 return; 221 222 if (obj->type == ACPI_TYPE_INTEGER) { 223 int eventcode = obj->integer.value; 224 struct key_entry *key; 225 226 if (eventcode == 0x10000000) { 227 led_classdev_notify_brightness_hw_changed( 228 &kbd_backlight, get_kbd_backlight_level(kbd_backlight.dev->parent)); 229 } else { 230 key = sparse_keymap_entry_from_scancode( 231 wmi_input_dev, eventcode); 232 if (key && key->type == KE_KEY) 233 sparse_keymap_report_entry(wmi_input_dev, 234 key, 1, true); 235 } 236 } 237 238 pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type, 239 obj->integer.value); 240} 241 242static void wmi_input_setup(void) 243{ 244 acpi_status status; 245 246 wmi_input_dev = input_allocate_device(); 247 if (wmi_input_dev) { 248 wmi_input_dev->name = "LG WMI hotkeys"; 249 wmi_input_dev->phys = "wmi/input0"; 250 wmi_input_dev->id.bustype = BUS_HOST; 251 252 if (sparse_keymap_setup(wmi_input_dev, wmi_keymap, NULL) || 253 input_register_device(wmi_input_dev)) { 254 pr_info("Cannot initialize input device"); 255 input_free_device(wmi_input_dev); 256 return; 257 } 258 259 inited |= INIT_SPARSE_KEYMAP; 260 status = wmi_install_notify_handler(WMI_EVENT_GUID0, wmi_notify, 261 (void *)0); 262 if (ACPI_SUCCESS(status)) 263 inited |= INIT_INPUT_WMI_0; 264 265 status = wmi_install_notify_handler(WMI_EVENT_GUID2, wmi_notify, 266 (void *)2); 267 if (ACPI_SUCCESS(status)) 268 inited |= INIT_INPUT_WMI_2; 269 } else { 270 pr_info("Cannot allocate input device"); 271 } 272} 273 274static void acpi_notify(struct acpi_device *device, u32 event) 275{ 276 acpi_handle_debug(device->handle, "notify: %d\n", event); 277} 278 279static ssize_t fan_mode_store(struct device *dev, 280 struct device_attribute *attr, 281 const char *buffer, size_t count) 282{ 283 unsigned long value; 284 union acpi_object *r; 285 int ret; 286 287 ret = kstrtoul(buffer, 10, &value); 288 if (ret) 289 return ret; 290 if (value >= 3) 291 return -EINVAL; 292 293 r = lg_wmab(dev, WM_FAN_MODE, WM_SET, 294 FIELD_PREP(FAN_MODE_LOWER, value) | 295 FIELD_PREP(FAN_MODE_UPPER, value)); 296 kfree(r); 297 298 return count; 299} 300 301static ssize_t fan_mode_show(struct device *dev, 302 struct device_attribute *attr, char *buffer) 303{ 304 unsigned int mode; 305 union acpi_object *r; 306 307 r = lg_wmab(dev, WM_FAN_MODE, WM_GET, 0); 308 if (!r) 309 return -EIO; 310 311 if (r->type != ACPI_TYPE_INTEGER) { 312 kfree(r); 313 return -EIO; 314 } 315 316 mode = FIELD_GET(FAN_MODE_LOWER, r->integer.value); 317 kfree(r); 318 319 return sysfs_emit(buffer, "%d\n", mode); 320} 321 322static ssize_t usb_charge_store(struct device *dev, 323 struct device_attribute *attr, 324 const char *buffer, size_t count) 325{ 326 bool value; 327 union acpi_object *r; 328 int ret; 329 330 ret = kstrtobool(buffer, &value); 331 if (ret) 332 return ret; 333 334 r = lg_wmbb(dev, WMBB_USB_CHARGE, WM_SET, value); 335 if (!r) 336 return -EIO; 337 338 kfree(r); 339 return count; 340} 341 342static ssize_t usb_charge_show(struct device *dev, 343 struct device_attribute *attr, char *buffer) 344{ 345 unsigned int status; 346 union acpi_object *r; 347 348 r = lg_wmbb(dev, WMBB_USB_CHARGE, WM_GET, 0); 349 if (!r) 350 return -EIO; 351 352 if (r->type != ACPI_TYPE_BUFFER) { 353 kfree(r); 354 return -EIO; 355 } 356 357 status = !!r->buffer.pointer[0x10]; 358 359 kfree(r); 360 361 return sysfs_emit(buffer, "%d\n", status); 362} 363 364static ssize_t reader_mode_store(struct device *dev, 365 struct device_attribute *attr, 366 const char *buffer, size_t count) 367{ 368 bool value; 369 union acpi_object *r; 370 int ret; 371 372 ret = kstrtobool(buffer, &value); 373 if (ret) 374 return ret; 375 376 r = lg_wmab(dev, WM_READER_MODE, WM_SET, value); 377 if (!r) 378 return -EIO; 379 380 kfree(r); 381 return count; 382} 383 384static ssize_t reader_mode_show(struct device *dev, 385 struct device_attribute *attr, char *buffer) 386{ 387 unsigned int status; 388 union acpi_object *r; 389 390 r = lg_wmab(dev, WM_READER_MODE, WM_GET, 0); 391 if (!r) 392 return -EIO; 393 394 if (r->type != ACPI_TYPE_INTEGER) { 395 kfree(r); 396 return -EIO; 397 } 398 399 status = !!r->integer.value; 400 401 kfree(r); 402 403 return sysfs_emit(buffer, "%d\n", status); 404} 405 406static ssize_t fn_lock_store(struct device *dev, 407 struct device_attribute *attr, 408 const char *buffer, size_t count) 409{ 410 bool value; 411 union acpi_object *r; 412 int ret; 413 414 ret = kstrtobool(buffer, &value); 415 if (ret) 416 return ret; 417 418 r = lg_wmab(dev, WM_FN_LOCK, WM_SET, value); 419 if (!r) 420 return -EIO; 421 422 kfree(r); 423 return count; 424} 425 426static ssize_t fn_lock_show(struct device *dev, 427 struct device_attribute *attr, char *buffer) 428{ 429 unsigned int status; 430 union acpi_object *r; 431 432 r = lg_wmab(dev, WM_FN_LOCK, WM_GET, 0); 433 if (!r) 434 return -EIO; 435 436 if (r->type != ACPI_TYPE_BUFFER) { 437 kfree(r); 438 return -EIO; 439 } 440 441 status = !!r->buffer.pointer[0]; 442 kfree(r); 443 444 return sysfs_emit(buffer, "%d\n", status); 445} 446 447static ssize_t charge_control_end_threshold_store(struct device *dev, 448 struct device_attribute *attr, 449 const char *buf, size_t count) 450{ 451 unsigned long value; 452 int ret; 453 454 ret = kstrtoul(buf, 10, &value); 455 if (ret) 456 return ret; 457 458 if (value == 100 || value == 80) { 459 union acpi_object *r; 460 461 if (battery_limit_use_wmbb) 462 r = lg_wmbb(&pf_device->dev, WMBB_BATT_LIMIT, WM_SET, value); 463 else 464 r = lg_wmab(&pf_device->dev, WM_BATT_LIMIT, WM_SET, value); 465 if (!r) 466 return -EIO; 467 468 kfree(r); 469 return count; 470 } 471 472 return -EINVAL; 473} 474 475static ssize_t charge_control_end_threshold_show(struct device *device, 476 struct device_attribute *attr, 477 char *buf) 478{ 479 unsigned int status; 480 union acpi_object *r; 481 482 if (battery_limit_use_wmbb) { 483 r = lg_wmbb(&pf_device->dev, WMBB_BATT_LIMIT, WM_GET, 0); 484 if (!r) 485 return -EIO; 486 487 if (r->type != ACPI_TYPE_BUFFER) { 488 kfree(r); 489 return -EIO; 490 } 491 492 status = r->buffer.pointer[0x10]; 493 } else { 494 r = lg_wmab(&pf_device->dev, WM_BATT_LIMIT, WM_GET, 0); 495 if (!r) 496 return -EIO; 497 498 if (r->type != ACPI_TYPE_INTEGER) { 499 kfree(r); 500 return -EIO; 501 } 502 503 status = r->integer.value; 504 } 505 kfree(r); 506 if (status != 80 && status != 100) 507 status = 0; 508 509 return sysfs_emit(buf, "%d\n", status); 510} 511 512static ssize_t battery_care_limit_show(struct device *dev, 513 struct device_attribute *attr, 514 char *buffer) 515{ 516 return charge_control_end_threshold_show(dev, attr, buffer); 517} 518 519static ssize_t battery_care_limit_store(struct device *dev, 520 struct device_attribute *attr, 521 const char *buffer, size_t count) 522{ 523 return charge_control_end_threshold_store(dev, attr, buffer, count); 524} 525 526static DEVICE_ATTR_RW(fan_mode); 527static DEVICE_ATTR_RW(usb_charge); 528static DEVICE_ATTR_RW(reader_mode); 529static DEVICE_ATTR_RW(fn_lock); 530static DEVICE_ATTR_RW(charge_control_end_threshold); 531static DEVICE_ATTR_RW(battery_care_limit); 532 533static int lg_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook) 534{ 535 if (device_create_file(&battery->dev, 536 &dev_attr_charge_control_end_threshold)) 537 return -ENODEV; 538 539 return 0; 540} 541 542static int lg_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook) 543{ 544 device_remove_file(&battery->dev, 545 &dev_attr_charge_control_end_threshold); 546 return 0; 547} 548 549static struct acpi_battery_hook battery_hook = { 550 .add_battery = lg_battery_add, 551 .remove_battery = lg_battery_remove, 552 .name = "LG Battery Extension", 553}; 554 555static struct attribute *dev_attributes[] = { 556 &dev_attr_fan_mode.attr, 557 &dev_attr_usb_charge.attr, 558 &dev_attr_reader_mode.attr, 559 &dev_attr_fn_lock.attr, 560 &dev_attr_battery_care_limit.attr, 561 NULL 562}; 563 564static const struct attribute_group dev_attribute_group = { 565 .attrs = dev_attributes, 566}; 567 568static void tpad_led_set(struct led_classdev *cdev, 569 enum led_brightness brightness) 570{ 571 union acpi_object *r; 572 573 r = lg_wmab(cdev->dev->parent, WM_TLED, WM_SET, brightness > LED_OFF); 574 kfree(r); 575} 576 577static enum led_brightness tpad_led_get(struct led_classdev *cdev) 578{ 579 return ggov(GOV_TLED) > 0 ? LED_ON : LED_OFF; 580} 581 582static LED_DEVICE(tpad_led, 1, 0); 583 584static void kbd_backlight_set(struct led_classdev *cdev, 585 enum led_brightness brightness) 586{ 587 u32 val; 588 union acpi_object *r; 589 590 val = 0x22; 591 if (brightness <= LED_OFF) 592 val = 0; 593 if (brightness >= LED_FULL) 594 val = 0x24; 595 r = lg_wmab(cdev->dev->parent, WM_KEY_LIGHT, WM_SET, val); 596 kfree(r); 597} 598 599static enum led_brightness get_kbd_backlight_level(struct device *dev) 600{ 601 union acpi_object *r; 602 int val; 603 604 r = lg_wmab(dev, WM_KEY_LIGHT, WM_GET, 0); 605 606 if (!r) 607 return LED_OFF; 608 609 if (r->type != ACPI_TYPE_BUFFER || r->buffer.pointer[1] != 0x05) { 610 kfree(r); 611 return LED_OFF; 612 } 613 614 switch (r->buffer.pointer[0] & 0x27) { 615 case 0x24: 616 val = LED_FULL; 617 break; 618 case 0x22: 619 val = LED_HALF; 620 break; 621 default: 622 val = LED_OFF; 623 } 624 625 kfree(r); 626 627 return val; 628} 629 630static enum led_brightness kbd_backlight_get(struct led_classdev *cdev) 631{ 632 return get_kbd_backlight_level(cdev->dev->parent); 633} 634 635static LED_DEVICE(kbd_backlight, 255, LED_BRIGHT_HW_CHANGED); 636 637static void wmi_input_destroy(void) 638{ 639 if (inited & INIT_INPUT_WMI_2) 640 wmi_remove_notify_handler(WMI_EVENT_GUID2); 641 642 if (inited & INIT_INPUT_WMI_0) 643 wmi_remove_notify_handler(WMI_EVENT_GUID0); 644 645 if (inited & INIT_SPARSE_KEYMAP) 646 input_unregister_device(wmi_input_dev); 647 648 inited &= ~(INIT_INPUT_WMI_0 | INIT_INPUT_WMI_2 | INIT_SPARSE_KEYMAP); 649} 650 651static struct platform_driver pf_driver = { 652 .driver = { 653 .name = PLATFORM_NAME, 654 } 655}; 656 657static acpi_status lg_laptop_address_space_write(struct device *dev, acpi_physical_address address, 658 size_t size, u64 value) 659{ 660 u8 byte; 661 662 /* Ignore any debug messages */ 663 if (address >= LG_ADDRESS_SPACE_DEBUG_MSG_START_ADR && 664 address <= LG_ADDRESS_SPACE_DEBUG_MSG_END_ADR) 665 return AE_OK; 666 667 if (size != sizeof(byte)) 668 return AE_BAD_PARAMETER; 669 670 byte = value & 0xFF; 671 672 switch (address) { 673 case LG_ADDRESS_SPACE_HD_AUDIO_POWER_ADDR: 674 /* 675 * The HD audio power field is not affected by the DTTM flag, 676 * so we have to manually check fw_debug. 677 */ 678 if (fw_debug) 679 dev_dbg(dev, "HD audio power %s\n", str_enabled_disabled(byte)); 680 681 return AE_OK; 682 case LG_ADDRESS_SPACE_FAN_MODE_ADR: 683 /* 684 * The fan mode field is not affected by the DTTM flag, so we 685 * have to manually check fw_debug. 686 */ 687 if (fw_debug) 688 dev_dbg(dev, "Fan mode set to mode %u\n", byte); 689 690 return AE_OK; 691 case LG_ADDRESS_SPACE_CPU_TEMP_ADR: 692 dev_dbg(dev, "CPU temperature is %u °C\n", byte); 693 return AE_OK; 694 case LG_ADDRESS_SPACE_CPU_TRIP_LOW_ADR: 695 dev_dbg(dev, "CPU lower trip point set to %u °C\n", byte); 696 return AE_OK; 697 case LG_ADDRESS_SPACE_CPU_TRIP_HIGH_ADR: 698 dev_dbg(dev, "CPU higher trip point set to %u °C\n", byte); 699 return AE_OK; 700 case LG_ADDRESS_SPACE_MB_TEMP_ADR: 701 dev_dbg(dev, "Motherboard temperature is %u °C\n", byte); 702 return AE_OK; 703 case LG_ADDRESS_SPACE_MB_TRIP_LOW_ADR: 704 dev_dbg(dev, "Motherboard lower trip point set to %u °C\n", byte); 705 return AE_OK; 706 case LG_ADDRESS_SPACE_MB_TRIP_HIGH_ADR: 707 dev_dbg(dev, "Motherboard higher trip point set to %u °C\n", byte); 708 return AE_OK; 709 default: 710 dev_notice_ratelimited(dev, "Ignoring write to unknown opregion address %llu\n", 711 address); 712 return AE_OK; 713 } 714} 715 716static acpi_status lg_laptop_address_space_read(struct device *dev, acpi_physical_address address, 717 size_t size, u64 *value) 718{ 719 if (size != 1) 720 return AE_BAD_PARAMETER; 721 722 switch (address) { 723 case LG_ADDRESS_SPACE_DEBUG_FLAG_ADR: 724 /* Debug messages are already printed using the standard ACPI Debug object */ 725 *value = 0x00; 726 return AE_OK; 727 case LG_ADDRESS_SPACE_DTTM_FLAG_ADR: 728 *value = fw_debug; 729 return AE_OK; 730 default: 731 dev_notice_ratelimited(dev, "Attempt to read unknown opregion address %llu\n", 732 address); 733 return AE_BAD_PARAMETER; 734 } 735} 736 737static acpi_status lg_laptop_address_space_handler(u32 function, acpi_physical_address address, 738 u32 bits, u64 *value, void *handler_context, 739 void *region_context) 740{ 741 struct device *dev = handler_context; 742 size_t size; 743 744 if (bits % BITS_PER_BYTE) 745 return AE_BAD_PARAMETER; 746 747 size = bits / BITS_PER_BYTE; 748 749 switch (function) { 750 case ACPI_READ: 751 return lg_laptop_address_space_read(dev, address, size, value); 752 case ACPI_WRITE: 753 return lg_laptop_address_space_write(dev, address, size, *value); 754 default: 755 return AE_BAD_PARAMETER; 756 } 757} 758 759static void lg_laptop_remove_address_space_handler(void *data) 760{ 761 struct acpi_device *device = data; 762 763 acpi_remove_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID, 764 &lg_laptop_address_space_handler); 765} 766 767static int acpi_add(struct acpi_device *device) 768{ 769 struct platform_device_info pdev_info = { 770 .fwnode = acpi_fwnode_handle(device), 771 .name = PLATFORM_NAME, 772 .id = PLATFORM_DEVID_NONE, 773 }; 774 acpi_status status; 775 int ret; 776 const char *product; 777 int year = 2017; 778 779 if (pf_device) 780 return 0; 781 782 status = acpi_install_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID, 783 &lg_laptop_address_space_handler, 784 NULL, &device->dev); 785 if (ACPI_FAILURE(status)) 786 return -ENODEV; 787 788 ret = devm_add_action_or_reset(&device->dev, lg_laptop_remove_address_space_handler, 789 device); 790 if (ret < 0) 791 return ret; 792 793 ret = platform_driver_register(&pf_driver); 794 if (ret) 795 return ret; 796 797 pf_device = platform_device_register_full(&pdev_info); 798 if (IS_ERR(pf_device)) { 799 ret = PTR_ERR(pf_device); 800 pf_device = NULL; 801 pr_err("unable to register platform device\n"); 802 goto out_platform_registered; 803 } 804 product = dmi_get_system_info(DMI_PRODUCT_NAME); 805 if (product && strlen(product) > 4) 806 switch (product[4]) { 807 case '5': 808 if (strlen(product) > 5) 809 switch (product[5]) { 810 case 'N': 811 year = 2021; 812 break; 813 case '0': 814 year = 2016; 815 break; 816 default: 817 year = 2022; 818 } 819 break; 820 case '6': 821 year = 2016; 822 break; 823 case '7': 824 year = 2017; 825 break; 826 case '8': 827 year = 2018; 828 break; 829 case '9': 830 year = 2019; 831 break; 832 case '0': 833 if (strlen(product) > 5) 834 switch (product[5]) { 835 case 'N': 836 year = 2020; 837 break; 838 case 'P': 839 year = 2021; 840 break; 841 case 'Q': 842 year = 2022; 843 break; 844 case 'R': 845 year = 2023; 846 break; 847 case 'S': 848 year = 2024; 849 break; 850 default: 851 year = 2025; 852 } 853 break; 854 default: 855 year = 2019; 856 } 857 pr_info("product: %s year: %d\n", product ?: "unknown", year); 858 859 if (year >= 2019) 860 battery_limit_use_wmbb = 1; 861 862 ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group); 863 if (ret) 864 goto out_platform_device; 865 866 /* LEDs are optional */ 867 led_classdev_register(&pf_device->dev, &kbd_backlight); 868 led_classdev_register(&pf_device->dev, &tpad_led); 869 870 wmi_input_setup(); 871 battery_hook_register(&battery_hook); 872 873 return 0; 874 875out_platform_device: 876 platform_device_unregister(pf_device); 877out_platform_registered: 878 platform_driver_unregister(&pf_driver); 879 return ret; 880} 881 882static void acpi_remove(struct acpi_device *device) 883{ 884 sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group); 885 886 led_classdev_unregister(&tpad_led); 887 led_classdev_unregister(&kbd_backlight); 888 889 battery_hook_unregister(&battery_hook); 890 wmi_input_destroy(); 891 platform_device_unregister(pf_device); 892 pf_device = NULL; 893 platform_driver_unregister(&pf_driver); 894} 895 896static const struct acpi_device_id device_ids[] = { 897 {"LGEX0820", 0}, 898 {"", 0} 899}; 900MODULE_DEVICE_TABLE(acpi, device_ids); 901 902static struct acpi_driver acpi_driver = { 903 .name = "LG Gram Laptop Support", 904 .class = "lg-laptop", 905 .ids = device_ids, 906 .ops = { 907 .add = acpi_add, 908 .remove = acpi_remove, 909 .notify = acpi_notify, 910 }, 911}; 912 913static int __init acpi_init(void) 914{ 915 int result; 916 917 result = acpi_bus_register_driver(&acpi_driver); 918 if (result < 0) { 919 pr_debug("Error registering driver\n"); 920 return -ENODEV; 921 } 922 923 return 0; 924} 925 926static void __exit acpi_exit(void) 927{ 928 acpi_bus_unregister_driver(&acpi_driver); 929} 930 931module_init(acpi_init); 932module_exit(acpi_exit);
~/
Read-only file preview.