2019-10-17 19:43:04 +00:00
|
|
|
From 5d229605142d04aed881b5df78faf510a3782e4d Mon Sep 17 00:00:00 2001
|
2019-07-02 22:36:37 +00:00
|
|
|
From: Maximilian Luz <luzmaximilian@gmail.com>
|
2019-07-26 02:15:42 +00:00
|
|
|
Date: Fri, 26 Jul 2019 03:42:15 +0200
|
2019-07-02 22:37:16 +00:00
|
|
|
Subject: [PATCH 03/12] buttons
|
2019-01-27 16:01:27 +00:00
|
|
|
|
|
|
|
---
|
2019-07-20 22:01:46 +00:00
|
|
|
drivers/input/misc/Kconfig | 6 +-
|
2019-10-17 19:43:04 +00:00
|
|
|
drivers/input/misc/soc_button_array.c | 112 +++++++++++++++++++---
|
|
|
|
drivers/platform/x86/surfacepro3_button.c | 47 +++++++++
|
|
|
|
3 files changed, 150 insertions(+), 15 deletions(-)
|
2019-01-27 16:01:27 +00:00
|
|
|
|
2019-07-20 22:01:46 +00:00
|
|
|
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
|
|
|
|
index ca59a2be9bc5..ea69610370e8 100644
|
|
|
|
--- a/drivers/input/misc/Kconfig
|
|
|
|
+++ b/drivers/input/misc/Kconfig
|
|
|
|
@@ -781,10 +781,10 @@ config INPUT_IDEAPAD_SLIDEBAR
|
|
|
|
|
|
|
|
config INPUT_SOC_BUTTON_ARRAY
|
|
|
|
tristate "Windows-compatible SoC Button Array"
|
|
|
|
- depends on KEYBOARD_GPIO
|
|
|
|
+ depends on KEYBOARD_GPIO && ACPI
|
|
|
|
help
|
|
|
|
- Say Y here if you have a SoC-based tablet that originally
|
|
|
|
- runs Windows 8.
|
|
|
|
+ Say Y here if you have a SoC-based tablet that originally runs
|
|
|
|
+ Windows 8 or a Microsoft Surface Book 2, Pro 5, Laptop 1 or later.
|
|
|
|
|
|
|
|
To compile this driver as a module, choose M here: the
|
|
|
|
module will be called soc_button_array.
|
2019-01-27 16:01:27 +00:00
|
|
|
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
|
2019-10-17 19:43:04 +00:00
|
|
|
index 55cd6e0b409c..5983733d78dd 100644
|
2019-01-27 16:01:27 +00:00
|
|
|
--- a/drivers/input/misc/soc_button_array.c
|
|
|
|
+++ b/drivers/input/misc/soc_button_array.c
|
2019-07-27 16:27:19 +00:00
|
|
|
@@ -29,6 +29,11 @@ struct soc_button_info {
|
2019-01-27 16:01:27 +00:00
|
|
|
bool wakeup;
|
|
|
|
};
|
|
|
|
|
|
|
|
+struct soc_device_data {
|
2019-07-27 16:27:19 +00:00
|
|
|
+ const struct soc_button_info *button_info;
|
2019-04-24 18:51:10 +00:00
|
|
|
+ int (*check)(struct device *dev);
|
2019-01-27 16:01:27 +00:00
|
|
|
+};
|
|
|
|
+
|
|
|
|
/*
|
|
|
|
* Some of the buttons like volume up/down are auto repeat, while others
|
|
|
|
* are not. To support both, we register two platform devices, and put
|
2019-10-17 19:43:04 +00:00
|
|
|
@@ -91,8 +96,20 @@ soc_button_device_create(struct platform_device *pdev,
|
2019-07-06 23:07:34 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index);
|
|
|
|
- if (!gpio_is_valid(gpio))
|
2019-10-17 19:43:04 +00:00
|
|
|
+ if (!gpio_is_valid(gpio)) {
|
|
|
|
+ /*
|
|
|
|
+ * Skip GPIO if not present. Note we deliberately
|
|
|
|
+ * ignore -EPROBE_DEFER errors here. On some devices
|
|
|
|
+ * Intel is using so called virtual GPIOs which are not
|
|
|
|
+ * GPIOs at all but some way for AML code to check some
|
|
|
|
+ * random status bits without need a custom opregion.
|
|
|
|
+ * In some cases the resources table we parse points to
|
|
|
|
+ * such a virtual GPIO, since these are not real GPIOs
|
|
|
|
+ * we do not have a driver for these so they will never
|
|
|
|
+ * show up, therefor we ignore -EPROBE_DEFER.
|
|
|
|
+ */
|
2019-07-06 23:07:34 +00:00
|
|
|
continue;
|
|
|
|
+ }
|
|
|
|
|
|
|
|
gpio_keys[n_buttons].type = info->event_type;
|
|
|
|
gpio_keys[n_buttons].code = info->event_code;
|
2019-10-17 19:43:04 +00:00
|
|
|
@@ -309,23 +326,26 @@ static int soc_button_remove(struct platform_device *pdev)
|
2019-07-27 16:27:19 +00:00
|
|
|
static int soc_button_probe(struct platform_device *pdev)
|
2019-01-27 16:01:27 +00:00
|
|
|
{
|
|
|
|
struct device *dev = &pdev->dev;
|
2019-07-27 16:27:19 +00:00
|
|
|
- const struct acpi_device_id *id;
|
|
|
|
- struct soc_button_info *button_info;
|
|
|
|
+ const struct soc_device_data *device_data;
|
|
|
|
+ const struct soc_button_info *button_info;
|
2019-01-27 16:01:27 +00:00
|
|
|
struct soc_button_data *priv;
|
|
|
|
struct platform_device *pd;
|
2019-07-27 16:27:19 +00:00
|
|
|
int i;
|
|
|
|
int error;
|
2019-01-27 16:01:27 +00:00
|
|
|
|
2019-07-27 16:27:19 +00:00
|
|
|
- id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
|
|
|
- if (!id)
|
|
|
|
- return -ENODEV;
|
|
|
|
+ device_data = acpi_device_get_match_data(dev);
|
2019-01-27 16:01:27 +00:00
|
|
|
+ if (device_data && device_data->check) {
|
|
|
|
+ error = device_data->check(dev);
|
2019-04-24 18:51:10 +00:00
|
|
|
+ if (error)
|
2019-01-27 16:01:27 +00:00
|
|
|
+ return error;
|
|
|
|
+ }
|
2019-07-27 16:27:19 +00:00
|
|
|
|
|
|
|
- if (!id->driver_data) {
|
2019-01-27 16:01:27 +00:00
|
|
|
+ if (device_data && device_data->button_info) {
|
2019-07-27 16:27:19 +00:00
|
|
|
+ button_info = device_data->button_info;
|
2019-01-27 16:01:27 +00:00
|
|
|
+ } else {
|
|
|
|
button_info = soc_button_get_button_info(dev);
|
|
|
|
if (IS_ERR(button_info))
|
|
|
|
return PTR_ERR(button_info);
|
|
|
|
- } else {
|
|
|
|
- button_info = (struct soc_button_info *)id->driver_data;
|
|
|
|
}
|
|
|
|
|
2019-07-27 16:27:19 +00:00
|
|
|
error = gpiod_count(dev, NULL);
|
2019-10-17 19:43:04 +00:00
|
|
|
@@ -357,7 +377,7 @@ static int soc_button_probe(struct platform_device *pdev)
|
2019-01-27 16:01:27 +00:00
|
|
|
if (!priv->children[0] && !priv->children[1])
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
- if (!id->driver_data)
|
|
|
|
+ if (!device_data || !device_data->button_info)
|
|
|
|
devm_kfree(dev, button_info);
|
|
|
|
|
|
|
|
return 0;
|
2019-10-17 19:43:04 +00:00
|
|
|
@@ -368,7 +388,7 @@ static int soc_button_probe(struct platform_device *pdev)
|
2019-04-24 18:51:10 +00:00
|
|
|
* is defined in section 2.8.7.2 of "Windows ACPI Design Guide for SoC
|
2019-07-27 16:27:19 +00:00
|
|
|
* Platforms"
|
|
|
|
*/
|
|
|
|
-static struct soc_button_info soc_button_PNP0C40[] = {
|
|
|
|
+static const struct soc_button_info soc_button_PNP0C40[] = {
|
|
|
|
{ "power", 0, EV_KEY, KEY_POWER, false, true },
|
|
|
|
{ "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
|
|
|
|
{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
|
2019-10-17 19:43:04 +00:00
|
|
|
@@ -377,9 +397,77 @@ static struct soc_button_info soc_button_PNP0C40[] = {
|
2019-01-27 16:01:27 +00:00
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
2019-07-27 16:27:19 +00:00
|
|
|
+static const struct soc_device_data soc_device_PNP0C40 = {
|
2019-01-27 16:01:27 +00:00
|
|
|
+ .button_info = soc_button_PNP0C40,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Special device check for Surface Book 2 and Surface Pro (2017).
|
|
|
|
+ * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
|
|
|
|
+ * devices use MSHW0040 for power and volume buttons, however the way they
|
|
|
|
+ * have to be addressed differs. Make sure that we only load this drivers
|
|
|
|
+ * for the correct devices by checking the OEM Platform Revision provided by
|
|
|
|
+ * the _DSM method.
|
|
|
|
+ */
|
2019-04-24 18:51:10 +00:00
|
|
|
+#define MSHW0040_DSM_REVISION 0x01
|
|
|
|
+#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
|
|
|
|
+static const guid_t MSHW0040_DSM_UUID =
|
|
|
|
+ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
|
2019-07-02 22:36:37 +00:00
|
|
|
+ 0x49, 0x80, 0x35);
|
|
|
|
+
|
2019-01-27 16:01:27 +00:00
|
|
|
+static int soc_device_check_MSHW0040(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ acpi_handle handle = ACPI_HANDLE(dev);
|
|
|
|
+ union acpi_object *result;
|
2019-07-20 22:01:46 +00:00
|
|
|
+ u64 oem_platform_rev = 0; // valid revisions are nonzero
|
2019-01-27 16:01:27 +00:00
|
|
|
+
|
2019-04-24 18:51:10 +00:00
|
|
|
+ // get OEM platform revision
|
|
|
|
+ result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
|
|
|
|
+ MSHW0040_DSM_REVISION,
|
2019-07-02 22:36:37 +00:00
|
|
|
+ MSHW0040_DSM_GET_OMPR, NULL,
|
2019-04-24 18:51:10 +00:00
|
|
|
+ ACPI_TYPE_INTEGER);
|
2019-01-27 16:01:27 +00:00
|
|
|
+
|
|
|
|
+ if (result) {
|
|
|
|
+ oem_platform_rev = result->integer.value;
|
|
|
|
+ ACPI_FREE(result);
|
|
|
|
+ }
|
|
|
|
+
|
2019-07-20 22:01:46 +00:00
|
|
|
+ /*
|
|
|
|
+ * If the revision is zero here, the _DSM evaluation has failed. This
|
|
|
|
+ * indicates that we have a Pro 4 or Book 1 and this driver should not
|
|
|
|
+ * be used.
|
|
|
|
+ */
|
2019-04-24 18:51:10 +00:00
|
|
|
+ if (oem_platform_rev == 0)
|
|
|
|
+ return -ENODEV;
|
|
|
|
+
|
2019-01-27 16:01:27 +00:00
|
|
|
+ dev_dbg(dev, "OEM Platform Revision %llu\n", oem_platform_rev);
|
|
|
|
+
|
2019-04-24 18:51:10 +00:00
|
|
|
+ return 0;
|
2019-01-27 16:01:27 +00:00
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Button infos for Microsoft Surface Book 2 and Surface Pro (2017).
|
2019-04-24 18:51:10 +00:00
|
|
|
+ * Obtained from DSDT/testing.
|
2019-01-27 16:01:27 +00:00
|
|
|
+ */
|
2019-07-27 16:27:19 +00:00
|
|
|
+static const struct soc_button_info soc_button_MSHW0040[] = {
|
2019-01-27 16:01:27 +00:00
|
|
|
+ { "power", 0, EV_KEY, KEY_POWER, false, true },
|
|
|
|
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
|
|
|
|
+ { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false },
|
|
|
|
+ { }
|
|
|
|
+};
|
|
|
|
+
|
2019-07-27 16:27:19 +00:00
|
|
|
+static const struct soc_device_data soc_device_MSHW0040 = {
|
2019-01-27 16:01:27 +00:00
|
|
|
+ .button_info = soc_button_MSHW0040,
|
|
|
|
+ .check = soc_device_check_MSHW0040,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
static const struct acpi_device_id soc_button_acpi_match[] = {
|
|
|
|
- { "PNP0C40", (unsigned long)soc_button_PNP0C40 },
|
|
|
|
+ { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
|
2019-07-27 16:27:19 +00:00
|
|
|
{ "ACPI0011", 0 },
|
2019-04-24 18:51:10 +00:00
|
|
|
+
|
|
|
|
+ /* Microsoft Surface Devices (5th and 6th generation) */
|
2019-01-27 16:01:27 +00:00
|
|
|
+ { "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
|
2019-04-24 18:51:10 +00:00
|
|
|
+
|
2019-01-27 16:01:27 +00:00
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
|
|
|
diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c
|
2019-07-20 22:01:46 +00:00
|
|
|
index 1b491690ce07..96627627060e 100644
|
2019-01-27 16:01:27 +00:00
|
|
|
--- a/drivers/platform/x86/surfacepro3_button.c
|
|
|
|
+++ b/drivers/platform/x86/surfacepro3_button.c
|
|
|
|
@@ -24,6 +24,12 @@
|
|
|
|
#define SURFACE_BUTTON_OBJ_NAME "VGBI"
|
|
|
|
#define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3/4 Buttons"
|
|
|
|
|
|
|
|
+#define MSHW0040_DSM_REVISION 0x01
|
|
|
|
+#define MSHW0040_DSM_GET_OMPR 0x02 // get OEM Platform Revision
|
|
|
|
+static const guid_t MSHW0040_DSM_UUID =
|
2019-04-24 18:51:10 +00:00
|
|
|
+ GUID_INIT(0x6fd05c69, 0xcde3, 0x49f4, 0x95, 0xed, 0xab, 0x16, 0x65,
|
|
|
|
+ 0x49, 0x80, 0x35);
|
2019-01-27 16:01:27 +00:00
|
|
|
+
|
|
|
|
#define SURFACE_BUTTON_NOTIFY_TABLET_MODE 0xc8
|
|
|
|
|
|
|
|
#define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6
|
2019-07-20 22:01:46 +00:00
|
|
|
@@ -146,6 +152,44 @@ static int surface_button_resume(struct device *dev)
|
2019-01-27 16:01:27 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * Surface Pro 4 and Surface Book 2 / Surface Pro 2017 use the same device
|
|
|
|
+ * ID (MSHW0040) for the power/volume buttons. Make sure this is the right
|
|
|
|
+ * device by checking for the _DSM method and OEM Platform Revision.
|
2019-07-20 22:01:46 +00:00
|
|
|
+ *
|
|
|
|
+ * Returns true if the driver should bind to this device, i.e. the device is
|
|
|
|
+ * either MSWH0028 (Pro 3) or MSHW0040 on a Pro 4 or Book 1.
|
2019-01-27 16:01:27 +00:00
|
|
|
+ */
|
2019-07-20 22:01:46 +00:00
|
|
|
+static bool surface_button_check_MSHW0040(struct acpi_device *dev)
|
2019-01-27 16:01:27 +00:00
|
|
|
+{
|
|
|
|
+ acpi_handle handle = dev->handle;
|
|
|
|
+ union acpi_object *result;
|
2019-07-20 22:01:46 +00:00
|
|
|
+ u64 oem_platform_rev = 0; // valid revisions are nonzero
|
2019-01-27 16:01:27 +00:00
|
|
|
+
|
2019-04-24 18:51:10 +00:00
|
|
|
+ // get OEM platform revision
|
|
|
|
+ result = acpi_evaluate_dsm_typed(handle, &MSHW0040_DSM_UUID,
|
|
|
|
+ MSHW0040_DSM_REVISION,
|
|
|
|
+ MSHW0040_DSM_GET_OMPR,
|
|
|
|
+ NULL, ACPI_TYPE_INTEGER);
|
2019-01-27 16:01:27 +00:00
|
|
|
+
|
2019-07-20 22:01:46 +00:00
|
|
|
+ /*
|
|
|
|
+ * If evaluating the _DSM fails, the method is not present. This means
|
|
|
|
+ * that we have either MSHW0028 or MSHW0040 on Pro 4 or Book 1, so we
|
|
|
|
+ * should use this driver. We use revision 0 indicating it is
|
|
|
|
+ * unavailable.
|
|
|
|
+ */
|
|
|
|
+
|
2019-01-27 16:01:27 +00:00
|
|
|
+ if (result) {
|
|
|
|
+ oem_platform_rev = result->integer.value;
|
|
|
|
+ ACPI_FREE(result);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ dev_dbg(&dev->dev, "OEM Platform Revision %llu\n", oem_platform_rev);
|
|
|
|
+
|
2019-07-20 22:01:46 +00:00
|
|
|
+ return oem_platform_rev == 0;
|
2019-01-27 16:01:27 +00:00
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
static int surface_button_add(struct acpi_device *device)
|
|
|
|
{
|
|
|
|
struct surface_button *button;
|
2019-07-20 22:01:46 +00:00
|
|
|
@@ -158,6 +202,9 @@ static int surface_button_add(struct acpi_device *device)
|
2019-01-27 16:01:27 +00:00
|
|
|
strlen(SURFACE_BUTTON_OBJ_NAME)))
|
|
|
|
return -ENODEV;
|
|
|
|
|
2019-07-20 22:01:46 +00:00
|
|
|
+ if (!surface_button_check_MSHW0040(device))
|
|
|
|
+ return -ENODEV;
|
2019-01-27 16:01:27 +00:00
|
|
|
+
|
|
|
|
button = kzalloc(sizeof(struct surface_button), GFP_KERNEL);
|
|
|
|
if (!button)
|
|
|
|
return -ENOMEM;
|
|
|
|
--
|
2019-08-25 22:54:14 +00:00
|
|
|
2.23.0
|
2019-01-27 16:01:27 +00:00
|
|
|
|