1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * System76 ACPI Driver
4  *
5  * Copyright (C) 2019 System76
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 
12 #include <linux/acpi.h>
13 #include <linux/hwmon.h>
14 #include <linux/hwmon-sysfs.h>
15 #include <linux/init.h>
16 #include <linux/input.h>
17 #include <linux/kernel.h>
18 #include <linux/leds.h>
19 #include <linux/module.h>
20 #include <linux/pci_ids.h>
21 #include <linux/power_supply.h>
22 #include <linux/sysfs.h>
23 #include <linux/types.h>
24 
25 #include <acpi/battery.h>
26 
27 struct system76_data {
28 	struct acpi_device *acpi_dev;
29 	struct led_classdev ap_led;
30 	struct led_classdev kb_led;
31 	enum led_brightness kb_brightness;
32 	enum led_brightness kb_toggle_brightness;
33 	int kb_color;
34 	struct device *therm;
35 	union acpi_object *nfan;
36 	union acpi_object *ntmp;
37 	struct input_dev *input;
38 };
39 
40 static const struct acpi_device_id device_ids[] = {
41 	{"17761776", 0},
42 	{"", 0},
43 };
44 MODULE_DEVICE_TABLE(acpi, device_ids);
45 
46 // Array of keyboard LED brightness levels
47 static const enum led_brightness kb_levels[] = {
48 	48,
49 	72,
50 	96,
51 	144,
52 	192,
53 	255
54 };
55 
56 // Array of keyboard LED colors in 24-bit RGB format
57 static const int kb_colors[] = {
58 	0xFFFFFF,
59 	0x0000FF,
60 	0xFF0000,
61 	0xFF00FF,
62 	0x00FF00,
63 	0x00FFFF,
64 	0xFFFF00
65 };
66 
67 // Get a System76 ACPI device value by name
68 static int system76_get(struct system76_data *data, char *method)
69 {
70 	acpi_handle handle;
71 	acpi_status status;
72 	unsigned long long ret = 0;
73 
74 	handle = acpi_device_handle(data->acpi_dev);
75 	status = acpi_evaluate_integer(handle, method, NULL, &ret);
76 	if (ACPI_SUCCESS(status))
77 		return ret;
78 	return -ENODEV;
79 }
80 
81 // Get a System76 ACPI device value by name with index
82 static int system76_get_index(struct system76_data *data, char *method, int index)
83 {
84 	union acpi_object obj;
85 	struct acpi_object_list obj_list;
86 	acpi_handle handle;
87 	acpi_status status;
88 	unsigned long long ret = 0;
89 
90 	obj.type = ACPI_TYPE_INTEGER;
91 	obj.integer.value = index;
92 	obj_list.count = 1;
93 	obj_list.pointer = &obj;
94 
95 	handle = acpi_device_handle(data->acpi_dev);
96 	status = acpi_evaluate_integer(handle, method, &obj_list, &ret);
97 	if (ACPI_SUCCESS(status))
98 		return ret;
99 	return -ENODEV;
100 }
101 
102 // Get a System76 ACPI device object by name
103 static int system76_get_object(struct system76_data *data, char *method, union acpi_object **obj)
104 {
105 	acpi_handle handle;
106 	acpi_status status;
107 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
108 
109 	handle = acpi_device_handle(data->acpi_dev);
110 	status = acpi_evaluate_object(handle, method, NULL, &buf);
111 	if (ACPI_SUCCESS(status)) {
112 		*obj = buf.pointer;
113 		return 0;
114 	}
115 
116 	return -ENODEV;
117 }
118 
119 // Get a name from a System76 ACPI device object
120 static char *system76_name(union acpi_object *obj, int index)
121 {
122 	if (obj && obj->type == ACPI_TYPE_PACKAGE && index <= obj->package.count) {
123 		if (obj->package.elements[index].type == ACPI_TYPE_STRING)
124 			return obj->package.elements[index].string.pointer;
125 	}
126 
127 	return NULL;
128 }
129 
130 // Set a System76 ACPI device value by name
131 static int system76_set(struct system76_data *data, char *method, int value)
132 {
133 	union acpi_object obj;
134 	struct acpi_object_list obj_list;
135 	acpi_handle handle;
136 	acpi_status status;
137 
138 	obj.type = ACPI_TYPE_INTEGER;
139 	obj.integer.value = value;
140 	obj_list.count = 1;
141 	obj_list.pointer = &obj;
142 	handle = acpi_device_handle(data->acpi_dev);
143 	status = acpi_evaluate_object(handle, method, &obj_list, NULL);
144 	if (ACPI_SUCCESS(status))
145 		return 0;
146 	else
147 		return -1;
148 }
149 
150 #define BATTERY_THRESHOLD_INVALID	0xFF
151 
152 enum {
153 	THRESHOLD_START,
154 	THRESHOLD_END,
155 };
156 
157 static ssize_t battery_get_threshold(int which, char *buf)
158 {
159 	struct acpi_object_list input;
160 	union acpi_object param;
161 	acpi_handle handle;
162 	acpi_status status;
163 	unsigned long long ret = BATTERY_THRESHOLD_INVALID;
164 
165 	handle = ec_get_handle();
166 	if (!handle)
167 		return -ENODEV;
168 
169 	input.count = 1;
170 	input.pointer = &param;
171 	// Start/stop selection
172 	param.type = ACPI_TYPE_INTEGER;
173 	param.integer.value = which;
174 
175 	status = acpi_evaluate_integer(handle, "GBCT", &input, &ret);
176 	if (ACPI_FAILURE(status))
177 		return -EIO;
178 	if (ret == BATTERY_THRESHOLD_INVALID)
179 		return -EINVAL;
180 
181 	return sysfs_emit(buf, "%d\n", (int)ret);
182 }
183 
184 static ssize_t battery_set_threshold(int which, const char *buf, size_t count)
185 {
186 	struct acpi_object_list input;
187 	union acpi_object params[2];
188 	acpi_handle handle;
189 	acpi_status status;
190 	unsigned int value;
191 	int ret;
192 
193 	handle = ec_get_handle();
194 	if (!handle)
195 		return -ENODEV;
196 
197 	ret = kstrtouint(buf, 10, &value);
198 	if (ret)
199 		return ret;
200 
201 	if (value > 100)
202 		return -EINVAL;
203 
204 	input.count = 2;
205 	input.pointer = params;
206 	// Start/stop selection
207 	params[0].type = ACPI_TYPE_INTEGER;
208 	params[0].integer.value = which;
209 	// Threshold value
210 	params[1].type = ACPI_TYPE_INTEGER;
211 	params[1].integer.value = value;
212 
213 	status = acpi_evaluate_object(handle, "SBCT", &input, NULL);
214 	if (ACPI_FAILURE(status))
215 		return -EIO;
216 
217 	return count;
218 }
219 
220 static ssize_t charge_control_start_threshold_show(struct device *dev,
221 	struct device_attribute *attr, char *buf)
222 {
223 	return battery_get_threshold(THRESHOLD_START, buf);
224 }
225 
226 static ssize_t charge_control_start_threshold_store(struct device *dev,
227 	struct device_attribute *attr, const char *buf, size_t count)
228 {
229 	return battery_set_threshold(THRESHOLD_START, buf, count);
230 }
231 
232 static DEVICE_ATTR_RW(charge_control_start_threshold);
233 
234 static ssize_t charge_control_end_threshold_show(struct device *dev,
235 	struct device_attribute *attr, char *buf)
236 {
237 	return battery_get_threshold(THRESHOLD_END, buf);
238 }
239 
240 static ssize_t charge_control_end_threshold_store(struct device *dev,
241 	struct device_attribute *attr, const char *buf, size_t count)
242 {
243 	return battery_set_threshold(THRESHOLD_END, buf, count);
244 }
245 
246 static DEVICE_ATTR_RW(charge_control_end_threshold);
247 
248 static struct attribute *system76_battery_attrs[] = {
249 	&dev_attr_charge_control_start_threshold.attr,
250 	&dev_attr_charge_control_end_threshold.attr,
251 	NULL,
252 };
253 
254 ATTRIBUTE_GROUPS(system76_battery);
255 
256 static int system76_battery_add(struct power_supply *battery)
257 {
258 	// System76 EC only supports 1 battery
259 	if (strcmp(battery->desc->name, "BAT0") != 0)
260 		return -ENODEV;
261 
262 	if (device_add_groups(&battery->dev, system76_battery_groups))
263 		return -ENODEV;
264 
265 	return 0;
266 }
267 
268 static int system76_battery_remove(struct power_supply *battery)
269 {
270 	device_remove_groups(&battery->dev, system76_battery_groups);
271 	return 0;
272 }
273 
274 static struct acpi_battery_hook system76_battery_hook = {
275 	.add_battery = system76_battery_add,
276 	.remove_battery = system76_battery_remove,
277 	.name = "System76 Battery Extension",
278 };
279 
280 static void system76_battery_init(void)
281 {
282 	acpi_handle handle;
283 
284 	handle = ec_get_handle();
285 	if (handle && acpi_has_method(handle, "GBCT"))
286 		battery_hook_register(&system76_battery_hook);
287 }
288 
289 static void system76_battery_exit(void)
290 {
291 	acpi_handle handle;
292 
293 	handle = ec_get_handle();
294 	if (handle && acpi_has_method(handle, "GBCT"))
295 		battery_hook_unregister(&system76_battery_hook);
296 }
297 
298 // Get the airplane mode LED brightness
299 static enum led_brightness ap_led_get(struct led_classdev *led)
300 {
301 	struct system76_data *data;
302 	int value;
303 
304 	data = container_of(led, struct system76_data, ap_led);
305 	value = system76_get(data, "GAPL");
306 	if (value > 0)
307 		return (enum led_brightness)value;
308 	else
309 		return LED_OFF;
310 }
311 
312 // Set the airplane mode LED brightness
313 static int ap_led_set(struct led_classdev *led, enum led_brightness value)
314 {
315 	struct system76_data *data;
316 
317 	data = container_of(led, struct system76_data, ap_led);
318 	return system76_set(data, "SAPL", value == LED_OFF ? 0 : 1);
319 }
320 
321 // Get the last set keyboard LED brightness
322 static enum led_brightness kb_led_get(struct led_classdev *led)
323 {
324 	struct system76_data *data;
325 
326 	data = container_of(led, struct system76_data, kb_led);
327 	return data->kb_brightness;
328 }
329 
330 // Set the keyboard LED brightness
331 static int kb_led_set(struct led_classdev *led, enum led_brightness value)
332 {
333 	struct system76_data *data;
334 
335 	data = container_of(led, struct system76_data, kb_led);
336 	data->kb_brightness = value;
337 	return system76_set(data, "SKBL", (int)data->kb_brightness);
338 }
339 
340 // Get the last set keyboard LED color
341 static ssize_t kb_led_color_show(
342 	struct device *dev,
343 	struct device_attribute *dev_attr,
344 	char *buf)
345 {
346 	struct led_classdev *led;
347 	struct system76_data *data;
348 
349 	led = (struct led_classdev *)dev->driver_data;
350 	data = container_of(led, struct system76_data, kb_led);
351 	return sprintf(buf, "%06X\n", data->kb_color);
352 }
353 
354 // Set the keyboard LED color
355 static ssize_t kb_led_color_store(
356 	struct device *dev,
357 	struct device_attribute *dev_attr,
358 	const char *buf,
359 	size_t size)
360 {
361 	struct led_classdev *led;
362 	struct system76_data *data;
363 	unsigned int val;
364 	int ret;
365 
366 	led = (struct led_classdev *)dev->driver_data;
367 	data = container_of(led, struct system76_data, kb_led);
368 	ret = kstrtouint(buf, 16, &val);
369 	if (ret)
370 		return ret;
371 	if (val > 0xFFFFFF)
372 		return -EINVAL;
373 	data->kb_color = (int)val;
374 	system76_set(data, "SKBC", data->kb_color);
375 
376 	return size;
377 }
378 
379 static const struct device_attribute kb_led_color_dev_attr = {
380 	.attr = {
381 		.name = "color",
382 		.mode = 0644,
383 	},
384 	.show = kb_led_color_show,
385 	.store = kb_led_color_store,
386 };
387 
388 // Notify that the keyboard LED was changed by hardware
389 static void kb_led_notify(struct system76_data *data)
390 {
391 	led_classdev_notify_brightness_hw_changed(
392 		&data->kb_led,
393 		data->kb_brightness
394 	);
395 }
396 
397 // Read keyboard LED brightness as set by hardware
398 static void kb_led_hotkey_hardware(struct system76_data *data)
399 {
400 	int value;
401 
402 	value = system76_get(data, "GKBL");
403 	if (value < 0)
404 		return;
405 	data->kb_brightness = value;
406 	kb_led_notify(data);
407 }
408 
409 // Toggle the keyboard LED
410 static void kb_led_hotkey_toggle(struct system76_data *data)
411 {
412 	if (data->kb_brightness > 0) {
413 		data->kb_toggle_brightness = data->kb_brightness;
414 		kb_led_set(&data->kb_led, 0);
415 	} else {
416 		kb_led_set(&data->kb_led, data->kb_toggle_brightness);
417 	}
418 	kb_led_notify(data);
419 }
420 
421 // Decrease the keyboard LED brightness
422 static void kb_led_hotkey_down(struct system76_data *data)
423 {
424 	int i;
425 
426 	if (data->kb_brightness > 0) {
427 		for (i = ARRAY_SIZE(kb_levels); i > 0; i--) {
428 			if (kb_levels[i - 1] < data->kb_brightness) {
429 				kb_led_set(&data->kb_led, kb_levels[i - 1]);
430 				break;
431 			}
432 		}
433 	} else {
434 		kb_led_set(&data->kb_led, data->kb_toggle_brightness);
435 	}
436 	kb_led_notify(data);
437 }
438 
439 // Increase the keyboard LED brightness
440 static void kb_led_hotkey_up(struct system76_data *data)
441 {
442 	int i;
443 
444 	if (data->kb_brightness > 0) {
445 		for (i = 0; i < ARRAY_SIZE(kb_levels); i++) {
446 			if (kb_levels[i] > data->kb_brightness) {
447 				kb_led_set(&data->kb_led, kb_levels[i]);
448 				break;
449 			}
450 		}
451 	} else {
452 		kb_led_set(&data->kb_led, data->kb_toggle_brightness);
453 	}
454 	kb_led_notify(data);
455 }
456 
457 // Cycle the keyboard LED color
458 static void kb_led_hotkey_color(struct system76_data *data)
459 {
460 	int i;
461 
462 	if (data->kb_color < 0)
463 		return;
464 	if (data->kb_brightness > 0) {
465 		for (i = 0; i < ARRAY_SIZE(kb_colors); i++) {
466 			if (kb_colors[i] == data->kb_color)
467 				break;
468 		}
469 		i += 1;
470 		if (i >= ARRAY_SIZE(kb_colors))
471 			i = 0;
472 		data->kb_color = kb_colors[i];
473 		system76_set(data, "SKBC", data->kb_color);
474 	} else {
475 		kb_led_set(&data->kb_led, data->kb_toggle_brightness);
476 	}
477 	kb_led_notify(data);
478 }
479 
480 static umode_t thermal_is_visible(const void *drvdata, enum hwmon_sensor_types type,
481 				  u32 attr, int channel)
482 {
483 	const struct system76_data *data = drvdata;
484 
485 	switch (type) {
486 	case hwmon_fan:
487 	case hwmon_pwm:
488 		if (system76_name(data->nfan, channel))
489 			return 0444;
490 		break;
491 
492 	case hwmon_temp:
493 		if (system76_name(data->ntmp, channel))
494 			return 0444;
495 		break;
496 
497 	default:
498 		return 0;
499 	}
500 
501 	return 0;
502 }
503 
504 static int thermal_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
505 			int channel, long *val)
506 {
507 	struct system76_data *data = dev_get_drvdata(dev);
508 	int raw;
509 
510 	switch (type) {
511 	case hwmon_fan:
512 		if (attr == hwmon_fan_input) {
513 			raw = system76_get_index(data, "GFAN", channel);
514 			if (raw < 0)
515 				return raw;
516 			*val = (raw >> 8) & 0xFFFF;
517 			return 0;
518 		}
519 		break;
520 
521 	case hwmon_pwm:
522 		if (attr == hwmon_pwm_input) {
523 			raw = system76_get_index(data, "GFAN", channel);
524 			if (raw < 0)
525 				return raw;
526 			*val = raw & 0xFF;
527 			return 0;
528 		}
529 		break;
530 
531 	case hwmon_temp:
532 		if (attr == hwmon_temp_input) {
533 			raw = system76_get_index(data, "GTMP", channel);
534 			if (raw < 0)
535 				return raw;
536 			*val = raw * 1000;
537 			return 0;
538 		}
539 		break;
540 
541 	default:
542 		return -EOPNOTSUPP;
543 	}
544 
545 	return -EOPNOTSUPP;
546 }
547 
548 static int thermal_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
549 			       int channel, const char **str)
550 {
551 	struct system76_data *data = dev_get_drvdata(dev);
552 
553 	switch (type) {
554 	case hwmon_fan:
555 		if (attr == hwmon_fan_label) {
556 			*str = system76_name(data->nfan, channel);
557 			if (*str)
558 				return 0;
559 		}
560 		break;
561 
562 	case hwmon_temp:
563 		if (attr == hwmon_temp_label) {
564 			*str = system76_name(data->ntmp, channel);
565 			if (*str)
566 				return 0;
567 		}
568 		break;
569 
570 	default:
571 		return -EOPNOTSUPP;
572 	}
573 
574 	return -EOPNOTSUPP;
575 }
576 
577 static const struct hwmon_ops thermal_ops = {
578 	.is_visible = thermal_is_visible,
579 	.read = thermal_read,
580 	.read_string = thermal_read_string,
581 };
582 
583 // Allocate up to 8 fans and temperatures
584 static const struct hwmon_channel_info *thermal_channel_info[] = {
585 	HWMON_CHANNEL_INFO(fan,
586 		HWMON_F_INPUT | HWMON_F_LABEL,
587 		HWMON_F_INPUT | HWMON_F_LABEL,
588 		HWMON_F_INPUT | HWMON_F_LABEL,
589 		HWMON_F_INPUT | HWMON_F_LABEL,
590 		HWMON_F_INPUT | HWMON_F_LABEL,
591 		HWMON_F_INPUT | HWMON_F_LABEL,
592 		HWMON_F_INPUT | HWMON_F_LABEL,
593 		HWMON_F_INPUT | HWMON_F_LABEL),
594 	HWMON_CHANNEL_INFO(pwm,
595 		HWMON_PWM_INPUT,
596 		HWMON_PWM_INPUT,
597 		HWMON_PWM_INPUT,
598 		HWMON_PWM_INPUT,
599 		HWMON_PWM_INPUT,
600 		HWMON_PWM_INPUT,
601 		HWMON_PWM_INPUT,
602 		HWMON_PWM_INPUT),
603 	HWMON_CHANNEL_INFO(temp,
604 		HWMON_T_INPUT | HWMON_T_LABEL,
605 		HWMON_T_INPUT | HWMON_T_LABEL,
606 		HWMON_T_INPUT | HWMON_T_LABEL,
607 		HWMON_T_INPUT | HWMON_T_LABEL,
608 		HWMON_T_INPUT | HWMON_T_LABEL,
609 		HWMON_T_INPUT | HWMON_T_LABEL,
610 		HWMON_T_INPUT | HWMON_T_LABEL,
611 		HWMON_T_INPUT | HWMON_T_LABEL),
612 	NULL
613 };
614 
615 static const struct hwmon_chip_info thermal_chip_info = {
616 	.ops = &thermal_ops,
617 	.info = thermal_channel_info,
618 };
619 
620 static void input_key(struct system76_data *data, unsigned int code)
621 {
622 	input_report_key(data->input, code, 1);
623 	input_sync(data->input);
624 
625 	input_report_key(data->input, code, 0);
626 	input_sync(data->input);
627 }
628 
629 // Handle ACPI notification
630 static void system76_notify(struct acpi_device *acpi_dev, u32 event)
631 {
632 	struct system76_data *data;
633 
634 	data = acpi_driver_data(acpi_dev);
635 	switch (event) {
636 	case 0x80:
637 		kb_led_hotkey_hardware(data);
638 		break;
639 	case 0x81:
640 		kb_led_hotkey_toggle(data);
641 		break;
642 	case 0x82:
643 		kb_led_hotkey_down(data);
644 		break;
645 	case 0x83:
646 		kb_led_hotkey_up(data);
647 		break;
648 	case 0x84:
649 		kb_led_hotkey_color(data);
650 		break;
651 	case 0x85:
652 		input_key(data, KEY_SCREENLOCK);
653 		break;
654 	}
655 }
656 
657 // Add a System76 ACPI device
658 static int system76_add(struct acpi_device *acpi_dev)
659 {
660 	struct system76_data *data;
661 	int err;
662 
663 	data = devm_kzalloc(&acpi_dev->dev, sizeof(*data), GFP_KERNEL);
664 	if (!data)
665 		return -ENOMEM;
666 	acpi_dev->driver_data = data;
667 	data->acpi_dev = acpi_dev;
668 
669 	err = system76_get(data, "INIT");
670 	if (err)
671 		return err;
672 	data->ap_led.name = "system76_acpi::airplane";
673 	data->ap_led.flags = LED_CORE_SUSPENDRESUME;
674 	data->ap_led.brightness_get = ap_led_get;
675 	data->ap_led.brightness_set_blocking = ap_led_set;
676 	data->ap_led.max_brightness = 1;
677 	data->ap_led.default_trigger = "rfkill-none";
678 	err = devm_led_classdev_register(&acpi_dev->dev, &data->ap_led);
679 	if (err)
680 		return err;
681 
682 	data->kb_led.name = "system76_acpi::kbd_backlight";
683 	data->kb_led.flags = LED_BRIGHT_HW_CHANGED | LED_CORE_SUSPENDRESUME;
684 	data->kb_led.brightness_get = kb_led_get;
685 	data->kb_led.brightness_set_blocking = kb_led_set;
686 	if (acpi_has_method(acpi_device_handle(data->acpi_dev), "SKBC")) {
687 		data->kb_led.max_brightness = 255;
688 		data->kb_toggle_brightness = 72;
689 		data->kb_color = 0xffffff;
690 		system76_set(data, "SKBC", data->kb_color);
691 	} else {
692 		data->kb_led.max_brightness = 5;
693 		data->kb_color = -1;
694 	}
695 	err = devm_led_classdev_register(&acpi_dev->dev, &data->kb_led);
696 	if (err)
697 		return err;
698 
699 	if (data->kb_color >= 0) {
700 		err = device_create_file(
701 			data->kb_led.dev,
702 			&kb_led_color_dev_attr
703 		);
704 		if (err)
705 			return err;
706 	}
707 
708 	data->input = devm_input_allocate_device(&acpi_dev->dev);
709 	if (!data->input)
710 		return -ENOMEM;
711 
712 	data->input->name = "System76 ACPI Hotkeys";
713 	data->input->phys = "system76_acpi/input0";
714 	data->input->id.bustype = BUS_HOST;
715 	data->input->dev.parent = &acpi_dev->dev;
716 	input_set_capability(data->input, EV_KEY, KEY_SCREENLOCK);
717 
718 	err = input_register_device(data->input);
719 	if (err)
720 		goto error;
721 
722 	err = system76_get_object(data, "NFAN", &data->nfan);
723 	if (err)
724 		goto error;
725 
726 	err = system76_get_object(data, "NTMP", &data->ntmp);
727 	if (err)
728 		goto error;
729 
730 	data->therm = devm_hwmon_device_register_with_info(&acpi_dev->dev,
731 		"system76_acpi", data, &thermal_chip_info, NULL);
732 	err = PTR_ERR_OR_ZERO(data->therm);
733 	if (err)
734 		goto error;
735 
736 	system76_battery_init();
737 
738 	return 0;
739 
740 error:
741 	kfree(data->ntmp);
742 	kfree(data->nfan);
743 	input_free_device(data->input);
744 	return err;
745 }
746 
747 // Remove a System76 ACPI device
748 static int system76_remove(struct acpi_device *acpi_dev)
749 {
750 	struct system76_data *data;
751 
752 	data = acpi_driver_data(acpi_dev);
753 
754 	system76_battery_exit();
755 
756 	if (data->kb_color >= 0)
757 		device_remove_file(data->kb_led.dev, &kb_led_color_dev_attr);
758 
759 	devm_led_classdev_unregister(&acpi_dev->dev, &data->ap_led);
760 	devm_led_classdev_unregister(&acpi_dev->dev, &data->kb_led);
761 
762 	kfree(data->nfan);
763 	kfree(data->ntmp);
764 
765 	system76_get(data, "FINI");
766 
767 	return 0;
768 }
769 
770 static struct acpi_driver system76_driver = {
771 	.name = "System76 ACPI Driver",
772 	.class = "hotkey",
773 	.ids = device_ids,
774 	.ops = {
775 		.add = system76_add,
776 		.remove = system76_remove,
777 		.notify = system76_notify,
778 	},
779 };
780 module_acpi_driver(system76_driver);
781 
782 MODULE_DESCRIPTION("System76 ACPI Driver");
783 MODULE_AUTHOR("Jeremy Soller <jeremy@system76.com>");
784 MODULE_LICENSE("GPL");
785