system76_acpi.c 19 KB

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