summaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-02-25 14:35:37 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-25 14:35:37 -0800
commit94eae8034002401d71ae950106659e16add36e77 (patch)
tree111846689f951b9615cc67cd285699090b924447 /drivers/platform
parent5d8a00eee2ed2e548a5d21b0edf495f3f7bf8bb4 (diff)
parentaf050abb5c2e5e7d3e1368475d63cbac597dc34f (diff)
Merge tag 'platform-drivers-x86-v4.11-1' of git://git.infradead.org/linux-platform-drivers-x86
Pull x86 platform driver updates from Darren Hart: "Big picture: - New intel_turbo_max_3 driver, providing max core frequency information to the scheduler. Intel PMC APL support, s0ix read API, and fixes. - New Silead touchscreen platform touchscreen descriptions. Additional hotkey support for the intel-hid driver. - New model support for dell-laptop and hp_accel. - Several cleanups, especially to the fujitsu-laptop and intel_mid_powerbtn drivers. Detail summary: platorm/x86: - silead depends on I2C being built-in - add support for devices with Silead touchscreens - Support Turbo Boost Max 3.0 for non HWP systems intel_turbo_max_3: - make it explicitly non-modular dell-laptop: - Add Latitude 7480 and others to the DMI whitelist intel-hid: - Support 5 button array thinkpad_acpi: - Call led_classdev_notify_brightness_hw_changed on kbd brightness change - Use brightness_set_blocking callback for LEDs - Stop setting led_classdev brightness directly acer-wmi: - add another KEY_WLAN keycode - Inform firmware that RF Button Driver is active - setup accelerometer when machine has appropriate notify event asus-wireless: - Fix indentation - Use per-HID HSWC parameters intel_pmc_ipc: - Add APL PMC PCI Id - read s0ix residency API - Remove unused iTCO_version variable alienware-wmi: - Remove header duplicate intel_pmc_core: - fix out-of-bounds accesses on stack intel_mid_powerbtn: - Use SCU IPC directly - Unify IRQ acknowledgment - Move comment to where it belongs - Unify PBSTATUS access - Remove snail address - Sort headers alphabetically - Join string literals - Enable driver for Merrifield - Acknowledge interrupts - Factor out mfld_ack() - Introduce driver data - Substitute mfld by mid - Convert to use devm_*() fujitsu-laptop: - make hotkey handling functions more similar - break up complex loop condition - move keycode processing to separate functions - decrease indentation in acpi_fujitsu_hotkey_notify() - simplify logolamp_get() - rework logolamp_set() to properly handle errors - set default trigger for radio LED to rfkill-any dell-smbios: - Auto-select as needed intel_mid_thermal: - Fix module autoload - Remove duplicated platform device ID mlx-platform: - mlxcpld-hotplug driver style fixes hp_accel: - Add support for HP ZBook 17" * tag 'platform-drivers-x86-v4.11-1' of git://git.infradead.org/linux-platform-drivers-x86: (45 commits) platform/x86: intel_turbo_max_3: make it explicitly non-modular platform/x86: dell-laptop: Add Latitude 7480 and others to the DMI whitelist platform/x86: intel-hid: Support 5 button array platform/x86: thinkpad_acpi: Call led_classdev_notify_brightness_hw_changed on kbd brightness change platform/x86: thinkpad_acpi: Use brightness_set_blocking callback for LEDs platform/x86: thinkpad_acpi: Stop setting led_classdev brightness directly leds: class: Add new optional brightness_hw_changed attribute platform/x86: acer-wmi: add another KEY_WLAN keycode platform/x86: acer-wmi: Inform firmware that RF Button Driver is active platform/x86: asus-wireless: Fix indentation platform/x86: asus-wireless: Use per-HID HSWC parameters platform/x86: intel_pmc_ipc: Add APL PMC PCI Id platform/x86: intel_pmc_ipc: read s0ix residency API platform/x86: alienware-wmi: Remove header duplicate platform/x86: intel_mid_powerbtn: Use SCU IPC directly platform/x86: intel_mid_powerbtn: Unify IRQ acknowledgment platform/x86: intel_mid_powerbtn: Move comment to where it belongs platform/x86: intel_mid_powerbtn: Unify PBSTATUS access platform/x86: intel_pmc_core: fix out-of-bounds accesses on stack platform/x86: silead depends on I2C being built-in ...
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig31
-rw-r--r--drivers/platform/x86/Makefile2
-rw-r--r--drivers/platform/x86/acer-wmi.c97
-rw-r--r--drivers/platform/x86/alienware-wmi.c1
-rw-r--r--drivers/platform/x86/asus-wireless.c60
-rw-r--r--drivers/platform/x86/dell-laptop.c6
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c220
-rw-r--r--drivers/platform/x86/hp_accel.c1
-rw-r--r--drivers/platform/x86/intel-hid.c96
-rw-r--r--drivers/platform/x86/intel_mid_powerbtn.c187
-rw-r--r--drivers/platform/x86/intel_mid_thermal.c2
-rw-r--r--drivers/platform/x86/intel_pmc_core.c6
-rw-r--r--drivers/platform/x86/intel_pmc_ipc.c67
-rw-r--r--drivers/platform/x86/intel_turbo_max_3.c151
-rw-r--r--drivers/platform/x86/mlx-platform.c84
-rw-r--r--drivers/platform/x86/silead_dmi.c136
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c124
17 files changed, 951 insertions, 320 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index a9e9c91cf4d4..4bc88eb52712 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -92,9 +92,8 @@ config ASUS_LAPTOP
If you have an ACPI-compatible ASUS laptop, say Y or M here.
config DELL_SMBIOS
- tristate "Dell SMBIOS Support"
- depends on DCDBAS
- default n
+ tristate
+ select DCDBAS
---help---
This module provides common functions for kernel modules using
Dell SMBIOS.
@@ -103,16 +102,15 @@ config DELL_SMBIOS
config DELL_LAPTOP
tristate "Dell Laptop Extras"
- depends on DELL_SMBIOS
depends on DMI
depends on BACKLIGHT_CLASS_DEVICE
depends on ACPI_VIDEO || ACPI_VIDEO = n
depends on RFKILL || RFKILL = n
depends on SERIO_I8042
+ select DELL_SMBIOS
select POWER_SUPPLY
select LEDS_CLASS
select NEW_LEDS
- default n
---help---
This driver adds support for rfkill and backlight control to Dell
laptops (except for some models covered by the Compal driver).
@@ -123,7 +121,7 @@ config DELL_WMI
depends on DMI
depends on INPUT
depends on ACPI_VIDEO || ACPI_VIDEO = n
- depends on DELL_SMBIOS
+ select DELL_SMBIOS
select INPUT_SPARSEKMAP
---help---
Say Y here if you want to support WMI-based hotkeys on Dell laptops.
@@ -1069,6 +1067,27 @@ config MLX_CPLD_PLATFORM
This driver handles hot-plug events for the power suppliers, power
cables and fans on the wide range Mellanox IB and Ethernet systems.
+config INTEL_TURBO_MAX_3
+ bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
+ depends on X86_64 && SCHED_MC_PRIO
+ ---help---
+ This driver reads maximum performance ratio of each CPU and set up
+ the scheduler priority metrics. In this way scheduler can prefer
+ CPU with higher performance to schedule tasks.
+ This driver is only required when the system is not using Hardware
+ P-States (HWP). In HWP mode, priority can be read from ACPI tables.
+
+config SILEAD_DMI
+ bool "Tablets with Silead touchscreens"
+ depends on ACPI && DMI && I2C=y && INPUT
+ ---help---
+ Certain ACPI based tablets with Silead touchscreens do not have
+ enough data in ACPI tables for the touchscreen driver to handle
+ the touchscreen properly, as OEMs expected the data to be baked
+ into the tablet model specific version of the driver shipped
+ with the OS-image for the device. This option supplies the missing
+ information. Enable this for x86 tablets with Silead touchscreens.
+
endif # X86_PLATFORM_DEVICES
config PMC_ATOM
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index cf9fc3e930c7..299d0f9e40f7 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o
obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o
+obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o
obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o
obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o
obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
@@ -76,3 +77,4 @@ obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o
obj-$(CONFIG_PMC_ATOM) += pmc_atom.o
obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o
obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o
+obj-$(CONFIG_INTEL_TURBO_MAX_3) += intel_turbo_max_3.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index a66192f692e3..dac0fbe87460 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -128,6 +128,7 @@ static const struct key_entry acer_wmi_keymap[] __initconst = {
{KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },
{KE_IGNORE, 0x83, {KEY_TOUCHPAD_TOGGLE} },
{KE_KEY, 0x85, {KEY_TOUCHPAD_TOGGLE} },
+ {KE_KEY, 0x86, {KEY_WLAN} },
{KE_END, 0}
};
@@ -150,15 +151,30 @@ struct event_return_value {
#define ACER_WMID3_GDS_BLUETOOTH (1<<11) /* BT */
#define ACER_WMID3_GDS_TOUCHPAD (1<<1) /* Touchpad */
-struct lm_input_params {
+/* Hotkey Customized Setting and Acer Application Status.
+ * Set Device Default Value and Report Acer Application Status.
+ * When Acer Application starts, it will run this method to inform
+ * BIOS/EC that Acer Application is on.
+ * App Status
+ * Bit[0]: Launch Manager Status
+ * Bit[1]: ePM Status
+ * Bit[2]: Device Control Status
+ * Bit[3]: Acer Power Button Utility Status
+ * Bit[4]: RF Button Status
+ * Bit[5]: ODD PM Status
+ * Bit[6]: Device Default Value Control
+ * Bit[7]: Hall Sensor Application Status
+ */
+struct func_input_params {
u8 function_num; /* Function Number */
u16 commun_devices; /* Communication type devices default status */
u16 devices; /* Other type devices default status */
- u8 lm_status; /* Launch Manager Status */
- u16 reserved;
+ u8 app_status; /* Acer Device Status. LM, ePM, RF Button... */
+ u8 app_mask; /* Bit mask to app_status */
+ u8 reserved;
} __attribute__((packed));
-struct lm_return_value {
+struct func_return_value {
u8 error_code; /* Error Code */
u8 ec_return_value; /* EC Return Value */
u16 reserved;
@@ -1769,13 +1785,13 @@ static void acer_wmi_notify(u32 value, void *context)
}
static acpi_status __init
-wmid3_set_lm_mode(struct lm_input_params *params,
- struct lm_return_value *return_value)
+wmid3_set_function_mode(struct func_input_params *params,
+ struct func_return_value *return_value)
{
acpi_status status;
union acpi_object *obj;
- struct acpi_buffer input = { sizeof(struct lm_input_params), params };
+ struct acpi_buffer input = { sizeof(struct func_input_params), params };
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output);
@@ -1796,7 +1812,7 @@ wmid3_set_lm_mode(struct lm_input_params *params,
return AE_ERROR;
}
- *return_value = *((struct lm_return_value *)obj->buffer.pointer);
+ *return_value = *((struct func_return_value *)obj->buffer.pointer);
kfree(obj);
return status;
@@ -1804,16 +1820,17 @@ wmid3_set_lm_mode(struct lm_input_params *params,
static int __init acer_wmi_enable_ec_raw(void)
{
- struct lm_return_value return_value;
+ struct func_return_value return_value;
acpi_status status;
- struct lm_input_params params = {
+ struct func_input_params params = {
.function_num = 0x1,
.commun_devices = 0xFFFF,
.devices = 0xFFFF,
- .lm_status = 0x00, /* Launch Manager Deactive */
+ .app_status = 0x00, /* Launch Manager Deactive */
+ .app_mask = 0x01,
};
- status = wmid3_set_lm_mode(&params, &return_value);
+ status = wmid3_set_function_mode(&params, &return_value);
if (return_value.error_code || return_value.ec_return_value)
pr_warn("Enabling EC raw mode failed: 0x%x - 0x%x\n",
@@ -1827,16 +1844,17 @@ static int __init acer_wmi_enable_ec_raw(void)
static int __init acer_wmi_enable_lm(void)
{
- struct lm_return_value return_value;
+ struct func_return_value return_value;
acpi_status status;
- struct lm_input_params params = {
+ struct func_input_params params = {
.function_num = 0x1,
.commun_devices = 0xFFFF,
.devices = 0xFFFF,
- .lm_status = 0x01, /* Launch Manager Active */
+ .app_status = 0x01, /* Launch Manager Active */
+ .app_mask = 0x01,
};
- status = wmid3_set_lm_mode(&params, &return_value);
+ status = wmid3_set_function_mode(&params, &return_value);
if (return_value.error_code || return_value.ec_return_value)
pr_warn("Enabling Launch Manager failed: 0x%x - 0x%x\n",
@@ -1846,11 +1864,46 @@ static int __init acer_wmi_enable_lm(void)
return status;
}
+static int __init acer_wmi_enable_rf_button(void)
+{
+ struct func_return_value return_value;
+ acpi_status status;
+ struct func_input_params params = {
+ .function_num = 0x1,
+ .commun_devices = 0xFFFF,
+ .devices = 0xFFFF,
+ .app_status = 0x10, /* RF Button Active */
+ .app_mask = 0x10,
+ };
+
+ status = wmid3_set_function_mode(&params, &return_value);
+
+ if (return_value.error_code || return_value.ec_return_value)
+ pr_warn("Enabling RF Button failed: 0x%x - 0x%x\n",
+ return_value.error_code,
+ return_value.ec_return_value);
+
+ return status;
+}
+
+#define ACER_WMID_ACCEL_HID "BST0001"
+
static acpi_status __init acer_wmi_get_handle_cb(acpi_handle ah, u32 level,
void *ctx, void **retval)
{
+ struct acpi_device *dev;
+
+ if (!strcmp(ctx, "SENR")) {
+ if (acpi_bus_get_device(ah, &dev))
+ return AE_OK;
+ if (!strcmp(ACER_WMID_ACCEL_HID, acpi_device_hid(dev)))
+ return AE_OK;
+ } else
+ return AE_OK;
+
*(acpi_handle *)retval = ah;
- return AE_OK;
+
+ return AE_CTRL_TERMINATE;
}
static int __init acer_wmi_get_handle(const char *name, const char *prop,
@@ -1877,7 +1930,7 @@ static int __init acer_wmi_accel_setup(void)
{
int err;
- err = acer_wmi_get_handle("SENR", "BST0001", &gsensor_handle);
+ err = acer_wmi_get_handle("SENR", ACER_WMID_ACCEL_HID, &gsensor_handle);
if (err)
return err;
@@ -2216,6 +2269,9 @@ static int __init acer_wmi_init(void)
interface->capability &= ~ACER_CAP_BRIGHTNESS;
if (wmi_has_guid(WMID_GUID3)) {
+ if (ACPI_FAILURE(acer_wmi_enable_rf_button()))
+ pr_warn("Cannot enable RF Button Driver\n");
+
if (ec_raw_mode) {
if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) {
pr_err("Cannot enable EC raw mode\n");
@@ -2233,10 +2289,11 @@ static int __init acer_wmi_init(void)
err = acer_wmi_input_setup();
if (err)
return err;
+ err = acer_wmi_accel_setup();
+ if (err)
+ return err;
}
- acer_wmi_accel_setup();
-
err = platform_driver_register(&acer_platform_driver);
if (err) {
pr_err("Unable to register platform driver\n");
diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c
index 005629447b0c..d6b34923fb4e 100644
--- a/drivers/platform/x86/alienware-wmi.c
+++ b/drivers/platform/x86/alienware-wmi.c
@@ -21,7 +21,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dmi.h>
-#include <linux/acpi.h>
#include <linux/leds.h>
#define LEGACY_CONTROL_GUID "A90597CE-A997-11DA-B012-B622A1EF5492"
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
index 9f31bc1a47d0..f3796164329e 100644
--- a/drivers/platform/x86/asus-wireless.c
+++ b/drivers/platform/x86/asus-wireless.c
@@ -17,19 +17,41 @@
#include <linux/pci_ids.h>
#include <linux/leds.h>
-#define ASUS_WIRELESS_LED_STATUS 0x2
-#define ASUS_WIRELESS_LED_OFF 0x4
-#define ASUS_WIRELESS_LED_ON 0x5
+struct hswc_params {
+ u8 on;
+ u8 off;
+ u8 status;
+};
struct asus_wireless_data {
struct input_dev *idev;
struct acpi_device *adev;
+ const struct hswc_params *hswc_params;
struct workqueue_struct *wq;
struct work_struct led_work;
struct led_classdev led;
int led_state;
};
+static const struct hswc_params atk4001_id_params = {
+ .on = 0x0,
+ .off = 0x1,
+ .status = 0x2,
+};
+
+static const struct hswc_params atk4002_id_params = {
+ .on = 0x5,
+ .off = 0x4,
+ .status = 0x2,
+};
+
+static const struct acpi_device_id device_ids[] = {
+ {"ATK4001", (kernel_ulong_t)&atk4001_id_params},
+ {"ATK4002", (kernel_ulong_t)&atk4002_id_params},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, device_ids);
+
static u64 asus_wireless_method(acpi_handle handle, const char *method,
int param)
{
@@ -61,8 +83,8 @@ static enum led_brightness led_state_get(struct led_classdev *led)
data = container_of(led, struct asus_wireless_data, led);
s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
- ASUS_WIRELESS_LED_STATUS);
- if (s == ASUS_WIRELESS_LED_ON)
+ data->hswc_params->status);
+ if (s == data->hswc_params->on)
return LED_FULL;
return LED_OFF;
}
@@ -76,14 +98,13 @@ static void led_state_update(struct work_struct *work)
data->led_state);
}
-static void led_state_set(struct led_classdev *led,
- enum led_brightness value)
+static void led_state_set(struct led_classdev *led, enum led_brightness value)
{
struct asus_wireless_data *data;
data = container_of(led, struct asus_wireless_data, led);
- data->led_state = value == LED_OFF ? ASUS_WIRELESS_LED_OFF :
- ASUS_WIRELESS_LED_ON;
+ data->led_state = value == LED_OFF ? data->hswc_params->off :
+ data->hswc_params->on;
queue_work(data->wq, &data->led_work);
}
@@ -104,12 +125,14 @@ static void asus_wireless_notify(struct acpi_device *adev, u32 event)
static int asus_wireless_add(struct acpi_device *adev)
{
struct asus_wireless_data *data;
+ const struct acpi_device_id *id;
int err;
data = devm_kzalloc(&adev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
adev->driver_data = data;
+ data->adev = adev;
data->idev = devm_input_allocate_device(&adev->dev);
if (!data->idev)
@@ -124,7 +147,16 @@ static int asus_wireless_add(struct acpi_device *adev)
if (err)
return err;
- data->adev = adev;
+ for (id = device_ids; id->id[0]; id++) {
+ if (!strcmp((char *) id->id, acpi_device_hid(adev))) {
+ data->hswc_params =
+ (const struct hswc_params *)id->driver_data;
+ break;
+ }
+ }
+ if (!data->hswc_params)
+ return 0;
+
data->wq = create_singlethread_workqueue("asus_wireless_workqueue");
if (!data->wq)
return -ENOMEM;
@@ -137,6 +169,7 @@ static int asus_wireless_add(struct acpi_device *adev)
err = devm_led_classdev_register(&adev->dev, &data->led);
if (err)
destroy_workqueue(data->wq);
+
return err;
}
@@ -149,13 +182,6 @@ static int asus_wireless_remove(struct acpi_device *adev)
return 0;
}
-static const struct acpi_device_id device_ids[] = {
- {"ATK4001", 0},
- {"ATK4002", 0},
- {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, device_ids);
-
static struct acpi_driver asus_wireless_driver = {
.name = "Asus Wireless Radio Control Driver",
.class = "hotkey",
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index 14392a01ab36..f57dd282a002 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -106,6 +106,12 @@ static const struct dmi_system_id dell_device_table[] __initconst = {
},
},
{
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /*Notebook*/
+ },
+ },
+ {
.ident = "Dell Computer Corporation",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 82d67715ce76..2b218b1d13e5 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -202,6 +202,7 @@ static int radio_led_set(struct led_classdev *cdev,
static struct led_classdev radio_led = {
.name = "fujitsu::radio_led",
+ .default_trigger = "rfkill-any",
.brightness_get = radio_led_get,
.brightness_set_blocking = radio_led_set
};
@@ -270,15 +271,20 @@ static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
static int logolamp_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
- if (brightness >= LED_FULL) {
- call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
- return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON);
- } else if (brightness >= LED_HALF) {
- call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
- return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF);
- } else {
- return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF);
- }
+ int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
+ int ret;
+
+ if (brightness < LED_HALF)
+ poweron = FUNC_LED_OFF;
+
+ if (brightness < LED_FULL)
+ always = FUNC_LED_OFF;
+
+ ret = call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
+ if (ret < 0)
+ return ret;
+
+ return call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
}
static int kblamps_set(struct led_classdev *cdev,
@@ -313,17 +319,17 @@ static int eco_led_set(struct led_classdev *cdev,
static enum led_brightness logolamp_get(struct led_classdev *cdev)
{
- enum led_brightness brightness = LED_OFF;
- int poweron, always;
-
- poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
- if (poweron == FUNC_LED_ON) {
- brightness = LED_HALF;
- always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
- if (always == FUNC_LED_ON)
- brightness = LED_FULL;
- }
- return brightness;
+ int ret;
+
+ ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
+ if (ret == FUNC_LED_ON)
+ return LED_FULL;
+
+ ret = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
+ if (ret == FUNC_LED_ON)
+ return LED_HALF;
+
+ return LED_OFF;
}
static enum led_brightness kblamps_get(struct led_classdev *cdev)
@@ -1029,107 +1035,117 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device)
return 0;
}
+static void acpi_fujitsu_hotkey_press(int keycode)
+{
+ struct input_dev *input = fujitsu_hotkey->input;
+ int status;
+
+ status = kfifo_in_locked(&fujitsu_hotkey->fifo,
+ (unsigned char *)&keycode, sizeof(keycode),
+ &fujitsu_hotkey->fifo_lock);
+ if (status != sizeof(keycode)) {
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "Could not push keycode [0x%x]\n", keycode);
+ return;
+ }
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "Push keycode into ringbuffer [%d]\n", keycode);
+}
+
+static void acpi_fujitsu_hotkey_release(void)
+{
+ struct input_dev *input = fujitsu_hotkey->input;
+ int keycode, status;
+
+ while (true) {
+ status = kfifo_out_locked(&fujitsu_hotkey->fifo,
+ (unsigned char *)&keycode,
+ sizeof(keycode),
+ &fujitsu_hotkey->fifo_lock);
+ if (status != sizeof(keycode))
+ return;
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+ vdbg_printk(FUJLAPTOP_DBG_TRACE,
+ "Pop keycode from ringbuffer [%d]\n", keycode);
+ }
+}
+
static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event)
{
struct input_dev *input;
- int keycode, keycode_r;
+ int keycode;
unsigned int irb = 1;
- int i, status;
+ int i;
input = fujitsu_hotkey->input;
+ if (event != ACPI_FUJITSU_NOTIFY_CODE1) {
+ keycode = KEY_UNKNOWN;
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "Unsupported event [0x%x]\n", event);
+ input_report_key(input, keycode, 1);
+ input_sync(input);
+ input_report_key(input, keycode, 0);
+ input_sync(input);
+ return;
+ }
+
if (fujitsu_hotkey->rfkill_supported)
fujitsu_hotkey->rfkill_state =
call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
- switch (event) {
- case ACPI_FUJITSU_NOTIFY_CODE1:
- i = 0;
- while ((irb =
- call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
- && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
- switch (irb & 0x4ff) {
- case KEY1_CODE:
- keycode = fujitsu->keycode1;
- break;
- case KEY2_CODE:
- keycode = fujitsu->keycode2;
- break;
- case KEY3_CODE:
- keycode = fujitsu->keycode3;
- break;
- case KEY4_CODE:
- keycode = fujitsu->keycode4;
- break;
- case KEY5_CODE:
- keycode = fujitsu->keycode5;
- break;
- case 0:
- keycode = 0;
- break;
- default:
- vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Unknown GIRB result [%x]\n", irb);
- keycode = -1;
- break;
- }
- if (keycode > 0) {
- vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "Push keycode into ringbuffer [%d]\n",
- keycode);
- status = kfifo_in_locked(&fujitsu_hotkey->fifo,
- (unsigned char *)&keycode,
- sizeof(keycode),
- &fujitsu_hotkey->fifo_lock);
- if (status != sizeof(keycode)) {
- vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Could not push keycode [0x%x]\n",
- keycode);
- } else {
- input_report_key(input, keycode, 1);
- input_sync(input);
- }
- } else if (keycode == 0) {
- while ((status =
- kfifo_out_locked(
- &fujitsu_hotkey->fifo,
- (unsigned char *) &keycode_r,
- sizeof(keycode_r),
- &fujitsu_hotkey->fifo_lock))
- == sizeof(keycode_r)) {
- input_report_key(input, keycode_r, 0);
- input_sync(input);
- vdbg_printk(FUJLAPTOP_DBG_TRACE,
- "Pop keycode from ringbuffer [%d]\n",
- keycode_r);
- }
- }
+ i = 0;
+ while ((irb =
+ call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
+ && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
+ switch (irb & 0x4ff) {
+ case KEY1_CODE:
+ keycode = fujitsu->keycode1;
+ break;
+ case KEY2_CODE:
+ keycode = fujitsu->keycode2;
+ break;
+ case KEY3_CODE:
+ keycode = fujitsu->keycode3;
+ break;
+ case KEY4_CODE:
+ keycode = fujitsu->keycode4;
+ break;
+ case KEY5_CODE:
+ keycode = fujitsu->keycode5;
+ break;
+ case 0:
+ keycode = 0;
+ break;
+ default:
+ vdbg_printk(FUJLAPTOP_DBG_WARN,
+ "Unknown GIRB result [%x]\n", irb);
+ keycode = -1;
+ break;
}
- /* On some models (first seen on the Skylake-based Lifebook
- * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is
- * handled in software; its state is queried using FUNC_RFKILL
- */
- if ((fujitsu_hotkey->rfkill_supported & BIT(26)) &&
- (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) {
- keycode = KEY_TOUCHPAD_TOGGLE;
- input_report_key(input, keycode, 1);
- input_sync(input);
- input_report_key(input, keycode, 0);
- input_sync(input);
- }
+ if (keycode > 0)
+ acpi_fujitsu_hotkey_press(keycode);
+ else if (keycode == 0)
+ acpi_fujitsu_hotkey_release();
+ }
- break;
- default:
- keycode = KEY_UNKNOWN;
- vdbg_printk(FUJLAPTOP_DBG_WARN,
- "Unsupported event [0x%x]\n", event);
+ /* On some models (first seen on the Skylake-based Lifebook
+ * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is
+ * handled in software; its state is queried using FUNC_RFKILL
+ */
+ if ((fujitsu_hotkey->rfkill_supported & BIT(26)) &&
+ (call_fext_func(FUNC_RFKILL, 0x1, 0x0, 0x0) & BIT(26))) {
+ keycode = KEY_TOUCHPAD_TOGGLE;
input_report_key(input, keycode, 1);
input_sync(input);
input_report_key(input, keycode, 0);
input_sync(input);
- break;
}
+
}
/* Initialization */
diff --git a/drivers/platform/x86/hp_accel.c b/drivers/platform/x86/hp_accel.c
index 09356684c32f..493d8910a74e 100644
--- a/drivers/platform/x86/hp_accel.c
+++ b/drivers/platform/x86/hp_accel.c
@@ -251,6 +251,7 @@ static const struct dmi_system_id lis3lv02d_dmi_ids[] = {
AXIS_DMI_MATCH("HPB64xx", "HP EliteBook 84", xy_swap),
AXIS_DMI_MATCH("HPB65xx", "HP ProBook 65", x_inverted),
AXIS_DMI_MATCH("HPZBook15", "HP ZBook 15", x_inverted),
+ AXIS_DMI_MATCH("HPZBook17", "HP ZBook 17", xy_swap_yz_inverted),
{ NULL, }
/* Laptop models without axis info (yet):
* "NC6910" "HP Compaq 6910"
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index cb3ab2b212b1..bcf438f38781 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -1,5 +1,5 @@
/*
- * Intel HID event driver for Windows 8
+ * Intel HID event & 5 button array driver
*
* Copyright (C) 2015 Alex Hung <alex.hung@canonical.com>
* Copyright (C) 2015 Andrew Lutomirski <luto@kernel.org>
@@ -57,8 +57,24 @@ static const struct key_entry intel_hid_keymap[] = {
{ KE_END },
};
+/* 5 button array notification value. */
+static const struct key_entry intel_array_keymap[] = {
+ { KE_KEY, 0xC2, { KEY_LEFTMETA } }, /* Press */
+ { KE_IGNORE, 0xC3, { KEY_LEFTMETA } }, /* Release */
+ { KE_KEY, 0xC4, { KEY_VOLUMEUP } }, /* Press */
+ { KE_IGNORE, 0xC5, { KEY_VOLUMEUP } }, /* Release */
+ { KE_KEY, 0xC6, { KEY_VOLUMEDOWN } }, /* Press */
+ { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* Release */
+ { KE_SW, 0xC8, { .sw = { SW_ROTATE_LOCK, 1 } } }, /* Press */
+ { KE_SW, 0xC9, { .sw = { SW_ROTATE_LOCK, 0 } } }, /* Release */
+ { KE_KEY, 0xCE, { KEY_POWER } }, /* Press */
+ { KE_IGNORE, 0xCF, { KEY_POWER } }, /* Release */
+ { KE_END },
+};
+
struct intel_hid_priv {
struct input_dev *input_dev;
+ struct input_dev *array;
};
static int intel_hid_set_enable(struct device *device, int enable)
@@ -78,15 +94,43 @@ static int intel_hid_set_enable(struct device *device, int enable)
return 0;
}
+static void intel_button_array_enable(struct device *device, bool enable)
+{
+ struct intel_hid_priv *priv = dev_get_drvdata(device);
+ acpi_handle handle = ACPI_HANDLE(device);
+ unsigned long long button_cap;
+ acpi_status status;
+
+ if (!priv->array)
+ return;
+
+ /* Query supported platform features */
+ status = acpi_evaluate_integer(handle, "BTNC", NULL, &button_cap);
+ if (ACPI_FAILURE(status)) {
+ dev_warn(device, "failed to get button capability\n");
+ return;
+ }
+
+ /* Enable|disable features - power button is always enabled */
+ status = acpi_execute_simple_method(handle, "BTNE",
+ enable ? button_cap : 1);
+ if (ACPI_FAILURE(status))
+ dev_warn(device, "failed to set button capability\n");
+}
+
static int intel_hid_pl_suspend_handler(struct device *device)
{
intel_hid_set_enable(device, 0);
+ intel_button_array_enable(device, false);
+
return 0;
}
static int intel_hid_pl_resume_handler(struct device *device)
{
intel_hid_set_enable(device, 1);
+ intel_button_array_enable(device, true);
+
return 0;
}
@@ -126,6 +170,27 @@ err_free_device:
return ret;
}
+static int intel_button_array_input_setup(struct platform_device *device)
+{
+ struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
+ int ret;
+
+ /* Setup input device for 5 button array */
+ priv->array = devm_input_allocate_device(&device->dev);
+ if (!priv->array)
+ return -ENOMEM;
+
+ ret = sparse_keymap_setup(priv->array, intel_array_keymap, NULL);
+ if (ret)
+ return ret;
+
+ priv->array->dev.parent = &device->dev;
+ priv->array->name = "Intel HID 5 button array";
+ priv->array->id.bustype = BUS_HOST;
+
+ return input_register_device(priv->array);
+}
+
static void intel_hid_input_destroy(struct platform_device *device)
{
struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
@@ -140,10 +205,11 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
unsigned long long ev_index;
acpi_status status;
- /* The platform spec only defines one event code: 0xC0. */
+ /* 0xC0 is for HID events, other values are for 5 button array */
if (event != 0xc0) {
- dev_warn(&device->dev, "received unknown event (0x%x)\n",
- event);
+ if (!priv->array ||
+ !sparse_keymap_report_event(priv->array, event, 1, true))
+ dev_info(&device->dev, "unknown event 0x%x\n", event);
return;
}
@@ -161,8 +227,8 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
static int intel_hid_probe(struct platform_device *device)
{
acpi_handle handle = ACPI_HANDLE(&device->dev);
+ unsigned long long event_cap, mode;
struct intel_hid_priv *priv;
- unsigned long long mode;
acpi_status status;