8b292ee95a1448f3637fbeb887b557c009836e7e
[linux-2.6-microblaze.git] / drivers / platform / x86 / system76_acpi.c
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");