xref: /linux/drivers/platform/x86/bitland-mifs-wmi.c (revision da6b5aae84beb0917ecb0c9fbc71169d145397ff)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Linux driver for Bitland notebooks.
4  *
5  * Copyright (C) 2026 2 Mingyou Chen <qby140326@gmail.com>
6  */
7 
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 
10 #include <linux/acpi.h>
11 #include <linux/array_size.h>
12 #include <linux/bits.h>
13 #include <linux/container_of.h>
14 #include <linux/dev_printk.h>
15 #include <linux/device.h>
16 #include <linux/device/devres.h>
17 #include <linux/err.h>
18 #include <linux/hwmon.h>
19 #include <linux/init.h>
20 #include <linux/input-event-codes.h>
21 #include <linux/input.h>
22 #include <linux/input/sparse-keymap.h>
23 #include <linux/kernel.h>
24 #include <linux/leds.h>
25 #include <linux/module.h>
26 #include <linux/notifier.h>
27 #include <linux/platform_profile.h>
28 #include <linux/pm.h>
29 #include <linux/power_supply.h>
30 #include <linux/stddef.h>
31 #include <linux/string.h>
32 #include <linux/sysfs.h>
33 #include <linux/unaligned.h>
34 #include <linux/units.h>
35 #include <linux/wmi.h>
36 
37 #define DRV_NAME		"bitland-mifs-wmi"
38 #define BITLAND_MIFS_GUID	"B60BFB48-3E5B-49E4-A0E9-8CFFE1B3434B"
39 #define BITLAND_EVENT_GUID	"46C93E13-EE9B-4262-8488-563BCA757FEF"
40 
41 enum bitland_mifs_operation {
42 	WMI_METHOD_GET	= 250,
43 	WMI_METHOD_SET	= 251,
44 };
45 
46 enum bitland_mifs_function {
47 	WMI_FN_SYSTEM_PER_MODE		= 8,
48 	WMI_FN_GPU_MODE			= 9,
49 	WMI_FN_KBD_TYPE			= 10,
50 	WMI_FN_FN_LOCK			= 11,
51 	WMI_FN_TP_LOCK			= 12,
52 	WMI_FN_FAN_SPEEDS		= 13,
53 	WMI_FN_RGB_KB_MODE		= 16,
54 	WMI_FN_RGB_KB_COLOR		= 17,
55 	WMI_FN_RGB_KB_BRIGHTNESS	= 18,
56 	WMI_FN_SYSTEM_AC_TYPE		= 19,
57 	WMI_FN_MAX_FAN_SWITCH		= 20,
58 	WMI_FN_MAX_FAN_SPEED		= 21,
59 	WMI_FN_CPU_THERMOMETER		= 22,
60 	WMI_FN_CPU_POWER		= 23,
61 };
62 
63 enum bitland_system_ac_mode {
64 	WMI_SYSTEM_AC_TYPEC		= 1,
65 	/* Unknown type, this is unused in the original driver */
66 	WMI_SYSTEM_AC_CIRCULARHOLE	= 2,
67 };
68 
69 enum bitland_mifs_power_profile {
70 	WMI_PP_BALANCED		= 0,
71 	WMI_PP_PERFORMANCE	= 1,
72 	WMI_PP_QUIET		= 2,
73 	WMI_PP_FULL_SPEED	= 3,
74 };
75 
76 enum bitland_mifs_event_id {
77 	WMI_EVENT_RESERVED_1		= 1,
78 	WMI_EVENT_RESERVED_2		= 2,
79 	WMI_EVENT_RESERVED_3		= 3,
80 	WMI_EVENT_AIRPLANE_MODE		= 4,
81 	WMI_EVENT_KBD_BRIGHTNESS	= 5,
82 	WMI_EVENT_TOUCHPAD_STATE	= 6,
83 	WMI_EVENT_FNLOCK_STATE		= 7,
84 	WMI_EVENT_KBD_MODE		= 8,
85 	WMI_EVENT_CAPSLOCK_STATE	= 9,
86 	WMI_EVENT_CALCULATOR_START	= 11,
87 	WMI_EVENT_BROWSER_START		= 12,
88 	WMI_EVENT_NUMLOCK_STATE		= 13,
89 	WMI_EVENT_SCROLLLOCK_STATE	= 14,
90 	WMI_EVENT_PERFORMANCE_PLAN	= 15,
91 	WMI_EVENT_FN_J			= 16,
92 	WMI_EVENT_FN_F			= 17,
93 	WMI_EVENT_FN_0			= 18,
94 	WMI_EVENT_FN_1			= 19,
95 	WMI_EVENT_FN_2			= 20,
96 	WMI_EVENT_FN_3			= 21,
97 	WMI_EVENT_FN_4			= 22,
98 	WMI_EVENT_FN_5			= 24,
99 	WMI_EVENT_REFRESH_RATE		= 25,
100 	WMI_EVENT_CPU_FAN_SPEED		= 26,
101 	WMI_EVENT_GPU_FAN_SPEED		= 32,
102 	WMI_EVENT_WIN_KEY_LOCK		= 33,
103 	WMI_EVENT_RESERVED_23		= 34,
104 	WMI_EVENT_OPEN_APP		= 35,
105 };
106 
107 enum bitland_mifs_event_type {
108 	WMI_EVENT_TYPE_HOTKEY	= 1,
109 };
110 
111 enum bitland_wmi_device_type {
112 	BITLAND_WMI_CONTROL	= 0,
113 	BITLAND_WMI_EVENT	= 1,
114 };
115 
116 struct bitland_mifs_input {
117 	u8 reserved1;
118 	u8 operation;
119 	u8 reserved2;
120 	u8 function;
121 	u8 payload[28];
122 } __packed;
123 
124 struct bitland_mifs_output {
125 	u8 reserved1;
126 	u8 operation;
127 	u8 reserved2;
128 	u8 function;
129 	u8 data[28];
130 } __packed;
131 
132 struct bitland_mifs_event {
133 	u8 event_type;
134 	u8 event_id;
135 	u8 value_low;	/* For most events, this is the value */
136 	u8 value_high;	/* For fan speed events, combined with value_low */
137 	u8 reserved[4];
138 } __packed;
139 
140 static BLOCKING_NOTIFIER_HEAD(bitland_notifier_list);
141 
142 enum bitland_notifier_actions {
143 	BITLAND_NOTIFY_KBD_BRIGHTNESS,
144 	BITLAND_NOTIFY_PLATFORM_PROFILE,
145 	BITLAND_NOTIFY_HWMON,
146 };
147 
148 struct bitland_fan_notify_data {
149 	int channel; /* 0 = CPU, 1 = GPU */
150 	u16 speed;
151 };
152 
153 struct bitland_mifs_wmi_data {
154 	struct wmi_device *wdev;
155 	struct mutex lock;		/* Protects WMI calls */
156 	struct led_classdev kbd_led;
157 	struct notifier_block notifier;
158 	struct input_dev *input_dev;
159 	struct device *hwmon_dev;
160 	struct device *pp_dev;
161 	enum platform_profile_option saved_profile;
162 };
163 
164 static int bitland_mifs_wmi_call(struct bitland_mifs_wmi_data *data,
165 				 const struct bitland_mifs_input *input,
166 				 struct bitland_mifs_output *output)
167 {
168 	struct wmi_buffer in_buf = { .length = sizeof(*input), .data = (void *)input };
169 	struct wmi_buffer out_buf = { 0 };
170 	int ret;
171 
172 	guard(mutex)(&data->lock);
173 
174 	if (!output)
175 		return wmidev_invoke_procedure(data->wdev, 0, 1, &in_buf);
176 
177 	ret = wmidev_invoke_method(data->wdev, 0, 1, &in_buf, &out_buf, sizeof(*output));
178 	if (ret)
179 		return ret;
180 
181 	memcpy(output, out_buf.data, sizeof(*output));
182 	kfree(out_buf.data);
183 
184 	return 0;
185 }
186 
187 static int laptop_profile_get(struct device *dev,
188 			      enum platform_profile_option *profile)
189 {
190 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
191 	struct bitland_mifs_input input = {
192 		.reserved1 = 0,
193 		.operation = WMI_METHOD_GET,
194 		.reserved2 = 0,
195 		.function = WMI_FN_SYSTEM_PER_MODE,
196 	};
197 	struct bitland_mifs_output result;
198 	int ret;
199 
200 	ret = bitland_mifs_wmi_call(data, &input, &result);
201 	if (ret)
202 		return ret;
203 
204 	switch (result.data[0]) {
205 	case WMI_PP_BALANCED:
206 		*profile = PLATFORM_PROFILE_BALANCED;
207 		break;
208 	case WMI_PP_PERFORMANCE:
209 		*profile = PLATFORM_PROFILE_BALANCED_PERFORMANCE;
210 		break;
211 	case WMI_PP_QUIET:
212 		*profile = PLATFORM_PROFILE_LOW_POWER;
213 		break;
214 	case WMI_PP_FULL_SPEED:
215 		*profile = PLATFORM_PROFILE_PERFORMANCE;
216 		break;
217 	default:
218 		return -EINVAL;
219 	}
220 	return 0;
221 }
222 
223 static int bitland_check_performance_capability(struct bitland_mifs_wmi_data *data)
224 {
225 	struct bitland_mifs_input input = {
226 		.operation = WMI_METHOD_GET,
227 		.function = WMI_FN_SYSTEM_AC_TYPE,
228 	};
229 	struct bitland_mifs_output output;
230 	int ret;
231 
232 	/* Full-speed/performance mode requires DC power (not USB-C) */
233 	if (!power_supply_is_system_supplied())
234 		return -EOPNOTSUPP;
235 
236 	ret = bitland_mifs_wmi_call(data, &input, &output);
237 	if (ret)
238 		return ret;
239 
240 	if (output.data[0] != WMI_SYSTEM_AC_CIRCULARHOLE)
241 		return -EOPNOTSUPP;
242 
243 	return 0;
244 }
245 
246 static int laptop_profile_set(struct device *dev,
247 			      enum platform_profile_option profile)
248 {
249 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
250 	struct bitland_mifs_input input = {
251 		.reserved1 = 0,
252 		.operation = WMI_METHOD_SET,
253 		.reserved2 = 0,
254 		.function = WMI_FN_SYSTEM_PER_MODE,
255 	};
256 	int ret;
257 	u8 val;
258 
259 	switch (profile) {
260 	case PLATFORM_PROFILE_LOW_POWER:
261 		val = WMI_PP_QUIET;
262 		break;
263 	case PLATFORM_PROFILE_BALANCED:
264 		val = WMI_PP_BALANCED;
265 		break;
266 	case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
267 		ret = bitland_check_performance_capability(data);
268 		if (ret)
269 			return ret;
270 		val = WMI_PP_PERFORMANCE;
271 		break;
272 	case PLATFORM_PROFILE_PERFORMANCE:
273 		ret = bitland_check_performance_capability(data);
274 		if (ret)
275 			return ret;
276 		val = WMI_PP_FULL_SPEED;
277 		break;
278 	default:
279 		return -EOPNOTSUPP;
280 	}
281 
282 	input.payload[0] = val;
283 
284 	return bitland_mifs_wmi_call(data, &input, NULL);
285 }
286 
287 static int platform_profile_probe(void *drvdata, unsigned long *choices)
288 {
289 	set_bit(PLATFORM_PROFILE_LOW_POWER, choices);
290 	set_bit(PLATFORM_PROFILE_BALANCED, choices);
291 	set_bit(PLATFORM_PROFILE_BALANCED_PERFORMANCE, choices);
292 	set_bit(PLATFORM_PROFILE_PERFORMANCE, choices);
293 
294 	return 0;
295 }
296 
297 static int bitland_mifs_wmi_suspend(struct device *dev)
298 {
299 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
300 	enum platform_profile_option profile;
301 	int ret;
302 
303 	ret = laptop_profile_get(data->pp_dev, &profile);
304 	if (ret == 0)
305 		data->saved_profile = profile;
306 
307 	return ret;
308 }
309 
310 static int bitland_mifs_wmi_resume(struct device *dev)
311 {
312 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
313 
314 	dev_dbg(dev, "Resuming, restoring profile %d\n", data->saved_profile);
315 	return laptop_profile_set(dev, data->saved_profile);
316 }
317 
318 static DEFINE_SIMPLE_DEV_PM_OPS(bitland_mifs_wmi_pm_ops,
319 				bitland_mifs_wmi_suspend,
320 				bitland_mifs_wmi_resume);
321 
322 static const struct platform_profile_ops laptop_profile_ops = {
323 	.probe = platform_profile_probe,
324 	.profile_get = laptop_profile_get,
325 	.profile_set = laptop_profile_set,
326 };
327 
328 static const char *const fan_labels[] = {
329 	"CPU", /* 0 */
330 	"GPU", /* 1 */
331 	"SYS", /* 2 */
332 };
333 
334 static int laptop_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
335 			     u32 attr, int channel, long *val)
336 {
337 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
338 	struct bitland_mifs_input input = {
339 		.reserved1 = 0,
340 		.operation = WMI_METHOD_GET,
341 		.reserved2 = 0,
342 	};
343 	struct bitland_mifs_output res;
344 	int ret;
345 
346 	switch (type) {
347 	case hwmon_temp:
348 		input.function = WMI_FN_CPU_THERMOMETER;
349 		ret = bitland_mifs_wmi_call(data, &input, &res);
350 		if (!ret)
351 			*val = res.data[0] * MILLIDEGREE_PER_DEGREE;
352 		return ret;
353 	case hwmon_fan:
354 		input.function = WMI_FN_FAN_SPEEDS;
355 		ret = bitland_mifs_wmi_call(data, &input, &res);
356 		if (ret)
357 			return ret;
358 
359 		switch (channel) {
360 		case 0: /* CPU */
361 			*val = get_unaligned_le16(&res.data[0]);
362 			return 0;
363 		case 1: /* GPU */
364 			*val = get_unaligned_le16(&res.data[2]);
365 			return 0;
366 		case 2: /* SYS */
367 			*val = get_unaligned_le16(&res.data[6]);
368 			return 0;
369 		default:
370 			return -EINVAL;
371 		}
372 	default:
373 		return -EINVAL;
374 	}
375 }
376 
377 static int laptop_hwmon_read_string(struct device *dev,
378 				    enum hwmon_sensor_types type, u32 attr,
379 				    int channel, const char **str)
380 {
381 	if (type == hwmon_fan && attr == hwmon_fan_label) {
382 		if (channel >= 0 && channel < ARRAY_SIZE(fan_labels)) {
383 			*str = fan_labels[channel];
384 			return 0;
385 		}
386 	}
387 	return -EINVAL;
388 }
389 
390 static const struct hwmon_channel_info *laptop_hwmon_info[] = {
391 	HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
392 	HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_LABEL,
393 				HWMON_F_INPUT | HWMON_F_LABEL,
394 				HWMON_F_INPUT | HWMON_F_LABEL),
395 	NULL
396 };
397 
398 static const struct hwmon_ops laptop_hwmon_ops = {
399 	.visible = 0444,
400 	.read = laptop_hwmon_read,
401 	.read_string = laptop_hwmon_read_string,
402 };
403 
404 static const struct hwmon_chip_info laptop_chip_info = {
405 	.ops = &laptop_hwmon_ops,
406 	.info = laptop_hwmon_info,
407 };
408 
409 static int laptop_kbd_led_set(struct led_classdev *led_cdev,
410 			      enum led_brightness value)
411 {
412 	struct bitland_mifs_wmi_data *data =
413 		container_of(led_cdev, struct bitland_mifs_wmi_data, kbd_led);
414 	struct bitland_mifs_input input = {
415 		.reserved1 = 0,
416 		.operation = WMI_METHOD_SET,
417 		.reserved2 = 0,
418 		.function = WMI_FN_RGB_KB_BRIGHTNESS,
419 	};
420 
421 	input.payload[0] = (u8)value;
422 
423 	return bitland_mifs_wmi_call(data, &input, NULL);
424 }
425 
426 static enum led_brightness laptop_kbd_led_get(struct led_classdev *led_cdev)
427 {
428 	struct bitland_mifs_wmi_data *data =
429 		container_of(led_cdev, struct bitland_mifs_wmi_data, kbd_led);
430 	struct bitland_mifs_input input = {
431 		.reserved1 = 0,
432 		.operation = WMI_METHOD_GET,
433 		.reserved2 = 0,
434 		.function = WMI_FN_RGB_KB_BRIGHTNESS,
435 	};
436 	struct bitland_mifs_output res;
437 	int ret;
438 
439 	ret = bitland_mifs_wmi_call(data, &input, &res);
440 	if (ret)
441 		return ret;
442 
443 	return res.data[0];
444 }
445 
446 static const char *const gpu_mode_strings[] = {
447 	"hybrid",
448 	"discrete",
449 	"uma",
450 };
451 
452 /* GPU Mode: 0:Hybrid, 1:Discrete, 2:UMA */
453 static ssize_t gpu_mode_show(struct device *dev, struct device_attribute *attr,
454 			     char *buf)
455 {
456 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
457 	struct bitland_mifs_input input = {
458 		.reserved1 = 0,
459 		.operation = WMI_METHOD_GET,
460 		.reserved2 = 0,
461 		.function = WMI_FN_GPU_MODE,
462 	};
463 	struct bitland_mifs_output res;
464 	u8 mode_val;
465 	int ret;
466 
467 	ret = bitland_mifs_wmi_call(data, &input, &res);
468 	if (ret)
469 		return ret;
470 
471 	mode_val = res.data[0];
472 	if (mode_val >= ARRAY_SIZE(gpu_mode_strings))
473 		return -EPROTO;
474 
475 	return sysfs_emit(buf, "%s\n", gpu_mode_strings[mode_val]);
476 }
477 
478 static ssize_t gpu_mode_store(struct device *dev, struct device_attribute *attr,
479 			      const char *buf, size_t count)
480 {
481 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
482 	struct bitland_mifs_input input = {
483 		.reserved1 = 0,
484 		.operation = WMI_METHOD_SET,
485 		.reserved2 = 0,
486 		.function = WMI_FN_GPU_MODE,
487 	};
488 	int val;
489 	int ret;
490 
491 	val = sysfs_match_string(gpu_mode_strings, buf);
492 	if (val < 0)
493 		return -EINVAL;
494 
495 	input.payload[0] = (u8)val;
496 
497 	ret = bitland_mifs_wmi_call(data, &input, NULL);
498 	if (ret)
499 		return ret;
500 
501 	return count;
502 }
503 
504 static const char *const kb_mode_strings[] = {
505 	"off",		/* 0 */
506 	"cyclic",	/* 1 */
507 	"fixed",	/* 2 */
508 	"custom",	/* 3 */
509 };
510 
511 static ssize_t kb_mode_show(struct device *dev, struct device_attribute *attr,
512 			    char *buf)
513 {
514 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
515 	struct bitland_mifs_input input = {
516 		.reserved1 = 0,
517 		.operation = WMI_METHOD_GET,
518 		.reserved2 = 0,
519 		.function = WMI_FN_RGB_KB_MODE,
520 	};
521 	struct bitland_mifs_output res;
522 	u8 mode_val;
523 	int ret;
524 
525 	ret = bitland_mifs_wmi_call(data, &input, &res);
526 	if (ret)
527 		return ret;
528 
529 	mode_val = res.data[0];
530 	if (mode_val >= ARRAY_SIZE(kb_mode_strings))
531 		return -EPROTO;
532 
533 	return sysfs_emit(buf, "%s\n", kb_mode_strings[mode_val]);
534 }
535 
536 static ssize_t kb_mode_store(struct device *dev, struct device_attribute *attr,
537 			     const char *buf, size_t count)
538 {
539 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
540 	struct bitland_mifs_input input = {
541 		.reserved1 = 0,
542 		.operation = WMI_METHOD_SET,
543 		.reserved2 = 0,
544 		.function = WMI_FN_RGB_KB_MODE,
545 	};
546 	// the wmi value (0, 1, 2 or 3)
547 	int val;
548 	int ret;
549 
550 	val = sysfs_match_string(kb_mode_strings, buf);
551 	if (val < 0)
552 		return -EINVAL;
553 
554 	input.payload[0] = (u8)val;
555 
556 	ret = bitland_mifs_wmi_call(data, &input, NULL);
557 	if (ret)
558 		return ret;
559 
560 	return count;
561 }
562 
563 /* Fan Boost: 0:Normal, 1:Max Speed */
564 static ssize_t fan_boost_store(struct device *dev,
565 			       struct device_attribute *attr, const char *buf,
566 			       size_t count)
567 {
568 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(dev);
569 	struct bitland_mifs_input input = {
570 		.reserved1 = 0,
571 		.operation = WMI_METHOD_SET,
572 		.reserved2 = 0,
573 		.function = WMI_FN_MAX_FAN_SWITCH,
574 	};
575 	bool val;
576 	int ret;
577 
578 	if (kstrtobool(buf, &val))
579 		return -EINVAL;
580 
581 	input.payload[0] = 0;	/* CPU/GPU Fan */
582 	input.payload[1] = val;
583 
584 	ret = bitland_mifs_wmi_call(data, &input, NULL);
585 	if (ret)
586 		return ret;
587 
588 	return count;
589 }
590 
591 static const DEVICE_ATTR_RW(gpu_mode);
592 static const DEVICE_ATTR_RW(kb_mode);
593 static const DEVICE_ATTR_WO(fan_boost);
594 
595 static const struct attribute *const laptop_attrs[] = {
596 	&dev_attr_gpu_mode.attr,
597 	&dev_attr_kb_mode.attr,
598 	&dev_attr_fan_boost.attr,
599 	NULL,
600 };
601 ATTRIBUTE_GROUPS(laptop);
602 
603 static const struct key_entry bitland_mifs_wmi_keymap[] = {
604 	{ KE_KEY, WMI_EVENT_OPEN_APP, { KEY_PROG1 } },
605 	{ KE_KEY, WMI_EVENT_CALCULATOR_START, { KEY_CALC } },
606 	{ KE_KEY, WMI_EVENT_BROWSER_START, { KEY_WWW } },
607 	{ KE_IGNORE, WMI_EVENT_FN_J, { KEY_RESERVED } },
608 	{ KE_IGNORE, WMI_EVENT_FN_F, { KEY_RESERVED } },
609 	{ KE_IGNORE, WMI_EVENT_FN_0, { KEY_RESERVED } },
610 	{ KE_IGNORE, WMI_EVENT_FN_1, { KEY_RESERVED } },
611 	{ KE_IGNORE, WMI_EVENT_FN_2, { KEY_RESERVED } },
612 	{ KE_IGNORE, WMI_EVENT_FN_3, { KEY_RESERVED } },
613 	{ KE_IGNORE, WMI_EVENT_FN_4, { KEY_RESERVED } },
614 	{ KE_IGNORE, WMI_EVENT_FN_5, { KEY_RESERVED } },
615 	{ KE_END, 0 }
616 };
617 
618 static void bitland_notifier_unregister(void *data)
619 {
620 	struct notifier_block *nb = data;
621 
622 	blocking_notifier_chain_unregister(&bitland_notifier_list, nb);
623 }
624 
625 static int bitland_notifier_callback(struct notifier_block *nb,
626 				     unsigned long action, void *data)
627 {
628 	struct bitland_mifs_wmi_data *data_ctx =
629 		container_of(nb, struct bitland_mifs_wmi_data, notifier);
630 	struct bitland_fan_notify_data *fan_info;
631 	u8 *brightness;
632 
633 	switch (action) {
634 	case BITLAND_NOTIFY_KBD_BRIGHTNESS:
635 		brightness = data;
636 		led_classdev_notify_brightness_hw_changed(&data_ctx->kbd_led,
637 							  *brightness);
638 		break;
639 	case BITLAND_NOTIFY_PLATFORM_PROFILE:
640 		platform_profile_notify(data_ctx->pp_dev);
641 		break;
642 	case BITLAND_NOTIFY_HWMON:
643 		fan_info = data;
644 
645 		hwmon_notify_event(data_ctx->hwmon_dev, hwmon_fan,
646 				   hwmon_fan_input, fan_info->channel);
647 		break;
648 	}
649 
650 	return NOTIFY_OK;
651 }
652 
653 static int bitland_mifs_wmi_probe(struct wmi_device *wdev, const void *context)
654 {
655 	struct bitland_mifs_wmi_data *drv_data;
656 	enum bitland_wmi_device_type dev_type =
657 		(enum bitland_wmi_device_type)(unsigned long)context;
658 	struct led_init_data init_data = {
659 		.devicename = DRV_NAME,
660 		.default_label = ":" LED_FUNCTION_KBD_BACKLIGHT,
661 		.devname_mandatory = true,
662 	};
663 	int ret;
664 
665 	drv_data = devm_kzalloc(&wdev->dev, sizeof(*drv_data), GFP_KERNEL);
666 	if (!drv_data)
667 		return -ENOMEM;
668 
669 	drv_data->wdev = wdev;
670 
671 	ret = devm_mutex_init(&wdev->dev, &drv_data->lock);
672 	if (ret)
673 		return ret;
674 
675 	dev_set_drvdata(&wdev->dev, drv_data);
676 
677 	if (dev_type == BITLAND_WMI_EVENT) {
678 		/* Register input device for hotkeys */
679 		drv_data->input_dev = devm_input_allocate_device(&wdev->dev);
680 		if (!drv_data->input_dev)
681 			return -ENOMEM;
682 
683 		drv_data->input_dev->name = "Bitland MIFS WMI hotkeys";
684 		drv_data->input_dev->phys = "wmi/input0";
685 		drv_data->input_dev->id.bustype = BUS_HOST;
686 		drv_data->input_dev->dev.parent = &wdev->dev;
687 
688 		ret = sparse_keymap_setup(drv_data->input_dev,
689 					  bitland_mifs_wmi_keymap, NULL);
690 		if (ret)
691 			return ret;
692 
693 		return input_register_device(drv_data->input_dev);
694 	}
695 
696 	/* Register platform profile */
697 	drv_data->pp_dev = devm_platform_profile_register(&wdev->dev, DRV_NAME, drv_data,
698 							  &laptop_profile_ops);
699 	if (IS_ERR(drv_data->pp_dev))
700 		return PTR_ERR(drv_data->pp_dev);
701 
702 	/* Register hwmon */
703 	drv_data->hwmon_dev = devm_hwmon_device_register_with_info(&wdev->dev,
704 								   "bitland_mifs",
705 								   drv_data,
706 								   &laptop_chip_info,
707 								   NULL);
708 	if (IS_ERR(drv_data->hwmon_dev))
709 		return PTR_ERR(drv_data->hwmon_dev);
710 
711 	/* Register keyboard LED */
712 	drv_data->kbd_led.max_brightness = 3;
713 	drv_data->kbd_led.brightness_set_blocking = laptop_kbd_led_set;
714 	drv_data->kbd_led.brightness_get = laptop_kbd_led_get;
715 	drv_data->kbd_led.brightness = laptop_kbd_led_get(&drv_data->kbd_led);
716 	drv_data->kbd_led.flags = LED_CORE_SUSPENDRESUME |
717 				  LED_BRIGHT_HW_CHANGED |
718 				  LED_REJECT_NAME_CONFLICT;
719 	ret = devm_led_classdev_register_ext(&wdev->dev, &drv_data->kbd_led, &init_data);
720 	if (ret)
721 		return ret;
722 
723 	drv_data->notifier.notifier_call = bitland_notifier_callback;
724 	ret = blocking_notifier_chain_register(&bitland_notifier_list, &drv_data->notifier);
725 	if (ret)
726 		return ret;
727 
728 	return devm_add_action_or_reset(&wdev->dev,
729 				       bitland_notifier_unregister,
730 				       &drv_data->notifier);
731 }
732 
733 static void bitland_mifs_wmi_notify(struct wmi_device *wdev,
734 				    const struct wmi_buffer *buffer)
735 {
736 	struct bitland_mifs_wmi_data *data = dev_get_drvdata(&wdev->dev);
737 	const struct bitland_mifs_event *event = buffer->data;
738 	struct bitland_fan_notify_data fan_data;
739 	u8 brightness;
740 
741 	/* Validate event type */
742 	if (event->event_type != WMI_EVENT_TYPE_HOTKEY)
743 		return;
744 
745 	dev_dbg(&wdev->dev,
746 		"WMI event: id=0x%02x value_low=0x%02x value_high=0x%02x\n",
747 		event->event_id, event->value_low, event->value_high);
748 
749 	switch (event->event_id) {
750 	case WMI_EVENT_KBD_BRIGHTNESS:
751 		brightness = event->value_low;
752 		blocking_notifier_call_chain(&bitland_notifier_list,
753 					     BITLAND_NOTIFY_KBD_BRIGHTNESS,
754 					     &brightness);
755 		break;
756 
757 	case WMI_EVENT_PERFORMANCE_PLAN:
758 		blocking_notifier_call_chain(&bitland_notifier_list,
759 					     BITLAND_NOTIFY_PLATFORM_PROFILE,
760 					     NULL);
761 		break;
762 
763 	case WMI_EVENT_OPEN_APP:
764 	case WMI_EVENT_CALCULATOR_START:
765 	case WMI_EVENT_BROWSER_START: {
766 		guard(mutex)(&data->lock);
767 		if (!sparse_keymap_report_event(data->input_dev,
768 						event->event_id, 1, true))
769 			dev_warn(&wdev->dev, "Unknown key pressed: 0x%02x\n",
770 				 event->event_id);
771 		break;
772 	}
773 
774 	/*
775 	 * The device has 3 fans (CPU, GPU, SYS),
776 	 * but there are only the CPU and GPU fan has events
777 	 */
778 	case WMI_EVENT_CPU_FAN_SPEED:
779 	case WMI_EVENT_GPU_FAN_SPEED:
780 		if (event->event_id == WMI_EVENT_CPU_FAN_SPEED)
781 			fan_data.channel = 0;
782 		else
783 			fan_data.channel = 1;
784 
785 		/* Fan speed is 16-bit value (value_low is LSB, value_high is MSB) */
786 		fan_data.speed = (event->value_high << 8) | event->value_low;
787 		blocking_notifier_call_chain(&bitland_notifier_list,
788 					     BITLAND_NOTIFY_HWMON,
789 					     &fan_data);
790 		break;
791 
792 	case WMI_EVENT_AIRPLANE_MODE:
793 	case WMI_EVENT_TOUCHPAD_STATE:
794 	case WMI_EVENT_FNLOCK_STATE:
795 	case WMI_EVENT_KBD_MODE:
796 	case WMI_EVENT_CAPSLOCK_STATE:
797 	case WMI_EVENT_NUMLOCK_STATE:
798 	case WMI_EVENT_SCROLLLOCK_STATE:
799 	case WMI_EVENT_REFRESH_RATE:
800 	case WMI_EVENT_WIN_KEY_LOCK:
801 		/* These events are informational or handled by firmware */
802 		dev_dbg(&wdev->dev, "State change event: id=%d value=%d\n",
803 			event->event_id, event->value_low);
804 		break;
805 
806 	default:
807 		dev_dbg(&wdev->dev, "Unknown event: id=0x%02x value=0x%02x\n",
808 			event->event_id, event->value_low);
809 		break;
810 	}
811 }
812 
813 static const struct wmi_device_id bitland_mifs_wmi_id_table[] = {
814 	{ BITLAND_MIFS_GUID, (void *)BITLAND_WMI_CONTROL },
815 	{ BITLAND_EVENT_GUID, (void *)BITLAND_WMI_EVENT },
816 	{}
817 };
818 MODULE_DEVICE_TABLE(wmi, bitland_mifs_wmi_id_table);
819 
820 static struct wmi_driver bitland_mifs_wmi_driver = {
821 	.no_singleton = true,
822 	.driver = {
823 		.name = DRV_NAME,
824 		.dev_groups = laptop_groups,
825 		.pm = pm_sleep_ptr(&bitland_mifs_wmi_pm_ops),
826 	},
827 	.id_table = bitland_mifs_wmi_id_table,
828 	.min_event_size = sizeof(struct bitland_mifs_event),
829 	.probe = bitland_mifs_wmi_probe,
830 	.notify_new = bitland_mifs_wmi_notify,
831 };
832 
833 module_wmi_driver(bitland_mifs_wmi_driver);
834 
835 MODULE_AUTHOR("Mingyou Chen <qby140326@gmail.com>");
836 MODULE_DESCRIPTION("Bitland MIFS (MiInterface) WMI driver");
837 MODULE_LICENSE("GPL");
838