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