1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Alienware WMAX WMI device driver
4 *
5 * Copyright (C) 2014 Dell Inc <Dell.Client.Kernel@dell.com>
6 * Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com>
7 */
8
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10
11 #include <linux/array_size.h>
12 #include <linux/bitfield.h>
13 #include <linux/bitmap.h>
14 #include <linux/bits.h>
15 #include <linux/debugfs.h>
16 #include <linux/dmi.h>
17 #include <linux/hwmon.h>
18 #include <linux/hwmon-sysfs.h>
19 #include <linux/kstrtox.h>
20 #include <linux/minmax.h>
21 #include <linux/moduleparam.h>
22 #include <linux/platform_profile.h>
23 #include <linux/pm.h>
24 #include <linux/seq_file.h>
25 #include <linux/units.h>
26 #include <linux/wmi.h>
27 #include "alienware-wmi.h"
28
29 #define WMAX_METHOD_HDMI_SOURCE 0x1
30 #define WMAX_METHOD_HDMI_STATUS 0x2
31 #define WMAX_METHOD_HDMI_CABLE 0x5
32 #define WMAX_METHOD_AMPLIFIER_CABLE 0x6
33 #define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B
34 #define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C
35 #define WMAX_METHOD_BRIGHTNESS 0x3
36 #define WMAX_METHOD_ZONE_CONTROL 0x4
37
38 #define AWCC_METHOD_GET_FAN_SENSORS 0x13
39 #define AWCC_METHOD_THERMAL_INFORMATION 0x14
40 #define AWCC_METHOD_THERMAL_CONTROL 0x15
41 #define AWCC_METHOD_FWUP_GPIO_CONTROL 0x20
42 #define AWCC_METHOD_READ_TOTAL_GPIOS 0x21
43 #define AWCC_METHOD_READ_GPIO_STATUS 0x22
44 #define AWCC_METHOD_GAME_SHIFT_STATUS 0x25
45
46 #define AWCC_FAILURE_CODE 0xFFFFFFFF
47 #define AWCC_FAILURE_CODE_2 0xFFFFFFFE
48
49 #define AWCC_SENSOR_ID_FLAG BIT(8)
50 #define AWCC_THERMAL_MODE_MASK GENMASK(3, 0)
51 #define AWCC_THERMAL_TABLE_MASK GENMASK(7, 4)
52 #define AWCC_RESOURCE_ID_MASK GENMASK(7, 0)
53
54 /* Arbitrary limit based on supported models */
55 #define AWCC_MAX_RES_COUNT 16
56 #define AWCC_ID_BITMAP_SIZE (U8_MAX + 1)
57 #define AWCC_ID_BITMAP_LONGS BITS_TO_LONGS(AWCC_ID_BITMAP_SIZE)
58
59 static bool force_hwmon;
60 module_param_unsafe(force_hwmon, bool, 0);
61 MODULE_PARM_DESC(force_hwmon, "Force probing for HWMON support without checking if the WMI backend is available");
62
63 static bool force_platform_profile;
64 module_param_unsafe(force_platform_profile, bool, 0);
65 MODULE_PARM_DESC(force_platform_profile, "Forces auto-detecting thermal profiles without checking if WMI thermal backend is available");
66
67 static bool force_gmode;
68 module_param_unsafe(force_gmode, bool, 0);
69 MODULE_PARM_DESC(force_gmode, "Forces G-Mode when performance profile is selected");
70
71 struct awcc_quirks {
72 bool hwmon;
73 bool pprof;
74 bool gmode;
75 };
76
77 static struct awcc_quirks g_series_quirks = {
78 .hwmon = true,
79 .pprof = true,
80 .gmode = true,
81 };
82
83 static struct awcc_quirks generic_quirks = {
84 .hwmon = true,
85 .pprof = true,
86 .gmode = false,
87 };
88
89 static struct awcc_quirks empty_quirks;
90
91 static const struct dmi_system_id awcc_dmi_table[] __initconst = {
92 {
93 .ident = "Alienware Area-51m R2",
94 .matches = {
95 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
96 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware Area-51m R2"),
97 },
98 .driver_data = &generic_quirks,
99 },
100 {
101 .ident = "Alienware m15 R7",
102 .matches = {
103 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
104 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m15 R7"),
105 },
106 .driver_data = &generic_quirks,
107 },
108 {
109 .ident = "Alienware m16 R1",
110 .matches = {
111 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
112 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1"),
113 },
114 .driver_data = &g_series_quirks,
115 },
116 {
117 .ident = "Alienware m16 R1 AMD",
118 .matches = {
119 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
120 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R1 AMD"),
121 },
122 .driver_data = &generic_quirks,
123 },
124 {
125 .ident = "Alienware m16 R2",
126 .matches = {
127 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
128 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m16 R2"),
129 },
130 .driver_data = &generic_quirks,
131 },
132 {
133 .ident = "Alienware m17 R5",
134 .matches = {
135 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
136 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m17 R5 AMD"),
137 },
138 .driver_data = &generic_quirks,
139 },
140 {
141 .ident = "Alienware m18 R2",
142 .matches = {
143 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
144 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware m18 R2"),
145 },
146 .driver_data = &generic_quirks,
147 },
148 {
149 .ident = "Alienware x15 R1",
150 .matches = {
151 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
152 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R1"),
153 },
154 .driver_data = &generic_quirks,
155 },
156 {
157 .ident = "Alienware x15 R2",
158 .matches = {
159 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
160 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x15 R2"),
161 },
162 .driver_data = &generic_quirks,
163 },
164 {
165 .ident = "Alienware x17 R2",
166 .matches = {
167 DMI_MATCH(DMI_SYS_VENDOR, "Alienware"),
168 DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x17 R2"),
169 },
170 .driver_data = &generic_quirks,
171 },
172 {
173 .ident = "Dell Inc. G15 5510",
174 .matches = {
175 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
176 DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5510"),
177 },
178 .driver_data = &g_series_quirks,
179 },
180 {
181 .ident = "Dell Inc. G15 5511",
182 .matches = {
183 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
184 DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5511"),
185 },
186 .driver_data = &g_series_quirks,
187 },
188 {
189 .ident = "Dell Inc. G15 5515",
190 .matches = {
191 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
192 DMI_MATCH(DMI_PRODUCT_NAME, "Dell G15 5515"),
193 },
194 .driver_data = &g_series_quirks,
195 },
196 {
197 .ident = "Dell Inc. G16 7630",
198 .matches = {
199 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
200 DMI_MATCH(DMI_PRODUCT_NAME, "Dell G16 7630"),
201 },
202 .driver_data = &g_series_quirks,
203 },
204 {
205 .ident = "Dell Inc. G3 3500",
206 .matches = {
207 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
208 DMI_MATCH(DMI_PRODUCT_NAME, "G3 3500"),
209 },
210 .driver_data = &g_series_quirks,
211 },
212 {
213 .ident = "Dell Inc. G3 3590",
214 .matches = {
215 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
216 DMI_MATCH(DMI_PRODUCT_NAME, "G3 3590"),
217 },
218 .driver_data = &g_series_quirks,
219 },
220 {
221 .ident = "Dell Inc. G5 5500",
222 .matches = {
223 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
224 DMI_MATCH(DMI_PRODUCT_NAME, "G5 5500"),
225 },
226 .driver_data = &g_series_quirks,
227 },
228 {
229 .ident = "Dell Inc. G5 5505",
230 .matches = {
231 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
232 DMI_MATCH(DMI_PRODUCT_NAME, "G5 5505"),
233 },
234 .driver_data = &g_series_quirks,
235 },
236 };
237
238 enum AWCC_GET_FAN_SENSORS_OPERATIONS {
239 AWCC_OP_GET_TOTAL_FAN_TEMPS = 0x01,
240 AWCC_OP_GET_FAN_TEMP_ID = 0x02,
241 };
242
243 enum AWCC_THERMAL_INFORMATION_OPERATIONS {
244 AWCC_OP_GET_SYSTEM_DESCRIPTION = 0x02,
245 AWCC_OP_GET_RESOURCE_ID = 0x03,
246 AWCC_OP_GET_TEMPERATURE = 0x04,
247 AWCC_OP_GET_FAN_RPM = 0x05,
248 AWCC_OP_GET_FAN_MIN_RPM = 0x08,
249 AWCC_OP_GET_FAN_MAX_RPM = 0x09,
250 AWCC_OP_GET_CURRENT_PROFILE = 0x0B,
251 AWCC_OP_GET_FAN_BOOST = 0x0C,
252 };
253
254 enum AWCC_THERMAL_CONTROL_OPERATIONS {
255 AWCC_OP_ACTIVATE_PROFILE = 0x01,
256 AWCC_OP_SET_FAN_BOOST = 0x02,
257 };
258
259 enum AWCC_GAME_SHIFT_STATUS_OPERATIONS {
260 AWCC_OP_TOGGLE_GAME_SHIFT = 0x01,
261 AWCC_OP_GET_GAME_SHIFT_STATUS = 0x02,
262 };
263
264 enum AWCC_THERMAL_TABLES {
265 AWCC_THERMAL_TABLE_LEGACY = 0x9,
266 AWCC_THERMAL_TABLE_USTT = 0xA,
267 };
268
269 enum AWCC_SPECIAL_THERMAL_CODES {
270 AWCC_SPECIAL_PROFILE_CUSTOM = 0x00,
271 AWCC_SPECIAL_PROFILE_GMODE = 0xAB,
272 };
273
274 enum AWCC_TEMP_SENSOR_TYPES {
275 AWCC_TEMP_SENSOR_CPU = 0x01,
276 AWCC_TEMP_SENSOR_GPU = 0x06,
277 };
278
279 enum awcc_thermal_profile {
280 AWCC_PROFILE_USTT_BALANCED,
281 AWCC_PROFILE_USTT_BALANCED_PERFORMANCE,
282 AWCC_PROFILE_USTT_COOL,
283 AWCC_PROFILE_USTT_QUIET,
284 AWCC_PROFILE_USTT_PERFORMANCE,
285 AWCC_PROFILE_USTT_LOW_POWER,
286 AWCC_PROFILE_LEGACY_QUIET,
287 AWCC_PROFILE_LEGACY_BALANCED,
288 AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE,
289 AWCC_PROFILE_LEGACY_PERFORMANCE,
290 AWCC_PROFILE_LAST,
291 };
292
293 struct wmax_led_args {
294 u32 led_mask;
295 struct color_platform colors;
296 u8 state;
297 } __packed;
298
299 struct wmax_brightness_args {
300 u32 led_mask;
301 u32 percentage;
302 };
303
304 struct wmax_basic_args {
305 u8 arg;
306 };
307
308 struct wmax_u32_args {
309 u8 operation;
310 u8 arg1;
311 u8 arg2;
312 u8 arg3;
313 };
314
315 struct awcc_fan_data {
316 unsigned long auto_channels_temp;
317 const char *label;
318 u32 min_rpm;
319 u32 max_rpm;
320 u8 suspend_cache;
321 u8 id;
322 };
323
324 struct awcc_priv {
325 struct wmi_device *wdev;
326 union {
327 u32 system_description;
328 struct {
329 u8 fan_count;
330 u8 temp_count;
331 u8 unknown_count;
332 u8 profile_count;
333 };
334 u8 res_count[4];
335 };
336
337 struct device *ppdev;
338 u8 supported_profiles[PLATFORM_PROFILE_LAST];
339
340 struct device *hwdev;
341 struct awcc_fan_data **fan_data;
342 unsigned long temp_sensors[AWCC_ID_BITMAP_LONGS];
343
344 u32 gpio_count;
345 };
346
347 static const enum platform_profile_option awcc_mode_to_platform_profile[AWCC_PROFILE_LAST] = {
348 [AWCC_PROFILE_USTT_BALANCED] = PLATFORM_PROFILE_BALANCED,
349 [AWCC_PROFILE_USTT_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE,
350 [AWCC_PROFILE_USTT_COOL] = PLATFORM_PROFILE_COOL,
351 [AWCC_PROFILE_USTT_QUIET] = PLATFORM_PROFILE_QUIET,
352 [AWCC_PROFILE_USTT_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
353 [AWCC_PROFILE_USTT_LOW_POWER] = PLATFORM_PROFILE_LOW_POWER,
354 [AWCC_PROFILE_LEGACY_QUIET] = PLATFORM_PROFILE_QUIET,
355 [AWCC_PROFILE_LEGACY_BALANCED] = PLATFORM_PROFILE_BALANCED,
356 [AWCC_PROFILE_LEGACY_BALANCED_PERFORMANCE] = PLATFORM_PROFILE_BALANCED_PERFORMANCE,
357 [AWCC_PROFILE_LEGACY_PERFORMANCE] = PLATFORM_PROFILE_PERFORMANCE,
358 };
359
360 static struct awcc_quirks *awcc;
361
362 /*
363 * The HDMI mux sysfs node indicates the status of the HDMI input mux.
364 * It can toggle between standard system GPU output and HDMI input.
365 */
cable_show(struct device * dev,struct device_attribute * attr,char * buf)366 static ssize_t cable_show(struct device *dev, struct device_attribute *attr,
367 char *buf)
368 {
369 struct alienfx_platdata *pdata = dev_get_platdata(dev);
370 struct wmax_basic_args in_args = {
371 .arg = 0,
372 };
373 u32 out_data;
374 int ret;
375
376 ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_CABLE,
377 &in_args, sizeof(in_args), &out_data);
378 if (!ret) {
379 if (out_data == 0)
380 return sysfs_emit(buf, "[unconnected] connected unknown\n");
381 else if (out_data == 1)
382 return sysfs_emit(buf, "unconnected [connected] unknown\n");
383 }
384
385 pr_err("alienware-wmi: unknown HDMI cable status: %d\n", ret);
386 return sysfs_emit(buf, "unconnected connected [unknown]\n");
387 }
388
source_show(struct device * dev,struct device_attribute * attr,char * buf)389 static ssize_t source_show(struct device *dev, struct device_attribute *attr,
390 char *buf)
391 {
392 struct alienfx_platdata *pdata = dev_get_platdata(dev);
393 struct wmax_basic_args in_args = {
394 .arg = 0,
395 };
396 u32 out_data;
397 int ret;
398
399 ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_STATUS,
400 &in_args, sizeof(in_args), &out_data);
401 if (!ret) {
402 if (out_data == 1)
403 return sysfs_emit(buf, "[input] gpu unknown\n");
404 else if (out_data == 2)
405 return sysfs_emit(buf, "input [gpu] unknown\n");
406 }
407
408 pr_err("alienware-wmi: unknown HDMI source status: %u\n", ret);
409 return sysfs_emit(buf, "input gpu [unknown]\n");
410 }
411
source_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)412 static ssize_t source_store(struct device *dev, struct device_attribute *attr,
413 const char *buf, size_t count)
414 {
415 struct alienfx_platdata *pdata = dev_get_platdata(dev);
416 struct wmax_basic_args args;
417 int ret;
418
419 if (strcmp(buf, "gpu\n") == 0)
420 args.arg = 1;
421 else if (strcmp(buf, "input\n") == 0)
422 args.arg = 2;
423 else
424 args.arg = 3;
425 pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf);
426
427 ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_HDMI_SOURCE, &args,
428 sizeof(args), NULL);
429 if (ret < 0)
430 pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", ret);
431
432 return count;
433 }
434
435 static DEVICE_ATTR_RO(cable);
436 static DEVICE_ATTR_RW(source);
437
hdmi_group_visible(struct kobject * kobj)438 static bool hdmi_group_visible(struct kobject *kobj)
439 {
440 return alienware_interface == WMAX && alienfx->hdmi_mux;
441 }
442 DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(hdmi);
443
444 static struct attribute *hdmi_attrs[] = {
445 &dev_attr_cable.attr,
446 &dev_attr_source.attr,
447 NULL,
448 };
449
450 const struct attribute_group wmax_hdmi_attribute_group = {
451 .name = "hdmi",
452 .is_visible = SYSFS_GROUP_VISIBLE(hdmi),
453 .attrs = hdmi_attrs,
454 };
455
456 /*
457 * Alienware GFX amplifier support
458 * - Currently supports reading cable status
459 * - Leaving expansion room to possibly support dock/undock events later
460 */
status_show(struct device * dev,struct device_attribute * attr,char * buf)461 static ssize_t status_show(struct device *dev, struct device_attribute *attr,
462 char *buf)
463 {
464 struct alienfx_platdata *pdata = dev_get_platdata(dev);
465 struct wmax_basic_args in_args = {
466 .arg = 0,
467 };
468 u32 out_data;
469 int ret;
470
471 ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_AMPLIFIER_CABLE,
472 &in_args, sizeof(in_args), &out_data);
473 if (!ret) {
474 if (out_data == 0)
475 return sysfs_emit(buf, "[unconnected] connected unknown\n");
476 else if (out_data == 1)
477 return sysfs_emit(buf, "unconnected [connected] unknown\n");
478 }
479
480 pr_err("alienware-wmi: unknown amplifier cable status: %d\n", ret);
481 return sysfs_emit(buf, "unconnected connected [unknown]\n");
482 }
483
484 static DEVICE_ATTR_RO(status);
485
amplifier_group_visible(struct kobject * kobj)486 static bool amplifier_group_visible(struct kobject *kobj)
487 {
488 return alienware_interface == WMAX && alienfx->amplifier;
489 }
490 DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(amplifier);
491
492 static struct attribute *amplifier_attrs[] = {
493 &dev_attr_status.attr,
494 NULL,
495 };
496
497 const struct attribute_group wmax_amplifier_attribute_group = {
498 .name = "amplifier",
499 .is_visible = SYSFS_GROUP_VISIBLE(amplifier),
500 .attrs = amplifier_attrs,
501 };
502
503 /*
504 * Deep Sleep Control support
505 * - Modifies BIOS setting for deep sleep control allowing extra wakeup events
506 */
deepsleep_show(struct device * dev,struct device_attribute * attr,char * buf)507 static ssize_t deepsleep_show(struct device *dev, struct device_attribute *attr,
508 char *buf)
509 {
510 struct alienfx_platdata *pdata = dev_get_platdata(dev);
511 struct wmax_basic_args in_args = {
512 .arg = 0,
513 };
514 u32 out_data;
515 int ret;
516
517 ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_STATUS,
518 &in_args, sizeof(in_args), &out_data);
519 if (!ret) {
520 if (out_data == 0)
521 return sysfs_emit(buf, "[disabled] s5 s5_s4\n");
522 else if (out_data == 1)
523 return sysfs_emit(buf, "disabled [s5] s5_s4\n");
524 else if (out_data == 2)
525 return sysfs_emit(buf, "disabled s5 [s5_s4]\n");
526 }
527
528 pr_err("alienware-wmi: unknown deep sleep status: %d\n", ret);
529 return sysfs_emit(buf, "disabled s5 s5_s4 [unknown]\n");
530 }
531
deepsleep_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)532 static ssize_t deepsleep_store(struct device *dev, struct device_attribute *attr,
533 const char *buf, size_t count)
534 {
535 struct alienfx_platdata *pdata = dev_get_platdata(dev);
536 struct wmax_basic_args args;
537 int ret;
538
539 if (strcmp(buf, "disabled\n") == 0)
540 args.arg = 0;
541 else if (strcmp(buf, "s5\n") == 0)
542 args.arg = 1;
543 else
544 args.arg = 2;
545 pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf);
546
547 ret = alienware_wmi_command(pdata->wdev, WMAX_METHOD_DEEP_SLEEP_CONTROL,
548 &args, sizeof(args), NULL);
549 if (!ret)
550 pr_err("alienware-wmi: deep sleep control failed: results: %u\n", ret);
551
552 return count;
553 }
554
555 static DEVICE_ATTR_RW(deepsleep);
556
deepsleep_group_visible(struct kobject * kobj)557 static bool deepsleep_group_visible(struct kobject *kobj)
558 {
559 return alienware_interface == WMAX && alienfx->deepslp;
560 }
561 DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(deepsleep);
562
563 static struct attribute *deepsleep_attrs[] = {
564 &dev_attr_deepsleep.attr,
565 NULL,
566 };
567
568 const struct attribute_group wmax_deepsleep_attribute_group = {
569 .name = "deepsleep",
570 .is_visible = SYSFS_GROUP_VISIBLE(deepsleep),
571 .attrs = deepsleep_attrs,
572 };
573
574 /*
575 * AWCC Helpers
576 */
is_awcc_thermal_profile_id(u8 code)577 static bool is_awcc_thermal_profile_id(u8 code)
578 {
579 u8 table = FIELD_GET(AWCC_THERMAL_TABLE_MASK, code);
580 u8 mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, code);
581
582 if (mode >= AWCC_PROFILE_LAST)
583 return false;
584
585 if (table == AWCC_THERMAL_TABLE_LEGACY && mode >= AWCC_PROFILE_LEGACY_QUIET)
586 return true;
587
588 if (table == AWCC_THERMAL_TABLE_USTT && mode <= AWCC_PROFILE_USTT_LOW_POWER)
589 return true;
590
591 return false;
592 }
593
awcc_wmi_command(struct wmi_device * wdev,u32 method_id,struct wmax_u32_args * args,u32 * out)594 static int awcc_wmi_command(struct wmi_device *wdev, u32 method_id,
595 struct wmax_u32_args *args, u32 *out)
596 {
597 int ret;
598
599 ret = alienware_wmi_command(wdev, method_id, args, sizeof(*args), out);
600 if (ret)
601 return ret;
602
603 if (*out == AWCC_FAILURE_CODE || *out == AWCC_FAILURE_CODE_2)
604 return -EBADRQC;
605
606 return 0;
607 }
608
awcc_get_fan_sensors(struct wmi_device * wdev,u8 operation,u8 fan_id,u8 index,u32 * out)609 static int awcc_get_fan_sensors(struct wmi_device *wdev, u8 operation,
610 u8 fan_id, u8 index, u32 *out)
611 {
612 struct wmax_u32_args args = {
613 .operation = operation,
614 .arg1 = fan_id,
615 .arg2 = index,
616 .arg3 = 0,
617 };
618
619 return awcc_wmi_command(wdev, AWCC_METHOD_GET_FAN_SENSORS, &args, out);
620 }
621
awcc_thermal_information(struct wmi_device * wdev,u8 operation,u8 arg,u32 * out)622 static int awcc_thermal_information(struct wmi_device *wdev, u8 operation, u8 arg,
623 u32 *out)
624 {
625 struct wmax_u32_args args = {
626 .operation = operation,
627 .arg1 = arg,
628 .arg2 = 0,
629 .arg3 = 0,
630 };
631
632 return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out);
633 }
634
awcc_fwup_gpio_control(struct wmi_device * wdev,u8 pin,u8 status)635 static int awcc_fwup_gpio_control(struct wmi_device *wdev, u8 pin, u8 status)
636 {
637 struct wmax_u32_args args = {
638 .operation = pin,
639 .arg1 = status,
640 .arg2 = 0,
641 .arg3 = 0,
642 };
643 u32 out;
644
645 return awcc_wmi_command(wdev, AWCC_METHOD_FWUP_GPIO_CONTROL, &args, &out);
646 }
647
awcc_read_total_gpios(struct wmi_device * wdev,u32 * count)648 static int awcc_read_total_gpios(struct wmi_device *wdev, u32 *count)
649 {
650 struct wmax_u32_args args = {};
651
652 return awcc_wmi_command(wdev, AWCC_METHOD_READ_TOTAL_GPIOS, &args, count);
653 }
654
awcc_read_gpio_status(struct wmi_device * wdev,u8 pin,u32 * status)655 static int awcc_read_gpio_status(struct wmi_device *wdev, u8 pin, u32 *status)
656 {
657 struct wmax_u32_args args = {
658 .operation = pin,
659 .arg1 = 0,
660 .arg2 = 0,
661 .arg3 = 0,
662 };
663
664 return awcc_wmi_command(wdev, AWCC_METHOD_READ_GPIO_STATUS, &args, status);
665 }
666
awcc_game_shift_status(struct wmi_device * wdev,u8 operation,u32 * out)667 static int awcc_game_shift_status(struct wmi_device *wdev, u8 operation,
668 u32 *out)
669 {
670 struct wmax_u32_args args = {
671 .operation = operation,
672 .arg1 = 0,
673 .arg2 = 0,
674 .arg3 = 0,
675 };
676
677 return awcc_wmi_command(wdev, AWCC_METHOD_GAME_SHIFT_STATUS, &args, out);
678 }
679
680 /**
681 * awcc_op_get_resource_id - Get the resource ID at a given index
682 * @wdev: AWCC WMI device
683 * @index: Index
684 * @out: Value returned by the WMI call
685 *
686 * Get the resource ID at a given @index. Resource IDs are listed in the
687 * following order:
688 *
689 * - Fan IDs
690 * - Sensor IDs
691 * - Unknown IDs
692 * - Thermal Profile IDs
693 *
694 * The total number of IDs of a given type can be obtained with
695 * AWCC_OP_GET_SYSTEM_DESCRIPTION.
696 *
697 * Return: 0 on success, -errno on failure
698 */
awcc_op_get_resource_id(struct wmi_device * wdev,u8 index,u8 * out)699 static int awcc_op_get_resource_id(struct wmi_device *wdev, u8 index, u8 *out)
700 {
701 struct wmax_u32_args args = {
702 .operation = AWCC_OP_GET_RESOURCE_ID,
703 .arg1 = index,
704 .arg2 = 0,
705 .arg3 = 0,
706 };
707 u32 out_data;
708 int ret;
709
710 ret = awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, &out_data);
711 if (ret)
712 return ret;
713
714 *out = FIELD_GET(AWCC_RESOURCE_ID_MASK, out_data);
715
716 return 0;
717 }
718
awcc_op_get_fan_rpm(struct wmi_device * wdev,u8 fan_id,u32 * out)719 static int awcc_op_get_fan_rpm(struct wmi_device *wdev, u8 fan_id, u32 *out)
720 {
721 struct wmax_u32_args args = {
722 .operation = AWCC_OP_GET_FAN_RPM,
723 .arg1 = fan_id,
724 .arg2 = 0,
725 .arg3 = 0,
726 };
727
728 return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out);
729 }
730
awcc_op_get_temperature(struct wmi_device * wdev,u8 temp_id,u32 * out)731 static int awcc_op_get_temperature(struct wmi_device *wdev, u8 temp_id, u32 *out)
732 {
733 struct wmax_u32_args args = {
734 .operation = AWCC_OP_GET_TEMPERATURE,
735 .arg1 = temp_id,
736 .arg2 = 0,
737 .arg3 = 0,
738 };
739
740 return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out);
741 }
742
awcc_op_get_fan_boost(struct wmi_device * wdev,u8 fan_id,u32 * out)743 static int awcc_op_get_fan_boost(struct wmi_device *wdev, u8 fan_id, u32 *out)
744 {
745 struct wmax_u32_args args = {
746 .operation = AWCC_OP_GET_FAN_BOOST,
747 .arg1 = fan_id,
748 .arg2 = 0,
749 .arg3 = 0,
750 };
751
752 return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out);
753 }
754
awcc_op_get_current_profile(struct wmi_device * wdev,u32 * out)755 static int awcc_op_get_current_profile(struct wmi_device *wdev, u32 *out)
756 {
757 struct wmax_u32_args args = {
758 .operation = AWCC_OP_GET_CURRENT_PROFILE,
759 .arg1 = 0,
760 .arg2 = 0,
761 .arg3 = 0,
762 };
763
764 return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_INFORMATION, &args, out);
765 }
766
awcc_op_activate_profile(struct wmi_device * wdev,u8 profile)767 static int awcc_op_activate_profile(struct wmi_device *wdev, u8 profile)
768 {
769 struct wmax_u32_args args = {
770 .operation = AWCC_OP_ACTIVATE_PROFILE,
771 .arg1 = profile,
772 .arg2 = 0,
773 .arg3 = 0,
774 };
775 u32 out;
776
777 return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_CONTROL, &args, &out);
778 }
779
awcc_op_set_fan_boost(struct wmi_device * wdev,u8 fan_id,u8 boost)780 static int awcc_op_set_fan_boost(struct wmi_device *wdev, u8 fan_id, u8 boost)
781 {
782 struct wmax_u32_args args = {
783 .operation = AWCC_OP_SET_FAN_BOOST,
784 .arg1 = fan_id,
785 .arg2 = boost,
786 .arg3 = 0,
787 };
788 u32 out;
789
790 return awcc_wmi_command(wdev, AWCC_METHOD_THERMAL_CONTROL, &args, &out);
791 }
792
793 /*
794 * HWMON
795 * - Provides temperature and fan speed monitoring as well as manual fan
796 * control
797 */
awcc_hwmon_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)798 static umode_t awcc_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
799 u32 attr, int channel)
800 {
801 const struct awcc_priv *priv = drvdata;
802 unsigned int temp_count;
803
804 switch (type) {
805 case hwmon_temp:
806 temp_count = bitmap_weight(priv->temp_sensors, AWCC_ID_BITMAP_SIZE);
807
808 return channel < temp_count ? 0444 : 0;
809 case hwmon_fan:
810 return channel < priv->fan_count ? 0444 : 0;
811 case hwmon_pwm:
812 return channel < priv->fan_count ? 0444 : 0;
813 default:
814 return 0;
815 }
816 }
817
awcc_hwmon_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)818 static int awcc_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
819 u32 attr, int channel, long *val)
820 {
821 struct awcc_priv *priv = dev_get_drvdata(dev);
822 const struct awcc_fan_data *fan;
823 u32 state;
824 int ret;
825 u8 temp;
826
827 switch (type) {
828 case hwmon_temp:
829 temp = find_nth_bit(priv->temp_sensors, AWCC_ID_BITMAP_SIZE, channel);
830
831 switch (attr) {
832 case hwmon_temp_input:
833 ret = awcc_op_get_temperature(priv->wdev, temp, &state);
834 if (ret)
835 return ret;
836
837 *val = state * MILLIDEGREE_PER_DEGREE;
838 break;
839 default:
840 return -EOPNOTSUPP;
841 }
842
843 break;
844 case hwmon_fan:
845 fan = priv->fan_data[channel];
846
847 switch (attr) {
848 case hwmon_fan_input:
849 ret = awcc_op_get_fan_rpm(priv->wdev, fan->id, &state);
850 if (ret)
851 return ret;
852
853 *val = state;
854 break;
855 case hwmon_fan_min:
856 *val = fan->min_rpm;
857 break;
858 case hwmon_fan_max:
859 *val = fan->max_rpm;
860 break;
861 default:
862 return -EOPNOTSUPP;
863 }
864
865 break;
866 case hwmon_pwm:
867 fan = priv->fan_data[channel];
868
869 switch (attr) {
870 case hwmon_pwm_auto_channels_temp:
871 *val = fan->auto_channels_temp;
872 break;
873 default:
874 return -EOPNOTSUPP;
875 }
876
877 break;
878 default:
879 return -EOPNOTSUPP;
880 }
881
882 return 0;
883 }
884
awcc_hwmon_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)885 static int awcc_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
886 u32 attr, int channel, const char **str)
887 {
888 struct awcc_priv *priv = dev_get_drvdata(dev);
889 u8 temp;
890
891 switch (type) {
892 case hwmon_temp:
893 temp = find_nth_bit(priv->temp_sensors, AWCC_ID_BITMAP_SIZE, channel);
894
895 switch (temp) {
896 case AWCC_TEMP_SENSOR_CPU:
897 *str = "CPU";
898 break;
899 case AWCC_TEMP_SENSOR_GPU:
900 *str = "GPU";
901 break;
902 default:
903 *str = "Unknown";
904 break;
905 }
906
907 break;
908 case hwmon_fan:
909 *str = priv->fan_data[channel]->label;
910 break;
911 default:
912 return -EOPNOTSUPP;
913 }
914
915 return 0;
916 }
917
918 static const struct hwmon_ops awcc_hwmon_ops = {
919 .is_visible = awcc_hwmon_is_visible,
920 .read = awcc_hwmon_read,
921 .read_string = awcc_hwmon_read_string,
922 };
923
924 static const struct hwmon_channel_info * const awcc_hwmon_info[] = {
925 HWMON_CHANNEL_INFO(temp,
926 HWMON_T_LABEL | HWMON_T_INPUT,
927 HWMON_T_LABEL | HWMON_T_INPUT,
928 HWMON_T_LABEL | HWMON_T_INPUT,
929 HWMON_T_LABEL | HWMON_T_INPUT,
930 HWMON_T_LABEL | HWMON_T_INPUT,
931 HWMON_T_LABEL | HWMON_T_INPUT
932 ),
933 HWMON_CHANNEL_INFO(fan,
934 HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX,
935 HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX,
936 HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX,
937 HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX,
938 HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX,
939 HWMON_F_LABEL | HWMON_F_INPUT | HWMON_F_MIN | HWMON_F_MAX
940 ),
941 HWMON_CHANNEL_INFO(pwm,
942 HWMON_PWM_AUTO_CHANNELS_TEMP,
943 HWMON_PWM_AUTO_CHANNELS_TEMP,
944 HWMON_PWM_AUTO_CHANNELS_TEMP,
945 HWMON_PWM_AUTO_CHANNELS_TEMP,
946 HWMON_PWM_AUTO_CHANNELS_TEMP,
947 HWMON_PWM_AUTO_CHANNELS_TEMP
948 ),
949 NULL
950 };
951
952 static const struct hwmon_chip_info awcc_hwmon_chip_info = {
953 .ops = &awcc_hwmon_ops,
954 .info = awcc_hwmon_info,
955 };
956
fan_boost_show(struct device * dev,struct device_attribute * attr,char * buf)957 static ssize_t fan_boost_show(struct device *dev, struct device_attribute *attr,
958 char *buf)
959 {
960 struct awcc_priv *priv = dev_get_drvdata(dev);
961 int index = to_sensor_dev_attr(attr)->index;
962 struct awcc_fan_data *fan = priv->fan_data[index];
963 u32 boost;
964 int ret;
965
966 ret = awcc_op_get_fan_boost(priv->wdev, fan->id, &boost);
967 if (ret)
968 return ret;
969
970 return sysfs_emit(buf, "%u\n", boost);
971 }
972
fan_boost_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)973 static ssize_t fan_boost_store(struct device *dev, struct device_attribute *attr,
974 const char *buf, size_t count)
975 {
976 struct awcc_priv *priv = dev_get_drvdata(dev);
977 int index = to_sensor_dev_attr(attr)->index;
978 struct awcc_fan_data *fan = priv->fan_data[index];
979 unsigned long val;
980 int ret;
981
982 ret = kstrtoul(buf, 0, &val);
983 if (ret)
984 return ret;
985
986 ret = awcc_op_set_fan_boost(priv->wdev, fan->id, clamp_val(val, 0, 255));
987
988 return ret ? ret : count;
989 }
990
991 static SENSOR_DEVICE_ATTR_RW(fan1_boost, fan_boost, 0);
992 static SENSOR_DEVICE_ATTR_RW(fan2_boost, fan_boost, 1);
993 static SENSOR_DEVICE_ATTR_RW(fan3_boost, fan_boost, 2);
994 static SENSOR_DEVICE_ATTR_RW(fan4_boost, fan_boost, 3);
995 static SENSOR_DEVICE_ATTR_RW(fan5_boost, fan_boost, 4);
996 static SENSOR_DEVICE_ATTR_RW(fan6_boost, fan_boost, 5);
997
fan_boost_attr_visible(struct kobject * kobj,struct attribute * attr,int n)998 static umode_t fan_boost_attr_visible(struct kobject *kobj, struct attribute *attr, int n)
999 {
1000 struct awcc_priv *priv = dev_get_drvdata(kobj_to_dev(kobj));
1001
1002 return n < priv->fan_count ? attr->mode : 0;
1003 }
1004
fan_boost_group_visible(struct kobject * kobj)1005 static bool fan_boost_group_visible(struct kobject *kobj)
1006 {
1007 return true;
1008 }
1009
1010 DEFINE_SYSFS_GROUP_VISIBLE(fan_boost);
1011
1012 static struct attribute *fan_boost_attrs[] = {
1013 &sensor_dev_attr_fan1_boost.dev_attr.attr,
1014 &sensor_dev_attr_fan2_boost.dev_attr.attr,
1015 &sensor_dev_attr_fan3_boost.dev_attr.attr,
1016 &sensor_dev_attr_fan4_boost.dev_attr.attr,
1017 &sensor_dev_attr_fan5_boost.dev_attr.attr,
1018 &sensor_dev_attr_fan6_boost.dev_attr.attr,
1019 NULL
1020 };
1021
1022 static const struct attribute_group fan_boost_group = {
1023 .attrs = fan_boost_attrs,
1024 .is_visible = SYSFS_GROUP_VISIBLE(fan_boost),
1025 };
1026
1027 static const struct attribute_group *awcc_hwmon_groups[] = {
1028 &fan_boost_group,
1029 NULL
1030 };
1031
awcc_hwmon_temps_init(struct wmi_device * wdev)1032 static int awcc_hwmon_temps_init(struct wmi_device *wdev)
1033 {
1034 struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
1035 unsigned int i;
1036 int ret;
1037 u8 id;
1038
1039 for (i = 0; i < priv->temp_count; i++) {
1040 /*
1041 * Temperature sensors IDs are listed after the fan IDs at
1042 * offset `fan_count`
1043 */
1044 ret = awcc_op_get_resource_id(wdev, i + priv->fan_count, &id);
1045 if (ret)
1046 return ret;
1047
1048 __set_bit(id, priv->temp_sensors);
1049 }
1050
1051 return 0;
1052 }
1053
awcc_get_fan_label(unsigned long * fan_temps)1054 static char *awcc_get_fan_label(unsigned long *fan_temps)
1055 {
1056 unsigned int temp_count = bitmap_weight(fan_temps, AWCC_ID_BITMAP_SIZE);
1057 char *label;
1058 u8 temp_id;
1059
1060 switch (temp_count) {
1061 case 0:
1062 label = "Independent Fan";
1063 break;
1064 case 1:
1065 temp_id = find_first_bit(fan_temps, AWCC_ID_BITMAP_SIZE);
1066
1067 switch (temp_id) {
1068 case AWCC_TEMP_SENSOR_CPU:
1069 label = "Processor Fan";
1070 break;
1071 case AWCC_TEMP_SENSOR_GPU:
1072 label = "Video Fan";
1073 break;
1074 default:
1075 label = "Unknown Fan";
1076 break;
1077 }
1078
1079 break;
1080 default:
1081 label = "Shared Fan";
1082 break;
1083 }
1084
1085 return label;
1086 }
1087
awcc_hwmon_fans_init(struct wmi_device * wdev)1088 static int awcc_hwmon_fans_init(struct wmi_device *wdev)
1089 {
1090 struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
1091 unsigned long fan_temps[AWCC_ID_BITMAP_LONGS];
1092 unsigned long gather[AWCC_ID_BITMAP_LONGS];
1093 u32 min_rpm, max_rpm, temp_count, temp_id;
1094 struct awcc_fan_data *fan_data;
1095 unsigned int i, j;
1096 int ret;
1097 u8 id;
1098
1099 for (i = 0; i < priv->fan_count; i++) {
1100 fan_data = devm_kzalloc(&wdev->dev, sizeof(*fan_data), GFP_KERNEL);
1101 if (!fan_data)
1102 return -ENOMEM;
1103
1104 /*
1105 * Fan IDs are listed first at offset 0
1106 */
1107 ret = awcc_op_get_resource_id(wdev, i, &id);
1108 if (ret)
1109 return ret;
1110
1111 ret = awcc_thermal_information(wdev, AWCC_OP_GET_FAN_MIN_RPM, id,
1112 &min_rpm);
1113 if (ret)
1114 return ret;
1115
1116 ret = awcc_thermal_information(wdev, AWCC_OP_GET_FAN_MAX_RPM, id,
1117 &max_rpm);
1118 if (ret)
1119 return ret;
1120
1121 ret = awcc_get_fan_sensors(wdev, AWCC_OP_GET_TOTAL_FAN_TEMPS, id,
1122 0, &temp_count);
1123 if (ret)
1124 return ret;
1125
1126 bitmap_zero(fan_temps, AWCC_ID_BITMAP_SIZE);
1127
1128 for (j = 0; j < temp_count; j++) {
1129 ret = awcc_get_fan_sensors(wdev, AWCC_OP_GET_FAN_TEMP_ID,
1130 id, j, &temp_id);
1131 if (ret)
1132 break;
1133
1134 temp_id = FIELD_GET(AWCC_RESOURCE_ID_MASK, temp_id);
1135 __set_bit(temp_id, fan_temps);
1136 }
1137
1138 fan_data->id = id;
1139 fan_data->min_rpm = min_rpm;
1140 fan_data->max_rpm = max_rpm;
1141 fan_data->label = awcc_get_fan_label(fan_temps);
1142 bitmap_gather(gather, fan_temps, priv->temp_sensors, AWCC_ID_BITMAP_SIZE);
1143 bitmap_copy(&fan_data->auto_channels_temp, gather, BITS_PER_LONG);
1144 priv->fan_data[i] = fan_data;
1145 }
1146
1147 return 0;
1148 }
1149
awcc_hwmon_init(struct wmi_device * wdev)1150 static int awcc_hwmon_init(struct wmi_device *wdev)
1151 {
1152 struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
1153 int ret;
1154
1155 priv->fan_data = devm_kcalloc(&wdev->dev, priv->fan_count,
1156 sizeof(*priv->fan_data), GFP_KERNEL);
1157 if (!priv->fan_data)
1158 return -ENOMEM;
1159
1160 ret = awcc_hwmon_temps_init(wdev);
1161 if (ret)
1162 return ret;
1163
1164 ret = awcc_hwmon_fans_init(wdev);
1165 if (ret)
1166 return ret;
1167
1168 priv->hwdev = devm_hwmon_device_register_with_info(&wdev->dev, "alienware_wmi",
1169 priv, &awcc_hwmon_chip_info,
1170 awcc_hwmon_groups);
1171
1172 return PTR_ERR_OR_ZERO(priv->hwdev);
1173 }
1174
awcc_hwmon_suspend(struct device * dev)1175 static void awcc_hwmon_suspend(struct device *dev)
1176 {
1177 struct awcc_priv *priv = dev_get_drvdata(dev);
1178 struct awcc_fan_data *fan;
1179 unsigned int i;
1180 u32 boost;
1181 int ret;
1182
1183 for (i = 0; i < priv->fan_count; i++) {
1184 fan = priv->fan_data[i];
1185
1186 ret = awcc_thermal_information(priv->wdev, AWCC_OP_GET_FAN_BOOST,
1187 fan->id, &boost);
1188 if (ret)
1189 dev_err(dev, "Failed to store Fan %u boost while suspending\n", i);
1190
1191 fan->suspend_cache = ret ? 0 : clamp_val(boost, 0, 255);
1192
1193 awcc_op_set_fan_boost(priv->wdev, fan->id, 0);
1194 if (ret)
1195 dev_err(dev, "Failed to set Fan %u boost to 0 while suspending\n", i);
1196 }
1197 }
1198
awcc_hwmon_resume(struct device * dev)1199 static void awcc_hwmon_resume(struct device *dev)
1200 {
1201 struct awcc_priv *priv = dev_get_drvdata(dev);
1202 struct awcc_fan_data *fan;
1203 unsigned int i;
1204 int ret;
1205
1206 for (i = 0; i < priv->fan_count; i++) {
1207 fan = priv->fan_data[i];
1208
1209 if (!fan->suspend_cache)
1210 continue;
1211
1212 ret = awcc_op_set_fan_boost(priv->wdev, fan->id, fan->suspend_cache);
1213 if (ret)
1214 dev_err(dev, "Failed to restore Fan %u boost while resuming\n", i);
1215 }
1216 }
1217
1218 /*
1219 * Thermal Profile control
1220 * - Provides thermal profile control through the Platform Profile API
1221 */
awcc_platform_profile_get(struct device * dev,enum platform_profile_option * profile)1222 static int awcc_platform_profile_get(struct device *dev,
1223 enum platform_profile_option *profile)
1224 {
1225 struct awcc_priv *priv = dev_get_drvdata(dev);
1226 u32 out_data;
1227 int ret;
1228
1229 ret = awcc_op_get_current_profile(priv->wdev, &out_data);
1230 if (ret)
1231 return ret;
1232
1233 switch (out_data) {
1234 case AWCC_SPECIAL_PROFILE_CUSTOM:
1235 *profile = PLATFORM_PROFILE_CUSTOM;
1236 return 0;
1237 case AWCC_SPECIAL_PROFILE_GMODE:
1238 *profile = PLATFORM_PROFILE_PERFORMANCE;
1239 return 0;
1240 default:
1241 break;
1242 }
1243
1244 if (!is_awcc_thermal_profile_id(out_data))
1245 return -ENODATA;
1246
1247 out_data = FIELD_GET(AWCC_THERMAL_MODE_MASK, out_data);
1248 *profile = awcc_mode_to_platform_profile[out_data];
1249
1250 return 0;
1251 }
1252
awcc_platform_profile_set(struct device * dev,enum platform_profile_option profile)1253 static int awcc_platform_profile_set(struct device *dev,
1254 enum platform_profile_option profile)
1255 {
1256 struct awcc_priv *priv = dev_get_drvdata(dev);
1257
1258 if (awcc->gmode) {
1259 u32 gmode_status;
1260 int ret;
1261
1262 ret = awcc_game_shift_status(priv->wdev,
1263 AWCC_OP_GET_GAME_SHIFT_STATUS,
1264 &gmode_status);
1265
1266 if (ret < 0)
1267 return ret;
1268
1269 if ((profile == PLATFORM_PROFILE_PERFORMANCE && !gmode_status) ||
1270 (profile != PLATFORM_PROFILE_PERFORMANCE && gmode_status)) {
1271 ret = awcc_game_shift_status(priv->wdev,
1272 AWCC_OP_TOGGLE_GAME_SHIFT,
1273 &gmode_status);
1274
1275 if (ret < 0)
1276 return ret;
1277 }
1278 }
1279
1280 return awcc_op_activate_profile(priv->wdev, priv->supported_profiles[profile]);
1281 }
1282
awcc_platform_profile_probe(void * drvdata,unsigned long * choices)1283 static int awcc_platform_profile_probe(void *drvdata, unsigned long *choices)
1284 {
1285 enum platform_profile_option profile;
1286 struct awcc_priv *priv = drvdata;
1287 enum awcc_thermal_profile mode;
1288 u8 id, offset = 0;
1289 int ret;
1290
1291 /*
1292 * Thermal profile IDs are listed last at offset
1293 * fan_count + temp_count + unknown_count
1294 */
1295 for (unsigned int i = 0; i < ARRAY_SIZE(priv->res_count) - 1; i++)
1296 offset += priv->res_count[i];
1297
1298 for (unsigned int i = 0; i < priv->profile_count; i++) {
1299 ret = awcc_op_get_resource_id(priv->wdev, i + offset, &id);
1300 /*
1301 * Some devices report an incorrect number of thermal profiles
1302 * so the resource ID list may end prematurely
1303 */
1304 if (ret == -EBADRQC)
1305 break;
1306 if (ret)
1307 return ret;
1308
1309 if (!is_awcc_thermal_profile_id(id)) {
1310 dev_dbg(&priv->wdev->dev, "Unmapped thermal profile ID 0x%02x\n", id);
1311 continue;
1312 }
1313
1314 mode = FIELD_GET(AWCC_THERMAL_MODE_MASK, id);
1315 profile = awcc_mode_to_platform_profile[mode];
1316 priv->supported_profiles[profile] = id;
1317
1318 __set_bit(profile, choices);
1319 }
1320
1321 if (bitmap_empty(choices, PLATFORM_PROFILE_LAST))
1322 return -ENODEV;
1323
1324 if (awcc->gmode) {
1325 priv->supported_profiles[PLATFORM_PROFILE_PERFORMANCE] =
1326 AWCC_SPECIAL_PROFILE_GMODE;
1327
1328 __set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
1329 }
1330
1331 /* Every model supports the "custom" profile */
1332 priv->supported_profiles[PLATFORM_PROFILE_CUSTOM] =
1333 AWCC_SPECIAL_PROFILE_CUSTOM;
1334
1335 __set_bit(PLATFORM_PROFILE_CUSTOM, choices);
1336
1337 return 0;
1338 }
1339
1340 static const struct platform_profile_ops awcc_platform_profile_ops = {
1341 .probe = awcc_platform_profile_probe,
1342 .profile_get = awcc_platform_profile_get,
1343 .profile_set = awcc_platform_profile_set,
1344 };
1345
awcc_platform_profile_init(struct wmi_device * wdev)1346 static int awcc_platform_profile_init(struct wmi_device *wdev)
1347 {
1348 struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
1349
1350 priv->ppdev = devm_platform_profile_register(&wdev->dev, "alienware-wmi",
1351 priv, &awcc_platform_profile_ops);
1352
1353 return PTR_ERR_OR_ZERO(priv->ppdev);
1354 }
1355
1356 /*
1357 * DebugFS
1358 */
awcc_debugfs_system_description_read(struct seq_file * seq,void * data)1359 static int awcc_debugfs_system_description_read(struct seq_file *seq, void *data)
1360 {
1361 struct device *dev = seq->private;
1362 struct awcc_priv *priv = dev_get_drvdata(dev);
1363
1364 seq_printf(seq, "0x%08x\n", priv->system_description);
1365
1366 return 0;
1367 }
1368
awcc_debugfs_hwmon_data_read(struct seq_file * seq,void * data)1369 static int awcc_debugfs_hwmon_data_read(struct seq_file *seq, void *data)
1370 {
1371 struct device *dev = seq->private;
1372 struct awcc_priv *priv = dev_get_drvdata(dev);
1373 const struct awcc_fan_data *fan;
1374 unsigned int bit;
1375
1376 seq_printf(seq, "Number of fans: %u\n", priv->fan_count);
1377 seq_printf(seq, "Number of temperature sensors: %u\n\n", priv->temp_count);
1378
1379 for (u32 i = 0; i < priv->fan_count; i++) {
1380 fan = priv->fan_data[i];
1381
1382 seq_printf(seq, "Fan %u:\n", i);
1383 seq_printf(seq, " ID: 0x%02x\n", fan->id);
1384 seq_printf(seq, " Related temperature sensors bitmap: %lu\n",
1385 fan->auto_channels_temp);
1386 }
1387
1388 seq_puts(seq, "\nTemperature sensor IDs:\n");
1389 for_each_set_bit(bit, priv->temp_sensors, AWCC_ID_BITMAP_SIZE)
1390 seq_printf(seq, " 0x%02x\n", bit);
1391
1392 return 0;
1393 }
1394
awcc_debugfs_pprof_data_read(struct seq_file * seq,void * data)1395 static int awcc_debugfs_pprof_data_read(struct seq_file *seq, void *data)
1396 {
1397 struct device *dev = seq->private;
1398 struct awcc_priv *priv = dev_get_drvdata(dev);
1399
1400 seq_printf(seq, "Number of thermal profiles: %u\n\n", priv->profile_count);
1401
1402 for (u32 i = 0; i < PLATFORM_PROFILE_LAST; i++) {
1403 if (!priv->supported_profiles[i])
1404 continue;
1405
1406 seq_printf(seq, "Platform profile %u:\n", i);
1407 seq_printf(seq, " ID: 0x%02x\n", priv->supported_profiles[i]);
1408 }
1409
1410 return 0;
1411 }
1412
awcc_gpio_pin_show(struct seq_file * seq,void * data)1413 static int awcc_gpio_pin_show(struct seq_file *seq, void *data)
1414 {
1415 unsigned long pin = debugfs_get_aux_num(seq->file);
1416 struct wmi_device *wdev = seq->private;
1417 u32 status;
1418 int ret;
1419
1420 ret = awcc_read_gpio_status(wdev, pin, &status);
1421 if (ret)
1422 return ret;
1423
1424 seq_printf(seq, "%u\n", status);
1425
1426 return 0;
1427 }
1428
awcc_gpio_pin_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)1429 static ssize_t awcc_gpio_pin_write(struct file *file, const char __user *buf,
1430 size_t count, loff_t *ppos)
1431 {
1432 unsigned long pin = debugfs_get_aux_num(file);
1433 struct seq_file *seq = file->private_data;
1434 struct wmi_device *wdev = seq->private;
1435 bool status;
1436 int ret;
1437
1438 if (!ppos || *ppos)
1439 return -EINVAL;
1440
1441 ret = kstrtobool_from_user(buf, count, &status);
1442 if (ret)
1443 return ret;
1444
1445 ret = awcc_fwup_gpio_control(wdev, pin, status);
1446 if (ret)
1447 return ret;
1448
1449 return count;
1450 }
1451
1452 DEFINE_SHOW_STORE_ATTRIBUTE(awcc_gpio_pin);
1453
awcc_debugfs_remove(void * data)1454 static void awcc_debugfs_remove(void *data)
1455 {
1456 struct dentry *root = data;
1457
1458 debugfs_remove(root);
1459 }
1460
awcc_debugfs_init(struct wmi_device * wdev)1461 static void awcc_debugfs_init(struct wmi_device *wdev)
1462 {
1463 struct awcc_priv *priv = dev_get_drvdata(&wdev->dev);
1464 struct dentry *root, *gpio_ctl;
1465 u32 gpio_count;
1466 char name[64];
1467 int ret;
1468
1469 scnprintf(name, sizeof(name), "%s-%s", "alienware-wmi", dev_name(&wdev->dev));
1470 root = debugfs_create_dir(name, NULL);
1471
1472 debugfs_create_devm_seqfile(&wdev->dev, "system_description", root,
1473 awcc_debugfs_system_description_read);
1474
1475 if (awcc->hwmon)
1476 debugfs_create_devm_seqfile(&wdev->dev, "hwmon_data", root,
1477 awcc_debugfs_hwmon_data_read);
1478
1479 if (awcc->pprof)
1480 debugfs_create_devm_seqfile(&wdev->dev, "pprof_data", root,
1481 awcc_debugfs_pprof_data_read);
1482
1483 ret = awcc_read_total_gpios(wdev, &gpio_count);
1484 if (ret) {
1485 dev_dbg(&wdev->dev, "Failed to get total GPIO Pin count\n");
1486 goto out_add_action;
1487 } else if (gpio_count > AWCC_MAX_RES_COUNT) {
1488 dev_dbg(&wdev->dev, "Reported GPIO Pin count may be incorrect: %u\n", gpio_count);
1489 goto out_add_action;
1490 }
1491
1492 gpio_ctl = debugfs_create_dir("gpio_ctl", root);
1493
1494 priv->gpio_count = gpio_count;
1495 debugfs_create_u32("total_gpios", 0444, gpio_ctl, &priv->gpio_count);
1496
1497 for (unsigned int i = 0; i < gpio_count; i++) {
1498 scnprintf(name, sizeof(name), "pin%u", i);
1499 debugfs_create_file_aux_num(name, 0644, gpio_ctl, wdev, i,
1500 &awcc_gpio_pin_fops);
1501 }
1502
1503 out_add_action:
1504 devm_add_action_or_reset(&wdev->dev, awcc_debugfs_remove, root);
1505 }
1506
alienware_awcc_setup(struct wmi_device * wdev)1507 static int alienware_awcc_setup(struct wmi_device *wdev)
1508 {
1509 struct awcc_priv *priv;
1510 int ret;
1511
1512 priv = devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL);
1513 if (!priv)
1514 return -ENOMEM;
1515
1516 ret = awcc_thermal_information(wdev, AWCC_OP_GET_SYSTEM_DESCRIPTION,
1517 0, &priv->system_description);
1518 if (ret < 0)
1519 return ret;
1520
1521 /* Sanity check */
1522 for (unsigned int i = 0; i < ARRAY_SIZE(priv->res_count); i++) {
1523 if (priv->res_count[i] > AWCC_MAX_RES_COUNT) {
1524 dev_err(&wdev->dev, "Malformed system description: 0x%08x\n",
1525 priv->system_description);
1526 return -ENXIO;
1527 }
1528 }
1529
1530 priv->wdev = wdev;
1531 dev_set_drvdata(&wdev->dev, priv);
1532
1533 if (awcc->hwmon) {
1534 ret = awcc_hwmon_init(wdev);
1535 if (ret)
1536 return ret;
1537 }
1538
1539 if (awcc->pprof) {
1540 ret = awcc_platform_profile_init(wdev);
1541 if (ret)
1542 return ret;
1543 }
1544
1545 awcc_debugfs_init(wdev);
1546
1547 return 0;
1548 }
1549
1550 /*
1551 * WMAX WMI driver
1552 */
wmax_wmi_update_led(struct alienfx_priv * priv,struct wmi_device * wdev,u8 location)1553 static int wmax_wmi_update_led(struct alienfx_priv *priv,
1554 struct wmi_device *wdev, u8 location)
1555 {
1556 struct wmax_led_args in_args = {
1557 .led_mask = 1 << location,
1558 .colors = priv->colors[location],
1559 .state = priv->lighting_control_state,
1560 };
1561
1562 return alienware_wmi_command(wdev, WMAX_METHOD_ZONE_CONTROL, &in_args,
1563 sizeof(in_args), NULL);
1564 }
1565
wmax_wmi_update_brightness(struct alienfx_priv * priv,struct wmi_device * wdev,u8 brightness)1566 static int wmax_wmi_update_brightness(struct alienfx_priv *priv,
1567 struct wmi_device *wdev, u8 brightness)
1568 {
1569 struct wmax_brightness_args in_args = {
1570 .led_mask = 0xFF,
1571 .percentage = brightness,
1572 };
1573
1574 return alienware_wmi_command(wdev, WMAX_METHOD_BRIGHTNESS, &in_args,
1575 sizeof(in_args), NULL);
1576 }
1577
wmax_wmi_probe(struct wmi_device * wdev,const void * context)1578 static int wmax_wmi_probe(struct wmi_device *wdev, const void *context)
1579 {
1580 struct alienfx_platdata pdata = {
1581 .wdev = wdev,
1582 .ops = {
1583 .upd_led = wmax_wmi_update_led,
1584 .upd_brightness = wmax_wmi_update_brightness,
1585 },
1586 };
1587 int ret;
1588
1589 if (awcc)
1590 ret = alienware_awcc_setup(wdev);
1591 else
1592 ret = alienware_alienfx_setup(&pdata);
1593
1594 return ret;
1595 }
1596
wmax_wmi_suspend(struct device * dev)1597 static int wmax_wmi_suspend(struct device *dev)
1598 {
1599 if (awcc->hwmon)
1600 awcc_hwmon_suspend(dev);
1601
1602 return 0;
1603 }
1604
wmax_wmi_resume(struct device * dev)1605 static int wmax_wmi_resume(struct device *dev)
1606 {
1607 if (awcc->hwmon)
1608 awcc_hwmon_resume(dev);
1609
1610 return 0;
1611 }
1612
1613 static DEFINE_SIMPLE_DEV_PM_OPS(wmax_wmi_pm_ops, wmax_wmi_suspend, wmax_wmi_resume);
1614
1615 static const struct wmi_device_id alienware_wmax_device_id_table[] = {
1616 { WMAX_CONTROL_GUID, NULL },
1617 { },
1618 };
1619 MODULE_DEVICE_TABLE(wmi, alienware_wmax_device_id_table);
1620
1621 static struct wmi_driver alienware_wmax_wmi_driver = {
1622 .driver = {
1623 .name = "alienware-wmi-wmax",
1624 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
1625 .pm = pm_sleep_ptr(&wmax_wmi_pm_ops),
1626 },
1627 .id_table = alienware_wmax_device_id_table,
1628 .probe = wmax_wmi_probe,
1629 .no_singleton = true,
1630 };
1631
alienware_wmax_wmi_init(void)1632 int __init alienware_wmax_wmi_init(void)
1633 {
1634 const struct dmi_system_id *id;
1635
1636 id = dmi_first_match(awcc_dmi_table);
1637 if (id)
1638 awcc = id->driver_data;
1639
1640 if (force_hwmon) {
1641 if (!awcc)
1642 awcc = &empty_quirks;
1643
1644 awcc->hwmon = true;
1645 }
1646
1647 if (force_platform_profile) {
1648 if (!awcc)
1649 awcc = &empty_quirks;
1650
1651 awcc->pprof = true;
1652 }
1653
1654 if (force_gmode) {
1655 if (awcc)
1656 awcc->gmode = true;
1657 else
1658 pr_warn("force_gmode requires platform profile support\n");
1659 }
1660
1661 return wmi_driver_register(&alienware_wmax_wmi_driver);
1662 }
1663
alienware_wmax_wmi_exit(void)1664 void __exit alienware_wmax_wmi_exit(void)
1665 {
1666 wmi_driver_unregister(&alienware_wmax_wmi_driver);
1667 }
1668