diff options
Diffstat (limited to 'drivers/platform')
22 files changed, 473 insertions, 90 deletions
diff --git a/drivers/platform/Kconfig b/drivers/platform/Kconfig index 69616aeaa966..09fde58b12e0 100644 --- a/drivers/platform/Kconfig +++ b/drivers/platform/Kconfig | |||
| @@ -5,3 +5,4 @@ if GOLDFISH | |||
| 5 | source "drivers/platform/goldfish/Kconfig" | 5 | source "drivers/platform/goldfish/Kconfig" |
| 6 | endif | 6 | endif |
| 7 | 7 | ||
| 8 | source "drivers/platform/chrome/Kconfig" | ||
diff --git a/drivers/platform/Makefile b/drivers/platform/Makefile index 8a44a4cd6d1e..3656b7b17b99 100644 --- a/drivers/platform/Makefile +++ b/drivers/platform/Makefile | |||
| @@ -5,3 +5,4 @@ | |||
| 5 | obj-$(CONFIG_X86) += x86/ | 5 | obj-$(CONFIG_X86) += x86/ |
| 6 | obj-$(CONFIG_OLPC) += olpc/ | 6 | obj-$(CONFIG_OLPC) += olpc/ |
| 7 | obj-$(CONFIG_GOLDFISH) += goldfish/ | 7 | obj-$(CONFIG_GOLDFISH) += goldfish/ |
| 8 | obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ | ||
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig new file mode 100644 index 000000000000..b13303e75a34 --- /dev/null +++ b/drivers/platform/chrome/Kconfig | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | # | ||
| 2 | # Platform support for Chrome OS hardware (Chromebooks and Chromeboxes) | ||
| 3 | # | ||
| 4 | |||
| 5 | menuconfig CHROME_PLATFORMS | ||
| 6 | bool "Platform support for Chrome hardware" | ||
| 7 | depends on X86 | ||
| 8 | ---help--- | ||
| 9 | Say Y here to get to see options for platform support for | ||
| 10 | various Chromebooks and Chromeboxes. This option alone does | ||
| 11 | not add any kernel code. | ||
| 12 | |||
| 13 | If you say N, all options in this submenu will be skipped and disabled. | ||
| 14 | |||
| 15 | if CHROME_PLATFORMS | ||
| 16 | |||
| 17 | config CHROMEOS_LAPTOP | ||
| 18 | tristate "Chrome OS Laptop" | ||
| 19 | depends on I2C | ||
| 20 | depends on DMI | ||
| 21 | ---help--- | ||
| 22 | This driver instantiates i2c and smbus devices such as | ||
| 23 | light sensors and touchpads. | ||
| 24 | |||
| 25 | If you have a supported Chromebook, choose Y or M here. | ||
| 26 | The module will be called chromeos_laptop. | ||
| 27 | |||
| 28 | endif # CHROMEOS_PLATFORMS | ||
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile new file mode 100644 index 000000000000..015e9195e226 --- /dev/null +++ b/drivers/platform/chrome/Makefile | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | |||
| 2 | obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o | ||
diff --git a/drivers/platform/x86/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index 3e5b4497a1d0..3e5b4497a1d0 100644 --- a/drivers/platform/x86/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c | |||
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index b51a7460cc49..d9dcd37b5a52 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
| @@ -79,17 +79,6 @@ config ASUS_LAPTOP | |||
| 79 | 79 | ||
| 80 | If you have an ACPI-compatible ASUS laptop, say Y or M here. | 80 | If you have an ACPI-compatible ASUS laptop, say Y or M here. |
| 81 | 81 | ||
| 82 | config CHROMEOS_LAPTOP | ||
| 83 | tristate "Chrome OS Laptop" | ||
| 84 | depends on I2C | ||
| 85 | depends on DMI | ||
| 86 | ---help--- | ||
| 87 | This driver instantiates i2c and smbus devices such as | ||
| 88 | light sensors and touchpads. | ||
| 89 | |||
| 90 | If you have a supported Chromebook, choose Y or M here. | ||
| 91 | The module will be called chromeos_laptop. | ||
| 92 | |||
| 93 | config DELL_LAPTOP | 82 | config DELL_LAPTOP |
| 94 | tristate "Dell Laptop Extras" | 83 | tristate "Dell Laptop Extras" |
| 95 | depends on X86 | 84 | depends on X86 |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 5dbe19324351..f0e6aa407ffb 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
| @@ -50,7 +50,6 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o | |||
| 50 | obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o | 50 | obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o |
| 51 | obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o | 51 | obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o |
| 52 | obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o | 52 | obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o |
| 53 | obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o | ||
| 54 | obj-$(CONFIG_INTEL_RST) += intel-rst.o | 53 | obj-$(CONFIG_INTEL_RST) += intel-rst.o |
| 55 | obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o | 54 | obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o |
| 56 | 55 | ||
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c index 605a9be55129..b9429fbf1cd8 100644 --- a/drivers/platform/x86/apple-gmux.c +++ b/drivers/platform/x86/apple-gmux.c | |||
| @@ -519,7 +519,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) | |||
| 519 | 519 | ||
| 520 | gmux_data->power_state = VGA_SWITCHEROO_ON; | 520 | gmux_data->power_state = VGA_SWITCHEROO_ON; |
| 521 | 521 | ||
| 522 | gmux_data->dhandle = DEVICE_ACPI_HANDLE(&pnp->dev); | 522 | gmux_data->dhandle = ACPI_HANDLE(&pnp->dev); |
| 523 | if (!gmux_data->dhandle) { | 523 | if (!gmux_data->dhandle) { |
| 524 | pr_err("Cannot find acpi handle for pnp device %s\n", | 524 | pr_err("Cannot find acpi handle for pnp device %s\n", |
| 525 | dev_name(&pnp->dev)); | 525 | dev_name(&pnp->dev)); |
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 0e9c169b42f8..594323a926cf 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
| @@ -1494,10 +1494,9 @@ static int asus_input_init(struct asus_laptop *asus) | |||
| 1494 | int error; | 1494 | int error; |
| 1495 | 1495 | ||
| 1496 | input = input_allocate_device(); | 1496 | input = input_allocate_device(); |
| 1497 | if (!input) { | 1497 | if (!input) |
| 1498 | pr_warn("Unable to allocate input device\n"); | ||
| 1499 | return -ENOMEM; | 1498 | return -ENOMEM; |
| 1500 | } | 1499 | |
| 1501 | input->name = "Asus Laptop extra buttons"; | 1500 | input->name = "Asus Laptop extra buttons"; |
| 1502 | input->phys = ASUS_LAPTOP_FILE "/input0"; | 1501 | input->phys = ASUS_LAPTOP_FILE "/input0"; |
| 1503 | input->id.bustype = BUS_HOST; | 1502 | input->id.bustype = BUS_HOST; |
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index bb77e18b3dd4..c608b1d33f4a 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
| 22 | #include <linux/dmi.h> | 22 | #include <linux/dmi.h> |
| 23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
| 24 | #include <linux/rfkill.h> | ||
| 24 | #include <linux/power_supply.h> | 25 | #include <linux/power_supply.h> |
| 25 | #include <linux/acpi.h> | 26 | #include <linux/acpi.h> |
| 26 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
| @@ -89,6 +90,13 @@ static struct platform_driver platform_driver = { | |||
| 89 | 90 | ||
| 90 | static struct platform_device *platform_device; | 91 | static struct platform_device *platform_device; |
| 91 | static struct backlight_device *dell_backlight_device; | 92 | static struct backlight_device *dell_backlight_device; |
| 93 | static struct rfkill *wifi_rfkill; | ||
| 94 | static struct rfkill *bluetooth_rfkill; | ||
| 95 | static struct rfkill *wwan_rfkill; | ||
| 96 | static bool force_rfkill; | ||
| 97 | |||
| 98 | module_param(force_rfkill, bool, 0444); | ||
| 99 | MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models"); | ||
| 92 | 100 | ||
| 93 | static const struct dmi_system_id dell_device_table[] __initconst = { | 101 | static const struct dmi_system_id dell_device_table[] __initconst = { |
| 94 | { | 102 | { |
| @@ -355,6 +363,108 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
| 355 | return buffer; | 363 | return buffer; |
| 356 | } | 364 | } |
| 357 | 365 | ||
| 366 | /* Derived from information in DellWirelessCtl.cpp: | ||
| 367 | Class 17, select 11 is radio control. It returns an array of 32-bit values. | ||
| 368 | |||
| 369 | Input byte 0 = 0: Wireless information | ||
| 370 | |||
| 371 | result[0]: return code | ||
| 372 | result[1]: | ||
| 373 | Bit 0: Hardware switch supported | ||
| 374 | Bit 1: Wifi locator supported | ||
| 375 | Bit 2: Wifi is supported | ||
| 376 | Bit 3: Bluetooth is supported | ||
| 377 | Bit 4: WWAN is supported | ||
| 378 | Bit 5: Wireless keyboard supported | ||
| 379 | Bits 6-7: Reserved | ||
| 380 | Bit 8: Wifi is installed | ||
| 381 | Bit 9: Bluetooth is installed | ||
| 382 | Bit 10: WWAN is installed | ||
| 383 | Bits 11-15: Reserved | ||
| 384 | Bit 16: Hardware switch is on | ||
| 385 | Bit 17: Wifi is blocked | ||
| 386 | Bit 18: Bluetooth is blocked | ||
| 387 | Bit 19: WWAN is blocked | ||
| 388 | Bits 20-31: Reserved | ||
| 389 | result[2]: NVRAM size in bytes | ||
| 390 | result[3]: NVRAM format version number | ||
| 391 | |||
| 392 | Input byte 0 = 2: Wireless switch configuration | ||
| 393 | result[0]: return code | ||
| 394 | result[1]: | ||
| 395 | Bit 0: Wifi controlled by switch | ||
| 396 | Bit 1: Bluetooth controlled by switch | ||
| 397 | Bit 2: WWAN controlled by switch | ||
| 398 | Bits 3-6: Reserved | ||
| 399 | Bit 7: Wireless switch config locked | ||
| 400 | Bit 8: Wifi locator enabled | ||
| 401 | Bits 9-14: Reserved | ||
| 402 | Bit 15: Wifi locator setting locked | ||
| 403 | Bits 16-31: Reserved | ||
| 404 | */ | ||
| 405 | |||
| 406 | static int dell_rfkill_set(void *data, bool blocked) | ||
| 407 | { | ||
| 408 | int disable = blocked ? 1 : 0; | ||
| 409 | unsigned long radio = (unsigned long)data; | ||
| 410 | int hwswitch_bit = (unsigned long)data - 1; | ||
| 411 | |||
| 412 | get_buffer(); | ||
| 413 | dell_send_request(buffer, 17, 11); | ||
| 414 | |||
| 415 | /* If the hardware switch controls this radio, and the hardware | ||
| 416 | switch is disabled, always disable the radio */ | ||
| 417 | if ((hwswitch_state & BIT(hwswitch_bit)) && | ||
| 418 | !(buffer->output[1] & BIT(16))) | ||
| 419 | disable = 1; | ||
| 420 | |||
| 421 | buffer->input[0] = (1 | (radio<<8) | (disable << 16)); | ||
| 422 | dell_send_request(buffer, 17, 11); | ||
| 423 | |||
| 424 | release_buffer(); | ||
| 425 | return 0; | ||
| 426 | } | ||
| 427 | |||
| 428 | /* Must be called with the buffer held */ | ||
| 429 | static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, | ||
| 430 | int status) | ||
| 431 | { | ||
| 432 | if (status & BIT(0)) { | ||
| 433 | /* Has hw-switch, sync sw_state to BIOS */ | ||
| 434 | int block = rfkill_blocked(rfkill); | ||
| 435 | buffer->input[0] = (1 | (radio << 8) | (block << 16)); | ||
| 436 | dell_send_request(buffer, 17, 11); | ||
| 437 | } else { | ||
| 438 | /* No hw-switch, sync BIOS state to sw_state */ | ||
| 439 | rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); | ||
| 440 | } | ||
| 441 | } | ||
| 442 | |||
| 443 | static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio, | ||
| 444 | int status) | ||
| 445 | { | ||
| 446 | if (hwswitch_state & (BIT(radio - 1))) | ||
| 447 | rfkill_set_hw_state(rfkill, !(status & BIT(16))); | ||
| 448 | } | ||
| 449 | |||
| 450 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) | ||
| 451 | { | ||
| 452 | int status; | ||
| 453 | |||
| 454 | get_buffer(); | ||
| 455 | dell_send_request(buffer, 17, 11); | ||
| 456 | status = buffer->output[1]; | ||
| 457 | |||
| 458 | dell_rfkill_update_hw_state(rfkill, (unsigned long)data, status); | ||
| 459 | |||
| 460 | release_buffer(); | ||
| 461 | } | ||
| 462 | |||
| 463 | static const struct rfkill_ops dell_rfkill_ops = { | ||
| 464 | .set_block = dell_rfkill_set, | ||
| 465 | .query = dell_rfkill_query, | ||
| 466 | }; | ||
| 467 | |||
| 358 | static struct dentry *dell_laptop_dir; | 468 | static struct dentry *dell_laptop_dir; |
| 359 | 469 | ||
| 360 | static int dell_debugfs_show(struct seq_file *s, void *data) | 470 | static int dell_debugfs_show(struct seq_file *s, void *data) |
| @@ -424,6 +534,136 @@ static const struct file_operations dell_debugfs_fops = { | |||
| 424 | .release = single_release, | 534 | .release = single_release, |
| 425 | }; | 535 | }; |
| 426 | 536 | ||
| 537 | static void dell_update_rfkill(struct work_struct *ignored) | ||
| 538 | { | ||
| 539 | int status; | ||
| 540 | |||
| 541 | get_buffer(); | ||
| 542 | dell_send_request(buffer, 17, 11); | ||
| 543 | status = buffer->output[1]; | ||
| 544 | |||
| 545 | if (wifi_rfkill) { | ||
| 546 | dell_rfkill_update_hw_state(wifi_rfkill, 1, status); | ||
| 547 | dell_rfkill_update_sw_state(wifi_rfkill, 1, status); | ||
| 548 | } | ||
| 549 | if (bluetooth_rfkill) { | ||
| 550 | dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status); | ||
| 551 | dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status); | ||
| 552 | } | ||
| 553 | if (wwan_rfkill) { | ||
| 554 | dell_rfkill_update_hw_state(wwan_rfkill, 3, status); | ||
| 555 | dell_rfkill_update_sw_state(wwan_rfkill, 3, status); | ||
| 556 | } | ||
| 557 | |||
| 558 | release_buffer(); | ||
| 559 | } | ||
| 560 | static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); | ||
| 561 | |||
| 562 | |||
| 563 | static int __init dell_setup_rfkill(void) | ||
| 564 | { | ||
| 565 | int status; | ||
| 566 | int ret; | ||
| 567 | const char *product; | ||
| 568 | |||
| 569 | /* | ||
| 570 | * rfkill causes trouble on various non Latitudes, according to Dell | ||
| 571 | * actually testing the rfkill functionality is only done on Latitudes. | ||
| 572 | */ | ||
| 573 | product = dmi_get_system_info(DMI_PRODUCT_NAME); | ||
| 574 | if (!force_rfkill && (!product || strncmp(product, "Latitude", 8))) | ||
| 575 | return 0; | ||
| 576 | |||
| 577 | get_buffer(); | ||
| 578 | dell_send_request(buffer, 17, 11); | ||
| 579 | status = buffer->output[1]; | ||
| 580 | buffer->input[0] = 0x2; | ||
| 581 | dell_send_request(buffer, 17, 11); | ||
| 582 | hwswitch_state = buffer->output[1]; | ||
| 583 | release_buffer(); | ||
| 584 | |||
| 585 | if (!(status & BIT(0))) { | ||
| 586 | if (force_rfkill) { | ||
| 587 | /* No hwsitch, clear all hw-controlled bits */ | ||
| 588 | hwswitch_state &= ~7; | ||
| 589 | } else { | ||
| 590 | /* rfkill is only tested on laptops with a hwswitch */ | ||
| 591 | return 0; | ||
| 592 | } | ||
| 593 | } | ||
| 594 | |||
| 595 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { | ||
| 596 | wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, | ||
| 597 | RFKILL_TYPE_WLAN, | ||
| 598 | &dell_rfkill_ops, (void *) 1); | ||
| 599 | if (!wifi_rfkill) { | ||
| 600 | ret = -ENOMEM; | ||
| 601 | goto err_wifi; | ||
| 602 | } | ||
| 603 | ret = rfkill_register(wifi_rfkill); | ||
| 604 | if (ret) | ||
| 605 | goto err_wifi; | ||
| 606 | } | ||
| 607 | |||
| 608 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { | ||
| 609 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", | ||
| 610 | &platform_device->dev, | ||
| 611 | RFKILL_TYPE_BLUETOOTH, | ||
| 612 | &dell_rfkill_ops, (void *) 2); | ||
| 613 | if (!bluetooth_rfkill) { | ||
| 614 | ret = -ENOMEM; | ||
| 615 | goto err_bluetooth; | ||
| 616 | } | ||
| 617 | ret = rfkill_register(bluetooth_rfkill); | ||
| 618 | if (ret) | ||
| 619 | goto err_bluetooth; | ||
| 620 | } | ||
| 621 | |||
| 622 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { | ||
| 623 | wwan_rfkill = rfkill_alloc("dell-wwan", | ||
| 624 | &platform_device->dev, | ||
| 625 | RFKILL_TYPE_WWAN, | ||
| 626 | &dell_rfkill_ops, (void *) 3); | ||
| 627 | if (!wwan_rfkill) { | ||
| 628 | ret = -ENOMEM; | ||
| 629 | goto err_wwan; | ||
| 630 | } | ||
| 631 | ret = rfkill_register(wwan_rfkill); | ||
| 632 | if (ret) | ||
| 633 | goto err_wwan; | ||
| 634 | } | ||
| 635 | |||
| 636 | return 0; | ||
| 637 | err_wwan: | ||
| 638 | rfkill_destroy(wwan_rfkill); | ||
| 639 | if (bluetooth_rfkill) | ||
| 640 | rfkill_unregister(bluetooth_rfkill); | ||
| 641 | err_bluetooth: | ||
| 642 | rfkill_destroy(bluetooth_rfkill); | ||
| 643 | if (wifi_rfkill) | ||
| 644 | rfkill_unregister(wifi_rfkill); | ||
| 645 | err_wifi: | ||
| 646 | rfkill_destroy(wifi_rfkill); | ||
| 647 | |||
| 648 | return ret; | ||
| 649 | } | ||
| 650 | |||
| 651 | static void dell_cleanup_rfkill(void) | ||
| 652 | { | ||
| 653 | if (wifi_rfkill) { | ||
| 654 | rfkill_unregister(wifi_rfkill); | ||
| 655 | rfkill_destroy(wifi_rfkill); | ||
| 656 | } | ||
| 657 | if (bluetooth_rfkill) { | ||
| 658 | rfkill_unregister(bluetooth_rfkill); | ||
| 659 | rfkill_destroy(bluetooth_rfkill); | ||
| 660 | } | ||
| 661 | if (wwan_rfkill) { | ||
| 662 | rfkill_unregister(wwan_rfkill); | ||
| 663 | rfkill_destroy(wwan_rfkill); | ||
| 664 | } | ||
| 665 | } | ||
| 666 | |||
| 427 | static int dell_send_intensity(struct backlight_device *bd) | 667 | static int dell_send_intensity(struct backlight_device *bd) |
| 428 | { | 668 | { |
| 429 | int ret = 0; | 669 | int ret = 0; |
| @@ -515,6 +755,30 @@ static void touchpad_led_exit(void) | |||
| 515 | led_classdev_unregister(&touchpad_led); | 755 | led_classdev_unregister(&touchpad_led); |
| 516 | } | 756 | } |
| 517 | 757 | ||
| 758 | static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, | ||
| 759 | struct serio *port) | ||
| 760 | { | ||
| 761 | static bool extended; | ||
| 762 | |||
| 763 | if (str & 0x20) | ||
| 764 | return false; | ||
| 765 | |||
| 766 | if (unlikely(data == 0xe0)) { | ||
| 767 | extended = true; | ||
| 768 | return false; | ||
| 769 | } else if (unlikely(extended)) { | ||
| 770 | switch (data) { | ||
| 771 | case 0x8: | ||
| 772 | schedule_delayed_work(&dell_rfkill_work, | ||
| 773 | round_jiffies_relative(HZ / 4)); | ||
| 774 | break; | ||
| 775 | } | ||
| 776 | extended = false; | ||
| 777 | } | ||
| 778 | |||
| 779 | return false; | ||
| 780 | } | ||
| 781 | |||
| 518 | static int __init dell_init(void) | 782 | static int __init dell_init(void) |
| 519 | { | 783 | { |
| 520 | int max_intensity = 0; | 784 | int max_intensity = 0; |
| @@ -557,10 +821,26 @@ static int __init dell_init(void) | |||
| 557 | } | 821 | } |
| 558 | buffer = page_address(bufferpage); | 822 | buffer = page_address(bufferpage); |
| 559 | 823 | ||
| 824 | ret = dell_setup_rfkill(); | ||
| 825 | |||
| 826 | if (ret) { | ||
| 827 | pr_warn("Unable to setup rfkill\n"); | ||
| 828 | goto fail_rfkill; | ||
| 829 | } | ||
| 830 | |||
| 831 | ret = i8042_install_filter(dell_laptop_i8042_filter); | ||
| 832 | if (ret) { | ||
| 833 | pr_warn("Unable to install key filter\n"); | ||
| 834 | goto fail_filter; | ||
| 835 | } | ||
| 836 | |||
| 560 | if (quirks && quirks->touchpad_led) | 837 | if (quirks && quirks->touchpad_led) |
| 561 | touchpad_led_init(&platform_device->dev); | 838 | touchpad_led_init(&platform_device->dev); |
| 562 | 839 | ||
| 563 | dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); | 840 | dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); |
| 841 | if (dell_laptop_dir != NULL) | ||
| 842 | debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, | ||
| 843 | &dell_debugfs_fops); | ||
| 564 | 844 | ||
| 565 | #ifdef CONFIG_ACPI | 845 | #ifdef CONFIG_ACPI |
| 566 | /* In the event of an ACPI backlight being available, don't | 846 | /* In the event of an ACPI backlight being available, don't |
| @@ -603,6 +883,11 @@ static int __init dell_init(void) | |||
| 603 | return 0; | 883 | return 0; |
| 604 | 884 | ||
| 605 | fail_backlight: | 885 | fail_backlight: |
| 886 | i8042_remove_filter(dell_laptop_i8042_filter); | ||
| 887 | cancel_delayed_work_sync(&dell_rfkill_work); | ||
| 888 | fail_filter: | ||
| 889 | dell_cleanup_rfkill(); | ||
| 890 | fail_rfkill: | ||
| 606 | free_page((unsigned long)bufferpage); | 891 | free_page((unsigned long)bufferpage); |
| 607 | fail_buffer: | 892 | fail_buffer: |
| 608 | platform_device_del(platform_device); | 893 | platform_device_del(platform_device); |
| @@ -620,7 +905,10 @@ static void __exit dell_exit(void) | |||
| 620 | debugfs_remove_recursive(dell_laptop_dir); | 905 | debugfs_remove_recursive(dell_laptop_dir); |
| 621 | if (quirks && quirks->touchpad_led) | 906 | if (quirks && quirks->touchpad_led) |
| 622 | touchpad_led_exit(); | 907 | touchpad_led_exit(); |
| 908 | i8042_remove_filter(dell_laptop_i8042_filter); | ||
| 909 | cancel_delayed_work_sync(&dell_rfkill_work); | ||
| 623 | backlight_device_unregister(dell_backlight_device); | 910 | backlight_device_unregister(dell_backlight_device); |
| 911 | dell_cleanup_rfkill(); | ||
| 624 | if (platform_device) { | 912 | if (platform_device) { |
| 625 | platform_device_unregister(platform_device); | 913 | platform_device_unregister(platform_device); |
| 626 | platform_driver_unregister(&platform_driver); | 914 | platform_driver_unregister(&platform_driver); |
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index fa9a2171cc13..60e0900bc117 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c | |||
| @@ -130,7 +130,8 @@ static const u16 bios_to_linux_keycode[256] __initconst = { | |||
| 130 | KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE, | 130 | KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE, |
| 131 | KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, | 131 | KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, |
| 132 | KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2, | 132 | KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2, |
| 133 | KEY_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 133 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, |
| 134 | KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_MICMUTE, | ||
| 134 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 135 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 135 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 136 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 136 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 137 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| @@ -139,8 +140,8 @@ static const u16 bios_to_linux_keycode[256] __initconst = { | |||
| 139 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 140 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 140 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 141 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 141 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 142 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 142 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | 143 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 143 | KEY_PROG3 | 144 | 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_PROG3 |
| 144 | }; | 145 | }; |
| 145 | 146 | ||
| 146 | static struct input_dev *dell_wmi_input_dev; | 147 | static struct input_dev *dell_wmi_input_dev; |
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index aefcc32e5634..dec68e7a99c7 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
| @@ -1203,10 +1203,8 @@ static int eeepc_input_init(struct eeepc_laptop *eeepc) | |||
| 1203 | int error; | 1203 | int error; |
| 1204 | 1204 | ||
| 1205 | input = input_allocate_device(); | 1205 | input = input_allocate_device(); |
| 1206 | if (!input) { | 1206 | if (!input) |
| 1207 | pr_info("Unable to allocate input device\n"); | ||
| 1208 | return -ENOMEM; | 1207 | return -ENOMEM; |
| 1209 | } | ||
| 1210 | 1208 | ||
| 1211 | input->name = "Asus EeePC extra buttons"; | 1209 | input->name = "Asus EeePC extra buttons"; |
| 1212 | input->phys = EEEPC_LAPTOP_FILE "/input0"; | 1210 | input->phys = EEEPC_LAPTOP_FILE "/input0"; |
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index 1c86fa0857c8..8ba8956b5a48 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
| @@ -54,6 +54,7 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); | |||
| 54 | #define HPWMI_HARDWARE_QUERY 0x4 | 54 | #define HPWMI_HARDWARE_QUERY 0x4 |
| 55 | #define HPWMI_WIRELESS_QUERY 0x5 | 55 | #define HPWMI_WIRELESS_QUERY 0x5 |
| 56 | #define HPWMI_HOTKEY_QUERY 0xc | 56 | #define HPWMI_HOTKEY_QUERY 0xc |
| 57 | #define HPWMI_FEATURE_QUERY 0xd | ||
| 57 | #define HPWMI_WIRELESS2_QUERY 0x1b | 58 | #define HPWMI_WIRELESS2_QUERY 0x1b |
| 58 | #define HPWMI_POSTCODEERROR_QUERY 0x2a | 59 | #define HPWMI_POSTCODEERROR_QUERY 0x2a |
| 59 | 60 | ||
| @@ -292,6 +293,17 @@ static int hp_wmi_tablet_state(void) | |||
| 292 | return (state & 0x4) ? 1 : 0; | 293 | return (state & 0x4) ? 1 : 0; |
| 293 | } | 294 | } |
| 294 | 295 | ||
| 296 | static int hp_wmi_bios_2009_later(void) | ||
| 297 | { | ||
| 298 | int state = 0; | ||
| 299 | int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, 0, &state, | ||
| 300 | sizeof(state), sizeof(state)); | ||
| 301 | if (ret) | ||
| 302 | return ret; | ||
| 303 | |||
| 304 | return (state & 0x10) ? 1 : 0; | ||
| 305 | } | ||
| 306 | |||
| 295 | static int hp_wmi_set_block(void *data, bool blocked) | 307 | static int hp_wmi_set_block(void *data, bool blocked) |
| 296 | { | 308 | { |
| 297 | enum hp_wmi_radio r = (enum hp_wmi_radio) data; | 309 | enum hp_wmi_radio r = (enum hp_wmi_radio) data; |
| @@ -871,7 +883,7 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
| 871 | gps_rfkill = NULL; | 883 | gps_rfkill = NULL; |
| 872 | rfkill2_count = 0; | 884 | rfkill2_count = 0; |
| 873 | 885 | ||
| 874 | if (hp_wmi_rfkill_setup(device)) | 886 | if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device)) |
| 875 | hp_wmi_rfkill2_setup(device); | 887 | hp_wmi_rfkill2_setup(device); |
| 876 | 888 | ||
| 877 | err = device_create_file(&device->dev, &dev_attr_display); | 889 | err = device_create_file(&device->dev, &dev_attr_display); |
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 6788acc22ab9..19ec95147f69 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
| @@ -570,10 +570,8 @@ static int ideapad_input_init(struct ideapad_private *priv) | |||
| 570 | int error; | 570 | int error; |
| 571 | 571 | ||
| 572 | inputdev = input_allocate_device(); | 572 | inputdev = input_allocate_device(); |
| 573 | if (!inputdev) { | 573 | if (!inputdev) |
| 574 | pr_info("Unable to allocate input device\n"); | ||
| 575 | return -ENOMEM; | 574 | return -ENOMEM; |
| 576 | } | ||
| 577 | 575 | ||
| 578 | inputdev->name = "Ideapad extra buttons"; | 576 | inputdev->name = "Ideapad extra buttons"; |
| 579 | inputdev->phys = "ideapad/input0"; | 577 | inputdev->phys = "ideapad/input0"; |
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c index 6b18aba82cfa..8d6775266d66 100644 --- a/drivers/platform/x86/intel_mid_powerbtn.c +++ b/drivers/platform/x86/intel_mid_powerbtn.c | |||
| @@ -66,10 +66,8 @@ static int mfld_pb_probe(struct platform_device *pdev) | |||
| 66 | return -EINVAL; | 66 | return -EINVAL; |
| 67 | 67 | ||
| 68 | input = input_allocate_device(); | 68 | input = input_allocate_device(); |
| 69 | if (!input) { | 69 | if (!input) |
| 70 | dev_err(&pdev->dev, "Input device allocation error\n"); | ||
| 71 | return -ENOMEM; | 70 | return -ENOMEM; |
| 72 | } | ||
| 73 | 71 | ||
| 74 | input->name = pdev->name; | 72 | input->name = pdev->name; |
| 75 | input->phys = "power-button/input0"; | 73 | input->phys = "power-button/input0"; |
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index d654f831410d..60ea476a9130 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c | |||
| @@ -58,12 +58,56 @@ | |||
| 58 | * message handler is called within firmware. | 58 | * message handler is called within firmware. |
| 59 | */ | 59 | */ |
| 60 | 60 | ||
| 61 | #define IPC_BASE_ADDR 0xFF11C000 /* IPC1 base register address */ | ||
| 62 | #define IPC_MAX_ADDR 0x100 /* Maximum IPC regisers */ | ||
| 63 | #define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */ | 61 | #define IPC_WWBUF_SIZE 20 /* IPC Write buffer Size */ |
| 64 | #define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */ | 62 | #define IPC_RWBUF_SIZE 20 /* IPC Read buffer Size */ |
| 65 | #define IPC_I2C_BASE 0xFF12B000 /* I2C control register base address */ | 63 | #define IPC_IOC 0x100 /* IPC command register IOC bit */ |
| 66 | #define IPC_I2C_MAX_ADDR 0x10 /* Maximum I2C regisers */ | 64 | |
| 65 | enum { | ||
| 66 | SCU_IPC_LINCROFT, | ||
| 67 | SCU_IPC_PENWELL, | ||
| 68 | SCU_IPC_CLOVERVIEW, | ||
| 69 | SCU_IPC_TANGIER, | ||
| 70 | }; | ||
| 71 | |||
| 72 | /* intel scu ipc driver data*/ | ||
| 73 | struct intel_scu_ipc_pdata_t { | ||
| 74 | u32 ipc_base; | ||
| 75 | u32 i2c_base; | ||
| 76 | u32 ipc_len; | ||
| 77 | u32 i2c_len; | ||
| 78 | u8 irq_mode; | ||
| 79 | }; | ||
| 80 | |||
| 81 | static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = { | ||
| 82 | [SCU_IPC_LINCROFT] = { | ||
| 83 | .ipc_base = 0xff11c000, | ||
| 84 | .i2c_base = 0xff12b000, | ||
| 85 | .ipc_len = 0x100, | ||
| 86 | .i2c_len = 0x10, | ||
| 87 | .irq_mode = 0, | ||
| 88 | }, | ||
| 89 | [SCU_IPC_PENWELL] = { | ||
| 90 | .ipc_base = 0xff11c000, | ||
| 91 | .i2c_base = 0xff12b000, | ||
| 92 | .ipc_len = 0x100, | ||
| 93 | .i2c_len = 0x10, | ||
| 94 | .irq_mode = 1, | ||
| 95 | }, | ||
| 96 | [SCU_IPC_CLOVERVIEW] = { | ||
| 97 | .ipc_base = 0xff11c000, | ||
| 98 | .i2c_base = 0xff12b000, | ||
| 99 | .ipc_len = 0x100, | ||
| 100 | .i2c_len = 0x10, | ||
| 101 | .irq_mode = 1, | ||
| 102 | }, | ||
| 103 | [SCU_IPC_TANGIER] = { | ||
| 104 | .ipc_base = 0xff009000, | ||
| 105 | .i2c_base = 0xff00d000, | ||
| 106 | .ipc_len = 0x100, | ||
| 107 | .i2c_len = 0x10, | ||
| 108 | .irq_mode = 0, | ||
| 109 | }, | ||
| 110 | }; | ||
| 67 | 111 | ||
| 68 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id); | 112 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id); |
| 69 | static void ipc_remove(struct pci_dev *pdev); | 113 | static void ipc_remove(struct pci_dev *pdev); |
| @@ -72,6 +116,8 @@ struct intel_scu_ipc_dev { | |||
| 72 | struct pci_dev *pdev; | 116 | struct pci_dev *pdev; |
| 73 | void __iomem *ipc_base; | 117 | void __iomem *ipc_base; |
| 74 | void __iomem *i2c_base; | 118 | void __iomem *i2c_base; |
| 119 | struct completion cmd_complete; | ||
| 120 | u8 irq_mode; | ||
| 75 | }; | 121 | }; |
| 76 | 122 | ||
| 77 | static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ | 123 | static struct intel_scu_ipc_dev ipcdev; /* Only one for now */ |
| @@ -98,6 +144,10 @@ static DEFINE_MUTEX(ipclock); /* lock used to prevent multiple call to SCU */ | |||
| 98 | */ | 144 | */ |
| 99 | static inline void ipc_command(u32 cmd) /* Send ipc command */ | 145 | static inline void ipc_command(u32 cmd) /* Send ipc command */ |
| 100 | { | 146 | { |
| 147 | if (ipcdev.irq_mode) { | ||
| 148 | reinit_completion(&ipcdev.cmd_complete); | ||
| 149 | writel(cmd | IPC_IOC, ipcdev.ipc_base); | ||
| 150 | } | ||
| 101 | writel(cmd, ipcdev.ipc_base); | 151 | writel(cmd, ipcdev.ipc_base); |
| 102 | } | 152 | } |
| 103 | 153 | ||
| @@ -156,6 +206,30 @@ static inline int busy_loop(void) /* Wait till scu status is busy */ | |||
| 156 | return 0; | 206 | return 0; |
| 157 | } | 207 | } |
| 158 | 208 | ||
| 209 | /* Wait till ipc ioc interrupt is received or timeout in 3 HZ */ | ||
| 210 | static inline int ipc_wait_for_interrupt(void) | ||
| 211 | { | ||
| 212 | int status; | ||
| 213 | |||
| 214 | if (!wait_for_completion_timeout(&ipcdev.cmd_complete, 3 * HZ)) { | ||
| 215 | struct device *dev = &ipcdev.pdev->dev; | ||
| 216 | dev_err(dev, "IPC timed out\n"); | ||
| 217 | return -ETIMEDOUT; | ||
| 218 | } | ||
| 219 | |||
| 220 | status = ipc_read_status(); | ||
| 221 | |||
| 222 | if ((status >> 1) & 1) | ||
| 223 | return -EIO; | ||
| 224 | |||
| 225 | return 0; | ||
| 226 | } | ||
| 227 | |||
| 228 | int intel_scu_ipc_check_status(void) | ||
| 229 | { | ||
| 230 | return ipcdev.irq_mode ? ipc_wait_for_interrupt() : busy_loop(); | ||
| 231 | } | ||
| 232 | |||
| 159 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ | 233 | /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ |
| 160 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | 234 | static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) |
| 161 | { | 235 | { |
| @@ -196,8 +270,8 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) | |||
| 196 | ipc_command(4 << 16 | id << 12 | 0 << 8 | op); | 270 | ipc_command(4 << 16 | id << 12 | 0 << 8 | op); |
| 197 | } | 271 | } |
| 198 | 272 | ||
| 199 | err = busy_loop(); | 273 | err = intel_scu_ipc_check_status(); |
| 200 | if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ | 274 | if (!err && id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ |
| 201 | /* Workaround: values are read as 0 without memcpy_fromio */ | 275 | /* Workaround: values are read as 0 without memcpy_fromio */ |
| 202 | memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); | 276 | memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); |
| 203 | for (nc = 0; nc < count; nc++) | 277 | for (nc = 0; nc < count; nc++) |
| @@ -391,7 +465,7 @@ int intel_scu_ipc_simple_command(int cmd, int sub) | |||
| 391 | return -ENODEV; | 465 | return -ENODEV; |
| 392 | } | 466 | } |
| 393 | ipc_command(sub << 12 | cmd); | 467 | ipc_command(sub << 12 | cmd); |
| 394 | err = busy_loop(); | 468 | err = intel_scu_ipc_check_status(); |
| 395 | mutex_unlock(&ipclock); | 469 | mutex_unlock(&ipclock); |
| 396 | return err; | 470 | return err; |
| 397 | } | 471 | } |
| @@ -425,10 +499,12 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen, | |||
| 425 | ipc_data_writel(*in++, 4 * i); | 499 | ipc_data_writel(*in++, 4 * i); |
| 426 | 500 | ||
| 427 | ipc_command((inlen << 16) | (sub << 12) | cmd); | 501 | ipc_command((inlen << 16) | (sub << 12) | cmd); |
| 428 | err = busy_loop(); | 502 | err = intel_scu_ipc_check_status(); |
| 429 | 503 | ||
| 430 | for (i = 0; i < outlen; i++) | 504 | if (!err) { |
| 431 | *out++ = ipc_data_readl(4 * i); | 505 | for (i = 0; i < outlen; i++) |
| 506 | *out++ = ipc_data_readl(4 * i); | ||
| 507 | } | ||
| 432 | 508 | ||
| 433 | mutex_unlock(&ipclock); | 509 | mutex_unlock(&ipclock); |
| 434 | return err; | 510 | return err; |
| @@ -491,6 +567,9 @@ EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); | |||
| 491 | */ | 567 | */ |
| 492 | static irqreturn_t ioc(int irq, void *dev_id) | 568 | static irqreturn_t ioc(int irq, void *dev_id) |
| 493 | { | 569 | { |
| 570 | if (ipcdev.irq_mode) | ||
| 571 | complete(&ipcdev.cmd_complete); | ||
| 572 | |||
| 494 | return IRQ_HANDLED; | 573 | return IRQ_HANDLED; |
| 495 | } | 574 | } |
| 496 | 575 | ||
| @@ -504,13 +583,18 @@ static irqreturn_t ioc(int irq, void *dev_id) | |||
| 504 | */ | 583 | */ |
| 505 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) | 584 | static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) |
| 506 | { | 585 | { |
| 507 | int err; | 586 | int err, pid; |
| 587 | struct intel_scu_ipc_pdata_t *pdata; | ||
| 508 | resource_size_t pci_resource; | 588 | resource_size_t pci_resource; |
| 509 | 589 | ||
| 510 | if (ipcdev.pdev) /* We support only one SCU */ | 590 | if (ipcdev.pdev) /* We support only one SCU */ |
| 511 | return -EBUSY; | 591 | return -EBUSY; |
| 512 | 592 | ||
| 593 | pid = id->driver_data; | ||
| 594 | pdata = &intel_scu_ipc_pdata[pid]; | ||
| 595 | |||
| 513 | ipcdev.pdev = pci_dev_get(dev); | 596 | ipcdev.pdev = pci_dev_get(dev); |
| 597 | ipcdev.irq_mode = pdata->irq_mode; | ||
| 514 | 598 | ||
| 515 | err = pci_enable_device(dev); | 599 | err = pci_enable_device(dev); |
| 516 | if (err) | 600 | if (err) |
| @@ -524,14 +608,16 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
| 524 | if (!pci_resource) | 608 | if (!pci_resource) |
| 525 | return -ENOMEM; | 609 | return -ENOMEM; |
| 526 | 610 | ||
| 611 | init_completion(&ipcdev.cmd_complete); | ||
| 612 | |||
| 527 | if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev)) | 613 | if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev)) |
| 528 | return -EBUSY; | 614 | return -EBUSY; |
| 529 | 615 | ||
| 530 | ipcdev.ipc_base = ioremap_nocache(IPC_BASE_ADDR, IPC_MAX_ADDR); | 616 | ipcdev.ipc_base = ioremap_nocache(pdata->ipc_base, pdata->ipc_len); |
| 531 | if (!ipcdev.ipc_base) | 617 | if (!ipcdev.ipc_base) |
| 532 | return -ENOMEM; | 618 | return -ENOMEM; |
| 533 | 619 | ||
| 534 | ipcdev.i2c_base = ioremap_nocache(IPC_I2C_BASE, IPC_I2C_MAX_ADDR); | 620 | ipcdev.i2c_base = ioremap_nocache(pdata->i2c_base, pdata->i2c_len); |
| 535 | if (!ipcdev.i2c_base) { | 621 | if (!ipcdev.i2c_base) { |
| 536 | iounmap(ipcdev.ipc_base); | 622 | iounmap(ipcdev.ipc_base); |
| 537 | return -ENOMEM; | 623 | return -ENOMEM; |
| @@ -564,7 +650,10 @@ static void ipc_remove(struct pci_dev *pdev) | |||
| 564 | } | 650 | } |
| 565 | 651 | ||
| 566 | static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { | 652 | static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { |
| 567 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, | 653 | {PCI_VDEVICE(INTEL, 0x082a), SCU_IPC_LINCROFT}, |
| 654 | {PCI_VDEVICE(INTEL, 0x080e), SCU_IPC_PENWELL}, | ||
| 655 | {PCI_VDEVICE(INTEL, 0x08ea), SCU_IPC_CLOVERVIEW}, | ||
| 656 | {PCI_VDEVICE(INTEL, 0x11a0), SCU_IPC_TANGIER}, | ||
| 568 | { 0,} | 657 | { 0,} |
| 569 | }; | 658 | }; |
| 570 | MODULE_DEVICE_TABLE(pci, pci_ids); | 659 | MODULE_DEVICE_TABLE(pci, pci_ids); |
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 10d12b221601..3008fd20572e 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c | |||
| @@ -490,11 +490,8 @@ static int acpi_pcc_init_input(struct pcc_acpi *pcc) | |||
| 490 | int error; | 490 | int error; |
| 491 | 491 | ||
| 492 | input_dev = input_allocate_device(); | 492 | input_dev = input_allocate_device(); |
| 493 | if (!input_dev) { | 493 | if (!input_dev) |
| 494 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 495 | "Couldn't allocate input device for hotkey")); | ||
| 496 | return -ENOMEM; | 494 | return -ENOMEM; |
| 497 | } | ||
| 498 | 495 | ||
| 499 | input_dev->name = ACPI_PCC_DRIVER_NAME; | 496 | input_dev->name = ACPI_PCC_DRIVER_NAME; |
| 500 | input_dev->phys = ACPI_PCC_INPUT_PHYS; | 497 | input_dev->phys = ACPI_PCC_INPUT_PHYS; |
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 47caab0ea7a1..fb233ae7bb0e 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
| @@ -140,12 +140,12 @@ MODULE_PARM_DESC(kbd_backlight_timeout, | |||
| 140 | "on the model (default: no change from current value)"); | 140 | "on the model (default: no change from current value)"); |
| 141 | 141 | ||
| 142 | #ifdef CONFIG_PM_SLEEP | 142 | #ifdef CONFIG_PM_SLEEP |
| 143 | static void sony_nc_kbd_backlight_resume(void); | ||
| 144 | static void sony_nc_thermal_resume(void); | 143 | static void sony_nc_thermal_resume(void); |
| 145 | #endif | 144 | #endif |
| 146 | static int sony_nc_kbd_backlight_setup(struct platform_device *pd, | 145 | static int sony_nc_kbd_backlight_setup(struct platform_device *pd, |
| 147 | unsigned int handle); | 146 | unsigned int handle); |
| 148 | static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd); | 147 | static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd, |
| 148 | unsigned int handle); | ||
| 149 | 149 | ||
| 150 | static int sony_nc_battery_care_setup(struct platform_device *pd, | 150 | static int sony_nc_battery_care_setup(struct platform_device *pd, |
| 151 | unsigned int handle); | 151 | unsigned int handle); |
| @@ -304,8 +304,8 @@ static int sony_laptop_input_keycode_map[] = { | |||
| 304 | KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */ | 304 | KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */ |
| 305 | KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */ | 305 | KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */ |
| 306 | KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */ | 306 | KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */ |
| 307 | KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */ | 307 | KEY_FN_1, /* 17 SONYPI_EVENT_FNKEY_1 */ |
| 308 | KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */ | 308 | KEY_FN_2, /* 18 SONYPI_EVENT_FNKEY_2 */ |
| 309 | KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */ | 309 | KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */ |
| 310 | KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */ | 310 | KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */ |
| 311 | KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */ | 311 | KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */ |
| @@ -1444,7 +1444,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd) | |||
| 1444 | case 0x014b: | 1444 | case 0x014b: |
| 1445 | case 0x014c: | 1445 | case 0x014c: |
| 1446 | case 0x0163: | 1446 | case 0x0163: |
| 1447 | sony_nc_kbd_backlight_cleanup(pd); | 1447 | sony_nc_kbd_backlight_cleanup(pd, handle); |
| 1448 | break; | 1448 | break; |
| 1449 | default: | 1449 | default: |
| 1450 | continue; | 1450 | continue; |
| @@ -1486,13 +1486,6 @@ static void sony_nc_function_resume(void) | |||
| 1486 | case 0x0135: | 1486 | case 0x0135: |
| 1487 | sony_nc_rfkill_update(); | 1487 | sony_nc_rfkill_update(); |
| 1488 | break; | 1488 | break; |
| 1489 | case 0x0137: | ||
| 1490 | case 0x0143: | ||
| 1491 | case 0x014b: | ||
| 1492 | case 0x014c: | ||
| 1493 | case 0x0163: | ||
| 1494 | sony_nc_kbd_backlight_resume(); | ||
| 1495 | break; | ||
| 1496 | default: | 1489 | default: |
| 1497 | continue; | 1490 | continue; |
| 1498 | } | 1491 | } |
| @@ -1822,6 +1815,12 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd, | |||
| 1822 | int result; | 1815 | int result; |
| 1823 | int ret = 0; | 1816 | int ret = 0; |
| 1824 | 1817 | ||
| 1818 | if (kbdbl_ctl) { | ||
| 1819 | pr_warn("handle 0x%.4x: keyboard backlight setup already done for 0x%.4x\n", | ||
| 1820 | handle, kbdbl_ctl->handle); | ||
| 1821 | return -EBUSY; | ||
| 1822 | } | ||
| 1823 | |||
| 1825 | /* verify the kbd backlight presence, these handles are not used for | 1824 | /* verify the kbd backlight presence, these handles are not used for |
| 1826 | * keyboard backlight only | 1825 | * keyboard backlight only |
| 1827 | */ | 1826 | */ |
| @@ -1881,9 +1880,10 @@ outkzalloc: | |||
| 1881 | return ret; | 1880 | return ret; |
| 1882 | } | 1881 | } |
| 1883 | 1882 | ||
| 1884 | static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd) | 1883 | static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd, |
| 1884 | unsigned int handle) | ||
| 1885 | { | 1885 | { |
| 1886 | if (kbdbl_ctl) { | 1886 | if (kbdbl_ctl && handle == kbdbl_ctl->handle) { |
| 1887 | device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); | 1887 | device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); |
| 1888 | device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr); | 1888 | device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr); |
| 1889 | kfree(kbdbl_ctl); | 1889 | kfree(kbdbl_ctl); |
| @@ -1891,25 +1891,6 @@ static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd) | |||
| 1891 | } | 1891 | } |
| 1892 | } | 1892 | } |
| 1893 | 1893 | ||
| 1894 | #ifdef CONFIG_PM_SLEEP | ||
| 1895 | static void sony_nc_kbd_backlight_resume(void) | ||
| 1896 | { | ||
| 1897 | int ignore = 0; | ||
| 1898 | |||
| 1899 | if (!kbdbl_ctl) | ||
| 1900 | return; | ||
| 1901 | |||
| 1902 | if (kbdbl_ctl->mode == 0) | ||
| 1903 | sony_call_snc_handle(kbdbl_ctl->handle, kbdbl_ctl->base, | ||
| 1904 | &ignore); | ||
| 1905 | |||
| 1906 | if (kbdbl_ctl->timeout != 0) | ||
| 1907 | sony_call_snc_handle(kbdbl_ctl->handle, | ||
| 1908 | (kbdbl_ctl->base + 0x200) | | ||
| 1909 | (kbdbl_ctl->timeout << 0x10), &ignore); | ||
| 1910 | } | ||
| 1911 | #endif | ||
| 1912 | |||
| 1913 | struct battery_care_control { | 1894 | struct battery_care_control { |
| 1914 | struct device_attribute attrs[2]; | 1895 | struct device_attribute attrs[2]; |
| 1915 | unsigned int handle; | 1896 | unsigned int handle; |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 05e046aa5e31..58b0274d24cc 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
| @@ -6438,7 +6438,12 @@ static struct ibm_struct brightness_driver_data = { | |||
| 6438 | #define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control" | 6438 | #define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control" |
| 6439 | #define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME | 6439 | #define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME |
| 6440 | 6440 | ||
| 6441 | static int alsa_index = ~((1 << (SNDRV_CARDS - 3)) - 1); /* last three slots */ | 6441 | #if SNDRV_CARDS <= 32 |
| 6442 | #define DEFAULT_ALSA_IDX ~((1 << (SNDRV_CARDS - 3)) - 1) | ||
| 6443 | #else | ||
| 6444 | #define DEFAULT_ALSA_IDX ~((1 << (32 - 3)) - 1) | ||
| 6445 | #endif | ||
| 6446 | static int alsa_index = DEFAULT_ALSA_IDX; /* last three slots */ | ||
| 6442 | static char *alsa_id = "ThinkPadEC"; | 6447 | static char *alsa_id = "ThinkPadEC"; |
| 6443 | static bool alsa_enable = SNDRV_DEFAULT_ENABLE1; | 6448 | static bool alsa_enable = SNDRV_DEFAULT_ENABLE1; |
| 6444 | 6449 | ||
| @@ -9163,7 +9168,6 @@ static int __init thinkpad_acpi_module_init(void) | |||
| 9163 | mutex_init(&tpacpi_inputdev_send_mutex); | 9168 | mutex_init(&tpacpi_inputdev_send_mutex); |
| 9164 | tpacpi_inputdev = input_allocate_device(); | 9169 | tpacpi_inputdev = input_allocate_device(); |
| 9165 | if (!tpacpi_inputdev) { | 9170 | if (!tpacpi_inputdev) { |
| 9166 | pr_err("unable to allocate input device\n"); | ||
| 9167 | thinkpad_acpi_module_exit(); | 9171 | thinkpad_acpi_module_exit(); |
| 9168 | return -ENOMEM; | 9172 | return -ENOMEM; |
| 9169 | } else { | 9173 | } else { |
diff --git a/drivers/platform/x86/topstar-laptop.c b/drivers/platform/x86/topstar-laptop.c index 67897c8740ba..e597de05e6c2 100644 --- a/drivers/platform/x86/topstar-laptop.c +++ b/drivers/platform/x86/topstar-laptop.c | |||
| @@ -97,10 +97,8 @@ static int acpi_topstar_init_hkey(struct topstar_hkey *hkey) | |||
| 97 | int error; | 97 | int error; |
| 98 | 98 | ||
| 99 | input = input_allocate_device(); | 99 | input = input_allocate_device(); |
| 100 | if (!input) { | 100 | if (!input) |
| 101 | pr_err("Unable to allocate input device\n"); | ||
| 102 | return -ENOMEM; | 101 | return -ENOMEM; |
| 103 | } | ||
| 104 | 102 | ||
| 105 | input->name = "Topstar Laptop extra buttons"; | 103 | input->name = "Topstar Laptop extra buttons"; |
| 106 | input->phys = "topstar/input0"; | 104 | input->phys = "topstar/input0"; |
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 0cfadb65f7c6..7fce391818d3 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
| @@ -975,10 +975,8 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
| 975 | u32 hci_result; | 975 | u32 hci_result; |
| 976 | 976 | ||
| 977 | dev->hotkey_dev = input_allocate_device(); | 977 | dev->hotkey_dev = input_allocate_device(); |
| 978 | if (!dev->hotkey_dev) { | 978 | if (!dev->hotkey_dev) |
| 979 | pr_info("Unable to register input device\n"); | ||
| 980 | return -ENOMEM; | 979 | return -ENOMEM; |
| 981 | } | ||
| 982 | 980 | ||
| 983 | dev->hotkey_dev->name = "Toshiba input device"; | 981 | dev->hotkey_dev->name = "Toshiba input device"; |
| 984 | dev->hotkey_dev->phys = "toshiba_acpi/input0"; | 982 | dev->hotkey_dev->phys = "toshiba_acpi/input0"; |
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 62e8c221d01e..c2e7b2657aeb 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c | |||
| @@ -672,8 +672,10 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, | |||
| 672 | struct wmi_block *wblock; | 672 | struct wmi_block *wblock; |
| 673 | 673 | ||
| 674 | wblock = dev_get_drvdata(dev); | 674 | wblock = dev_get_drvdata(dev); |
| 675 | if (!wblock) | 675 | if (!wblock) { |
| 676 | return -ENOMEM; | 676 | strcat(buf, "\n"); |
| 677 | return strlen(buf); | ||
| 678 | } | ||
| 677 | 679 | ||
| 678 | wmi_gtoa(wblock->gblock.guid, guid_string); | 680 | wmi_gtoa(wblock->gblock.guid, guid_string); |
| 679 | 681 | ||
