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