1 // SPDX-License-Identifier: GPL-2.0+
3 * lg-laptop.c - LG Gram ACPI features and hotkeys Driver
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 #include <linux/acpi.h>
11 #include <linux/dmi.h>
12 #include <linux/input.h>
13 #include <linux/input/sparse-keymap.h>
14 #include <linux/kernel.h>
15 #include <linux/leds.h>
16 #include <linux/module.h>
17 #include <linux/platform_device.h>
18 #include <linux/types.h>
20 #include <acpi/battery.h>
22 #define LED_DEVICE(_name, max, flag) struct led_classdev _name = { \
23 .name = __stringify(_name), \
24 .max_brightness = max, \
25 .brightness_set = _name##_set, \
26 .brightness_get = _name##_get, \
30 MODULE_AUTHOR("Matan Ziv-Av");
31 MODULE_DESCRIPTION("LG WMI Hotkey Driver");
32 MODULE_LICENSE("GPL");
34 #define WMI_EVENT_GUID0 "E4FB94F9-7F2B-4173-AD1A-CD1D95086248"
35 #define WMI_EVENT_GUID1 "023B133E-49D1-4E10-B313-698220140DC2"
36 #define WMI_EVENT_GUID2 "37BE1AC0-C3F2-4B1F-BFBE-8FDEAF2814D6"
37 #define WMI_EVENT_GUID3 "911BAD44-7DF8-4FBB-9319-BABA1C4B293B"
38 #define WMI_METHOD_WMAB "C3A72B38-D3EF-42D3-8CBB-D5A57049F66D"
39 #define WMI_METHOD_WMBB "2B4F501A-BD3C-4394-8DCF-00A7D2BC8210"
40 #define WMI_EVENT_GUID WMI_EVENT_GUID0
42 #define SB_GGOV_METHOD "\\_SB.GGOV"
43 #define GOV_TLED 0x2020008
46 #define WM_KEY_LIGHT 0x400
48 #define WM_FN_LOCK 0x407
49 #define WM_BATT_LIMIT 0x61
50 #define WM_READER_MODE 0xBF
51 #define WM_FAN_MODE 0x33
52 #define WMBB_USB_CHARGE 0x10B
53 #define WMBB_BATT_LIMIT 0x10C
55 #define PLATFORM_NAME "lg-laptop"
57 MODULE_ALIAS("wmi:" WMI_EVENT_GUID0);
58 MODULE_ALIAS("wmi:" WMI_EVENT_GUID1);
59 MODULE_ALIAS("wmi:" WMI_EVENT_GUID2);
60 MODULE_ALIAS("wmi:" WMI_EVENT_GUID3);
61 MODULE_ALIAS("wmi:" WMI_METHOD_WMAB);
62 MODULE_ALIAS("wmi:" WMI_METHOD_WMBB);
64 static struct platform_device *pf_device;
65 static struct input_dev *wmi_input_dev;
68 #define INIT_INPUT_WMI_0 0x01
69 #define INIT_INPUT_WMI_2 0x02
70 #define INIT_INPUT_ACPI 0x04
71 #define INIT_SPARSE_KEYMAP 0x80
73 static int battery_limit_use_wmbb;
74 static struct led_classdev kbd_backlight;
75 static enum led_brightness get_kbd_backlight_level(struct device *dev);
77 static const struct key_entry wmi_keymap[] = {
78 {KE_KEY, 0x70, {KEY_F15} }, /* LG control panel (F1) */
79 {KE_KEY, 0x74, {KEY_F21} }, /* Touchpad toggle (F5) */
80 {KE_KEY, 0xf020000, {KEY_F14} }, /* Read mode (F9) */
81 {KE_KEY, 0x10000000, {KEY_F16} },/* Keyboard backlight (F8) - pressing
82 * this key both sends an event and
83 * changes backlight level.
88 static int ggov(u32 arg0)
90 union acpi_object args[1];
94 struct acpi_object_list arg;
95 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
98 args[0].type = ACPI_TYPE_INTEGER;
99 args[0].integer.value = arg0;
101 status = acpi_get_handle(NULL, (acpi_string) SB_GGOV_METHOD, &handle);
102 if (ACPI_FAILURE(status)) {
103 pr_err("Cannot get handle");
110 status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
111 if (ACPI_FAILURE(status)) {
112 acpi_handle_err(handle, "GGOV: call failed.\n");
117 if (r->type != ACPI_TYPE_INTEGER) {
122 res = r->integer.value;
128 static union acpi_object *lg_wmab(struct device *dev, u32 method, u32 arg1, u32 arg2)
130 union acpi_object args[3];
132 struct acpi_object_list arg;
133 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
135 args[0].type = ACPI_TYPE_INTEGER;
136 args[0].integer.value = method;
137 args[1].type = ACPI_TYPE_INTEGER;
138 args[1].integer.value = arg1;
139 args[2].type = ACPI_TYPE_INTEGER;
140 args[2].integer.value = arg2;
145 status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMAB", &arg, &buffer);
146 if (ACPI_FAILURE(status)) {
147 dev_err(dev, "WMAB: call failed.\n");
151 return buffer.pointer;
154 static union acpi_object *lg_wmbb(struct device *dev, u32 method_id, u32 arg1, u32 arg2)
156 union acpi_object args[3];
158 struct acpi_object_list arg;
159 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
162 *(u32 *)buf = method_id;
163 *(u32 *)(buf + 4) = arg1;
164 *(u32 *)(buf + 16) = arg2;
165 args[0].type = ACPI_TYPE_INTEGER;
166 args[0].integer.value = 0; /* ignored */
167 args[1].type = ACPI_TYPE_INTEGER;
168 args[1].integer.value = 1; /* Must be 1 or 2. Does not matter which */
169 args[2].type = ACPI_TYPE_BUFFER;
170 args[2].buffer.length = 32;
171 args[2].buffer.pointer = buf;
176 status = acpi_evaluate_object(ACPI_HANDLE(dev), "WMBB", &arg, &buffer);
177 if (ACPI_FAILURE(status)) {
178 dev_err(dev, "WMBB: call failed.\n");
182 return (union acpi_object *)buffer.pointer;
185 static void wmi_notify(u32 value, void *context)
187 struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
188 union acpi_object *obj;
190 long data = (long)context;
192 pr_debug("event guid %li\n", data);
193 status = wmi_get_event_data(value, &response);
194 if (ACPI_FAILURE(status)) {
195 pr_err("Bad event status 0x%x\n", status);
199 obj = (union acpi_object *)response.pointer;
203 if (obj->type == ACPI_TYPE_INTEGER) {
204 int eventcode = obj->integer.value;
205 struct key_entry *key;
207 if (eventcode == 0x10000000) {
208 led_classdev_notify_brightness_hw_changed(
209 &kbd_backlight, get_kbd_backlight_level(kbd_backlight.dev->parent));
211 key = sparse_keymap_entry_from_scancode(
212 wmi_input_dev, eventcode);
213 if (key && key->type == KE_KEY)
214 sparse_keymap_report_entry(wmi_input_dev,
219 pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type,
221 kfree(response.pointer);
224 static void wmi_input_setup(void)
228 wmi_input_dev = input_allocate_device();
230 wmi_input_dev->name = "LG WMI hotkeys";
231 wmi_input_dev->phys = "wmi/input0";
232 wmi_input_dev->id.bustype = BUS_HOST;
234 if (sparse_keymap_setup(wmi_input_dev, wmi_keymap, NULL) ||
235 input_register_device(wmi_input_dev)) {
236 pr_info("Cannot initialize input device");
237 input_free_device(wmi_input_dev);
241 inited |= INIT_SPARSE_KEYMAP;
242 status = wmi_install_notify_handler(WMI_EVENT_GUID0, wmi_notify,
244 if (ACPI_SUCCESS(status))
245 inited |= INIT_INPUT_WMI_0;
247 status = wmi_install_notify_handler(WMI_EVENT_GUID2, wmi_notify,
249 if (ACPI_SUCCESS(status))
250 inited |= INIT_INPUT_WMI_2;
252 pr_info("Cannot allocate input device");
256 static void acpi_notify(struct acpi_device *device, u32 event)
258 acpi_handle_debug(device->handle, "notify: %d\n", event);
261 static ssize_t fan_mode_store(struct device *dev,
262 struct device_attribute *attr,
263 const char *buffer, size_t count)
266 union acpi_object *r;
270 ret = kstrtobool(buffer, &value);
274 r = lg_wmab(dev, WM_FAN_MODE, WM_GET, 0);
278 if (r->type != ACPI_TYPE_INTEGER) {
283 m = r->integer.value;
285 r = lg_wmab(dev, WM_FAN_MODE, WM_SET, (m & 0xffffff0f) | (value << 4));
287 r = lg_wmab(dev, WM_FAN_MODE, WM_SET, (m & 0xfffffff0) | value);
293 static ssize_t fan_mode_show(struct device *dev,
294 struct device_attribute *attr, char *buffer)
297 union acpi_object *r;
299 r = lg_wmab(dev, WM_FAN_MODE, WM_GET, 0);
303 if (r->type != ACPI_TYPE_INTEGER) {
308 status = r->integer.value & 0x01;
311 return sysfs_emit(buffer, "%d\n", status);
314 static ssize_t usb_charge_store(struct device *dev,
315 struct device_attribute *attr,
316 const char *buffer, size_t count)
319 union acpi_object *r;
322 ret = kstrtobool(buffer, &value);
326 r = lg_wmbb(dev, WMBB_USB_CHARGE, WM_SET, value);
334 static ssize_t usb_charge_show(struct device *dev,
335 struct device_attribute *attr, char *buffer)
338 union acpi_object *r;
340 r = lg_wmbb(dev, WMBB_USB_CHARGE, WM_GET, 0);
344 if (r->type != ACPI_TYPE_BUFFER) {
349 status = !!r->buffer.pointer[0x10];
353 return sysfs_emit(buffer, "%d\n", status);
356 static ssize_t reader_mode_store(struct device *dev,
357 struct device_attribute *attr,
358 const char *buffer, size_t count)
361 union acpi_object *r;
364 ret = kstrtobool(buffer, &value);
368 r = lg_wmab(dev, WM_READER_MODE, WM_SET, value);
376 static ssize_t reader_mode_show(struct device *dev,
377 struct device_attribute *attr, char *buffer)
380 union acpi_object *r;
382 r = lg_wmab(dev, WM_READER_MODE, WM_GET, 0);
386 if (r->type != ACPI_TYPE_INTEGER) {
391 status = !!r->integer.value;
395 return sysfs_emit(buffer, "%d\n", status);
398 static ssize_t fn_lock_store(struct device *dev,
399 struct device_attribute *attr,
400 const char *buffer, size_t count)
403 union acpi_object *r;
406 ret = kstrtobool(buffer, &value);
410 r = lg_wmab(dev, WM_FN_LOCK, WM_SET, value);
418 static ssize_t fn_lock_show(struct device *dev,
419 struct device_attribute *attr, char *buffer)
422 union acpi_object *r;
424 r = lg_wmab(dev, WM_FN_LOCK, WM_GET, 0);
428 if (r->type != ACPI_TYPE_BUFFER) {
433 status = !!r->buffer.pointer[0];
436 return sysfs_emit(buffer, "%d\n", status);
439 static ssize_t charge_control_end_threshold_store(struct device *dev,
440 struct device_attribute *attr,
441 const char *buf, size_t count)
446 ret = kstrtoul(buf, 10, &value);
450 if (value == 100 || value == 80) {
451 union acpi_object *r;
453 if (battery_limit_use_wmbb)
454 r = lg_wmbb(&pf_device->dev, WMBB_BATT_LIMIT, WM_SET, value);
456 r = lg_wmab(&pf_device->dev, WM_BATT_LIMIT, WM_SET, value);
467 static ssize_t charge_control_end_threshold_show(struct device *device,
468 struct device_attribute *attr,
472 union acpi_object *r;
474 if (battery_limit_use_wmbb) {
475 r = lg_wmbb(&pf_device->dev, WMBB_BATT_LIMIT, WM_GET, 0);
479 if (r->type != ACPI_TYPE_BUFFER) {
484 status = r->buffer.pointer[0x10];
486 r = lg_wmab(&pf_device->dev, WM_BATT_LIMIT, WM_GET, 0);
490 if (r->type != ACPI_TYPE_INTEGER) {
495 status = r->integer.value;
498 if (status != 80 && status != 100)
501 return sysfs_emit(buf, "%d\n", status);
504 static ssize_t battery_care_limit_show(struct device *dev,
505 struct device_attribute *attr,
508 return charge_control_end_threshold_show(dev, attr, buffer);
511 static ssize_t battery_care_limit_store(struct device *dev,
512 struct device_attribute *attr,
513 const char *buffer, size_t count)
515 return charge_control_end_threshold_store(dev, attr, buffer, count);
518 static DEVICE_ATTR_RW(fan_mode);
519 static DEVICE_ATTR_RW(usb_charge);
520 static DEVICE_ATTR_RW(reader_mode);
521 static DEVICE_ATTR_RW(fn_lock);
522 static DEVICE_ATTR_RW(charge_control_end_threshold);
523 static DEVICE_ATTR_RW(battery_care_limit);
525 static int lg_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
527 if (device_create_file(&battery->dev,
528 &dev_attr_charge_control_end_threshold))
534 static int lg_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
536 device_remove_file(&battery->dev,
537 &dev_attr_charge_control_end_threshold);
541 static struct acpi_battery_hook battery_hook = {
542 .add_battery = lg_battery_add,
543 .remove_battery = lg_battery_remove,
544 .name = "LG Battery Extension",
547 static struct attribute *dev_attributes[] = {
548 &dev_attr_fan_mode.attr,
549 &dev_attr_usb_charge.attr,
550 &dev_attr_reader_mode.attr,
551 &dev_attr_fn_lock.attr,
552 &dev_attr_battery_care_limit.attr,
556 static const struct attribute_group dev_attribute_group = {
557 .attrs = dev_attributes,
560 static void tpad_led_set(struct led_classdev *cdev,
561 enum led_brightness brightness)
563 union acpi_object *r;
565 r = lg_wmab(cdev->dev->parent, WM_TLED, WM_SET, brightness > LED_OFF);
569 static enum led_brightness tpad_led_get(struct led_classdev *cdev)
571 return ggov(GOV_TLED) > 0 ? LED_ON : LED_OFF;
574 static LED_DEVICE(tpad_led, 1, 0);
576 static void kbd_backlight_set(struct led_classdev *cdev,
577 enum led_brightness brightness)
580 union acpi_object *r;
583 if (brightness <= LED_OFF)
585 if (brightness >= LED_FULL)
587 r = lg_wmab(cdev->dev->parent, WM_KEY_LIGHT, WM_SET, val);
591 static enum led_brightness get_kbd_backlight_level(struct device *dev)
593 union acpi_object *r;
596 r = lg_wmab(dev, WM_KEY_LIGHT, WM_GET, 0);
601 if (r->type != ACPI_TYPE_BUFFER || r->buffer.pointer[1] != 0x05) {
606 switch (r->buffer.pointer[0] & 0x27) {
622 static enum led_brightness kbd_backlight_get(struct led_classdev *cdev)
624 return get_kbd_backlight_level(cdev->dev->parent);
627 static LED_DEVICE(kbd_backlight, 255, LED_BRIGHT_HW_CHANGED);
629 static void wmi_input_destroy(void)
631 if (inited & INIT_INPUT_WMI_2)
632 wmi_remove_notify_handler(WMI_EVENT_GUID2);
634 if (inited & INIT_INPUT_WMI_0)
635 wmi_remove_notify_handler(WMI_EVENT_GUID0);
637 if (inited & INIT_SPARSE_KEYMAP)
638 input_unregister_device(wmi_input_dev);
640 inited &= ~(INIT_INPUT_WMI_0 | INIT_INPUT_WMI_2 | INIT_SPARSE_KEYMAP);
643 static struct platform_driver pf_driver = {
645 .name = PLATFORM_NAME,
649 static int acpi_add(struct acpi_device *device)
651 struct platform_device_info pdev_info = {
652 .fwnode = acpi_fwnode_handle(device),
653 .name = PLATFORM_NAME,
654 .id = PLATFORM_DEVID_NONE,
663 ret = platform_driver_register(&pf_driver);
667 pf_device = platform_device_register_full(&pdev_info);
668 if (IS_ERR(pf_device)) {
669 ret = PTR_ERR(pf_device);
671 pr_err("unable to register platform device\n");
672 goto out_platform_registered;
674 product = dmi_get_system_info(DMI_PRODUCT_NAME);
675 if (product && strlen(product) > 4)
676 switch (product[4]) {
678 if (strlen(product) > 5)
679 switch (product[5]) {
703 if (strlen(product) > 5)
704 switch (product[5]) {
718 pr_info("product: %s year: %d\n", product ?: "unknown", year);
721 battery_limit_use_wmbb = 1;
723 ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group);
725 goto out_platform_device;
727 /* LEDs are optional */
728 led_classdev_register(&pf_device->dev, &kbd_backlight);
729 led_classdev_register(&pf_device->dev, &tpad_led);
732 battery_hook_register(&battery_hook);
737 platform_device_unregister(pf_device);
738 out_platform_registered:
739 platform_driver_unregister(&pf_driver);
743 static void acpi_remove(struct acpi_device *device)
745 sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
747 led_classdev_unregister(&tpad_led);
748 led_classdev_unregister(&kbd_backlight);
750 battery_hook_unregister(&battery_hook);
752 platform_device_unregister(pf_device);
754 platform_driver_unregister(&pf_driver);
757 static const struct acpi_device_id device_ids[] = {
761 MODULE_DEVICE_TABLE(acpi, device_ids);
763 static struct acpi_driver acpi_driver = {
764 .name = "LG Gram Laptop Support",
765 .class = "lg-laptop",
769 .remove = acpi_remove,
770 .notify = acpi_notify,
774 static int __init acpi_init(void)
778 result = acpi_bus_register_driver(&acpi_driver);
780 pr_debug("Error registering driver\n");
787 static void __exit acpi_exit(void)
789 acpi_bus_unregister_driver(&acpi_driver);
792 module_init(acpi_init);
793 module_exit(acpi_exit);