xref: /linux/drivers/platform/x86/ideapad-laptop.c (revision 170aafe35cb98e0f3fbacb446ea86389fbce22ea)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  ideapad-laptop.c - Lenovo IdeaPad ACPI Extras
4  *
5  *  Copyright © 2010 Intel Corporation
6  *  Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
7  */
8 
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 
11 #include <linux/acpi.h>
12 #include <linux/backlight.h>
13 #include <linux/bitfield.h>
14 #include <linux/bitops.h>
15 #include <linux/bug.h>
16 #include <linux/cleanup.h>
17 #include <linux/debugfs.h>
18 #include <linux/device.h>
19 #include <linux/dmi.h>
20 #include <linux/fb.h>
21 #include <linux/i8042.h>
22 #include <linux/init.h>
23 #include <linux/input.h>
24 #include <linux/input/sparse-keymap.h>
25 #include <linux/kernel.h>
26 #include <linux/leds.h>
27 #include <linux/module.h>
28 #include <linux/platform_device.h>
29 #include <linux/platform_profile.h>
30 #include <linux/rfkill.h>
31 #include <linux/seq_file.h>
32 #include <linux/sysfs.h>
33 #include <linux/types.h>
34 #include <linux/wmi.h>
35 #include "ideapad-laptop.h"
36 
37 #include <acpi/video.h>
38 
39 #include <dt-bindings/leds/common.h>
40 
41 #define IDEAPAD_RFKILL_DEV_NUM	3
42 
43 enum {
44 	CFG_CAP_BT_BIT       = 16,
45 	CFG_CAP_3G_BIT       = 17,
46 	CFG_CAP_WIFI_BIT     = 18,
47 	CFG_CAP_CAM_BIT      = 19,
48 
49 	/*
50 	 * These are OnScreenDisplay support bits that can be useful to determine
51 	 * whether a hotkey exists/should show OSD. But they aren't particularly
52 	 * meaningful since they were introduced later, i.e. 2010 IdeaPads
53 	 * don't have these, but they still have had OSD for hotkeys.
54 	 */
55 	CFG_OSD_NUMLK_BIT    = 27,
56 	CFG_OSD_CAPSLK_BIT   = 28,
57 	CFG_OSD_MICMUTE_BIT  = 29,
58 	CFG_OSD_TOUCHPAD_BIT = 30,
59 	CFG_OSD_CAM_BIT      = 31,
60 };
61 
62 enum {
63 	GBMD_CONSERVATION_STATE_BIT = 5,
64 };
65 
66 enum {
67 	SBMC_CONSERVATION_ON  = 3,
68 	SBMC_CONSERVATION_OFF = 5,
69 };
70 
71 enum {
72 	HALS_KBD_BL_SUPPORT_BIT       = 4,
73 	HALS_KBD_BL_STATE_BIT         = 5,
74 	HALS_USB_CHARGING_SUPPORT_BIT = 6,
75 	HALS_USB_CHARGING_STATE_BIT   = 7,
76 	HALS_FNLOCK_SUPPORT_BIT       = 9,
77 	HALS_FNLOCK_STATE_BIT         = 10,
78 	HALS_HOTKEYS_PRIMARY_BIT      = 11,
79 };
80 
81 enum {
82 	SALS_KBD_BL_ON        = 0x8,
83 	SALS_KBD_BL_OFF       = 0x9,
84 	SALS_USB_CHARGING_ON  = 0xa,
85 	SALS_USB_CHARGING_OFF = 0xb,
86 	SALS_FNLOCK_ON        = 0xe,
87 	SALS_FNLOCK_OFF       = 0xf,
88 };
89 
90 /*
91  * These correspond to the number of supported states - 1
92  * Future keyboard types may need a new system, if there's a collision
93  * KBD_BL_TRISTATE_AUTO has no way to report or set the auto state
94  * so it effectively has 3 states, but needs to handle 4
95  */
96 enum {
97 	KBD_BL_STANDARD      = 1,
98 	KBD_BL_TRISTATE      = 2,
99 	KBD_BL_TRISTATE_AUTO = 3,
100 };
101 
102 #define KBD_BL_QUERY_TYPE		0x1
103 #define KBD_BL_TRISTATE_TYPE		0x5
104 #define KBD_BL_TRISTATE_AUTO_TYPE	0x7
105 
106 #define KBD_BL_COMMAND_GET		0x2
107 #define KBD_BL_COMMAND_SET		0x3
108 #define KBD_BL_COMMAND_TYPE		GENMASK(7, 4)
109 
110 #define KBD_BL_GET_BRIGHTNESS		GENMASK(15, 1)
111 #define KBD_BL_SET_BRIGHTNESS		GENMASK(19, 16)
112 
113 #define KBD_BL_KBLC_CHANGED_EVENT	12
114 
115 struct ideapad_dytc_priv {
116 	enum platform_profile_option current_profile;
117 	struct platform_profile_handler pprof;
118 	struct mutex mutex; /* protects the DYTC interface */
119 	struct ideapad_private *priv;
120 };
121 
122 struct ideapad_rfk_priv {
123 	int dev;
124 	struct ideapad_private *priv;
125 };
126 
127 struct ideapad_private {
128 	struct acpi_device *adev;
129 	struct mutex vpc_mutex; /* protects the VPC calls */
130 	struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
131 	struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
132 	struct platform_device *platform_device;
133 	struct input_dev *inputdev;
134 	struct backlight_device *blightdev;
135 	struct ideapad_dytc_priv *dytc;
136 	struct dentry *debug;
137 	unsigned long cfg;
138 	unsigned long r_touchpad_val;
139 	struct {
140 		bool conservation_mode    : 1;
141 		bool dytc                 : 1;
142 		bool fan_mode             : 1;
143 		bool fn_lock              : 1;
144 		bool set_fn_lock_led      : 1;
145 		bool hw_rfkill_switch     : 1;
146 		bool kbd_bl               : 1;
147 		bool touchpad_ctrl_via_ec : 1;
148 		bool ctrl_ps2_aux_port    : 1;
149 		bool usb_charging         : 1;
150 		bool ymc_ec_trigger       : 1;
151 	} features;
152 	struct {
153 		bool initialized;
154 		int type;
155 		struct led_classdev led;
156 		unsigned int last_brightness;
157 	} kbd_bl;
158 	struct {
159 		bool initialized;
160 		struct led_classdev led;
161 		unsigned int last_brightness;
162 	} fn_lock;
163 };
164 
165 static bool no_bt_rfkill;
166 module_param(no_bt_rfkill, bool, 0444);
167 MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
168 
169 static bool allow_v4_dytc;
170 module_param(allow_v4_dytc, bool, 0444);
171 MODULE_PARM_DESC(allow_v4_dytc,
172 	"Enable DYTC version 4 platform-profile support. "
173 	"If you need this please report this to: platform-driver-x86@vger.kernel.org");
174 
175 static bool hw_rfkill_switch;
176 module_param(hw_rfkill_switch, bool, 0444);
177 MODULE_PARM_DESC(hw_rfkill_switch,
178 	"Enable rfkill support for laptops with a hw on/off wifi switch/slider. "
179 	"If you need this please report this to: platform-driver-x86@vger.kernel.org");
180 
181 static bool set_fn_lock_led;
182 module_param(set_fn_lock_led, bool, 0444);
183 MODULE_PARM_DESC(set_fn_lock_led,
184 	"Enable driver based updates of the fn-lock LED on fn-lock changes. "
185 	"If you need this please report this to: platform-driver-x86@vger.kernel.org");
186 
187 static bool ctrl_ps2_aux_port;
188 module_param(ctrl_ps2_aux_port, bool, 0444);
189 MODULE_PARM_DESC(ctrl_ps2_aux_port,
190 	"Enable driver based PS/2 aux port en-/dis-abling on touchpad on/off toggle. "
191 	"If you need this please report this to: platform-driver-x86@vger.kernel.org");
192 
193 static bool touchpad_ctrl_via_ec;
194 module_param(touchpad_ctrl_via_ec, bool, 0444);
195 MODULE_PARM_DESC(touchpad_ctrl_via_ec,
196 	"Enable registering a 'touchpad' sysfs-attribute which can be used to manually "
197 	"tell the EC to enable/disable the touchpad. This may not work on all models.");
198 
199 static bool ymc_ec_trigger __read_mostly;
200 module_param(ymc_ec_trigger, bool, 0444);
201 MODULE_PARM_DESC(ymc_ec_trigger,
202 	"Enable EC triggering work-around to force emitting tablet mode events. "
203 	"If you need this please report this to: platform-driver-x86@vger.kernel.org");
204 
205 /*
206  * shared data
207  */
208 
209 static struct ideapad_private *ideapad_shared;
210 static DEFINE_MUTEX(ideapad_shared_mutex);
211 
212 static int ideapad_shared_init(struct ideapad_private *priv)
213 {
214 	int ret;
215 
216 	guard(mutex)(&ideapad_shared_mutex);
217 
218 	if (!ideapad_shared) {
219 		ideapad_shared = priv;
220 		ret = 0;
221 	} else {
222 		dev_warn(&priv->adev->dev, "found multiple platform devices\n");
223 		ret = -EINVAL;
224 	}
225 
226 	return ret;
227 }
228 
229 static void ideapad_shared_exit(struct ideapad_private *priv)
230 {
231 	guard(mutex)(&ideapad_shared_mutex);
232 
233 	if (ideapad_shared == priv)
234 		ideapad_shared = NULL;
235 }
236 
237 /*
238  * ACPI Helpers
239  */
240 
241 static int eval_int(acpi_handle handle, const char *name, unsigned long *res)
242 {
243 	unsigned long long result;
244 	acpi_status status;
245 
246 	status = acpi_evaluate_integer(handle, (char *)name, NULL, &result);
247 	if (ACPI_FAILURE(status))
248 		return -EIO;
249 
250 	*res = result;
251 
252 	return 0;
253 }
254 
255 static int exec_simple_method(acpi_handle handle, const char *name, unsigned long arg)
256 {
257 	acpi_status status = acpi_execute_simple_method(handle, (char *)name, arg);
258 
259 	return ACPI_FAILURE(status) ? -EIO : 0;
260 }
261 
262 static int eval_gbmd(acpi_handle handle, unsigned long *res)
263 {
264 	return eval_int(handle, "GBMD", res);
265 }
266 
267 static int exec_sbmc(acpi_handle handle, unsigned long arg)
268 {
269 	return exec_simple_method(handle, "SBMC", arg);
270 }
271 
272 static int eval_hals(acpi_handle handle, unsigned long *res)
273 {
274 	return eval_int(handle, "HALS", res);
275 }
276 
277 static int exec_sals(acpi_handle handle, unsigned long arg)
278 {
279 	return exec_simple_method(handle, "SALS", arg);
280 }
281 
282 static int exec_kblc(acpi_handle handle, unsigned long arg)
283 {
284 	return exec_simple_method(handle, "KBLC", arg);
285 }
286 
287 static int eval_kblc(acpi_handle handle, unsigned long cmd, unsigned long *res)
288 {
289 	return eval_int_with_arg(handle, "KBLC", cmd, res);
290 }
291 
292 static int eval_dytc(acpi_handle handle, unsigned long cmd, unsigned long *res)
293 {
294 	return eval_int_with_arg(handle, "DYTC", cmd, res);
295 }
296 
297 /*
298  * debugfs
299  */
300 static int debugfs_status_show(struct seq_file *s, void *data)
301 {
302 	struct ideapad_private *priv = s->private;
303 	unsigned long value;
304 
305 	guard(mutex)(&priv->vpc_mutex);
306 
307 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
308 		seq_printf(s, "Backlight max:  %lu\n", value);
309 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
310 		seq_printf(s, "Backlight now:  %lu\n", value);
311 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
312 		seq_printf(s, "BL power value: %s (%lu)\n", value ? "on" : "off", value);
313 
314 	seq_puts(s, "=====================\n");
315 
316 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
317 		seq_printf(s, "Radio status: %s (%lu)\n", value ? "on" : "off", value);
318 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
319 		seq_printf(s, "Wifi status:  %s (%lu)\n", value ? "on" : "off", value);
320 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
321 		seq_printf(s, "BT status:    %s (%lu)\n", value ? "on" : "off", value);
322 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
323 		seq_printf(s, "3G status:    %s (%lu)\n", value ? "on" : "off", value);
324 
325 	seq_puts(s, "=====================\n");
326 
327 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
328 		seq_printf(s, "Touchpad status: %s (%lu)\n", value ? "on" : "off", value);
329 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
330 		seq_printf(s, "Camera status:   %s (%lu)\n", value ? "on" : "off", value);
331 
332 	seq_puts(s, "=====================\n");
333 
334 	if (!eval_gbmd(priv->adev->handle, &value))
335 		seq_printf(s, "GBMD: %#010lx\n", value);
336 	if (!eval_hals(priv->adev->handle, &value))
337 		seq_printf(s, "HALS: %#010lx\n", value);
338 
339 	return 0;
340 }
341 DEFINE_SHOW_ATTRIBUTE(debugfs_status);
342 
343 static int debugfs_cfg_show(struct seq_file *s, void *data)
344 {
345 	struct ideapad_private *priv = s->private;
346 
347 	seq_printf(s, "_CFG: %#010lx\n\n", priv->cfg);
348 
349 	seq_puts(s, "Capabilities:");
350 	if (test_bit(CFG_CAP_BT_BIT, &priv->cfg))
351 		seq_puts(s, " bluetooth");
352 	if (test_bit(CFG_CAP_3G_BIT, &priv->cfg))
353 		seq_puts(s, " 3G");
354 	if (test_bit(CFG_CAP_WIFI_BIT, &priv->cfg))
355 		seq_puts(s, " wifi");
356 	if (test_bit(CFG_CAP_CAM_BIT, &priv->cfg))
357 		seq_puts(s, " camera");
358 	seq_puts(s, "\n");
359 
360 	seq_puts(s, "OSD support:");
361 	if (test_bit(CFG_OSD_NUMLK_BIT, &priv->cfg))
362 		seq_puts(s, " num-lock");
363 	if (test_bit(CFG_OSD_CAPSLK_BIT, &priv->cfg))
364 		seq_puts(s, " caps-lock");
365 	if (test_bit(CFG_OSD_MICMUTE_BIT, &priv->cfg))
366 		seq_puts(s, " mic-mute");
367 	if (test_bit(CFG_OSD_TOUCHPAD_BIT, &priv->cfg))
368 		seq_puts(s, " touchpad");
369 	if (test_bit(CFG_OSD_CAM_BIT, &priv->cfg))
370 		seq_puts(s, " camera");
371 	seq_puts(s, "\n");
372 
373 	seq_puts(s, "Graphics: ");
374 	switch (priv->cfg & 0x700) {
375 	case 0x100:
376 		seq_puts(s, "Intel");
377 		break;
378 	case 0x200:
379 		seq_puts(s, "ATI");
380 		break;
381 	case 0x300:
382 		seq_puts(s, "Nvidia");
383 		break;
384 	case 0x400:
385 		seq_puts(s, "Intel and ATI");
386 		break;
387 	case 0x500:
388 		seq_puts(s, "Intel and Nvidia");
389 		break;
390 	}
391 	seq_puts(s, "\n");
392 
393 	return 0;
394 }
395 DEFINE_SHOW_ATTRIBUTE(debugfs_cfg);
396 
397 static void ideapad_debugfs_init(struct ideapad_private *priv)
398 {
399 	struct dentry *dir;
400 
401 	dir = debugfs_create_dir("ideapad", NULL);
402 	priv->debug = dir;
403 
404 	debugfs_create_file("cfg", 0444, dir, priv, &debugfs_cfg_fops);
405 	debugfs_create_file("status", 0444, dir, priv, &debugfs_status_fops);
406 }
407 
408 static void ideapad_debugfs_exit(struct ideapad_private *priv)
409 {
410 	debugfs_remove_recursive(priv->debug);
411 	priv->debug = NULL;
412 }
413 
414 /*
415  * sysfs
416  */
417 static ssize_t camera_power_show(struct device *dev,
418 				 struct device_attribute *attr,
419 				 char *buf)
420 {
421 	struct ideapad_private *priv = dev_get_drvdata(dev);
422 	unsigned long result;
423 	int err;
424 
425 	scoped_guard(mutex, &priv->vpc_mutex)
426 		err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
427 	if (err)
428 		return err;
429 
430 	return sysfs_emit(buf, "%d\n", !!result);
431 }
432 
433 static ssize_t camera_power_store(struct device *dev,
434 				  struct device_attribute *attr,
435 				  const char *buf, size_t count)
436 {
437 	struct ideapad_private *priv = dev_get_drvdata(dev);
438 	bool state;
439 	int err;
440 
441 	err = kstrtobool(buf, &state);
442 	if (err)
443 		return err;
444 
445 	scoped_guard(mutex, &priv->vpc_mutex)
446 		err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
447 	if (err)
448 		return err;
449 
450 	return count;
451 }
452 
453 static DEVICE_ATTR_RW(camera_power);
454 
455 static ssize_t conservation_mode_show(struct device *dev,
456 				      struct device_attribute *attr,
457 				      char *buf)
458 {
459 	struct ideapad_private *priv = dev_get_drvdata(dev);
460 	unsigned long result;
461 	int err;
462 
463 	err = eval_gbmd(priv->adev->handle, &result);
464 	if (err)
465 		return err;
466 
467 	return sysfs_emit(buf, "%d\n", !!test_bit(GBMD_CONSERVATION_STATE_BIT, &result));
468 }
469 
470 static ssize_t conservation_mode_store(struct device *dev,
471 				       struct device_attribute *attr,
472 				       const char *buf, size_t count)
473 {
474 	struct ideapad_private *priv = dev_get_drvdata(dev);
475 	bool state;
476 	int err;
477 
478 	err = kstrtobool(buf, &state);
479 	if (err)
480 		return err;
481 
482 	err = exec_sbmc(priv->adev->handle, state ? SBMC_CONSERVATION_ON : SBMC_CONSERVATION_OFF);
483 	if (err)
484 		return err;
485 
486 	return count;
487 }
488 
489 static DEVICE_ATTR_RW(conservation_mode);
490 
491 static ssize_t fan_mode_show(struct device *dev,
492 			     struct device_attribute *attr,
493 			     char *buf)
494 {
495 	struct ideapad_private *priv = dev_get_drvdata(dev);
496 	unsigned long result;
497 	int err;
498 
499 	scoped_guard(mutex, &priv->vpc_mutex)
500 		err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
501 	if (err)
502 		return err;
503 
504 	return sysfs_emit(buf, "%lu\n", result);
505 }
506 
507 static ssize_t fan_mode_store(struct device *dev,
508 			      struct device_attribute *attr,
509 			      const char *buf, size_t count)
510 {
511 	struct ideapad_private *priv = dev_get_drvdata(dev);
512 	unsigned int state;
513 	int err;
514 
515 	err = kstrtouint(buf, 0, &state);
516 	if (err)
517 		return err;
518 
519 	if (state > 4 || state == 3)
520 		return -EINVAL;
521 
522 	scoped_guard(mutex, &priv->vpc_mutex)
523 		err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
524 	if (err)
525 		return err;
526 
527 	return count;
528 }
529 
530 static DEVICE_ATTR_RW(fan_mode);
531 
532 static int ideapad_fn_lock_get(struct ideapad_private *priv)
533 {
534 	unsigned long hals;
535 	int err;
536 
537 	err = eval_hals(priv->adev->handle, &hals);
538 	if (err)
539 		return err;
540 
541 	return !!test_bit(HALS_FNLOCK_STATE_BIT, &hals);
542 }
543 
544 static int ideapad_fn_lock_set(struct ideapad_private *priv, bool state)
545 {
546 	return exec_sals(priv->adev->handle,
547 		state ? SALS_FNLOCK_ON : SALS_FNLOCK_OFF);
548 }
549 
550 static void ideapad_fn_lock_led_notify(struct ideapad_private *priv, int brightness)
551 {
552 	if (!priv->fn_lock.initialized)
553 		return;
554 
555 	if (brightness == priv->fn_lock.last_brightness)
556 		return;
557 
558 	priv->fn_lock.last_brightness = brightness;
559 
560 	led_classdev_notify_brightness_hw_changed(&priv->fn_lock.led, brightness);
561 }
562 
563 static ssize_t fn_lock_show(struct device *dev,
564 			    struct device_attribute *attr,
565 			    char *buf)
566 {
567 	struct ideapad_private *priv = dev_get_drvdata(dev);
568 	int brightness;
569 
570 	brightness = ideapad_fn_lock_get(priv);
571 	if (brightness < 0)
572 		return brightness;
573 
574 	return sysfs_emit(buf, "%d\n", brightness);
575 }
576 
577 static ssize_t fn_lock_store(struct device *dev,
578 			     struct device_attribute *attr,
579 			     const char *buf, size_t count)
580 {
581 	struct ideapad_private *priv = dev_get_drvdata(dev);
582 	bool state;
583 	int err;
584 
585 	err = kstrtobool(buf, &state);
586 	if (err)
587 		return err;
588 
589 	err = ideapad_fn_lock_set(priv, state);
590 	if (err)
591 		return err;
592 
593 	ideapad_fn_lock_led_notify(priv, state);
594 
595 	return count;
596 }
597 
598 static DEVICE_ATTR_RW(fn_lock);
599 
600 static ssize_t touchpad_show(struct device *dev,
601 			     struct device_attribute *attr,
602 			     char *buf)
603 {
604 	struct ideapad_private *priv = dev_get_drvdata(dev);
605 	unsigned long result;
606 	int err;
607 
608 	scoped_guard(mutex, &priv->vpc_mutex)
609 		err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
610 	if (err)
611 		return err;
612 
613 	priv->r_touchpad_val = result;
614 
615 	return sysfs_emit(buf, "%d\n", !!result);
616 }
617 
618 static ssize_t touchpad_store(struct device *dev,
619 			      struct device_attribute *attr,
620 			      const char *buf, size_t count)
621 {
622 	struct ideapad_private *priv = dev_get_drvdata(dev);
623 	bool state;
624 	int err;
625 
626 	err = kstrtobool(buf, &state);
627 	if (err)
628 		return err;
629 
630 	scoped_guard(mutex, &priv->vpc_mutex)
631 		err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
632 	if (err)
633 		return err;
634 
635 	priv->r_touchpad_val = state;
636 
637 	return count;
638 }
639 
640 static DEVICE_ATTR_RW(touchpad);
641 
642 static ssize_t usb_charging_show(struct device *dev,
643 				 struct device_attribute *attr,
644 				 char *buf)
645 {
646 	struct ideapad_private *priv = dev_get_drvdata(dev);
647 	unsigned long hals;
648 	int err;
649 
650 	err = eval_hals(priv->adev->handle, &hals);
651 	if (err)
652 		return err;
653 
654 	return sysfs_emit(buf, "%d\n", !!test_bit(HALS_USB_CHARGING_STATE_BIT, &hals));
655 }
656 
657 static ssize_t usb_charging_store(struct device *dev,
658 				  struct device_attribute *attr,
659 				  const char *buf, size_t count)
660 {
661 	struct ideapad_private *priv = dev_get_drvdata(dev);
662 	bool state;
663 	int err;
664 
665 	err = kstrtobool(buf, &state);
666 	if (err)
667 		return err;
668 
669 	err = exec_sals(priv->adev->handle, state ? SALS_USB_CHARGING_ON : SALS_USB_CHARGING_OFF);
670 	if (err)
671 		return err;
672 
673 	return count;
674 }
675 
676 static DEVICE_ATTR_RW(usb_charging);
677 
678 static struct attribute *ideapad_attributes[] = {
679 	&dev_attr_camera_power.attr,
680 	&dev_attr_conservation_mode.attr,
681 	&dev_attr_fan_mode.attr,
682 	&dev_attr_fn_lock.attr,
683 	&dev_attr_touchpad.attr,
684 	&dev_attr_usb_charging.attr,
685 	NULL
686 };
687 
688 static umode_t ideapad_is_visible(struct kobject *kobj,
689 				  struct attribute *attr,
690 				  int idx)
691 {
692 	struct device *dev = kobj_to_dev(kobj);
693 	struct ideapad_private *priv = dev_get_drvdata(dev);
694 	bool supported = true;
695 
696 	if (attr == &dev_attr_camera_power.attr)
697 		supported = test_bit(CFG_CAP_CAM_BIT, &priv->cfg);
698 	else if (attr == &dev_attr_conservation_mode.attr)
699 		supported = priv->features.conservation_mode;
700 	else if (attr == &dev_attr_fan_mode.attr)
701 		supported = priv->features.fan_mode;
702 	else if (attr == &dev_attr_fn_lock.attr)
703 		supported = priv->features.fn_lock;
704 	else if (attr == &dev_attr_touchpad.attr)
705 		supported = priv->features.touchpad_ctrl_via_ec;
706 	else if (attr == &dev_attr_usb_charging.attr)
707 		supported = priv->features.usb_charging;
708 
709 	return supported ? attr->mode : 0;
710 }
711 
712 static const struct attribute_group ideapad_attribute_group = {
713 	.is_visible = ideapad_is_visible,
714 	.attrs = ideapad_attributes
715 };
716 
717 /*
718  * DYTC Platform profile
719  */
720 #define DYTC_CMD_QUERY        0 /* To get DYTC status - enable/revision */
721 #define DYTC_CMD_SET          1 /* To enable/disable IC function mode */
722 #define DYTC_CMD_GET          2 /* To get current IC function and mode */
723 #define DYTC_CMD_RESET    0x1ff /* To reset back to default */
724 
725 #define DYTC_QUERY_ENABLE_BIT 8  /* Bit        8 - 0 = disabled, 1 = enabled */
726 #define DYTC_QUERY_SUBREV_BIT 16 /* Bits 16 - 27 - sub revision */
727 #define DYTC_QUERY_REV_BIT    28 /* Bits 28 - 31 - revision */
728 
729 #define DYTC_GET_FUNCTION_BIT 8  /* Bits  8-11 - function setting */
730 #define DYTC_GET_MODE_BIT     12 /* Bits 12-15 - mode setting */
731 
732 #define DYTC_SET_FUNCTION_BIT 12 /* Bits 12-15 - function setting */
733 #define DYTC_SET_MODE_BIT     16 /* Bits 16-19 - mode setting */
734 #define DYTC_SET_VALID_BIT    20 /* Bit     20 - 1 = on, 0 = off */
735 
736 #define DYTC_FUNCTION_STD     0  /* Function = 0, standard mode */
737 #define DYTC_FUNCTION_CQL     1  /* Function = 1, lap mode */
738 #define DYTC_FUNCTION_MMC     11 /* Function = 11, desk mode */
739 
740 #define DYTC_MODE_PERFORM     2  /* High power mode aka performance */
741 #define DYTC_MODE_LOW_POWER       3  /* Low power mode aka quiet */
742 #define DYTC_MODE_BALANCE   0xF  /* Default mode aka balanced */
743 
744 #define DYTC_SET_COMMAND(function, mode, on) \
745 	(DYTC_CMD_SET | (function) << DYTC_SET_FUNCTION_BIT | \
746 	 (mode) << DYTC_SET_MODE_BIT | \
747 	 (on) << DYTC_SET_VALID_BIT)
748 
749 #define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0)
750 
751 #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1)
752 
753 static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
754 {
755 	switch (dytcmode) {
756 	case DYTC_MODE_LOW_POWER:
757 		*profile = PLATFORM_PROFILE_LOW_POWER;
758 		break;
759 	case DYTC_MODE_BALANCE:
760 		*profile =  PLATFORM_PROFILE_BALANCED;
761 		break;
762 	case DYTC_MODE_PERFORM:
763 		*profile =  PLATFORM_PROFILE_PERFORMANCE;
764 		break;
765 	default: /* Unknown mode */
766 		return -EINVAL;
767 	}
768 
769 	return 0;
770 }
771 
772 static int convert_profile_to_dytc(enum platform_profile_option profile, int *perfmode)
773 {
774 	switch (profile) {
775 	case PLATFORM_PROFILE_LOW_POWER:
776 		*perfmode = DYTC_MODE_LOW_POWER;
777 		break;
778 	case PLATFORM_PROFILE_BALANCED:
779 		*perfmode = DYTC_MODE_BALANCE;
780 		break;
781 	case PLATFORM_PROFILE_PERFORMANCE:
782 		*perfmode = DYTC_MODE_PERFORM;
783 		break;
784 	default: /* Unknown profile */
785 		return -EOPNOTSUPP;
786 	}
787 
788 	return 0;
789 }
790 
791 /*
792  * dytc_profile_get: Function to register with platform_profile
793  * handler. Returns current platform profile.
794  */
795 static int dytc_profile_get(struct platform_profile_handler *pprof,
796 			    enum platform_profile_option *profile)
797 {
798 	struct ideapad_dytc_priv *dytc = container_of(pprof, struct ideapad_dytc_priv, pprof);
799 
800 	*profile = dytc->current_profile;
801 	return 0;
802 }
803 
804 /*
805  * Helper function - check if we are in CQL mode and if we are
806  *  - disable CQL,
807  *  - run the command
808  *  - enable CQL
809  *  If not in CQL mode, just run the command
810  */
811 static int dytc_cql_command(struct ideapad_private *priv, unsigned long cmd,
812 			    unsigned long *output)
813 {
814 	int err, cmd_err, cur_funcmode;
815 
816 	/* Determine if we are in CQL mode. This alters the commands we do */
817 	err = eval_dytc(priv->adev->handle, DYTC_CMD_GET, output);
818 	if (err)
819 		return err;
820 
821 	cur_funcmode = (*output >> DYTC_GET_FUNCTION_BIT) & 0xF;
822 	/* Check if we're OK to return immediately */
823 	if (cmd == DYTC_CMD_GET && cur_funcmode != DYTC_FUNCTION_CQL)
824 		return 0;
825 
826 	if (cur_funcmode == DYTC_FUNCTION_CQL) {
827 		err = eval_dytc(priv->adev->handle, DYTC_DISABLE_CQL, NULL);
828 		if (err)
829 			return err;
830 	}
831 
832 	cmd_err = eval_dytc(priv->adev->handle, cmd, output);
833 	/* Check return condition after we've restored CQL state */
834 
835 	if (cur_funcmode == DYTC_FUNCTION_CQL) {
836 		err = eval_dytc(priv->adev->handle, DYTC_ENABLE_CQL, NULL);
837 		if (err)
838 			return err;
839 	}
840 
841 	return cmd_err;
842 }
843 
844 /*
845  * dytc_profile_set: Function to register with platform_profile
846  * handler. Sets current platform profile.
847  */
848 static int dytc_profile_set(struct platform_profile_handler *pprof,
849 			    enum platform_profile_option profile)
850 {
851 	struct ideapad_dytc_priv *dytc = container_of(pprof, struct ideapad_dytc_priv, pprof);
852 	struct ideapad_private *priv = dytc->priv;
853 	unsigned long output;
854 	int err;
855 
856 	scoped_guard(mutex_intr, &dytc->mutex) {
857 		if (profile == PLATFORM_PROFILE_BALANCED) {
858 			/* To get back to balanced mode we just issue a reset command */
859 			err = eval_dytc(priv->adev->handle, DYTC_CMD_RESET, NULL);
860 			if (err)
861 				return err;
862 		} else {
863 			int perfmode;
864 
865 			err = convert_profile_to_dytc(profile, &perfmode);
866 			if (err)
867 				return err;
868 
869 			/* Determine if we are in CQL mode. This alters the commands we do */
870 			err = dytc_cql_command(priv,
871 					       DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1),
872 					       &output);
873 			if (err)
874 				return err;
875 		}
876 
877 		/* Success - update current profile */
878 		dytc->current_profile = profile;
879 		return 0;
880 	}
881 
882 	return -EINTR;
883 }
884 
885 static void dytc_profile_refresh(struct ideapad_private *priv)
886 {
887 	enum platform_profile_option profile;
888 	unsigned long output;
889 	int err, perfmode;
890 
891 	scoped_guard(mutex, &priv->dytc->mutex)
892 		err = dytc_cql_command(priv, DYTC_CMD_GET, &output);
893 	if (err)
894 		return;
895 
896 	perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF;
897 
898 	if (convert_dytc_to_profile(perfmode, &profile))
899 		return;
900 
901 	if (profile != priv->dytc->current_profile) {
902 		priv->dytc->current_profile = profile;
903 		platform_profile_notify();
904 	}
905 }
906 
907 static const struct dmi_system_id ideapad_dytc_v4_allow_table[] = {
908 	{
909 		/* Ideapad 5 Pro 16ACH6 */
910 		.matches = {
911 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
912 			DMI_MATCH(DMI_PRODUCT_NAME, "82L5")
913 		}
914 	},
915 	{
916 		/* Ideapad 5 15ITL05 */
917 		.matches = {
918 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
919 			DMI_MATCH(DMI_PRODUCT_VERSION, "IdeaPad 5 15ITL05")
920 		}
921 	},
922 	{}
923 };
924 
925 static int ideapad_dytc_profile_init(struct ideapad_private *priv)
926 {
927 	int err, dytc_version;
928 	unsigned long output;
929 
930 	if (!priv->features.dytc)
931 		return -ENODEV;
932 
933 	err = eval_dytc(priv->adev->handle, DYTC_CMD_QUERY, &output);
934 	/* For all other errors we can flag the failure */
935 	if (err)
936 		return err;
937 
938 	/* Check DYTC is enabled and supports mode setting */
939 	if (!test_bit(DYTC_QUERY_ENABLE_BIT, &output)) {
940 		dev_info(&priv->platform_device->dev, "DYTC_QUERY_ENABLE_BIT returned false\n");
941 		return -ENODEV;
942 	}
943 
944 	dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF;
945 
946 	if (dytc_version < 4) {
947 		dev_info(&priv->platform_device->dev, "DYTC_VERSION < 4 is not supported\n");
948 		return -ENODEV;
949 	}
950 
951 	if (dytc_version < 5 &&
952 	    !(allow_v4_dytc || dmi_check_system(ideapad_dytc_v4_allow_table))) {
953 		dev_info(&priv->platform_device->dev,
954 			 "DYTC_VERSION 4 support may not work. Pass ideapad_laptop.allow_v4_dytc=Y on the kernel commandline to enable\n");
955 		return -ENODEV;
956 	}
957 
958 	priv->dytc = kzalloc(sizeof(*priv->dytc), GFP_KERNEL);
959 	if (!priv->dytc)
960 		return -ENOMEM;
961 
962 	mutex_init(&priv->dytc->mutex);
963 
964 	priv->dytc->priv = priv;
965 	priv->dytc->pprof.profile_get = dytc_profile_get;
966 	priv->dytc->pprof.profile_set = dytc_profile_set;
967 
968 	/* Setup supported modes */
969 	set_bit(PLATFORM_PROFILE_LOW_POWER, priv->dytc->pprof.choices);
970 	set_bit(PLATFORM_PROFILE_BALANCED, priv->dytc->pprof.choices);
971 	set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->dytc->pprof.choices);
972 
973 	/* Create platform_profile structure and register */
974 	err = platform_profile_register(&priv->dytc->pprof);
975 	if (err)
976 		goto pp_reg_failed;
977 
978 	/* Ensure initial values are correct */
979 	dytc_profile_refresh(priv);
980 
981 	return 0;
982 
983 pp_reg_failed:
984 	mutex_destroy(&priv->dytc->mutex);
985 	kfree(priv->dytc);
986 	priv->dytc = NULL;
987 
988 	return err;
989 }
990 
991 static void ideapad_dytc_profile_exit(struct ideapad_private *priv)
992 {
993 	if (!priv->dytc)
994 		return;
995 
996 	platform_profile_remove();
997 	mutex_destroy(&priv->dytc->mutex);
998 	kfree(priv->dytc);
999 
1000 	priv->dytc = NULL;
1001 }
1002 
1003 /*
1004  * Rfkill
1005  */
1006 struct ideapad_rfk_data {
1007 	char *name;
1008 	int cfgbit;
1009 	int opcode;
1010 	int type;
1011 };
1012 
1013 static const struct ideapad_rfk_data ideapad_rfk_data[] = {
1014 	{ "ideapad_wlan",      CFG_CAP_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
1015 	{ "ideapad_bluetooth", CFG_CAP_BT_BIT,   VPCCMD_W_BT,   RFKILL_TYPE_BLUETOOTH },
1016 	{ "ideapad_3g",        CFG_CAP_3G_BIT,   VPCCMD_W_3G,   RFKILL_TYPE_WWAN },
1017 };
1018 
1019 static int ideapad_rfk_set(void *data, bool blocked)
1020 {
1021 	struct ideapad_rfk_priv *priv = data;
1022 	int opcode = ideapad_rfk_data[priv->dev].opcode;
1023 
1024 	guard(mutex)(&priv->priv->vpc_mutex);
1025 
1026 	return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
1027 }
1028 
1029 static const struct rfkill_ops ideapad_rfk_ops = {
1030 	.set_block = ideapad_rfk_set,
1031 };
1032 
1033 static void ideapad_sync_rfk_state(struct ideapad_private *priv)
1034 {
1035 	unsigned long hw_blocked = 0;
1036 	int i;
1037 
1038 	if (priv->features.hw_rfkill_switch) {
1039 		guard(mutex)(&priv->vpc_mutex);
1040 
1041 		if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
1042 			return;
1043 		hw_blocked = !hw_blocked;
1044 	}
1045 
1046 	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1047 		if (priv->rfk[i])
1048 			rfkill_set_hw_state(priv->rfk[i], hw_blocked);
1049 }
1050 
1051 static int ideapad_register_rfkill(struct ideapad_private *priv, int dev)
1052 {
1053 	unsigned long rf_enabled;
1054 	int err;
1055 
1056 	if (no_bt_rfkill && ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH) {
1057 		/* Force to enable bluetooth when no_bt_rfkill=1 */
1058 		write_ec_cmd(priv->adev->handle, ideapad_rfk_data[dev].opcode, 1);
1059 		return 0;
1060 	}
1061 
1062 	priv->rfk_priv[dev].dev = dev;
1063 	priv->rfk_priv[dev].priv = priv;
1064 
1065 	priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name,
1066 				      &priv->platform_device->dev,
1067 				      ideapad_rfk_data[dev].type,
1068 				      &ideapad_rfk_ops,
1069 				      &priv->rfk_priv[dev]);
1070 	if (!priv->rfk[dev])
1071 		return -ENOMEM;
1072 
1073 	err = read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode - 1, &rf_enabled);
1074 	if (err)
1075 		rf_enabled = 1;
1076 
1077 	rfkill_init_sw_state(priv->rfk[dev], !rf_enabled);
1078 
1079 	err = rfkill_register(priv->rfk[dev]);
1080 	if (err)
1081 		rfkill_destroy(priv->rfk[dev]);
1082 
1083 	return err;
1084 }
1085 
1086 static void ideapad_unregister_rfkill(struct ideapad_private *priv, int dev)
1087 {
1088 	if (!priv->rfk[dev])
1089 		return;
1090 
1091 	rfkill_unregister(priv->rfk[dev]);
1092 	rfkill_destroy(priv->rfk[dev]);
1093 }
1094 
1095 /*
1096  * Platform device
1097  */
1098 static int ideapad_sysfs_init(struct ideapad_private *priv)
1099 {
1100 	return device_add_group(&priv->platform_device->dev,
1101 				&ideapad_attribute_group);
1102 }
1103 
1104 static void ideapad_sysfs_exit(struct ideapad_private *priv)
1105 {
1106 	device_remove_group(&priv->platform_device->dev,
1107 			    &ideapad_attribute_group);
1108 }
1109 
1110 /*
1111  * input device
1112  */
1113 #define IDEAPAD_WMI_KEY 0x100
1114 
1115 static const struct key_entry ideapad_keymap[] = {
1116 	{ KE_KEY,   6, { KEY_SWITCHVIDEOMODE } },
1117 	{ KE_KEY,   7, { KEY_CAMERA } },
1118 	{ KE_KEY,   8, { KEY_MICMUTE } },
1119 	{ KE_KEY,  11, { KEY_F16 } },
1120 	{ KE_KEY,  13, { KEY_WLAN } },
1121 	{ KE_KEY,  16, { KEY_PROG1 } },
1122 	{ KE_KEY,  17, { KEY_PROG2 } },
1123 	{ KE_KEY,  64, { KEY_PROG3 } },
1124 	{ KE_KEY,  65, { KEY_PROG4 } },
1125 	{ KE_KEY,  66, { KEY_TOUCHPAD_OFF } },
1126 	{ KE_KEY,  67, { KEY_TOUCHPAD_ON } },
1127 	{ KE_KEY, 128, { KEY_ESC } },
1128 
1129 	/*
1130 	 * WMI keys
1131 	 */
1132 
1133 	/* FnLock (handled by the firmware) */
1134 	{ KE_IGNORE,	0x02 | IDEAPAD_WMI_KEY },
1135 	/* Esc (handled by the firmware) */
1136 	{ KE_IGNORE,	0x03 | IDEAPAD_WMI_KEY },
1137 	/* Customizable Lenovo Hotkey ("star" with 'S' inside) */
1138 	{ KE_KEY,	0x01 | IDEAPAD_WMI_KEY, { KEY_FAVORITES } },
1139 	{ KE_KEY,	0x04 | IDEAPAD_WMI_KEY, { KEY_SELECTIVE_SCREENSHOT } },
1140 	/* Lenovo Support */
1141 	{ KE_KEY,	0x07 | IDEAPAD_WMI_KEY, { KEY_HELP } },
1142 	{ KE_KEY,	0x0e | IDEAPAD_WMI_KEY, { KEY_PICKUP_PHONE } },
1143 	{ KE_KEY,	0x0f | IDEAPAD_WMI_KEY, { KEY_HANGUP_PHONE } },
1144 	/* Refresh Rate Toggle (Fn+R) */
1145 	{ KE_KEY,	0x10 | IDEAPAD_WMI_KEY, { KEY_REFRESH_RATE_TOGGLE } },
1146 	/* Dark mode toggle */
1147 	{ KE_KEY,	0x13 | IDEAPAD_WMI_KEY, { KEY_PROG1 } },
1148 	/* Sound profile switch */
1149 	{ KE_KEY,	0x12 | IDEAPAD_WMI_KEY, { KEY_PROG2 } },
1150 	/* Lenovo Virtual Background application */
1151 	{ KE_KEY,	0x28 | IDEAPAD_WMI_KEY, { KEY_PROG3 } },
1152 	/* Lenovo Support */
1153 	{ KE_KEY,	0x27 | IDEAPAD_WMI_KEY, { KEY_HELP } },
1154 	/* Refresh Rate Toggle */
1155 	{ KE_KEY,	0x0a | IDEAPAD_WMI_KEY, { KEY_REFRESH_RATE_TOGGLE } },
1156 
1157 	{ KE_END },
1158 };
1159 
1160 static int ideapad_input_init(struct ideapad_private *priv)
1161 {
1162 	struct input_dev *inputdev;
1163 	int err;
1164 
1165 	inputdev = input_allocate_device();
1166 	if (!inputdev)
1167 		return -ENOMEM;
1168 
1169 	inputdev->name = "Ideapad extra buttons";
1170 	inputdev->phys = "ideapad/input0";
1171 	inputdev->id.bustype = BUS_HOST;
1172 	inputdev->dev.parent = &priv->platform_device->dev;
1173 
1174 	err = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
1175 	if (err) {
1176 		dev_err(&priv->platform_device->dev,
1177 			"Could not set up input device keymap: %d\n", err);
1178 		goto err_free_dev;
1179 	}
1180 
1181 	err = input_register_device(inputdev);
1182 	if (err) {
1183 		dev_err(&priv->platform_device->dev,
1184 			"Could not register input device: %d\n", err);
1185 		goto err_free_dev;
1186 	}
1187 
1188 	priv->inputdev = inputdev;
1189 
1190 	return 0;
1191 
1192 err_free_dev:
1193 	input_free_device(inputdev);
1194 
1195 	return err;
1196 }
1197 
1198 static void ideapad_input_exit(struct ideapad_private *priv)
1199 {
1200 	input_unregister_device(priv->inputdev);
1201 	priv->inputdev = NULL;
1202 }
1203 
1204 static void ideapad_input_report(struct ideapad_private *priv,
1205 				 unsigned long scancode)
1206 {
1207 	sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
1208 }
1209 
1210 static void ideapad_input_novokey(struct ideapad_private *priv)
1211 {
1212 	unsigned long long_pressed;
1213 
1214 	scoped_guard(mutex, &priv->vpc_mutex)
1215 		if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
1216 			return;
1217 
1218 	if (long_pressed)
1219 		ideapad_input_report(priv, 17);
1220 	else
1221 		ideapad_input_report(priv, 16);
1222 }
1223 
1224 static void ideapad_check_special_buttons(struct ideapad_private *priv)
1225 {
1226 	unsigned long bit, value;
1227 
1228 	scoped_guard(mutex, &priv->vpc_mutex)
1229 		if (read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value))
1230 			return;
1231 
1232 	for_each_set_bit (bit, &value, 16) {
1233 		switch (bit) {
1234 		case 6:	/* Z570 */
1235 		case 0:	/* Z580 */
1236 			/* Thermal Management / Performance Mode button */
1237 			if (priv->dytc)
1238 				platform_profile_cycle();
1239 			else
1240 				ideapad_input_report(priv, 65);
1241 			break;
1242 		case 1:
1243 			/* OneKey Theater button */
1244 			ideapad_input_report(priv, 64);
1245 			break;
1246 		default:
1247 			dev_info(&priv->platform_device->dev,
1248 				 "Unknown special button: %lu\n", bit);
1249 			break;
1250 		}
1251 	}
1252 }
1253 
1254 /*
1255  * backlight
1256  */
1257 static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
1258 {
1259 	struct ideapad_private *priv = bl_get_data(blightdev);
1260 	unsigned long now;
1261 	int err;
1262 
1263 	guard(mutex)(&priv->vpc_mutex);
1264 
1265 	err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1266 	if (err)
1267 		return err;
1268 
1269 	return now;
1270 }
1271 
1272 static int ideapad_backlight_update_status(struct backlight_device *blightdev)
1273 {
1274 	struct ideapad_private *priv = bl_get_data(blightdev);
1275 	int err;
1276 
1277 	guard(mutex)(&priv->vpc_mutex);
1278 
1279 	err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
1280 			   blightdev->props.brightness);
1281 	if (err)
1282 		return err;
1283 
1284 	err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL_POWER,
1285 			   blightdev->props.power != FB_BLANK_POWERDOWN);
1286 	if (err)
1287 		return err;
1288 
1289 	return 0;
1290 }
1291 
1292 static const struct backlight_ops ideapad_backlight_ops = {
1293 	.get_brightness = ideapad_backlight_get_brightness,
1294 	.update_status = ideapad_backlight_update_status,
1295 };
1296 
1297 static int ideapad_backlight_init(struct ideapad_private *priv)
1298 {
1299 	struct backlight_device *blightdev;
1300 	struct backlight_properties props;
1301 	unsigned long max, now, power;
1302 	int err;
1303 
1304 	err = read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &max);
1305 	if (err)
1306 		return err;
1307 
1308 	err = read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1309 	if (err)
1310 		return err;
1311 
1312 	err = read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power);
1313 	if (err)
1314 		return err;
1315 
1316 	memset(&props, 0, sizeof(props));
1317 
1318 	props.max_brightness = max;
1319 	props.type = BACKLIGHT_PLATFORM;
1320 
1321 	blightdev = backlight_device_register("ideapad",
1322 					      &priv->platform_device->dev,
1323 					      priv,
1324 					      &ideapad_backlight_ops,
1325 					      &props);
1326 	if (IS_ERR(blightdev)) {
1327 		err = PTR_ERR(blightdev);
1328 		dev_err(&priv->platform_device->dev,
1329 			"Could not register backlight device: %d\n", err);
1330 		return err;
1331 	}
1332 
1333 	priv->blightdev = blightdev;
1334 	blightdev->props.brightness = now;
1335 	blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
1336 
1337 	backlight_update_status(blightdev);
1338 
1339 	return 0;
1340 }
1341 
1342 static void ideapad_backlight_exit(struct ideapad_private *priv)
1343 {
1344 	backlight_device_unregister(priv->blightdev);
1345 	priv->blightdev = NULL;
1346 }
1347 
1348 static void ideapad_backlight_notify_power(struct ideapad_private *priv)
1349 {
1350 	struct backlight_device *blightdev = priv->blightdev;
1351 	unsigned long power;
1352 
1353 	if (!blightdev)
1354 		return;
1355 
1356 	guard(mutex)(&priv->vpc_mutex);
1357 
1358 	if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
1359 		return;
1360 
1361 	blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
1362 }
1363 
1364 static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
1365 {
1366 	unsigned long now;
1367 
1368 	/* if we control brightness via acpi video driver */
1369 	if (!priv->blightdev)
1370 		scoped_guard(mutex, &priv->vpc_mutex)
1371 			read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1372 	else
1373 		backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
1374 }
1375 
1376 /*
1377  * keyboard backlight
1378  */
1379 static int ideapad_kbd_bl_check_tristate(int type)
1380 {
1381 	return (type == KBD_BL_TRISTATE) || (type == KBD_BL_TRISTATE_AUTO);
1382 }
1383 
1384 static int ideapad_kbd_bl_brightness_get(struct ideapad_private *priv)
1385 {
1386 	unsigned long value;
1387 	int err;
1388 
1389 	if (ideapad_kbd_bl_check_tristate(priv->kbd_bl.type)) {
1390 		err = eval_kblc(priv->adev->handle,
1391 				FIELD_PREP(KBD_BL_COMMAND_TYPE, priv->kbd_bl.type) |
1392 				KBD_BL_COMMAND_GET,
1393 				&value);
1394 
1395 		if (err)
1396 			return err;
1397 
1398 		/* Convert returned value to brightness level */
1399 		value = FIELD_GET(KBD_BL_GET_BRIGHTNESS, value);
1400 
1401 		/* Off, low or high */
1402 		if (value <= priv->kbd_bl.led.max_brightness)
1403 			return value;
1404 
1405 		/* Auto, report as off */
1406 		if (value == priv->kbd_bl.led.max_brightness + 1)
1407 			return 0;
1408 
1409 		/* Unknown value */
1410 		dev_warn(&priv->platform_device->dev,
1411 			 "Unknown keyboard backlight value: %lu", value);
1412 		return -EINVAL;
1413 	}
1414 
1415 	err = eval_hals(priv->adev->handle, &value);
1416 	if (err)
1417 		return err;
1418 
1419 	return !!test_bit(HALS_KBD_BL_STATE_BIT, &value);
1420 }
1421 
1422 static enum led_brightness ideapad_kbd_bl_led_cdev_brightness_get(struct led_classdev *led_cdev)
1423 {
1424 	struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led);
1425 
1426 	return ideapad_kbd_bl_brightness_get(priv);
1427 }
1428 
1429 static int ideapad_kbd_bl_brightness_set(struct ideapad_private *priv, unsigned int brightness)
1430 {
1431 	int err;
1432 	unsigned long value;
1433 	int type = priv->kbd_bl.type;
1434 
1435 	if (ideapad_kbd_bl_check_tristate(type)) {
1436 		if (brightness > priv->kbd_bl.led.max_brightness)
1437 			return -EINVAL;
1438 
1439 		value = FIELD_PREP(KBD_BL_SET_BRIGHTNESS, brightness) |
1440 			FIELD_PREP(KBD_BL_COMMAND_TYPE, type) |
1441 			KBD_BL_COMMAND_SET;
1442 		err = exec_kblc(priv->adev->handle, value);
1443 	} else {
1444 		err = exec_sals(priv->adev->handle, brightness ? SALS_KBD_BL_ON : SALS_KBD_BL_OFF);
1445 	}
1446 
1447 	if (err)
1448 		return err;
1449 
1450 	priv->kbd_bl.last_brightness = brightness;
1451 
1452 	return 0;
1453 }
1454 
1455 static int ideapad_kbd_bl_led_cdev_brightness_set(struct led_classdev *led_cdev,
1456 						  enum led_brightness brightness)
1457 {
1458 	struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, kbd_bl.led);
1459 
1460 	return ideapad_kbd_bl_brightness_set(priv, brightness);
1461 }
1462 
1463 static void ideapad_kbd_bl_notify(struct ideapad_private *priv)
1464 {
1465 	int brightness;
1466 
1467 	if (!priv->kbd_bl.initialized)
1468 		return;
1469 
1470 	brightness = ideapad_kbd_bl_brightness_get(priv);
1471 	if (brightness < 0)
1472 		return;
1473 
1474 	if (brightness == priv->kbd_bl.last_brightness)
1475 		return;
1476 
1477 	priv->kbd_bl.last_brightness = brightness;
1478 
1479 	led_classdev_notify_brightness_hw_changed(&priv->kbd_bl.led, brightness);
1480 }
1481 
1482 static int ideapad_kbd_bl_init(struct ideapad_private *priv)
1483 {
1484 	int brightness, err;
1485 
1486 	if (!priv->features.kbd_bl)
1487 		return -ENODEV;
1488 
1489 	if (WARN_ON(priv->kbd_bl.initialized))
1490 		return -EEXIST;
1491 
1492 	if (ideapad_kbd_bl_check_tristate(priv->kbd_bl.type)) {
1493 		priv->kbd_bl.led.max_brightness = 2;
1494 	} else {
1495 		priv->kbd_bl.led.max_brightness = 1;
1496 	}
1497 
1498 	brightness = ideapad_kbd_bl_brightness_get(priv);
1499 	if (brightness < 0)
1500 		return brightness;
1501 
1502 	priv->kbd_bl.last_brightness = brightness;
1503 	priv->kbd_bl.led.name                    = "platform::" LED_FUNCTION_KBD_BACKLIGHT;
1504 	priv->kbd_bl.led.brightness_get          = ideapad_kbd_bl_led_cdev_brightness_get;
1505 	priv->kbd_bl.led.brightness_set_blocking = ideapad_kbd_bl_led_cdev_brightness_set;
1506 	priv->kbd_bl.led.flags                   = LED_BRIGHT_HW_CHANGED;
1507 
1508 	err = led_classdev_register(&priv->platform_device->dev, &priv->kbd_bl.led);
1509 	if (err)
1510 		return err;
1511 
1512 	priv->kbd_bl.initialized = true;
1513 
1514 	return 0;
1515 }
1516 
1517 static void ideapad_kbd_bl_exit(struct ideapad_private *priv)
1518 {
1519 	if (!priv->kbd_bl.initialized)
1520 		return;
1521 
1522 	priv->kbd_bl.initialized = false;
1523 
1524 	led_classdev_unregister(&priv->kbd_bl.led);
1525 }
1526 
1527 /*
1528  * FnLock LED
1529  */
1530 static enum led_brightness ideapad_fn_lock_led_cdev_get(struct led_classdev *led_cdev)
1531 {
1532 	struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, fn_lock.led);
1533 
1534 	return ideapad_fn_lock_get(priv);
1535 }
1536 
1537 static int ideapad_fn_lock_led_cdev_set(struct led_classdev *led_cdev,
1538 	enum led_brightness brightness)
1539 {
1540 	struct ideapad_private *priv = container_of(led_cdev, struct ideapad_private, fn_lock.led);
1541 
1542 	return ideapad_fn_lock_set(priv, brightness);
1543 }
1544 
1545 static int ideapad_fn_lock_led_init(struct ideapad_private *priv)
1546 {
1547 	int brightness, err;
1548 
1549 	if (!priv->features.fn_lock)
1550 		return -ENODEV;
1551 
1552 	if (WARN_ON(priv->fn_lock.initialized))
1553 		return -EEXIST;
1554 
1555 	priv->fn_lock.led.max_brightness = 1;
1556 
1557 	brightness = ideapad_fn_lock_get(priv);
1558 	if (brightness < 0)
1559 		return brightness;
1560 
1561 	priv->fn_lock.last_brightness = brightness;
1562 	priv->fn_lock.led.name                    = "platform::" LED_FUNCTION_FNLOCK;
1563 	priv->fn_lock.led.brightness_get          = ideapad_fn_lock_led_cdev_get;
1564 	priv->fn_lock.led.brightness_set_blocking = ideapad_fn_lock_led_cdev_set;
1565 	priv->fn_lock.led.flags                   = LED_BRIGHT_HW_CHANGED;
1566 
1567 	err = led_classdev_register(&priv->platform_device->dev, &priv->fn_lock.led);
1568 	if (err)
1569 		return err;
1570 
1571 	priv->fn_lock.initialized = true;
1572 
1573 	return 0;
1574 }
1575 
1576 static void ideapad_fn_lock_led_exit(struct ideapad_private *priv)
1577 {
1578 	if (!priv->fn_lock.initialized)
1579 		return;
1580 
1581 	priv->fn_lock.initialized = false;
1582 
1583 	led_classdev_unregister(&priv->fn_lock.led);
1584 }
1585 
1586 /*
1587  * module init/exit
1588  */
1589 static void ideapad_sync_touchpad_state(struct ideapad_private *priv, bool send_events)
1590 {
1591 	unsigned long value;
1592 	unsigned char param;
1593 	int ret;
1594 
1595 	/* Without reading from EC touchpad LED doesn't switch state */
1596 	scoped_guard(mutex, &priv->vpc_mutex)
1597 		ret = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value);
1598 	if (ret)
1599 		return;
1600 
1601 	/*
1602 	 * Some IdeaPads don't really turn off touchpad - they only
1603 	 * switch the LED state. We (de)activate KBC AUX port to turn
1604 	 * touchpad off and on. We send KEY_TOUCHPAD_OFF and
1605 	 * KEY_TOUCHPAD_ON to not to get out of sync with LED
1606 	 */
1607 	if (priv->features.ctrl_ps2_aux_port)
1608 		i8042_command(&param, value ? I8042_CMD_AUX_ENABLE : I8042_CMD_AUX_DISABLE);
1609 
1610 	/*
1611 	 * On older models the EC controls the touchpad and toggles it on/off
1612 	 * itself, in this case we report KEY_TOUCHPAD_ON/_OFF. Some models do
1613 	 * an acpi-notify with VPC bit 5 set on resume, so this function get
1614 	 * called with send_events=true on every resume. Therefor if the EC did
1615 	 * not toggle, do nothing to avoid sending spurious KEY_TOUCHPAD_TOGGLE.
1616 	 */
1617 	if (send_events && value != priv->r_touchpad_val) {
1618 		ideapad_input_report(priv, value ? 67 : 66);
1619 		sysfs_notify(&priv->platform_device->dev.kobj, NULL, "touchpad");
1620 	}
1621 
1622 	priv->r_touchpad_val = value;
1623 }
1624 
1625 static const struct dmi_system_id ymc_ec_trigger_quirk_dmi_table[] = {
1626 	{
1627 		/* Lenovo Yoga 7 14ARB7 */
1628 		.matches = {
1629 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1630 			DMI_MATCH(DMI_PRODUCT_NAME, "82QF"),
1631 		},
1632 	},
1633 	{
1634 		/* Lenovo Yoga 7 14ACN6 */
1635 		.matches = {
1636 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1637 			DMI_MATCH(DMI_PRODUCT_NAME, "82N7"),
1638 		},
1639 	},
1640 	{ }
1641 };
1642 
1643 static void ideapad_laptop_trigger_ec(void)
1644 {
1645 	struct ideapad_private *priv;
1646 	int ret;
1647 
1648 	guard(mutex)(&ideapad_shared_mutex);
1649 
1650 	priv = ideapad_shared;
1651 	if (!priv)
1652 		return;
1653 
1654 	if (!priv->features.ymc_ec_trigger)
1655 		return;
1656 
1657 	scoped_guard(mutex, &priv->vpc_mutex)
1658 		ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_YMC, 1);
1659 	if (ret)
1660 		dev_warn(&priv->platform_device->dev, "Could not write YMC: %d\n", ret);
1661 }
1662 
1663 static int ideapad_laptop_nb_notify(struct notifier_block *nb,
1664 				    unsigned long action, void *data)
1665 {
1666 	switch (action) {
1667 	case IDEAPAD_LAPTOP_YMC_EVENT:
1668 		ideapad_laptop_trigger_ec();
1669 		break;
1670 	}
1671 
1672 	return 0;
1673 }
1674 
1675 static struct notifier_block ideapad_laptop_notifier = {
1676 	.notifier_call = ideapad_laptop_nb_notify,
1677 };
1678 
1679 static BLOCKING_NOTIFIER_HEAD(ideapad_laptop_chain_head);
1680 
1681 int ideapad_laptop_register_notifier(struct notifier_block *nb)
1682 {
1683 	return blocking_notifier_chain_register(&ideapad_laptop_chain_head, nb);
1684 }
1685 EXPORT_SYMBOL_NS_GPL(ideapad_laptop_register_notifier, IDEAPAD_LAPTOP);
1686 
1687 int ideapad_laptop_unregister_notifier(struct notifier_block *nb)
1688 {
1689 	return blocking_notifier_chain_unregister(&ideapad_laptop_chain_head, nb);
1690 }
1691 EXPORT_SYMBOL_NS_GPL(ideapad_laptop_unregister_notifier, IDEAPAD_LAPTOP);
1692 
1693 void ideapad_laptop_call_notifier(unsigned long action, void *data)
1694 {
1695 	blocking_notifier_call_chain(&ideapad_laptop_chain_head, action, data);
1696 }
1697 EXPORT_SYMBOL_NS_GPL(ideapad_laptop_call_notifier, IDEAPAD_LAPTOP);
1698 
1699 static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
1700 {
1701 	struct ideapad_private *priv = data;
1702 	unsigned long vpc1, vpc2, bit;
1703 
1704 	scoped_guard(mutex, &priv->vpc_mutex) {
1705 		if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
1706 			return;
1707 
1708 		if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
1709 			return;
1710 	}
1711 
1712 	vpc1 = (vpc2 << 8) | vpc1;
1713 
1714 	for_each_set_bit (bit, &vpc1, 16) {
1715 		switch (bit) {
1716 		case 13:
1717 		case 11:
1718 		case 8:
1719 		case 7:
1720 		case 6:
1721 			ideapad_input_report(priv, bit);
1722 			break;
1723 		case 10:
1724 			/*
1725 			 * This event gets send on a Yoga 300-11IBR when the EC
1726 			 * believes that the device has changed between laptop/
1727 			 * tent/stand/tablet mode. The EC relies on getting
1728 			 * angle info from 2 accelerometers through a special
1729 			 * windows service calling a DSM on the DUAL250E ACPI-
1730 			 * device. Linux does not do this, making the laptop/
1731 			 * tent/stand/tablet mode info unreliable, so we simply
1732 			 * ignore these events.
1733 			 */
1734 			break;
1735 		case 9:
1736 			ideapad_sync_rfk_state(priv);
1737 			break;
1738 		case 5:
1739 			ideapad_sync_touchpad_state(priv, true);
1740 			break;
1741 		case 4:
1742 			ideapad_backlight_notify_brightness(priv);
1743 			break;
1744 		case 3:
1745 			ideapad_input_novokey(priv);
1746 			break;
1747 		case 2:
1748 			ideapad_backlight_notify_power(priv);
1749 			break;
1750 		case KBD_BL_KBLC_CHANGED_EVENT:
1751 		case 1:
1752 			/*
1753 			 * Some IdeaPads report event 1 every ~20
1754 			 * seconds while on battery power; some
1755 			 * report this when changing to/from tablet
1756 			 * mode; some report this when the keyboard
1757 			 * backlight has changed.
1758 			 */
1759 			ideapad_kbd_bl_notify(priv);
1760 			break;
1761 		case 0:
1762 			ideapad_check_special_buttons(priv);
1763 			break;
1764 		default:
1765 			dev_info(&priv->platform_device->dev,
1766 				 "Unknown event: %lu\n", bit);
1767 		}
1768 	}
1769 }
1770 
1771 /* On some models we need to call exec_sals(SALS_FNLOCK_ON/OFF) to set the LED */
1772 static const struct dmi_system_id set_fn_lock_led_list[] = {
1773 	{
1774 		/* https://bugzilla.kernel.org/show_bug.cgi?id=212671 */
1775 		.matches = {
1776 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1777 			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion R7000P2020H"),
1778 		}
1779 	},
1780 	{
1781 		.matches = {
1782 			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1783 			DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion 5 15ARH05"),
1784 		}
1785 	},
1786 	{}
1787 };
1788 
1789 /*
1790  * Some ideapads have a hardware rfkill switch, but most do not have one.
1791  * Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill,
1792  * switch causing ideapad_laptop to wrongly report all radios as hw-blocked.
1793  * There used to be a long list of DMI ids for models without a hw rfkill
1794  * switch here, but that resulted in playing whack a mole.
1795  * More importantly wrongly reporting the wifi radio as hw-blocked, results in
1796  * non working wifi. Whereas not reporting it hw-blocked, when it actually is
1797  * hw-blocked results in an empty SSID list, which is a much more benign
1798  * failure mode.
1799  * So the default now is the much safer option of assuming there is no
1800  * hardware rfkill switch. This default also actually matches most hardware,
1801  * since having a hw rfkill switch is quite rare on modern hardware, so this
1802  * also leads to a much shorter list.
1803  */
1804 static const struct dmi_system_id hw_rfkill_list[] = {
1805 	{}
1806 };
1807 
1808 /*
1809  * On some models the EC toggles the touchpad muted LED on touchpad toggle
1810  * hotkey presses, but the EC does not actually disable the touchpad itself.
1811  * On these models the driver needs to explicitly enable/disable the i8042
1812  * (PS/2) aux port.
1813  */
1814 static const struct dmi_system_id ctrl_ps2_aux_port_list[] = {
1815 	{
1816 	/* Lenovo Ideapad Z570 */
1817 	.matches = {
1818 		DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1819 		DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"),
1820 		},
1821 	},
1822 	{}
1823 };
1824 
1825 static void ideapad_check_features(struct ideapad_private *priv)
1826 {
1827 	acpi_handle handle = priv->adev->handle;
1828 	unsigned long val;
1829 
1830 	priv->features.set_fn_lock_led =
1831 		set_fn_lock_led || dmi_check_system(set_fn_lock_led_list);
1832 	priv->features.hw_rfkill_switch =
1833 		hw_rfkill_switch || dmi_check_system(hw_rfkill_list);
1834 	priv->features.ctrl_ps2_aux_port =
1835 		ctrl_ps2_aux_port || dmi_check_system(ctrl_ps2_aux_port_list);
1836 	priv->features.touchpad_ctrl_via_ec = touchpad_ctrl_via_ec;
1837 	priv->features.ymc_ec_trigger =
1838 		ymc_ec_trigger || dmi_check_system(ymc_ec_trigger_quirk_dmi_table);
1839 
1840 	if (!read_ec_data(handle, VPCCMD_R_FAN, &val))
1841 		priv->features.fan_mode = true;
1842 
1843 	if (acpi_has_method(handle, "GBMD") && acpi_has_method(handle, "SBMC"))
1844 		priv->features.conservation_mode = true;
1845 
1846 	if (acpi_has_method(handle, "DYTC"))
1847 		priv->features.dytc = true;
1848 
1849 	if (acpi_has_method(handle, "HALS") && acpi_has_method(handle, "SALS")) {
1850 		if (!eval_hals(handle, &val)) {
1851 			if (test_bit(HALS_FNLOCK_SUPPORT_BIT, &val))
1852 				priv->features.fn_lock = true;
1853 
1854 			if (test_bit(HALS_KBD_BL_SUPPORT_BIT, &val)) {
1855 				priv->features.kbd_bl = true;
1856 				priv->kbd_bl.type = KBD_BL_STANDARD;
1857 			}
1858 
1859 			if (test_bit(HALS_USB_CHARGING_SUPPORT_BIT, &val))
1860 				priv->features.usb_charging = true;
1861 		}
1862 	}
1863 
1864 	if (acpi_has_method(handle, "KBLC")) {
1865 		if (!eval_kblc(priv->adev->handle, KBD_BL_QUERY_TYPE, &val)) {
1866 			if (val == KBD_BL_TRISTATE_TYPE) {
1867 				priv->features.kbd_bl = true;
1868 				priv->kbd_bl.type = KBD_BL_TRISTATE;
1869 			} else if (val == KBD_BL_TRISTATE_AUTO_TYPE) {
1870 				priv->features.kbd_bl = true;
1871 				priv->kbd_bl.type = KBD_BL_TRISTATE_AUTO;
1872 			} else {
1873 				dev_warn(&priv->platform_device->dev,
1874 					 "Unknown keyboard type: %lu",
1875 					 val);
1876 			}
1877 		}
1878 	}
1879 }
1880 
1881 #if IS_ENABLED(CONFIG_ACPI_WMI)
1882 /*
1883  * WMI driver
1884  */
1885 enum ideapad_wmi_event_type {
1886 	IDEAPAD_WMI_EVENT_ESC,
1887 	IDEAPAD_WMI_EVENT_FN_KEYS,
1888 };
1889 
1890 struct ideapad_wmi_private {
1891 	enum ideapad_wmi_event_type event;
1892 };
1893 
1894 static int ideapad_wmi_probe(struct wmi_device *wdev, const void *context)
1895 {
1896 	struct ideapad_wmi_private *wpriv;
1897 
1898 	wpriv = devm_kzalloc(&wdev->dev, sizeof(*wpriv), GFP_KERNEL);
1899 	if (!wpriv)
1900 		return -ENOMEM;
1901 
1902 	*wpriv = *(const struct ideapad_wmi_private *)context;
1903 
1904 	dev_set_drvdata(&wdev->dev, wpriv);
1905 	return 0;
1906 }
1907 
1908 static void ideapad_wmi_notify(struct wmi_device *wdev, union acpi_object *data)
1909 {
1910 	struct ideapad_wmi_private *wpriv = dev_get_drvdata(&wdev->dev);
1911 	struct ideapad_private *priv;
1912 
1913 	guard(mutex)(&ideapad_shared_mutex);
1914 
1915 	priv = ideapad_shared;
1916 	if (!priv)
1917 		return;
1918 
1919 	switch (wpriv->event) {
1920 	case IDEAPAD_WMI_EVENT_ESC:
1921 		ideapad_input_report(priv, 128);
1922 		break;
1923 	case IDEAPAD_WMI_EVENT_FN_KEYS:
1924 		if (priv->features.set_fn_lock_led) {
1925 			int brightness = ideapad_fn_lock_get(priv);
1926 
1927 			if (brightness >= 0) {
1928 				ideapad_fn_lock_set(priv, brightness);
1929 				ideapad_fn_lock_led_notify(priv, brightness);
1930 			}
1931 		}
1932 
1933 		if (data->type != ACPI_TYPE_INTEGER) {
1934 			dev_warn(&wdev->dev,
1935 				 "WMI event data is not an integer\n");
1936 			break;
1937 		}
1938 
1939 		dev_dbg(&wdev->dev, "WMI fn-key event: 0x%llx\n",
1940 			data->integer.value);
1941 
1942 		/* 0x02 FnLock, 0x03 Esc */
1943 		if (data->integer.value == 0x02 || data->integer.value == 0x03)
1944 			ideapad_fn_lock_led_notify(priv, data->integer.value == 0x02);
1945 
1946 		ideapad_input_report(priv,
1947 				     data->integer.value | IDEAPAD_WMI_KEY);
1948 
1949 		break;
1950 	}
1951 }
1952 
1953 static const struct ideapad_wmi_private ideapad_wmi_context_esc = {
1954 	.event = IDEAPAD_WMI_EVENT_ESC
1955 };
1956 
1957 static const struct ideapad_wmi_private ideapad_wmi_context_fn_keys = {
1958 	.event = IDEAPAD_WMI_EVENT_FN_KEYS
1959 };
1960 
1961 static const struct wmi_device_id ideapad_wmi_ids[] = {
1962 	{ "26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", &ideapad_wmi_context_esc }, /* Yoga 3 */
1963 	{ "56322276-8493-4CE8-A783-98C991274F5E", &ideapad_wmi_context_esc }, /* Yoga 700 */
1964 	{ "8FC0DE0C-B4E4-43FD-B0F3-8871711C1294", &ideapad_wmi_context_fn_keys }, /* Legion 5 */
1965 	{},
1966 };
1967 MODULE_DEVICE_TABLE(wmi, ideapad_wmi_ids);
1968 
1969 static struct wmi_driver ideapad_wmi_driver = {
1970 	.driver = {
1971 		.name = "ideapad_wmi",
1972 	},
1973 	.id_table = ideapad_wmi_ids,
1974 	.probe = ideapad_wmi_probe,
1975 	.notify = ideapad_wmi_notify,
1976 };
1977 
1978 static int ideapad_wmi_driver_register(void)
1979 {
1980 	return wmi_driver_register(&ideapad_wmi_driver);
1981 }
1982 
1983 static void ideapad_wmi_driver_unregister(void)
1984 {
1985 	return wmi_driver_unregister(&ideapad_wmi_driver);
1986 }
1987 
1988 #else
1989 static inline int ideapad_wmi_driver_register(void) { return 0; }
1990 static inline void ideapad_wmi_driver_unregister(void) { }
1991 #endif
1992 
1993 /*
1994  * ACPI driver
1995  */
1996 static int ideapad_acpi_add(struct platform_device *pdev)
1997 {
1998 	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
1999 	struct ideapad_private *priv;
2000 	acpi_status status;
2001 	unsigned long cfg;
2002 	int err, i;
2003 
2004 	if (!adev || eval_int(adev->handle, "_CFG", &cfg))
2005 		return -ENODEV;
2006 
2007 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
2008 	if (!priv)
2009 		return -ENOMEM;
2010 
2011 	dev_set_drvdata(&pdev->dev, priv);
2012 
2013 	priv->cfg = cfg;
2014 	priv->adev = adev;
2015 	priv->platform_device = pdev;
2016 
2017 	err = devm_mutex_init(&pdev->dev, &priv->vpc_mutex);
2018 	if (err)
2019 		return err;
2020 
2021 	ideapad_check_features(priv);
2022 
2023 	err = ideapad_sysfs_init(priv);
2024 	if (err)
2025 		return err;
2026 
2027 	ideapad_debugfs_init(priv);
2028 
2029 	err = ideapad_input_init(priv);
2030 	if (err)
2031 		goto input_failed;
2032 
2033 	err = ideapad_kbd_bl_init(priv);
2034 	if (err) {
2035 		if (err != -ENODEV)
2036 			dev_warn(&pdev->dev, "Could not set up keyboard backlight LED: %d\n", err);
2037 		else
2038 			dev_info(&pdev->dev, "Keyboard backlight control not available\n");
2039 	}
2040 
2041 	err = ideapad_fn_lock_led_init(priv);
2042 	if (err) {
2043 		if (err != -ENODEV)
2044 			dev_warn(&pdev->dev, "Could not set up FnLock LED: %d\n", err);
2045 		else
2046 			dev_info(&pdev->dev, "FnLock control not available\n");
2047 	}
2048 
2049 	/*
2050 	 * On some models without a hw-switch (the yoga 2 13 at least)
2051 	 * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
2052 	 */
2053 	if (!priv->features.hw_rfkill_switch)
2054 		write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
2055 
2056 	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
2057 		if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
2058 			ideapad_register_rfkill(priv, i);
2059 
2060 	ideapad_sync_rfk_state(priv);
2061 	ideapad_sync_touchpad_state(priv, false);
2062 
2063 	err = ideapad_dytc_profile_init(priv);
2064 	if (err) {
2065 		if (err != -ENODEV)
2066 			dev_warn(&pdev->dev, "Could not set up DYTC interface: %d\n", err);
2067 		else
2068 			dev_info(&pdev->dev, "DYTC interface is not available\n");
2069 	}
2070 
2071 	if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
2072 		err = ideapad_backlight_init(priv);
2073 		if (err && err != -ENODEV)
2074 			goto backlight_failed;
2075 	}
2076 
2077 	status = acpi_install_notify_handler(adev->handle,
2078 					     ACPI_DEVICE_NOTIFY,
2079 					     ideapad_acpi_notify, priv);
2080 	if (ACPI_FAILURE(status)) {
2081 		err = -EIO;
2082 		goto notification_failed;
2083 	}
2084 
2085 	err = ideapad_shared_init(priv);
2086 	if (err)
2087 		goto shared_init_failed;
2088 
2089 	ideapad_laptop_register_notifier(&ideapad_laptop_notifier);
2090 
2091 	return 0;
2092 
2093 shared_init_failed:
2094 	acpi_remove_notify_handler(priv->adev->handle,
2095 				   ACPI_DEVICE_NOTIFY,
2096 				   ideapad_acpi_notify);
2097 
2098 notification_failed:
2099 	ideapad_backlight_exit(priv);
2100 
2101 backlight_failed:
2102 	ideapad_dytc_profile_exit(priv);
2103 
2104 	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
2105 		ideapad_unregister_rfkill(priv, i);
2106 
2107 	ideapad_fn_lock_led_exit(priv);
2108 	ideapad_kbd_bl_exit(priv);
2109 	ideapad_input_exit(priv);
2110 
2111 input_failed:
2112 	ideapad_debugfs_exit(priv);
2113 	ideapad_sysfs_exit(priv);
2114 
2115 	return err;
2116 }
2117 
2118 static void ideapad_acpi_remove(struct platform_device *pdev)
2119 {
2120 	struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
2121 	int i;
2122 
2123 	ideapad_laptop_unregister_notifier(&ideapad_laptop_notifier);
2124 
2125 	ideapad_shared_exit(priv);
2126 
2127 	acpi_remove_notify_handler(priv->adev->handle,
2128 				   ACPI_DEVICE_NOTIFY,
2129 				   ideapad_acpi_notify);
2130 
2131 	ideapad_backlight_exit(priv);
2132 	ideapad_dytc_profile_exit(priv);
2133 
2134 	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
2135 		ideapad_unregister_rfkill(priv, i);
2136 
2137 	ideapad_fn_lock_led_exit(priv);
2138 	ideapad_kbd_bl_exit(priv);
2139 	ideapad_input_exit(priv);
2140 	ideapad_debugfs_exit(priv);
2141 	ideapad_sysfs_exit(priv);
2142 }
2143 
2144 #ifdef CONFIG_PM_SLEEP
2145 static int ideapad_acpi_resume(struct device *dev)
2146 {
2147 	struct ideapad_private *priv = dev_get_drvdata(dev);
2148 
2149 	ideapad_sync_rfk_state(priv);
2150 	ideapad_sync_touchpad_state(priv, false);
2151 
2152 	if (priv->dytc)
2153 		dytc_profile_refresh(priv);
2154 
2155 	return 0;
2156 }
2157 #endif
2158 static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume);
2159 
2160 static const struct acpi_device_id ideapad_device_ids[] = {
2161 	{"VPC2004", 0},
2162 	{"", 0},
2163 };
2164 MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
2165 
2166 static struct platform_driver ideapad_acpi_driver = {
2167 	.probe = ideapad_acpi_add,
2168 	.remove_new = ideapad_acpi_remove,
2169 	.driver = {
2170 		.name   = "ideapad_acpi",
2171 		.pm     = &ideapad_pm,
2172 		.acpi_match_table = ACPI_PTR(ideapad_device_ids),
2173 	},
2174 };
2175 
2176 static int __init ideapad_laptop_init(void)
2177 {
2178 	int err;
2179 
2180 	err = ideapad_wmi_driver_register();
2181 	if (err)
2182 		return err;
2183 
2184 	err = platform_driver_register(&ideapad_acpi_driver);
2185 	if (err) {
2186 		ideapad_wmi_driver_unregister();
2187 		return err;
2188 	}
2189 
2190 	return 0;
2191 }
2192 module_init(ideapad_laptop_init)
2193 
2194 static void __exit ideapad_laptop_exit(void)
2195 {
2196 	ideapad_wmi_driver_unregister();
2197 	platform_driver_unregister(&ideapad_acpi_driver);
2198 }
2199 module_exit(ideapad_laptop_exit)
2200 
2201 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
2202 MODULE_DESCRIPTION("IdeaPad ACPI Extras");
2203 MODULE_LICENSE("GPL");
2204