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