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