xref: /openbmc/linux/drivers/platform/x86/lg-laptop.c (revision 195c5ad9)
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/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>
19 
20 #include <acpi/battery.h>
21 
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,          \
27 	.flags = flag,                          \
28 }
29 
30 MODULE_AUTHOR("Matan Ziv-Av");
31 MODULE_DESCRIPTION("LG WMI Hotkey Driver");
32 MODULE_LICENSE("GPL");
33 
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
41 
42 #define WMAB_METHOD     "\\XINI.WMAB"
43 #define WMBB_METHOD     "\\XINI.WMBB"
44 #define SB_GGOV_METHOD  "\\_SB.GGOV"
45 #define GOV_TLED        0x2020008
46 #define WM_GET          1
47 #define WM_SET          2
48 #define WM_KEY_LIGHT    0x400
49 #define WM_TLED         0x404
50 #define WM_FN_LOCK      0x407
51 #define WM_BATT_LIMIT   0x61
52 #define WM_READER_MODE  0xBF
53 #define WM_FAN_MODE	0x33
54 #define WMBB_USB_CHARGE 0x10B
55 #define WMBB_BATT_LIMIT 0x10C
56 
57 #define PLATFORM_NAME   "lg-laptop"
58 
59 MODULE_ALIAS("wmi:" WMI_EVENT_GUID0);
60 MODULE_ALIAS("wmi:" WMI_EVENT_GUID1);
61 MODULE_ALIAS("wmi:" WMI_EVENT_GUID2);
62 MODULE_ALIAS("wmi:" WMI_EVENT_GUID3);
63 MODULE_ALIAS("wmi:" WMI_METHOD_WMAB);
64 MODULE_ALIAS("wmi:" WMI_METHOD_WMBB);
65 
66 static struct platform_device *pf_device;
67 static struct input_dev *wmi_input_dev;
68 
69 static u32 inited;
70 #define INIT_INPUT_WMI_0        0x01
71 #define INIT_INPUT_WMI_2        0x02
72 #define INIT_INPUT_ACPI         0x04
73 #define INIT_SPARSE_KEYMAP      0x80
74 
75 static int battery_limit_use_wmbb;
76 static struct led_classdev kbd_backlight;
77 static enum led_brightness get_kbd_backlight_level(void);
78 
79 static const struct key_entry wmi_keymap[] = {
80 	{KE_KEY, 0x70, {KEY_F15} },	 /* LG control panel (F1) */
81 	{KE_KEY, 0x74, {KEY_F21} },	 /* Touchpad toggle (F5) */
82 	{KE_KEY, 0xf020000, {KEY_F14} }, /* Read mode (F9) */
83 	{KE_KEY, 0x10000000, {KEY_F16} },/* Keyboard backlight (F8) - pressing
84 					  * this key both sends an event and
85 					  * changes backlight level.
86 					  */
87 	{KE_KEY, 0x80, {KEY_RFKILL} },
88 	{KE_END, 0}
89 };
90 
91 static int ggov(u32 arg0)
92 {
93 	union acpi_object args[1];
94 	union acpi_object *r;
95 	acpi_status status;
96 	acpi_handle handle;
97 	struct acpi_object_list arg;
98 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
99 	int res;
100 
101 	args[0].type = ACPI_TYPE_INTEGER;
102 	args[0].integer.value = arg0;
103 
104 	status = acpi_get_handle(NULL, (acpi_string) SB_GGOV_METHOD, &handle);
105 	if (ACPI_FAILURE(status)) {
106 		pr_err("Cannot get handle");
107 		return -ENODEV;
108 	}
109 
110 	arg.count = 1;
111 	arg.pointer = args;
112 
113 	status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
114 	if (ACPI_FAILURE(status)) {
115 		acpi_handle_err(handle, "GGOV: call failed.\n");
116 		return -EINVAL;
117 	}
118 
119 	r = buffer.pointer;
120 	if (r->type != ACPI_TYPE_INTEGER) {
121 		kfree(r);
122 		return -EINVAL;
123 	}
124 
125 	res = r->integer.value;
126 	kfree(r);
127 
128 	return res;
129 }
130 
131 static union acpi_object *lg_wmab(u32 method, u32 arg1, u32 arg2)
132 {
133 	union acpi_object args[3];
134 	acpi_status status;
135 	acpi_handle handle;
136 	struct acpi_object_list arg;
137 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
138 
139 	args[0].type = ACPI_TYPE_INTEGER;
140 	args[0].integer.value = method;
141 	args[1].type = ACPI_TYPE_INTEGER;
142 	args[1].integer.value = arg1;
143 	args[2].type = ACPI_TYPE_INTEGER;
144 	args[2].integer.value = arg2;
145 
146 	status = acpi_get_handle(NULL, (acpi_string) WMAB_METHOD, &handle);
147 	if (ACPI_FAILURE(status)) {
148 		pr_err("Cannot get handle");
149 		return NULL;
150 	}
151 
152 	arg.count = 3;
153 	arg.pointer = args;
154 
155 	status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
156 	if (ACPI_FAILURE(status)) {
157 		acpi_handle_err(handle, "WMAB: call failed.\n");
158 		return NULL;
159 	}
160 
161 	return buffer.pointer;
162 }
163 
164 static union acpi_object *lg_wmbb(u32 method_id, u32 arg1, u32 arg2)
165 {
166 	union acpi_object args[3];
167 	acpi_status status;
168 	acpi_handle handle;
169 	struct acpi_object_list arg;
170 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
171 	u8 buf[32];
172 
173 	*(u32 *)buf = method_id;
174 	*(u32 *)(buf + 4) = arg1;
175 	*(u32 *)(buf + 16) = arg2;
176 	args[0].type = ACPI_TYPE_INTEGER;
177 	args[0].integer.value = 0; /* ignored */
178 	args[1].type = ACPI_TYPE_INTEGER;
179 	args[1].integer.value = 1; /* Must be 1 or 2. Does not matter which */
180 	args[2].type = ACPI_TYPE_BUFFER;
181 	args[2].buffer.length = 32;
182 	args[2].buffer.pointer = buf;
183 
184 	status = acpi_get_handle(NULL, (acpi_string)WMBB_METHOD, &handle);
185 	if (ACPI_FAILURE(status)) {
186 		pr_err("Cannot get handle");
187 		return NULL;
188 	}
189 
190 	arg.count = 3;
191 	arg.pointer = args;
192 
193 	status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
194 	if (ACPI_FAILURE(status)) {
195 		acpi_handle_err(handle, "WMAB: call failed.\n");
196 		return NULL;
197 	}
198 
199 	return (union acpi_object *)buffer.pointer;
200 }
201 
202 static void wmi_notify(u32 value, void *context)
203 {
204 	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
205 	union acpi_object *obj;
206 	acpi_status status;
207 	long data = (long)context;
208 
209 	pr_debug("event guid %li\n", data);
210 	status = wmi_get_event_data(value, &response);
211 	if (ACPI_FAILURE(status)) {
212 		pr_err("Bad event status 0x%x\n", status);
213 		return;
214 	}
215 
216 	obj = (union acpi_object *)response.pointer;
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());
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 	kfree(response.pointer);
239 }
240 
241 static void wmi_input_setup(void)
242 {
243 	acpi_status status;
244 
245 	wmi_input_dev = input_allocate_device();
246 	if (wmi_input_dev) {
247 		wmi_input_dev->name = "LG WMI hotkeys";
248 		wmi_input_dev->phys = "wmi/input0";
249 		wmi_input_dev->id.bustype = BUS_HOST;
250 
251 		if (sparse_keymap_setup(wmi_input_dev, wmi_keymap, NULL) ||
252 		    input_register_device(wmi_input_dev)) {
253 			pr_info("Cannot initialize input device");
254 			input_free_device(wmi_input_dev);
255 			return;
256 		}
257 
258 		inited |= INIT_SPARSE_KEYMAP;
259 		status = wmi_install_notify_handler(WMI_EVENT_GUID0, wmi_notify,
260 						    (void *)0);
261 		if (ACPI_SUCCESS(status))
262 			inited |= INIT_INPUT_WMI_0;
263 
264 		status = wmi_install_notify_handler(WMI_EVENT_GUID2, wmi_notify,
265 						    (void *)2);
266 		if (ACPI_SUCCESS(status))
267 			inited |= INIT_INPUT_WMI_2;
268 	} else {
269 		pr_info("Cannot allocate input device");
270 	}
271 }
272 
273 static void acpi_notify(struct acpi_device *device, u32 event)
274 {
275 	struct key_entry *key;
276 
277 	acpi_handle_debug(device->handle, "notify: %d\n", event);
278 	if (inited & INIT_SPARSE_KEYMAP) {
279 		key = sparse_keymap_entry_from_scancode(wmi_input_dev, 0x80);
280 		if (key && key->type == KE_KEY)
281 			sparse_keymap_report_entry(wmi_input_dev, key, 1, true);
282 	}
283 }
284 
285 static ssize_t fan_mode_store(struct device *dev,
286 			      struct device_attribute *attr,
287 			      const char *buffer, size_t count)
288 {
289 	bool value;
290 	union acpi_object *r;
291 	u32 m;
292 	int ret;
293 
294 	ret = kstrtobool(buffer, &value);
295 	if (ret)
296 		return ret;
297 
298 	r = lg_wmab(WM_FAN_MODE, WM_GET, 0);
299 	if (!r)
300 		return -EIO;
301 
302 	if (r->type != ACPI_TYPE_INTEGER) {
303 		kfree(r);
304 		return -EIO;
305 	}
306 
307 	m = r->integer.value;
308 	kfree(r);
309 	r = lg_wmab(WM_FAN_MODE, WM_SET, (m & 0xffffff0f) | (value << 4));
310 	kfree(r);
311 	r = lg_wmab(WM_FAN_MODE, WM_SET, (m & 0xfffffff0) | value);
312 	kfree(r);
313 
314 	return count;
315 }
316 
317 static ssize_t fan_mode_show(struct device *dev,
318 			     struct device_attribute *attr, char *buffer)
319 {
320 	unsigned int status;
321 	union acpi_object *r;
322 
323 	r = lg_wmab(WM_FAN_MODE, WM_GET, 0);
324 	if (!r)
325 		return -EIO;
326 
327 	if (r->type != ACPI_TYPE_INTEGER) {
328 		kfree(r);
329 		return -EIO;
330 	}
331 
332 	status = r->integer.value & 0x01;
333 	kfree(r);
334 
335 	return sysfs_emit(buffer, "%d\n", status);
336 }
337 
338 static ssize_t usb_charge_store(struct device *dev,
339 				struct device_attribute *attr,
340 				const char *buffer, size_t count)
341 {
342 	bool value;
343 	union acpi_object *r;
344 	int ret;
345 
346 	ret = kstrtobool(buffer, &value);
347 	if (ret)
348 		return ret;
349 
350 	r = lg_wmbb(WMBB_USB_CHARGE, WM_SET, value);
351 	if (!r)
352 		return -EIO;
353 
354 	kfree(r);
355 	return count;
356 }
357 
358 static ssize_t usb_charge_show(struct device *dev,
359 			       struct device_attribute *attr, char *buffer)
360 {
361 	unsigned int status;
362 	union acpi_object *r;
363 
364 	r = lg_wmbb(WMBB_USB_CHARGE, WM_GET, 0);
365 	if (!r)
366 		return -EIO;
367 
368 	if (r->type != ACPI_TYPE_BUFFER) {
369 		kfree(r);
370 		return -EIO;
371 	}
372 
373 	status = !!r->buffer.pointer[0x10];
374 
375 	kfree(r);
376 
377 	return sysfs_emit(buffer, "%d\n", status);
378 }
379 
380 static ssize_t reader_mode_store(struct device *dev,
381 				 struct device_attribute *attr,
382 				 const char *buffer, size_t count)
383 {
384 	bool value;
385 	union acpi_object *r;
386 	int ret;
387 
388 	ret = kstrtobool(buffer, &value);
389 	if (ret)
390 		return ret;
391 
392 	r = lg_wmab(WM_READER_MODE, WM_SET, value);
393 	if (!r)
394 		return -EIO;
395 
396 	kfree(r);
397 	return count;
398 }
399 
400 static ssize_t reader_mode_show(struct device *dev,
401 				struct device_attribute *attr, char *buffer)
402 {
403 	unsigned int status;
404 	union acpi_object *r;
405 
406 	r = lg_wmab(WM_READER_MODE, WM_GET, 0);
407 	if (!r)
408 		return -EIO;
409 
410 	if (r->type != ACPI_TYPE_INTEGER) {
411 		kfree(r);
412 		return -EIO;
413 	}
414 
415 	status = !!r->integer.value;
416 
417 	kfree(r);
418 
419 	return sysfs_emit(buffer, "%d\n", status);
420 }
421 
422 static ssize_t fn_lock_store(struct device *dev,
423 			     struct device_attribute *attr,
424 			     const char *buffer, size_t count)
425 {
426 	bool value;
427 	union acpi_object *r;
428 	int ret;
429 
430 	ret = kstrtobool(buffer, &value);
431 	if (ret)
432 		return ret;
433 
434 	r = lg_wmab(WM_FN_LOCK, WM_SET, value);
435 	if (!r)
436 		return -EIO;
437 
438 	kfree(r);
439 	return count;
440 }
441 
442 static ssize_t fn_lock_show(struct device *dev,
443 			    struct device_attribute *attr, char *buffer)
444 {
445 	unsigned int status;
446 	union acpi_object *r;
447 
448 	r = lg_wmab(WM_FN_LOCK, WM_GET, 0);
449 	if (!r)
450 		return -EIO;
451 
452 	if (r->type != ACPI_TYPE_BUFFER) {
453 		kfree(r);
454 		return -EIO;
455 	}
456 
457 	status = !!r->buffer.pointer[0];
458 	kfree(r);
459 
460 	return sysfs_emit(buffer, "%d\n", status);
461 }
462 
463 static ssize_t charge_control_end_threshold_store(struct device *dev,
464 						  struct device_attribute *attr,
465 						  const char *buf, size_t count)
466 {
467 	unsigned long value;
468 	int ret;
469 
470 	ret = kstrtoul(buf, 10, &value);
471 	if (ret)
472 		return ret;
473 
474 	if (value == 100 || value == 80) {
475 		union acpi_object *r;
476 
477 		if (battery_limit_use_wmbb)
478 			r = lg_wmbb(WMBB_BATT_LIMIT, WM_SET, value);
479 		else
480 			r = lg_wmab(WM_BATT_LIMIT, WM_SET, value);
481 		if (!r)
482 			return -EIO;
483 
484 		kfree(r);
485 		return count;
486 	}
487 
488 	return -EINVAL;
489 }
490 
491 static ssize_t charge_control_end_threshold_show(struct device *device,
492 						 struct device_attribute *attr,
493 						 char *buf)
494 {
495 	unsigned int status;
496 	union acpi_object *r;
497 
498 	if (battery_limit_use_wmbb) {
499 		r = lg_wmbb(WMBB_BATT_LIMIT, WM_GET, 0);
500 		if (!r)
501 			return -EIO;
502 
503 		if (r->type != ACPI_TYPE_BUFFER) {
504 			kfree(r);
505 			return -EIO;
506 		}
507 
508 		status = r->buffer.pointer[0x10];
509 	} else {
510 		r = lg_wmab(WM_BATT_LIMIT, WM_GET, 0);
511 		if (!r)
512 			return -EIO;
513 
514 		if (r->type != ACPI_TYPE_INTEGER) {
515 			kfree(r);
516 			return -EIO;
517 		}
518 
519 		status = r->integer.value;
520 	}
521 	kfree(r);
522 	if (status != 80 && status != 100)
523 		status = 0;
524 
525 	return sysfs_emit(buf, "%d\n", status);
526 }
527 
528 static ssize_t battery_care_limit_show(struct device *dev,
529 				       struct device_attribute *attr,
530 				       char *buffer)
531 {
532 	return charge_control_end_threshold_show(dev, attr, buffer);
533 }
534 
535 static ssize_t battery_care_limit_store(struct device *dev,
536 					struct device_attribute *attr,
537 					const char *buffer, size_t count)
538 {
539 	return charge_control_end_threshold_store(dev, attr, buffer, count);
540 }
541 
542 static DEVICE_ATTR_RW(fan_mode);
543 static DEVICE_ATTR_RW(usb_charge);
544 static DEVICE_ATTR_RW(reader_mode);
545 static DEVICE_ATTR_RW(fn_lock);
546 static DEVICE_ATTR_RW(charge_control_end_threshold);
547 static DEVICE_ATTR_RW(battery_care_limit);
548 
549 static int lg_battery_add(struct power_supply *battery, struct acpi_battery_hook *hook)
550 {
551 	if (device_create_file(&battery->dev,
552 			       &dev_attr_charge_control_end_threshold))
553 		return -ENODEV;
554 
555 	return 0;
556 }
557 
558 static int lg_battery_remove(struct power_supply *battery, struct acpi_battery_hook *hook)
559 {
560 	device_remove_file(&battery->dev,
561 			   &dev_attr_charge_control_end_threshold);
562 	return 0;
563 }
564 
565 static struct acpi_battery_hook battery_hook = {
566 	.add_battery = lg_battery_add,
567 	.remove_battery = lg_battery_remove,
568 	.name = "LG Battery Extension",
569 };
570 
571 static struct attribute *dev_attributes[] = {
572 	&dev_attr_fan_mode.attr,
573 	&dev_attr_usb_charge.attr,
574 	&dev_attr_reader_mode.attr,
575 	&dev_attr_fn_lock.attr,
576 	&dev_attr_battery_care_limit.attr,
577 	NULL
578 };
579 
580 static const struct attribute_group dev_attribute_group = {
581 	.attrs = dev_attributes,
582 };
583 
584 static void tpad_led_set(struct led_classdev *cdev,
585 			 enum led_brightness brightness)
586 {
587 	union acpi_object *r;
588 
589 	r = lg_wmab(WM_TLED, WM_SET, brightness > LED_OFF);
590 	kfree(r);
591 }
592 
593 static enum led_brightness tpad_led_get(struct led_classdev *cdev)
594 {
595 	return ggov(GOV_TLED) > 0 ? LED_ON : LED_OFF;
596 }
597 
598 static LED_DEVICE(tpad_led, 1, 0);
599 
600 static void kbd_backlight_set(struct led_classdev *cdev,
601 			      enum led_brightness brightness)
602 {
603 	u32 val;
604 	union acpi_object *r;
605 
606 	val = 0x22;
607 	if (brightness <= LED_OFF)
608 		val = 0;
609 	if (brightness >= LED_FULL)
610 		val = 0x24;
611 	r = lg_wmab(WM_KEY_LIGHT, WM_SET, val);
612 	kfree(r);
613 }
614 
615 static enum led_brightness get_kbd_backlight_level(void)
616 {
617 	union acpi_object *r;
618 	int val;
619 
620 	r = lg_wmab(WM_KEY_LIGHT, WM_GET, 0);
621 
622 	if (!r)
623 		return LED_OFF;
624 
625 	if (r->type != ACPI_TYPE_BUFFER || r->buffer.pointer[1] != 0x05) {
626 		kfree(r);
627 		return LED_OFF;
628 	}
629 
630 	switch (r->buffer.pointer[0] & 0x27) {
631 	case 0x24:
632 		val = LED_FULL;
633 		break;
634 	case 0x22:
635 		val = LED_HALF;
636 		break;
637 	default:
638 		val = LED_OFF;
639 	}
640 
641 	kfree(r);
642 
643 	return val;
644 }
645 
646 static enum led_brightness kbd_backlight_get(struct led_classdev *cdev)
647 {
648 	return get_kbd_backlight_level();
649 }
650 
651 static LED_DEVICE(kbd_backlight, 255, LED_BRIGHT_HW_CHANGED);
652 
653 static void wmi_input_destroy(void)
654 {
655 	if (inited & INIT_INPUT_WMI_2)
656 		wmi_remove_notify_handler(WMI_EVENT_GUID2);
657 
658 	if (inited & INIT_INPUT_WMI_0)
659 		wmi_remove_notify_handler(WMI_EVENT_GUID0);
660 
661 	if (inited & INIT_SPARSE_KEYMAP)
662 		input_unregister_device(wmi_input_dev);
663 
664 	inited &= ~(INIT_INPUT_WMI_0 | INIT_INPUT_WMI_2 | INIT_SPARSE_KEYMAP);
665 }
666 
667 static struct platform_driver pf_driver = {
668 	.driver = {
669 		   .name = PLATFORM_NAME,
670 	}
671 };
672 
673 static int acpi_add(struct acpi_device *device)
674 {
675 	int ret;
676 	const char *product;
677 	int year = 2017;
678 
679 	if (pf_device)
680 		return 0;
681 
682 	ret = platform_driver_register(&pf_driver);
683 	if (ret)
684 		return ret;
685 
686 	pf_device = platform_device_register_simple(PLATFORM_NAME,
687 						    PLATFORM_DEVID_NONE,
688 						    NULL, 0);
689 	if (IS_ERR(pf_device)) {
690 		ret = PTR_ERR(pf_device);
691 		pf_device = NULL;
692 		pr_err("unable to register platform device\n");
693 		goto out_platform_registered;
694 	}
695 	product = dmi_get_system_info(DMI_PRODUCT_NAME);
696 	if (product && strlen(product) > 4)
697 		switch (product[4]) {
698 		case '5':
699 			if (strlen(product) > 5)
700 				switch (product[5]) {
701 				case 'N':
702 					year = 2021;
703 					break;
704 				case '0':
705 					year = 2016;
706 					break;
707 				default:
708 					year = 2022;
709 				}
710 			break;
711 		case '6':
712 			year = 2016;
713 			break;
714 		case '7':
715 			year = 2017;
716 			break;
717 		case '8':
718 			year = 2018;
719 			break;
720 		case '9':
721 			year = 2019;
722 			break;
723 		case '0':
724 			if (strlen(product) > 5)
725 				switch (product[5]) {
726 				case 'N':
727 					year = 2020;
728 					break;
729 				case 'P':
730 					year = 2021;
731 					break;
732 				default:
733 					year = 2022;
734 				}
735 			break;
736 		default:
737 			year = 2019;
738 		}
739 	pr_info("product: %s  year: %d\n", product, year);
740 
741 	if (year >= 2019)
742 		battery_limit_use_wmbb = 1;
743 
744 	ret = sysfs_create_group(&pf_device->dev.kobj, &dev_attribute_group);
745 	if (ret)
746 		goto out_platform_device;
747 
748 	/* LEDs are optional */
749 	led_classdev_register(&pf_device->dev, &kbd_backlight);
750 	led_classdev_register(&pf_device->dev, &tpad_led);
751 
752 	wmi_input_setup();
753 	battery_hook_register(&battery_hook);
754 
755 	return 0;
756 
757 out_platform_device:
758 	platform_device_unregister(pf_device);
759 out_platform_registered:
760 	platform_driver_unregister(&pf_driver);
761 	return ret;
762 }
763 
764 static void acpi_remove(struct acpi_device *device)
765 {
766 	sysfs_remove_group(&pf_device->dev.kobj, &dev_attribute_group);
767 
768 	led_classdev_unregister(&tpad_led);
769 	led_classdev_unregister(&kbd_backlight);
770 
771 	battery_hook_unregister(&battery_hook);
772 	wmi_input_destroy();
773 	platform_device_unregister(pf_device);
774 	pf_device = NULL;
775 	platform_driver_unregister(&pf_driver);
776 }
777 
778 static const struct acpi_device_id device_ids[] = {
779 	{"LGEX0815", 0},
780 	{"", 0}
781 };
782 MODULE_DEVICE_TABLE(acpi, device_ids);
783 
784 static struct acpi_driver acpi_driver = {
785 	.name = "LG Gram Laptop Support",
786 	.class = "lg-laptop",
787 	.ids = device_ids,
788 	.ops = {
789 		.add = acpi_add,
790 		.remove = acpi_remove,
791 		.notify = acpi_notify,
792 		},
793 	.owner = THIS_MODULE,
794 };
795 
796 static int __init acpi_init(void)
797 {
798 	int result;
799 
800 	result = acpi_bus_register_driver(&acpi_driver);
801 	if (result < 0) {
802 		pr_debug("Error registering driver\n");
803 		return -ENODEV;
804 	}
805 
806 	return 0;
807 }
808 
809 static void __exit acpi_exit(void)
810 {
811 	acpi_bus_unregister_driver(&acpi_driver);
812 }
813 
814 module_init(acpi_init);
815 module_exit(acpi_exit);
816