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