summaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-08-22 14:14:15 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-08-22 14:14:15 -0700
commit899fbc33fd775b9dfa363db28f322272920a2196 (patch)
treecdf16895e3cfed6950873894e0a54988f1a8a81b /drivers/platform/x86
parent2edd73a42e0ec847770c8f7ae511d43c26e59b74 (diff)
parent9bd5196e5cf7431d0118d86d7d784405663e763e (diff)
Merge tag 'platform-drivers-x86-v4.19-1' of git://git.infradead.org/linux-platform-drivers-x86
Pull x86 platform driver updates from Andy Shevchenko: - The driver for Silead touchscreen configurations has been renamed from silead_dmi to touchscreen_dmi since it starts supporting other touchscreens which require some DMI quirks It also gets expanded to cover cases for Chuwi Vi10, ONDA V891W, Connect Tablet 9, Onda V820w, and Cube KNote i1101 tablets. - Another bunch of changes is related to Mellanox platform code to allow user space to communicate with Mellanox for system control and monitoring purposes. The driver notifies user on hotplug device signal receiving. - ASUS WMI drivers recognize lid flip action on UX360, and correctly toggles airplane mode LED. In addition the keyboard backlight toggle gets support. - ThinkPad ACPI driver enables support for calculator key (on at least P52). It also has been fixed to support three characters model designators, which are used for modern laptops. Earlier the battery, marked as BAT1, on ThinkPad laptops has not been configured properly, which is fixed. On the opposite the multi-battery configurations now probed correctly. - Dell SMBIOS driver starts working on some Dell servers which do not support token interface. The regression with backlight detection has also been fixed. In order to support dock mode on some laptops, Intel virtual button driver has been fixed. The last but not least is the fix to Intel HID driver due to changes in Dell systems that prevented to use power button. * tag 'platform-drivers-x86-v4.19-1' of git://git.infradead.org/linux-platform-drivers-x86: (47 commits) platform/x86: acer-wmi: Silence "unsupported" message a bit platform/x86: intel_punit_ipc: fix build errors platform/x86: ideapad: Add Y520-15IKBM and Y720-15IKBM to no_hw_rfkill platform/x86: asus-nb-wmi: Add keymap entry for lid flip action on UX360 platform/x86: acer-wmi: refactor function has_cap platform/x86: thinkpad_acpi: Fix multi-battery bug platform/x86: thinkpad_acpi: extend battery quirk coverage platform/x86: touchscreen_dmi: Add info for the Cube KNote i1101 tablet platform/x86: mlx-platform: Fix copy-paste error in mlxplat_init() platform/x86: mlx-platform: Remove unused define platform/x86: mlx-platform: Change mlxreg-io configuration for MSN274x systems Documentation/ABI: Add new attribute for mlxreg-io sysfs interfaces platform/x86: mlx-platform: Allow mlxreg-io driver activation for more systems platform/x86: mlx-platform: Add ASIC hotplug device configuration platform/mellanox: mlxreg-hotplug: Add hotplug hwmon uevent notification platform/mellanox: mlxreg-hotplug: Improve mechanism of ASIC health discovery platform/x86: mlx-platform: Add mlxreg-fan platform driver activation platform/x86: dell-laptop: Fix backlight detection platform/x86: toshiba_acpi: Fix defined but not used build warnings platform/x86: thinkpad_acpi: Support battery quirk ...
Diffstat (limited to 'drivers/platform/x86')
-rw-r--r--drivers/platform/x86/Kconfig16
-rw-r--r--drivers/platform/x86/Makefile2
-rw-r--r--drivers/platform/x86/acer-wmi.c7
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c1
-rw-r--r--drivers/platform/x86/asus-wireless.c24
-rw-r--r--drivers/platform/x86/asus-wmi.c34
-rw-r--r--drivers/platform/x86/dell-smbios-base.c35
-rw-r--r--drivers/platform/x86/dell-smbios-smm.c4
-rw-r--r--drivers/platform/x86/dell-smbios-wmi.c2
-rw-r--r--drivers/platform/x86/ideapad-laptop.c18
-rw-r--r--drivers/platform/x86/intel-hid.c178
-rw-r--r--drivers/platform/x86/intel-vbtn.c5
-rw-r--r--drivers/platform/x86/intel_ips.c5
-rw-r--r--drivers/platform/x86/intel_pmc_core.c120
-rw-r--r--drivers/platform/x86/intel_pmc_core.h6
-rw-r--r--drivers/platform/x86/intel_punit_ipc.c1
-rw-r--r--drivers/platform/x86/mlx-platform.c486
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c135
-rw-r--r--drivers/platform/x86/toshiba_acpi.c33
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c (renamed from drivers/platform/x86/silead_dmi.c)639
-rw-r--r--drivers/platform/x86/wmi.c9
21 files changed, 1359 insertions, 401 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 107d336453b2..0c1aa6c314f5 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1196,16 +1196,16 @@ config INTEL_TURBO_MAX_3
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"
+config TOUCHSCREEN_DMI
+ bool "DMI based touchscreen configuration info"
depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD
---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.
+ Certain ACPI based tablets with e.g. Silead or Chipone touchscreens
+ do not have enough data in ACPI tables for the touchscreen driver to
+ handle the touchscreen properly, as OEMs expect the data to be baked
+ into the tablet model specific version of the driver shipped with the
+ the OS-image for the device. This option supplies the missing info.
+ Enable this for x86 tablets with Silead or Chipone touchscreens.
config INTEL_CHTDC_TI_PWRBTN
tristate "Intel Cherry Trail Dollar Cove TI power button driver"
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 50dc8f280914..e6d1becf81ce 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -78,7 +78,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_TOUCHSCREEN_DMI) += touchscreen_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
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 8952173dd380..fcfeadd1301f 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -672,10 +672,7 @@ static void __init find_quirks(void)
static bool has_cap(u32 cap)
{
- if ((interface->capability & cap) != 0)
- return 1;
-
- return 0;
+ return interface->capability & cap;
}
/*
@@ -2216,7 +2213,7 @@ static int __init acer_wmi_init(void)
if (wmi_has_guid(AMW0_GUID1) &&
!dmi_check_system(amw0_whitelist) &&
quirks == &quirk_unknown) {
- pr_err("Unsupported machine has AMW0_GUID1, unable to load\n");
+ pr_debug("Unsupported machine has AMW0_GUID1, unable to load\n");
return -ENODEV;
}
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index 136ff2b4cce5..db2af09067db 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -496,6 +496,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
{ KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
{ KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */
+ { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */
{ KE_END, 0},
};
diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c
index 6afd011de9e5..7458f7602d5e 100644
--- a/drivers/platform/x86/asus-wireless.c
+++ b/drivers/platform/x86/asus-wireless.c
@@ -52,13 +52,12 @@ static const struct acpi_device_id device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, device_ids);
-static u64 asus_wireless_method(acpi_handle handle, const char *method,
- int param)
+static acpi_status asus_wireless_method(acpi_handle handle, const char *method,
+ int param, u64 *ret)
{
struct acpi_object_list p;
union acpi_object obj;
acpi_status s;
- u64 ret;
acpi_handle_debug(handle, "Evaluating method %s, parameter %#x\n",
method, param);
@@ -67,24 +66,27 @@ static u64 asus_wireless_method(acpi_handle handle, const char *method,
p.count = 1;
p.pointer = &obj;
- s = acpi_evaluate_integer(handle, (acpi_string) method, &p, &ret);
+ s = acpi_evaluate_integer(handle, (acpi_string) method, &p, ret);
if (ACPI_FAILURE(s))
acpi_handle_err(handle,
"Failed to eval method %s, param %#x (%d)\n",
method, param, s);
- acpi_handle_debug(handle, "%s returned %#llx\n", method, ret);
- return ret;
+ else
+ acpi_handle_debug(handle, "%s returned %#llx\n", method, *ret);
+
+ return s;
}
static enum led_brightness led_state_get(struct led_classdev *led)
{
struct asus_wireless_data *data;
- int s;
+ acpi_status s;
+ u64 ret;
data = container_of(led, struct asus_wireless_data, led);
s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
- data->hswc_params->status);
- if (s == data->hswc_params->on)
+ data->hswc_params->status, &ret);
+ if (ACPI_SUCCESS(s) && ret == data->hswc_params->on)
return LED_FULL;
return LED_OFF;
}
@@ -92,10 +94,11 @@ static enum led_brightness led_state_get(struct led_classdev *led)
static void led_state_update(struct work_struct *work)
{
struct asus_wireless_data *data;
+ u64 ret;
data = container_of(work, struct asus_wireless_data, led_work);
asus_wireless_method(acpi_device_handle(data->adev), "HSWC",
- data->led_state);
+ data->led_state, &ret);
}
static void led_state_set(struct led_classdev *led, enum led_brightness value)
@@ -167,6 +170,7 @@ static int asus_wireless_add(struct acpi_device *adev)
data->led.brightness_get = led_state_get;
data->led.flags = LED_CORE_SUSPENDRESUME;
data->led.max_brightness = 1;
+ data->led.default_trigger = "rfkill-none";
err = devm_led_classdev_register(&adev->dev, &data->led);
if (err)
destroy_workqueue(data->wq);
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index d67f32a29bb4..2d6e272315a8 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -67,6 +67,7 @@ MODULE_LICENSE("GPL");
#define NOTIFY_BRNDOWN_MAX 0x2e
#define NOTIFY_KBD_BRTUP 0xc4
#define NOTIFY_KBD_BRTDWN 0xc5
+#define NOTIFY_KBD_BRTTOGGLE 0xc7
/* WMI Methods */
#define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */
@@ -470,6 +471,7 @@ static void kbd_led_update(struct work_struct *work)
ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F);
asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL);
+ led_classdev_notify_brightness_hw_changed(&asus->kbd_led, asus->kbd_led_wk);
}
static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
@@ -500,15 +502,16 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
return retval;
}
-static void kbd_led_set(struct led_classdev *led_cdev,
- enum led_brightness value)
+static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
{
struct asus_wmi *asus;
+ int max_level;
asus = container_of(led_cdev, struct asus_wmi, kbd_led);
+ max_level = asus->kbd_led.max_brightness;
- if (value > asus->kbd_led.max_brightness)
- value = asus->kbd_led.max_brightness;
+ if (value > max_level)
+ value = max_level;
else if (value < 0)
value = 0;
@@ -516,6 +519,12 @@ static void kbd_led_set(struct led_classdev *led_cdev,
queue_work(asus->led_workqueue, &asus->kbd_led_work);
}
+static void kbd_led_set(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ do_kbd_led_set(led_cdev, value);
+}
+
static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
{
struct asus_wmi *asus;
@@ -666,6 +675,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
asus->kbd_led_wk = led_val;
asus->kbd_led.name = "asus::kbd_backlight";
+ asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
asus->kbd_led.brightness_set = kbd_led_set;
asus->kbd_led.brightness_get = kbd_led_get;
asus->kbd_led.max_brightness = 3;
@@ -1754,6 +1764,22 @@ static void asus_wmi_notify(u32 value, void *context)
}
}
+ if (code == NOTIFY_KBD_BRTUP) {
+ do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1);
+ goto exit;
+ }
+ if (code == NOTIFY_KBD_BRTDWN) {
+ do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk - 1);
+ goto exit;
+ }
+ if (code == NOTIFY_KBD_BRTTOGGLE) {
+ if (asus->kbd_led_wk == asus->kbd_led.max_brightness)
+ do_kbd_led_set(&asus->kbd_led, 0);
+ else
+ do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1);
+ goto exit;
+ }
+
if (is_display_toggle(code) &&
asus->driver->quirks->no_display_toggle)
goto exit;
diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c
index 9dc282ed5a9e..0537d44d45a6 100644
--- a/drivers/platform/x86/dell-smbios-base.c
+++ b/drivers/platform/x86/dell-smbios-base.c
@@ -212,6 +212,12 @@ int dell_smbios_call_filter(struct device *d,
if ((buffer->cmd_class == CLASS_TOKEN_READ ||
buffer->cmd_class == CLASS_TOKEN_WRITE) &&
buffer->cmd_select < 3) {
+ /* tokens enabled ? */
+ if (!da_tokens) {
+ dev_dbg(d, "no token support on this system\n");
+ return -EINVAL;
+ }
+
/* find the matching token ID */
for (i = 0; i < da_num_tokens; i++) {
if (da_tokens[i].location != buffer->input[0])
@@ -315,6 +321,9 @@ struct calling_interface_token *dell_smbios_find_token(int tokenid)
{
int i;
+ if (!da_tokens)
+ return NULL;
+
for (i = 0; i < da_num_tokens; i++) {
if (da_tokens[i].tokenID == tokenid)
return &da_tokens[i];
@@ -565,11 +574,6 @@ static int __init dell_smbios_init(void)
dmi_walk(find_tokens, NULL);
- if (!da_tokens) {
- pr_info("Unable to find dmi tokens\n");
- return -ENODEV;
- }
-
ret = platform_driver_register(&platform_driver);
if (ret)
goto fail_platform_driver;
@@ -583,13 +587,6 @@ static int __init dell_smbios_init(void)
if (ret)
goto fail_platform_device_add;
- /* duplicate tokens will cause problems building sysfs files */
- zero_duplicates(&platform_device->dev);
-
- ret = build_tokens_sysfs(platform_device);
- if (ret)
- goto fail_create_group;
-
/* register backends */
wmi = init_dell_smbios_wmi();
if (wmi)
@@ -600,7 +597,16 @@ static int __init dell_smbios_init(void)
if (wmi && smm) {
pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n",
wmi, smm);
- goto fail_sysfs;
+ goto fail_create_group;
+ }
+
+ if (da_tokens) {
+ /* duplicate tokens will cause problems building sysfs files */
+ zero_duplicates(&platform_device->dev);
+
+ ret = build_tokens_sysfs(platform_device);
+ if (ret)
+ goto fail_sysfs;
}
return 0;
@@ -628,7 +634,8 @@ static void __exit dell_smbios_exit(void)
exit_dell_smbios_smm();
mutex_lock(&smbios_mutex);
if (platform_device) {
- free_group(platform_device);
+ if (da_tokens)
+ free_group(platform_device);
platform_device_unregister(platform_device);
platform_driver_unregister(&platform_driver);
}
diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c
index e9e9da556318..97a90bebc360 100644
--- a/drivers/platform/x86/dell-smbios-smm.c
+++ b/drivers/platform/x86/dell-smbios-smm.c
@@ -24,7 +24,7 @@
static int da_command_address;
static int da_command_code;
static struct calling_interface_buffer *buffer;
-struct platform_device *platform_device;
+static struct platform_device *platform_device;
static DEFINE_MUTEX(smm_mutex);
static const struct dmi_system_id dell_device_table[] __initconst = {
@@ -82,7 +82,7 @@ static void find_cmd_address(const struct dmi_header *dm, void *dummy)
}
}
-int dell_smbios_smm_call(struct calling_interface_buffer *input)
+static int dell_smbios_smm_call(struct calling_interface_buffer *input)
{
struct smi_cmd command;
size_t size;
diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c
index fbefedb1c172..88afe5651d24 100644
--- a/drivers/platform/x86/dell-smbios-wmi.c
+++ b/drivers/platform/x86/dell-smbios-wmi.c
@@ -82,7 +82,7 @@ static int run_smbios_call(struct wmi_device *wdev)
return 0;
}
-int dell_smbios_wmi_call(struct calling_interface_buffer *buffer)
+static int dell_smbios_wmi_call(struct calling_interface_buffer *buffer)
{
struct wmi_smbios_priv *priv;
size_t difference;
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 45b7cb01f410..d4f1259ff5a2 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -1133,10 +1133,17 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
},
},
{
- .ident = "Lenovo Legion Y520-15IKBN",
+ .ident = "Lenovo Legion Y520-15IKB",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKB"),
+ },
+ },
+ {
+ .ident = "Lenovo Y520-15IKBM",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBM"),
},
},
{
@@ -1154,6 +1161,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = {
},
},
{
+ .ident = "Lenovo Y720-15IKBM",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBM"),
+ },
+ },
+ {
.ident = "Lenovo Yoga 2 11 / 13 / Pro",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c
index b5adba227783..6cf9b7fa5bf0 100644
--- a/drivers/platform/x86/intel-hid.c
+++ b/drivers/platform/x86/intel-hid.c
@@ -96,13 +96,140 @@ struct intel_hid_priv {
bool wakeup_mode;
};
-static int intel_hid_set_enable(struct device *device, bool enable)
+#define HID_EVENT_FILTER_UUID "eeec56b3-4442-408f-a792-4edd4d758054"
+
+enum intel_hid_dsm_fn_codes {
+ INTEL_HID_DSM_FN_INVALID,
+ INTEL_HID_DSM_BTNL_FN,
+ INTEL_HID_DSM_HDMM_FN,
+ INTEL_HID_DSM_HDSM_FN,
+ INTEL_HID_DSM_HDEM_FN,
+ INTEL_HID_DSM_BTNS_FN,
+ INTEL_HID_DSM_BTNE_FN,
+ INTEL_HID_DSM_HEBC_V1_FN,
+ INTEL_HID_DSM_VGBS_FN,
+ INTEL_HID_DSM_HEBC_V2_FN,
+ INTEL_HID_DSM_FN_MAX
+};
+
+static const char *intel_hid_dsm_fn_to_method[INTEL_HID_DSM_FN_MAX] = {
+ NULL,
+ "BTNL",
+ "HDMM",
+ "HDSM",
+ "HDEM",
+ "BTNS",
+ "BTNE",
+ "HEBC",
+ "VGBS",
+ "HEBC"
+};
+
+static unsigned long long intel_hid_dsm_fn_mask;
+static guid_t intel_dsm_guid;
+
+static bool intel_hid_execute_method(acpi_handle handle,
+ enum intel_hid_dsm_fn_codes fn_index,
+ unsigned long long arg)
{
+ union acpi_object *obj, argv4, req;
acpi_status status;
+ char *method_name;
- status = acpi_execute_simple_method(ACPI_HANDLE(device), "HDSM",
- enable);
- if (ACPI_FAILURE(status)) {
+ if (fn_index <= INTEL_HID_DSM_FN_INVALID ||
+ fn_index >= INTEL_HID_DSM_FN_MAX)
+ return false;
+
+ method_name = (char *)intel_hid_dsm_fn_to_method[fn_index];
+
+ if (!(intel_hid_dsm_fn_mask & fn_index))
+ goto skip_dsm_exec;
+
+ /* All methods expects a package with one integer element */
+ req.type = ACPI_TYPE_INTEGER;
+ req.integer.value = arg;
+
+ argv4.type = ACPI_TYPE_PACKAGE;
+ argv4.package.count = 1;
+ argv4.package.elements = &req;
+
+ obj = acpi_evaluate_dsm(handle, &intel_dsm_guid, 1, fn_index, &argv4);
+ if (obj) {
+ acpi_handle_debug(handle, "Exec DSM Fn code: %d[%s] success\n",
+ fn_index, method_name);
+ ACPI_FREE(obj);
+ return true;
+ }
+
+skip_dsm_exec:
+ status = acpi_execute_simple_method(handle, method_name, arg);
+ if (ACPI_SUCCESS(status))
+ return true;
+
+ return false;
+}
+
+static bool intel_hid_evaluate_method(acpi_handle handle,
+ enum intel_hid_dsm_fn_codes fn_index,
+ unsigned long long *result)
+{
+ union acpi_object *obj;
+ acpi_status status;
+ char *method_name;
+
+ if (fn_index <= INTEL_HID_DSM_FN_INVALID ||
+ fn_index >= INTEL_HID_DSM_FN_MAX)
+ return false;
+
+ method_name = (char *)intel_hid_dsm_fn_to_method[fn_index];
+
+ if (!(intel_hid_dsm_fn_mask & fn_index))
+ goto skip_dsm_eval;
+
+ obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid,
+ 1, fn_index,
+ NULL, ACPI_TYPE_INTEGER);
+ if (obj) {
+ *result = obj->integer.value;
+ acpi_handle_debug(handle,
+ "Eval DSM Fn code: %d[%s] results: 0x%llx\n",
+ fn_index, method_name, *result);
+ ACPI_FREE(obj);
+ return true;
+ }
+
+skip_dsm_eval:
+ status = acpi_evaluate_integer(handle, method_name, NULL, result);
+ if (ACPI_SUCCESS(status))
+ return true;
+
+ return false;
+}
+
+static void intel_hid_init_dsm(acpi_handle handle)
+{
+ union acpi_object *obj;
+
+ guid_parse(HID_EVENT_FILTER_UUID, &intel_dsm_guid);
+
+ obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid, 1, 0, NULL,
+ ACPI_TYPE_BUFFER);
+ if (obj) {
+ intel_hid_dsm_fn_mask = *obj->buffer.pointer;
+ ACPI_FREE(obj);
+ }
+
+ acpi_handle_debug(handle, "intel_hid_dsm_fn_mask = %llx\n",
+ intel_hid_dsm_fn_mask);
+}
+
+static int intel_hid_set_enable(struct device *device, bool enable)
+{
+ acpi_handle handle = ACPI_HANDLE(device);
+
+ /* Enable|disable features - power button is always enabled */
+ if (!intel_hid_execute_method(handle, INTEL_HID_DSM_HDSM_FN,
+ enable)) {
dev_warn(device, "failed to %sable hotkeys\n",
enable ? "en" : "dis");
return -EIO;
@@ -129,9 +256,8 @@ static void intel_button_array_enable(struct device *device, bool enable)
}
/* Enable|disable features - power button is always enabled */
- status = acpi_execute_simple_method(handle, "BTNE",
- enable ? button_cap : 1);
- if (ACPI_FAILURE(status))
+ if (!intel_hid_execute_method(handle, INTEL_HID_DSM_BTNE_FN,
+ enable ? button_cap : 1))
dev_warn(device, "failed to set button capability\n");
}
@@ -217,7 +343,6 @@ static void notify_handler(acpi_handle handle, u32 event, void *context)
struct platform_device *device = context;
struct intel_hid_priv *priv = dev_get_drvdata(&device->dev);
unsigned long long ev_index;
- acpi_status status;
if (priv->wakeup_mode) {
/*
@@ -269,8 +394,8 @@ wakeup:
return;
}
- status = acpi_evaluate_integer(handle, "HDEM", NULL, &ev_index);
- if (ACPI_FAILURE(status)) {
+ if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDEM_FN,
+ &ev_index)) {
dev_warn(&device->dev, "failed to get event index\n");
return;
}
@@ -284,17 +409,24 @@ static bool button_array_present(struct platform_device *device)
{
acpi_handle handle = ACPI_HANDLE(&device->dev);
unsigned long long event_cap;
- acpi_status status;
- bool supported = false;
- status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap);
- if (ACPI_SUCCESS(status) && (event_cap & 0x20000))
- supported = true;
+ if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V2_FN,
+ &event_cap)) {
+ /* Check presence of 5 button array or v2 power button */
+ if (event_cap & 0x60000)
+ return true;
+ }
+
+ if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V1_FN,
+ &event_cap)) {
+ if (event_cap & 0x20000)
+ return true;
+ }
if (dmi_check_system(button_array_table))
- supported = true;
+ return true;
- return supported;
+ return false;
}
static int intel_hid_probe(struct platform_device *device)
@@ -305,8 +437,9 @@ static int intel_hid_probe(struct platform_device *device)
acpi_status status;
int err;
- status = acpi_evaluate_integer(handle, "HDMM", NULL, &mode);
- if (ACPI_FAILURE(status)) {
+ intel_hid_init_dsm(handle);
+
+ if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDMM_FN, &mode)) {
dev_warn(&device->dev, "failed to read mode\n");
return -ENODEV;
}
@@ -352,13 +485,16 @@ static int intel_hid_probe(struct platform_device *device)
goto err_remove_notify;
if (priv->array) {
+ unsigned long long dummy;
+
intel_button_array_enable(&device->dev, true);
/* Call button load method to enable HID power button */
- status = acpi_evaluate_object(handle, "BTNL", NULL, NULL);
- if (ACPI_FAILURE(status))
+ if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_BTNL_FN,
+ &dummy)) {
dev_warn(&device->dev,
"failed to enable HID power button\n");
+ }
}
device_init_wakeup(&device->dev, true);
diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c
index c13780b8dabb..06cd7e818ed5 100644
--- a/drivers/platform/x86/intel-vbtn.c
+++ b/drivers/platform/x86/intel-vbtn.c
@@ -17,6 +17,7 @@
/* When NOT in tablet mode, VGBS returns with the flag 0x40 */
#define TABLET_MODE_FLAG 0x40
+#define DOCK_MODE_FLAG 0x80
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AceLan Kao");
@@ -38,6 +39,8 @@ static const struct key_entry intel_vbtn_keymap[] = {
{ KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */
{ KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key press */
{ KE_KEY, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key release */
+ { KE_SW, 0xCA, { .sw = { SW_DOCK, 1 } } }, /* Docked */
+ { KE_SW, 0xCB, { .sw = { SW_DOCK, 0 } } }, /* Undocked */
{ KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */
{ KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */
{ KE_END },
@@ -121,6 +124,8 @@ static void detect_tablet_mode(struct platform_device *device)
m = !(obj->integer.value & TABLET_MODE_FLAG);
input_report_switch(priv->input_dev, SW_TABLET_MODE, m);
+ m = (obj->integer.value & DOCK_MODE_FLAG) ? 1 : 0;
+ input_report_switch(priv->input_dev, SW_DOCK, m);
out:
kfree(vgbs_output.pointer);
}
diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c
index 014fc1634a3d..c5ece7ef08c6 100644
--- a/drivers/platform/x86/intel_ips.c
+++ b/drivers/platform/x86/intel_ips.c
@@ -858,10 +858,7 @@ static u16 read_mgtv(struct ips_driver *ips)
static u16 read_ptv(struct ips_driver *ips)
{
- u16 val, slope, offset;
-
- slope = (ips->pta_val & PTA_SLOPE_MASK) >> PTA_SLOPE_SHIFT;
- offset = ips->pta_val & PTA_OFFSET_MASK;
+ u16 val;
val = thm_readw(THM_PTV) & PTV_MASK;
diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c
index 43bbe74743d9..2d272a3e0176 100644
--- a/drivers/platform/x86/intel_pmc_core.c
+++ b/drivers/platform/x86/intel_pmc_core.c
@@ -196,9 +196,67 @@ static const struct pmc_bit_map cnp_pfear_map[] = {
{}
};
+static const struct pmc_bit_map cnp_slps0_dbg0_map[] = {
+ {"AUDIO_D3", BIT(0)},
+ {"OTG_D3", BIT(1)},
+ {"XHCI_D3", BIT(2)},
+ {"LPIO_D3", BIT(3)},
+ {"SDX_D3", BIT(4)},
+ {"SATA_D3", BIT(5)},
+ {"UFS0_D3", BIT(6)},
+ {"UFS1_D3", BIT(7)},
+ {"EMMC_D3", BIT(8)},
+ {}
+};
+
+static const struct pmc_bit_map cnp_slps0_dbg1_map[] = {
+ {"SDIO_PLL_OFF", BIT(0)},
+ {"USB2_PLL_OFF", BIT(1)},
+ {"AUDIO_PLL_OFF", BIT(2)},
+ {"OC_PLL_OFF", BIT(3)},
+ {"MAIN_PLL_OFF", BIT(4)},
+ {"XOSC_OFF", BIT(5)},
+ {"LPC_CLKS_GATED", BIT(6)},
+ {"PCIE_CLKREQS_IDLE", BIT(7)},
+ {"AUDIO_ROSC_OFF", BIT(8)},
+ {"HPET_XOSC_CLK_REQ", BIT(9)},
+ {"PMC_ROSC_SLOW_CLK", BIT(10)},
+ {"AON2_ROSC_GATED", BIT(11)},
+ {"CLKACKS_DEASSERTED", BIT(12)},
+ {}
+};
+
+static const struct pmc_bit_map cnp_slps0_dbg2_map[] = {
+ {"MPHY_CORE_GATED", BIT(0)},
+ {"CSME_GATED", BIT(1)},
+ {"USB2_SUS_GATED", BIT(2)},
+ {"DYN_FLEX_IO_IDLE", BIT(3)},
+ {"GBE_NO_LINK", BIT(4)},
+ {"THERM_SEN_DISABLED", BIT(5)},
+ {"PCIE_LOW_POWER", BIT(6)},
+ {"ISH_VNNAON_REQ_ACT", BIT(7)},
+ {"ISH_VNN_REQ_ACT", BIT(8)},
+ {"CNV_VNNAON_REQ_ACT", BIT(9)},
+ {"CNV_VNN_REQ_ACT", BIT(10)},
+ {"NPK_VNNON_REQ_ACT", BIT(11)},
+ {"PMSYNC_STATE_IDLE", BIT(12)},
+ {"ALST_GT_THRES", BIT(13)},
+ {"PMC_ARC_PG_READY", BIT(14)},
+ {}
+};
+
+static const struct pmc_bit_map *cnp_slps0_dbg_maps[] = {
+ cnp_slps0_dbg0_map,
+ cnp_slps0_dbg1_map,
+ cnp_slps0_dbg2_map,
+ NULL,
+};
+
static const struct pmc_reg_map cnp_reg_map = {
.pfear_sts = cnp_pfear_map,
.slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET,
+ .slps0_dbg_maps = cnp_slps0_dbg_maps,
+ .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET,
.ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET,
.regmap_length = CNP_PMC_MMIO_REG_LEN,
.ppfear0_offset = CNP_PMC_HOST_PPFEAR0A,
@@ -252,6 +310,8 @@ static int pmc_core_check_read_lock_bit(void)
}
#if IS_ENABLED(CONFIG_DEBUG_FS)
+static bool slps0_dbg_latch;
+
static void pmc_core_display_map(struct seq_file *s, int index,
u8 pf_reg, const struct pmc_bit_map *pf_map)
{
@@ -481,6 +541,57 @@ static const struct file_operations pmc_core_ltr_ignore_ops = {
.release = single_release,
};
+static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset)
+{
+ const struct pmc_reg_map *map = pmcdev->map;
+ u32 fd;
+
+ mutex_lock(&pmcdev->lock);
+
+ if (!reset && !slps0_dbg_latch)
+ goto out_unlock;
+
+ fd = pmc_core_reg_read(pmcdev, map->slps0_dbg_offset);
+ if (reset)
+ fd &= ~CNP_PMC_LATCH_SLPS0_EVENTS;
+ else
+ fd |= CNP_PMC_LATCH_SLPS0_EVENTS;
+ pmc_core_reg_write(pmcdev, map->slps0_dbg_offset, fd);
+
+ slps0_dbg_latch = 0;
+
+out_unlock:
+ mutex_unlock(&pmcdev->lock);
+}
+
+static int pmc_core_slps0_dbg_show(struct seq_file *s, void *unused)
+{
+ struct pmc_dev *pmcdev = s->private;
+ const struct pmc_bit_map **maps = pmcdev->map->slps0_dbg_maps;
+ const struct pmc_bit_map *map;
+ int offset;
+ u32 data;
+
+ pmc_core_slps0_dbg_latch(pmcdev, false);
+ offset = pmcdev->map->slps0_dbg_offset;
+ while (*maps) {
+ map = *maps;
+ data = pmc_core_reg_read(pmcdev, offset);
+ offset += 4;
+ while (map->name) {
+ seq_printf(s, "SLP_S0_DBG: %-32s\tState: %s\n",
+ map->name,
+ data & map->bit_mask ?
+ "Yes" : "No");
+ ++map;
+ }
+ ++maps;
+ }
+ pmc_core_slps0_dbg_latch(pmcdev, true);
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(pmc_core_slps0_dbg);
+
static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev)
{
debugfs_remove_recursive(pmcdev->dbgfs_dir);
@@ -514,6 +625,15 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev)
0444, dir, pmcdev,
&pmc_core_mphy_