xtensa: support DMA buffers in high memory
[cris-mirror.git] / drivers / platform / x86 / ideapad-laptop.c
blob5b6f18b188012dcc94b19c9156ee54b42650473b
1 /*
2 * ideapad-laptop.c - Lenovo IdeaPad ACPI Extras
4 * Copyright © 2010 Intel Corporation
5 * Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
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.
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.
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.
23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
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>
43 #define IDEAPAD_RFKILL_DEV_NUM (3)
45 #define BM_CONSERVATION_BIT (5)
47 #define CFG_BT_BIT (16)
48 #define CFG_3G_BIT (17)
49 #define CFG_WIFI_BIT (18)
50 #define CFG_CAMERA_BIT (19)
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 */
57 #endif
59 enum {
60 BMCMD_CONSERVATION_ON = 3,
61 BMCMD_CONSERVATION_OFF = 5,
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,
91 struct ideapad_rfk_priv {
92 int dev;
93 struct ideapad_private *priv;
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;
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.");
114 * ACPI Helpers
116 #define IDEAPAD_EC_TIMEOUT (100) /* in ms */
118 static int read_method_int(acpi_handle handle, const char *method, int *val)
120 acpi_status status;
121 unsigned long long result;
123 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
124 if (ACPI_FAILURE(status)) {
125 *val = -1;
126 return -1;
128 *val = result;
129 return 0;
133 static int method_gbmd(acpi_handle handle, unsigned long *ret)
135 int result, val;
137 result = read_method_int(handle, "GBMD", &val);
138 *ret = val;
139 return result;
142 static int method_sbmc(acpi_handle handle, int cmd)
144 acpi_status status;
146 status = acpi_execute_simple_method(handle, "SBMC", cmd);
147 return ACPI_FAILURE(status) ? -1 : 0;
150 static int method_vpcr(acpi_handle handle, int cmd, int *ret)
152 acpi_status status;
153 unsigned long long result;
154 struct acpi_object_list params;
155 union acpi_object in_obj;
157 params.count = 1;
158 params.pointer = &in_obj;
159 in_obj.type = ACPI_TYPE_INTEGER;
160 in_obj.integer.value = cmd;
162 status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
164 if (ACPI_FAILURE(status)) {
165 *ret = -1;
166 return -1;
168 *ret = result;
169 return 0;
173 static int method_vpcw(acpi_handle handle, int cmd, int data)
175 struct acpi_object_list params;
176 union acpi_object in_obj[2];
177 acpi_status status;
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;
186 status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
187 if (status != AE_OK)
188 return -1;
189 return 0;
192 static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
194 int val;
195 unsigned long int end_jiffies;
197 if (method_vpcw(handle, 1, cmd))
198 return -1;
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;
212 pr_err("timeout in read_ec_cmd\n");
213 return -1;
216 static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
218 int val;
219 unsigned long int end_jiffies;
221 if (method_vpcw(handle, 0, data))
222 return -1;
223 if (method_vpcw(handle, 1, cmd))
224 return -1;
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;
234 pr_err("timeout in %s\n", __func__);
235 return -1;
239 * debugfs
241 static int debugfs_status_show(struct seq_file *s, void *data)
243 struct ideapad_private *priv = s->private;
244 unsigned long value;
246 if (!priv)
247 return -EINVAL;
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");
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");
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");
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);
285 return 0;
287 DEFINE_SHOW_ATTRIBUTE(debugfs_status);
289 static int debugfs_cfg_show(struct seq_file *s, void *data)
291 struct ideapad_private *priv = s->private;
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;
324 seq_printf(s, "\n");
326 return 0;
328 DEFINE_SHOW_ATTRIBUTE(debugfs_cfg);
330 static int ideapad_debugfs_init(struct ideapad_private *priv)
332 struct dentry *node;
334 priv->debug = debugfs_create_dir("ideapad", NULL);
335 if (priv->debug == NULL) {
336 pr_err("failed to create debugfs directory");
337 goto errout;
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;
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;
354 return 0;
356 errout:
357 return -ENOMEM;
360 static void ideapad_debugfs_exit(struct ideapad_private *priv)
362 debugfs_remove_recursive(priv->debug);
363 priv->debug = NULL;
367 * sysfs
369 static ssize_t show_ideapad_cam(struct device *dev,
370 struct device_attribute *attr,
371 char *buf)
373 unsigned long result;
374 struct ideapad_private *priv = dev_get_drvdata(dev);
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);
381 static ssize_t store_ideapad_cam(struct device *dev,
382 struct device_attribute *attr,
383 const char *buf, size_t count)
385 int ret, state;
386 struct ideapad_private *priv = dev_get_drvdata(dev);
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;
398 static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
400 static ssize_t show_ideapad_fan(struct device *dev,
401 struct device_attribute *attr,
402 char *buf)
404 unsigned long result;
405 struct ideapad_private *priv = dev_get_drvdata(dev);
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);
412 static ssize_t store_ideapad_fan(struct device *dev,
413 struct device_attribute *attr,
414 const char *buf, size_t count)
416 int ret, state;
417 struct ideapad_private *priv = dev_get_drvdata(dev);
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;
431 static DEVICE_ATTR(fan_mode, 0644, show_ideapad_fan, store_ideapad_fan);
433 static ssize_t touchpad_show(struct device *dev,
434 struct device_attribute *attr,
435 char *buf)
437 struct ideapad_private *priv = dev_get_drvdata(dev);
438 unsigned long result;
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);
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)
450 struct ideapad_private *priv = dev_get_drvdata(dev);
451 bool state;
452 int ret;
454 ret = kstrtobool(buf, &state);
455 if (ret)
456 return ret;
458 ret = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
459 if (ret < 0)
460 return -EIO;
461 return count;
464 static DEVICE_ATTR_RO(touchpad);
466 static ssize_t conservation_mode_show(struct device *dev,
467 struct device_attribute *attr,
468 char *buf)
470 struct ideapad_private *priv = dev_get_drvdata(dev);
471 unsigned long result;
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));
478 static ssize_t conservation_mode_store(struct device *dev,
479 struct device_attribute *attr,
480 const char *buf, size_t count)
482 struct ideapad_private *priv = dev_get_drvdata(dev);
483 bool state;
484 int ret;
486 ret = kstrtobool(buf, &state);
487 if (ret)
488 return ret;
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;
498 static DEVICE_ATTR_RW(conservation_mode);
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
508 static umode_t ideapad_is_visible(struct kobject *kobj,
509 struct attribute *attr,
510 int idx)
512 struct device *dev = container_of(kobj, struct device, kobj);
513 struct ideapad_private *priv = dev_get_drvdata(dev);
514 bool supported;
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;
528 return supported ? attr->mode : 0;
531 static const struct attribute_group ideapad_attribute_group = {
532 .is_visible = ideapad_is_visible,
533 .attrs = ideapad_attributes
537 * Rfkill
539 struct ideapad_rfk_data {
540 char *name;
541 int cfgbit;
542 int opcode;
543 int type;
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 },
552 static int ideapad_rfk_set(void *data, bool blocked)
554 struct ideapad_rfk_priv *priv = data;
555 int opcode = ideapad_rfk_data[priv->dev].opcode;
557 return write_ec_cmd(priv->priv->adev->handle, opcode, !blocked);
560 static const struct rfkill_ops ideapad_rfk_ops = {
561 .set_block = ideapad_rfk_set,
564 static void ideapad_sync_rfk_state(struct ideapad_private *priv)
566 unsigned long hw_blocked = 0;
567 int i;
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;
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);
580 static int ideapad_register_rfkill(struct ideapad_private *priv, int dev)
582 int ret;
583 unsigned long sw_blocked;
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;
592 priv->rfk_priv[dev].dev = dev;
593 priv->rfk_priv[dev].priv = priv;
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;
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);
611 ret = rfkill_register(priv->rfk[dev]);
612 if (ret) {
613 rfkill_destroy(priv->rfk[dev]);
614 return ret;
616 return 0;
619 static void ideapad_unregister_rfkill(struct ideapad_private *priv, int dev)
621 if (!priv->rfk[dev])
622 return;
624 rfkill_unregister(priv->rfk[dev]);
625 rfkill_destroy(priv->rfk[dev]);
629 * Platform device
631 static int ideapad_sysfs_init(struct ideapad_private *priv)
633 return sysfs_create_group(&priv->platform_device->dev.kobj,
634 &ideapad_attribute_group);
637 static void ideapad_sysfs_exit(struct ideapad_private *priv)
639 sysfs_remove_group(&priv->platform_device->dev.kobj,
640 &ideapad_attribute_group);
644 * input device
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 } },
660 { KE_END, 0 },
663 static int ideapad_input_init(struct ideapad_private *priv)
665 struct input_dev *inputdev;
666 int error;
668 inputdev = input_allocate_device();
669 if (!inputdev)
670 return -ENOMEM;
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;
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;
683 error = input_register_device(inputdev);
684 if (error) {
685 pr_err("Unable to register input device\n");
686 goto err_free_dev;
689 priv->inputdev = inputdev;
690 return 0;
692 err_free_dev:
693 input_free_device(inputdev);
694 return error;
697 static void ideapad_input_exit(struct ideapad_private *priv)
699 input_unregister_device(priv->inputdev);
700 priv->inputdev = NULL;
703 static void ideapad_input_report(struct ideapad_private *priv,
704 unsigned long scancode)
706 sparse_keymap_report_event(priv->inputdev, scancode, 1, true);
709 static void ideapad_input_novokey(struct ideapad_private *priv)
711 unsigned long long_pressed;
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);
721 static void ideapad_check_special_buttons(struct ideapad_private *priv)
723 unsigned long bit, value;
725 read_ec_data(priv->adev->handle, VPCCMD_R_SPECIAL_BUTTONS, &value);
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;
748 * backlight
750 static int ideapad_backlight_get_brightness(struct backlight_device *blightdev)
752 struct ideapad_private *priv = bl_get_data(blightdev);
753 unsigned long now;
755 if (!priv)
756 return -EINVAL;
758 if (read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now))
759 return -EIO;
760 return now;
763 static int ideapad_backlight_update_status(struct backlight_device *blightdev)
765 struct ideapad_private *priv = bl_get_data(blightdev);
767 if (!priv)
768 return -EINVAL;
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;
777 return 0;
780 static const struct backlight_ops ideapad_backlight_ops = {
781 .get_brightness = ideapad_backlight_get_brightness,
782 .update_status = ideapad_backlight_update_status,
785 static int ideapad_backlight_init(struct ideapad_private *priv)
787 struct backlight_device *blightdev;
788 struct backlight_properties props;
789 unsigned long max, now, power;
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;
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);
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);
816 return 0;
819 static void ideapad_backlight_exit(struct ideapad_private *priv)
821 backlight_device_unregister(priv->blightdev);
822 priv->blightdev = NULL;
825 static void ideapad_backlight_notify_power(struct ideapad_private *priv)
827 unsigned long power;
828 struct backlight_device *blightdev = priv->blightdev;
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;
837 static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
839 unsigned long now;
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;
847 backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY);
851 * module init/exit
853 static void ideapad_sync_touchpad_state(struct ideapad_private *priv)
855 unsigned long value;
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);
870 static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data)
872 struct ideapad_private *priv = data;
873 unsigned long vpc1, vpc2, vpc_bit;
875 if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1))
876 return;
877 if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2))
878 return;
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.
915 break;
916 default:
917 pr_info("Unknown event: %lu\n", vpc_bit);
923 #if IS_ENABLED(CONFIG_ACPI_WMI)
924 static void ideapad_wmi_notify(u32 value, void *context)
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);
934 #endif
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.
941 static const struct dmi_system_id no_hw_rfkill_list[] = {
943 .ident = "Lenovo RESCUER R720-15IKBN",
944 .matches = {
945 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
946 DMI_MATCH(DMI_BOARD_NAME, "80WW"),
950 .ident = "Lenovo G40-30",
951 .matches = {
952 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
953 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G40-30"),
957 .ident = "Lenovo G50-30",
958 .matches = {
959 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
960 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"),
964 .ident = "Lenovo V310-14IKB",
965 .matches = {
966 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
967 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14IKB"),
971 .ident = "Lenovo V310-14ISK",
972 .matches = {
973 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
974 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-14ISK"),
978 .ident = "Lenovo V310-15IKB",
979 .matches = {
980 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
981 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15IKB"),
985 .ident = "Lenovo V310-15ISK",
986 .matches = {
987 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
988 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V310-15ISK"),
992 .ident = "Lenovo V510-15IKB",
993 .matches = {
994 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
995 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo V510-15IKB"),
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"),
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"),
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"),
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"),
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"),
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"),
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"),
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"),
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"),
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"),
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"),
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"),
1083 .ident = "Lenovo Legion Y520-15IKBN",
1084 .matches = {
1085 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1086 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"),
1090 .ident = "Lenovo Legion Y720-15IKB",
1091 .matches = {
1092 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1093 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKB"),
1097 .ident = "Lenovo Legion Y720-15IKBN",
1098 .matches = {
1099 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1100 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBN"),
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"),
1111 .ident = "Lenovo Yoga 2 11 / 13 / Pro",
1112 .matches = {
1113 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1114 DMI_MATCH(DMI_BOARD_NAME, "Yoga2"),
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"),
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"),
1132 .ident = "Lenovo Yoga 700",
1133 .matches = {
1134 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1135 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 700"),
1139 .ident = "Lenovo Yoga 900",
1140 .matches = {
1141 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1142 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 900"),
1146 .ident = "Lenovo Yoga 900",
1147 .matches = {
1148 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
1149 DMI_MATCH(DMI_BOARD_NAME, "VIUU4"),
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"),
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"),
1169 static int ideapad_acpi_add(struct platform_device *pdev)
1171 int ret, i;
1172 int cfg;
1173 struct ideapad_private *priv;
1174 struct acpi_device *adev;
1176 ret = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev);
1177 if (ret)
1178 return -ENODEV;
1180 if (read_method_int(adev->handle, "_CFG", &cfg))
1181 return -ENODEV;
1183 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
1184 if (!priv)
1185 return -ENOMEM;
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);
1193 ret = ideapad_sysfs_init(priv);
1194 if (ret)
1195 return ret;
1197 ret = ideapad_debugfs_init(priv);
1198 if (ret)
1199 goto debugfs_failed;
1201 ret = ideapad_input_init(priv);
1202 if (ret)
1203 goto input_failed;
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.
1209 if (!priv->has_hw_rfkill_switch)
1210 write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1);
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);
1216 ideapad_sync_rfk_state(priv);
1217 ideapad_sync_touchpad_state(priv);
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;
1224 ret = acpi_install_notify_handler(adev->handle,
1225 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify, priv);
1226 if (ret)
1227 goto notification_failed;
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;
1238 if (ret != AE_OK && ret != AE_NOT_EXIST)
1239 goto notification_failed_wmi;
1240 #endif
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;
1261 static int ideapad_acpi_remove(struct platform_device *pdev)
1263 struct ideapad_private *priv = dev_get_drvdata(&pdev->dev);
1264 int i;
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);
1280 return 0;
1283 #ifdef CONFIG_PM_SLEEP
1284 static int ideapad_acpi_resume(struct device *device)
1286 struct ideapad_private *priv;
1288 if (!device)
1289 return -EINVAL;
1290 priv = dev_get_drvdata(device);
1292 ideapad_sync_rfk_state(priv);
1293 ideapad_sync_touchpad_state(priv);
1294 return 0;
1296 #endif
1297 static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume);
1299 static const struct acpi_device_id ideapad_device_ids[] = {
1300 { "VPC2004", 0},
1301 { "", 0},
1303 MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
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),
1315 module_platform_driver(ideapad_acpi_driver);
1317 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
1318 MODULE_DESCRIPTION("IdeaPad ACPI Extras");
1319 MODULE_LICENSE("GPL");