xref: /linux/drivers/platform/x86/ideapad-laptop.c (revision eabe533904cbcb6c7df530fd807cf2a3c3567d35)
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/kernel.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/types.h>
15 #include <linux/acpi.h>
16 #include <linux/rfkill.h>
17 #include <linux/platform_device.h>
18 #include <linux/platform_profile.h>
19 #include <linux/input.h>
20 #include <linux/input/sparse-keymap.h>
21 #include <linux/backlight.h>
22 #include <linux/fb.h>
23 #include <linux/debugfs.h>
24 #include <linux/seq_file.h>
25 #include <linux/i8042.h>
26 #include <linux/dmi.h>
27 #include <linux/device.h>
28 #include <acpi/video.h>
29 
30 #define IDEAPAD_RFKILL_DEV_NUM	(3)
31 
32 #define BM_CONSERVATION_BIT (5)
33 #define HA_FNLOCK_BIT       (10)
34 
35 #define CFG_BT_BIT	(16)
36 #define CFG_3G_BIT	(17)
37 #define CFG_WIFI_BIT	(18)
38 #define CFG_CAMERA_BIT	(19)
39 
40 #if IS_ENABLED(CONFIG_ACPI_WMI)
41 static const char *const ideapad_wmi_fnesc_events[] = {
42 	"26CAB2E5-5CF1-46AE-AAC3-4A12B6BA50E6", /* Yoga 3 */
43 	"56322276-8493-4CE8-A783-98C991274F5E", /* Yoga 700 */
44 };
45 #endif
46 
47 enum {
48 	BMCMD_CONSERVATION_ON = 3,
49 	BMCMD_CONSERVATION_OFF = 5,
50 	HACMD_FNLOCK_ON = 0xe,
51 	HACMD_FNLOCK_OFF = 0xf,
52 };
53 
54 enum {
55 	VPCCMD_R_VPC1 = 0x10,
56 	VPCCMD_R_BL_MAX,
57 	VPCCMD_R_BL,
58 	VPCCMD_W_BL,
59 	VPCCMD_R_WIFI,
60 	VPCCMD_W_WIFI,
61 	VPCCMD_R_BT,
62 	VPCCMD_W_BT,
63 	VPCCMD_R_BL_POWER,
64 	VPCCMD_R_NOVO,
65 	VPCCMD_R_VPC2,
66 	VPCCMD_R_TOUCHPAD,
67 	VPCCMD_W_TOUCHPAD,
68 	VPCCMD_R_CAMERA,
69 	VPCCMD_W_CAMERA,
70 	VPCCMD_R_3G,
71 	VPCCMD_W_3G,
72 	VPCCMD_R_ODD, /* 0x21 */
73 	VPCCMD_W_FAN,
74 	VPCCMD_R_RF,
75 	VPCCMD_W_RF,
76 	VPCCMD_R_FAN = 0x2B,
77 	VPCCMD_R_SPECIAL_BUTTONS = 0x31,
78 	VPCCMD_W_BL_POWER = 0x33,
79 };
80 
81 struct ideapad_dytc_priv {
82 	enum platform_profile_option current_profile;
83 	struct platform_profile_handler pprof;
84 	struct mutex mutex;
85 	struct ideapad_private *priv;
86 };
87 
88 struct ideapad_rfk_priv {
89 	int dev;
90 	struct ideapad_private *priv;
91 };
92 
93 struct ideapad_private {
94 	struct acpi_device *adev;
95 	struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM];
96 	struct ideapad_rfk_priv rfk_priv[IDEAPAD_RFKILL_DEV_NUM];
97 	struct platform_device *platform_device;
98 	struct input_dev *inputdev;
99 	struct backlight_device *blightdev;
100 	struct ideapad_dytc_priv *dytc;
101 	struct dentry *debug;
102 	unsigned long cfg;
103 	bool has_hw_rfkill_switch;
104 	bool has_touchpad_switch;
105 	const char *fnesc_guid;
106 };
107 
108 static bool no_bt_rfkill;
109 module_param(no_bt_rfkill, bool, 0444);
110 MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
111 
112 /*
113  * ACPI Helpers
114  */
115 #define IDEAPAD_EC_TIMEOUT (200) /* in ms */
116 
117 static int read_method_int(acpi_handle handle, const char *method, int *val)
118 {
119 	acpi_status status;
120 	unsigned long long result;
121 
122 	status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
123 	if (ACPI_FAILURE(status)) {
124 		*val = -1;
125 		return -1;
126 	}
127 	*val = result;
128 	return 0;
129 
130 }
131 
132 static int method_gbmd(acpi_handle handle, unsigned long *ret)
133 {
134 	int result, val;
135 
136 	result = read_method_int(handle, "GBMD", &val);
137 	*ret = val;
138 	return result;
139 }
140 
141 static int method_int1(acpi_handle handle, char *method, int cmd)
142 {
143 	acpi_status status;
144 
145 	status = acpi_execute_simple_method(handle, method, cmd);
146 	return ACPI_FAILURE(status) ? -1 : 0;
147 }
148 
149 static int method_dytc(acpi_handle handle, int cmd, int *ret)
150 {
151 	acpi_status status;
152 	unsigned long long result;
153 	struct acpi_object_list params;
154 	union acpi_object in_obj;
155 
156 	params.count = 1;
157 	params.pointer = &in_obj;
158 	in_obj.type = ACPI_TYPE_INTEGER;
159 	in_obj.integer.value = cmd;
160 
161 	status = acpi_evaluate_integer(handle, "DYTC", &params, &result);
162 
163 	if (ACPI_FAILURE(status)) {
164 		*ret = -1;
165 		return -1;
166 	}
167 	*ret = result;
168 	return 0;
169 }
170 
171 static int method_vpcr(acpi_handle handle, int cmd, int *ret)
172 {
173 	acpi_status status;
174 	unsigned long long result;
175 	struct acpi_object_list params;
176 	union acpi_object in_obj;
177 
178 	params.count = 1;
179 	params.pointer = &in_obj;
180 	in_obj.type = ACPI_TYPE_INTEGER;
181 	in_obj.integer.value = cmd;
182 
183 	status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
184 
185 	if (ACPI_FAILURE(status)) {
186 		*ret = -1;
187 		return -1;
188 	}
189 	*ret = result;
190 	return 0;
191 
192 }
193 
194 static int method_vpcw(acpi_handle handle, int cmd, int data)
195 {
196 	struct acpi_object_list params;
197 	union acpi_object in_obj[2];
198 	acpi_status status;
199 
200 	params.count = 2;
201 	params.pointer = in_obj;
202 	in_obj[0].type = ACPI_TYPE_INTEGER;
203 	in_obj[0].integer.value = cmd;
204 	in_obj[1].type = ACPI_TYPE_INTEGER;
205 	in_obj[1].integer.value = data;
206 
207 	status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
208 	if (status != AE_OK)
209 		return -1;
210 	return 0;
211 }
212 
213 static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
214 {
215 	int val;
216 	unsigned long int end_jiffies;
217 
218 	if (method_vpcw(handle, 1, cmd))
219 		return -1;
220 
221 	for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
222 	     time_before(jiffies, end_jiffies);) {
223 		schedule();
224 		if (method_vpcr(handle, 1, &val))
225 			return -1;
226 		if (val == 0) {
227 			if (method_vpcr(handle, 0, &val))
228 				return -1;
229 			*data = val;
230 			return 0;
231 		}
232 	}
233 	pr_err("timeout in %s\n", __func__);
234 	return -1;
235 }
236 
237 static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
238 {
239 	int val;
240 	unsigned long int end_jiffies;
241 
242 	if (method_vpcw(handle, 0, data))
243 		return -1;
244 	if (method_vpcw(handle, 1, cmd))
245 		return -1;
246 
247 	for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
248 	     time_before(jiffies, end_jiffies);) {
249 		schedule();
250 		if (method_vpcr(handle, 1, &val))
251 			return -1;
252 		if (val == 0)
253 			return 0;
254 	}
255 	pr_err("timeout in %s\n", __func__);
256 	return -1;
257 }
258 
259 /*
260  * debugfs
261  */
262 static int debugfs_status_show(struct seq_file *s, void *data)
263 {
264 	struct ideapad_private *priv = s->private;
265 	unsigned long value;
266 
267 	if (!priv)
268 		return -EINVAL;
269 
270 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &value))
271 		seq_printf(s, "Backlight max:\t%lu\n", value);
272 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL, &value))
273 		seq_printf(s, "Backlight now:\t%lu\n", value);
274 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &value))
275 		seq_printf(s, "BL power value:\t%s\n", value ? "On" : "Off");
276 	seq_printf(s, "=====================\n");
277 
278 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_RF, &value))
279 		seq_printf(s, "Radio status:\t%s(%lu)\n",
280 			   value ? "On" : "Off", value);
281 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_WIFI, &value))
282 		seq_printf(s, "Wifi status:\t%s(%lu)\n",
283 			   value ? "On" : "Off", value);
284 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_BT, &value))
285 		seq_printf(s, "BT status:\t%s(%lu)\n",
286 			   value ? "On" : "Off", value);
287 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_3G, &value))
288 		seq_printf(s, "3G status:\t%s(%lu)\n",
289 			   value ? "On" : "Off", value);
290 	seq_printf(s, "=====================\n");
291 
292 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value))
293 		seq_printf(s, "Touchpad status:%s(%lu)\n",
294 			   value ? "On" : "Off", value);
295 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &value))
296 		seq_printf(s, "Camera status:\t%s(%lu)\n",
297 			   value ? "On" : "Off", value);
298 	seq_puts(s, "=====================\n");
299 
300 	if (!method_gbmd(priv->adev->handle, &value)) {
301 		seq_printf(s, "Conservation mode:\t%s(%lu)\n",
302 			   test_bit(BM_CONSERVATION_BIT, &value) ? "On" : "Off",
303 			   value);
304 	}
305 
306 	return 0;
307 }
308 DEFINE_SHOW_ATTRIBUTE(debugfs_status);
309 
310 static int debugfs_cfg_show(struct seq_file *s, void *data)
311 {
312 	struct ideapad_private *priv = s->private;
313 
314 	if (!priv) {
315 		seq_printf(s, "cfg: N/A\n");
316 	} else {
317 		seq_printf(s, "cfg: 0x%.8lX\n\nCapability: ",
318 			   priv->cfg);
319 		if (test_bit(CFG_BT_BIT, &priv->cfg))
320 			seq_printf(s, "Bluetooth ");
321 		if (test_bit(CFG_3G_BIT, &priv->cfg))
322 			seq_printf(s, "3G ");
323 		if (test_bit(CFG_WIFI_BIT, &priv->cfg))
324 			seq_printf(s, "Wireless ");
325 		if (test_bit(CFG_CAMERA_BIT, &priv->cfg))
326 			seq_printf(s, "Camera ");
327 		seq_printf(s, "\nGraphic: ");
328 		switch ((priv->cfg)&0x700) {
329 		case 0x100:
330 			seq_printf(s, "Intel");
331 			break;
332 		case 0x200:
333 			seq_printf(s, "ATI");
334 			break;
335 		case 0x300:
336 			seq_printf(s, "Nvidia");
337 			break;
338 		case 0x400:
339 			seq_printf(s, "Intel and ATI");
340 			break;
341 		case 0x500:
342 			seq_printf(s, "Intel and Nvidia");
343 			break;
344 		}
345 		seq_printf(s, "\n");
346 	}
347 	return 0;
348 }
349 DEFINE_SHOW_ATTRIBUTE(debugfs_cfg);
350 
351 static void ideapad_debugfs_init(struct ideapad_private *priv)
352 {
353 	struct dentry *dir;
354 
355 	dir = debugfs_create_dir("ideapad", NULL);
356 	priv->debug = dir;
357 
358 	debugfs_create_file("cfg", S_IRUGO, dir, priv, &debugfs_cfg_fops);
359 	debugfs_create_file("status", S_IRUGO, dir, priv, &debugfs_status_fops);
360 }
361 
362 static void ideapad_debugfs_exit(struct ideapad_private *priv)
363 {
364 	debugfs_remove_recursive(priv->debug);
365 	priv->debug = NULL;
366 }
367 
368 /*
369  * sysfs
370  */
371 static ssize_t show_ideapad_cam(struct device *dev,
372 				struct device_attribute *attr,
373 				char *buf)
374 {
375 	unsigned long result;
376 	struct ideapad_private *priv = dev_get_drvdata(dev);
377 
378 	if (read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result))
379 		return sprintf(buf, "-1\n");
380 	return sprintf(buf, "%lu\n", result);
381 }
382 
383 static ssize_t store_ideapad_cam(struct device *dev,
384 				 struct device_attribute *attr,
385 				 const char *buf, size_t count)
386 {
387 	int ret, state;
388 	struct ideapad_private *priv = dev_get_drvdata(dev);
389 
390 	if (!count)
391 		return 0;
392 	if (sscanf(buf, "%i", &state) != 1)
393 		return -EINVAL;
394 	ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
395 	if (ret < 0)
396 		return -EIO;
397 	return count;
398 }
399 
400 static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
401 
402 static ssize_t show_ideapad_fan(struct device *dev,
403 				struct device_attribute *attr,
404 				char *buf)
405 {
406 	unsigned long result;
407 	struct ideapad_private *priv = dev_get_drvdata(dev);
408 
409 	if (read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result))
410 		return sprintf(buf, "-1\n");
411 	return sprintf(buf, "%lu\n", result);
412 }
413 
414 static ssize_t store_ideapad_fan(struct device *dev,
415 				 struct device_attribute *attr,
416 				 const char *buf, size_t count)
417 {
418 	int ret, state;
419 	struct ideapad_private *priv = dev_get_drvdata(dev);
420 
421 	if (!count)
422 		return 0;
423 	if (sscanf(buf, "%i", &state) != 1)
424 		return -EINVAL;
425 	if (state < 0 || state > 4 || state == 3)
426 		return -EINVAL;
427 	ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
428 	if (ret < 0)
429 		return -EIO;
430 	return count;
431 }
432 
433 static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan);
434 
435 static ssize_t touchpad_show(struct device *dev,
436 			     struct device_attribute *attr,
437 			     char *buf)
438 {
439 	struct ideapad_private *priv = dev_get_drvdata(dev);
440 	unsigned long result;
441 
442 	if (read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result))
443 		return sprintf(buf, "-1\n");
444 	return sprintf(buf, "%lu\n", result);
445 }
446 
447 /* Switch to RO for now: It might be revisited in the future */
448 static ssize_t __maybe_unused touchpad_store(struct device *dev,
449 					     struct device_attribute *attr,
450 					     const char *buf, size_t count)
451 {
452 	struct ideapad_private *priv = dev_get_drvdata(dev);
453 	bool state;
454 	int ret;
455 
456 	ret = kstrtobool(buf, &state);
457 	if (ret)
458 		return ret;
459 
460 	ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
461 	if (ret < 0)
462 		return -EIO;
463 	return count;
464 }
465 
466 static DEVICE_ATTR_RO(touchpad);
467 
468 static ssize_t conservation_mode_show(struct device *dev,
469 				struct device_attribute *attr,
470 				char *buf)
471 {
472 	struct ideapad_private *priv = dev_get_drvdata(dev);
473 	unsigned long result;
474 
475 	if (method_gbmd(priv->adev->handle, &result))
476 		return sprintf(buf, "-1\n");
477 	return sprintf(buf, "%u\n", test_bit(BM_CONSERVATION_BIT, &result));
478 }
479 
480 static ssize_t conservation_mode_store(struct device *dev,
481 				 struct device_attribute *attr,
482 				 const char *buf, size_t count)
483 {
484 	struct ideapad_private *priv = dev_get_drvdata(dev);
485 	bool state;
486 	int ret;
487 
488 	ret = kstrtobool(buf, &state);
489 	if (ret)
490 		return ret;
491 
492 	ret = method_int1(priv->adev->handle, "SBMC", state ?
493 					      BMCMD_CONSERVATION_ON :
494 					      BMCMD_CONSERVATION_OFF);
495 	if (ret < 0)
496 		return -EIO;
497 	return count;
498 }
499 
500 static DEVICE_ATTR_RW(conservation_mode);
501 
502 static ssize_t fn_lock_show(struct device *dev,
503 			    struct device_attribute *attr,
504 			    char *buf)
505 {
506 	struct ideapad_private *priv = dev_get_drvdata(dev);
507 	unsigned long result;
508 	int hals;
509 	int fail = read_method_int(priv->adev->handle, "HALS", &hals);
510 
511 	if (fail)
512 		return sprintf(buf, "-1\n");
513 
514 	result = hals;
515 	return sprintf(buf, "%u\n", test_bit(HA_FNLOCK_BIT, &result));
516 }
517 
518 static ssize_t fn_lock_store(struct device *dev,
519 			     struct device_attribute *attr,
520 			     const char *buf, size_t count)
521 {
522 	struct ideapad_private *priv = dev_get_drvdata(dev);
523 	bool state;
524 	int ret;
525 
526 	ret = kstrtobool(buf, &state);
527 	if (ret)
528 		return ret;
529 
530 	ret = method_int1(priv->adev->handle, "SALS", state ?
531 			  HACMD_FNLOCK_ON :
532 			  HACMD_FNLOCK_OFF);
533 	if (ret < 0)
534 		return -EIO;
535 	return count;
536 }
537 
538 static DEVICE_ATTR_RW(fn_lock);
539 
540 
541 static struct attribute *ideapad_attributes[] = {
542 	&dev_attr_camera_power.attr,
543 	&dev_attr_fan_mode.attr,
544 	&dev_attr_touchpad.attr,
545 	&dev_attr_conservation_mode.attr,
546 	&dev_attr_fn_lock.attr,
547 	NULL
548 };
549 
550 static umode_t ideapad_is_visible(struct kobject *kobj,
551 				 struct attribute *attr,
552 				 int idx)
553 {
554 	struct device *dev = container_of(kobj, struct device, kobj);
555 	struct ideapad_private *priv = dev_get_drvdata(dev);
556 	bool supported;
557 
558 	if (attr == &dev_attr_camera_power.attr)
559 		supported = test_bit(CFG_CAMERA_BIT, &(priv->cfg));
560 	else if (attr == &dev_attr_fan_mode.attr) {
561 		unsigned long value;
562 		supported = !read_ec_data(priv->adev->handle, VPCCMD_R_FAN,
563 					  &value);
564 	} else if (attr == &dev_attr_conservation_mode.attr) {
565 		supported = acpi_has_method(priv->adev->handle, "GBMD") &&
566 			    acpi_has_method(priv->adev->handle, "SBMC");
567 	} else if (attr == &dev_attr_fn_lock.attr) {
568 		supported = acpi_has_method(priv->adev->handle, "HALS") &&
569 			acpi_has_method(priv->adev->handle, "SALS");
570 	} else if (attr == &dev_attr_touchpad.attr)
571 		supported = priv->has_touchpad_switch;
572 	else
573 		supported = true;
574 
575 	return supported ? attr->mode : 0;
576 }
577 
578 static const struct attribute_group ideapad_attribute_group = {
579 	.is_visible = ideapad_is_visible,
580 	.attrs = ideapad_attributes
581 };
582 
583 /*
584  * DYTC Platform profile
585  */
586 #define DYTC_CMD_QUERY        0 /* To get DYTC status - enable/revision */
587 #define DYTC_CMD_SET          1 /* To enable/disable IC function mode */
588 #define DYTC_CMD_GET          2 /* To get current IC function and mode */
589 #define DYTC_CMD_RESET    0x1ff /* To reset back to default */
590 
591 #define DYTC_QUERY_ENABLE_BIT 8  /* Bit        8 - 0 = disabled, 1 = enabled */
592 #define DYTC_QUERY_SUBREV_BIT 16 /* Bits 16 - 27 - sub revision */
593 #define DYTC_QUERY_REV_BIT    28 /* Bits 28 - 31 - revision */
594 
595 #define DYTC_GET_FUNCTION_BIT 8  /* Bits  8-11 - function setting */
596 #define DYTC_GET_MODE_BIT     12 /* Bits 12-15 - mode setting */
597 
598 #define DYTC_SET_FUNCTION_BIT 12 /* Bits 12-15 - function setting */
599 #define DYTC_SET_MODE_BIT     16 /* Bits 16-19 - mode setting */
600 #define DYTC_SET_VALID_BIT    20 /* Bit     20 - 1 = on, 0 = off */
601 
602 #define DYTC_FUNCTION_STD     0  /* Function = 0, standard mode */
603 #define DYTC_FUNCTION_CQL     1  /* Function = 1, lap mode */
604 #define DYTC_FUNCTION_MMC     11 /* Function = 11, desk mode */
605 
606 #define DYTC_MODE_PERFORM     2  /* High power mode aka performance */
607 #define DYTC_MODE_LOW_POWER       3  /* Low power mode aka quiet */
608 #define DYTC_MODE_BALANCE   0xF  /* Default mode aka balanced */
609 
610 #define DYTC_SET_COMMAND(function, mode, on) \
611 	(DYTC_CMD_SET | (function) << DYTC_SET_FUNCTION_BIT | \
612 	 (mode) << DYTC_SET_MODE_BIT | \
613 	 (on) << DYTC_SET_VALID_BIT)
614 
615 #define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0)
616 
617 #define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1)
618 
619 static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
620 {
621 	switch (dytcmode) {
622 	case DYTC_MODE_LOW_POWER:
623 		*profile = PLATFORM_PROFILE_LOW_POWER;
624 		break;
625 	case DYTC_MODE_BALANCE:
626 		*profile =  PLATFORM_PROFILE_BALANCED;
627 		break;
628 	case DYTC_MODE_PERFORM:
629 		*profile =  PLATFORM_PROFILE_PERFORMANCE;
630 		break;
631 	default: /* Unknown mode */
632 		return -EINVAL;
633 	}
634 	return 0;
635 }
636 
637 static int convert_profile_to_dytc(enum platform_profile_option profile, int *perfmode)
638 {
639 	switch (profile) {
640 	case PLATFORM_PROFILE_LOW_POWER:
641 		*perfmode = DYTC_MODE_LOW_POWER;
642 		break;
643 	case PLATFORM_PROFILE_BALANCED:
644 		*perfmode = DYTC_MODE_BALANCE;
645 		break;
646 	case PLATFORM_PROFILE_PERFORMANCE:
647 		*perfmode = DYTC_MODE_PERFORM;
648 		break;
649 	default: /* Unknown profile */
650 		return -EOPNOTSUPP;
651 	}
652 	return 0;
653 }
654 
655 /*
656  * dytc_profile_get: Function to register with platform_profile
657  * handler. Returns current platform profile.
658  */
659 int dytc_profile_get(struct platform_profile_handler *pprof,
660 			enum platform_profile_option *profile)
661 {
662 	struct ideapad_dytc_priv *dytc;
663 
664 	dytc = container_of(pprof, struct ideapad_dytc_priv, pprof);
665 	*profile = dytc->current_profile;
666 	return 0;
667 }
668 
669 /*
670  * Helper function - check if we are in CQL mode and if we are
671  *  -  disable CQL,
672  *  - run the command
673  *  - enable CQL
674  *  If not in CQL mode, just run the command
675  */
676 int dytc_cql_command(struct ideapad_private *priv, int command, int *output)
677 {
678 	int err, cmd_err, dummy;
679 	int cur_funcmode;
680 
681 	/* Determine if we are in CQL mode. This alters the commands we do */
682 	err = method_dytc(priv->adev->handle, DYTC_CMD_GET, output);
683 	if (err)
684 		return err;
685 
686 	cur_funcmode = (*output >> DYTC_GET_FUNCTION_BIT) & 0xF;
687 	/* Check if we're OK to return immediately */
688 	if ((command == DYTC_CMD_GET) && (cur_funcmode != DYTC_FUNCTION_CQL))
689 		return 0;
690 
691 	if (cur_funcmode == DYTC_FUNCTION_CQL) {
692 		err = method_dytc(priv->adev->handle, DYTC_DISABLE_CQL, &dummy);
693 		if (err)
694 			return err;
695 	}
696 
697 	cmd_err = method_dytc(priv->adev->handle, command,	output);
698 	/* Check return condition after we've restored CQL state */
699 
700 	if (cur_funcmode == DYTC_FUNCTION_CQL) {
701 		err = method_dytc(priv->adev->handle, DYTC_ENABLE_CQL, &dummy);
702 		if (err)
703 			return err;
704 	}
705 
706 	return cmd_err;
707 }
708 
709 /*
710  * dytc_profile_set: Function to register with platform_profile
711  * handler. Sets current platform profile.
712  */
713 int dytc_profile_set(struct platform_profile_handler *pprof,
714 			enum platform_profile_option profile)
715 {
716 	struct ideapad_dytc_priv *dytc;
717 	struct ideapad_private *priv;
718 	int output;
719 	int err;
720 
721 	dytc = container_of(pprof, struct ideapad_dytc_priv, pprof);
722 	priv = dytc->priv;
723 
724 	err = mutex_lock_interruptible(&dytc->mutex);
725 	if (err)
726 		return err;
727 
728 	if (profile == PLATFORM_PROFILE_BALANCED) {
729 		/* To get back to balanced mode we just issue a reset command */
730 		err = method_dytc(priv->adev->handle, DYTC_CMD_RESET, &output);
731 		if (err)
732 			goto unlock;
733 	} else {
734 		int perfmode;
735 
736 		err = convert_profile_to_dytc(profile, &perfmode);
737 		if (err)
738 			goto unlock;
739 
740 		/* Determine if we are in CQL mode. This alters the commands we do */
741 		err = dytc_cql_command(priv,
742 				DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1),
743 				&output);
744 		if (err)
745 			goto unlock;
746 	}
747 	/* Success - update current profile */
748 	dytc->current_profile = profile;
749 unlock:
750 	mutex_unlock(&dytc->mutex);
751 	return err;
752 }
753 
754 static void dytc_profile_refresh(struct ideapad_private *priv)
755 {
756 	enum platform_profile_option profile;
757 	int output, err;
758 	int perfmode;
759 
760 	mutex_lock(&priv->dytc->mutex);
761 	err = dytc_cql_command(priv, DYTC_CMD_GET, &output);
762 	mutex_unlock(&priv->dytc->mutex);
763 	if (err)
764 		return;
765 
766 	perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF;
767 	convert_dytc_to_profile(perfmode, &profile);
768 	if (profile != priv->dytc->current_profile) {
769 		priv->dytc->current_profile = profile;
770 		platform_profile_notify();
771 	}
772 }
773 
774 static int ideapad_dytc_profile_init(struct ideapad_private *priv)
775 {
776 	int err, output, dytc_version;
777 
778 	err = method_dytc(priv->adev->handle, DYTC_CMD_QUERY, &output);
779 	/* For all other errors we can flag the failure */
780 	if (err)
781 		return err;
782 
783 	/* Check DYTC is enabled and supports mode setting */
784 	if (!(output & BIT(DYTC_QUERY_ENABLE_BIT)))
785 		return -ENODEV;
786 
787 	dytc_version = (output >> DYTC_QUERY_REV_BIT) & 0xF;
788 	if (dytc_version < 5)
789 		return -ENODEV;
790 
791 	priv->dytc = kzalloc(sizeof(struct ideapad_dytc_priv), GFP_KERNEL);
792 	if (!priv->dytc)
793 		return -ENOMEM;
794 
795 	mutex_init(&priv->dytc->mutex);
796 
797 	priv->dytc->priv = priv;
798 	priv->dytc->pprof.profile_get = dytc_profile_get;
799 	priv->dytc->pprof.profile_set = dytc_profile_set;
800 
801 	/* Setup supported modes */
802 	set_bit(PLATFORM_PROFILE_LOW_POWER, priv->dytc->pprof.choices);
803 	set_bit(PLATFORM_PROFILE_BALANCED, priv->dytc->pprof.choices);
804 	set_bit(PLATFORM_PROFILE_PERFORMANCE, priv->dytc->pprof.choices);
805 
806 	/* Create platform_profile structure and register */
807 	err = platform_profile_register(&priv->dytc->pprof);
808 	if (err)
809 		goto mutex_destroy;
810 
811 	/* Ensure initial values are correct */
812 	dytc_profile_refresh(priv);
813 
814 	return 0;
815 
816 mutex_destroy:
817 	mutex_destroy(&priv->dytc->mutex);
818 	kfree(priv->dytc);
819 	priv->dytc = NULL;
820 	return err;
821 }
822 
823 static void ideapad_dytc_profile_exit(struct ideapad_private *priv)
824 {
825 	if (!priv->dytc)
826 		return;
827 
828 	platform_profile_remove();
829 	mutex_destroy(&priv->dytc->mutex);
830 	kfree(priv->dytc);
831 	priv->dytc = NULL;
832 }
833 
834 /*
835  * Rfkill
836  */
837 struct ideapad_rfk_data {
838 	char *name;
839 	int cfgbit;
840 	int opcode;
841 	int type;
842 };
843 
844 static const struct ideapad_rfk_data ideapad_rfk_data[] = {
845 	{ "ideapad_wlan",    CFG_WIFI_BIT, VPCCMD_W_WIFI, RFKILL_TYPE_WLAN },
846 	{ "ideapad_bluetooth", CFG_BT_BIT, VPCCMD_W_BT, RFKILL_TYPE_BLUETOOTH },
847 	{ "ideapad_3g",        CFG_3G_BIT, VPCCMD_W_3G, RFKILL_TYPE_WWAN },
848 };
849 
850 static int ideapad_rfk_set(void *data, bool blocked)
851 {
852 	struct ideapad_rfk_priv *priv = data;
853 	int opcode = ideapad_rfk_data[priv->dev].opcode;
854 
855 	return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
856 }
857 
858 static const struct rfkill_ops ideapad_rfk_ops = {
859 	.set_block = ideapad_rfk_set,
860 };
861 
862 static void ideapad_sync_rfk_state(struct ideapad_private *priv)
863 {
864 	unsigned long hw_blocked = 0;
865 	int i;
866 
867 	if (priv->has_hw_rfkill_switch) {
868 		if (read_ec_data(priv->adev->handle, VPCCMD_R_RF, &hw_blocked))
869 			return;
870 		hw_blocked = !hw_blocked;
871 	}
872 
873 	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
874 		if (priv->rfk[i])
875 			rfkill_set_hw_state(priv->rfk[i], hw_blocked);
876 }
877 
878 static int ideapad_register_rfkill(struct ideapad_private *priv, int dev)
879 {
880 	int ret;
881 	unsigned long sw_blocked;
882 
883 	if (no_bt_rfkill &&
884 	    (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) {
885 		/* Force to enable bluetooth when no_bt_rfkill=1 */
886 		write_ec_cmd(priv->adev->handle,
887 			     ideapad_rfk_data[dev].opcode, 1);
888 		return 0;
889 	}
890 	priv->rfk_priv[dev].dev = dev;
891 	priv->rfk_priv[dev].priv = priv;
892 
893 	priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name,
894 				      &priv->platform_device->dev,
895 				      ideapad_rfk_data[dev].type,
896 				      &ideapad_rfk_ops,
897 				      &priv->rfk_priv[dev]);
898 	if (!priv->rfk[dev])
899 		return -ENOMEM;
900 
901 	if (read_ec_data(priv->adev->handle, ideapad_rfk_data[dev].opcode-1,
902 			 &sw_blocked)) {
903 		rfkill_init_sw_state(priv->rfk[dev], 0);
904 	} else {
905 		sw_blocked = !sw_blocked;
906 		rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
907 	}
908 
909 	ret = rfkill_register(priv->rfk[dev]);
910 	if (ret) {
911 		rfkill_destroy(priv->rfk[dev]);
912 		return ret;
913 	}
914 	return 0;
915 }
916 
917 static void ideapad_unregister_rfkill(struct ideapad_private *priv, int dev)
918 {
919 	if (!priv->rfk[dev])
920 		return;
921 
922 	rfkill_unregister(priv->rfk[dev]);
923 	rfkill_destroy(priv->rfk[dev]);
924 }
925 
926 /*
927  * Platform device
928  */
929 static int ideapad_sysfs_init(struct ideapad_private *priv)
930 {
931 	return sysfs_create_group(&priv->platform_device->dev.kobj,
932 				    &ideapad_attribute_group);
933 }
934 
935 static void ideapad_sysfs_exit(struct ideapad_private *priv)
936 {
937 	sysfs_remove_group(&priv->platform_device->dev.kobj,
938 			   &ideapad_attribute_group);
939 }
940 
941 /*
942  * input device
943  */
944 static const struct key_entry ideapad_keymap[] = {
945 	{ KE_KEY, 6,  { KEY_SWITCHVIDEOMODE } },
946 	{ KE_KEY, 7,  { KEY_CAMERA } },
947 	{ KE_KEY, 8,  { KEY_MICMUTE } },
948 	{ KE_KEY, 11, { KEY_F16 } },
949 	{ KE_KEY, 13, { KEY_WLAN } },
950 	{ KE_KEY, 16, { KEY_PROG1 } },
951 	{ KE_KEY, 17, { KEY_PROG2 } },
952 	{ KE_KEY, 64, { KEY_PROG3 } },
953 	{ KE_KEY, 65, { KEY_PROG4 } },
954 	{ KE_KEY, 66, { KEY_TOUCHPAD_OFF } },
955 	{ KE_KEY, 67, { KEY_TOUCHPAD_ON } },
956 	{ KE_KEY, 128, { KEY_ESC } },
957 
958 	{ KE_END, 0 },
959 };
960 
961 static int ideapad_input_init(struct ideapad_private *priv)
962 {
963 	struct input_dev *inputdev;
964 	int error;
965 
966 	inputdev = input_allocate_device();
967 	if (!inputdev)
968 		return -ENOMEM;
969 
970 	inputdev->name = "Ideapad extra buttons";
971 	inputdev->phys = "ideapad/input0";
972 	inputdev->id.bustype = BUS_HOST;
973 	inputdev->dev.parent = &priv->platform_device->dev;
974 
975 	error = sparse_keymap_setup(inputdev, ideapad_keymap, NULL);
976 	if (error) {
977 		pr_err("Unable to setup input device keymap\n");
978 		goto err_free_dev;
979 	}
980 
981 	error = input_register_device(inputdev);
982 	if (error) {
983 		pr_err("Unable to register input device\n");
984 		goto err_free_dev;
985 	}
986 
987 	priv->inputdev = inputdev;
988 	return 0;
989 
990 err_free_dev:
991 	input_free_device(inputdev);
992 	return error;
993 }
994 
995 static void ideapad_input_exit(struct ideapad_private *priv)
996 {
997 	input_unregister_device(priv->inputdev);
998 	priv->inputdev = NULL;
999 }
1000 
1001 static void ideapad_input_report(struct ideapad_private *priv,
1002 				 unsigned long scancode)
1003 {
1004 	sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
1005 }
1006 
1007 static void ideapad_input_novokey(struct ideapad_private *priv)
1008 {
1009 	unsigned long long_pressed;
1010 
1011 	if (read_ec_data(priv->adev->handle, VPCCMD_R_NOVO, &long_pressed))
1012 		return;
1013 	if (long_pressed)
1014 		ideapad_input_report(priv, 17);
1015 	else
1016 		ideapad_input_report(priv, 16);
1017 }
1018 
1019 static void ideapad_check_special_buttons(struct ideapad_private *priv)
1020 {
1021 	unsigned long bit, value;
1022 
1023 	read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value);
1024 
1025 	for (bit = 0; bit < 16; bit++) {
1026 		if (test_bit(bit, &value)) {
1027 			switch (bit) {
1028 			case 0:	/* Z580 */
1029 			case 6:	/* Z570 */
1030 				/* Thermal Management button */
1031 				ideapad_input_report(priv, 65);
1032 				break;
1033 			case 1:
1034 				/* OneKey Theater button */
1035 				ideapad_input_report(priv, 64);
1036 				break;
1037 			default:
1038 				pr_info("Unknown special button: %lu\n", bit);
1039 				break;
1040 			}
1041 		}
1042 	}
1043 }
1044 
1045 /*
1046  * backlight
1047  */
1048 static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
1049 {
1050 	struct ideapad_private *priv = bl_get_data(blightdev);
1051 	unsigned long now;
1052 
1053 	if (!priv)
1054 		return -EINVAL;
1055 
1056 	if (read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now))
1057 		return -EIO;
1058 	return now;
1059 }
1060 
1061 static int ideapad_backlight_update_status(struct backlight_device *blightdev)
1062 {
1063 	struct ideapad_private *priv = bl_get_data(blightdev);
1064 
1065 	if (!priv)
1066 		return -EINVAL;
1067 
1068 	if (write_ec_cmd(priv->adev->handle, VPCCMD_W_BL,
1069 			 blightdev->props.brightness))
1070 		return -EIO;
1071 	if (write_ec_cmd(priv->adev->handle, VPCCMD_W_BL_POWER,
1072 			 blightdev->props.power == FB_BLANK_POWERDOWN ? 0 : 1))
1073 		return -EIO;
1074 
1075 	return 0;
1076 }
1077 
1078 static const struct backlight_ops ideapad_backlight_ops = {
1079 	.get_brightness = ideapad_backlight_get_brightness,
1080 	.update_status = ideapad_backlight_update_status,
1081 };
1082 
1083 static int ideapad_backlight_init(struct ideapad_private *priv)
1084 {
1085 	struct backlight_device *blightdev;
1086 	struct backlight_properties props;
1087 	unsigned long max, now, power;
1088 
1089 	if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_MAX, &max))
1090 		return -EIO;
1091 	if (read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now))
1092 		return -EIO;
1093 	if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
1094 		return -EIO;
1095 
1096 	memset(&props, 0, sizeof(struct backlight_properties));
1097 	props.max_brightness = max;
1098 	props.type = BACKLIGHT_PLATFORM;
1099 	blightdev = backlight_device_register("ideapad",
1100 					      &priv->platform_device->dev,
1101 					      priv,
1102 					      &ideapad_backlight_ops,
1103 					      &props);
1104 	if (IS_ERR(blightdev)) {
1105 		pr_err("Could not register backlight device\n");
1106 		return PTR_ERR(blightdev);
1107 	}
1108 
1109 	priv->blightdev = blightdev;
1110 	blightdev->props.brightness = now;
1111 	blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
1112 	backlight_update_status(blightdev);
1113 
1114 	return 0;
1115 }
1116 
1117 static void ideapad_backlight_exit(struct ideapad_private *priv)
1118 {
1119 	backlight_device_unregister(priv->blightdev);
1120 	priv->blightdev = NULL;
1121 }
1122 
1123 static void ideapad_backlight_notify_power(struct ideapad_private *priv)
1124 {
1125 	unsigned long power;
1126 	struct backlight_device *blightdev = priv->blightdev;
1127 
1128 	if (!blightdev)
1129 		return;
1130 	if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
1131 		return;
1132 	blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
1133 }
1134 
1135 static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
1136 {
1137 	unsigned long now;
1138 
1139 	/* if we control brightness via acpi video driver */
1140 	if (priv->blightdev == NULL) {
1141 		read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now);
1142 		return;
1143 	}
1144 
1145 	backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
1146 }
1147 
1148 /*
1149  * module init/exit
1150  */
1151 static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
1152 {
1153 	unsigned long value;
1154 
1155 	if (!priv->has_touchpad_switch)
1156 		return;
1157 
1158 	/* Without reading from EC touchpad LED doesn't switch state */
1159 	if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) {
1160 		/* Some IdeaPads don't really turn off touchpad - they only
1161 		 * switch the LED state. We (de)activate KBC AUX port to turn
1162 		 * touchpad off and on. We send KEY_TOUCHPAD_OFF and
1163 		 * KEY_TOUCHPAD_ON to not to get out of sync with LED */
1164 		unsigned char param;
1165 		i8042_command(&param, value ? I8042_CMD_AUX_ENABLE :
1166 			      I8042_CMD_AUX_DISABLE);
1167 		ideapad_input_report(priv, value ? 67 : 66);
1168 	}
1169 }
1170 
1171 static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
1172 {
1173 	struct ideapad_private *priv = data;
1174 	unsigned long vpc1, vpc2, vpc_bit;
1175 
1176 	if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
1177 		return;
1178 	if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
1179 		return;
1180 
1181 	vpc1 = (vpc2 << 8) | vpc1;
1182 	for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
1183 		if (test_bit(vpc_bit, &vpc1)) {
1184 			switch (vpc_bit) {
1185 			case 9:
1186 				ideapad_sync_rfk_state(priv);
1187 				break;
1188 			case 13:
1189 			case 11:
1190 			case 8:
1191 			case 7:
1192 			case 6:
1193 				ideapad_input_report(priv, vpc_bit);
1194 				break;
1195 			case 5:
1196 				ideapad_sync_touchpad_state(priv);
1197 				break;
1198 			case 4:
1199 				ideapad_backlight_notify_brightness(priv);
1200 				break;
1201 			case 3:
1202 				ideapad_input_novokey(priv);
1203 				break;
1204 			case 2:
1205 				ideapad_backlight_notify_power(priv);
1206 				break;
1207 			case 0:
1208 				ideapad_check_special_buttons(priv);
1209 				break;
1210 			case 1:
1211 				/* Some IdeaPads report event 1 every ~20
1212 				 * seconds while on battery power; some
1213 				 * report this when changing to/from tablet
1214 				 * mode. Squelch this event.
1215 				 */
1216 				break;
1217 			default:
1218 				pr_info("Unknown event: %lu\n", vpc_bit);
1219 			}
1220 		}
1221 	}
1222 }
1223 
1224 #if IS_ENABLED(CONFIG_ACPI_WMI)
1225 static void ideapad_wmi_notify(u32 value, void *context)
1226 {
1227 	switch (value) {
1228 	case 128:
1229 		ideapad_input_report(context, value);
1230 		break;
1231 	default:
1232 		pr_info("Unknown WMI event %u\n", value);
1233 	}
1234 }
1235 #endif
1236 
1237 /*
1238  * Some ideapads have a hardware rfkill switch, but most do not have one.
1239  * Reading VPCCMD_R_RF always results in 0 on models without a hardware rfkill,
1240  * switch causing ideapad_laptop to wrongly report all radios as hw-blocked.
1241  * There used to be a long list of DMI ids for models without a hw rfkill
1242  * switch here, but that resulted in playing whack a mole.
1243  * More importantly wrongly reporting the wifi radio as hw-blocked, results in
1244  * non working wifi. Whereas not reporting it hw-blocked, when it actually is
1245  * hw-blocked results in an empty SSID list, which is a much more benign
1246  * failure mode.
1247  * So the default now is the much safer option of assuming there is no
1248  * hardware rfkill switch. This default also actually matches most hardware,
1249  * since having a hw rfkill switch is quite rare on modern hardware, so this
1250  * also leads to a much shorter list.
1251  */
1252 static const struct dmi_system_id hw_rfkill_list[] = {
1253 	{}
1254 };
1255 
1256 static int ideapad_acpi_add(struct platform_device *pdev)
1257 {
1258 	int ret, i;
1259 	int cfg;
1260 	struct ideapad_private *priv;
1261 	struct acpi_device *adev;
1262 
1263 	ret = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev);
1264 	if (ret)
1265 		return -ENODEV;
1266 
1267 	if (read_method_int(adev->handle, "_CFG", &cfg))
1268 		return -ENODEV;
1269 
1270 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1271 	if (!priv)
1272 		return -ENOMEM;
1273 
1274 	dev_set_drvdata(&pdev->dev, priv);
1275 	priv->cfg = cfg;
1276 	priv->adev = adev;
1277 	priv->platform_device = pdev;
1278 	priv->has_hw_rfkill_switch = dmi_check_system(hw_rfkill_list);
1279 
1280 	/* Most ideapads with ELAN0634 touchpad don't use EC touchpad switch */
1281 	priv->has_touchpad_switch = !acpi_dev_present("ELAN0634", NULL, -1);
1282 
1283 	ret = ideapad_sysfs_init(priv);
1284 	if (ret)
1285 		return ret;
1286 
1287 	ideapad_debugfs_init(priv);
1288 
1289 	ret = ideapad_input_init(priv);
1290 	if (ret)
1291 		goto input_failed;
1292 
1293 	/*
1294 	 * On some models without a hw-switch (the yoga 2 13 at least)
1295 	 * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work.
1296 	 */
1297 	if (!priv->has_hw_rfkill_switch)
1298 		write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
1299 
1300 	/* The same for Touchpad */
1301 	if (!priv->has_touchpad_switch)
1302 		write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, 1);
1303 
1304 	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1305 		if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg))
1306 			ideapad_register_rfkill(priv, i);
1307 
1308 	ideapad_sync_rfk_state(priv);
1309 	ideapad_sync_touchpad_state(priv);
1310 
1311 	ideapad_dytc_profile_init(priv);
1312 
1313 	if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1314 		ret = ideapad_backlight_init(priv);
1315 		if (ret && ret != -ENODEV)
1316 			goto backlight_failed;
1317 	}
1318 	ret = acpi_install_notify_handler(adev->handle,
1319 		ACPI_DEVICE_NOTIFY, ideapad_acpi_notify, priv);
1320 	if (ret)
1321 		goto notification_failed;
1322 
1323 #if IS_ENABLED(CONFIG_ACPI_WMI)
1324 	for (i = 0; i < ARRAY_SIZE(ideapad_wmi_fnesc_events); i++) {
1325 		ret = wmi_install_notify_handler(ideapad_wmi_fnesc_events[i],
1326 						 ideapad_wmi_notify, priv);
1327 		if (ret == AE_OK) {
1328 			priv->fnesc_guid = ideapad_wmi_fnesc_events[i];
1329 			break;
1330 		}
1331 	}
1332 	if (ret != AE_OK && ret != AE_NOT_EXIST)
1333 		goto notification_failed_wmi;
1334 #endif
1335 
1336 	return 0;
1337 #if IS_ENABLED(CONFIG_ACPI_WMI)
1338 notification_failed_wmi:
1339 	acpi_remove_notify_handler(priv->adev->handle,
1340 		ACPI_DEVICE_NOTIFY, ideapad_acpi_notify);
1341 #endif
1342 notification_failed:
1343 	ideapad_backlight_exit(priv);
1344 backlight_failed:
1345 	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1346 		ideapad_unregister_rfkill(priv, i);
1347 	ideapad_input_exit(priv);
1348 input_failed:
1349 	ideapad_debugfs_exit(priv);
1350 	ideapad_sysfs_exit(priv);
1351 	return ret;
1352 }
1353 
1354 static int ideapad_acpi_remove(struct platform_device *pdev)
1355 {
1356 	struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
1357 	int i;
1358 
1359 #if IS_ENABLED(CONFIG_ACPI_WMI)
1360 	if (priv->fnesc_guid)
1361 		wmi_remove_notify_handler(priv->fnesc_guid);
1362 #endif
1363 	acpi_remove_notify_handler(priv->adev->handle,
1364 		ACPI_DEVICE_NOTIFY, ideapad_acpi_notify);
1365 	ideapad_backlight_exit(priv);
1366 	ideapad_dytc_profile_exit(priv);
1367 	for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++)
1368 		ideapad_unregister_rfkill(priv, i);
1369 	ideapad_input_exit(priv);
1370 	ideapad_debugfs_exit(priv);
1371 	ideapad_sysfs_exit(priv);
1372 	dev_set_drvdata(&pdev->dev, NULL);
1373 
1374 	return 0;
1375 }
1376 
1377 #ifdef CONFIG_PM_SLEEP
1378 static int ideapad_acpi_resume(struct device *device)
1379 {
1380 	struct ideapad_private *priv;
1381 
1382 	if (!device)
1383 		return -EINVAL;
1384 	priv = dev_get_drvdata(device);
1385 
1386 	ideapad_sync_rfk_state(priv);
1387 	ideapad_sync_touchpad_state(priv);
1388 
1389 	if (priv->dytc)
1390 		dytc_profile_refresh(priv);
1391 
1392 	return 0;
1393 }
1394 #endif
1395 static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume);
1396 
1397 static const struct acpi_device_id ideapad_device_ids[] = {
1398 	{ "VPC2004", 0},
1399 	{ "", 0},
1400 };
1401 MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
1402 
1403 static struct platform_driver ideapad_acpi_driver = {
1404 	.probe = ideapad_acpi_add,
1405 	.remove = ideapad_acpi_remove,
1406 	.driver = {
1407 		.name   = "ideapad_acpi",
1408 		.pm     = &ideapad_pm,
1409 		.acpi_match_table = ACPI_PTR(ideapad_device_ids),
1410 	},
1411 };
1412 
1413 module_platform_driver(ideapad_acpi_driver);
1414 
1415 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1416 MODULE_DESCRIPTION("IdeaPad ACPI Extras");
1417 MODULE_LICENSE("GPL");
1418