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 sysfs_emit(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 struct device_attribute dev_attr_kb_led_color = {
380 	.attr = {
381 		.name = "color",
382 		.mode = 0644,
383 	},
384 	.show = kb_led_color_show,
385 	.store = kb_led_color_store,
386 };
387 
388 static struct attribute *system76_kb_led_color_attrs[] = {
389 	&dev_attr_kb_led_color.attr,
390 	NULL,
391 };
392 
393 ATTRIBUTE_GROUPS(system76_kb_led_color);
394 
395 // Notify that the keyboard LED was changed by hardware
396 static void kb_led_notify(struct system76_data *data)
397 {
398 	led_classdev_notify_brightness_hw_changed(
399 		&data->kb_led,
400 		data->kb_brightness
401 	);
402 }
403 
404 // Read keyboard LED brightness as set by hardware
405 static void kb_led_hotkey_hardware(struct system76_data *data)
406 {
407 	int value;
408 
409 	value = system76_get(data, "GKBL");
410 	if (value < 0)
411 		return;
412 	data->kb_brightness = value;
413 	kb_led_notify(data);
414 }
415 
416 // Toggle the keyboard LED
417 static void kb_led_hotkey_toggle(struct system76_data *data)
418 {
419 	if (data->kb_brightness > 0) {
420 		data->kb_toggle_brightness = data->kb_brightness;
421 		kb_led_set(&data->kb_led, 0);
422 	} else {
423 		kb_led_set(&data->kb_led, data->kb_toggle_brightness);
424 	}
425 	kb_led_notify(data);
426 }
427 
428 // Decrease the keyboard LED brightness
429 static void kb_led_hotkey_down(struct system76_data *data)
430 {
431 	int i;
432 
433 	if (data->kb_brightness > 0) {
434 		for (i = ARRAY_SIZE(kb_levels); i > 0; i--) {
435 			if (kb_levels[i - 1] < data->kb_brightness) {
436 				kb_led_set(&data->kb_led, kb_levels[i - 1]);
437 				break;
438 			}
439 		}
440 	} else {
441 		kb_led_set(&data->kb_led, data->kb_toggle_brightness);
442 	}
443 	kb_led_notify(data);
444 }
445 
446 // Increase the keyboard LED brightness
447 static void kb_led_hotkey_up(struct system76_data *data)
448 {
449 	int i;
450 
451 	if (data->kb_brightness > 0) {
452 		for (i = 0; i < ARRAY_SIZE(kb_levels); i++) {
453 			if (kb_levels[i] > data->kb_brightness) {
454 				kb_led_set(&data->kb_led, kb_levels[i]);
455 				break;
456 			}
457 		}
458 	} else {
459 		kb_led_set(&data->kb_led, data->kb_toggle_brightness);
460 	}
461 	kb_led_notify(data);
462 }
463 
464 // Cycle the keyboard LED color
465 static void kb_led_hotkey_color(struct system76_data *data)
466 {
467 	int i;
468 
469 	if (data->kb_color < 0)
470 		return;
471 	if (data->kb_brightness > 0) {
472 		for (i = 0; i < ARRAY_SIZE(kb_colors); i++) {
473 			if (kb_colors[i] == data->kb_color)
474 				break;
475 		}
476 		i += 1;
477 		if (i >= ARRAY_SIZE(kb_colors))
478 			i = 0;
479 		data->kb_color = kb_colors[i];
480 		system76_set(data, "SKBC", data->kb_color);
481 	} else {
482 		kb_led_set(&data->kb_led, data->kb_toggle_brightness);
483 	}
484 	kb_led_notify(data);
485 }
486 
487 static umode_t thermal_is_visible(const void *drvdata, enum hwmon_sensor_types type,
488 				  u32 attr, int channel)
489 {
490 	const struct system76_data *data = drvdata;
491 
492 	switch (type) {
493 	case hwmon_fan:
494 	case hwmon_pwm:
495 		if (system76_name(data->nfan, channel))
496 			return 0444;
497 		break;
498 
499 	case hwmon_temp:
500 		if (system76_name(data->ntmp, channel))
501 			return 0444;
502 		break;
503 
504 	default:
505 		return 0;
506 	}
507 
508 	return 0;
509 }
510 
511 static int thermal_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
512 			int channel, long *val)
513 {
514 	struct system76_data *data = dev_get_drvdata(dev);
515 	int raw;
516 
517 	switch (type) {
518 	case hwmon_fan:
519 		if (attr == hwmon_fan_input) {
520 			raw = system76_get_index(data, "GFAN", channel);
521 			if (raw < 0)
522 				return raw;
523 			*val = (raw >> 8) & 0xFFFF;
524 			return 0;
525 		}
526 		break;
527 
528 	case hwmon_pwm:
529 		if (attr == hwmon_pwm_input) {
530 			raw = system76_get_index(data, "GFAN", channel);
531 			if (raw < 0)
532 				return raw;
533 			*val = raw & 0xFF;
534 			return 0;
535 		}
536 		break;
537 
538 	case hwmon_temp:
539 		if (attr == hwmon_temp_input) {
540 			raw = system76_get_index(data, "GTMP", channel);
541 			if (raw < 0)
542 				return raw;
543 			*val = raw * 1000;
544 			return 0;
545 		}
546 		break;
547 
548 	default:
549 		return -EOPNOTSUPP;
550 	}
551 
552 	return -EOPNOTSUPP;
553 }
554 
555 static int thermal_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
556 			       int channel, const char **str)
557 {
558 	struct system76_data *data = dev_get_drvdata(dev);
559 
560 	switch (type) {
561 	case hwmon_fan:
562 		if (attr == hwmon_fan_label) {
563 			*str = system76_name(data->nfan, channel);
564 			if (*str)
565 				return 0;
566 		}
567 		break;
568 
569 	case hwmon_temp:
570 		if (attr == hwmon_temp_label) {
571 			*str = system76_name(data->ntmp, channel);
572 			if (*str)
573 				return 0;
574 		}
575 		break;
576 
577 	default:
578 		return -EOPNOTSUPP;
579 	}
580 
581 	return -EOPNOTSUPP;
582 }
583 
584 static const struct hwmon_ops thermal_ops = {
585 	.is_visible = thermal_is_visible,
586 	.read = thermal_read,
587 	.read_string = thermal_read_string,
588 };
589 
590 // Allocate up to 8 fans and temperatures
591 static const struct hwmon_channel_info *thermal_channel_info[] = {
592 	HWMON_CHANNEL_INFO(fan,
593 		HWMON_F_INPUT | HWMON_F_LABEL,
594 		HWMON_F_INPUT | HWMON_F_LABEL,
595 		HWMON_F_INPUT | HWMON_F_LABEL,
596 		HWMON_F_INPUT | HWMON_F_LABEL,
597 		HWMON_F_INPUT | HWMON_F_LABEL,
598 		HWMON_F_INPUT | HWMON_F_LABEL,
599 		HWMON_F_INPUT | HWMON_F_LABEL,
600 		HWMON_F_INPUT | HWMON_F_LABEL),
601 	HWMON_CHANNEL_INFO(pwm,
602 		HWMON_PWM_INPUT,
603 		HWMON_PWM_INPUT,
604 		HWMON_PWM_INPUT,
605 		HWMON_PWM_INPUT,
606 		HWMON_PWM_INPUT,
607 		HWMON_PWM_INPUT,
608 		HWMON_PWM_INPUT,
609 		HWMON_PWM_INPUT),
610 	HWMON_CHANNEL_INFO(temp,
611 		HWMON_T_INPUT | HWMON_T_LABEL,
612 		HWMON_T_INPUT | HWMON_T_LABEL,
613 		HWMON_T_INPUT | HWMON_T_LABEL,
614 		HWMON_T_INPUT | HWMON_T_LABEL,
615 		HWMON_T_INPUT | HWMON_T_LABEL,
616 		HWMON_T_INPUT | HWMON_T_LABEL,
617 		HWMON_T_INPUT | HWMON_T_LABEL,
618 		HWMON_T_INPUT | HWMON_T_LABEL),
619 	NULL
620 };
621 
622 static const struct hwmon_chip_info thermal_chip_info = {
623 	.ops = &thermal_ops,
624 	.info = thermal_channel_info,
625 };
626 
627 static void input_key(struct system76_data *data, unsigned int code)
628 {
629 	input_report_key(data->input, code, 1);
630 	input_sync(data->input);
631 
632 	input_report_key(data->input, code, 0);
633 	input_sync(data->input);
634 }
635 
636 // Handle ACPI notification
637 static void system76_notify(struct acpi_device *acpi_dev, u32 event)
638 {
639 	struct system76_data *data;
640 
641 	data = acpi_driver_data(acpi_dev);
642 	switch (event) {
643 	case 0x80:
644 		kb_led_hotkey_hardware(data);
645 		break;
646 	case 0x81:
647 		kb_led_hotkey_toggle(data);
648 		break;
649 	case 0x82:
650 		kb_led_hotkey_down(data);
651 		break;
652 	case 0x83:
653 		kb_led_hotkey_up(data);
654 		break;
655 	case 0x84:
656 		kb_led_hotkey_color(data);
657 		break;
658 	case 0x85:
659 		input_key(data, KEY_SCREENLOCK);
660 		break;
661 	}
662 }
663 
664 // Add a System76 ACPI device
665 static int system76_add(struct acpi_device *acpi_dev)
666 {
667 	struct system76_data *data;
668 	int err;
669 
670 	data = devm_kzalloc(&acpi_dev->dev, sizeof(*data), GFP_KERNEL);
671 	if (!data)
672 		return -ENOMEM;
673 	acpi_dev->driver_data = data;
674 	data->acpi_dev = acpi_dev;
675 
676 	err = system76_get(data, "INIT");
677 	if (err)
678 		return err;
679 	data->ap_led.name = "system76_acpi::airplane";
680 	data->ap_led.flags = LED_CORE_SUSPENDRESUME;
681 	data->ap_led.brightness_get = ap_led_get;
682 	data->ap_led.brightness_set_blocking = ap_led_set;
683 	data->ap_led.max_brightness = 1;
684 	data->ap_led.default_trigger = "rfkill-none";
685 	err = devm_led_classdev_register(&acpi_dev->dev, &data->ap_led);
686 	if (err)
687 		return err;
688 
689 	data->kb_led.name = "system76_acpi::kbd_backlight";
690 	data->kb_led.flags = LED_BRIGHT_HW_CHANGED | LED_CORE_SUSPENDRESUME;
691 	data->kb_led.brightness_get = kb_led_get;
692 	data->kb_led.brightness_set_blocking = kb_led_set;
693 	if (acpi_has_method(acpi_device_handle(data->acpi_dev), "SKBC")) {
694 		data->kb_led.max_brightness = 255;
695 		data->kb_led.groups = system76_kb_led_color_groups;
696 		data->kb_toggle_brightness = 72;
697 		data->kb_color = 0xffffff;
698 		system76_set(data, "SKBC", data->kb_color);
699 	} else {
700 		data->kb_led.max_brightness = 5;
701 		data->kb_color = -1;
702 	}
703 	err = devm_led_classdev_register(&acpi_dev->dev, &data->kb_led);
704 	if (err)
705 		return err;
706 
707 	data->input = devm_input_allocate_device(&acpi_dev->dev);
708 	if (!data->input)
709 		return -ENOMEM;
710 
711 	data->input->name = "System76 ACPI Hotkeys";
712 	data->input->phys = "system76_acpi/input0";
713 	data->input->id.bustype = BUS_HOST;
714 	data->input->dev.parent = &acpi_dev->dev;
715 	input_set_capability(data->input, EV_KEY, KEY_SCREENLOCK);
716 
717 	err = input_register_device(data->input);
718 	if (err)
719 		goto error;
720 
721 	err = system76_get_object(data, "NFAN", &data->nfan);
722 	if (err)
723 		goto error;
724 
725 	err = system76_get_object(data, "NTMP", &data->ntmp);
726 	if (err)
727 		goto error;
728 
729 	data->therm = devm_hwmon_device_register_with_info(&acpi_dev->dev,
730 		"system76_acpi", data, &thermal_chip_info, NULL);
731 	err = PTR_ERR_OR_ZERO(data->therm);
732 	if (err)
733 		goto error;
734 
735 	system76_battery_init();
736 
737 	return 0;
738 
739 error:
740 	kfree(data->ntmp);
741 	kfree(data->nfan);
742 	return err;
743 }
744 
745 // Remove a System76 ACPI device
746 static int system76_remove(struct acpi_device *acpi_dev)
747 {
748 	struct system76_data *data;
749 
750 	data = acpi_driver_data(acpi_dev);
751 
752 	system76_battery_exit();
753 
754 	devm_led_classdev_unregister(&acpi_dev->dev, &data->ap_led);
755 	devm_led_classdev_unregister(&acpi_dev->dev, &data->kb_led);
756 
757 	kfree(data->nfan);
758 	kfree(data->ntmp);
759 
760 	system76_get(data, "FINI");
761 
762 	return 0;
763 }
764 
765 static struct acpi_driver system76_driver = {
766 	.name = "System76 ACPI Driver",
767 	.class = "hotkey",
768 	.ids = device_ids,
769 	.ops = {
770 		.add = system76_add,
771 		.remove = system76_remove,
772 		.notify = system76_notify,
773 	},
774 };
775 module_acpi_driver(system76_driver);
776 
777 MODULE_DESCRIPTION("System76 ACPI Driver");
778 MODULE_AUTHOR("Jeremy Soller <jeremy@system76.com>");
779 MODULE_LICENSE("GPL");
780