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 backlight_device_unregister(priv->blightdev); 733 priv->blightdev = NULL; 734 } 735 736 static void ideapad_backlight_notify_power(struct ideapad_private *priv) 737 { 738 unsigned long power; 739 struct backlight_device *blightdev = priv->blightdev; 740 741 if (!blightdev) 742 return; 743 if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power)) 744 return; 745 blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; 746 } 747 748 static void ideapad_backlight_notify_brightness(struct ideapad_private *priv) 749 { 750 unsigned long now; 751 752 /* if we control brightness via acpi video driver */ 753 if (priv->blightdev == NULL) { 754 read_ec_data(priv->adev->handle, VPCCMD_R_BL, &now); 755 return; 756 } 757 758 backlight_force_update(priv->blightdev, BACKLIGHT_UPDATE_HOTKEY); 759 } 760 761 /* 762 * module init/exit 763 */ 764 static void ideapad_sync_touchpad_state(struct ideapad_private *priv) 765 { 766 unsigned long value; 767 768 /* Without reading from EC touchpad LED doesn't switch state */ 769 if (!read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &value)) { 770 /* Some IdeaPads don't really turn off touchpad - they only 771 * switch the LED state. We (de)activate KBC AUX port to turn 772 * touchpad off and on. We send KEY_TOUCHPAD_OFF and 773 * KEY_TOUCHPAD_ON to not to get out of sync with LED */ 774 unsigned char param; 775 i8042_command(¶m, value ? I8042_CMD_AUX_ENABLE : 776 I8042_CMD_AUX_DISABLE); 777 ideapad_input_report(priv, value ? 67 : 66); 778 } 779 } 780 781 static void ideapad_acpi_notify(acpi_handle handle, u32 event, void *data) 782 { 783 struct ideapad_private *priv = data; 784 unsigned long vpc1, vpc2, vpc_bit; 785 786 if (read_ec_data(handle, VPCCMD_R_VPC1, &vpc1)) 787 return; 788 if (read_ec_data(handle, VPCCMD_R_VPC2, &vpc2)) 789 return; 790 791 vpc1 = (vpc2 << 8) | vpc1; 792 for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) { 793 if (test_bit(vpc_bit, &vpc1)) { 794 switch (vpc_bit) { 795 case 9: 796 ideapad_sync_rfk_state(priv); 797 break; 798 case 13: 799 case 11: 800 case 7: 801 case 6: 802 ideapad_input_report(priv, vpc_bit); 803 break; 804 case 5: 805 ideapad_sync_touchpad_state(priv); 806 break; 807 case 4: 808 ideapad_backlight_notify_brightness(priv); 809 break; 810 case 3: 811 ideapad_input_novokey(priv); 812 break; 813 case 2: 814 ideapad_backlight_notify_power(priv); 815 break; 816 case 0: 817 ideapad_check_special_buttons(priv); 818 break; 819 default: 820 pr_info("Unknown event: %lu\n", vpc_bit); 821 } 822 } 823 } 824 } 825 826 /* 827 * Some ideapads don't have a hardware rfkill switch, reading VPCCMD_R_RF 828 * always results in 0 on these models, causing ideapad_laptop to wrongly 829 * report all radios as hardware-blocked. 830 */ 831 static const struct dmi_system_id no_hw_rfkill_list[] = { 832 { 833 .ident = "Lenovo Yoga 2 11 / 13 / Pro", 834 .matches = { 835 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 836 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2"), 837 }, 838 }, 839 { 840 .ident = "Lenovo Yoga 3 Pro 1370", 841 .matches = { 842 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 843 DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo YOGA 3 Pro-1370"), 844 }, 845 }, 846 {} 847 }; 848 849 static int ideapad_acpi_add(struct platform_device *pdev) 850 { 851 int ret, i; 852 int cfg; 853 struct ideapad_private *priv; 854 struct acpi_device *adev; 855 856 ret = acpi_bus_get_device(ACPI_HANDLE(&pdev->dev), &adev); 857 if (ret) 858 return -ENODEV; 859 860 if (read_method_int(adev->handle, "_CFG", &cfg)) 861 return -ENODEV; 862 863 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 864 if (!priv) 865 return -ENOMEM; 866 867 dev_set_drvdata(&pdev->dev, priv); 868 priv->cfg = cfg; 869 priv->adev = adev; 870 priv->platform_device = pdev; 871 priv->has_hw_rfkill_switch = !dmi_check_system(no_hw_rfkill_list); 872 873 ret = ideapad_sysfs_init(priv); 874 if (ret) 875 return ret; 876 877 ret = ideapad_debugfs_init(priv); 878 if (ret) 879 goto debugfs_failed; 880 881 ret = ideapad_input_init(priv); 882 if (ret) 883 goto input_failed; 884 885 /* 886 * On some models without a hw-switch (the yoga 2 13 at least) 887 * VPCCMD_W_RF must be explicitly set to 1 for the wifi to work. 888 */ 889 if (!priv->has_hw_rfkill_switch) 890 write_ec_cmd(priv->adev->handle, VPCCMD_W_RF, 1); 891 892 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 893 if (test_bit(ideapad_rfk_data[i].cfgbit, &priv->cfg)) 894 ideapad_register_rfkill(priv, i); 895 896 ideapad_sync_rfk_state(priv); 897 ideapad_sync_touchpad_state(priv); 898 899 if (!acpi_video_backlight_support()) { 900 ret = ideapad_backlight_init(priv); 901 if (ret && ret != -ENODEV) 902 goto backlight_failed; 903 } 904 ret = acpi_install_notify_handler(adev->handle, 905 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify, priv); 906 if (ret) 907 goto notification_failed; 908 909 return 0; 910 notification_failed: 911 ideapad_backlight_exit(priv); 912 backlight_failed: 913 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 914 ideapad_unregister_rfkill(priv, i); 915 ideapad_input_exit(priv); 916 input_failed: 917 ideapad_debugfs_exit(priv); 918 debugfs_failed: 919 ideapad_sysfs_exit(priv); 920 return ret; 921 } 922 923 static int ideapad_acpi_remove(struct platform_device *pdev) 924 { 925 struct ideapad_private *priv = dev_get_drvdata(&pdev->dev); 926 int i; 927 928 acpi_remove_notify_handler(priv->adev->handle, 929 ACPI_DEVICE_NOTIFY, ideapad_acpi_notify); 930 ideapad_backlight_exit(priv); 931 for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) 932 ideapad_unregister_rfkill(priv, i); 933 ideapad_input_exit(priv); 934 ideapad_debugfs_exit(priv); 935 ideapad_sysfs_exit(priv); 936 dev_set_drvdata(&pdev->dev, NULL); 937 938 return 0; 939 } 940 941 #ifdef CONFIG_PM_SLEEP 942 static int ideapad_acpi_resume(struct device *device) 943 { 944 struct ideapad_private *priv; 945 946 if (!device) 947 return -EINVAL; 948 priv = dev_get_drvdata(device); 949 950 ideapad_sync_rfk_state(priv); 951 ideapad_sync_touchpad_state(priv); 952 return 0; 953 } 954 #endif 955 static SIMPLE_DEV_PM_OPS(ideapad_pm, NULL, ideapad_acpi_resume); 956 957 static const struct acpi_device_id ideapad_device_ids[] = { 958 { "VPC2004", 0}, 959 { "", 0}, 960 }; 961 MODULE_DEVICE_TABLE(acpi, ideapad_device_ids); 962 963 static struct platform_driver ideapad_acpi_driver = { 964 .probe = ideapad_acpi_add, 965 .remove = ideapad_acpi_remove, 966 .driver = { 967 .name = "ideapad_acpi", 968 .pm = &ideapad_pm, 969 .acpi_match_table = ACPI_PTR(ideapad_device_ids), 970 }, 971 }; 972 973 module_platform_driver(ideapad_acpi_driver); 974 975 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 976 MODULE_DESCRIPTION("IdeaPad ACPI Extras"); 977 MODULE_LICENSE("GPL"); 978