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