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