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