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