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