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