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