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