diff options
author | Linus Torvalds | 2016-01-19 17:54:15 -0800 |
---|---|---|
committer | Linus Torvalds | 2016-01-19 17:54:15 -0800 |
commit | 2b4015e9fb335aa6982a68dbe6e4158d6c1b10ee (patch) | |
tree | 2af6f884c42804cda14821f527a6237d4a1a3ee7 /drivers/platform/x86/thinkpad_acpi.c | |
parent | d36ccdbd1ca1050ad4e7b9b16ced848132533f6e (diff) | |
parent | 4bef0a27e414f79e0200f33ab23adeb07965272e (diff) |
Merge tag 'platform-drivers-x86-v4.5-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull x86 platform driver updates from Darren Hart:
"Add intel punit and telemetry driver for APL SoCs.
Add intel-hid driver for various laptop hotkey support.
Add asus-wireless radio control driver.
Keyboard backlight support/improvements for ThinkPads, Vaio, and Toshiba.
Several hotkey related fixes and improvements for dell and toshiba.
Fix oops on dual GPU Macs in apple-gmux.
A few new device IDs and quirks.
Various minor config related build issues and cleanups.
surface pro 4:
- fix compare_const_fl.cocci warnings
- Add support for Surface Pro 4 Buttons
platform/x86:
- Add Intel Telemetry Debugfs interfaces
- Add Intel telemetry platform device
- Add Intel telemetry platform driver
- Add Intel Telemetry Core Driver
- add NULL check for input parameters
- add Intel P-Unit mailbox IPC driver
- update acpi resource structure for Punit
thinkpad_acpi:
- Add support for keyboard backlight
dell-wmi:
- Process only one event on devices with interface version 0
- Check if Dell WMI descriptor structure is valid
- Improve unknown hotkey handling
- Use a C99-style array for bios_to_linux_keycode
tc1100-wmi:
- fix build warning when CONFIG_PM not enabled
asus-wireless:
- Add ACPI HID ATK4001
- Add Asus Wireless Radio Control driver
asus-wmi:
- drop to_platform_driver macro
intel-hid:
- new hid event driver for hotkeys
sony-laptop:
- Keyboard backlight control for some Vaio Fit models
ideapad-laptop:
- Add Lenovo ideapad Y700-17ISK to no_hw_rfkill dmi list
apple-gmux:
- Assign apple_gmux_data before registering
toshiba_acpi:
- Add rfkill dependency to ACPI_TOSHIBA entry
- Fix keyboard backlight sysfs entries not being updated
- Add WWAN RFKill support
- Add support for WWAN devices
- Fix blank screen at boot if transflective backlight is supported
- Propagate the hotkey value via genetlink
toshiba_bluetooth:
- Add missing newline in toshiba_bluetooth_present function"
* tag 'platform-drivers-x86-v4.5-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (29 commits)
surface pro 4: fix compare_const_fl.cocci warnings
surface pro 4: Add support for Surface Pro 4 Buttons
platform:x86: Add Intel Telemetry Debugfs interfaces
platform:x86: Add Intel telemetry platform device
platform:x86: Add Intel telemetry platform driver
platform/x86: Add Intel Telemetry Core Driver
intel_punit_ipc: add NULL check for input parameters
thinkpad_acpi: Add support for keyboard backlight
dell-wmi: Process only one event on devices with interface version 0
dell-wmi: Check if Dell WMI descriptor structure is valid
tc1100-wmi: fix build warning when CONFIG_PM not enabled
asus-wireless: Add ACPI HID ATK4001
platform/x86: Add Asus Wireless Radio Control driver
asus-wmi: drop to_platform_driver macro
intel-hid: new hid event driver for hotkeys
Keyboard backlight control for some Vaio Fit models
platform/x86: Add rfkill dependency to ACPI_TOSHIBA entry
platform:x86: add Intel P-Unit mailbox IPC driver
intel_pmc_ipc: update acpi resource structure for Punit
ideapad-laptop: Add Lenovo ideapad Y700-17ISK to no_hw_rfkill dmi list
...
Diffstat (limited to 'drivers/platform/x86/thinkpad_acpi.c')
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index f453d5dc085e..1f0eda2cc06a 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -303,6 +303,7 @@ static struct { u32 hotkey_mask:1; u32 hotkey_wlsw:1; u32 hotkey_tablet:1; + u32 kbdlight:1; u32 light:1; u32 light_status:1; u32 bright_acpimode:1; @@ -4986,6 +4987,207 @@ static struct ibm_struct video_driver_data = { #endif /* CONFIG_THINKPAD_ACPI_VIDEO */ /************************************************************************* + * Keyboard backlight subdriver + */ + +static int kbdlight_set_level(int level) +{ + if (!hkey_handle) + return -ENXIO; + + if (!acpi_evalf(hkey_handle, NULL, "MLCS", "dd", level)) + return -EIO; + + return 0; +} + +static int kbdlight_get_level(void) +{ + int status = 0; + + if (!hkey_handle) + return -ENXIO; + + if (!acpi_evalf(hkey_handle, &status, "MLCG", "dd", 0)) + return -EIO; + + if (status < 0) + return status; + + return status & 0x3; +} + +static bool kbdlight_is_supported(void) +{ + int status = 0; + + if (!hkey_handle) + return false; + + if (!acpi_has_method(hkey_handle, "MLCG")) { + vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG is unavailable\n"); + return false; + } + + if (!acpi_evalf(hkey_handle, &status, "MLCG", "qdd", 0)) { + vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG failed\n"); + return false; + } + + if (status < 0) { + vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG err: %d\n", status); + return false; + } + + vdbg_printk(TPACPI_DBG_INIT, "kbdlight MLCG returned 0x%x\n", status); + /* + * Guessed test for keyboard backlight: + * + * Machines with backlight keyboard return: + * b010100000010000000XX - ThinkPad X1 Carbon 3rd + * b110100010010000000XX - ThinkPad x230 + * b010100000010000000XX - ThinkPad x240 + * b010100000010000000XX - ThinkPad W541 + * (XX is current backlight level) + * + * Machines without backlight keyboard return: + * b10100001000000000000 - ThinkPad x230 + * b10110001000000000000 - ThinkPad E430 + * b00000000000000000000 - ThinkPad E450 + * + * Candidate BITs for detection test (XOR): + * b01000000001000000000 + * ^ + */ + return status & BIT(9); +} + +static void kbdlight_set_worker(struct work_struct *work) +{ + struct tpacpi_led_classdev *data = + container_of(work, struct tpacpi_led_classdev, work); + + if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING)) + kbdlight_set_level(data->new_state); +} + +static void kbdlight_sysfs_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct tpacpi_led_classdev *data = + container_of(led_cdev, + struct tpacpi_led_classdev, + led_classdev); + data->new_state = brightness; + queue_work(tpacpi_wq, &data->work); +} + +static enum led_brightness kbdlight_sysfs_get(struct led_classdev *led_cdev) +{ + int level; + + level = kbdlight_get_level(); + if (level < 0) + return 0; + + return level; +} + +static struct tpacpi_led_classdev tpacpi_led_kbdlight = { + .led_classdev = { + .name = "tpacpi::kbd_backlight", + .max_brightness = 2, + .brightness_set = &kbdlight_sysfs_set, + .brightness_get = &kbdlight_sysfs_get, + .flags = LED_CORE_SUSPENDRESUME, + } +}; + +static int __init kbdlight_init(struct ibm_init_struct *iibm) +{ + int rc; + + vdbg_printk(TPACPI_DBG_INIT, "initializing kbdlight subdriver\n"); + + TPACPI_ACPIHANDLE_INIT(hkey); + INIT_WORK(&tpacpi_led_kbdlight.work, kbdlight_set_worker); + + if (!kbdlight_is_supported()) { + tp_features.kbdlight = 0; + vdbg_printk(TPACPI_DBG_INIT, "kbdlight is unsupported\n"); + return 1; + } + + tp_features.kbdlight = 1; + + rc = led_classdev_register(&tpacpi_pdev->dev, + &tpacpi_led_kbdlight.led_classdev); + if (rc < 0) { + tp_features.kbdlight = 0; + return rc; + } + + return 0; +} + +static void kbdlight_exit(void) +{ + if (tp_features.kbdlight) + led_classdev_unregister(&tpacpi_led_kbdlight.led_classdev); + flush_workqueue(tpacpi_wq); +} + +static int kbdlight_read(struct seq_file *m) +{ + int level; + + if (!tp_features.kbdlight) { + seq_printf(m, "status:\t\tnot supported\n"); + } else { + level = kbdlight_get_level(); + if (level < 0) + seq_printf(m, "status:\t\terror %d\n", level); + else + seq_printf(m, "status:\t\t%d\n", level); + seq_printf(m, "commands:\t0, 1, 2\n"); + } + + return 0; +} + +static int kbdlight_write(char *buf) +{ + char *cmd; + int level = -1; + + if (!tp_features.kbdlight) + return -ENODEV; + + while ((cmd = next_cmd(&buf))) { + if (strlencmp(cmd, "0") == 0) + level = 0; + else if (strlencmp(cmd, "1") == 0) + level = 1; + else if (strlencmp(cmd, "2") == 0) + level = 2; + else + return -EINVAL; + } + + if (level == -1) + return -EINVAL; + + return kbdlight_set_level(level); +} + +static struct ibm_struct kbdlight_driver_data = { + .name = "kbdlight", + .read = kbdlight_read, + .write = kbdlight_write, + .exit = kbdlight_exit, +}; + +/************************************************************************* * Light (thinklight) subdriver */ @@ -9207,6 +9409,10 @@ static struct ibm_init_struct ibms_init[] __initdata = { }, #endif { + .init = kbdlight_init, + .data = &kbdlight_driver_data, + }, + { .init = light_init, .data = &light_driver_data, }, |