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